天天看点

控制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通过。问题如下:

    这是路由器的参数设置:

这是我的笔记本的参数设置:

继续阅读