openWrt 数据接收过程分析

来源:互联网 发布:淘宝上的latoja排毒针 编辑:程序博客网 时间:2024/05/22 14:27

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:                       /* Clear skb->pkt_type in order to not confuse kernel                       * netstack. */                       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中)。

/*  * This function returns whether or not the SKB  * was destined for RX processing or not, which,  * if consume is true, is equivalent to whether  * or not the skb was consumed.  */  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))) {                /*                * all the other fields are valid across frames                * that belong to an aMPDU since they are on the                * same TID from the same station                */                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)                /* must be after MMIC verify so header is counted in MPDU mic */  #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)                /* special treatment -- needs the queue */                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中)。

/*  * requires that rx->skb is a frame with ethernet header  */  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' will only take the values 0 or 2 here                * since all frames are required to be aligned                * to 2-byte boundaries when being passed to                * mac80211; the code here works just as well if                * that isn't true, but mac80211 assumes it can                * access fields as 2-byte aligned (e.g. for                * compare_ether_addr)                */                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) {                       /* deliver to local stack */                       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中。