hostapd源代码分析(三):管理帧的收发和处理
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源代码分析(三):管理帧的收发和处理的更多相关文章
- hostapd源代码分析(二):hostapd的工作机制
[转]hostapd源代码分析(二):hostapd的工作机制 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004433 在我的上一 ...
- hostapd源代码分析(一):网络接口和BSS的初始化
[转]hostapd源代码分析(一):网络接口和BSS的初始化 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004349 最近在做一 ...
- Nouveau源代码分析(三):NVIDIA设备初始化之nouveau_drm_probe
Nouveau源代码分析(三) 向DRM注冊了Nouveau驱动之后,内核中的PCI模块就会扫描全部没有相应驱动的设备,然后和nouveau_drm_pci_table对比. 对于匹配的设备,PCI模 ...
- Android 中View的绘制机制源代码分析 三
到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...
- [Android]Fragment源代码分析(三) 事务
Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的很的出彩.我们先引入一个简单经常使用的Fragment事务管理代码片段: FragmentTransaction ft = thi ...
- 【原创】Kakfa utils源代码分析(三)
Kafka utils包最后一篇~~~ 十五.ShutdownableThread.scala 可关闭的线程抽象类! 继承自Thread同时还接收一个boolean变量isInterruptible表 ...
- Volley简单学习使用五—— 源代码分析三
一.Volley工作流程图: 二.Network 在NetworkDispatcher中须要处理的网络请求.由以下进行处理: NetworkResponse networkResponse = ...
- TestNG源代码分析:依赖管理的实现
TestNG源代码分析:依赖管理的实现 2018-03-19 1 背景 当case之间有依赖关系,有依赖关系的case,它们的执行顺序是有限制的.TestNG提供了依赖管理功能 2 基础理论 这个执行 ...
- openVswitch(OVS)源代码分析之工作流程(数据包处理)
上篇分析到数据包的收发,这篇开始着手分析数据包的处理问题.在openVswitch中数据包的处理是其核心技术,该技术分为三部分来实现:第一.根据skb数据包提取相关信息封装成key值:第二.根据提取到 ...
随机推荐
- [Unity3D]MonoBehaviour函数介绍
原文地址: http://www.cocos2dev.com/?p=486 Unity中的脚本都是继承自MonoBehaviour. 一.基础函数: 创建脚本就默认的update.start方法:(这 ...
- 每日一九度之 题目1040:Prime Number
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6732 解决:2738 题目描述: Output the k-th prime number. 输入: k≤10000 输出: The k- ...
- 关于Filter的配置
配置代码: <filter> <display-name>OneFilter</display-name> <filter-name>OneFilte ...
- js调用MVC3自带js验证
验证: if ($(this).is("form")) { return $(this).validate().checkForm() ...
- JS实现base64编码与解码
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ...
- 南阳oj 求N!的二进制表示最低位的1的位置(从右向左数)。
N! 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 阶乘(Factorial)是一个很有意思的函数,但是不少人都比较怕它.现在这里有一个问题,给定一个N(0< ...
- 安装Docker和下载images镜像和常用Docker命令
我的是centos7,也会6的方法: $sudo yum install docker 直接yum安装contos7使用centos6.5先获取epel源并 启动Docker,并注册开机服务 [roo ...
- Android WebView使用基础
WebView基本使用 WebView是View的一个子类,可以让你在activity中显示网页. 可以在布局文件中写入WebView:比如下面这个写了一个填满整个屏幕的WebView: <?x ...
- 2016年12月12日 星期一 --出埃及记 Exodus 21:7
2016年12月12日 星期一 --出埃及记 Exodus 21:7 "If a man sells his daughter as a servant, she is not to go ...
- CSocket客户端(TCP)
首先是UDP和TCP的区别: UDP是不连接服务器,每次发送数据的时候需要服务器的IP:而TCP是先连接服务器,保持常连接,然后直接发送不需要IP. 下面是TCP客户端: 1.新建项目,TestCSo ...