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-07 21:52:50

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

ORACLE数据库SQL语句的执行过程

首先是最简单链接数据库的过程,JDBC标准的链接的过程: 1. 载入JDBC驱动程序,一般来说载入驱动程序,采用的都是利用Class.forName()反射来加载驱动 Oracle: Class.forName("oracle.jdbc.driver.OracleDriver"); SQLServer: Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver"); MySql: Class.forNam

jsp的组成和执行过程

jsp由以下五个组成: Html静态页面 指令:  <%@  xxx  %> 小脚本:<%   xxx   %> 表达式:<% =       %> 声明:  <%!   xxx  %> 注释: html注释 <!-- html注释 -->  jsp注释 <%--jsp注释 --%> 脚本中的注释(java注释) /* 多行注释 */ //单行注释   sql注释 -- 执行过程: 翻译阶段 编译阶段 执行阶段 翻译   编译   执

一个C#程序的执行过程

可能很多人都知道我们把程序打包成dll就丢出去了,但是里面的具体的执行过程是怎么样的呢. 程序集是由元数据和IL组成的.IL是和CPU无关的语言,是微软的几个专家请教了外面的编译器的作则,开发出来的.IL比大多数机器语言都要高级一点.IL能够访问和操作对象类型,并提高了指令来初始化对象,调用对象上的虚方法以及直接操作数组元素. 比如下面这个例子 class Program { static void Main(string[] args) { Console.WriteLine("Hello&q

mysql(1)—— 详解一条sql语句的执行过程

SQL是一套标准,全称结构化查询语言,是用来完成和数据库之间的通信的编程语言,SQL语言是脚本语言,直接运行在数据库上.同时,SQL语句与数据在数据库上的存储方式无关,只是不同的数据库对于同一条SQL语句的底层实现不同罢了,但结果相同.这有点类似于java中接口的作用,一个接口可以有不同的实现类,不同的实现类对于接口中方法的实现方式可以不同,结果可以相同.这里SQL语言的作用就类似于java中的接口,数据库就类似于java中接口的实现类,SQL语句就类似于java接口中的方法.不同的是java中

高程(4):执行环境、作用域、上下文执行过程、垃圾收集、try...catch...

高程三 4.2.4.3 一.执行环境 1.全局执行环境是最外层的执行环境. 2.每个函数都有自己的执行环境,执行函数时,函数环境就会被推入一个当前环境栈中,执行完毕,栈将其环境弹出,把控制器返回给之前的执行环境. 二.作用域 1.每个执行环境,都对应一个自己的作用域. 2.每个执行环境,都能访问上一级的父级.父父级....作用域,称为 "作用域链" 3.执行代码时,会按照标识符沿着作用域链一级一级向上查找.如果找不到,则会报错 *标志符:执行时,使用到的变量或函数 三.上下文执行过程

通过源码了解ASP.NET MVC 几种Filter的执行过程

一.前言 之前也阅读过MVC的源码,并了解过各个模块的运行原理和执行过程,但都没有形成文章(所以也忘得特别快),总感觉分析源码是大神的工作,而且很多人觉得平时根本不需要知道这些,会用就行了.其实阅读源码是个很好的习惯,它不只停留在知道怎么用的阶段,而是让我们知道一系列的为什么,为什么这样设计,为什么这样使用....很多朋友应该看过<asp.net x 框架揭秘>这本书,确实不错,特别是边看源码边看书,可以有不小的收获.Ok,我不是大神,我只是心血来潮想看一下源码! 二.几种常见的Filter

JAVA编译和执行过程

Java代码编译是由Java源码编译器来完成,流程图如下所示: Java字节码的执行是由JVM执行引擎来完成,流程图如下所示: Java代码编译和执行的整个过程包含了以下三个重要的机制: Java源码编译机制 类加载机制 类执行机制 Java源码编译机制 Java 源码编译由以下三个过程组成: 分析和输入到符号表 注解处理 语义分析和生成class文件 流程图如下所示: 最后生成的class文件由以下部分组成: 结构信息.包括class文件格式版本号及各部分的数量与大小的信息 元数据.对应于Ja

JSP基本构成和执行过程

JSP(Java Server Page)页面是指扩展名为 .jsp 的文件. JSP是服务器端运行的页面,不像html文件直接就可以在浏览器中运行.JSP页面必须部署到web容器中编译成Servlet才能执行,可以说,JSP就是Servlet的一种形式. 事实上,JSP是Servlet发展的产物,关于JSP和Servlet的关系以后再在博客中介绍. JSP基本页面由指令标签,HTML标记语言,注释,Java代码,JSP动作标签5个部分组成. 1.JSP指令标签不会产生任何内容输出到网页中,主要

NameNode跟secondarynamenode的执行过程

一.NameNode详解 文件包括: fsimage:元数据镜像文件.存储某一时段NameNode内存元数据信息. edits:操作日志文件. fstime:保存最近一次checkpoint的时间 以上这些文件是保存在linux的文件系统中. /data/hadoop/hdfs/name [[email protected] name]$ ls current  image  in_use.lock  previous.checkpoint [[email protected] name]$ c