最近一直在为文章做实验,其中涉及mac层调度算法,所以一直在读和修改ath5k和mac80211的代码。也学习了一些东西,本来一直记载笔记上面,但是怕这些知识会被自己慢慢地淡忘,所以选择书写一些博客来记录下自己学习的脚步。
上面这张图片来自与Daniel Camps Mur 的linux Wi-Fi Open Source Driver -mac80211, ath9k/ath5k演讲的ppt。这张图代表了数据从内核传送给无线网卡,在经过无线网卡传送出去的过程。如果结合netfilter的思路,那么就是数据进入内核之后,netfilter/iptable判断这些数据是不是传送给本机的还是通过本机转发的,如果是通过本机转发的,那么就通过内核传送给网卡。
1. ieee_80211_subif_start_xmit
kernel将所要传输的数据放在skb中,ieee_80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev),可以看出这个函数有两个参数,第一个是包含数据的skb,第二个是数据的来源网络接口,在我的配置中(数据通过有线接口eth0进入,然后通过wlan0传送给客户端)应该是wlan0(printk输出参数显示,该接口就是wlan0)。然后这个函数调用_ieee_80211_subif_xmit函数,这个函数的参数是刚才的skb和网络接口类型,还有一个0,在此对skb进行创建80211头操作:
skb = ieee80211_build_hdr(sdata, skb, info_flags);
其中sdata为:
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);(这个数据结构比较复杂,需要进一步了解)
在创建完80211头之后,发送到master接口,
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
dev->trans_start = jiffies; //最近传送数据包的时间
ieee80211_xmit(sdata, skb);
其中dev->stats中的stats是一个数据结构,其结构如下:
struct net_device_stats
};
它是一个用来保存发送数据状态的数据结构。
最后__ieee80211_subif_start_xmit调用ieee80211_xmit(sdata, skb);
小结:在这个函数中,最主要的工作还是为skb创建ieee80211 header,其次是设置发送数据加一和记录最近的发送时间。
2. ieee80211_xmit(sdata,skb)
这个函数主要有三个作用:
1. 为加密分配headroom
2.ieee80211_set_qos_hdr在包头中设置QoS参数,
void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *p;
u8 ack_policy, tid;
if (!ieee80211_is_data_qos(hdr->frame_control))
return;
p = ieee80211_get_qos_ctl(hdr);//这里是用来获取IP包里面的TOS域内容。
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
/* preserve EOSP bit */
ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
if (is_multicast_ether_addr(hdr->addr1) ||
sdata->noack_map & BIT(tid)) {
ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
info->flags |= IEEE80211_TX_CTL_NO_ACK;
}
/* qos header is 2 bytes */
*p++ = ack_policy | tid;
if (ieee80211_vif_is_mesh(&sdata->vif)) {
/* preserve RSPI and Mesh PS Level bit */
*p &= ((IEEE80211_QOS_CTL_RSPI |
IEEE80211_QOS_CTL_MESH_PS_LEVEL) >> 8);
/* Nulls don't have a mesh header (frame body) */
if (!ieee80211_is_qos_nullfunc(hdr->frame_control))
*p |= (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8);
} else {
*p = 0;
}
}
这个函数应该就是为了修改P也就是ip包中的TOS域的内容。
3.调用ieee80211_tx(sdata,skb,false,band)
3 ieee80211_tx(sdata,skb,false,band)
dnsmasq-25107 [002] 98228.755607: funcgraph_entry: | ieee80211_subif_start_xmit() {
dnsmasq-25107 [002] 98228.755619: funcgraph_entry: | __ieee80211_subif_start_xmit() {
dnsmasq-25107 [002] 98228.755632: funcgraph_entry: 1.726 us | ieee80211_build_hdr();
dnsmasq-25107 [002] 98228.755634: funcgraph_entry: | ieee80211_xmit() {
dnsmasq-25107 [002] 98228.755635: funcgraph_entry: 0.356 us | ieee80211_set_qos_hdr();
dnsmasq-25107 [002] 98228.755636: funcgraph_entry: | ieee80211_tx() {
dnsmasq-25107 [002] 98228.755637: funcgraph_entry: 0.491 us | ieee80211_tx_prepare();
dnsmasq-25107 [002] 98228.755639: funcgraph_entry: 0.834 us | ieee80211_tx_h_select_key();
dnsmasq-25107 [002] 98228.755643: funcgraph_entry: 0.198 us | ieee80211_tx_h_michael_mic_add();
dnsmasq-25107 [002] 98228.755645: funcgraph_entry: 0.120 us | ieee80211_tx_set_protected();
dnsmasq-25107 [002] 98228.755647: funcgraph_entry: 8.724 us | __ieee80211_tx();
dnsmasq-25107 [002] 98228.755669: funcgraph_exit: + 32.257 us | }
dnsmasq-25107 [002] 98228.755675: funcgraph_exit: + 40.463 us | }
dnsmasq-25107 [002] 98228.755676: funcgraph_exit: + 56.223 us | }
dnsmasq-25107 [002] 98228.755676: funcgraph_exit: + 57.636 us | }
<idle>-0 [002] 98228.758095: funcgraph_entry: | ieee80211_tx_status() {
<idle>-0 [002] 98228.758106: funcgraph_entry: 0.286 us | ieee80211_tx_get_rates.isra.14();
<idle>-0 [002] 98228.758117: funcgraph_exit: + 11.453 us | }