-
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.staticvoidieee80211_tasklet_handler(unsignedlongdata)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.caseIEEE80211_RX_MSG:09./* Clear skb->pkt_type in order to not confuse kernel10.* netstack. */11.skb->pkt_type =0;12.ieee80211_rx(&local->hw, skb);13.break;14.caseIEEE80211_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.voidieee80211_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.staticvoid__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.interr =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 SKB03.* was destined for RX processing or not, which,04.* if consume is true, is equivalent to whether05.* or not the skb was consumed.06.*/07.staticbool 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.returntrue;12.}
5. ieee80211_invoke_rx_handlers()
调用ieee80211_invoke_rx_handlers()(位于OpenWRT内核文件夹子目录/net/mac80211,文件rx.c中)。
01.staticvoidieee80211_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.staticvoidieee80211_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.gotorxh_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 frames15.* that belong to an aMPDU since they are on the16.* same TID from the same station17.*/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_MESH27.if(ieee80211_vif_is_mesh(&rx->sdata->vif))28.CALL_RXH(ieee80211_rx_h_mesh_fwding);29.#endif30.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.gotorxh_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_RXH44.}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.staticieee80211_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.returnRX_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 header03.*/04.staticvoid05.ieee80211_deliver_skb(struct ieee80211_rx_data *rx)06.{07.…08.skb = rx->skb;09.…10.if(skb) {11.intalign __maybe_unused;12.#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS13./*14.* 'align' will only take the values 0 or 2 here15.* since all frames are required to be aligned16.* to 2-byte boundaries when being passed to17.* mac80211; the code here works just as well if18.* that isn't true, but mac80211 assumes it can19.* access fields as 2-byte aligned (e.g. for20.* compare_ether_addr)21.*/22.align = ((unsignedlong)(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.#endif36.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中。
OpenWRT数据接收过程
最新推荐文章于 2024-07-26 14:45:48 发布
本文详细介绍了OpenWRT环境下无线数据包的接收过程,包括从硬件中断触发到最终交付给内核网络子系统的整个流程。重点分析了ieee80211_tasklet_handler、ieee80211_rx、__ieee80211_rx_handle_packet等关键函数的作用及调用过程。
2689

被折叠的 条评论
为什么被折叠?



