控制MAC層數據發送過程遇到的問題


做TDMA的一個關鍵是控制住信號從MAC層向驅動層的數據的發送,從原來的事件觸發轉換成定時器觸發。在原有的80211協議中有兩個地方會觸發該操作。一個操作是:

(1)ieee80211_subif_start_xmit (tx.c):

-Addsthe 802.11 header.

-Initializestransmission time in devtrans_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通過。問題如下:

    這是路由器的參數設置:

 

這是我的筆記本的參數設置:

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章