Chinaunix首页 | 论坛 | 博客
  • 博客访问: 543768
  • 博文数量: 51
  • 博客积分: 345
  • 博客等级: 民兵
  • 技术积分: 534
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-21 12:02
个人简介

文章分类

全部博文(51)

文章存档

2023年(2)

2022年(1)

2021年(7)

2020年(10)

2019年(2)

2016年(20)

2015年(5)

2014年(1)

2011年(3)

我的朋友

分类: 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

         对用户空间来说32ioctl是不够用的,所有Wireless Extension 15引入了sub-ioctls

 

驱动是如何提取由iwpriv传输的数据?

1、  若数据固定且小于16B,那么存放在struct iwreq的‘u.name’字段;

2、  如果数据不固定,且大于16Bstruct 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->standarddev->wireless_handlers-> private两类函数表,返回对应的处理函数*/

              if (handler) {    //区分standardprivate两类处理进行处理,其实最后还是由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;

}

阅读(8009) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~