openwrt消息通知方式linux,OpenWRT数据接收过程

1. ieee80211_tasklet_handler()

内核是通过中断来对接收到的数据进行响应的。当硬件检测到有接收数据的时候,产生一个中断,中断触发下半部的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()对帧进行处理,下面分析接收帧为数据帧的情况。

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);

print

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()

/*

* 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);

}

}

}

调用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中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值