Chinaunix首页 | 论坛 | 博客
  • 博客访问: 805280
  • 博文数量: 106
  • 博客积分: 1250
  • 博客等级: 少尉
  • 技术积分: 1349
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-09 09:38
文章分类

全部博文(106)

文章存档

2014年(1)

2013年(13)

2012年(92)

分类:

2012-09-18 13:02:04

通过上面的分析,我们认为实际上使用的发送速率就是r0,那么如何获取呢?

速率控制的驱动中有一个函数:
  1. void

  2. ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,

  3.       int shortPreamble, size_t frameLen,

  4.       u_int8_t *rix, int *try0, u_int8_t *txrate)

  5. {

  6.       struct onoe_node *on = ATH_NODE_ONOE(an);



  7.       *rix = on->on_tx_rix0;

  8.       *try0 = on->on_tx_try0;

  9.       if (shortPreamble)

  10.            *txrate = on->on_tx_rate0sp;

  11.       else

  12.            *txrate = on->on_tx_rate0;

  13. }
复制代码
返回的txrate 就是实际上使用的on->on_tx_rate0,r0

该函数也在if_ath.c 中每次ath_tx_start函数进行发送的时候调用,这个函数虽然参数很多,但是查看代码,只有struct ath_node *an的输入代码是有效的,shortPreamble是否为短符号,可以不考虑,设置为0.



因此,需要修改ioctl部分的函数,将auto部分返回-1的代码,修改为调用ath_rate_findrat函数,调用该函数的关键就是如何获取struct ath_node *an参数。
4、AMRR代码阅读

AMRR是onoe的改进,使用了二进制避退(BEB)的概念,来适应改变rn/cn的周期,为了适应快速变化的无线信道,设置c0=c1=c2=c3=1,速率r3设置为最小可用速率(6Mbps 802.11a),而r1和r2由r0决定,也就是r1为r0的下一个低速率,r2为r1的下一个低速率;因此,核心是改变r0。

AMRR使用了一个定时器来周期性的进行速率控制,时间设置为1秒。
  1. static void
  2. ath_ratectl(unsigned long data)
  3. {
  4.       ……..
  5.       asc->timer.expires = jiffies + ((HZ * interval) / 1000);
  6.       add_timer(&asc->timer);
  7. }
