驱动层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

  1. 初始化缓存,并设置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);
    
  2. 注册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中调用
    
    
  3. 如果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));
    }
}