OpenWRT数据接收过程 二

来源:互联网 发布:淘宝大数据 编辑:程序博客网 时间:2024/05/22 12:55

http://blog.csdn.net/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中)

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static void ieee80211_tasklet_handler(unsigned long data)  
  2. {  
  3.        struct ieee80211_local *local = (struct ieee80211_local *) data;  
  4.        struct sk_buff *skb;  
  5.        while ((skb = skb_dequeue(&local->skb_queue)) ||  
  6.               (skb = skb_dequeue(&local->skb_queue_unreliable))) {  
  7.               switch (skb->pkt_type) {  
  8.               case IEEE80211_RX_MSG:  
  9.                      /* Clear skb->pkt_type in order to not confuse kernel 
  10.                       * netstack. */  
  11.                      skb->pkt_type = 0;  
  12.                      ieee80211_rx(&local->hw, skb);  
  13.                      break;  
  14.               case IEEE80211_TX_STATUS_MSG:  
  15.                      ...  
  16.               default:  
  17.                      ...  
  18.               }  
  19.        }  
  20. }  

2.  ieee80211_rx()

系统收到数据时会开辟一个sk_buff缓存空间进行数据的存储,ieee80211_tasklet_handler()触发后对sk_buff中存储的数据帧进行判断,如果是接收来的数据(MPDU),则进入ieee80211_rx()函数:(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)  
  2. {  
  3.        struct ieee80211_local *local = hw_to_local(hw);  
  4.        struct ieee80211_rate *rate = NULL;  
  5.        struct ieee80211_supported_band *sband;  
  6.        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);  
  7.        ...  
  8.        __ieee80211_rx_handle_packet(hw, skb);  
  9.        rcu_read_unlock();  
  10.        return;  
  11.  drop:  
  12.        kfree_skb(skb);  
  13. }  
  14. 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()对帧进行处理,下面分析接收帧为数据帧的情况。


[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb)  
  2. {  
  3.        struct ieee80211_local *local = hw_to_local(hw);  
  4.        struct ieee80211_sub_if_data *sdata;  
  5.        struct ieee80211_hdr *hdr;  
  6.        __le16 fc;  
  7.        struct ieee80211_rx_data rx;  
  8.        struct ieee80211_sub_if_data *prev;  
  9.        struct sta_info *sta, *tmp, *prev_sta;  
  10.        int err = 0;  
  11.        ...  
  12.        hdr = (struct ieee80211_hdr *)skb->data;  
  13.        ieee80211_parse_qos(&rx);  
  14.        ieee80211_verify_alignment(&rx);  
  15.        if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) ||  
  16.                    ieee80211_is_beacon(hdr->frame_control)))  
  17.        {          
  18.               ieee80211_scan_rx(local, skb);              /*扫描帧信息*/  
  19.               }  
  20.        if (ieee80211_is_data(fc)) {  
  21.               prev_sta = NULL;  
  22.               for_each_sta_info(local, hdr->addr2, sta, tmp) {  
  23.                      if (!prev_sta) {  
  24.                             prev_sta = sta;  
  25.                             continue;  
  26.                      }  
  27.                      rx.sta = prev_sta;  
  28.                      rx.sdata = prev_sta->sdata;  
  29.                      ieee80211_prepare_and_rx_handle(&rx, skb, false);  
  30.                      prev_sta = sta;  
  31.               }  
  32.               ...  
  33.        }  
  34.        ...  
  35.  out:  
  36.        dev_kfree_skb(skb);  
  37. }  

4.  ieee80211_prepare_and_rx_handle()

调用ieee80211_prepare_and_rx_handle()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * This function returns whether or not the SKB 
  3.  * was destined for RX processing or not, which, 
  4.  * if consume is true, is equivalent to whether 
  5.  * or not the skb was consumed. 
  6.  */  
  7. static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, struct sk_buff *skb, bool consume)  
  8. {  
  9. …  
  10.        ieee80211_invoke_rx_handlers(rx);  
  11.        return true;  
  12. }  


5.  ieee80211_invoke_rx_handlers()

调用ieee80211_invoke_rx_handlers()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)  
  2. {  
  3. …  
  4.        ieee80211_rx_reorder_ampdu(rx, &reorder_release);  
  5.        ieee80211_rx_handlers(rx, &reorder_release);  
  6.        return;  
  7.  rxh_next:  
  8.        ieee80211_rx_handlers_result(rx, res);  
  9. …  
  10. }  

6.  ieee80211_rx_handlers()