复制代码
首先看ath_rate_tx_complete函数,每次发送后是如何处理的,
  1. void

  2. ath_rate_tx_complete(struct ath_softc *sc,

  3.       struct ath_node *an, const struct ath_desc *ds)

  4. {

  5.       struct amrr_node *amn = ATH_NODE_AMRR(an);

  6.       int sr = ds->ds_txstat.ts_shortretry;

  7.       int lr = ds->ds_txstat.ts_longretry;

  8.       int retry_count = sr + lr;

  9. //这个变量表明重传的次数,需要注意 c0=c1=c2=c3=1,因此,重传次数最多为4次,
  10.        amn->amn_tx_try0_cnt++;
  11. //amn->amn_tx_try0_cnt 变量为使用速率r0发送的次数,因为c0=1,每次发送,都会并且只会使//用r0发送一次,因此,这个变量还可以同时表示发送的包的个数(包括成功和失败的)

  12.        if (retry_count == 1) {

  13. //如果重传次数是一次,由于c0=c1=c2=c3=1,必然可以得出使用速率r0发送了一次,失败之后,又使用速率r1发送了一次

  14.            amn->amn_tx_try1_cnt++;

  15.       } else if (retry_count == 2) {

  16. //同理可以得出如果重传次数是2次,由于c0=c1=c2=c3=1,必然可以得出使用速率r0发送了一次,失败之后,又使用速率r1发送了一次,再使用r2 发送了一次

  17.            amn->amn_tx_try1_cnt++;

  18.            amn->amn_tx_try2_cnt++;

  19.       } else if (retry_count == 3) {

  20.            amn->amn_tx_try1_cnt++;

  21.            amn->amn_tx_try2_cnt++;

  22.            amn->amn_tx_try3_cnt++;

  23.       } else if (retry_count > 3) {

  24. //如果次数为4次,说明各个速率都尝试过,并且最后都发送都失败了。

  25.            amn->amn_tx_try1_cnt++;

  26.            amn->amn_tx_try2_cnt++;

  27.            amn->amn_tx_try3_cnt++;

  28.            amn->amn_tx_failure_cnt++;

  29.       }

  30. }



  31. static void

  32. ath_rate_ctl(void *arg, struct ieee80211_node *ni)

  33. {

  34.       struct ath_softc *sc = arg;

  35.       struct amrr_node *amn = ATH_NODE_AMRR(ATH_NODE (ni));

  36.       int old_rate;

  37. #define is_success(amn) (amn->amn_tx_try1_cnt  < (amn->amn_tx_try0_cnt / 10))

  38. 如果发送包的中小于10%的包出现了重传,那么认为上次速率设置发送是成功的,

  39. #define is_enough(amn)  (amn->amn_tx_try0_cnt > 10)

  40. 如果发送包的个数大于10,认为是足够进行判断了

  41. #define is_failure(amn) (amn->amn_tx_try1_cnt > (amn->amn_tx_try0_cnt / 3))

  42. 如果发送包中出现大约33%的包需要重传,那么认为上次速率设置是失败的

  43. #define is_max_rate(ni) ((ni->ni_txrate + 1) >= ni->ni_rates.rs_nrates)

  44. #define is_min_rate(ni) (ni->ni_txrate == 0)

  45.        old_rate = ni->ni_txrate;

  46.        if (is_success(amn) && is_enough(amn)) {

  47.            //如果发送成功,将成功的计数器加1

  48. amn->amn_success++;

  49.            if (amn->amn_success == amn->amn_success_threshold &&

  50.                !is_max_rate(ni)) {

  51.             如果计数器达到阈值,那么将速率增加,并且设置一个变量,amn_recovery=1,表明处于尝试速率增加阶段

  52.                  amn->amn_recovery = 1;

  53.                  amn->amn_success = 0;

  54.                  ni->ni_txrate++;

  55.                  DPRINTF(sc, "increase rate to %d\n", ni->ni_txrate);

  56.            } else

  57.                  amn->amn_recovery = 0;

  58.       } else if (is_failure(amn)) {

  59.            如果发送失败,成功的计数器清零。

  60. amn->amn_success = 0;

  61.            if (!is_min_rate(ni)) {

  62.                  if (amn->amn_recovery) {

  63.                       /* recovery failure. */

  64.                       如果处于是处于尝试速率增加阶段,那么将阈值翻倍,

  65. amn->amn_success_threshold *= 2;

  66.                       amn->amn_success_threshold = min(amn->amn_success_threshold,

  67.                                                (u_int)ath_rate_max_success_threshold);

  68.                       DPRINTF(sc, "decrease rate recovery thr: %d\n",

  69.                             amn->amn_success_threshold);

  70.                  } else {

  71.                       /* simple failure. */

  72.                       否则,如果处于正常情况下的失败,将阈值设置为最小

  73. amn->amn_success_threshold = ath_rate_min_success_threshold;

  74.                       DPRINTF(sc, "decrease rate normal thr: %d\n",

  75.                             amn->amn_success_threshold);

  76.                  }

  77.                  amn->amn_recovery = 0;

  78.                  ni->ni_txrate--;

  79.            } else

  80.                  amn->amn_recovery = 0;
  81.       }
  82. }
复制代码
可以看出来,AMRR协议类似于AARF,每次尝试速率增加的时候,如果尝试失败,将阈值翻倍。




5、SampleRate自适应速率说明

该说明来源于“Bit-rate Selection in Wireless Networks“,John C. Bicket ,MIT 硕士论文 P29

该文主要提出了SampleRate算法,也对其他的算法进行了说明。

该算法周期性的发送其他速率的包进行探询,看其他速率发送是否合适。

本文认为速率选择算法需要考虑一下几个方面:

1)不能认为因为如果某低速率性能性能差,那么比它高一级的速率会性能更差(3.5章节的说明)

2)最高吞吐量的算法可能丢包率也多,丢包率小的速率可能吞吐量未必最高(3.2节)

