openWrt 数据接收过程分析
来源:互联网 发布:淘宝上的latoja排毒针 编辑:程序博客网 时间:2024/05/22 14:27
OpenWRT数据接收过程 这里使用的是ath9k网卡驱动,硬件平台是TP-link TL-WR841N V7.1 路由器
Linux内核是通过中断来对接收到的数据进行响应的。当硬件检测到有接收数据的时候,产生一个中断,中断触发下半部的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: ... } } }
系统收到数据时会开辟一个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);
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()对帧进行处理,下面分析接收帧为数据帧的情况。
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中)。
/* * 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); }
只看是数据帧的情况,会继续调用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; }
调用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); } } … }
- openWrt 数据接收过程分析
- OpenWRT数据接收过程
- OpenWRT数据接收过程
- OpenWRT数据接收过程 二
- OpenWRT数据接收过程【Linux内核-OpenWRT】
- openWrt: 数据发送过程分析
- 网络数据接收过程分析
- [OpenWrt] OpenWrt启动过程分析
- OpenWrt启动过程分析
- OpenWrt启动过程分析
- OpenWrt启动过程分析
- OpenWRT数据发送过程【Linux内核-OpenWRT】
- Ethernet 接收 数据过程
- openwrt系统 sysupgrade 命令执行过程分析
- openwrt系统 sysupgrade 命令执行过程分析
- openwrt启动过程分析(转载)
- openwrt系统 sysupgrade 命令执行过程分析
- openwrt系统 sysupgrade 命令执行过程分析
- Android控件之SeekBar
- cURL类库—利用URL语法爱命令行方式下工作的文件传输工具
- SVN回滚版本
- 冒泡排序
- 菜单面板管理者(管理模块)的思考
- openWrt 数据接收过程分析
- cocos scrollview和clippingnode之间的影响问题
- c语言实现通用数据结构(一):通用链表
- js中Object类型三种初始化方式
- Android 自定义 一个可以控制子控件是否可以点击的layout
- HTML元素(二)
- iframe用法大全
- thinkphp框架中使用ueditor入门
- jquery