WEXT driver的执行过程实现(iwpriv部分/softapcontroller)

之前在看wifi driver源代码时一直有一个疑惑就是net dev的wireless_handlers中(WEXT类型的接口)提供两个iw_handler接口,怎么知道上层是调用的是private中的函数还是standard中的SIOCSIWPRIV接口和SIOCGIWPRIV接口。

问Wifi的FAE,人家也不清楚,后来没办法只好在源代码中找,现在终于有点头绪与大家分享一下。

android 中有个system/netd/目录,在netd下有个softapController.cpp文件实际上该文件实现了程序iwpriv的功能,那么这个程序是干嘛的呢?嘿嘿从名字就可看出啦是给softap下control 命令的。至于这些命令从哪里来,待后续有机会再与大家分享netd部分时再讨论。

 

分析代码的从入口函数开始,构造函数

SoftapController::SoftapController()

mSock = socket(AF_INET,SOCK_DGRAM, 0); //socket调用,这个我们之前有分析过,这个mSock很重要,这就是socket关联的文件描述符接口,上层通过该接口与内核沟通。

其它函数除了getPrivFuncNum外基本都是开给上层的函数接口,用于和底层沟通。我们就分析打开softap执行的第一个函数startDriver

fnum = getPrivFuncNum(iface,"START");//函数用START作为参数,并返回该函数在driver中private中的第几个

ret = ioctl(mSock, fnum, &wrq);//执行指定的(”START”所对应的)程序

 

getPrivFuncNum函数

strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));//指定net device 比如wlan0/eth0

    wrq.u.data.pointer = mBuf;

    wrq.u.data.length = sizeof(mBuf) /sizeof(struct iw_priv_args);

    wrq.u.data.flags = 0;

    if ((ret = ioctl(mSock,SIOCGIWPRIV, &wrq)) < 0) {//获得driver private handler的iw_priv_args

        LOGE("SIOCGIPRIV failed: %d",ret);

        return ret;

    }

    priv_ptr = (struct iw_priv_args*)wrq.u.data.pointer;

    for(i=0;(i < wrq.u.data.length);i++) {

        if (strcmp(priv_ptr[i].name, fname) ==0)//找出指定CMD

            return priv_ptr[i].cmd;

}

之前看这段代码时真是困惑死了,SIOCGIWPRIV明明是standard提供的一个标准接口且在我要调用的wifi driver中并没有实现怎么会调用结果是获得private 的iw_priv_args,目前我先将该疑问留着到后面自然会明白。

 

如下我只分析ioctl(mSock, SIOCGIWPRIV,&wrq)的流程,其它的ioctl流程基本一致只是过程中调用不同的函数。

 

 

如上调用实际上该函数最终通过系统调用调用到kernel space.如下所示

kernel/fs/Ioctl.c

SYSCALL_DEFINE3(ioctl, unsigned int, fd,unsigned int, cmd, unsigned long, arg)

{

……………………………………………………………………..

         error= do_vfs_ioctl(filp, fd, cmd, arg);//调用虚拟文件系统的ioctl

……………………………………………………………..

}

如上系统调用ioctl

int do_vfs_ioctl(struct file *filp,unsigned int fd, unsigned int cmd,

              unsigned long arg)

