博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hostapd源代码分析(三):管理帧的收发和处理
阅读量:4681 次
发布时间:2019-06-09

本文共 5211 字,大约阅读时间需要 17 分钟。

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

原文链接:

 

  这篇文章我来讲解一下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来建立监视接口。

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

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

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

二、接收和处理管理帧

  当原始套接字接收到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函数的部分代码如下。

1 len = recv(sock, buf, sizeof(buf), 0); //读取从原始套接字接收的帧   2 ...   3 while (1) {   4     ret = ieee80211_radiotap_iterator_next(&iter); //抽取radiotap报头   5     if (ret == -ENOENT)   6         break;   7     if (ret) {   8         wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)", ret);   9         return;  10     }  11     switch (iter.this_arg_index) {  12     case IEEE80211_RADIOTAP_FLAGS:  13         if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)  14             len -= 4;  15         break;  16     case IEEE80211_RADIOTAP_RX_FLAGS: //接收(Rx)帧(一般是“请求帧”)  17         rxflags = 1;  18         break;  19     case IEEE80211_RADIOTAP_TX_FLAGS: //发送(Tx)帧(一般是“回应帧”)  20         injected = 1;  21         failed = le_to_host16((*(uint16_t *) iter.this_arg)) & IEEE80211_RADIOTAP_F_TX_FAIL;  22         break;  23     case IEEE80211_RADIOTAP_DATA_RETRIES:  24         break;  25     case IEEE80211_RADIOTAP_CHANNEL:  26         /* TODO: convert from freq/flags to channel number */  27         break;  28     case IEEE80211_RADIOTAP_RATE:  29         datarate = *iter.this_arg * 5;  30         break;  31     case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:  32         ssi_signal = (s8) *iter.this_arg;  33         break;  34     }  35 }  36   37 if (rxflags && injected)  38      return;  39   40 if (!injected)  41     handle_frame(drv, buf + iter._max_length, len - iter._max_length, datarate, ssi_signal); //处理“请求帧”  42 else  43     handle_tx_callback(drv->ctx, buf + iter._max_length, len - iter._max_length, !failed); //处理“发送帧”  44 }

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

1 static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)   2 {   3     struct hostapd_iface *iface = hapd->iface;   4     const struct ieee80211_hdr *hdr;   5     const u8 *bssid;   6     struct hostapd_frame_info fi;   7     int ret;   8    9     hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;  10     bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); //获取该帧所属的BSSID  11     if (bssid == NULL)  12         return 0;  13   14     hapd = get_hapd_bssid(iface, bssid); //根据BSSID获取相应的BSS  15     if (hapd == NULL) { //相应的BSS不存在,则抛弃不处理。  16         u16 fc;  17         fc = le_to_host16(hdr->frame_control);  18   19         /* 20          * Drop frames to unknown BSSIDs except for Beacon frames which 21          * could be used to update neighbor information. 22          */  23         if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&  24             WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)  25             hapd = iface->bss[0];  26         else  27             return 0;  28     }  29   30     os_memset(&fi, 0, sizeof(fi));  31     fi.datarate = rx_mgmt->datarate;  32     fi.ssi_signal = rx_mgmt->ssi_signal;  33   34     if (hapd == HAPD_BROADCAST) { //广播帧  35         size_t i;  36         ret = 0;  37                 //将广播帧发送给每一个BSS  38         for (i = 0; i < iface->num_bss; i++) {  39             /* if bss is set, driver will call this function for 40              * each bss individually. */  41             if (rx_mgmt->drv_priv &&  42                 (iface->bss[i]->drv_priv != rx_mgmt->drv_priv))  43                 continue;  44   45             if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,  46                         rx_mgmt->frame_len, &fi) > 0)  47                 ret = 1;  48         }  49     } else //单播帧  50         ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,  51                       &fi);  52   53     random_add_randomness(&fi, sizeof(fi));  54   55     return ret;  56 }

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

转载于:https://www.cnblogs.com/happygirl-zjj/p/5995825.html

你可能感兴趣的文章
mysql 5.7.7+支持JSON字段格式
查看>>
iOS开发之多媒体播放
查看>>
开始iOS 7中自动布局教程(一)
查看>>
POJ 3254 Corn Fields(状压DP)
查看>>
MySQL 删除重复数据
查看>>
ACM-ICPC 2018 徐州赛区网络预赛 B(dp)
查看>>
BZOJ 1022(博弈论)
查看>>
loj 515(bitset优化dp)
查看>>
练习:等待用户输入input()
查看>>
Linux命令全称
查看>>
[.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
查看>>
Socket 编程IO Multiplexing
查看>>
通用的方法,来检查字段是否存在
查看>>
wx入门(一)
查看>>
w3a-Monitor-update-13-07-23
查看>>
数据存储——SQLite数据库存储——API
查看>>
概率论
查看>>
PHP-cli简介
查看>>
学习嵌入式—导火线
查看>>
nullnullDefining and Launching the Query 定义和启动查询
查看>>