驱动层TX MGMT处理过程
管理帧主要包含Beacon、Probe、Authentication、Association,其中Beacon是预先分配好内存,并填充内容,当FW上报beacon发送事件的时候,会调用ol_beacon_swba_handler函数,会把beacon帧发送发送到htc层。
其他的管理帧,则是在用到的时候现场分配内存,统一调用ieee80211_send_mgmt函数发送到htc层,下面以auth为例,说明了大致过程:
ieee80211_send_auth
ieee80211_send_mgmt
wlan_mgmt_txrx_mgmt_frame_tx{
tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send(vdev, buf, desc->desc_id, mgmt_tx_params)
实际调用 ol_if_mgmt_send 因为 tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send = ol_if_mgmt_send
{
ol_ath_tx_mgmt_wmi_send(ic, nbuf, ni, mgmt_tx_params);
ol_mgmt_send
wmi_mgmt_unified_cmd_send
wmi_handle->ops->send_mgmt_cmd
实际调用 send_mgmt_cmd_tlv,因为 wmi_handle->ops->send_mgmt_cmd = send_mgmt_cmd_tlv
{
wmi_unified_cmd_send
wmi_htc_send_pkt
htc_send_pkt
__htc_send_pkt
}
}
}
Beacon
初始化缓存,并设置beacon的内容到av_wbuf中
ol_ath_vap_create_post_init(struct vdev_mlme_obj *vdev_mlme, int flags) { vap->iv_hostap_up_pre_init = ol_ath_hostap_up_pre_init; } QDF_STATUS mlme_ext_vap_up_pre_init(struct wlan_objmgr_vdev *vdev, bool restart) { switch (opmode) { case IEEE80211_M_STA: ic->ic_vap_set_param(vap, IEEE80211_VHT_SUBFEE, 0); reassoc = restart; ic->ic_newassoc(ni, !reassoc); break; case IEEE80211_M_HOSTAP: case IEEE80211_M_IBSS: status = vap->iv_hostap_up_pre_init(vdev, restart); break; default: break; } } ol_ath_hostap_up_pre_init ol_ath_beacon_alloc ol_ath_vap_iter_beacon_alloc // 填充内容 avn->av_wbuf = ieee80211_beacon_alloc(ni, &avn->av_beacon_offsets);注册beacon事件到fw
void ol_ath_beacon_soc_attach(ol_ath_soc_softc_t *soc) { struct wmi_unified *wmi_handle; wmi_handle = lmac_get_wmi_hdl(soc->psoc_obj); /* Register WMI event handlers */ //注册ol_beacon_swba_handler地方 wmi_unified_register_event_handler((void *)wmi_handle, wmi_host_swba_event_id,ol_beacon_swba_handler, WMI_RX_UMAC_CTX); } 实际调用ol_beacon_swba_handler地方 参见文档《接收管理帧过程》中关于wmi_unified_register_event_handler 实际上就是在__wmi_control_rx中调用如果fw发送beacon 的事件,则开始发送beacon
ol_beacon_swba_handler ol_ath_beacon_swba_handler ol_prepare_send_vap_bcn wlan_mgmt_txrx_beacon_frame_tx { tx_ops->mgmt_txrx_tx_ops.beacon_send(vdev, buf) 实际调用ol_ath_mgmt_beacon_send ,因为 tx_ops->mgmt_txrx_tx_ops.beacon_send = ol_ath_mgmt_beacon_send { ol_ath_beacon_send wmi_unified_beacon_send_cmd wmi_handle->ops->send_beacon_send_cmd 实际调用 send_beacon_send_cmd_tlv 因为 wmi_handle->ops->send_beacon_send_cmd = send_beacon_send_cmd_tlv { wmi_unified_cmd_send 再往下就和 管理帧一样的 wmi_htc_send_pkt htc_send_pkt __htc_send_pkt } } }
Probe
探测请求 Probe Request
mlme_vdev_subst_start_conn_progress_event
mlme_vdev_start_continue_cb
{
{
wlan_assoc_sm_start(wlan_mlme_get_assoc_sm_handle(vap->vdev_obj),mlme_cm_get_active_scan_entry(vap),req.prev_bssid.bytes);
ieee80211_mlme_join_infra_continue(vap,EOK); // 这里发送probe 请求帧
// WIM_LOG_DEBUG("SMAC:%s DMAC:%s",ether_sprintf(vap->iv_myaddr),ether_sprintf(ni->ni_bssid));
}
}
ieee80211_mlme_join_infra_continue
{
if ((ic->ic_strict_pscan_enable && IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) && !vap->iv_wps_mode) {
mlme_priv->im_request_type = MLME_REQ_NONE;
IEEE80211_DELIVER_EVENT_MLME_JOIN_COMPLETE_INFRA(vap, IEEE80211_STATUS_SUCCESS);
return;
}
else {
/* Send a direct probe to increase the odds of receiving a probe response */
// 这里调用,这里是否可以取消该probe req 参见本章《高阶》中介绍
ieee80211_send_probereq(ni, vap->iv_myaddr, ni->ni_bssid,ni->ni_bssid, ni->ni_essid, ni->ni_esslen, vap->iv_opt_ie.ie, vap->iv_opt_ie.length);
//WIM_LOG_DEBUG("SMAC:%s DMAC:%s",ether_sprintf(vap->iv_myaddr),ether_sprintf(ni->ni_bssid));
}
}
ieee80211_send_probereq
ieee80211_send_mgmt
int ieee80211_send_probereq(struct ieee80211_node *ni,
const u_int8_t *sa,
const u_int8_t *da,
const u_int8_t *bssid,
const u_int8_t *ssid,
const u_int32_t ssidlen,
const void *optie,
const size_t optielen);
{
wbuf_t wbuf;
enum ieee80211_phymode mode;
struct ieee80211_frame *wh;
// 分配空间
wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE);
// 把内存转换为802.11头指针wh
wh = (struct ieee80211_frame *)wbuf_header(wbuf);
// 取frm 然后设置里面的内容
frm = (u_int8_t *)&wh[1];
/*
* prreq frame format
*[tlv] ssid
*[tlv] supported rates
*[tlv] extended supported rates
*[tlv] HT Capabilities
*[tlv] VHT Capabilities
*[tlv] user-specified ie's
*/
frm = ieee80211_add_ssid(frm, ssid, ssidlen);
mode = ieee80211_get_current_phymode(ic);
/* XXX: supported rates or operational rates? */
frm = ieee80211_add_rates(frm, &vap->iv_op_rates[mode]);
frm = ieee80211_add_xrates(vap, frm, &vap->iv_op_rates[mode]);
// 增加ie 域
frm = ieee80211_mlme_app_ie_append(vap, IEEE80211_FRAME_TYPE_PROBEREQ, frm);
#if QCN_IE
frm = ieee80211_add_qcn_info_ie(frm, vap, &ie_len,
QCN_MAC_PHY_PARAM_IE_TYPE, NULL);
#endif
frm = ieee80211_add_generic_vendor_capabilities_ie(frm, ic);
// 发送帧
return ieee80211_send_mgmt(vap,ni, wbuf,true);
}
探测请求应答 Probe Response
ieee80211_send_proberesp
ieee80211_send_mgmt
int
ieee80211_send_proberesp(struct ieee80211_node *ni, u_int8_t *macaddr,
const void *optie, const size_t optielen,
struct ieee80211_framing_extractx *extractx)
{
// 申请内存空间
wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE);
// 把内存转换为802.11头指针wh
wh = (struct ieee80211_frame *)wbuf_header(wbuf);
ieee80211_send_setup(vap, ni, wh,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP,
vap->iv_myaddr, macaddr,
ieee80211_node_get_bssid(ni));
// 取frm 然后设置里面的内容
frm = (u_int8_t *)&wh[1];
//此处省略设置过程
// 发送地方
ieee80211_send_mgmt(vap,ni, wbuf,true);
}
Authentication
身份认证 Authentication
ieee80211_send_auth
ieee80211_send_mgmt
int
ieee80211_send_auth(
struct ieee80211_node *ni,
u_int16_t seq,
u_int16_t status,
u_int8_t *challenge_txt,
u_int8_t challenge_len,
struct ieee80211_app_ie_t* optie
)
{
wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE);
wh = (struct ieee80211_frame *)wbuf_header(wbuf);
frm = (u_int8_t *)&wh[1];
// 设置frm
// 实际发送的地方
ieee80211_send_mgmt(vap,ni, wbuf,false)
}
去身份认证 Deauthentication
ieee80211_send_deauth
ieee80211_send_mgmt
int
ieee80211_send_deauth(struct ieee80211_node *ni, u_int16_t reason)
{
wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, (sizeof(struct ieee80211_frame)+frlen));
wh = (struct ieee80211_frame *)wbuf_header(wbuf);
frm = (u_int8_t *)&wh[1];
if (vap->iv_vap_is_down)
return ieee80211_send_mgmt(vap, ni, wbuf, true);
else
return ieee80211_send_mgmt(vap, ni, wbuf, false);
}
Association
关联请求 Association or Reassociation Request
ieee80211_send_assoc
ieee80211_send_mgmt
int
ieee80211_send_assoc(struct ieee80211_node *ni,
int reassoc, u_int8_t *prev_bssid)
{
// 申请空间
wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE);
// 设置内容
length = ieee80211_setup_assoc(ni, (struct ieee80211_frame *)wbuf_header(wbuf),
reassoc, prev_bssid);
// 传输到os层
/* Callback to allow OS layer to copy assoc/reassoc frame (Vista requirement) */
IEEE80211_DELIVER_EVENT_MLME_ASSOC_REQ(vap, wbuf);
// 发送
return ieee80211_send_mgmt(vap,ni,wbuf,false);
}
关联请求应答 Association Response
ieee80211_send_assocresp
ieee80211_send_mgmt
int
ieee80211_send_assocresp(struct ieee80211_node *ni, u_int8_t reassoc, u_int16_t reason,
struct ieee80211_app_ie_t* optie)
{
//申请并设置wbuf内容
wbuf = ieee80211_setup_assocresp(ni, NULL, reassoc, reason, optie);
// 发送
ieee80211_send_mgmt(vap,ni, wbuf,false);
}
去关联 Disassociation
ieee80211_send_disassoc
ieee80211_send_disassoc_with_callback(ni, reason, NULL, NULL);
ieee80211_send_mgmt
int
ieee80211_send_disassoc(struct ieee80211_node *ni, u_int16_t reason)
{
int retval;
retval = ieee80211_send_disassoc_with_callback(ni, reason, NULL, NULL);
{
wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE);
wh = (struct ieee80211_frame *)wbuf_header(wbuf);
ieee80211_flush_peer_mgmt_queue(ni);
// 实际发送地方
if (vap->iv_vap_is_down)
return ieee80211_send_mgmt(vap, ni, wbuf, true);
else
return ieee80211_send_mgmt(vap, ni, wbuf, false); frm = (u_int8_t *)&wh[1];
}
return retval;
}
ieee80211_send_mgmt 通用函数
int
ieee80211_send_mgmt(struct ieee80211vap *vap,struct ieee80211_node *ni, wbuf_t wbuf, bool force_send)
{
u_int8_t subtype;
u_int8_t fc_type;
int retval;
struct ieee80211_frame *wh;
ni = ieee80211_try_ref_node(ni, WLAN_MGMT_TX_ID);
if (!ni) {
wbuf_complete(wbuf);
return EOK;
} else {
wlan_wbuf_set_peer_node(wbuf, ni);
}
wh = (struct ieee80211_frame *)wbuf_header(wbuf);
fc_type = wh->i_fc[0];
/*
* if forced sleep is set then turn on the powersave
* bit on all management except for the probe request.
*/
if (ieee80211_vap_forced_sleep_is_set(vap)) {
subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
if (subtype != IEEE80211_FC0_SUBTYPE_PROBE_REQ) {
wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
wbuf_set_pwrsaveframe(wbuf);
}
}
/*
* call registered function to add any additional IEs.
*/
if (vap->iv_output_mgmt_filter) {
if (vap->iv_output_mgmt_filter(wbuf)) {
/*
* filtered out and freed by the filter function,
* nothing to do, just return.
*/
IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER,
"[%s] frame filtered out; do not send\n",
__func__);
ieee80211node_test_set_delayed_node_cleanup_fail(ni,
IEEE80211_NODE_DELAYED_CLEANUP_FAIL);
ieee80211_free_node(ni, WLAN_MGMT_TX_ID);
return EOK;
}
}
vap->iv_lastdata = OS_GET_TIMESTAMP();
#if 0
if (wbuf_is_keepalive(wbuf)){
if (force_send)
qdf_nofl_info("\n the force_send is set\n");
if(ieee80211node_has_flag(ni,IEEE80211_NODE_PWR_MGT)){
qdf_nofl_info("\n powersave node\n");
for (int i = 0; i < 6; i++) {
qdf_nofl_info("%02x:", ni->ni_macaddr[i]);
}
}
}
#endif
/*
* do not sent the frame is node is in power save (or) if the vap is paused
* and the frame is is not marked as special force_send frame, and if the node
* is temporary, don't do pwrsave
*/
if (!force_send &&
(ieee80211node_is_paused(ni)) &&
!ieee80211node_has_flag(ni, IEEE80211_NODE_TEMP)) {
#if !LMAC_SUPPORT_POWERSAVE_QUEUE
wlan_wbuf_set_peer_node(wbuf, NULL);
#endif
ieee80211node_pause(ni); /* pause it to make sure that no one else unpaused it after the node_is_paused check above, pause operation is ref counted */
ieee80211_node_saveq_queue(ni,wbuf,IEEE80211_FC0_TYPE_MGT);
ieee80211node_unpause(ni); /* unpause it if we are the last one, the frame will be flushed out */
#if !LMAC_SUPPORT_POWERSAVE_QUEUE
ieee80211node_test_set_delayed_node_cleanup_fail(ni,
IEEE80211_NODE_DELAYED_CLEANUP_FAIL);
ieee80211_free_node(ni, WLAN_MGMT_TX_ID);
return EOK;
#endif
}
/*
* if the vap is not ready drop the frame.
*/
if (!(vap->iv_opmode == IEEE80211_M_HOSTAP && vap->iv_is_up) &&
(wlan_vdev_chan_config_valid(vap->vdev_obj) != QDF_STATUS_SUCCESS) &&
!vap->iv_special_vap_mode &&
!vap->iv_dpp_vap_mode) {
struct ieee80211_tx_status ts;
ts.ts_flags = IEEE80211_TX_ERROR;
ts.ts_retries=0;
/*
* complete buf will decrement the pending count.
*/
ieee80211_complete_wbuf(wbuf,&ts);
return EOK;
}
#ifdef QCA_SUPPORT_CP_STATS
peer_cp_stats_tx_mgmt_inc(ni->peer_obj, 1);
vdev_ucast_cp_stats_tx_mgmt_inc(vap->vdev_obj, 1);
#endif
if ((wh->i_fc[0] == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_RESP)) ||
(wh->i_fc[0] == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_REASSOC_RESP))) {
wbuf_set_complete_handler(wbuf, ieee80211_mlme_frame_complete_handler, ni);
}
// 实际发送过程
/* Hand over the wbuf to the mgmt_txrx infrastructure. */
retval = wlan_mgmt_txrx_mgmt_frame_tx(ni->peer_obj, NULL, wbuf, NULL,
ieee80211_mgmt_complete_wbuf,
WLAN_UMAC_COMP_MLME, NULL);
if(QDF_IS_STATUS_ERROR(retval))
{
struct ieee80211_tx_status ts;
ts.ts_flags = IEEE80211_TX_ERROR;
ts.ts_retries=0;
#ifdef QCA_SUPPORT_CP_STATS
vdev_cp_stats_tx_not_ok_inc(vap->vdev_obj, 1);
#endif
if ((fc_type == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_RESP)) ||
(fc_type == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_REASSOC_RESP))) {
#ifdef QCA_SUPPORT_CP_STATS
WLAN_PEER_CP_STAT(ni, tx_assoc_fail);
#endif
}
#ifdef QCA_SUPPORT_CP_STATS
peer_cp_stats_tx_mgmt_dec(ni->peer_obj, 1);
#endif
ieee80211_complete_wbuf(wbuf,&ts);
}
else if ((fc_type == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_RESP)) ||
(fc_type == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_REASSOC_RESP))) {
if (ni->ni_assocstatus == IEEE80211_STATUS_SUCCESS) {
#ifdef QCA_SUPPORT_CP_STATS
WLAN_PEER_CP_STAT(ni, tx_assoc);
#endif
} else {
#ifdef QCA_SUPPORT_CP_STATS
WLAN_PEER_CP_STAT(ni, tx_assoc_fail);
#endif
}
}
return -retval;
}
在往下就是下面的过程了
ieee80211_send_mgmt
wlan_mgmt_txrx_mgmt_frame_tx{
tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send(vdev, buf, desc->desc_id, mgmt_tx_params)
实际调用 ol_if_mgmt_send 因为 tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send = ol_if_mgmt_send
{
ol_ath_tx_mgmt_wmi_send(ic, nbuf, ni, mgmt_tx_params);
ol_mgmt_send
wmi_mgmt_unified_cmd_send
wmi_handle->ops->send_mgmt_cmd
实际调用 send_mgmt_cmd_tlv,因为 wmi_handle->ops->send_mgmt_cmd = send_mgmt_cmd_tlv
{
wmi_unified_cmd_send
wmi_htc_send_pkt
htc_send_pkt
__htc_send_pkt
}
}
}
高阶
去掉roam时probe 请求帧
void ieee80211_mlme_join_infra_continue(struct ieee80211vap *vap, int32_t status)
{
if ((ic->ic_strict_pscan_enable && IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan))
&& !vap->iv_wps_mode) {
mlme_priv->im_request_type = MLME_REQ_NONE;
IEEE80211_DELIVER_EVENT_MLME_JOIN_COMPLETE_INFRA(vap, IEEE80211_STATUS_SUCCESS);
return;
}
else {
/* Send a direct probe to increase the odds of receiving a probe response */
// 把下面的屏蔽掉,并且wpa_cli 需要把list_network bssid 字段为 any,可以用
// wpa_cli -p /var/run/wpa_supplicant-ath0 -iath0 set_network 0 bssid "any" 命令设置,然后进行roam
// ieee80211_send_probereq(ni, vap->iv_myaddr, ni->ni_bssid,
// ni->ni_bssid, ni->ni_essid, ni->ni_esslen,
// vap->iv_opt_ie.ie, vap->iv_opt_ie.length);
WIM_LOG_DEBUG("SMAC:%s DMAC:%s",ether_sprintf(vap->iv_myaddr),ether_sprintf(ni->ni_bssid));
}
}