⑴ 如何利用ioctl调用内核函数
首先请检查open、read之类的正确。之后,你的ioctl要是自己定义的cmd,需要同时在内核态以及用户态建立描述这个cmd的头文件。否则乱传cmd自然不能匹配。cmd里包含你的ioctl的参数类型(是否有参数,参数是只传递进内核;还是只从内核取;还是既传递进内核又从内核取)以及混淆具体cmd的定义你可以很容易到内核源码里找到例子,grep-rni"ioctl"./drivers跟着学就好了
⑵ ioctl() 小于0 的问题
我看看
“蓝屏”的软件原因
一、启动时加载程序过多
不要在启动时加载过多的应用程序(尤其是你的内存小于64MB),以免使系统资源消耗殆尽。正常情况下,Win9X启动后系统资源应不低于90%。最好维持在90%以上,若启动后未运行任何程序就低于70%,就需要卸掉一部分应用程序,否则就可能出现“蓝屏”。
二、应用程序存在着BUG
有些应用程序设计上存在着缺陷或错误,运行时有可能与Win9X发生冲突或争夺资源,造成Win9X无法为其分配内存地址或遇到其保护性错误。这种BUG可能是无法预知的,免费软件最为常见。另外,由于一些用户还在使用盗版软件(包括盗版Win9X),这些盗版软件在解密过程中会破坏和丢失部分源代码,使软件十分不稳定,不可靠,也常常导致“蓝屏”。
三、遭到不明的程序或病毒攻击所至
这个现象只要是平时我们在上网的时候遇到的,当我们在冲浪的时候,特别是进到一些BBS站时,可能暴露了自己的IP,被“黑客“用一些软件攻击所至。对互这种情况最好就是在自己的计算机上安装一些防御软件。再有就是登录BBS要进行安全设置,隐藏自己IP。
四、版本冲突
有些应用程序需调用特定版本的动态链接库DLL,如果在安装软件时,旧版本的DLL覆盖了新版本的DLL,或者删除应用程序时,误删了有用的DLL文件,就可能使上述调用失败,从而出现“蓝屏”。不妨重新安装试一试。
此篇说的是软件使用可能引起的蓝屏,当然这只是引起蓝屏的一小部份原因。
五、注册表中存在错误或损坏
很多情况下这是出现“蓝屏”的主要原因。注册表保存着Win9X的硬件配置、应用程序设置和用户资料等重要数据,如果注册表出现错误或被损坏,就很可能出现“蓝屏”。如果你的电脑经常出现“蓝屏”,你首先就应考虑是注册表出现了问题,应及时对其检测、修复,避免更大的损失。
六、软硬件不兼容
新技术、新硬件的发展很快,如果安装了新的硬件常常出现“蓝屏”,那多半与主板的BIOS或驱动程序太旧有关,以致不能很好支持硬件。如果你的主板支持BIOS升级,应尽快升级到最新版本或安装最新的设备驱动程序。
“蓝屏”的硬件原因
在计算机的使用过程中,经常会遇到蓝屏的情况。对于初学者来讲,好象就是一场电脑灾难一样,不知所措。其实只要了解了原因之后就不用怕了。造成计算机蓝屏的原因有很多种,硬件方面的原因总体可以概括为以下几种:
一、屏幕显示系统忙,请按任意键继续
1、虚拟内存不足造成系统多任务运算错误
虚拟内存是WINDOWS系统所特有的一种解决系统资源不足的方法,其一般要求主引导区的硬盘剩余空间是其物理
内存的2-3倍。而一些发烧友为了充分利用空间,将自己的硬盘塞到满满的,忙记了WINDOWS这个苛刻的要求。结果导致虚拟内存因硬盘空间不足而出现运算错误,所以就出现蓝屏。 要解决这个问题好简单,尽量不要把硬盘塞得满满的,要经常删除一些系统产生的临时文件、交换文件,从而可以释放空间。或可以手动配置虚拟内存,选择高级,把虚拟内存的默认地址,转到其他的逻辑盘下。这样就可以避免了因虚拟内存不足而引起的蓝屏。
⑶ linux-ioctl什么时候会调用失败,而且返回
首先请检查open、read之类的正确。之后,
你的ioctl要是自己定义的cmd,需要同时在内核态以及用户态建立描述这个cmd的头文件。否则乱传cmd自然不能匹配。
cmd里包含你的ioctl的参数类型(是否有参数,参数是只传递进内核;还是只从内核取;还是既传递进内核又从内核取)以及混淆
具体cmd的定义你可以很容易到内核源码里找到例子,grep -rni "ioctl" ./drivers
跟着学就好了
⑷ ioctl()函数的参数和作用
因为用户层定义它是个变参函数
ioctl (int __fd, unsigned long int __request, ...)
跟printf似的
⑸ linux下怎么用C++实现对文件的写入要测试一个项目用。以下是关于文件写入部分的源码
写进文件的是字符,你要是写进一个值,得把这个值处理一下再写,比如你要写15,你就得取出1和5,然后分别变成字符"1"和"5"再往文件里写。
⑹ 求两相四线步进电机驱动,C语言源码,可以控制步数的。
#include <stdio.h> #include <fcntl.h> #include <string.h> #include <sys/ioctl.h>
#define STEPMOTOR_IOCTRL_PHASE 0x13 staticintstep_fd = -1;
char *STEP_DEV="/dev/exio/0raw"; //定义一个指针指向步进电机的驱动 程序
/********* A, AB, B, BC, C CD, D, DA ***/
char stepdata[]={0x10,0x30,0x20,0x60,0x40,0xc0,0x80,0x90};//各 个相位对应的值
void Delay(int t) //延时函数 { int i;
for(;t>0;t--)
for(i=0;i<400;i++); }
/***************************************************** ***********/
int main(intargc, char **argv) {
int i = 0;
if((step_fd=open(STEP_DEV, O_WRONLY))<0){ printf("Error opening /dev/exio/0raw device\n"); return 1; } /*
打开设备的驱动程序,由于LINUX把所有的设备都模拟成文件。 step_fd=open(STEP_DEV,0_WRONLY)实际调用的函数为:
staticint s3c2410_exio_open(structinode *inode, struct file *filp) //驱动程序中的设备打开程序 */
for (;;) {
for (i=0; i<sizeof(stepdata)/sizeof(stepdata[0]); i++) { ioctl(step_fd, STEPMOTOR_IOCTRL_PHASE, stepdata[i]); }
/*程序进入一个死循环,这样可以使电机在没有人为停止的状况下,一直的 转动下去。
*第二层for语句循环一次即电机转动一周。函数ioctl()对应函 数*s3c2410_exio_ioctl()
*而这个函数最终将调用函数do_stepmotor_run((char)arg);使步进电 机转动起来。 */
printf("Delay(100)\n"); Delay(100); }
close(step_fd); //程序结束时关闭设备 printf("Step motor start running!\n"); return 0; }本文来自网络文库,你可以搜搜,其中答案更详细的!
⑺ Linux下碰到一个关于ioctl缓冲区的问题
是不是buffer的长度系统默认是接受100个包的大小,你可以改改大小试试
⑻ 怎么使用Android源码编译c模块生成可执行文件
1. 在./development目录下创建一目录 如:myhello
2. 进入hello目录,在其下编写自己的.c文件,如: myhello.c
#include <stdio.h>
int main()
{
printf("hello world\n");
exit(0);
//return 0;
}
3. 在hello目录中,编写Android.mk, 内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := myhelloworld
LOCAL_SRC_FILES := myhello.c
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
4. 回到Android源代码顶层目录,进行编译,make myhelloworld
5. 生成的可执行文件位于:out/target/proct/lotus/system/bin/ 目录下
6. adb push 到手机 /data 目录下,然后进入adb shell,到data目录下,执行./myhelloworld 皆可
手动编译连接【arm-eabi-gcc 的目录随andorid的版本而有变化,还有就是需要链接的文件如果比较多时,需要很多-l 就很麻烦了】
7、编译成目标文件:
#$(yourAndroid)/prebuilt/linux-x86/toolchain/[arm-eabi-4.2.1]/bin/arm-eabi-gcc -I bionic/libc/arch-arm/include/ -I bionic/libc/include -I bionic/libc/kernel/common -I bionic/libc/kernel/arch-arm -g -c helloworld.c -o hello.o
8、生成可执行代码:
#$(yourAndroid)/prebuilt/linux-x86/toolchain/[arm-eabi-4.2.1]/bin/arm-eabi-gcc -nostdlib -Bdynamic -Wl,-T,build/core/armelf.x -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,noreloc -o helloworld -Lout/target/proct/[generic]/obj/lib -Wl,-rpath-link=out/target/proct/[generic]/obj/lib -lc hello.o -entry=main
其中[ ]中部分根据实际情况修改
**************************************************
实验:
1. 建目录(my Android)/development/test, 在该目录下新建 Android.mk和fb_test.c文件
2. Android.mk文件
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := myfbtest
LOCAL_SRC_FILES := fb_test.c
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
3. 以下为fb_test.c
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <linux/kd.h>
#include <stdio.h>
#define FBBIT_PER_PIXEL 32
#define FBBIT_PIXEL_IMAGE 16
#define PIXELS_WIDTH_BYTE 4
#define BYTE_PER_PIXEL 3
#define FB_GRAPHICS_PATH "/dev/graphics/fb0"
#define DEV_TTY0_PATH "/dev/tty0"
#define DISPLAY_ERROR -1
#define DISPLAY_SUCCESS 0
#define GET_BATTERYCAPACITY_ERR -1
#define MAX_STR 255
static struct {
int fd;
void *pixels;
struct fb_fix_screeninfo fixed;
struct fb_var_screeninfo var;
int align_xres;
} fb;
int getBatteryCapacity(void)
{
FILE *in;
char tmpStr[MAX_STR + 1];
char capfile[] = "/sys/class/power_supply/battery/capacity";
if (capfile == NULL)
return GET_BATTERYCAPACITY_ERR;
in = fopen(capfile, "rt");
if (in == NULL)
return GET_BATTERYCAPACITY_ERR;
if (fgets(tmpStr, MAX_STR, in) == NULL) {
printf("Failed to read battery capacity!\n");
fclose(in);
return GET_BATTERYCAPACITY_ERR;
}
printf("Battery capacity(ascii): %s\n", tmpStr);
fclose(in);
return 0;//atoi(tmpStr);
}
static int vt_set_graphicsmode(int graphics)
{
int fd, r;
fd = open(DEV_TTY0_PATH, O_RDWR | O_SYNC);
if (fd < 0)
return DISPLAY_ERROR;
r = ioctl(fd, KDSETMODE, graphics);
close(fd);
return r;
}
int display_init(void)
{
fb.fd = open(FB_GRAPHICS_PATH, O_RDWR);
if (fb.fd < 0)
return DISPLAY_ERROR;
if (ioctl(fb.fd, FBIOGET_FSCREENINFO, &fb.fixed) < 0)
return DISPLAY_ERROR;
if (ioctl(fb.fd, FBIOGET_VSCREENINFO, &fb.var) < 0)
return DISPLAY_ERROR;
fb.align_xres = fb.fixed.line_length /
(fb.var.bits_per_pixel >> BYTE_PER_PIXEL);
fb.pixels = mmap(0, fb.fixed.line_length * fb.var.yres_virtual,
PROT_READ | PROT_WRITE, MAP_SHARED, fb.fd, 0);
if (fb.pixels == MAP_FAILED)
return DISPLAY_ERROR;
vt_set_graphicsmode(KD_GRAPHICS);
memset(fb.pixels, 0, fb.fixed.line_length * fb.var.yres_virtual);
//display_update(fb.pixels, fb.align_xres, fb.var.yres);
fb.var.activate = FB_ACTIVATE_FORCE;
ioctl(fb.fd, FBIOPUT_VSCREENINFO, &fb.var);
printf("display_init ok\n");
return DISPLAY_SUCCESS;
}
void display_on(void)
{
ioctl(fb.fd, FBIOBLANK, FB_BLANK_UNBLANK);
}
void display_off(void)
{
ioctl(fb.fd, FBIOBLANK, FB_BLANK_POWERDOWN);
}
int main()
{
display_init();
display_off();//关显示屏
getBatteryCapacity();
sleep(5);
display_on();//开显示屏
return 0;
}
⑼ 如何伪造tcp数据包,并进行正确的校验的例子演示及源码
下面的程序是在linux下进行tcp伪造的一个例子:涉及原始套接字和tcp的校验算法
/************************tcp_pseudo.c********************/
/** Author :cbchen. */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INTERFACE "eth0"
#define IP ""
/*Prototype area*/
int Open_Packet_Socket();
int Open_Raw_Socket();
int Set_Promisc(char *interface, int sock);
void send_tcp_ack(int sockfd,struct sockaddr_in *addr);
unsigned short check_sum(unsigned short *addr,int len);
struct ip *iprecv;
struct tcphdr *tcprecv;
struct sockaddr_in addr;
int main()
{
int sockfd,sendfd,bytes_recieved;
char buffer[1518];
u_char *buf2;
char saddr[20],daddr[20];
sockfd=Open_Packet_Socket();
sendfd=Open_Raw_Socket();
//printf("sockfd:%d/tsendfd:%d/n",sockfd,sendfd);
int on=1;
/******** 设置IP数据包格式,告诉系统内核模块IP数据包由我们自己来填写 ***/
setsockopt(sendfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
Set_Promisc(INTERFACE, sockfd);
int count=1;
while(1)
{
bytes_recieved = recvfrom(sockfd, buffer, 1518, 0, NULL, NULL);
buf2=buffer;
buf2+=14;
iprecv=(struct ip *)buf2;
//iprecv+=sizeof(struct ethhdr*);
/*See if this is a TCP packet*/
if(iprecv->ip_v == 4&iprecv->ip_p == 6) {
printf("---------------------------Number %d packet-----------------------------------------------/n",count);
count++;
printf("/nBytes received ::: %5d/n",bytes_recieved);
printf("ip version:%u/n",iprecv->ip_v);
printf("IP包头解码:/n");
printf("Source ip:%s/t",inet_ntoa(iprecv->ip_src));
printf("Dest ip:%s/t",inet_ntoa(iprecv->ip_dst));
printf("proto:%u/n",iprecv->ip_p);
buf2+=iprecv->ip_hl<<2;
printf("TCP包头解码:/n");
tcprecv = (struct tcphdr*)buf2;
//tcprecv = (struct tcphdr *)(buffer + (iprecv->ip_hl<<2));
printf("Source port :::%d/n",ntohs(tcprecv->source));
printf("Dest port :::%d/n",ntohs(tcprecv->dest));
printf("seq num:%u/n",ntohl(tcprecv->seq));
printf("ack num:%u/n",ntohl(tcprecv->ack_seq));
printf("urg:%x/tack:%x/tpsh:%x/trst:%x/tsyn:%x/tfin:%x/n",tcprecv->urg,tcprecv->ack,tcprecv->psh,tcprecv->rst,tcprecv->syn,tcprecv->fin);
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
//addr2.sin_port=htons(thdr->source);
addr.sin_port=tcprecv->source;
//addr2.sin_addr=iphdr->ip_src;
addr.sin_addr=iprecv->ip_src;
/********* 发送阻隔包了!!!! ****/
if(tcprecv->syn==1&tcprecv->urg!=1&tcprecv->ack!=1&tcprecv->psh!=1&tcprecv->rst!=1&tcprecv->fin!=1)
{
//send_tcp_ack(sendfd,&addr);
//printf("It's a syn pocket!/n");
}
}
}
close(sockfd);
close(sendfd);
}
//end main
/******* 发送阻隔包的实现 *********/
/*
void send_tcp_ack(int sockfd,struct sockaddr_in *addr)
{
struct send_tcp
{
struct iphdr ip;
struct tcphdr tcp;
} send_tcp;
struct pseudo_header
{
unsigned int source_address;
unsigned int dest_address;
unsigned char placeholder;
unsigned char protocol;
unsigned short tcp_length;
struct tcphdr tcp;
} pseudo_header;
int tcp_socket;
struct sockaddr_in sin;
int sinlen;
// form ip packet
send_tcp.ip.ihl = 5;
send_tcp.ip.version = 4;
send_tcp.ip.tos = 0;
send_tcp.ip.tot_len = htons(40);
send_tcp.ip.frag_off = 0;
send_tcp.ip.ttl = 64;
send_tcp.ip.protocol = IPPROTO_TCP;
send_tcp.ip.check = 0;
send_tcp.ip.saddr = iprecv->ip_dst.s_addr;
send_tcp.ip.daddr = addr->sin_addr.s_addr;
// form tcp packet
send_tcp.tcp.dest = addr->sin_port;
send_tcp.tcp.source = tcprecv->dest;
send_tcp.tcp.ack_seq = htonl(ntohl(tcprecv->seq)+0x01);
send_tcp.tcp.res1 = 0;
send_tcp.tcp.doff = 5;
send_tcp.tcp.fin = 0;
send_tcp.tcp.syn = 1;
send_tcp.tcp.rst = 0;
send_tcp.tcp.psh = 0;
send_tcp.tcp.ack = 1;
send_tcp.tcp.urg = 0;
send_tcp.tcp.res2 = 0;
send_tcp.tcp.window = htons(512);
send_tcp.tcp.check = 0;
send_tcp.tcp.urg_ptr = 0;
send_tcp.tcp.seq = tcprecv->seq;
// set fields that need to be changed
//send_tcp.tcp.source++;
send_tcp.ip.id = 0 ;
//send_tcp.tcp.seq++;
send_tcp.tcp.check = 0;
send_tcp.ip.check = 0;
// calculate the ip checksum
send_tcp.ip.check = in_cksum((unsigned short *)&send_tcp.ip, 20);
// set the pseudo header fields
pseudo_header.source_address = send_tcp.ip.saddr;
pseudo_header.dest_address = send_tcp.ip.daddr;
pseudo_header.placeholder = 0;
pseudo_header.protocol = IPPROTO_TCP;
pseudo_header.tcp_length = htons(20);
b((char *)&send_tcp.tcp, (char *)&pseudo_header.tcp, 20);
send_tcp.tcp.check = in_cksum((unsigned short *)&pseudo_header, 32);
sinlen = sizeof(sin);
int count;
for(count=0;count<2;count++){
if(sendto(sockfd, &send_tcp, 40, 0, (struct sockaddr *)addr,sizeof(struct sockaddr))<0)
{
printf("sendto error!/n");
}
else
{
printf("send packet ok!/n");
}
}
*/
/* 下面是首部校验和的算法 */
unsigned short in_cksum(unsigned short *addr, int len) /* function is from ping.c */
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer =0;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(u_char *)(&answer) = *(u_char *)w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
int Open_Packet_Socket()
{
int sock;
sock=socket(AF_INET,SOCK_PACKET,htons(ETH_P_ALL));
if (sock==-1)
{
perror("socket");
exit(errno);
}
printf("sockfd:%d/n",sock);
return(sock);
}
int Open_Raw_Socket()
{
int sock;
sock=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
if (sock==-1)
{
perror("socket");
exit(errno);
}
printf("sendfd:%d/n",sock);
return(sock);
}
int Set_Promisc(char *interface, int sockfd )
{
struct ifreq ifr;
strncpy(ifr.ifr_name,interface,strnlen(interface)+1);
if (ioctl(sockfd,SIOCGIFFLAGS,&ifr)==-1)
{
perror("ioctl1");
exit(errno);
}
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl(sockfd,SIOCSIFFLAGS,&ifr))
{
perror("ioctl2");
exit(errno);
}
// printf("Setting interface ::: %s ::: to promisc...ok..../n", interface);
return(1);
}
⑽ struct模块中的ioctl函数有什么作用
一、在普通程序中设置网卡混杂模式。
在普通程序中普遍用ioctl函数来设置,该函数很值得大家好好的了解,因为它的使用非常的广泛。下面
给出设置网卡混杂模式的实现代码:
#include
#include
#include
#include
int set_all_promisc()
{ struct ifreq ifaces[16];
struct ifconf param;
int sock, i;
param.ifc_len = sizeof(ifaces);
param.ifc_req = ifaces;
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock <= 0)
return 0;
if (ioctl(sock, SIOCGIFCONF, ¶m))
return 0;
for (i = 0; i < param.ifc_len / sizeof(struct ifreq); i++) {
if (ioctl(sock, SIOCGIFFLAGS, ifaces + i))
return 0;
ifaces[i].ifr_flags |= IFF_PROMISC; /*如果恢复网卡模式,把|= 改成 &=~ */
if (ioctl(sock, SIOCSIFFLAGS, ifaces + i))
return 0;
}
return 1;
}
二、在核心空间中设置混杂模式
1.在kernel-2.2.x 中
static struct device *sniffer_dev = NULL;
static unsigned short old_flags, old_gflags;
int init_mole ( void ) /* 模块初始化 */
{
......
sniffer_dev = dev_get("eth0");
if ( sniffer_dev != NULL )
{
/* thanks for difeijing of whnet's Security */
old_flags = sniffer_dev->flags;
old_gflags = sniffer_dev->gflags;
/*
* 参看net/core/dev.c里的dev_change_flags()
* ->gflags的作用是避免多次重复设置混杂模式,没有其他特别含义
*/
/* 设置混杂模式 */
sniffer_dev->flags |= IFF_PROMISC;
sniffer_dev->gflags |= IFF_PROMISC;
start_bh_atomic();
/* 注意,这个回调函数还是会报告 eth0: Setting promiscuous mode. */
sniffer_dev->set_multicast_list( sniffer_dev );
end_bh_atomic();
}
......
return 0;
}
void cleanup_mole(void)
{
......
if (sniffer_dev != NULL)
{
/* 恢复原有模式 */
sniffer_dev>flags = old_flags;
sniffer_dev>gflags = old_gflags;
start_bh_atomic();
sniffer_dev>set_multicast_list( sniffer_dev );
end_bh_atomic();
}
......
}
2.在kernel-2.4.x 中
在2.4中有了许多变化,首先struct device结构改为struct net_device, 再者dev_get
功能改为测试网络设备是否存在,真正的设置网络混杂模式的函数改为
void dev_set_promiscuity(struct net_device *dev, int inc);
其中根据inc的值来设置混杂模式还是恢复原来设置模式,通过计数来恢复原来模式,这样的好处就是:不会和其他的程序冲突,不在像上述两种实现方式中恢复原来模式就全恢复了,不管还有没有其他的程序是否也设置了混杂模式。现在就通过计数来恢复原来的模式,只要当计数相加为零才设置成普通模式。
linux源代码的注释如下:
/**
* dev_set_promiscuity - update promiscuity count on a device
* @dev: device
* @inc: modifier
*
* Add or remove promsicuity from a device. While the count in the device
* remains above zero the interface remains promiscuous. Once it hits zero
* the device reverts back to normal filtering operation. A negative inc
* value is used to drop promiscuity on the device.
*/
设置网卡混杂模式的实现代码如下:
struct net_device *sniffer_dev = NULL;
int dev_flags = 0;
int init_mole ( void ) /* 模块初始化 */
{
......
sniffer_dev = dev_get_by_name("eth0");
if (sniffer_dev != NULL)
{
dev_flags = 1;
dev_set_promiscuity(sniffer_dev, 1);
dev_put(sniffer_dev);
sniffer_dev = NULL;
}
......
return 0;
}
void cleanup_mole(void)
{
......
if (dev_flags)
{
sniffer_dev = dev_get_by_name("eth0");
if (sniffer_dev != NULL)
{
dev_flags = 0;
dev_set_promiscuity(sniffer_dev, -1); /*注意此处的第二个参数*/
dev_put(sniffer_dev);
sniffer_dev = NULL;
}
}
......
}