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

OpenWRT数据接收过程

2014-10-22 16:30 573 查看


OpenWRT数据接收过程

转自:http://www.it165.net/os/html/201404/8091.html


这里使用的是ath9k网卡驱动,硬件平台是TP-link TL-WR841N V7.1 路由器。

1. ieee80211_tasklet_handler()

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

view
sourceprint?

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

view
sourceprint?

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

view
sourceprint?

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

view
sourceprint?

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

view
sourceprint?

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

view
sourceprint?

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

view
sourceprint?

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

view
sourceprint?

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