1 IOCTL的调用逻辑
之所以要分析这个,是因为上层wpa_supplicant和WIFI驱动打交道的方式,多半是通过ioctl的方式进行的,所以看看它的调用逻辑(这里只列出其主要的调用逻辑):
上面便是用户ioctl调用的流程图,它最终分为两条线即有两种支持,选择那一条或两条都选(个人感觉最好选第2条线,因为它最后也是会调用到相应的函数的,而且还有其它更多的命令支持),从实际的代码来看,如果dev->netdev_ops
->ndo_do_ioctl被初始化了,那么它一定会被调用,是否被初始化,在前面选择对net结构变量的初始化方式中有讨论过。
下面来具体看看该调用流程,首先说明下,上面的流程主要实现在kernel/net/wireless/wext_core.c文件中,这是wireless的协议层实现,恰好我们在wpa_supplicant中通常选择的驱动类型也是wext,它的入口函数是wext_ioctl_dispatch:
/* entry point from dev ioctl*/
static int wext_ioctl_dispatch(struct net *net, struct ifreq*ifr,
unsigned int cmd, struct iw_request_info *info,
wext_ioctl_func standard,
wext_ioctl_funcprivate)
{
int ret = wext_permission_check(cmd);
if (ret)
return ret;
dev_load(net, ifr->ifr_name);
rtnl_lock();
ret = wireless_process_ioctl(net, ifr, cmd, info, standard,private);
rtnl_unlock();
return ret;
}
它其实就是wireless_process_ioctl的封装函数,除了进行许可权限的确认,没有做什么其它内容,这里有standard和private两个函数指针的传递,其实就是两个回调函数,在后面会用到,它是由wext_handle_ioctl函数传递过来的:
int wext_handle_ioctl(structnet *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg)
{
struct iw_request_info info = { .cmd =cmd, .flags = 0 };
int ret;
ret = wext_ioctl_dispatch(net, ifr, cmd, &info,
ioctl_standard_call,
ioctl_private_call); //这两个回调函数的定义之后再讨论,这里暂不理论
if (ret >= 0 &&
IW_IS_GET(cmd) &&
copy_to_user(arg, ifr, sizeof(structiwreq)))
return -EFAULT;
return ret;
}
实际上传递的就是ioctl_standard_call和ioctl_private_call两个函数,在看看wireless_process_ioctl函数,这个函数很重要,下面做重点分析:
static intwireless_process_ioctl(struct net *net, struct ifreq *ifr,
unsigned int cmd,
structiw_request_info *info,
wext_ioctl_func standard,
wext_ioctl_func private)
{
struct iwreq *iwr = (struct iwreq *)ifr;
struct net_device *dev;
iw_handler handler;
/* Permissions are already checked indev_ioctl() before calling us.
* The copy_to/from_user() of ifr isalso dealt with in there */
/* Make sure the device exist */
if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) //通过网络接口名获取net_device设备
return -ENODEV;
/* A bunch of special cases, then thegeneric case...
* Note that 'cmd' is already filteredin dev_ioctl() with
* (cmd >= SIOCIWFIRST &&cmd <= SIOCIWLAST) */
if (cmd == SIOCGIWSTATS)
returnstandard(dev, iwr, cmd, info,
&iw_handler_get_iwstats); //如果是状态查询命令,调用该函数(回调函数中的一个)
#ifdef CONFIG_WEXT_PRIV
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
returnstandard(dev, iwr, cmd, info,
iw_handler_get_private); //如果是专有命令,调用回调函数,同上
#endif
/* Basic check */
if (!netif_device_present(dev))
return -ENODEV;
/* New driver API : try to find thehandler */
handler = get_handler(dev, cmd); //根据cmd参数,从dev成员中查询相应的处理函数
if (handler) {
/* Standard and private are notthe same */
if (cmd < SIOCIWFIRSTPRIV)
return standard(dev, iwr, cmd, info, handler); //调用相应命令的处理函数
else if (private)
return private(dev, iwr, cmd, info, handler); //同上
}
/* Old driver API : call driver ioctlhandler */
if(dev->netdev_ops->ndo_do_ioctl)
return dev->netdev_ops->ndo_do_ioctl(dev,ifr, cmd); //如果被设置就调用该函数
return -EOPNOTSUPP;
}
该函数的大意是,通过网络接口名称获得一个网络设备,然后根据命令的类型调用相应的处理函数,特别的是当dev->netdev_ops->ndo_do_ioctl或dev->wireless_handlers被设置时,则会查找执行对应的处理函数。Get_handle函数用于查询处理函数使用:
static iw_handlerget_handler(struct net_device *dev, unsigned int cmd)
{
/* Don't "optimise" thefollowing variable, it will crash */
unsigned int index; /* *MUST* be unsigned */
const struct iw_handler_def *handlers = NULL;
#ifdef CONFIG_CFG80211_WEXT
if (dev->ieee80211_ptr &&dev->ieee80211_ptr->wiphy)
handlers =dev->ieee80211_ptr->wiphy->wext; //初始化默认的处理函数
#endif
#ifdef CONFIG_WIRELESS_EXT
if (dev->wireless_handlers)
handlers= dev->wireless_handlers; //这里的dev->wireless_handlers在net初始化时被作为扩张功能选择性的设置,前面有提到过
#endif
if (!handlers)
return NULL;
/* Try as a standard command */
index = IW_IOCTL_IDX(cmd);
if (index <handlers->num_standard)
returnhandlers->standard[index]; //返回对应的标准函数
#ifdef CONFIG_WEXT_PRIV
/* Try as a private command */
index = cmd - SIOCIWFIRSTPRIV;
if (index <handlers->num_private)
return handlers->private[index]; //返回对应的专有函数
#endif
/* Not found */
return NULL;
}
那么这个dev->wire