3)链路状态是会发生变化的,不能对链路状态进行反映,会导致低的吞吐量;

4)速率选择算法必须要高效,不能尝试所有的速率;


6、AMARF协议的实现

AMARF协议是ARF协议的改进,核心是给每个速率设置一个不同的阈值,阈值的大小可以自适应的变化,因此,AMARF适用于信道快速变化的场合。

使用madwifi可能存在的问题:

1)madwifi属于高延时的系统,是否能够进行每个包的控制,另外如何控制FIFIO?

2)madwifi驱动本身提供了多速率多重传的机制,如何利用?



因此,我们提出两种方法:

纯粹的P-AMARF,结合madwifi的M-AMARF

首先分析P-AMARF:

还是从ath_rate_tx_complete函数看其,每次发送后是如何处理的。



上面的几个算法都是周期性的对速率进行控制,引入了定时器,每次发送之后仅仅是对速率进行统计,我们的算法需要进行快速的调整速率,每次发送完之后都进行控制!!
  1. void ath_rate_tx_complete(struct ath_softc *sc,struct ath_node *an, const struct ath_desc *ds)

  2. {

  3.       struct amarf_node *arn = ATH_NODE_AMARF(an);

  4.       arn->amarf_txok=!(ds->ds_txstat.ts_status); //判断是否发送成功

  5.         //printk("txok is %d\n",arn->amarf_txok);

  6.         ath_rate_ctl(sc,&an->an_node);

  7. }

  8. static void ath_rate_ctl(void *arg,struct ieee80211_node *ni)

  9. {

  10.       struct ath_softc *sc=arg;

  11.       struct amarf_node *arn=ATH_NODE_AMARF(ATH_NODE(ni));

  12.       int old_rate;

  13.       sc->sc_stats.ast_rate_calls++;

  14.       #define is_max_rate(ni)    ((ni->ni_txrate + 1) >= ni->ni_rates.rs_nrates)

  15.         #define is_min_rate(ni)    (ni->ni_txrate == 0) /* ni_txrate : index to ni_rates[] */

  16.         old_rate = ni->ni_txrate;

  17.       if(arn->amarf_txok)

  18.        {

  19.           if(arn->amarf_counter_success>=amarf_th[ni->ni_txrate])

  20.             { arn->amarf_counter_success=0;

  21.                amarf_th[ni->ni_txrate]+=amarf_c;

  22.                DEBUG2("amarf_c is %f\n",amarf_c);      

  23.               if(!is_max_rate(ni))

  24.               { ni->ni_txrate++;

  25.                 DEBUG2("increase to %d\n",ni->ni_txrate);

  26.                 arn->amarf_isprobe=1;

  27.               }

  28.              }

  29.           else

  30.             arn->amarf_counter_success++;

  31.             arn->amarf_isprobe=0;

  32.              //  DEBUG2("consecutive counter_success is %d\n",arn->amarf_counter_success);

  33.        }

  34.         else

  35.          {

  36.                arn->amarf_counter_success=0;

  37.                 if(arn->amarf_isprobe==1)

  38.                 amarf_th[ni->ni_txrate]-=amarf_a;

  39.                 DEBUG2("amarf_a is %f\n",amarf_a);

  40.                 else

  41.                 amarf_th[ni->ni_txrate]-=amarf_b;

  42.                 DEBUG2("amarf_b is %f\n",amarf_b);

  43.                 if(!is_min_rate(ni))

  44.                 {

  45.                 ni->ni_txrate--;

  46.                 DEBUG2("decrease to %d\n",ni->ni_txrate);

  47.                 }

  48.                 arn->amarf_isprobe=0;

  49.          }

  50.   if(ni->ni_txrate!=old_rate)               

  51.   ath_rate_update(sc,ni,ni->ni_txrate);

  52. }
复制代码
7、madwifi驱动阅读

该程序有好几个目录

ath: 物理网卡的控制函数,例如发送等

ath_rate: 速率控制的相关代码

hal: 硬件抽象层的相关库,不公开源代码