switch (cmd) {

…………………………………………..

default:

                   if(S_ISREG(filp->f_path.dentry->d_inode->i_mode))

                            error= file_ioctl(filp, cmd, arg);

                   else

                            error= vfs_ioctl(filp, cmd, arg);

                   break;

 

staticlong vfs_ioctl(struct file *filp, unsigned int cmd,

                         unsigned long arg)

{

         int error = -ENOTTY;

 

         if (!filp->f_op)

                   goto out;

 

         if (filp->f_op->unlocked_ioctl) {

                   error = filp->f_op->unlocked_ioctl(filp, cmd, arg);//此处调用的文件描述符接口在创建socket时init_file中赋值file->f_op = fop;

                   if (error == -ENOIOCTLCMD)

                            error = -EINVAL;

                   goto out;

在本例中如上实际上调用了socket的文件描述符,该描述符在创建socket时就提供如“android基于Socket的系统调用实现”中描述。

socket_file_ops. unlocked_ioctl = sock_ioctl

 

如下列出部分commond的宏定义,具体在kernel/include/linux/Wireless.h中定义。

#define SIOCGIWPRIV 0x8B0D

#define SIOCIWFIRSTPRIV 0x8BE0//第一个privatecommand对应位址

#define SIOCIWLASTPRIV 0x8BFF

#define SIOCIWFIRST 0x8B00

#define SIOCIWLAST SIOCIWLASTPRIV 

 

static longsock_ioctl(struct file *file, unsigned cmd, unsigned long arg)

#ifdef CONFIG_WIRELESS_EXT

         if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {// 很明显SIOCGIWPRIV是在条件之内的。

                   err= dev_ioctl(net, cmd, argp);

         }else

#endif

 

kernel/net/core/Dev.c

int dev_ioctl(struct net*net, unsigned int cmd, void __user *arg)

/* Take care of Wireless Extensions */

                   if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)

                            return wext_handle_ioctl(net, &ifr, cmd, arg);

 

kernel/net/wireless/Wext.c

intwext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,

                         void __user *arg)

         ret= wext_ioctl_dispatch(net, ifr, cmd, &info,

                                      ioctl_standard_call,//调用执行driver提供的standard handler

                                       ioctl_private_call);// 调用执行driver提供的private handler

         if(ret >= 0 &&

             IW_IS_GET(cmd) &&

             copy_to_user(arg, ifr, sizeof(structiwreq)))

 

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_func private)

dev_load(net, ifr->ifr_name);//根据名字得到net

rtnl_lock();

         ret= wireless_process_ioctl(net, ifr, cmd, info, standard, private);

         rtnl_unlock();

 

void dev_load(struct net *net, const char*name)

{

         structnet_device *dev;

 

         read_lock(&dev_base_lock);

         dev= __dev_get_by_name(net, name);

         read_unlock(&dev_base_lock);

 

         if(!dev && capable(CAP_NET_ADMIN))

                   request_module("%s",name);

}

//dev_load通过name获取net的dev,name就是softapcontroller.cpp中getPrivFuncNum的第一个参数iface

 

static int wireless_process_ioctl(structnet *net, struct ifreq *ifr,

                                       unsigned int cmd,

                                       struct iw_request_info *info,

                                       wext_ioctl_func standard,

                                       wext_ioctl_func private)

if(cmd == SIOCGIWSTATS)

                   return standard(dev, iwr,cmd, info,

                                     &iw_handler_get_iwstats);//get status,和SIOCGIWPRIV一样是个特殊的command,从代码跟下去看,wifidriver提供了指定接口。

 

         if (cmd == SIOCGIWPRIV &&dev->wireless_handlers)

                   return standard(dev, iwr, cmd,info,

                                     &iw_handler_get_private); //get private handle的信息(句柄,参数等)

 

static int ioctl_standard_call(structnet_device *  dev,

                                   struct iwreq                 *iwr,

                                   unsigned int                 cmd,

                                   struct iw_request_info      *info,

                                   iw_handler                   handler)

descr = &(standard_ioctl[cmd- SIOCIWFIRST]);//获得指定cmd的一些信息如下有描述该结构体数组

 

         /*Check if we have a pointer to user space data or not */

         if(descr->header_type != IW_HEADER_TYPE_POINT){

 

                   /*No extra arguments. Trivial to handle */

                   ret= handler(dev, info, &(iwr->u), NULL);

 

                   /*Generate an event to notify listeners of the change */

                   if((descr->flags & IW_DESCR_FLAG_EVENT) &&

                      ((ret== 0) || (ret == -EIWCOMMIT)))

                            wireless_send_event(dev,cmd, &(iwr->u), NULL);

         }else {// SIOCGIWPRIV调用下面的函数,其中handler为iw_handler_get_private

                   ret= ioctl_standard_iw_point(&iwr->u.data, cmd, descr,

                                                     handler,dev, info);

         }

 

