Iwpriv工作流程及常用命令使用之二
=>main
=>set_private
=>iw_get_priv_info获取wireless网卡所能处理的所有wlan_private_args类型.
=>wext_handle_ioctl
=>wireless_process_ioctl
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
return ioctl_standard_call(dev, ifr, cmd,
&iw_handler_get_private);
static int ioctl_standard_call(struct net_device * dev,
struct ifreq * ifr,
unsigned int cmd,
iw_handler handler)
{
...
/* Call the handler */
ret = handler(dev, &info, &(iwr->u), extra);
if (user_length < iwr->u.data.length) {
kfree(extra);
return -E2BIG;
//通知iwpriv,本wifi网卡对应的private命令还没有完,还有,这样iwpriv将会继续
//maxpriv默认为16,即将以16个为一组,一组一组的从wifi网卡驱动读取该网卡所能支持的所有private_args参数
//newpriv = realloc(priv, maxpriv * sizeof(priv[0]));继续申请,继续拷贝,知道将wifi网卡自定义的wlan_private_args参数全部
//传出到iwpriv为止.
}
...
}
/* New driver API : try to find the handler */
handler = get_handler(dev, cmd);//获取
/* Standard and private are not the same */
if (cmd < SIOCIWFIRSTPRIV)
return ioctl_standard_call(dev, ifr, cmd, handler);
else
return ioctl_private_call(dev, ifr, cmd, handler);
}
/* Old driver API : call driver ioctl handler */
if (dev->do_ioctl)
//如果dev->wireless_handlers->standard和dev->wireless_handlers->private[index都不对该cmd作处理,那么由
//dev->do_ioctl = wlan_do_ioctl;我们驱动的最后处理函数wlan_do_ioctl处理.
return dev->do_ioctl(dev, ifr, cmd);
{
/* Don't "optimise" the following variable, it will crash */
unsigned int index; /* *MUST* be unsigned */
if (dev->wireless_handlers == NULL)
return NULL;
index = cmd - SIOCIWFIRST;
if (index < dev->wireless_handlers->num_standard)
return dev->wireless_handlers->standard[index];
index = cmd - SIOCIWFIRSTPRIV;//
return dev->wireless_handlers->private[index];//该private命令的handler.
/* Not found */
return NULL;
}
num_standard:sizeof(wlan_handler) / sizeof(iw_handler),
num_private:sizeof(wlan_private_handler) / sizeof(iw_handler),
num_private_args:sizeof(wlan_private_args) / sizeof(struct iw_priv_args),
standard:(iw_handler *) wlan_handler,
private:(iw_handler *) wlan_private_handler,
private_args:(struct iw_priv_args *) wlan_private_args,
#if WIRELESS_EXT > 20
get_wireless_stats:wlan_get_wireless_stats,
#endif
};
"extscan"/ "hostcmd"/ "arpfilter"/ "regrdwr"/ "sdcmd52rw"/
"sdcmd53rw"/ "setgetconf"/ "getcis"/ "scantype"/ "deauth"
"getNF"/ "getRSSI"/ "bgscan"/ "enable11d"/ "adhocgrate"
"sdioclock"/ "wmm"/ "uapsdnullgen"/ "setcoalescing"/ "adhocgprot"
"setpowercons"/ "wmm_qosinfo"/ "lolisteninter"/ "fwwakeupmethod"
"psnullinterval"/ "bcnmisto"/ "adhocawakepd"/ "moduletype"
"autodeepsleep"/ "enhanceps"/ "wakeupmt"/ "setrxant"/ "settxant"
"authalgs"/ "encryptionmode"/ "setregioncode"/ "setlisteninter"
"setmultipledtim"/ "setbcnavg"/ "setdataavg"/ "associate"/ "getregioncode"
"getlisteninter"/ "getmultipledtim"/ "gettxrate"/ "getbcnavg"
"getdataavg"/ "getrxant"/ "gettxant"/ "gettsf"/ "wpssession"
"deepsleep"/ "adhocstop"/ "radioon"/ "radiooff"/ "rmaeskey"
"crypto_test"/ "reasso-on"/ "reasso-off"/ "wlanidle-on"/ "wlanidle-off"
"sleepparams"/ "requesttpc"/ "powercap"/ "measreq"/ "bca-ts"
"scanmode"/ "getadhocstatus"/ "setgenie"/ "getgenie"/ "qstatus"
"ts_status"/ "setaeskey"/ "getaeskey"/ "version"/ "verext"/ "setwpaie"
"setband"/ "setadhocch"/ "chanswann"/ "getband"/ "getadhocch"
"getlog"/ "tpccfg"/ "scanprobes"/ "ledgpio"/ "sleeppd"/ "rateadapt"
"getSNR"/ "getrate"/ "getrxinfo"/ "atimwindow"/ "bcninterval"/ "sdiopullctrl"
"scantime"/ "sysclock"/ "txcontrol"/ "hscfg"/ "hssetpara"/ "inactoext"
"dbgscfg"/ "drvdbg"/ "drvdelaymax"/ "intfctrl"/ "setquietie"/ ""
"setuserscan"/ "getscantable"/ "setmrvltlv"/ "getassocrsp"/ "addts"
"delts"/ "qconfig"/ "qstats"/ "txpktstats"/ "getcfptable"/ "mefcfg"
"getmem"
1.应用层程序iwpriv
wireless tools网络配置应用程序iwpriv命令格式:
iwpriv ethX private-command [parameters]
int main(int argc, char *argv[])
{
...
sockfd = socket(AF_INET, SOCK_STREAM, 0);
...
ioctl(sockfd, ioctl_val, &iwr);//将控制命令通过ioctl发送到无线网卡
...
}
====================
2.系统调用sys_ioctl
应用层通过ioctl(sockfd, ioctl_val, &iwr);触发sys_ioctl系统调用,实际流程:
sys_ioctl=>vfs_ioctl=>do_ioctl=最后调用
filp->f_op->unlocked_ioctl执行具体的ioctl操作,该操作就是sock_ioctl,至于为什么是sock_ioctl,后边作了进一步分析
sock_ioctl=>
{
...
#ifdef CONFIG_WIRELESS_EXT
if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
err = dev_ioctl(net, cmd, argp);//
#endif
...
}
dev_ioctl=>wext_handle_ioctl
{
...
/* Take care of Wireless Extensions */
if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
return wext_handle_ioctl(net, &ifr, cmd, arg);
...
}
wext_handle_ioctl=>wireless_process_ioctl=>
然后通过if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL)函数,
从系统管理的net链表中,把ioctl指定的ethX对应的struct net_device摘出来,
最后调用ioctl_private_call(handler)或者调用dev->do_ioctl(dev, ifr, cmd)来处理该ioctl,
这两个函数分别指向wlan_handler_def和wlan_do_ioctl
====================
3.wifi网卡是怎么登记到kernel上的
wlan_probe()=>wlan_add_card()=>alloc_etherdev()=>
之后将操作方法添加到struct net_device *dev=alloc_etherdev()申请的dev上去,其中包括:
...
/* Setup the OS Interface to our functions */
dev->open = wlan_open;
dev->hard_start_xmit = wlan_hard_start_xmit;
dev->stop = wlan_close;
dev->do_ioctl = wlan_do_ioctl;
dev->set_mac_address = wlan_set_mac_address;
dev->get_stats = wlan_get_stats;
dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
dev->wireless_handlers = (struct iw_handler_def *) &wlan_handler_def;
dev->set_multicast_list = wlan_set_multicast_list;
...
4.socket系统调用如何关联上ioctl和ethX设备
接下来从net_families全局管理结构体中找到当前family对应的ops操作集,
net_proto_family *pf=net_families[family];
pf->create(net, sock, protocol);//核心调用,对于ipv4,就是inet_create
以ipv4为例
static struct net_proto_family inet_family_ops = {
.family = PF_INET,
.create = inet_create,
.owner = THIS_MODULE,
};
还记得上面应用层创建sokcet的函数吧,
sockfd = socket(AF_INET, SOCK_STREAM, 0);//AF_INET虽然等于PF_INET,但是因为种种原因我们提倡使用PF_INET
可见family等于AF_INET,type等于SOCK_STREAM,协议protocol为0,也就是采用IP协议,
inet_create=>inetsw[sock->type]也就是inetsw[SOCK_STREAM],
从inetsw[sock->type]中找到已经登记的protocol网络协议处理函数,
inetsw[]是怎么填充的呢?inet_init()=>inet_register_protosw(inetsw_array)=>这样inetsw_array中的所有protocol处理模块都将登记到inetsw中了,
static struct inet_protosw inetsw_array[] =
{
{
.type = SOCK_STREAM,
.protocol = IPPROTO_TCP,
.prot = &tcp_prot,
.ops = &inet_stream_ops,
.capability = -1,
.no_check = 0,
.flags = INET_PROTOSW_PERMANENT | INET_PROTOSW_ICSK,
},
.type = SOCK_DGRAM,
.protocol = IPPROTO_UDP,
.prot = &udp_prot,
.ops = &inet_dgram_ops,
.capability = -1,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_PERMANENT,
},
.type = SOCK_RAW,
.protocol = IPPROTO_IP, /* wild card */
.prot = &raw_prot,
.ops = &inet_sockraw_ops,
.capability = CAP_NET_RAW,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_REUSE,
}
};
至 于inet_init,则是以fs_initcall(inet_init)方式,以5号优先级被build in到了内核中,当kernel启动时会在start_kernel=>rest_init=>kernel_init=> do_basic_setup=>do_initcalls中依据优先级号优先于其他module驱动被调用.
这样sock->ops = answer->ops;对于ipv4也就等于inet_stream_ops,
接下来就是将ops填充到file操作指针中了,
sys_socket=>sock_map_fd=>sock_attach_fd=>
dentry->d_op = &sockfs_dentry_operations;
init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE, &socket_file_ops);
file->private_data = sock;
其中init_file=>file->f_op = fop;也就是file->f_op = socket_file_ops;
所以read(),wirte(),poll()和ioctl()应用程序调用的file->f_op就是socket_file_ops了,
比如:
read()对应sock_aio_read网络异步读
write()对应sock_aio_write网络异步写
ioctl()对应sock_ioctl
static const struct file_operations socket_file_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.aio_read = sock_aio_read,
.aio_write = sock_aio_write,
.poll = sock_poll,
.unlocked_ioctl = sock_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_sock_ioctl,
#endif
.mmap = sock_mmap,
.open = sock_no_open, /* special open code to disallow open via /proc */
.release = sock_close,
.fasync = sock_fasync,
.sendpage = sock_sendpage,
.splice_write = generic_splice_sendpage,
};
网卡控制因为涉及到的知识点比较多,上面只是从宏观上对数据流程做了一个简单的介绍,深入到其中的每个知识点,都会牵扯出一系列文章,读者需要自己去一个个的慢慢深入,希望本文能够对刚刚接触网络驱动的读者有所帮助和启发【gliethttp.Leith】
wlan_add_card=>
wlan_create_thread(wlan_service_main_thread, &priv->MainThread, "wlan_main_service");
=>wlan_service_main_thread=>wlan_exec_next_cmd=>
将调用wlan_enter_ps和wlan_exit_ps
在mmc_signal_sdio_irq=>将调用wake_up_process(host->sdio_irq_thread);来唤醒该irq处理线程,可能还有其他命令需要处理wlan_exec_next_cmd
这个pxamci_irq就是mmc的物理irq中断了,pxamci_irq=>mmc_signal_sdio_irq(host->mmc);
那么就会执行wlan_dnld_cmd_to_fw(wlan_private * priv, CmdCtrlNode * CmdNode)将CmdNode中的数据下发下去,
然后重新触发wlan_mod_timer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_5S);
也就是wlan_cmd_timeout_func命令超时处理函数,
在cmd已经有了恢复之后,在主线程中调用wlan_process_cmdresp,立即调用wlan_cancel_timer(&Adapter->MrvDrvCommandTimer);来删除定时器
====
/* Execute the next command */
if (!priv->wlan_dev.cmd_sent && !Adapter->CurCmd)
wlan_exec_next_cmd(priv);
====
wlan_hostcmd_ioctl=>
获取一个空闲的CmdNode节点wlan_get_cmd_node,当完成赋值之后,执行如下语句,将CmdNode节点添加到处理队列中:
wlan_insert_cmd_to_pending_q(Adapter, CmdNode, TRUE);
wake_up_interruptible(&priv->MainThread.waitQ);
另外在数组中
/*
* iwconfig settable callbacks
*/
static const iw_handler wlan_handler[]这个数组中全部是回调函数,
struct iw_handler_def wlan_handler_def = {
num_standard:sizeof(wlan_handler) / sizeof(iw_handler),
num_private:sizeof(wlan_private_handler) / sizeof(iw_handler),
num_private_args:sizeof(wlan_private_args) / sizeof(struct iw_priv_args),
standard:(iw_handler *) wlan_handler,
private:(iw_handler *) wlan_private_handler,
private_args:(struct iw_priv_args *) wlan_private_args,
#if WIRELESS_EXT > 20
get_wireless_stats:wlan_get_wireless_stats,
#endif
};
在wlan_add_card函数中
dev->wireless_handlers = (struct iw_handler_def *) &wlan_handler_def;
{
/* Don't "optimise" the following variable, it will crash */
unsigned int index; /* *MUST* be unsigned */
if (dev->wireless_handlers == NULL)
return NULL;
index = cmd - SIOCIWFIRST;
if (index < dev->wireless_handlers->num_standard)
return dev->wireless_handlers->standard[index];
index = cmd - SIOCIWFIRSTPRIV;
if (index < dev->wireless_handlers->num_private)
return dev->wireless_handlers->private[index];
return NULL;
}
=>dev_ioctl
+++/* Take care of Wireless Extensions */
+++if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
+++return wext_handle_ioctl(net, &ifr, cmd, arg);
=>wext_handle_ioctl
=>wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd)
=>get_handler(dev, cmd);如果没有实现该cmd,那么将调用dev->do_ioctl来处理,
wmm_start_queue=>
wlan_tx_packet=>
wlan_tx_timeout=>
wlan_remove_card=>
wlan_hostcmd_ioctl=>
wlan_auto_deep_sleep=>
wlan_set_deep_sleep=>
wlan_prepare_cmd=>
wlan_cmd_timeout_func=>
将调用wake_up_interruptible(&priv->MainThread.waitQ);唤醒wlan_service_main_thread主处理线程.
dev->tx_timeout = wlan_tx_timeout;
wlan_initialize_timer(&Adapter->MrvDrvCommandTimer, wlan_cmd_timeout_func, priv);
{
...
case WLAN_WAKEUP_MT:
if (wrq->u.data.length > 0)
Adapter->IntCounter++;
wake_up_interruptible(&priv->MainThread.waitQ);
break;
...
}
wlan_insert_cmd_to_free_q=>wlan_clean_cmd_noder,从命令链表上删除已经处理完成的cmd_node,
wlan_clean_cmd_noder然后pTempNode->CmdWaitQWoken = TRUE;同时如果该cmd_node是一个被阻塞等待的,那么唤醒等待的程序.
wake_up_interruptible(&pTempNode->cmdwait_q);
set (8BE2) : set 1024 char & get 0
connStatus (0004) : set 1024 char & get 2047 char
driverVer (0005) : set 1024 char & get 2047 char
bainfo (0006) : set 1024 char & get 2047 char
descinfo (0007) : set 1024 char & get 2047 char
radio_off (000A) : set 1024 char & get 2047 char
radio_on (000B) : set 1024 char & get 2047 char
show (0015) : set 1024 char & get 2047 char
adhocEntry (0016) : set 1024 char & get 2047 char
bbp (8BE3) : set 2047 char & get 2047 char
mac (8BE5) : set 1024 char & get 1024 char
rf (8BF3) : set 2047 char & get 2047 char
e2p (8BE7) : set 1024 char & get 1024 char
stat (8BE9) : set 0 & get 2047 char
iwpriv ra0 set SSID=""
iwpriv ra0 set Channel=0
iwpriv ra0 set NetworkType=Infra
iwpriv ra0 set AuthMode=SHARED
iwpriv ra0 set EncrypType=WEP
iwpriv ra0 set DefaultKeyID=1
iwpriv ra0 set Key1="whatever"
iwpriv ra0 set SSID="some_ssed"
iwpriv ra0 set WPAPSK="wpa_key"
iwpriv ra0 show NetworkType
iwpriv ra0 show Key1
iwpriv ra0 show WPAPSK
ra0 show:
SSID
WirelessMode
TxBurst
TxPreamble
TxPower
Channel
BGProtection
RTSThreshold
FragThreshold
HtBw
HtMcs
HtGi
HtOpMode
HtExtcha
HtMpduDensity
HtBaWinSize
HtRdg
HtAmsdu
HtAutoBa
CountryRegion
CountryRegionABand
CountryCode
PktAggregate
WmmCapable
IEEE80211H
NetworkType
WPAPSK
AutoReconnect
AuthMode
EncrypType
DefaultKeyID
Key1
Key2
Key3
Key4
PMK
轉自:http://hi.baidu.com/fghzone/blog/item/4131382a6a57ff88033bf6f0.html
Iwpriv工作流程及常用命令使用之二的更多相关文章
- Iwpriv工作流程及常用命令使用
iwpriv工具通过ioctl动态获取相应无线网卡驱动的private_args所有扩展参数 iwpriv是处理下面的wlan_private_args的所有扩展命令,iwpriv的实现上,是这样的, ...
- git详情、git工作流程、常用命令、忽略文件、分支操作、gitee远程仓库使用
今日内容概要 git详情 git工作流程 git常用命令 过滤文件 分支操作 git远程仓库使用 可参照:https://www.cnblogs.com/liuqingzheng/p/15328319 ...
- git flow 工作流程以及常用命令
一.分支介绍 master 也是产品分支,只有一个,一般情况下不会在这个分支上进行代码操作 develop 只有一个,新特性的开发是基于 develop 开发的,但是不能直接在 develop 上进行 ...
- Linux常用命令大全(二)
Linux常用命令大全(二) cp命令 将源文件或目录复制到目标文件或目录中 注:如果是目录,需要使用-r选项 -d 复制时保留文件链接 -f 如果现存的目标文件不能打开,则删除并重试 -i 在覆盖目 ...
- Linux 常用命令随笔(二)
Linux 常用命令随笔(二) 1.RPM RPM是RedHat Package Manager(RedHat软件包管理工具) 1.1.安装软件包 rpm -ivh ***.rpm 其中i表示安装,v ...
- Git 工作原理以及常用命令操作
GIT工作原理 要了解GIT工作原理,先了解GIT的这几块区域: 工作区域划分 工作区:指的是本地工作空间,如果刚拉取下来的代码,没有修改的内容,这块区域是空白的 (modified-已修改状态) 暂 ...
- git开发流程、常用命令及工具、TortoiseGit使用及常见问题
根据我最近使用git的一些经历,git是基于分支的版本控制工具,分支有远程分支和本地分支. 一.开发流程 - 从远程服务器的master,clone一份项目文件到本地,然后本地master的基础上br ...
- [工作需求]linux常用命令以及vim常用命令
一. Linux 常用命令 mkdir dirname新建文件夹 cd ~ 进入自己的家目录 cd dirname 进入名字为dirname的目录: l 显示当前文件夹下的文件 ...
- Linux部分常用命令学习(二)
1.wc:wc命令是一个统计的工具,主要用来显示文件所包含的行.字和字节数.wc命令是word count的缩写. 命令格式:wc [选项参数] [文件] 选项参数: -c 统计字节数 -l 统计行数 ...
随机推荐
- 【redis】02string类型和hash类型
Redis的数据类型 Redis主要分为五个数据类型,一个是string,最简单的一个数据类型,hash,list, 还有set集合,还有zset有序集合,这是咱们redis的五种基础类型, 接下 ...
- [转载]Java学习这七年
从2005那会做自动化测试开始接触Java开始,至今近7年.今天正好项目结束,趁机整理下思路,确定后续方向. 前三个年头基本上集中于Java基础的学习,包括设计模式,从完全不懂,到看的懂但似乎又不懂, ...
- JsRender系列demo-对null 和boolen类型数据的探讨
废话不说了,直接上代码 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <he ...
- SDUT2087离散事件模拟-银行管理
呃,这个题,我只想仰天长啸:无语死我了,还动用了繁和帅锅给我改,妹的,做题一定要仔细仔细再仔细啊,这种小错误都犯真是该打. 题目描述 现在银行已经很普遍,每个人总会去银行办理业务,一个好的银行是要考虑 ...
- jmeter 使用聚合报告分析jtl文件
对于jmeter测试生成产生的jtl文件除了使用jemter插件来产生csv或者结果,还可以直接用聚合报告来打开,下面来介绍一下怎么操作. 1. 产生jtl文件 注意,默认情况下聚合报告插件只能分析聚 ...
- eclipse中(装了插件m2eclipse后的)导入maven工程显示"感叹号"
有时候导入一些开源工程(maven结构的),在eclipse中(装了插件m2eclipse后的)该工程前面会有一个小的红色感叹号,但点开工程后没有发现有打小红叉的内容,这种情况其实大部分是jar包 ...
- asp.net 权限问题
asp.net项目中通过Web.config配置文件及文件夹的访问权限! http://blog.csdn.net/qingyun1029/article/details/6184723
- java:I/O 字节流和字符流
字节流 InputStream和OutputStream的子类:FileInputStream 和 FileOutputStream 方法: int read(byte[] b,int off,int ...
- 转AOP 介绍
来自:http://blog.csdn.net/a906998248/article/details/7514969 这篇也不错,详细介绍了CGLIP http://blog.jobbole.com/ ...
- Map.putAll方法——追加另一个Map对象到当前Map集合(转)
该方法用来追加另一个Map对象到当前Map集合对象,它会把另一个Map集合对象中的所有内容添加到当前Map集合对象. 语法 putAll(Map<? extends K,? extends V ...