您的位置:首页 > 其它

五、无线信息传递——通过ssid传递对hostapd传输方式的具体说明

2016-09-09 14:52 369 查看
  粗略了解了hostapd以及用户态与内核态通信的其中一种方式(netlink/genlink),不了解的读者可以查看上面发表的内容。

  这一章将以ssid的传输来具体说明ssid的值是怎样通过hostapd传入内核中的,即第三系列:

1、无线驱动信息传递框架:说明无线信息传递的步骤流程以及各程序块之间的联系;

2、generic Netlink信号传递机制:hostapd与无线驱动之间的信息传递机制;

3、以ssid为例说明用户将user space中的ssid配置内容传递至kernel space的流程:以此系统地了解整个无线信息传递流程。

导读

  通过前面几章的描述,基本了解了hostapd的初始化以及代码框架,也基本可以了解hostapd中运用的netlink通信及其特殊的一种通信方式genlink。但感觉如果需要更好地把握这些内容块还需要有一根线能将这些块串联起来,以达到在了解了这些内容怎么来之后,也能进一步知道怎么去用,用在哪。接下来进入正题。

本章目的

  通过前面几章的描述,基本了解了hostapd的初始化以及代码框架,也基本可以了解hostapd中运用的netlink通信及其特殊的一种通信方式genlink。但感觉如果需要更好地把握这些内容块还需要有一根线能将这些块串联起来,以达到在了解了这些内容怎么来之后,也能进一步知道怎么去用,用在哪。接下来进入正题。

主要内容:

1、ssid在hostapd端中的传输;

  1.1、关于普遍的配置内容在hostapd中的接口调用关系;

  1.2、ssid值在hostapd初始化时的接口传输。

2、ssid登陆内核后的赋值处理;

3、内核通过genlink获取ssid后,怎么将其用填充于beacon帧中。

一、ssid在hostapd端中的传输

1.1、关于普遍的配置内容在hostapd中的接口调用关系

  下图为hostapd相对于ssid的接口调用关系,从做至右表示从相对底层至上层hostapd的main()接口。当然该图中并不表示包含了全部ssid的传输过程,只是选了其中5条线路进行展示。

  因为这里主要说明初始化时ssid的传输,所以读者们可以主要观察红色线路的传输,其他线路了解即可。



1.2、ssid值在hostapd初始化时的接口传输

  因为是初始化说明,所以这里主要叙述上图中的红色线路。

1、main函数:hostapd入口;

2、hostapd_interface_init:初始化interface设备

2.1、hostapd_init:hostapd初始化,创建hostapd的资源空间;

2.2、hostapd_config_read(获取到配置文件中的ssid):读取hostapd.conf配置文件的文件内容,并将内容赋值于一个结构体并返回出来,其中调用的hostapd_config_fill实现真正的从文件读取配置功能;

3、hostapd_setup_interface:初始化网卡驱动,并调用setup_interface;

4、hostapd_setup_interface_complete:进行整体设置网卡;

5、hostapd_setup_bss:设置每一个bss。

  至此后续的传递如上图所示,而ssid则是包含在这些接口的参数中,进行一级一级地向下传递,直至调用到set_ap函数指针指向的wpa_driver_nl80211_set_up接口。展开wpa_driver_nl80211_set_up接口代码说明。

static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
...
wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",params->ssid, params->ssid_len);   //此处为打印
NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,params->ssid);         //这就厉害了,这里以NL80211_ATTR_SSID为向底层传输的genlink的独特序号,将
//ssid内容通过netlink向底层传输
...
}


  到这里,hostapd中的ssid传输说明完成。这一阶段主要说明的是hostapd中主要对于涉及到ssid值的接口调用关系。同时读者也可以以此发现其他wifi配置内容的接口调用关系,套路都是一样的。

二、ssid登陆内核后的赋值处理

  通过前面的netlink及genlink的分析,可以对用户态变量至内核态变量的传输有一个基本的了解,在这里主要对获取到ssid后的接口调用流程简单说明。

  hostapd(用户态)将ssid通过genlink机制将ssid传输至内核态时,执行如下2个主要的步骤操作,将内容发现并使用(ssid为例):

1、cfg80211进行解析获取到的用户态传输过来的信息;

