驱动层RX MGMT过程
ol_ath_mgmt_rx_event_handler函数分析
static int ol_ath_mgmt_rx_event_handler(ol_scn_t sc, u_int8_t *data, u_int32_t datalen)
{
wbuf_t wbuf;
// 将data数据解压,到rx_event里面
// bufp 指向
struct mgmt_rx_event_params rx_event = {0};
wmi_extract_mgmt_rx_params(wmi_handle, data, &rx_event, &bufp);
//初始化缓存长度为接受数据的长度rx_event.buf_len
wbuf = wbuf_alloc(ic->ic_osdev, WBUF_RX_INTERNAL,len);
wbuf_init(wbuf, rx_event.buf_len);
wh = (struct ieee80211_frame *)wbuf_header(wbuf);
// 拷贝管理帧数据到wh 中
OS_MEMCPY(wh, bufp, rx_event.buf_len);
{
uint8_t mgmt_type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
uint8_t mgmt_subtype = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
WIM_LOG_DEBUG("rx frame type 0x%x subtype 0x%x "QDF_MAC_ADDR_FMT" ",mgmt_type, mgmt_subtype,QDF_MAC_ADDR_REF(wh->i_addr2));
}
// 继续往下调用 处理 wh 管理帧 下面分析 ol_ath_mgmt_handler函数
ol_ath_mgmt_handler(pdev, scn, wbuf, wh, rx_event, false);
}
上面分析的疑问
ol_ath_mgmt_rx_event_handler函数哪里注册和调用?注册地方
void ol_ath_mgmt_soc_attach(ol_ath_soc_softc_t *soc) { wmi_unified_t wmi_handle; wmi_handle = lmac_get_wmi_unified_hdl(soc->psoc_obj); /* Register WMI event handlers 注册地方 */ wmi_unified_register_event_handler(wmi_handle, wmi_mgmt_rx_event_id, ol_ath_mgmt_rx_event_handler, WMI_RX_UMAC_CTX); { return wmi_register_event_handler_with_ctx(wmi_handle, event_id,handler_func, rx_ctx,WMI_RX_PROCESSED_BUFF); { // 真正把ol_ath_mgmt_rx_event_handler赋值给 wmi_handle->event_handler[idx] 指针,下面看在哪里调用的 wmi_handle->event_handler[idx] = handler_func; // 真正把ol_ath_mgmt_rx_event_handler赋值给 wmi_handle->event_handler[idx] 指针, wmi_handle->event_id[idx] = evt_id; } } }
调用地方
static QDF_STATUS wmi_initialize_worker_context(struct wmi_unified *wmi_handle) { // 创建工作线程,回调函数为 wmi_rx_diag_event_work qdf_create_work(0, &wmi_handle->rx_event_work,wmi_rx_event_work, wmi_handle); } // 在工作线程中,取出数据队列,然后调用__wmi_control_rx处理 static void wmi_rx_event_work(void *arg) { buf = qdf_nbuf_queue_remove(&wmi->event_queue); while (buf) { __wmi_control_rx(wmi, buf); { void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) { /* Call the WMI registered event handler */ if (wmi_handle->target_type == WMI_TLV_TARGET) { ev_buff_type = wmi_handle->ctx[idx].buff_type; if (ev_buff_type == WMI_RX_PROCESSED_BUFF) { wmi_handle->event_handler[idx] (wmi_handle->scn_handle,wmi_cmd_struct_ptr, len); // 实际调用地方 } else if (ev_buff_type == WMI_RX_RAW_BUFF) { ev_buf.evt_raw_buf = data; ev_buf.evt_processed_buf = wmi_cmd_struct_ptr; wmi_handle->event_handler[idx] (wmi_handle->scn_handle,(void *)&ev_buf, len); } } else wmi_handle->event_handler[idx] (wmi_handle->scn_handle,data, len); } } } }
怎么解压数据到event中?
struct mgmt_rx_event_params { uint32_t chan_freq; uint32_t channel; uint32_t snr; uint8_t rssi_ctl[WLAN_MGMT_TXRX_HOST_MAX_ANTENNA]; uint32_t rate; enum wlan_phymode phy_mode; uint32_t buf_len; uint8_t status; uint32_t flags; int32_t rssi; uint32_t tsf_delta; uint8_t pdev_id; void *rx_params; }; static QDF_STATUS extract_mgmt_rx_params_tlv(wmi_unified_t wmi_handle, void *evt_buf, struct mgmt_rx_event_params *hdr, uint8_t **bufp) { WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs = NULL; wmi_mgmt_rx_hdr *ev_hdr = NULL; int i; param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *) evt_buf; ev_hdr = param_tlvs->hdr; hdr->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( wmi_handle, ev_hdr->pdev_id); hdr->chan_freq = ev_hdr->chan_freq; hdr->channel = ev_hdr->channel; hdr->snr = ev_hdr->snr; hdr->rate = ev_hdr->rate; hdr->phy_mode = ev_hdr->phy_mode; hdr->buf_len = ev_hdr->buf_len; hdr->status = ev_hdr->status; hdr->flags = ev_hdr->flags; hdr->rssi = ev_hdr->rssi; hdr->tsf_delta = ev_hdr->tsf_delta; for (i = 0; i < ATH_MAX_ANTENNA; i++) hdr->rssi_ctl[i] = ev_hdr->rssi_ctl[i]; *bufp = param_tlvs->bufp; return QDF_STATUS_SUCCESS; }
ol_ath_mgmt_handler函数后面干了什么?下面新开章节分析
大致流程如下:
static int ol_ath_mgmt_rx_event_handler(ol_scn_t sc, u_int8_t *data, u_int32_t datalen) { struct mgmt_rx_event_params rx_event = {0}; // 解压tlv数据 存放到rx_event里面 wmi_extract_mgmt_rx_params(wmi_handle, data, &rx_event, &bufp); ol_ath_mgmt_handler(pdev, scn, wbuf, wh, rx_event, false); { mgmt_txrx_rx_handler(psoc, wbuf, &rx_event); { mgmt_rx_ops = wlan_lmac_if_get_mgmt_txrx_rx_ops(psoc); if (mgmt_rx_ops && mgmt_rx_ops->mgmt_rx_frame_handler) return mgmt_rx_ops->mgmt_rx_frame_handler(psoc, nbuf, params); //该函数为 tgt_mgmt_txrx_rx_frame_handler { // 该函数很重要 下面单独拉出来,分析 } } } }
ol_ath_mgmt_handler函数分析
void ol_ath_mgmt_handler(struct wlan_objmgr_pdev *pdev,
struct ol_ath_softc_net80211 *scn,
wbuf_t wbuf,
struct ieee80211_frame * wh,
struct mgmt_rx_event_params rx_event,
bool null_data_handler)
{
struct ieee80211com *ic = &scn->sc_ic;
struct ieee80211_rx_status rs;
struct ieee80211_node *ni;
struct wlan_objmgr_psoc *psoc;
qdf_mem_zero(&rs, sizeof(rs));
// 这里根据帧内容 找到一个node,
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wbuf_header(wbuf), WLAN_MGMT_RX_ID);
psoc = wlan_pdev_get_psoc(scn->sc_pdev);
// 把一些状态赋值给 struct ieee80211_rx_status
rs.rs_ic = ic;
rs.rs_ni = ni;
rs.rs_snr = rx_event.snr;
rx_event.rx_params = (void *)&rs; // 注意这里的 rx_event.rx_params 是struct ieee80211_rx_status
// 如果我们收到一个带有广播 bssid 的 probereq,通常发送者发送以发现新网络,所有 vap 都应发送回复
// ol_ath_rxstat2ieee(ic, &rx_event, &rs);函数,继续跟进ic和rx_event数据更新 状态到 rs中
// 这里最终到到了mgmt_txrx_rx_handler(psoc, wbuf, &rx_event);函数 下面分析
if (ni == NULL || (IEEE80211_IS_PROBEREQ(wh) && IEEE80211_IS_BROADCAST(wh->i_addr3))) {
ol_ath_rxstat2ieee(ic, &rx_event, &rs);
mgmt_txrx_rx_handler(psoc, wbuf, &rx_event);
if (ni) {
ieee80211_free_node(ni, WLAN_MGMT_RX_ID);
}
} else {
ol_ath_rxstat2ieee(ni->ni_ic, &rx_event, &rs);
#ifdef QCA_SUPPORT_CP_STATS
WLAN_PEER_CP_STAT_SET(ni, rx_mgmt_rate, rx_event.rate);
WLAN_PEER_CP_STAT_SET(ni, rx_mgmt_snr, rx_event.snr);
#endif
/*
* hand over the wbuf to the mgmt_txrx layer
* for further processing.
*/
mgmt_txrx_rx_handler(psoc, wbuf, &rx_event);
ieee80211_free_node(ni, WLAN_MGMT_RX_ID);
}
return ;
}
mgmt_txrx_rx_handler函数分析
static inline QDF_STATUS
mgmt_txrx_rx_handler(struct wlan_objmgr_psoc *psoc, qdf_nbuf_t nbuf,
void *params)
{
struct wlan_lmac_if_mgmt_txrx_rx_ops *mgmt_rx_ops;
// 根据psoc 得到 注册的 管理帧处理函数mgmt_rx_ops
mgmt_rx_ops = wlan_lmac_if_get_mgmt_txrx_rx_ops(psoc);
// 调用该函数,实际 mgmt_txrx_rx_ops->mgmt_rx_frame_handler =tgt_mgmt_txrx_rx_frame_handler;
// 故而调用tgt_mgmt_txrx_rx_frame_handler函数,下面分析该函数
if (mgmt_rx_ops && mgmt_rx_ops->mgmt_rx_frame_handler)
return mgmt_rx_ops->mgmt_rx_frame_handler(psoc, nbuf, params);
if (nbuf)
qdf_nbuf_free(nbuf);
return QDF_STATUS_E_NULL_VALUE;
}
tgt_mgmt_txrx_rx_frame_handler函数分析
QDF_STATUS tgt_mgmt_txrx_rx_frame_handler(
struct wlan_objmgr_psoc *psoc,
qdf_nbuf_t buf,
struct mgmt_rx_event_params *mgmt_rx_params)
{
struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
struct ieee80211_frame *wh;
qdf_nbuf_t copy_buf;
struct wlan_objmgr_peer *peer = NULL;
uint8_t mgmt_type, mgmt_subtype;
uint8_t *mac_addr, *mpdu_data_ptr;
enum mgmt_frame_type frm_type;
struct mgmt_rx_handler *rx_handler;
struct mgmt_rx_handler *rx_handler_head = NULL, *rx_handler_tail = NULL;
u_int8_t *data, *ivp = NULL;
uint16_t buflen;
uint16_t len = 0;
QDF_STATUS status = QDF_STATUS_SUCCESS;
bool is_from_addr_valid, is_bssid_valid;
data = (uint8_t *)qdf_nbuf_data(buf);
wh = (struct ieee80211_frame *)data;
buflen = qdf_nbuf_len(buf);
// 得到管理帧的类型
/* 得到帧类型 mgmt_type 00 管理帧
01 控制帧
10 数据帧
mgmt_subtype 对于mgmt_type为00的管理帧 该字段意思为
0000 Association request
0001 Association response
0010 Reassociation req
0011 Reassociation response
0100 Probe response
0101 Probe response
1000 Beacon
1001 ATIM
1010 Disassociation
1011 Authentication
1100 Deauthentication
*/
mgmt_type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
mgmt_subtype = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
/* 得到80211 数据实体的指针 mpdu_data_ptr is pointer to action header */
mpdu_data_ptr = (uint8_t *)qdf_nbuf_data(buf) +izeof(struct ieee80211_frame);
frm_type = mgmt_txrx_get_frm_type(mgmt_subtype, mpdu_data_ptr);
mgmt_txrx_psoc_ctx = (struct mgmt_txrx_priv_psoc_context *)wlan_objmgr_psoc_get_comp_private_obj(psoc,WLAN_UMAC_COMP_MGMT_TXRX);
// 下面 功能会取出所有注册的处理函数,rx_handler_head 指向其头部 rx_handler_tail 指向其尾部 注册的地方下面分析
// 根据查找函数一共注册了3个
// MGMT_FRAME_TYPE_ALL 对应 ieee80211_mgmt_input 函数
// MGMT_PROBE_RESP 对应 tgt_scan_bcn_probe_rx_callback 函数
// MGMT_BEACON 对应 tgt_scan_bcn_probe_rx_callback 函数
rx_handler = mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type];
if (rx_handler) {
status = wlan_mgmt_txrx_rx_handler_list_copy(rx_handler,&rx_handler_head, &rx_handler_tail);
}
rx_handler = mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[MGMT_FRAME_TYPE_ALL];
if (rx_handler) {
status = wlan_mgmt_txrx_rx_handler_list_copy(rx_handler,
&rx_handler_head, &rx_handler_tail);
}
mac_addr = (uint8_t *)wh->i_addr2;
/*
* peer can be NULL in following 2 scenarios:
* 1. broadcast frame received
* 2. operating in monitor mode
*
* and in both scenarios, the receiver of frame
* is expected to do processing accordingly considerng
* the fact that peer = NULL can be received and is a valid
* scenario.
*/
peer = wlan_objmgr_get_peer(psoc, mgmt_rx_params->pdev_id,mac_addr, WLAN_MGMT_SB_ID);
if (!peer && !qdf_is_macaddr_broadcast(
(struct qdf_mac_addr *)wh->i_addr1)) {
mac_addr = (uint8_t *)wh->i_addr1;
peer = wlan_objmgr_get_peer(psoc,mgmt_rx_params->pdev_id, mac_addr, WLAN_MGMT_SB_ID);
}
// 下面就是轮询调用上面的三个回调函数 从rx_handler_head 调用到 rx_handler_tail
// tgt_scan_bcn_probe_rx_callback tgt_scan_bcn_probe_rx_callback ieee80211_mgmt_input
// 故而只需分析tgt_scan_bcn_probe_rx_callback和ieee80211_mgmt_input函数即可
rx_handler = rx_handler_head;
while (rx_handler->next) {
copy_buf = qdf_nbuf_clone(buf);
if (!copy_buf) {
rx_handler = rx_handler->next;
continue;
}
rx_handler->rx_cb(psoc, peer, copy_buf,
mgmt_rx_params, frm_type);
rx_handler = rx_handler->next;
}
rx_handler->rx_cb(psoc, peer, buf,
mgmt_rx_params, frm_type);
if (peer)
wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_SB_ID);
rx_handler_mem_free:
while (rx_handler_head) {
rx_handler = rx_handler_head;
rx_handler_head = rx_handler_head->next;
qdf_mem_free(rx_handler);
}
return status;
}
遗留问题
mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type]值哪里来的下面先介绍几个重要概念:
结构体
struct mgmt_rx_handler内容如下,就是一个单向链表struct mgmt_rx_handler { enum wlan_umac_comp_id comp_id; mgmt_frame_rx_callback rx_cb; struct mgmt_rx_handler *next; };
comp_id 组件id如下:
enum wlan_umac_comp_id { WLAN_UMAC_COMP_MLME = 0, WLAN_UMAC_COMP_MGMT_TXRX = 1, WLAN_UMAC_COMP_SERIALIZATION = 2, WLAN_UMAC_COMP_SCAN = 3, WLAN_UMAC_COMP_PMO = 4, WLAN_UMAC_COMP_P2P = 5, WLAN_UMAC_COMP_POLICY_MGR = 6, WLAN_UMAC_COMP_CONFIG = 7, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX = 8, WLAN_UMAC_COMP_WIFI_POS = 9, WLAN_UMAC_COMP_TDLS = 10, WLAN_UMAC_COMP_ATF = 11, WLAN_UMAC_COMP_SA_API = 12, WLAN_UMAC_COMP_REGULATORY = 13, WLAN_UMAC_COMP_CRYPTO = 14, WLAN_UMAC_COMP_NAN = 15, WLAN_UMAC_COMP_DFS = 16, WLAN_UMAC_COMP_OFFCHAN_TXRX = 17, WLAN_UMAC_COMP_SON = 18, WLAN_UMAC_COMP_SPECTRAL = 19, WLAN_UMAC_COMP_SPLITMAC = 20, WLAN_UMAC_COMP_DISA = 21, WLAN_UMAC_COMP_GREEN_AP = 22, WLAN_UMAC_COMP_FTM = 23, WLAN_UMAC_COMP_FD = 24, WLAN_UMAC_COMP_OCB = 25, WLAN_UMAC_COMP_IPA = 26, WLAN_UMAC_COMP_CP_STATS = 27, WLAN_UMAC_COMP_ACTION_OUI = 28, WLAN_UMAC_COMP_FWOL = 29, WLAN_UMAC_COMP_CFR = 30, WLAN_UMAC_COMP_INTEROP_ISSUES_AP = 31, WLAN_UMAC_COMP_BLACKLIST_MGR = 32, WLAN_UMAC_COMP_COEX = 33, WLAN_UMAC_COMP_FTM_TIME_SYNC = 34, WLAN_UMAC_COMP_PKT_CAPTURE = 35, WLAN_UMAC_COMP_DCS = 36, WLAN_IOT_SIM_COMP = 37, WLAN_UMAC_COMP_IF_MGR = 38, WLAN_UMAC_COMP_GPIO = 39, WLAN_UMAC_COMP_ID_MAX, };
mgmt_rx_comp_cb[frm_type]是struct mgmt_rx_handler *类型槽,一共MGMT_FRAME_TYPE_ALL多个如下图所示,一共有119个槽,每个槽的索引为帧类型,没个槽下面可以挂N个
rx_handler,
wlan_mgmt_txrx_register_rx_cb函数作用即实现下面的功能有N个
struct mgmt_rx_handler*类型的槽,每个槽初始都是空的,每个槽的索引为frm_type,比如我们现在同一个frm_type类型下挂了多个struct mgmt_rx_handler的实体,操作如下:struct mgmt_txrx_mgmt_frame_cb_info cb_info[2]; cb_info[0].frm_type = MGMT_BEACON; cb_info[0].mgmt_rx_cb = tgt_scan_bcn_rx_callback; cb_info[1].frm_type = MGMT_BEACON; cb_info[1].mgmt_rx_cb = tgt_scan_probe_rx_callback; wlan_mgmt_txrx_register_rx_cb(psoc,WLAN_UMAC_COMP_SCAN, cb_info, 2); /* 调用完函数后, struct mgmt_rx_handler[0]->rx_cb = cb_info[0].mgmt_rx_cb即tgt_scan_bcn_rx_callback struct mgmt_rx_handler[1]->rx_cb = cb_info[1].mgmt_rx_cb即tgt_scan_probe_rx_callback struct mgmt_rx_handler[1]->next = struct mgmt_rx_handler[0] mgmt_rx_comp_cb[MGMT_BEACON] = struct mgmt_rx_handler[1] 效果如下: |--------------------------------------| MGMT_BEACON| struct mgmt_rx_handler[1] |->next 指向 struct mgmt_rx_handler[0] |--------------------------------------| */
说白了就是把他们单链表串起来
实际的代码中注册地方
rx_cb_info.frm_type = MGMT_FRAME_TYPE_ALL;
rx_cb_info.mgmt_rx_cb = ieee80211_mgmt_input;
wlan_mgmt_txrx_register_rx_cb(soc->psoc_obj, WLAN_UMAC_COMP_MLME,&rx_cb_info, 1);
struct mgmt_txrx_mgmt_frame_cb_info cb_info[2];
cb_info[0].frm_type = MGMT_PROBE_RESP;
cb_info[0].mgmt_rx_cb = tgt_scan_bcn_probe_rx_callback;
cb_info[1].frm_type = MGMT_BEACON;
cb_info[1].mgmt_rx_cb = tgt_scan_bcn_probe_rx_callback;
wlan_mgmt_txrx_register_rx_cb(psoc,WLAN_UMAC_COMP_SCAN, cb_info, 2);
最终效果如下:
struct mgmt_rx_handler *类型槽
|--------------------------------------|
| MGMT_ASSOC_REQ |
|--------------------------------------|
| MGMT_ASSOC_RESP |
|--------------------------------------|
: ______________________________________________
|--------------------------------------| |comp_id = WLAN_UMAC_COMP_SCAN |
| MGMT_PROBE_RESP |struct mgmt_rx_handler |rx_cb = tgt_scan_bcn_probe_rx_callback | 【A】
|--------------------------------------| |next = mgmt_rx_comp_cb[MGMT_PROBE_RESP] |
: ______________________________________________
|--------------------------------------| |comp_id = WLAN_UMAC_COMP_SCAN |
| MGMT_BEACON |struct mgmt_rx_handler |rx_cb = tgt_scan_bcn_probe_rx_callback |【B】
|--------------------------------------| |next = mgmt_rx_comp_cb[MGMT_BEACON] |
: --------------------------------------------------------------------------
:
: ______________________________________________
|--------------------------------------| |comp_id = WLAN_UMAC_COMP_MLME |
| MGMT_FRAME_TYPE_ALL |struct mgmt_rx_handler |rx_cb = ieee80211_mgmt_input |【C】
|--------------------------------------| |next = mgmt_rx_comp_cb[MGMT_FRAME_TYPE_ALL] |
--------------------------------------------------------------------------
wlan_mgmt_txrx_rx_handler_list_copy(rx_handler,&rx_handler_head, &rx_handler_tail)函数作用是什么把rx_handler里面的内容,串起来,rx_handler_head指向其头,rx_handler_tail指向其尾部,比如上面注册的三个,调用后如下
rx_handler = mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type]; if (rx_handler) { status = wlan_mgmt_txrx_rx_handler_list_copy(rx_handler,&rx_handler_head, &rx_handler_tail); } rx_handler = mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[MGMT_FRAME_TYPE_ALL]; if (rx_handler) { status = wlan_mgmt_txrx_rx_handler_list_copy(rx_handler, &rx_handler_head, &rx_handler_tail); }
比如现在传入的是beacon帧,结果如下:
rx_handler_head->【B】 ->【C】<-rx_handler_tail
如果beacon帧后面还有handler,比如存在B1,那么最终结果如下:
rx_handler_head->【B1】 ->【B】 ->【C】<-rx_handler_tail
综上:下面需要分析:
tgt_scan_bcn_probe_rx_callback函数ieee80211_mgmt_input函数
tgt_scan_bcn_probe_rx_callback函数分析
QDF_STATUS tgt_scan_bcn_probe_rx_callback(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_peer *peer, qdf_nbuf_t buf,
struct mgmt_rx_event_params *rx_param,
enum mgmt_frame_type frm_type)
{
struct scheduler_msg msg = {0};
struct scan_bcn_probe_event *bcn = NULL;
QDF_STATUS status;
uint32_t scan_queue_size = 0;
// 进行类型判断,能进到该函数的只有PROBE_RESP和BEACON帧
if ((frm_type != MGMT_PROBE_RESP) &&
(frm_type != MGMT_BEACON)) {
scm_err("frame is not beacon or probe resp");
status = QDF_STATUS_E_INVAL;
goto free;
}
// 创建struct scan_bcn_probe_event 并 填充内容
bcn = qdf_mem_malloc_atomic(sizeof(*bcn));
bcn->rx_data =qdf_mem_malloc_atomic(sizeof(*rx_param));
if (frm_type == MGMT_PROBE_RESP)
bcn->frm_type = MGMT_SUBTYPE_PROBE_RESP;
else
bcn->frm_type = MGMT_SUBTYPE_BEACON;
bcn->psoc = psoc;
bcn->buf = buf;
// 拷贝数据
qdf_mem_copy(bcn->rx_data, rx_param, sizeof(*rx_param));
// 创建msg
msg.bodyptr = bcn;
msg.callback = scm_handle_bcn_probe;
msg.flush_callback = scm_bcn_probe_flush_callback;
// 调度器post 消息,调度器运作机制,参见本文档《scheduler_post_message 消息机制》章节
status = scheduler_post_message(QDF_MODULE_ID_SCAN,
QDF_MODULE_ID_SCAN,
QDF_MODULE_ID_SCAN, &msg);
// 到这里,等待调度器取到该消息,会执行该消息的回调函数scm_handle_bcn_probe 下面分析该函数
free:
if (bcn && bcn->rx_data)
qdf_mem_free(bcn->rx_data);
if (bcn)
qdf_mem_free(bcn);
if (buf)
qdf_nbuf_free(buf);
return status;
}
scm_handle_bcn_probe函数分析
QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
{
return __scm_handle_bcn_probe(msg->bodyptr);
}
// 该函数的主要作用就是解压beacon帧,根据需要 然后把sacn_list 插入到 内核的扫描列表中,这里不做过多分析
QDF_STATUS __scm_handle_bcn_probe(struct scan_bcn_probe_event *bcn)
{
struct wlan_objmgr_psoc *psoc;
struct wlan_objmgr_pdev *pdev = NULL;
struct scan_cache_entry *scan_entry;
struct wlan_scan_obj *scan_obj;
qdf_list_t *scan_list = NULL;
QDF_STATUS status = QDF_STATUS_SUCCESS;
uint32_t list_count, i;
qdf_list_node_t *next_node = NULL;
struct scan_cache_node *scan_node;
struct wlan_frame_hdr *hdr = NULL;
hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcn->buf);
psoc = bcn->psoc;
pdev = wlan_objmgr_get_pdev_by_id(psoc,
bcn->rx_data->pdev_id, WLAN_SCAN_ID);
scan_obj = wlan_psoc_get_scan_obj(psoc);
if (bcn->frm_type == MGMT_SUBTYPE_BEACON &&
wlan_reg_is_dfs_for_freq(pdev, bcn->rx_data->chan_freq)) {
util_scan_add_hidden_ssid(pdev, bcn->buf);
}
scan_list =
util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf),
qdf_nbuf_len(bcn->buf), bcn->frm_type,
bcn->rx_data);
if (!scan_list || qdf_list_empty(scan_list)) {
scm_debug("failed to unpack %d frame BSSID: "QDF_MAC_ADDR_FMT,
bcn->frm_type, QDF_MAC_ADDR_REF(hdr->i_addr3));
status = QDF_STATUS_E_INVAL;
goto free_nbuf;
}
list_count = qdf_list_size(scan_list);
for (i = 0; i < list_count; i++) {
status = qdf_list_remove_front(scan_list, &next_node);
if (QDF_IS_STATUS_ERROR(status) || !next_node) {
scm_debug("list remove failure i:%d, lsize:%d, BSSID: "QDF_MAC_ADDR_FMT,
i, list_count, QDF_MAC_ADDR_REF(hdr->i_addr3));
status = QDF_STATUS_E_INVAL;
goto free_nbuf;
}
scan_node = qdf_container_of(next_node,
struct scan_cache_node, node);
scan_entry = scan_node->entry;
if (scan_obj->drop_bcn_on_chan_mismatch &&
scan_entry->channel_mismatch) {
scm_nofl_debug("Drop frame for chan mismatch "QDF_MAC_ADDR_FMT" Seq Num: %d freq %d RSSI %d",
QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
scan_entry->seq_num,
scan_entry->channel.chan_freq,
scan_entry->rssi_raw);
util_scan_free_cache_entry(scan_entry);
qdf_mem_free(scan_node);
continue;
}
/* Do not add invalid channel entry as kernel will reject it */
if (scan_obj->drop_bcn_on_invalid_freq &&
wlan_reg_is_disable_for_freq(pdev,
scan_entry->channel.chan_freq)) {
scm_nofl_debug("Drop frame for invalid freq %d: "QDF_MAC_ADDR_FMT" Seq Num: %d RSSI %d",
scan_entry->channel.chan_freq,
QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
scan_entry->seq_num,
scan_entry->rssi_raw);
util_scan_free_cache_entry(scan_entry);
qdf_mem_free(scan_node);
continue;
}
if (scan_obj->cb.update_beacon)
scan_obj->cb.update_beacon(pdev, scan_entry);
status = scm_add_update_entry(psoc, pdev, scan_entry);
if (QDF_IS_STATUS_ERROR(status)) {
scm_debug("failed to add entry for BSSID: "QDF_MAC_ADDR_FMT" Seq Num: %d",
QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
scan_entry->seq_num);
util_scan_free_cache_entry(scan_entry);
qdf_mem_free(scan_node);
continue;
}
qdf_mem_free(scan_node);
}
free_nbuf:
if (scan_list)
qdf_mem_free(scan_list);
if (bcn->psoc)
wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
if (pdev)
wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
if (bcn->rx_data)
qdf_mem_free(bcn->rx_data);
if (bcn->buf)
qdf_nbuf_free(bcn->buf);
qdf_mem_free(bcn);
return status;
}
ieee80211_mgmt_input函数分析
QDF_STATUS
ieee80211_mgmt_input(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_peer *peer,
wbuf_t wbuf,
struct mgmt_rx_event_params *mgmt_rx_params,
enum mgmt_frame_type txrx_type)
{
struct ieee80211_rx_status *rx_status = (struct ieee80211_rx_status *)mgmt_rx_params->rx_params;
struct ieee80211_node *ni = rx_status->rs_ni;
struct ieee80211_frame *wh = (struct ieee80211_frame *)wbuf_header(wbuf);
struct ieee80211com *ic = rx_status->rs_ic;
if (!ni || (IEEE80211_IS_PROBEREQ(wh) && IEEE80211_IS_BROADCAST(wh->i_addr3))) {
ieee80211_input_all(ic, wbuf, rx_status);
} else {
ieee80211_input(ni, wbuf, rx_status);
}
return QDF_STATUS_SUCCESS;
}
接下来分析ieee80211_input_all函数
int
ieee80211_input_all(struct ieee80211com *ic,
wbuf_t wbuf, struct ieee80211_rx_status *rs)
{
struct ieee80211_iter_input_all_arg params;
u_int32_t num_vaps;
struct ieee80211_frame *wh = (struct ieee80211_frame *)wbuf_header(wbuf);
uint8_t addr2[QDF_MAC_ADDR_SIZE];
uint8_t addr3[QDF_MAC_ADDR_SIZE];
bool is_mbss_ie_enable = wlan_pdev_nif_feat_cap_get(ic->ic_pdev_obj,
WLAN_PDEV_F_MBSS_IE_ENABLE);
bool is_probe_req = IEEE80211_IS_PROBEREQ(wh);
if (is_mbss_ie_enable && is_probe_req) {
qdf_mem_copy(addr2, wh->i_addr2, QDF_MAC_ADDR_SIZE);
qdf_mem_copy(addr3, wh->i_addr3, QDF_MAC_ADDR_SIZE);
ic->ic_mbss.resp_sent = 0;
}
params.wbuf = wbuf;
params.rs = rs;
params.type = -1;
ieee80211_iterate_vap_list_internal(ic,ieee80211_iter_input_all,(void *)¶ms,num_vaps);
if (is_mbss_ie_enable && is_probe_req) {
if (IEEE80211_IS_BROADCAST(addr3) ||
(!IEEE80211_IS_BROADCAST(addr3) &&
!ic->ic_mbss.resp_sent))
ieee80211_input_handle_mbss_probereq(ic, addr2);
}
if (params.wbuf != NULL) /* no vaps, reclaim wbuf */
wbuf_free(params.wbuf);
return params.type;
}
大致顺序如下:
ieee80211_input_all
ieee80211_iterate_vap_list_internal(ic,ieee80211_iter_input_all,(void *)¶ms,num_vaps);
ieee80211_iter_input_all
ieee80211_input
int
ieee80211_input(struct ieee80211_node *ni, wbuf_t wbuf, struct ieee80211_rx_status *rs)
{
#define QOS_NULL (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL)
#define HAS_SEQ(type, subtype) (((type & 0x4) == 0) && ((type | subtype) != QOS_NULL))
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_frame *wh;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_phy_stats *phy_stats;
int type = -1, subtype = -1, dir;
u_int16_t rxseq =0;
u_int8_t *bssid;
bool snr_update = true;
bool is_bcast = false;
wh = (struct ieee80211_frame *) wbuf_header(wbuf);
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
if (IEEE80211_IS_BROADCAST(wh->i_addr3))
is_bcast = true;
if(snr_update && rs->rs_isvalidsnr)
ni->ni_snr = rs->rs_snr;
if (type == IEEE80211_FC0_TYPE_DATA) {
// 这里处理data帧
ieee80211_input_data(ni, wbuf, rs, subtype, dir);
} else if (type == IEEE80211_FC0_TYPE_MGT) {
// 这里处理管理帧
IEEE80211_HANDLE_MGMT(ic,vap,ni, wbuf, subtype,type, rs);
} else if (type == IEEE80211_FC0_TYPE_CTL) {
// 这里处理控制帧
ieee80211_recv_ctrl(ni, wbuf, subtype, rs);
/*
* deliver the frame to the os. the handler cosumes the wbuf.
*/
if (vap->iv_evtable) {
vap->iv_evtable->wlan_receive(vap->iv_ifp, wbuf, type, subtype, rs);
}
}
}
调用过程如下:
IEEE80211_HANDLE_MGMT
ieee80211_recv_mgmt
int
ieee80211_recv_mgmt(struct ieee80211_node *ni,
wbuf_t wbuf,
int subtype,
struct ieee80211_rx_status *rs)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_frame *wh;
int is_bcast, forward_to_filter = 1;
int i;
int eq=0, ret = 0;
struct ieee80211vap *tmpvap = NULL;
bool action_taken = true;
wh = (struct ieee80211_frame *) wbuf_header(wbuf);
if ((vap->iv_opmode == IEEE80211_M_HOSTAP) && vap->iv_vap_is_down) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME,
"AP vap_is_down. drop frame subtype: %d, TA:%s\n", subtype,
ether_sprintf(wh->i_addr2));
return -EINVAL;
}
/* Make sure this is not a rogue frame carrying source address
* same as some active vap on underlying radio.
* If yes, do not process this frame and drop it.
*/
TAILQ_FOREACH(tmpvap, &(ic)->ic_vaps, iv_next) {
if (IEEE80211_ADDR_EQ(wh->i_addr2, tmpvap->iv_myaddr)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_AUTH,
"%s: WARN: Rx frame subtype:%d on vap:%d from mac:%s(matching vap:%d)\n",
__func__, subtype, vap->iv_unit, ether_sprintf(wh->i_addr2),
tmpvap->iv_unit);
return -EINVAL;
}
}
if (IEEE80211_IS_MULTICAST(wh->i_addr2) ||
IS_NULL_ADDR(wh->i_addr2)) {
/* Drop the management and control frames originated with invalid
* address, viz., multicast or zero address
*/
IEEE80211_DPRINTF(vap, IEEE80211_MSG_INPUT,
"%s: Invalid SA:%s in received mgmt frm - ignore silently",
__func__, ether_sprintf(wh->i_addr2));
return 0;
}
/* check for ACL policy if smart mesh is enabled */
if ((vap->iv_smart_mesh_cfg & SMART_MESH_ACL_ENHANCEMENT)) {
if (!ieee80211_acl_check(vap, wh->i_addr2)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
"[%s] MGMT subtype:%d, disallowed by ACL \n", ether_sprintf(ni->ni_macaddr), subtype);
#ifdef QCA_SUPPORT_CP_STATS
vdev_cp_stats_rx_acl_inc(vap->vdev_obj, 1);
#endif
return -EINVAL;
}
}
#if UMAC_SUPPORT_WNM
if (ieee80211_vap_wnm_is_set(vap) && ieee80211_wnm_bss_is_set(vap->wnm) &&
ni != ni->ni_bss_node) {
ieee80211_wnm_bssmax_updaterx(ni, IEEE80211_IS_MFP_FRAME(wh));
}
#endif
if(subtype == IEEE80211_FC0_SUBTYPE_AUTH ||
subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ||
subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
if (ni != ni->ni_vap->iv_bss) {
wds_clear_wds_table(ni,&ic->ic_sta, wbuf);
}
}
is_bcast = IEEE80211_IS_BROADCAST(wh->i_addr1) ? 1:0;
if (IEEE80211_IS_MFP_FRAME(wh)) {
struct wlan_objmgr_pdev *pdev;
struct wlan_objmgr_psoc *psoc;
struct wlan_lmac_if_crypto_rx_ops *crypto_rx_ops;
pdev = ic->ic_pdev_obj;
if(pdev == NULL) {
qdf_print("%s[%d]pdev is NULL", __func__, __LINE__);
return -1;
}
psoc = wlan_pdev_get_psoc(pdev);
if(psoc == NULL) {
qdf_print("%s[%d]psoc is NULL", __func__, __LINE__);
return -1;
}
IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "Received MFP frame with Subtype 0x%2X\n", subtype);
/*
* There are two reasons that a received MFP frame must be dropped:
* 1) decryption error
* 2) MFP is not negociated
*/
crypto_rx_ops = wlan_crypto_get_crypto_rx_ops(psoc);
if ((crypto_rx_ops && WLAN_CRYPTO_RX_OPS_DECAP(crypto_rx_ops) &&
(WLAN_CRYPTO_RX_OPS_DECAP(crypto_rx_ops)(vap->vdev_obj,
wbuf, ni->ni_macaddr, 16) != 0))
|| (!ieee80211_is_pmf_enabled(vap, ni)) || (rs->rs_flags)){
/* Increment rx decrypt errors in peer stats */
#ifdef QCA_SUPPORT_CP_STATS
peer_cp_stats_rx_decryptcrc_inc(ni->peer_obj, 1);
#endif
IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "Decrypt Error MFP frame with Subtype 0x%2X\n", subtype);
return -EINVAL;
} else {
#ifdef QCA_SUPPORT_CP_STATS
is_bcast ? vdev_mcast_cp_stats_rx_decryptok_inc(vap->vdev_obj, 1):
vdev_ucast_cp_stats_rx_decryptok_inc(vap->vdev_obj, 1);
#endif
}
/* recalculate wh pointer, header may shift after decap */
wh = (struct ieee80211_frame *) wbuf_header(wbuf);
/* NB: We clear the Protected bit later */
}
else {
u_int8_t *frm = (u_int8_t *)&wh[1];
u_int8_t *efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf);
struct ieee80211_action *ia;
IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_action));
ia = (struct ieee80211_action *)frm;
if (ieee80211_is_pmf_enabled(vap, ni) &&
(subtype == IEEE80211_FC0_SUBTYPE_ACTION)) {
switch(ia->ia_category) {
case IEEE80211_ACTION_CAT_SPECTRUM:
case IEEE80211_ACTION_CAT_QOS:
case IEEE80211_ACTION_CAT_DLS:
case IEEE80211_ACTION_CAT_BA:
case IEEE80211_ACTION_CAT_RADIO:
case IEEE80211_ACTION_CAT_SA_QUERY:
case IEEE80211_ACTION_CAT_PROT_DUAL:
case IEEE80211_ACTION_CAT_WNM:
case IEEE80211_ACTION_CAT_WMM_QOS:
case IEEE80211_ACTION_CAT_FST:
/* unprotected action frame that must be protected, drop it */
IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
wh, ieee80211_mgt_subtype_name[
subtype >> IEEE80211_FC0_SUBTYPE_SHIFT],
"%s", "mfp frame is not protected");
return -EINVAL;
default:
break;
}
}
}
if ((vap->iv_opmode == IEEE80211_M_HOSTAP) && (vap->iv_bss == ni)) {
switch (subtype) {
case IEEE80211_FC0_SUBTYPE_BEACON:
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
case IEEE80211_FC0_SUBTYPE_AUTH:
case IEEE80211_FC0_SUBTYPE_ATIM:
case IEEE80211_FC0_SUBTYPE_ACTION:
case IEEE80211_FCO_SUBTYPE_ACTION_NO_ACK:
break;
default:
IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "Dropping mgmt frame with subtype %d recevied in self peer\n",subtype);
return -EINVAL;
}
}
#ifdef QCA_SUPPORT_CP_STATS
is_bcast ? vdev_mcast_cp_stats_rx_mgmt_inc(vap->vdev_obj, 1):
vdev_ucast_cp_stats_rx_mgmt_inc(vap->vdev_obj, 1);
#endif
switch (subtype) {
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
case IEEE80211_FC0_SUBTYPE_BEACON:
ieee80211_recv_beacon(ni, wbuf, subtype, rs); // 处理接收的beacon帧 和 probe 应答帧
break;
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
if(ieee80211_recv_probereq(ni, wbuf, subtype, rs) < 0) { // 处理probe 请求帧
ret = -EINVAL;
forward_to_filter = 0;
}
break;
case IEEE80211_FC0_SUBTYPE_AUTH:
if(ieee80211_recv_auth(ni, wbuf, subtype, rs) < 0) { // 处理au请求帧
ret = -EINVAL;
forward_to_filter = 0;
}
break;
case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
ieee80211_recv_asresp(ni, wbuf, subtype); // 处理as的 应答帧
break;
case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: // 处理as 请求帧
case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
if (ieee80211_recv_asreq(ni, wbuf, subtype)) {
ret = -EINVAL;
forward_to_filter = 0;
}
break;
case IEEE80211_FC0_SUBTYPE_DEAUTH: // 处理 de au 帧
ret = ieee80211_recv_deauth(ni, wbuf, subtype);
break;
case IEEE80211_FC0_SUBTYPE_DISASSOC: // 处理 de as帧
ret = ieee80211_recv_disassoc(ni, wbuf, subtype);
break;
case IEEE80211_FC0_SUBTYPE_ACTION:
case IEEE80211_FCO_SUBTYPE_ACTION_NO_ACK:
ret = ieee80211_recv_action(ni, wbuf, subtype, rs, &action_taken);// 处理action帧
break;
default:
break;
}
/*
* deliver 802.11 frame if the OS is interested in it and
* we have decided to forward it. (Some processed Action frames are not forwarded
* to hostapd to avoid getting another response)
*/
if (ieee80211_vap_registered_is_set(vap) && forward_to_filter && vap->iv_evtable && vap->iv_evtable->wlan_receive_filter_80211) {
ret = vap->iv_evtable->wlan_receive_filter_80211(vap->iv_ifp, wbuf, IEEE80211_FC0_TYPE_MGT, subtype, rs);// os层面的过滤
if (ret && (subtype == IEEE80211_FC0_SUBTYPE_AUTH)) {
ni = ieee80211_vap_find_node(vap, wh->i_addr2, WLAN_MGMT_RX_ID);
if(ni && (ni != vap->iv_bss)) {
IEEE80211_NODE_LEAVE(ni) ;
}
if(ni) {
ieee80211_free_node(ni, WLAN_MGMT_RX_ID);
}
}
}
return ret;
}
scheduler_post_message 消息机制

