了解netlink和libnl之后,现在来看nl80211。简单来说,nl80211的核心就是通过netlink机制向Kernel中的无线网卡驱动发送特定的消息。只不过这些消息的类型、参数等都由nl80211.h定义。此处通过一个案例,学习如何通过nl80211触发网卡进行无线网络扫描。
[-->driver_nl80211.c::wpa_driver_nl80211_scan]
static int wpa_driver_nl80211_scan(void *priv,
struct wpa_driver_scan_params *params)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1, timeout;
struct nl_msg *msg, *rates = NULL; // 定义两个nl_msg对象,rates和P2P有关,读者可忽略它
drv->scan_for_auth = 0;
// 创建nl80211消息,其中NL80211_CMD_TRIGGER_SCAN是Nl80211定义的命令,用于触发网络扫描
msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
......// P2P 处理
// 发送netlink消息
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret)
goto nla_put_failure;
......// wpa_supplicant其他处理
......// 错误处理
return ret;
}
上面代码中构造无线网络扫描nl_msg的重要函数nl80211_scan_common代码如下所示。
[-->driver_nl80211.c::nl80211_scan_common]
static struct nl_msg * nl80211_scan_common
(struct wpa_driver_nl80211_data *drv, u8 cmd,
struct wpa_driver_scan_params *params)
{
struct nl_msg *msg;
int err;
size_t i;
// 分配一个nl_msg对象
msg = nlmsg_alloc();
/*
调用nl80211_cmd函数填充nl_msg中的信息,其内部代码如下。
static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg, int flags, uint8_t cmd){
return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,0, flags, cmd, 0);
}
*/
nl80211_cmd(drv, msg, 0, cmd);
/*
nl80211消息的参数通过netlink中的nlattr来存储。NL80211_ATTR_IFINDEX代表
此次操作所指定的网络设备编号。
*/
nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (params->num_ssids) {
struct nl_msg *ssids = nlmsg_alloc();
for (i = 0; i < params->num_ssids; i++) {
nla_put(ssids, i + 1, params->ssids[i].ssid_len,params->ssids[i].ssid);
......
}
// netlink支持消息嵌套,即属性中携带的数据可以是另外一个nl_msg消息
err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
nlmsg_free(ssids);
......
}
......// 其他处理
return msg;
......// 错误处理
}
由上面的例子可知,nl80211其实就是利用netlink机制将一些802.11相关的命令和参数发送给驱动去执行。这些命令和参数信息可通过nl80211头文件查询。
提示 本书后续章节将分析wpa_supplicant8,读者可参考external/wpa_supplicant8/wpa_supplicant/src/drivers/nl80211_copy.h。
首先,nl80211_copy.h定义其支持的命令,如下所示。
[-->nl80211_copy.h]
enum nl80211_commands {
NL80211_CMD_UNSPEC,
NL80211_CMD_GET_WIPHY,
NL80211_CMD_SET_WIPHY,
......
NL80211_CMD_GET_INTERFACE,
NL80211_CMD_SET_INTERFACE,
......
NL80211_CMD_SET_BSS,
NL80211_CMD_SET_REG,
......// 一共定义了94条命令
}
然后定义属性的取值,如下所示。
enum nl80211_attrs {
NL80211_ATTR_UNSPEC,
NL80211_ATTR_WIPHY,
NL80211_ATTR_WIPHY_NAME,
NL80211_ATTR_IFINDEX,
NL80211_ATTR_IFNAME,
NL80211_ATTR_IFTYPE,
NL80211_ATTR_MAC,
......// 一共定义了155条属性
}
头文件中对命令、属性等信息的注释都非常详细。本节不赘述,请读者自行阅读该文件。
提示 相比wext而言,nl80211的使用难度明显要复杂,其中重要原因是它是基于netlink编程的。而且,如果没有libnl的支持,相信使用难度会更大。但从Wi-Fi角度来看,nl80211和wext到没有太大区别,二者都是紧紧围绕MAC层service来设计数据结构的。