hostapd源代码分析(三):管理帧的收发和处理

原文链接:http://blog.csdn.net/qq_21949217/article/details/46004379

  这篇文章我来讲解一下hostapd是如何处理IEEE 802.11管理帧的。我们知道,hostapd主要负责管理工作站(station)认证和接入。因此,它只处理管理帧(Management Frame),并不处理数据帧。802.11的管理帧主要有信标帧(beacon)、探测请求帧(probe request)、探测回应帧(probe response)、请求认证帧(authentication request)、认证回应帧(authentication response)、请求关联帧(association request)和关联回应帧(association response)等。hostapd在初始化的阶段,会将无线网卡转换为AP模式,并且建立监视接口(Monitor Interface,一般是mon.wlan0),这个监视接口主要负责接收802.11管理帧。内核收到管理帧后,就会把它送回用户空间的hostapd来处理。

一、建立监视接口

  基于nl80211驱动的hostapd在初始化的时候,会调用位于src/driver/driver_nl80211.c的nl80211_create_monitor_interface来建立监视接口。

 drv->monitor_ifidx = nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, , NULL, NULL, ); //通过Netlink通知内核新建一个监视接口  

  监视接口建立以后,通过socket来接收原始帧,并把socket注册到event loop中(关于event loop,请参考《hostapd源代码分析(二):》)

 //建立原始套接字
drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
...
//把原始套接字的描述符和回调函数handle_monitor_read注册到event loop
if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, drv, NULL)) {
wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
goto error;
}

二、接收和处理管理帧

  当原始套接字接收到802.11管理帧后,会调用handle_monitor_read来进一步处理。handle_monitor_read中,会根据Rx或者Tx标志来调用handle_frame或者handle_tx_callback函数来处理。根据我的理解和分析,一般handle_frame处理“请求”帧,比如probe request帧,authentication request帧,等等;handle_tx_callback一般用来处理“回应”帧,比如,authentication response帧,association response帧等。handle_monitor_read函数的部分代码如下。

 len = recv(sock, buf, sizeof(buf), ); //读取从原始套接字接收的帧
...
while () {
ret = ieee80211_radiotap_iterator_next(&iter); //抽取radiotap报头
if (ret == -ENOENT)
break;
if (ret) {
wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)", ret);
return;
}
switch (iter.this_arg_index) {
case IEEE80211_RADIOTAP_FLAGS:
if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
len -= ;
break;
case IEEE80211_RADIOTAP_RX_FLAGS: //接收(Rx)帧(一般是“请求帧”)
rxflags = ;
break;
case IEEE80211_RADIOTAP_TX_FLAGS: //发送(Tx)帧(一般是“回应帧”)
injected = ;
failed = le_to_host16((*(uint16_t *) iter.this_arg)) & IEEE80211_RADIOTAP_F_TX_FAIL;
break;
case IEEE80211_RADIOTAP_DATA_RETRIES:
break;
case IEEE80211_RADIOTAP_CHANNEL:
/* TODO: convert from freq/flags to channel number */
break;
case IEEE80211_RADIOTAP_RATE:
datarate = *iter.this_arg * ;
break;
case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
ssi_signal = (s8) *iter.this_arg;
break;
}
} if (rxflags && injected)
return; if (!injected)
handle_frame(drv, buf + iter._max_length, len - iter._max_length, datarate, ssi_signal); //处理“请求帧”
else
handle_tx_callback(drv->ctx, buf + iter._max_length, len - iter._max_length, !failed); //处理“发送帧”
}

然后,进入handle_frame后,再调用wpa_supplicant_event(位于src/ap/drv_callbacks.c)来进一步处理。对于“请求帧”,会调用hostapd_mgmt_rx(位于src/ap/drv_callbacks.c)。hostapd_mgmt_rx的代码如下:

 static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
{
struct hostapd_iface *iface = hapd->iface;
const struct ieee80211_hdr *hdr;
const u8 *bssid;
struct hostapd_frame_info fi;
int ret; hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); //获取该帧所属的BSSID
if (bssid == NULL)
return ; hapd = get_hapd_bssid(iface, bssid); //根据BSSID获取相应的BSS
if (hapd == NULL) { //相应的BSS不存在,则抛弃不处理。
u16 fc;
fc = le_to_host16(hdr->frame_control); /*
* Drop frames to unknown BSSIDs except for Beacon frames which
* could be used to update neighbor information.
*/
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
hapd = iface->bss[];
else
return ;
} os_memset(&fi, , sizeof(fi));
fi.datarate = rx_mgmt->datarate;
fi.ssi_signal = rx_mgmt->ssi_signal; if (hapd == HAPD_BROADCAST) { //广播帧
size_t i;
ret = ;
//将广播帧发送给每一个BSS
for (i = ; i < iface->num_bss; i++) {
/* if bss is set, driver will call this function for
* each bss individually. */
if (rx_mgmt->drv_priv &&
(iface->bss[i]->drv_priv != rx_mgmt->drv_priv))
continue; if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
rx_mgmt->frame_len, &fi) > )
ret = ;
}
} else //单播帧
ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
&fi); random_add_randomness(&fi, sizeof(fi)); return ret;
}

