全部博文(51)
分类: LINUX
2016-09-13 15:15:57
本文对Atheros源码进行分析。
每个无线设备拥有一些不被标准无线扩展包含的特定功能。私有ioctl允许设备导出驱动的特定功能,使得用户直接与驱动交互;
与标准无线扩展一样,每个私有请求通过ioctl number来标识,并且携带一定参数;
无线标准ioctl用户态工具对应iwconfig;
无线私有ioctl用户态工具对应iwpriv;
最初的iwpriv实现使用的ioctl 号范围由SIOCDEVPRIVATE确定[#define SIOCDEVPRIVATE 0x89F0 /* to 89FF */];但这些ioctl被其它功能占用,支持功能有限。
新ioctl范围由SIOCIWFIRSTPRIV确定;这些ioctl是特定为无线扩展使用,不用担心与其它功能冲突;下面是针对SIOCIWFIRSTPRIV的内核描述,支持私有ioctl号为32个;用户可以使用SIOCGIWPRIV(#define SIOCGIWPRIV 0x8B0D)来获取私有ioclt的描述信息;
/* These 32 ioctl are wireless device private, for 16 commands. * Each driver is free to use them for whatever purpose it chooses, * however the driver *must* export the description of those ioctls * with SIOCGIWPRIV and *must* use arguments as defined below. * If you don't follow those rules, DaveM is going to hate you (reason : * it make mixed 32/64bit operation impossible). */ #define SIOCIWFIRSTPRIV 0x8BE0 #define SIOCIWLASTPRIV 0x8BFF |
对用户空间来说32个ioctl是不够用的,所有Wireless Extension 15引入了sub-ioctls。
驱动是如何提取由iwpriv传输的数据?
1、 若数据固定且小于16B,那么存放在struct iwreq的‘u.name’字段;
2、 如果数据不固定,且大于16B,struct iwreq的‘u.data.pointer’字段指向用户空间的数据;由copy_from/to_user()进行拷贝;
用户态通过ioctl访问驱动,在内核态处理流程从sock_ioctl开始介绍。
static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { …… sock = file->private_data; sk = sock->sk; net = sock_net(sk); if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { //[0x89F0, 0x89FF] err = dev_ioctl(net, cmd, argp); } else #ifdef CONFIG_WEXT_CORE if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { //[0x8BE0, 0x8BFF] err = dev_ioctl(net, cmd, argp); } else #endif 。。。。。。 } |
#define SIOCIWFIRSTPRIV 0x8BE0 #define SIOCIWLASTPRIV 0x8BFF
#define SIOCIWFIRST 0x8B00 #define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) #define IW_HANDLER(id, func) [IW_IOCTL_IDX(id)] = func |
wifi私有ioctl进入dev_ioctl处理:
int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) { ……. /* Take care of Wireless Extensions */ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) //[0x8BE0, 0x8BFF] return wext_handle_ioctl(net, &ifr, cmd, arg); …… } |
int wext_handle_ioctl(struct net *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); //继续调用wireless_process_ioctl(net, ifr, cmd, info, standard, private); …… } |
在介绍wireless_process_ioctl之前,先来看一下,wifi设备建立时是如何关联到其ioctl的处理函数的;
wifi设备可以分为实际物理设备及vap设备;
root@OpenWrt:/tmp# ifconfig ath01 Link encap:Ethernet HWaddr 00:03:7F:12:D2:D2 inet6 addr: fe80::203:7fff:fe12:d2d2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:21513 errors:0 dropped:0 overruns:0 frame:0 TX packets:21513 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1463952 (1.3 MiB) TX bytes:1463952 (1.3 MiB) wifi0 Link encap:UNSPEC HWaddr 00-03-7F-12-D2-D2-00-00-00-00-00-00-00-00-00-00 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:2699 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) Interrupt:200 Memory:d2400000-d2600000 |
对于实际物理设备wifi0,驱动probe处理时,将处理函数与设备进行关联;
|
static struct iw_handler_def ath_iw_handler_def = { .standard = (iw_handler *) NULL, //标准ioctl .num_standard = 0, .private = (iw_handler *) ath_iw_priv_handlers, //私有ioctl处理函数, Array of handlers for private ioctls .num_private = TABLE_SIZE(ath_iw_priv_handlers), /*处理函数个数 */ .private_args = (struct iw_priv_args *) ath_iw_priv_args, /* Arguments of private handler. Private ioctl interface information */ .num_private_args = TABLE_SIZE(ath_iw_priv_args), /* Number of private arg description */ .get_wireless_stats = NULL, }; |
ath_pci_probe -->__ath_attach--> ath_iw_attach |
void ath_iw_attach(struct net_device *dev) { dev->wireless_handlers = &ath_iw_handler_def; } |
对于虚拟vap设备ath01,在创建该虚拟设备时,将处理函数与设备进行关联;
static struct iw_handler_def ieee80211_iw_handler_def = { #define N(a) (sizeof (a) / sizeof (a[0])) .standard = (iw_handler *) ieee80211_handlers, /* Array of handlers for standard ioctls * We will call dev->wireless_handlers->standard[ioctl - SIOCIWFIRST] */ .num_standard = N(ieee80211_handlers), /* Number of handlers defined*/ .private = (iw_handler *) ieee80211_priv_handlers, /*私有ioctl处理函数*/ .num_private = N(ieee80211_priv_handlers), .private_args = (struct iw_priv_args *) ieee80211_priv_args, /* Arguments of private handler. Private ioctl interface information */ .num_private_args = N(ieee80211_priv_args), #if WIRELESS_EXT > 18 .get_wireless_stats = ieee80211_iw_getstats /* Wireless statistics (used for /proc/net/wireless)*/ #endif #undef N }; |
ath_ioctl -->ath_ucfg_create_vap -->osif_ioctl_create_vap -->ieee80211_ioctl_vattach |
void ieee80211_ioctl_vattach(struct net_device *dev) { #if WIRELESS_EXT <= 18 dev->get_wireless_stats = ieee80211_iw_getstats; #endif dev->wireless_handlers = &ieee80211_iw_handler_def; } |
可以看出无论标准ioctl还是私有ioctl其设备处理的入口是dev->wireless_handlers;
现在来看wireless_process_ioctl的代码:
/* * Main IOCTl dispatcher. * Check the type of IOCTL and call the appropriate wrapper... */ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private) /*standard--> ioctl_standard_call private--> ioctl_private_call */ { struct iwreq *iwr = (struct iwreq *) ifr; struct net_device *dev; iw_handler handler;
/* Permissions are already checked in dev_ioctl() before calling us. * The copy_to/from_user() of ifr is also dealt with in there */
/* Make sure the device exist */ if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) return -ENODEV;
/* A bunch of special cases, then the generic case... * Note that 'cmd' is already filtered in dev_ioctl() with * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ if (cmd == SIOCGIWSTATS) //获取无线统计数据 return standard(dev, iwr, cmd, info, &iw_handler_get_iwstats);
#ifdef CONFIG_WEXT_PRIV if (cmd == SIOCGIWPRIV && dev->wireless_handlers) //来获取私有ioclt的描述信息 return standard(dev, iwr, cmd, info, iw_handler_get_private); //最终调用iw_handler_get_private实现,拷贝dev->wireless_handlers->private_args的内容; #endif
/* Basic check */ if (!netif_device_present(dev)) return -ENODEV;
/* New driver API : try to find the handler */ handler = get_handler(dev, cmd); /*通过cmd参数信息,检索dev->wireless_handlers->standard、dev->wireless_handlers-> private两类函数表,返回对应的处理函数*/ if (handler) { //区分standard和private两类处理进行处理,其实最后还是由handler完成; /* Standard and private are not the 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 ioctl handler */ if (dev->netdev_ops->ndo_do_ioctl) return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); return -EOPNOTSUPP; } |
static iw_handler get_handler(struct net_device *dev, unsigned int cmd) { /* Don't "optimise" the following variable, it will crash */ unsigned int index; /* *MUST* be unsigned */ const struct iw_handler_def *handlers = NULL;
#ifdef CONFIG_WIRELESS_EXT if (dev->wireless_handlers) handlers = dev->wireless_handlers; #endif
if (!handlers) return NULL;
/* Try as a standard command */ //ioctl号从0x8B00开始 index = IW_IOCTL_IDX(cmd); //#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) if (index < handlers->num_standard) return handlers->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; } |