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),根據具體的幀來執行相應的操作。


發佈了3 篇原創文章 · 獲贊 11 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章