接下来,继续调用ieee802_11_mgmt(位于src/ap/ieee80211.c),根据具体的帧来执行相应的操作。

hostapd源代码分析(三):管理帧的收发和处理的更多相关文章

  1. hostapd源代码分析(二):hostapd的工作机制

    [转]hostapd源代码分析(二):hostapd的工作机制 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004433 在我的上一 ...

  2. hostapd源代码分析(一):网络接口和BSS的初始化

    [转]hostapd源代码分析(一):网络接口和BSS的初始化 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004349 最近在做一 ...

  3. Nouveau源代码分析(三):NVIDIA设备初始化之nouveau_drm_probe

    Nouveau源代码分析(三) 向DRM注冊了Nouveau驱动之后,内核中的PCI模块就会扫描全部没有相应驱动的设备,然后和nouveau_drm_pci_table对比. 对于匹配的设备,PCI模 ...

  4. Android 中View的绘制机制源代码分析 三

    到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...

  5. [Android]Fragment源代码分析(三) 事务

    Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的很的出彩.我们先引入一个简单经常使用的Fragment事务管理代码片段: FragmentTransaction ft = thi ...

  6. 【原创】Kakfa utils源代码分析(三)

    Kafka utils包最后一篇~~~ 十五.ShutdownableThread.scala 可关闭的线程抽象类! 继承自Thread同时还接收一个boolean变量isInterruptible表 ...

  7. Volley简单学习使用五—— 源代码分析三

    一.Volley工作流程图: 二.Network     在NetworkDispatcher中须要处理的网络请求.由以下进行处理: NetworkResponse networkResponse = ...

  8. TestNG源代码分析:依赖管理的实现

    TestNG源代码分析:依赖管理的实现 2018-03-19 1 背景 当case之间有依赖关系,有依赖关系的case,它们的执行顺序是有限制的.TestNG提供了依赖管理功能 2 基础理论 这个执行 ...

  9. openVswitch(OVS)源代码分析之工作流程(数据包处理)

    上篇分析到数据包的收发,这篇开始着手分析数据包的处理问题.在openVswitch中数据包的处理是其核心技术,该技术分为三部分来实现:第一.根据skb数据包提取相关信息封装成key值:第二.根据提取到 ...

随机推荐

  1. myeclipse 常用快捷键总结

    1 shift+enter 不管鼠标在当前行的什么位置,重新开启一行(向下) 2 shift+ctrl+enter 不管鼠标在当前行的什么位置,重新开启一行(向上) 3 Ctrl+D     删除一行 ...

  2. js格式化日期 年月日

    /**                     * 格式化日期                     * @param value                     * @param row  ...

  3. Django的第一个web程序及深入学习

    本学习历程参照Practical Django Projects和http://djangobook.py3k.cn上翻译的内容进行 注:本例以本机加以说明: 根据Django的安装过程可知:在命令行 ...

  4. 棋盘问题 分类: 搜索 POJ 2015-08-09 13:02 4人阅读 评论(0) 收藏

    棋盘问题 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28474 Accepted: 14084 Description 在一 ...

  5. Wampserver3.0.0设置语言为中文无效

    打开配置文件"wampmanager.conf",将language改成chinese,再从右键的语言选择中选中文. 这个配置文件有两个,改第一个双引号里的,第二个没有引号的不要改 ...

  6. PostgreSql安装

    官网:http://www.postgresql.org/download/linux/redhat/ 一.安装 由于我的机子是centos6.2,所以选择RedHat的. 按照官网所说的进行安装: ...

  7. div+css基础

    Div+css技术 Div是用于存放文字,图片,元素的容器 Css 是用于指定存放在div中的内容如何显示,包括内容的位置和外观(层叠样式表) Html 文件 <!--必须引入的文件--> ...

  8. Codeforces Round #368 (Div. 2) C

    Description Katya studies in a fifth grade. Recently her class studied right triangles and the Pytha ...

  9. 一致性hash算法——之二

    摘自:http://www.tomkleinpeter.com/2008/03/17/programmers-toolbox-part-3-consistent-hashing/

  10. 嵌入式linux

    嵌入式开发 1.1开发板和宿主机的连接方法:cable 电缆可以通过 串口 网络 以及 JTGA等连接方式. JTAG:国际标准测试协议对芯片内部测试对flash烧写.注意JTAG 是一种协议,具体去 ...