OpenWRT数据接收过程

  • OpenWRT数据接收过程
    这里使用的是ath9k网卡驱动,硬件平台是TP-link TL-WR841N V7.1 路由器。
    1. ieee80211_tasklet_handler()

    Linux内核是通过中断来对接收到的数据进行响应的。当硬件检测到有接收数据的时候,产生一个中断,中断触发下半部的tasklet机制,在802.11协议栈这里会调用ieee80211_tasklet_handler()函数。我们来看一看函数体:(位于OpenWRT内核文件夹子目录/net/mac80211,文件main.c中)

    01. static void ieee80211_tasklet_handler(unsigned long data)
    02. {
    03. struct ieee80211_local *local = (struct ieee80211_local *) data;
    04. struct sk_buff *skb;
    05. while ((skb = skb_dequeue(&local->skb_queue)) ||
    06. (skb = skb_dequeue(&local->skb_queue_unreliable))) {
    07. switch (skb->pkt_type) {
    08. case IEEE80211_RX_MSG:
    09. /* 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中)。

    01. void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
    02. {
    03. struct ieee80211_local *local = hw_to_local(hw);
    04. struct ieee80211_rate *rate = NULL;
    05. struct ieee80211_supported_band *sband;
    06. struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
    07. ...
    08. __ieee80211_rx_handle_packet(hw, skb);
    09. 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()对帧进行处理,下面分析接收帧为数据帧的情况。


    01. static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb)
    02. {
    03. struct ieee80211_local *local = hw_to_local(hw);
    04. struct ieee80211_sub_if_data *sdata;
    05. struct ieee80211_hdr *hdr;
    06. __le16 fc;
    07. struct ieee80211_rx_data rx;
    08. struct ieee80211_sub_if_data *prev;
    09. 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中)。

    01. /*
    02. * This function returns whether or not the SKB
    03. * was destined for RX processing or not, which,
    04. * if consume is true, is equivalent to whether
    05. * or not the skb was consumed.
    06. */
    07. static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, struct sk_buff *skb, bool consume)
    08. {
    09.
    10. ieee80211_invoke_rx_handlers(rx);
    11. return true;
    12. }


    5. ieee80211_invoke_rx_handlers()

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

    01. static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
    02. {
    03.
    04. ieee80211_rx_reorder_ampdu(rx, &reorder_release);
    05. ieee80211_rx_handlers(rx, &reorder_release);
    06. return;
    07. rxh_next:
    08. ieee80211_rx_handlers_result(rx, res);
    09.
    10. }

    6. ieee80211_rx_handlers()

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

    01. static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
    02. {
    03. ieee80211_rx_result res = RX_DROP_MONITOR;
    04. struct sk_buff *skb;
    05. #define CALL_RXH(rxh)                     \
    06. do {                            \
    07. res = rxh(rx);              \
    08. if (res != RX_CONTINUE)    \
    09. 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中)。

    01. static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
    02. {
    03.
    04. rx->skb->dev = dev;
    05. dev->stats.rx_packets++;
    06. dev->stats.rx_bytes += rx->skb->len;
    07. if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
    08. !is_multicast_ether_addr(
    09. ((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中)。

    01. /*
    02. * requires that rx->skb is a frame with ethernet header
    03. */
    04. static void
    05. ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
    06. {
    07.
    08. skb = rx->skb;
    09.
    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中。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值