scheduler提供一个消息处理的线程,有三个优先级的消息队列:
Timer Message Queue
Target Interface Message Queue
OS Interface Message Queue
**注意:**消息优先级顺序为Timer Message Queue > Target Interface Message Queue > OS Interface Message Queue
模块在post消息体中会存在钩子函数,在scheduler调度器中取到消息后,会调用消息的钩子函数。
scheduler调度器api如下:
scheduler_init(void):初始化调度器,创建控制器线程,和对应的消息队列scheduler_deinit(void):去初始化,释放资源scheduler_register_module(QDF_MODULE_ID qid, scheduler_msg_process_fn_callback):注册队列及其相应的处理程序。优先级顺序与注册队列的顺序相同scheduler_deregister_module(QDF_MODULE_ID qid):取消注册队列。这应该在卸载驱动程序期间完成,然后再执行调度程序卸载scheduler_post_msg_by_priority(qid, *msg, is_high_priority):将消息发布到给定消息队列的前面,根据队列优先级处理对用的消息
scheduler 消息使用示例:
这是一个初始化调度器的示例:
if (QDF_STATUS_SUCCESS != scheduler_init()) goto scheduler_init_fail;
注册队列的处理函数
scheduler_register_module(QDF_MODULE_ID_SYS,&scheduler_timer_q_mq_handler); scheduler_register_module(QDF_MODULE_ID_TARGET_IF,&scheduler_target_if_mq_handler); scheduler_register_module(QDF_MODULE_ID_OS_IF,&scheduler_os_if_mq_handler);
函数中提到的回调是指定队列的默认消息处理程序。无论何时将消息发布到指定队列,都会调用默认处理程序。
post msg
// 定义调度消息结构体msg struct scheduler_msg msg = {0}; // 下面是填充event_info内容, struct scan_event *event = &event_info->event; uint8_t vdev_id = event->vdev_id; QDF_STATUS status; event_info->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,vdev_id, WLAN_SCAN_ID); if (!event_info->vdev) { scm_err("null vdev, vdev_id: %d, psoc: 0x%p", vdev_id, psoc); return QDF_STATUS_E_INVAL; } // 这步很重要,填充消息msg 信息 msg.bodyptr = event_info; // 指针,在回调函数中 可以拿出来用,相当于一个用户指针,放什么内容自己决定 msg.callback = scm_scan_event_handler; // 消息回调函数
然后使用下面的代码post出消息
status = scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg);// 抛出消息到消息队里,scheduler取到消息后,会调用对应的回调函数scm_scan_event_handler if (QDF_IS_STATUS_ERROR(status)) { wlan_objmgr_vdev_release_ref(event_info->vdev, WLAN_SCAN_ID);
注意事项
msg.bodyptr指针由用户自己申请并释放内存,调度器不管,可以在post前申请内存
回调函数中释放内存
消息队列的申请管理释放等都是在调度器中完成
分发数据到网络协议栈
// 定义地方
static wlan_event_handler_table common_evt_handler = {
osif_receive,
osif_receive_filter_80211,
osif_receive_monitor_80211,
osif_dev_xmit_queue,
osif_vap_xmit_queue,
NULL,
#if ATH_SUPPORT_IWSPY
osif_iwspy_update,
#endif
#if ATH_SUPPORT_FLOWMAC_MODULE
osif_pause_queue,
#endif
osif_vap_scan_cancel, /* wlan_vap_scan_cancel */
osif_bringup_ap_vaps, /* wlan_bringup_ap_vaps */
};
// 注册地方
static void osif_vap_setup(wlan_if_t vap, struct net_device *dev,
enum ieee80211_opmode opmode)
{
osif_dev *osifp = ath_netdev_priv(dev);
switch(opmode) {
case IEEE80211_M_STA:
case IEEE80211_M_P2P_CLIENT:
wlan_vap_register_event_handlers(vap,&common_evt_handler);
case IEEE80211_M_HOSTAP:
case IEEE80211_M_P2P_GO:
wlan_vap_register_event_handlers(vap,&common_evt_handler); //
}
//函数原型
static void osif_receive (os_if_t osif, wbuf_t wbuf,
u_int16_t type, u_int16_t subtype,
ieee80211_recv_status *rs)
{
struct sk_buff *skb = (struct sk_buff *)wbuf;
if (type != IEEE80211_FC0_TYPE_DATA) {
if(wbuf_next(wbuf) != NULL) {
wbuf_t wbx = wbuf;
while (wbx) {
wbuf = wbuf_next(wbx);
wbuf_free(wbx);
wbx = wbuf;
}
} else {
wbuf_free(wbuf);
}
return;
}
/* deliver the data to network interface */
__osif_deliver_data(osif, skb);
}
// 调用地方
/*
* deliver the frame to the os. the handler cosumes the wbuf.
*/
if (vap->iv_evtable) {
vap->iv_evtable->wlan_receive(vap->iv_ifp, wbuf, type, subtype, rs);
}