您的位置:首页 > 运维架构

OpenWRT数据接收过程 二

2017-02-17 15:28 295 查看

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

 





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中)。

[cpp] view
plain copy

 





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()对帧进行处理,下面分析接收帧为数据帧的情况。

[cpp] view
plain copy

 





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中)。

[cpp] view
plain copy

 





/* 

 * 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中)。

[cpp] view
plain copy

 





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中)。

[cpp] view
plain copy

 





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中)。

[cpp] view
plain copy

 





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中)。

[cpp] view
plain copy

 





/* 

 * 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中
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: