http://blog.youkuaiyun.com/ussam/article/details/24693575
OpenWRT数据接收过程 这里使用的是ath9k网卡驱动,硬件平台是TP-link TL-WR841N V7.1 路由器
1. ieee80211_tasklet_handler()
Linux内核是通过中断来对接收到的数据进行响应的。当硬件检测到有接收数据的时候,产生一个中断,中断触发下半部的tasklet机制,在802.11协议栈这里会调用ieee80211_tasklet_handler()函数。我们来看一看函数体:(位于OpenWRT内核文件夹子目录/net/mac80211,文件main.c中)
- static void ieee80211_tasklet_handler(unsigned long data)
- {
- struct ieee80211_local *local = (struct ieee80211_local *) data;
- struct sk_buff *skb;
- while ((skb = skb_dequeue(&local->skb_queue)) ||
- (skb = skb_dequeue(&local->skb_queue_unreliable))) {
- switch (skb->pkt_type) {
- case IEEE80211_RX_MSG:
-
-
- skb->pkt_type = 0;
- ieee80211_rx(&local->hw, skb);
- break;
- case IEEE80211_TX_STATUS_MSG:
- ...
- default:
- ...
- }
- }
- }
2. ieee80211_rx()
系统收到数据时会开辟一个sk_buff缓存空间进行数据的存储,ieee80211_tasklet_handler()触发后对sk_buff中存储的数据帧进行判断,如果是接收来的数据(MPDU),则进入ieee80211_rx()函数:(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。
- void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
- {
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_rate *rate = NULL;
- struct ieee80211_supported_band *sband;
- struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- ...
- __ieee80211_rx_handle_packet(hw, skb);
- rcu_read_unlock();
- return;
- drop:
- kfree_skb(skb);
- }
- EXPORT_SYMBOL(ieee80211_rx);
3. __ieee80211_rx_handle_packet()
ieee80211_rx()函数再调用__ieee80211_rx_handle_packet()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中),__ieee80211_rx_handle_packet()是接收帧的处理函数,会对帧类型进行判断,如果检测出该帧是beacon帧(或sta主动扫描后从AP端返回的响应帧),则进入ieee80211_scan_rx()函数对帧信息进行扫描,如果是数据帧,则调用ieee80211_prepare_and_rx_handle()对帧进行处理,下面分析接收帧为数据帧的情况。
- static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb)
- {
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_hdr *hdr;
- __le16 fc;
- struct ieee80211_rx_data rx;
- struct ieee80211_sub_if_data *prev;
- struct sta_info *sta, *tmp, *prev_sta;
- int err = 0;
- ...
- hdr = (struct ieee80211_hdr *)skb->data;
- ieee80211_parse_qos(&rx);
- ieee80211_verify_alignment(&rx);
- if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) ||
- ieee80211_is_beacon(hdr->frame_control)))
- {
- ieee80211_scan_rx(local, skb);
- }
- if (ieee80211_is_data(fc)) {
- prev_sta = NULL;
- for_each_sta_info(local, hdr->addr2, sta, tmp) {
- if (!prev_sta) {
- prev_sta = sta;
- continue;
- }
- rx.sta = prev_sta;
- rx.sdata = prev_sta->sdata;
- ieee80211_prepare_and_rx_handle(&rx, skb, false);
- prev_sta = sta;
- }
- ...
- }
- ...
- out:
- dev_kfree_skb(skb);
- }
4. ieee80211_prepare_and_rx_handle()
调用ieee80211_prepare_and_rx_handle()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。
-
-
-
-
-
-
- static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, struct sk_buff *skb, bool consume)
- {
- …
- ieee80211_invoke_rx_handlers(rx);
- return true;
- }
5. ieee80211_invoke_rx_handlers()
调用ieee80211_invoke_rx_handlers()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。
- static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
- {
- …
- ieee80211_rx_reorder_ampdu(rx, &reorder_release);
- ieee80211_rx_handlers(rx, &reorder_release);
- return;
- rxh_next:
- ieee80211_rx_handlers_result(rx, res);
- …
- }
6. ieee80211_rx_handlers()
调用ieee80211_rx_handlers()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。
- static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
- {
- ieee80211_rx_result res = RX_DROP_MONITOR;
- struct sk_buff *skb;
- #define CALL_RXH(rxh) \
- do { \
- res = rxh(rx); \
- if (res != RX_CONTINUE) \
- goto rxh_next; \
- } while (0);
- spin_lock_bh(&rx->local->rx_path_lock);
- while ((skb = __skb_dequeue(frames))) {
-
-
-
-
-
- rx->skb = skb;
- CALL_RXH(ieee80211_rx_h_decrypt)
- CALL_RXH(ieee80211_rx_h_check_more_data)
- CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)
- CALL_RXH(ieee80211_rx_h_sta_process)
- CALL_RXH(ieee80211_rx_h_defragment)
- CALL_RXH(ieee80211_rx_h_michael_mic_verify)
-
- #ifdef CPTCFG_MAC80211_MESH
- if (ieee80211_vif_is_mesh(&rx->sdata->vif))
- CALL_RXH(ieee80211_rx_h_mesh_fwding);
- #endif
- CALL_RXH(ieee80211_rx_h_amsdu)
- CALL_RXH(ieee80211_rx_h_data)
-
- res = ieee80211_rx_h_ctrl(rx, frames);
- if (res != RX_CONTINUE)
- goto rxh_next;
- CALL_RXH(ieee80211_rx_h_mgmt_check)
- CALL_RXH(ieee80211_rx_h_action)
- CALL_RXH(ieee80211_rx_h_userspace_mgmt)
- CALL_RXH(ieee80211_rx_h_action_return)
- CALL_RXH(ieee80211_rx_h_mgmt)
- rxh_next:
- ieee80211_rx_handlers_result(rx, res);
- #undef CALL_RXH
- }
- spin_unlock_bh(&rx->local->rx_path_lock);
- }
7. ieee80211_rx_h_data()
只看是数据帧的情况,会继续调用ieee80211_rx_h_data()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。
- static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
- {
- …
- rx->skb->dev = dev;
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += rx->skb->len;
- if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
- !is_multicast_ether_addr(
- ((struct ethhdr *)rx->skb->data)->h_dest) &&
- (!local->scanning &&
- !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))) {
- mod_timer(&local->dynamic_ps_timer, jiffies +
- msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
- }
- ieee80211_deliver_skb(rx);
- return RX_QUEUED;
- }
8. ieee80211_deliver_skb()
调用ieee80211_deliver_skb()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。
-
-
-
- static void
- ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
- {
- …
- skb = rx->skb;
- …
- if (skb) {
- int align __maybe_unused;
- #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-
-
-
-
-
-
-
-
-
- align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
- if (align) {
- if (WARN_ON(skb_headroom(skb) < 3)) {
- dev_kfree_skb(skb);
- skb = NULL;
- } else {
- u8 *data = skb->data;
- size_t len = skb_headlen(skb);
- skb->data -= align;
- memmove(skb->data, data, len);
- skb_set_tail_pointer(skb, len);
- }
- }
- #endif
- if (skb) {
-
- skb->protocol = eth_type_trans(skb, dev);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_receive_skb(skb);
- }
- }
- …
- }
这里最核心的代码就是netif_receive_skb(skb)了,至此,数据已经接收到并发送至内核的网络子系统去处理。netif_receive_skb定义于内核文件夹linux-3.3.8的子目录/net/core的文件dev.c中