原文連接:http://blog.csdn.net/qq_21949217/article/details/46004379dom
這篇文章我來說解一下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來處理。socket
基於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源代碼分析(二):》)oop
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函數的部分代碼以下。ui
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的代碼以下:this
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),根據具體的幀來執行相應的操做。spa