這篇文章我來講解一下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, 0, NULL, NULL, 0);
監視接口建立以後,通過socket來接收原始幀,並把socket註冊到event loop中(關於event loop,請參考《hostapd源代碼分析(二):》)
-
-
drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-
...
-
-
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), 0);
-
...
-
while (1) {
-
ret = ieee80211_radiotap_iterator_next(&iter);
-
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 -= 4;
-
break;
-
case IEEE80211_RADIOTAP_RX_FLAGS:
-
rxflags = 1;
-
break;
-
case IEEE80211_RADIOTAP_TX_FLAGS:
-
injected = 1;
-
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:
-
-
break;
-
case IEEE80211_RADIOTAP_RATE:
-
datarate = *iter.this_arg * 5;
-
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);
-
if (bssid == NULL)
-
return 0;
-
-
hapd = get_hapd_bssid(iface, bssid);
-
if (hapd == NULL) {
-
u16 fc;
-
fc = le_to_host16(hdr->frame_control);
-
-
-
-
-
-
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
-
hapd = iface->bss[0];
-
else
-
return 0;
-
}
-
-
os_memset(&fi, 0, sizeof(fi));
-
fi.datarate = rx_mgmt->datarate;
-
fi.ssi_signal = rx_mgmt->ssi_signal;
-
-
if (hapd == HAPD_BROADCAST) {
-
size_t i;
-
ret = 0;
-
-
for (i = 0; i < iface->num_bss; i++) {
-
-
-
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) > 0)
-
ret = 1;
-
}
-
} 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),根據具體的幀來執行相應的操作。