2、解析并得到ssid序号——NL80211_ATTR_SSID,并在同一个数据包中解析获得ssid的数据内容,将他们通过一个结构体包含起来,后续通过该ssid序号获取ssid内容。

3、内核中的接口在相应的接口(这里以nl80211_start_ap接口为例进行说明)通过ssid序号获取ssid内容使用(函数接口的使用在下一模块说明)。

  下面具体通过代码以顺蔓摸瓜,由下而上的方式进行说明。

主要接口及结构体说明:

  下面是几个代码块内容的概括。

1、nl80211_policy:nl80211策略,一个netlink策略的结构体数组,其中包含与用户态对应的netlink属性序号,序号内容的类型以及序号代表的数据内容长度,其中就包括NL80211_ATTR_SSID;

2、nl80211_ops:nl80211结构体数组,其中包含各个对用户层(如:hostapd)传递下来的命令,其中就包括给wiphy(wifi物理层)进行具体数据设置等命令。

3、nl80211_start_ap():启动ap接口,赋值于nl80211_ops结构体中的NL80211_CMD_START_AP命令;

4、nl80211_init():nl80211初始化接口,是一个基本的netlink用户态协议,主要是对无线设备进行配置管理;

5、cfg80211_init():cfg80211初始化接口,同样是对无线设备进行配置管理,但与nl80211不同的是,这里的配置管理是针对内核态的。

/* policy for the attributes */
//nl80211策略
static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
...
[NL80211_ATTR_SSID] = {                 //nl80211中的ssid属性序号
.type = NLA_BINARY,             //属性类型
.len = IEEE80211_MAX_SSID_LEN           //ssid数据内容最大长度
},
...
};


//nl80211结构体数组
static struct genl_ops nl80211_ops[] = {
...
{
.cmd = NL80211_CMD_START_AP, //命令序号
.policy = nl80211_policy, //nl80211策略(具体见上方代码),其中包含了ssid的属性序号
.flags = GENL_ADMIN_PERM,
.doit = nl80211_start_ap, //命令序号对应的调用接口
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL,
},
...
};


/*启动ap接口*/
static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) //该接口具体在下一模块进行说明
{
...
if (info->attrs[NL80211_ATTR_SSID]) { //匹配ssid属性NL80211_ATTR_SSID
params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); //获取的数据包中ssid数据内容
params.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); //获取的数据包中ssid的内容数据长度
if (params.ssid_len == 0 || params.ssid_len > IEEE80211_MAX_SSID_LEN)
return -EINVAL;
}
...
}


//nl80211初始化接口
int nl80211_init(void)
{
...
err = genl_register_family_with_ops(&nl80211_fam, nl80211_ops, ARRAY_SIZE(nl80211_ops)); //对nl80211_ops结构体的genlink注册
if (err)
return err;
...
}


/*nl80211初始化接口*/
/////
static int __init cfg80211_init(void)
{
...
err = nl80211_init(); //调用nl80211_init接口
if (err)
goto out_fail_nl80211;
...
}

//最终由subsys_initcall加载(对于驱动模块,使用subsys_initcall等价于使用module_init)
subsys_initcall(cfg80211_init);


三、内核通过genlink获取ssid后,怎么将其用填充于beacon帧中

  至此,知道了无线中用户态(hostapd)至内核态通过genlink的数据传输大致流程。接下来说明传下来的ssid是如何实现向beacon填充的,以最终完结这一整套beacon填充功能的代码说明。

  在前面一章beacon填充的方式说明中可以了解到其中主要展现了一个接口wla_beacon_get,以及后续具体项目实现说明的另一个接口:ieee80211_assign_beacon()。这两个接口都可以按照80211协议,巧妙地实现向beacon中填充我们需要的内容。

但其中使用到的数据是如果传给他们的呢?下面的一幅图就可以很明了地说明这两个接口使用的数据的来源。



  上图说明的即是内核态在获取到ssid数据内容后,对于向beacon帧中进行内容填充的流程说明。

小结

  至此,关于无线信息传递的系列就已经全部粗略说明完成。主要是针对向beacon中填充ssid进行的,当然关于其他内容也是大致相同,可以以此为出发点,举一反三进行更深入的探究。

  有这些基础,下面对项目中向beacon帧中填充需要信息功能进行单一的功能性实现的描述,就不再拓展扰乱文章架构了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  内核 通信 框架