做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通過。問題如下:
這是路由器的參數設置:
這是我的筆記本的參數設置: