wifi配置工具iw源码解析
来源:互联网 发布:mysql set 动态参数 编辑:程序博客网 时间:2024/06/11 09:34
iw是一个基于nl80211接口的无线配置工具,用于替代原先基于wext接口的iwconfig。iw源码可以在网址 https://www.kernel.org/pub/software/network/iw/ 获取,或者使用git命令从http://git.kernel.org/?p=linux/kernel/git/jberg/iw.git. 中下载。
1、简单的nl80211程序
iw的源码主体在iw.c文件里,其他文件都是一些命令选项的实现。
4.9版本的iw.c源码有586行,也不是很多,但是通过去掉程序参数解析源码和命令匹配源码,就可以得到iw.c最核心的代码,也是一个最简单的使用nl80211命令配置无线网卡的例程。
/** * 该程序使用nl80211命令从内核中读取wlan0接口信息, * 然后在回调函数中解析信息,打印出wlan0的接口类型。 */#include "netlink/netlink.h"#include "netlink/genl/genl.h"#include "netlink/genl/ctrl.h"#include <net/if.h>//从iw复制过来#include "nl80211.h"static int expected_id;static int nl_callback(struct nl_msg* msg, void* arg){ struct nlmsghdr* ret_hdr = nlmsg_hdr(msg); struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; if (ret_hdr->nlmsg_type != expected_id) { // what is this?? return NL_STOP; } struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(ret_hdr); nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb_msg[NL80211_ATTR_IFTYPE]) { int type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]); printf("Type: %d", type); }}int main(int argc, char** argv){ int ret; //给socket分配空间 nl_sock* sk = nl_socket_alloc(); //连接内核的Generic Netlink genl_connect(sk); //获取nl80211的驱动ID expected_id = genl_ctrl_resolve(sk, "nl80211"); //关联回调函数 nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, nlCallback, NULL); //声明一个netlink消息结构体nl_msg,并分配内存空间 nl_msg* msg = nlmsg_alloc(); //设置nl80211的命令,命令类型在nl80211.h定义 //这里NL80211_CMD_GET_INTERFACE是获取一个接口的配置信息 nl80211_commands cmd = NL80211_CMD_GET_INTERFACE; int ifIndex = if_nametoindex("wlan0"); int flags = 0; //向msg变量中填充数据 genlmsg_put(msg, 0, 0, expected_id, 0, flags, cmd, 0); //添加msg消息的属性 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifIndex); //将msg消息发送至内核中 ret = nl_send_auto_complete(sk, msg); //这个函数会一直阻塞,直到该netlink socket得到返回值, //然后自动调用回调函数nl_callback nl_recvmsgs_default(sk); return 0;nla_put_failure: nlmsg_free(msg); return 1;}
上面这个程序与iw的整体执行流程是一样的,首先与内核建立一个nl80211的netlink连接,然后构造一个netlink消息结构,向其填入命令、属性、网卡接口等信息,然后通过netlink连接发送至内核,等待接收返回数据,最后使用回调函数解析返回数据。
2、对section的巧妙使用
iw程序针对各种类型的命令编写了对应的.c文件,每个命令的.c文件是一个独立模块。与常见的程序结构不同,iw中并没有使用.h头文件声明函数,主文件iw.c也没有显示声明外部函数,那它是怎样实现对其他文件中函数的调用的呢?
在每个.c文件中都可以看到几个command宏的应用,现在一步步将这个宏展开。例如如下的宏:
COMMAND(station, dump, "[-v]", NL80211_CMD_GET_STATION, NLM_F_DUMP, CIB_NETDEV, handle_station_dump, "List all stations known, e.g. the AP on managed interfaces");
第一步展开:
__COMMAND(&(__station_station), dump, "dump", "[-v]", NL80211_CMD_GET_STATION, NLM_F_DUMP, 0, CIB_NETDEV, handle_station_dump, "List all stations known, e.g. the AP on managed interfaces", NULL)
第二步展开:
static struct cmd __cmd_dump_handle_station_dump_NL80211_CMD_GET_STATION_CIB_NETDEV_0 __attribute__((used)) __attribute__((section("__cmd"))) = { .name = ("dump"), .args = ("[-v]"), .cmd = (NL80211_CMD_GET_STATION), .nl_msg_flags = (NLM_F_DUMP), .hidden = (0), .idby = (CIB_NETDEV), .handler = (handle_station_dump), .help = ( "List all stations known, e.g. the AP on managed interfaces"), .parent = &(__station_station), .selector = (NULL), }
可以看到,COMMAND最终声明了一个cmd结构体变量,这个结构体变量使用了gcc编译属性__attribute__。__attribute__((used))指示编译器在对象文件中保留变量为静态变量,不进行任何空间优化;__attribute__((section(“__cmd”)))指示编译器将这个变量的内存空间位置放置在生成文件的”__cmd”这个段中。
这样就明白了,在iw程序的内存空间的静态变量区有一个“__cmd”段,会顺序存储使用COMMAND宏定义的cmd结构体变量。
cmd结构体有两个重要的成员,一个是
const enum nl80211_commands cmd
它定义了这个cmd的nl80211命令,会填入到发送至内核的nl_msg结构体消息中,内核接收到这个消息,根据命令和相关参数,返回数据。
还有一个就是:
int (*handler)(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id);
这个函数并没有特定的用法,大多情况下是用于注册回调函数,当netlink返回数据后,就会调用所注册的回调函数解析数据。
每个命令的.c文件中都会使用COMMAND、TOPLEVEL这样的宏来定义该命令的cmd结构体变量,这些变量在同一块存储区域顺序存储,主程序只要从这个存储区域的开始位置一个个提取变量,将cmd结构体的name与用户的命令参数匹配,匹配成功,就将cmd结构体的cmd、nl_msg_flags、idby 填入nl_msg消息中发给内核,最后使用handler注册的回调函数。iw程序正是这样做的。
for_each_cmd(cmd) { if (!cmd->handler) continue; if (cmd->parent != sectcmd) continue; /* * ignore mismatch id by, but allow WDEV * in place of NETDEV */ if (cmd->idby != command_idby && !(cmd->idby == CIB_NETDEV && command_idby == CIB_WDEV)) continue; if (strcmp(cmd->name, command)) continue; if (argc > 1 && !cmd->args) continue; match = cmd; break;}
for_each_cmd是一个宏,其定义如下:
#define for_each_cmd(_cmd) \ for (_cmd = &__start___cmd; _cmd < &__stop___cmd; \ _cmd = (const struct cmd *)((char *)_cmd + cmd_size))
所以for_each_cmd(cmd)展开就是
for (cmd= &__start___cmd; cmd < &__stop___cmd; cmd = (const struct cmd *)((char *)cmd+ cmd_size))
GCC链接器会以section的名称”name”自动生成符号__start_”name”和__end_”name”,分别指示这个section存储区域的开始位置和结束位置,所以就有__start___cmd和__end___cmd。
- wifi配置工具iw源码解析
- iw工具源码编译
- WIFI工具移植之IW工具移植
- iw工具
- wifi iw tool introduce
- wifi iw tool introduce
- iw 工具下载地址
- 使用wifi网卡笔记2----概念及工具iw(STA模式)
- 五十三 wifi配置工具
- iw工具安装和使用
- iw工具安卓移植
- iw
- 五十三 wifi 无线网络配置工具
- siege工具源码解析
- WIFI P2P (WIFI直连)源码解析
- WIFI P2P (WIFI直连)源码解析
- Wifi模块配置工具WIZSmartScript详细介绍
- Mac OS下的wifi配置工具
- leetcode 74|240. Search a 2D Matrix 1|II
- android 找不到符号 符号 RequiresApi
- 编译原理(三) 消除文法左递归
- 终端自适应js操作代码实例,不同屏幕比例尺寸
- 工业相机SDK接口使用总结
- wifi配置工具iw源码解析
- bzoj 2796: [Poi2012]Fibonacci Representation 记忆化搜索
- 欢迎使用CSDN-markdown编辑器
- jsp中EL 表达式的用法
- 2017 Clion PyCharm激活码
- 关于直播网站的搭建--第二步:关于非法请求的拦截
- Flume架构以及应用介绍
- MySql的存储引擎(表类型)
- ALV调用的几个标准函数