static const struct iw_ioctl_description standard_ioctl[] = {

         [SIOCSIWCOMMIT  - SIOCIWFIRST] = {

                   .header_type   = IW_HEADER_TYPE_NULL,

         },

-----------------------------------省略号-----------------------------------------------------

[SIOCGIWPRIV          -SIOCIWFIRST] = { /* (handled directly by us) *///看见原注释没,实际作用是获得driver中提供的private handle的个数及对应cmd的位置,以便调用到指定private handle。

                   .header_type   = IW_HEADER_TYPE_POINT,

                   .token_size      = sizeof(struct iw_priv_args),

                   .max_tokens    = 16,

                   .flags                  = IW_DESCR_FLAG_NOMAX,

         },

         [SIOCSIWSTATS         - SIOCIWFIRST] = {

                   .header_type   = IW_HEADER_TYPE_NULL,

         },

         [SIOCGIWSTATS        -SIOCIWFIRST] = { /* (handled directly by us) */ //get status command

                   .header_type   = IW_HEADER_TYPE_POINT,

                   .token_size      = 1,

                   .max_tokens    = sizeof(struct iw_statistics),

                   .flags                  = IW_DESCR_FLAG_DUMP,

         },

-----------------------------------省略号-----------------------------------------------------

 

 

static int ioctl_standard_iw_point(structiw_point *iwp, unsigned int cmd,

                                        const struct iw_ioctl_description *descr,

                                        iw_handler handler, struct net_device *dev,

                                        struct iw_request_info *info)

err = handler(dev,info, (union iwreq_data *) iwp, extra);

 

 

/*---------------------------------------------------------------- */

/*

 * Standard Wireless Handler : get iwpriv definitions

 * Export the driver private handler definition

 * They will be picked up by tools like iwpriv...

 */

static int iw_handler_get_private(structnet_device *           dev,

                                       struct iw_request_info *     info,

                                       union iwreq_data *               wrqu,

                                       char *                     extra)

{

         /*Check if the driver has something to export */

         if((dev->wireless_handlers->num_private_args == 0) ||

            (dev->wireless_handlers->private_args== NULL))

                   return-EOPNOTSUPP;

 

         /*Check if there is enough buffer up there */

         if(wrqu->data.length < dev->wireless_handlers->num_private_args) {

                   /*User space can't know in advance how large the buffer

                    * needs to be. Give it a hint, so that we cansupport

                    * any size buffer we want somewhatefficiently... */

                   wrqu->data.length= dev->wireless_handlers->num_private_args;

                   return-E2BIG;

         }

 

         /* Set the number of available ioctls. */

         wrqu->data.length =dev->wireless_handlers->num_private_args;

 

         /* Copy structure to the user buffer. */

         memcpy(extra, dev->wireless_handlers->private_args,

                sizeof(structiw_priv_args) * wrqu->data.length);

 

         return0;

}

 

如下为某wifi driver中定义的wext接口

const struct iw_handler_defwl_iw_handler_def =

{

         .num_standard= ARRAYSIZE(wl_iw_handler),

         .standard= (iw_handler *) wl_iw_handler,

         .num_private= ARRAYSIZE(wl_iw_priv_handler),

         .num_private_args = ARRAY_SIZE(wl_iw_priv_args),

         .private= (iw_handler *)wl_iw_priv_handler,

         .private_args = (void *) wl_iw_priv_args,

 

#if WIRELESS_EXT >= 19

         get_wireless_stats:dhd_get_wireless_stats,// SIOCGIWSTATS执行的接口

#endif

         };

#endif

 

至此可知道SIOCGIWPRIV实际上是将iface作为net设备名所对应的driver num_private_args及private_args传给上层。接下来再调用对应的privatehandler中的函数.

如start ioctl_private_call

#if WIRELESS_EXT > 12

static const iw_handlerwl_iw_priv_handler[] = {

         NULL,//SIOCIWFIRSTPRIV+0

         (iw_handler)wl_iw_set_active_scan,//SIOCIWFIRSTPRIV+1

         NULL,

         (iw_handler)wl_iw_get_rssi,//SIOCIWFIRSTPRIV+3

         NULL,

         (iw_handler)wl_iw_set_passive_scan,//SIOCIWFIRSTPRIV+5

         NULL,

         (iw_handler)wl_iw_get_link_speed,//SIOCIWFIRSTPRIV+7

         NULL,

         (iw_handler)wl_iw_get_macaddr,//SIOCIWFIRSTPRIV+9

         NULL,

         (iw_handler)wl_iw_control_wl_off,//SIOCIWFIRSTPRIV+11

         NULL,

         (iw_handler)wl_iw_control_wl_on,//SIOCIWFIRSTPRIV+13 所以调用start就是调用driver中该函数。

#ifdef SOFTAP      

 

        

         NULL,

         (iw_handler)iwpriv_set_ap_config,

 

        

        

         NULL,

         (iw_handler)iwpriv_get_assoc_list,

 

        

         NULL,

         (iw_handler)iwpriv_set_mac_filters,

 

        

         NULL,

         (iw_handler)iwpriv_en_ap_bss,

 

        

         NULL,

         (iw_handler)iwpriv_wpasupp_loop_tst,

        

         NULL,

         (iw_handler)iwpriv_softap_stop,

        

         NULL,

         (iw_handler)iwpriv_fw_reload,

#endif

#if defined(CSCAN)

        

         NULL,

         (iw_handler)iwpriv_set_cscan

#endif     

};

 

//start command在如下中定义。

static const struct iw_priv_argswl_iw_priv_args[] =

{

…………………………………………………………………………………………….

         {

                   WL_IW_SET_START,//start 对应command,该command在wifi driver中有定义位址,可根据SIOCIWFIRSTPRIV(第一个privatecmd位址)来计算偏移。该driver中定义:#define WL_IW_SET_START                            (SIOCIWFIRSTPRIV+13)

                   0,

                   IW_PRIV_TYPE_CHAR| IW_PRIV_SIZE_FIXED | MAX_WX_STRING,

                   "START"

         },

 

 

from:http://blog.csdn.net/zjjdyb/article/details/20993117

时间: 2024-10-01 06:05:45

WEXT driver的执行过程实现(iwpriv部分/softapcontroller)的相关文章

Hive源码分析:Driver类运行过程

说明: 本文的源码分析基于hive-0.12.0-cdh5.0.1. 概括 从<hive cli的入口类>中可以知道hive中处理hive命令的处理器一共有以下几种: (1)set SetProcessor,设置修改参数,设置到SessionState的HiveConf里. (2)dfs DfsProcessor,使用hadoop的FsShell运行hadoop的命令. (3)add AddResourceProcessor,添加到SessionState的resource_map里,运行提交

[20170703]SQL语句分析执行过程.txt

[20170703]SQL语句分析执行过程.txt --//正常sql select语句执行需要这些过程,create cursor,parse,execute and fetch. --//dml估计缺少fetch步骤.参考vage的书写的例子,原书的例子存在问题,理解如下脚本对于sql语句如何执行很有益处. --//当然正常的编程很少有人这样写代码的. DECLARE    mcur     NUMBER;    mstat    NUMBER;    v_name   VARCHAR2 (

jvm执行流程(static代码块和初始化快和父类子类执行过程)

大家猜想一下,结果会是什么? 为什么会是这样呢? 1.jvm加载StaticBlock的main方法前,要看SubClass中是否有静态的变量和语句,如果有,先给这些静态的变量分配存储空间和执行静态语句(不是静态方法),且由于SubClass的父类中也有静态的变量,根据继承的特性,则先执行父类Parent的静态数据的初始化,然会执行子类的静态数据的初始化. 2.执行main方法中的new StaticBlock(); 语句,进行Parent的类的实例化因为Parent的静态数据已经实例化,并且在

deluge-shell能处理在执行过程中产生新的console,并在console中执行命令的情况吗?

问题描述 shell能处理在执行过程中产生新的console,并在console中执行命令的情况吗? 在shell执行 deluge-console 命令时会单独打开一个console cli窗口,可在其中执行一系列自定义命令.这个过程我希望全部用shell来实现,请问shell能 处理这种执行过程中出现新的命令执行console的情况吗 解决方案 可以,启动一个cmd.exe

浅谈SEO优化执行过程中的几点弊端

SEO作为近年来流行于站长界的网络推广.营销方式,正越来越被行业内从业人员的重视.一则是相对大部分传统付费营销方式在费用上的缺省,二则是相对传统免费推广方法在效果上的显而易见. 虽然SEO优化是依附于搜索引擎而生存的网站优化方法,但以其各方面的优势被站长们热力追捧,必定具有其不可抗拒的魅力.早些时候,笔者也曾简单介绍了网站seo优化的原因.其中指出网站为什么要做seo优化的5点原因:1.从搜索引擎获得的流量质量高;2.使网站简单易用,加强用户体验;3.长期有效的推广手段;4.可扩展性强;5.性价

Javascript的执行过程简介

正如我们了解的一样,当我们书写了JS程序之后,打开浏览器,我们的代码就可以开始运行了(当然保证你的代码没有问题,才能按照你的预期进行执行).刚才说的是JS执行的一个大的环境,今天我们学习一下,JS在解析器里的一个执行过程. 这个过程分为两个阶段: 进入执行上下文执行代码    变量对象的变化,和这两个阶段息息相关. 在介绍这两个阶段之前,了解相关的概念. 如果变量和执行上下文相关,那么它应该知道在哪里存储数据和怎么访问数据,这种机制叫做变量对象(variable object,简称VO).用于存

查看MSSQL 执行过程中执行状态

  创建一个存储过程:dba_WhatSQLIsExecuting 然后执行这个存储过程就可以查看相关的信息了. MS SQL 执行过程中执行状态,可查看当前正在执行的sql等信息 当前执行到哪句SQL,等,这个可以帮助长时间的SQL执行做进度条. USE [RMA_DWH] GO /****** Object: StoredProcedure [dbo].[dba_WhatSQLIsExecuting] Script Date: 07/12/2013 10:28:27 ******/ SET

从底层简析Python程序的执行过程

  这篇文章主要介绍了从底层简析Python程序的执行过程,包括注入操作码和封装程序等解释器执行层面的知识,需要的朋友可以参考下 最近我在学习 Python 的运行模型.我对 Python 的一些内部机制很是好奇,比如 Python 是怎么实现类似 YIELDVALUE.YIELDFROM 这样的操作码的;对于 递推式构造列表(List Comprehensions).生成器表达式(generator expressions)以及其他一些有趣的 Python 特性是怎么编译的;从字节码的层面来看

javascript-页面js文件解析执行过程

问题描述 页面js文件解析执行过程 在高性能javascript书中有如下讲解,感觉甚是不懂!如下:每个文件必须等到前一个文件下载并执行完成才开始下载.如下图:(http://img.ask.csdn.net/upload/201508/25/1440490986_104397.png) 疑问:一些外部引入的js文件不是不能被执行么,还有那些页面加载完后再执行的js文件,这里为什么是下载并执行呢!又晕了,求大神解答!感谢! 解决方案 这个要看你的htnl怎么写的,如果是外部js,那么肯定是先下载