做TDMA的一个关键是控制住信号从MAC层向驱动层的数据的发送,从原来的事件触发转换成定时器触发。在原有的80211协议中有两个地方会触发该操作。一个操作是:
(1)ieee80211_subif_start_xmit (tx.c):
-Addsthe 802.11 header.
-Initializestransmission time in devtrans_start
(2)ieee80211_xmit (tx.c):
-Makesheadroom for encryption
(3) ieee80211_tx (tx.c):
-Obtains the proper transmission queue.
-Prepares transmission
-If the packet can not be transmitted, it is
queued
(4) _ieee80211_tx (tx.c):
-Returns false if the framecouldn't be transmitted but was queued instead.
(5) static boolieee80211_tx_frags(struct ieee80211_local *local,
structieee80211_vif *vif,
structieee80211_sta *sta,
structsk_buff_head *skbs,
booltxpending)
-Calls drv_tx() to pass the frame to the actualdriver for transmission
另外一个是流程如下:
首先是void ieee80211_tx_pending(unsigned long data)(tx.c)函数中的
while(!skb_queue_empty(&local->pending[i])) { //遍历队列中的每个skb
然后调用函数struct sk_buff *skb =__skb_dequeue(&local->pending[i]);
队列中的第一个skb出列,接着调用 txok =ieee80211_tx_pending_skb(local, skb)
在函数ieee80211_tx_pending_skb中总是重新初始化一个队列,然后将传递进来的skb加入队列,如下所示:
struct sk_buff_head skbs;
__skb_queue_head_init(&skbs);
__skb_queue_tail(&skbs,skb);
最后进入ieee80211_tx_frags函数中。
为了能做到TDMA,我才去的措施是控制第一个不发送,第二个由事件驱动改成时钟驱动。原因是第二个是在tasklet的bf的处理过程,因此修改起来比较容易。
分析两个发送流程,两者最后都到达ieee80211_tx_frags函数,而这个函数的一个参数是booltxpending,这个值分别对应false和true恰好是以上两个流程的不同的值。
现在仔细分析ieee80211_tx_frags函数,其代码如下:
struct ieee80211_tx_control control;
structsk_buff *skb, *tmp;
unsignedlong flags;
//added byshenlei 2014 12 17 to the number of skbs of a sk_buff queue
int i=0;
skb_queue_walk_safe(skbs,skb, tmp) {
printk(KERN_INFO"SKBNUMBER: %d\n",i);
i++;
structieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int q =info->hw_queue;
#ifdef CPTCFG_MAC80211_VERBOSE_DEBUG
if(WARN_ON_ONCE(q >= local->hw.queues)) {
__skb_unlink(skb,skbs);
ieee80211_free_txskb(&local->hw,skb);
continue;
}
#endif
spin_lock_irqsave(&local->queue_stop_reason_lock,flags);
if(local->queue_stop_reasons[q] ||
(!txpending &&!skb_queue_empty(&local->pending[q]))) {
if(unlikely(info->flags &
IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) {
if(local->queue_stop_reasons[q] &
~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL)){
/*
* Drop off-channel frames if queues
* are stopped for any reason other
* than off-channel operation. Never
* queue them.
*/
spin_unlock_irqrestore(
&local->queue_stop_reason_lock,
flags);
ieee80211_purge_tx_queue(&local->hw,
skbs);
returntrue;
}
}else {
/*
* Since queue is stopped, queue up frames for
* later transmission from the tx-pending
* tasklet when the queue is woken again.
*/
if(txpending)
skb_queue_splice_init(skbs,
&local->pending[q]);
else
skb_queue_splice_tail_init(skbs,
&local->pending[q]);
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags);
/*changed by shenlei 2014 12 16 */
returntrue;
//returnfalse;
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock,flags);
info->control.vif= vif;
control.sta= sta;
__skb_unlink(skb,skbs);
drv_tx(local,&control, skb);
分析这段代码的21、22两行
if(local->queue_stop_reasons[q] ||
(!txpending &&!skb_queue_empty(&local->pending[q]))) {
可以知道这个入口条件,可以知道当txpending可以作为不同操作的一个依据,但是他还有个条件是local->pending[q]为假,也就是说第q个MAC层软件缓冲区没有等待发送的数据报,因此这个地方需要改进,我的思路是,直接txpengding为假,也就是说从第一种方式传递过来的情况下,直接让他放在相对应的数据队列中即可。
代码如下:
If(!txpending){
__skb_queue_tail(&local->pending[q],skb);
}
Else 发送出去
问题就是在这个地方,这样修改后网络连接出了问题。我本来想组成adhoc模式的网络,可以连上但是无法ping通过。问题如下:
这是路由器的参数设置:
这是我的笔记本的参数设置: