上一篇说道,ieee80211_invoke_rx_handlers中CALL_RXH(ieee80211_rx_h_mgmt)用于管理帧的处理,这篇文章将对ieee80211_rx_h_mgmt函数进行简单分析。
ieee80211_queue_work(&rx->local->hw, &sdata->work);把sdata->work放入处理队里,而sdata->work被初始化为ieee80211_iface_work函数。继续跟踪ieee80211_iface_work下面一切操作的前提是接口类型是station,如果是AP,会在前面的用户空间处理函数中上交给上层,如hostapd。
①sta = sta_info_get_bss(sdata, mgmt->sa)这个函数根据mgmt->sa,也就是mgmt frame的源地址,进行哈希查表找到对应的station信息,然后判断sta对应的sdata(sdata是一个ieee80211_sub_if_data结构体)是否是这个的sdata,sta对应的bss是不是该sdata对应的bss。
②ieee80211_sta_rx_queued_mgmt(sdata, skb)。粘一段代码。
switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_BEACON:
ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
break;
case IEEE80211_STYPE_PROBE_RESP:
ieee80211_rx_mgmt_probe_resp(sdata, skb);
break;
case IEEE80211_STYPE_AUTH:
ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
break;
case IEEE80211_STYPE_DEAUTH:
ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
break;
case IEEE80211_STYPE_DISASSOC:
ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
break;
首先说ieee80211_rx_mgmt_beacon.
①ieee80211_rx_bss_info,更新功率及一些统计信息;
②更新当前AP的RSSI统计值;RSSI超过或低于某一门限时通过回调函数通知底层驱动;
③有一些ieee80211_send_nullfunc操作,好像和powersave模式有关,但是没有读懂;
④如果HT模式,带宽改变会引起disassociate;
⑤ieee80211_bss_info_change_notify(sdata, changed)通知底层驱动改变相关参数。
接着说ieee80211_rx_mgmt_auth。
①如果认证失败,就会通过cfg80211_rx_mlme_mgmt——>cfg80211_process_auth——>nl80211_send_rx_auth交给上层处理;
②cfg80211_process_auth——>如果status为加密算法选择错误,cfg80211_sme_rx_auth自动选择加密方式,此时的状态为关联后\正在认证,然后schedule_work(&rdev->conn_work)进行cfg80211_conn_work工作。else (status_code != WLAN_STATUS_SUCCESS) __cfg80211_connect_result,应该是结果上传给上层,但是不能确定;否则status转为正在关联状态。cfg80211_conn_do_work简单叙述如下:
cfg80211_conn_do_work(wdev)
switch (wdev->conn->state) {
case CFG80211_CONN_SCANNING:
/* didn't find it during scan ... */
return -ENOENT;
case CFG80211_CONN_SCAN_AGAIN:
return cfg80211_conn_scan(wdev);
case CFG80211_CONN_AUTHENTICATE_NEXT:
BUG_ON(!rdev->ops->auth);
wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
return cfg80211_mlme_auth(rdev, wdev->netdev,
params->channel, params->auth_type,
params->bssid,
params->ssid, params->ssid_len,
NULL, 0,
params->key, params->key_len,
params->key_idx, NULL, 0);
case CFG80211_CONN_AUTH_FAILED:
return -ENOTCONN;
case CFG80211_CONN_ASSOCIATE_NEXT:
BUG_ON(!rdev->ops->assoc);
wdev->conn->state = CFG80211_CONN_ASSOCIATING;
if (wdev->conn->prev_bssid_valid)
req.prev_bssid = wdev->conn->prev_bssid;
req.ie = params->ie;
req.ie_len = params->ie_len;
req.use_mfp = params->mfp != NL80211_MFP_NO;
req.crypto = params->crypto;
req.flags = params->flags;
req.ht_capa = params->ht_capa;
req.ht_capa_mask = params->ht_capa_mask;
req.vht_capa = params->vht_capa;
req.vht_capa_mask = params->vht_capa_mask;
err = cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel,
params->bssid, params->ssid,
params->ssid_len, &req);
if (err)
cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
NULL, 0,
WLAN_REASON_DEAUTH_LEAVING,
false);
return err;
case CFG80211_CONN_ASSOC_FAILED:
cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
NULL, 0,
WLAN_REASON_DEAUTH_LEAVING, false);
return -ENOTCONN;
case CFG80211_CONN_DEAUTH:
cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
NULL, 0,
WLAN_REASON_DEAUTH_LEAVING, false);
/* free directly, disconnected event already sent */
cfg80211_sme_free(wdev);
return 0;
default:
return 0;
}
}
cfg80211_mlme_xx会调用到ieee80211_mgd_xx都是用于配置相应结构体的成员变量。