net80211: 802.11相关的代码,与物理层独立,完成诸如scan、wap、VAP等功能。


  1. Ieee80211_wireless.c

  2. static const iw_handler ieee80211_handlers[] = {

  3. (iw_handler) ieee80211_ioctl_siwrate,        /* SIOCSIWRATE */

  4. (iw_handler) ieee80211_ioctl_giwrate,        /* SIOCGIWRATE */

复制代码
模块的入口函数:if_ath_pci.c /module_init(init_ath_pci);
  1. static int __init
  2. init_ath_pci(void)
  3. {

  4.       printk(KERN_INFO "%s: %s\n", dev_info, version);

  5.        if (pci_register_driver(&ath_pci_drv_id) < 0) {

  6.            printk("ath_pci: No devices found, driver not installed.\n");

  7.            return (-ENODEV);

  8.       }

  9. #ifdef CONFIG_SYSCTL

  10.       ath_sysctl_register();

  11. #endif

  12.       return (0);

  13. }

  14. module_init(init_ath_pci);
复制代码
初始化会调用 ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)函数,

进一步加载ath无线网卡:
  1.       if (ath_attach(vdevice, dev) != 0)

  2.            goto bad4;

  3. If_ath.c (ath)文件实现ath_attach函数,该函数的实现非常复杂,关键的代码如下:

  4. ath_attach(u_int16_t devid, struct net_device *dev)

  5. {……………

  6. ah = _ath_hal_attach(devid, sc, NULL, (void *) dev->mem_start, &status);

  7. 可能是探测与硬件相关的东西,不能显示更进一步的代码:

  8. ………………..

  9. dev->hard_start_xmit = ath_hardstart;

  10. dev->do_ioctl = ath_ioctl;



  11. ieee80211_ifattach(ic); 该函数在Ieee80211.c 文件中实现



  12. ic->ic_vap_create = ath_vap_create;

  13. ic->ic_vap_delete = ath_vap_delete;

复制代码
重点需要掌握ath与80211目录的关联,ath_vap_create是做什么的。
  1. static struct ieee80211vap *

  2. ath_vap_create(struct ieee80211com *ic, const char *name, int unit,

  3.       int opmode, int flags, struct net_device *mdev)

  4. {

  5. ……………………

  6. ieee80211_vap_setup(ic, dev, name, unit, opmode, flags);

  7. ………….

  8.       (void) ieee80211_vap_attach(vap,

  9.            ieee80211_media_change, ieee80211_media_status);



  10. Ieee80211_wireless.c

  11. ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev,

  12.      const char *name, int unit, int opmode, int flags)->
复制代码
调用下面的函数,实现ioctl函数,
  1. ieee80211_ioctl_vattach(struct ieee80211vap *vap)

  2. {

  3.       struct net_device *dev = vap->iv_dev;

  4.       dev->do_ioctl = ieee80211_ioctl;

  5. 这里就存在两次对dev->do_ioctl赋值的情况,一次是在ath_attach函数中,一次在ieee80211_ioctl_vattach函数中,怀疑第二次是不是就将第一次的覆盖了。



  6. ieee80211_ioctl函数就有很多的子函数用以实现不同的功能,以设置和获取速率为例:

  7. ieee80211_ioctl_siwrate(struct net_device *dev, struct iw_request_info *info,

  8.       struct iw_param *rrq, char *extra)

  9. 获取速率的ioctl函数的实现

  10. ieee80211_ioctl_giwrate(struct net_device *dev,   struct iw_request_info *info,

  11.       struct iw_param *rrq, char *extra)

  12. {

  13.       struct ieee80211vap *vap = dev->priv;

  14.       struct ifmediareq imr;

  15.       int rate;



  16.       memset(&imr, 0, sizeof(imr));

  17.       vap->iv_media.ifm_status(vap->iv_dev, &imr);



  18.       rrq->fixed = IFM_SUBTYPE(vap->iv_media.ifm_media) != IFM_AUTO;

  19.       /* media status will have the current xmit rate if available */

  20.       rate = ieee80211_media2rate(imr.ifm_active);  //这个函数的意思是将速率编号转换为实际的速率

  21.       if (rate == -1)       /* IFM_AUTO */

  22.            rate = 0;   //如果是auto,那么就返回0

  23.       rrq->value = 1000000 * (rate / 2);

  24.       return 0;

  25. }
复制代码
有关于速率的东西都在ifm_active变量中,这个变量包含了很多的属性,包括速率、模式等等,在if_media.h文件中
  1. #define    IFM_IEEE80211_DS1     5     /* Direct Sequence 1Mbps */

  2. #define    IFM_IEEE80211_DS2     6     /* Direct Sequence 2Mbps */

  3. #define    IFM_IEEE80211_DS5     7     /* Direct Sequence 5.5Mbps */

  4. #define    IFM_IEEE80211_DS11    8     /* Direct Sequence 11Mbps */

  5. 函数ieee80211com_media_status实现获得ifm_active变量

  6. ieee80211com_media_status(struct net_device *dev, struct ifmediareq *imr)

  7. {

  8.       struct ieee80211com *ic = dev->priv;   /*XXX*/



  9.       imr->ifm_status = IFM_AVALID;

  10.       if (!TAILQ_EMPTY(&ic->ic_vaps))

  11.            imr->ifm_status |= IFM_ACTIVE;

  12.       imr->ifm_active = media_status(ic->ic_opmode, ic->ic_curchan);

  13. }
复制代码
通过上述分析,发现ifm_active变量的获得实际上是ieee80211com *ic结构体获得的。



数据发送过程分析:
  1. static int

  2. ath_hardstart(struct sk_buff *skb, struct net_device *dev)->

  3. ath_tx_start(struct net_device *dev, struct ieee80211_node *ni, struct ath_buf *bf, struct sk_buff *skb, int nextfraglen)

  4. {

  5. ……….

  6. ath_rate_findrate(sc, an, shortPreamble, skb->len,

  7.                       &rix, &try0, &txrate);  //有关速率控制的东西

  8. ………

  9.       ath_hal_setuptxdesc(ah, ds

  10.                      , pktlen          /* packet length */

  11.                      , hdrlen          /* header length */

  12.                      , atype           /* Atheros packet type */

  13.                      , MIN(ni->ni_txpower, 60)/* txpower */

  14.                      , txrate, try0    /* series 0 rate/tries */

  15.                      , keyix           /* key cache index */

  16.                      , antenna         /* antenna mode */

  17.                      , flags           /* flags */

  18.                      , ctsrate         /* rts/cts rate */

  19.                      , ctsduration     /* rts/cts duration */

  20.                      , icvlen          /* comp icv len */

  21.                      , ivlen           /* comp iv len */

  22.                      , comp       /* comp scheme */

  23.            );  //与硬件相关的函数

  24.       if (try0 != ATH_TXMAXTRY)

  25.            ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, skb->len, rix);  //速率控制的描述符

  26. }
复制代码
8、有关速率获取的问题

通过上面的代码分析,我们认为在madwifi情况下,r0就是实际的速率,因此,需要在应用层能够获得r0的指,经过跟踪,发现当调用iwconfig命令,来获取速率的值的时候,会调用
  1. ieee80211_ioctl_giwrate(struct net_device *dev,   struct iw_request_info *info,

  2.       struct iw_param *rrq, char *extra)

  3. {

  4.       struct ieee80211vap *vap = dev->priv;
复制代码
现在当使用auto的自适应速率时候,自动返回-1,因此,获得速率值为0.

因此,需要修改这个函数,调用ARMARF自适应速率的ath_rate_findrate函数

通过上面的分析,我们认为实际上使用的发送速率就是r0,那么如何获取呢?

速率控制的驱动中有一个函数:
  1. void
  2. ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,

  3.       int shortPreamble, size_t frameLen,
  4.       u_int8_t *rix, int *try0, u_int8_t *txrate)
  5. {

  6.       struct onoe_node *on = ATH_NODE_ONOE(an);
  7.       *rix = on->on_tx_rix0;

  8.       *try0 = on->on_tx_try0;

  9.       if (shortPreamble)
  10.            *txrate = on->on_tx_rate0sp;
  11.       else

  12.            *txrate = on->on_tx_rate0;
  13. }
复制代码
返回的txrate 就是实际上使用的on->on_tx_rate0,r0
阅读(2426) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~