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中。
相关文章推荐
- OpenWRT数据接收过程
- OpenWRT数据接收过程 二
- openWrt 数据接收过程分析
- OpenWRT数据接收过程【Linux内核-OpenWRT】
- vlc学习计划(5)--网络数据流接收处理过程分析
- vlc学习计划(6)--从接收到数据流到播放视频的过程分析
- vlc学习计划(6)--从接收到数据流到播放视频的过程分析
- 数据报的接收过程详解---从网卡到L3层(非NAPI,即接收数据采用中断方式)
- 数据报的接收过程详解---从网卡到L3层(非NAPI,即接收数据采用中断方式)
- JAVA编码转换的详细过程理解—>浏览器和服务器的接收和发送数据的编码
- 使用Ajax传递 json数据,并在一般处理页面进行接收全过程
- OpenWRT数据发送过程【Linux内核-OpenWRT】
- 网络数据流接收处理过程分析
- vlc学习计划(6)--网络数据流接收处理过程分析
- Contiki通信之数据接收过程
- VLC中网络数据流接收处理过程分析
- 嵌入式 vlc从接收到数据流到播放视频的过程分析(经典)
- 数据报的接收过程详解---从网卡到L3层(非NAPI,即接收数据采用中断方式)
- [VB.NET]串口接收过程中怎样将末尾3位字符数据去掉?
- vlc学习计划(5)--网络数据流接收处理过程分析