调用ieee80211_rx_handlers()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)  
  2. {  
  3.        ieee80211_rx_result res = RX_DROP_MONITOR;  
  4.        struct sk_buff *skb;  
  5. #define CALL_RXH(rxh)                     \  
  6.        do {                            \  
  7.               res = rxh(rx);              \  
  8.               if (res != RX_CONTINUE)    \  
  9.                      goto rxh_next;  \  
  10.        } while (0);  
  11.        spin_lock_bh(&rx->local->rx_path_lock);  
  12.        while ((skb = __skb_dequeue(frames))) {  
  13.               /* 
  14.                * all the other fields are valid across frames 
  15.                * that belong to an aMPDU since they are on the 
  16.                * same TID from the same station 
  17.                */  
  18.               rx->skb = skb;  
  19.               CALL_RXH(ieee80211_rx_h_decrypt)  
  20.               CALL_RXH(ieee80211_rx_h_check_more_data)  
  21.               CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)  
  22.               CALL_RXH(ieee80211_rx_h_sta_process)  
  23.               CALL_RXH(ieee80211_rx_h_defragment)  
  24.               CALL_RXH(ieee80211_rx_h_michael_mic_verify)  
  25.               /* must be after MMIC verify so header is counted in MPDU mic */  
  26. #ifdef CPTCFG_MAC80211_MESH  
  27.               if (ieee80211_vif_is_mesh(&rx->sdata->vif))  
  28.                      CALL_RXH(ieee80211_rx_h_mesh_fwding);  
  29. #endif  
  30.               CALL_RXH(ieee80211_rx_h_amsdu)  
  31.               CALL_RXH(ieee80211_rx_h_data)  
  32.               /* special treatment -- needs the queue */  
  33.               res = ieee80211_rx_h_ctrl(rx, frames);  
  34.               if (res != RX_CONTINUE)  
  35.                      goto rxh_next;  
  36.               CALL_RXH(ieee80211_rx_h_mgmt_check)  
  37.               CALL_RXH(ieee80211_rx_h_action)  
  38.               CALL_RXH(ieee80211_rx_h_userspace_mgmt)  
  39.               CALL_RXH(ieee80211_rx_h_action_return)  
  40.               CALL_RXH(ieee80211_rx_h_mgmt)  
  41.  rxh_next:  
  42.               ieee80211_rx_handlers_result(rx, res);  
  43. #undef CALL_RXH  
  44.        }  
  45.        spin_unlock_bh(&rx->local->rx_path_lock);  
  46. }  

7.  ieee80211_rx_h_data()

只看是数据帧的情况,会继续调用ieee80211_rx_h_data()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx)  
  2. {  
  3. …  
  4.        rx->skb->dev = dev;  
  5.        dev->stats.rx_packets++;  
  6.        dev->stats.rx_bytes += rx->skb->len;  
  7.        if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&  
  8.            !is_multicast_ether_addr(  
  9.                   ((struct ethhdr *)rx->skb->data)->h_dest) &&  
  10.            (!local->scanning &&  
  11.             !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))) {  
  12.                      mod_timer(&local->dynamic_ps_timer, jiffies +  
  13.                       msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));  
  14.        }  
  15.        ieee80211_deliver_skb(rx);  
  16.        return RX_QUEUED;  
  17. }  

8.  ieee80211_deliver_skb()

调用ieee80211_deliver_skb()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * requires that rx->skb is a frame with ethernet header 
  3.  */  
  4. static void  
  5. ieee80211_deliver_skb(struct ieee80211_rx_data *rx)  
  6. {  
  7.        …  
  8.        skb = rx->skb;  
  9.        …  
  10.        if (skb) {  
  11.               int align __maybe_unused;  
  12. #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS  
  13.               /* 
  14.                * 'align' will only take the values 0 or 2 here 
  15.                * since all frames are required to be aligned 
  16.                * to 2-byte boundaries when being passed to 
  17.                * mac80211; the code here works just as well if 
  18.                * that isn't true, but mac80211 assumes it can 
  19.                * access fields as 2-byte aligned (e.g. for 
  20.                * compare_ether_addr) 
  21.                */  
  22.               align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;  
  23.               if (align) {  
  24.                      if (WARN_ON(skb_headroom(skb) < 3)) {  
  25.                             dev_kfree_skb(skb);  
  26.                             skb = NULL;  
  27.                      } else {  
  28.                             u8 *data = skb->data;  
  29.                             size_t len = skb_headlen(skb);  
  30.                             skb->data -= align;  
  31.                             memmove(skb->data, data, len);  
  32.                             skb_set_tail_pointer(skb, len);  
  33.                      }  
  34.               }  
  35. #endif  
  36.               if (skb) {  
  37.                      /* deliver to local stack */  
  38.                      skb->protocol = eth_type_trans(skb, dev);  
  39.                      memset(skb->cb, 0, sizeof(skb->cb));  
  40.                      netif_receive_skb(skb);  
  41.               }  
  42.        }  
  43.        …  
  44. }  

这里最核心的代码就是netif_receive_skb(skb)了,至此,数据已经接收到并发送至内核的网络子系统去处理。netif_receive_skb定义于内核文件夹linux-3.3.8的子目录/net/core的文件dev.c中

0 0
原创粉丝点击