全部博文(146)
分类: LINUX
2008-11-17 14:13:16
一、应用层
uint16 data16;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket failed\n\r");
}
if(ioctl(fd, SIOCSIFVLAN_PVID_PRI, &data16) < 0)
{
printf("ioctl pvid failed\n\r");
}
二、linux内核
1、 在sockios.h中定义
#define SIOCSIFVLAN_PVID_PRI 0x8985 /* Set 802.1Q VLAN pvid */
2、在af_inet.c中
添加
extern int VLAN1QEN(unsigned int ,void *arg);
在inet_ioctl()函数中添加
case SIOCSIFVLAN_PVID_PRI:
return VLAN1QEN(cmd, arg);
3、另外定义:
static unsigned int VLAN_PVID_PRI = 0;
int VLAN1QEN(unsigned int cmd,void *arg)
{
unsigned int data;
if (copy_from_user(&data, arg, sizeof(int)))
return -EFAULT;
switch (cmd) {
case SIOCSIFVLAN_PVID_PRI:
VLAN_PVID_PRI = data;
break;
default:
return -EINVAL;
}
}
//end
在copy_from_user()和copy_to_user()的过程中,使用了arg这个参数指向用户空间某命令参数,在用户空间使用ioctl(int fd,int cmd, *bcf)想内核空间传递这个参数
这里,找不到bcf和arg的联系。
这里我把我的理解写在这里:
首先,ioctl的功能我就不说了,网上比较多,大致是用来控制IO的。
其次,第一个参数fd是一个文件描述符,我们这里是建立的一个套接字描述符
再次,第二个参数,是在sockios.h中定义的一个32位描述符,我们也可以在这里添加新的类型,用来扩展实际需求。
最后,第三个参数,是一个指针,用来指向某些我们实际应用中的参数。
在af_inet.c中的inet_ioctl()函数中的switch——case中,对上面第二个参数分别进行了描述。
例如需要的是这样的一个类型:
ioctl( fd, SIOCSIFBR, &bcf )
在inet_ioctl()函数中如下表示: Linux/net/ipv4/af_inet.c
int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
switch (cmd)
{……
case SIOCGIFBR:
case SIOCSIFBR:
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
#ifdef CONFIG_KMOD
if (br_ioctl_hook == NULL)
request_module("bridge");
#endif
if (br_ioctl_hook != NULL)
return br_ioctl_hook(arg);
879 #endif
return -ENOPKG;
……
}//switch end here
这里inet_ioctl()中的第三个参数arg,正好对应在ioctl中的的三个参数&bcf,其实,inet_ioctl属于ioctl在linux内核中的网络设备ioctl的底层函数,用来处理网络设备的一些IO操作。
上面的一小段程序显示,我们用户层ioctl函数中的第三个参数对应在br_ioctl_hook(arg)中的arg上。
而在我们的另外一个函数中定义了一个函数叫br_ioctl(arg)函数,并且其中使用了copy_to_user 和copy_from_user 用来将用户层中ioctl函数传下来的 命令在内核中进行相应的处理。最后,用一句:br_ioctl_hook = br_ioctl 将这个函数送进inet_ioctl中。
这里才明白ioctl —— br_ioctl之间的关系