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

全部博文(106)

文章存档

2014年(1)

2013年(13)

2012年(92)

分类:

2012-09-18 13:01:57

在我的Doctor课题研究中,基于ARF协议设计了一个改进型的AMARF协议,该文发表在milcom06和电子科学学刊英文版上。最近,我们将PC机上,使用linux操作系统,基于madwifi开源代码实现了AMARF协议,已经在室内固定以及移动环境测试表明,AMARF协议明显优越于现有的协议。

2008-9-20

现在使用了madwifi程序实现AMARF协议,下面分析其代码。

使用iwconfig命令可以设置速率:
1、iwconfig源代码阅读

首先下载iwconfig.c代码,源代码包为\wireless_tools.29目录
先看执行
  1. iwconfig eth0
复制代码
的命令的执行过程:

调用main函数,因为是两个参数:
  1.            if(argc == 2)

  2.           print_info(skfd, argv[1], NULL, 0);

  3. print_info调用

  4. get_info(int                skfd,

  5.        char *               ifname,

  6.        struct wireless_info *     info)
复制代码
将网卡的各种信息打印出来。

下面与打印发送速率为例,说明调用过程,get_info函数里面:
  1. /* Get bit rate */

  2.   if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)

  3.     {

  4.       info->has_bitrate = 1;

  5.       memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));

  6.     }
复制代码
对信息的获取都是通过iw_get_ext函数来实现的,通过参数SIOCGIWRATE来识别不同的内容



iwlib.h文件定义了iw_get_ext:
  1. iw_get_ext(int              skfd,      /* Socket to the kernel */

  2.          const char *       ifname,          /* Device name */

  3.          int                request,   /* WE ID */

  4.          struct iwreq *     pwrq)      /* Fixed part of the request */

  5. {

  6.   /* Set device name */

  7.   strncpy(pwrq->ifr_name, ifname, IFNAMSIZ);

  8.   /* Do the request */

  9.   return(ioctl(skfd, request, pwrq));

  10. }
复制代码
因此,真正对网卡其他参数的实现是通过ioctl函数实现的,ioctl是驱动程序的基本功能,因此,如果自己想编写一个对网卡参数设置的程序,也应该使用ioctl函数。

下面在看使用
  1. iwconfig eth0 rate auto
复制代码
命令执行情况

main函数,当输入参数大于2的时候,调用:
  1. goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
复制代码
set_info函数调用iwcmd = find_command(args[0]);

用来查找命令,所有的命令都存放在一个表中,只要查找这个表即可:
  1. static const struct iwconfig_entry iwconfig_cmds[] = {

  2. ……….

  3. { "bit",         set_bitrate_info,     1,    SIOCSIWRATE,

  4.       "Set Bit Rate",             "{N[k|M|G]|auto|fixed}" },

  5.   { "rate",           set_bitrate_info,     1,    SIOCSIWRATE,

  6.       "Set Bit Rate",             "{N[k|M|G]|auto|fixed}" },
复制代码
当第三个参数为rate的时候,就会自动调用set_bitrate_info函数,该函数的定义为:
  1. set_bitrate_info

  2. if(!strcasecmp(args[0], "auto"))

  3.     {

  4.       wrq.u.bitrate.value = -1;

  5.       wrq.u.bitrate.fixed = 0; //如果输入是auto,那么设置为bitrate.value = -1;

  6.     }

  7.   else

  8.     {

  9.       if(!strcasecmp(args[0], "fixed"))

  10.       {

  11.         /* Get old bitrate */

  12.         if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) < 0)

  13.           return(IWERR_GET_EXT);

  14.         wrq.u.bitrate.fixed = 1;

  15.       }

  16. ……………

  17.   if(iw_set_ext(skfd, ifname, SIOCSIWRATE, &wrq) < 0)

  18.     return(IWERR_SET_EXT);
复制代码
也就是说,如果选择auto,那么设置变量bitrate.fixed=0,最后调用iw_set_ext(skfd, ifname, SIOCSIWRATE, &wrq)函数,这个函数也是直接与网卡相关的。

与iw_get_ext函数一样,iw_set_ext也是通过SIOCGIWRATE来识别的:
  1. static inline int

  2. iw_set_ext(int              skfd,      /* Socket to the kernel */

  3.          const char *       ifname,          /* Device name */

  4.          int                request,   /* WE ID */

  5.          struct iwreq *     pwrq)      /* Fixed part of the request */

  6. {

  7.   /* Set device name */

  8.   strncpy(pwrq->ifr_name, ifname, IFNAMSIZ);

  9.   /* Do the request */

  10.   return(ioctl(skfd, request, pwrq));

  11. }
复制代码
2、madiwifi驱动和硬件说明

该说明来源于“IEEE 802.11 Rate Adaptation: A Practical Approach”

该文主要提出了AMRR算法。

本文首先谈到是否能够基于包级的速率控制需要看硬件是否支持,有些芯片在硬件里面包含了CPU,

Texas Instruments around an ARM core ,WaveLAN 802.11b,因此具有低的延时。

然而,Atheros 802.11 chipsets芯片不包含CPU,需要主机CPU来完成很多的MAC功能,而主机CPU很难实现实时的控制,基于包的速率控制是不可行的,认为是高延时的一类。

ARF算法和AARF算法、以及AMARF都是基于低延时的控制算法,

Atheros的linux驱动,称为Multiband Atheros Driver for WiFi (MadWiFi),可以在SourceForge上找到源代码,使用了HAL(硬件抽象层的概念),与硬件有关的部分是二进制的代码,不提供源代码。

Atheros硬件允许用户创建9个发送FIFIO描述符,对发送进行调度;每个发送描述符包含了发送状况,数据的指针和长度,并且包含了一个4对的“速率/重传次数”对(r0/c0, r1/ c1,r2/c2,r3/c3)。

当无线信道可以发送的时候,硬件将引发处于FIFO头的数据的发送,首先以速率r0发送,如果发送失败,继续以速率r0发送c0-1次,然而再次以速率r1发送,如果发送失败,继续以速率r1发送c1-1次……如果发送失败了c0+c1+c2+c3次,那么放弃这次发送。

当发送完毕,或者发送放弃,硬件会在发送描述符中报告本次发送丢失的ACK的数目,因此,通过获知丢失的ACK的数目可以间接的得到本次的发送速率。

MadWiFi 的这个机制称为Multi Rate Retry mechanism。


3、onoe自适应速率说明

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

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

onoe对每个包的失败与否并不敏感,试图找到丢帧率小于50%的最高速率;

对于每个目的连接,onoe保存了一个当前链路的比特速率、以及该比特率的信用度;算法跟踪每个链路当前比特速率的信用度,如果丢包率较小,那么增加该信用度;如果该信用度达到一定的阈值,那么尝试增加信用度;如果发生了一些错误,那么该信用度复位,速率下降。

当第一次发送到目的地址的时候,将初始的速率设置为24M(802.11a/g),11M(802.11b);onoe周期性的执行算法(缺省值为1秒)

1)如果没有数据发送成功,降低到下一个速率;
2)如果发送了10个以上的包,并且每个包的平均重传次数大于1,降低到下一个速率;
3)如果超过10%的包需要重传,将信用值减小(保持大于0),
4)如果少于10%的包需要重传,增加信用值;次数               
5)如果信用值大于10,增加速率;

相关代码为:

//每次发送完数据后,都会调用该函数,来判断发送的结果,成功还是失败,以及重传的次数
  1. void

  2. ath_rate_tx_complete(struct ath_softc *sc,

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

  4. {

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



  6.       if (ds->ds_txstat.ts_status == 0) //如果 ts_status为0,表明发送成功

  7.            on->on_tx_ok++; //统计发送成功和发送失败的次数,

  8.       else

  9.            on->on_tx_err++;

  10.       on->on_tx_retr += ds->ds_txstat.ts_shortretry  //统计重传的次数,长重传加上短重传,适用于不同的长度,一般来说应该是一个为0,而另外一个不为0,

  11.                  + ds->ds_txstat.ts_longretry;

  12.       if (jiffies >= on->on_nextcheck) {  //判断现在的时间,每大约1秒钟执行一次速率控制

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

  14.            /* XXX halve rate for station mode */

  15.            on->on_nextcheck = jiffies + (ath_rateinterval * HZ) / 1000; //ath_rateinterval 定义为1000,

  16.       }

  17. }
复制代码
//这个是速率控制函数
  1. static void
  2. ath_rate_ctl(void *arg, struct ieee80211_node *ni)
  3. {

  4.       struct ath_softc *sc = arg;

  5.       struct onoe_node *on = ATH_NODE_ONOE(ATH_NODE(ni));

  6.       struct ieee80211_rateset *rs = &ni->ni_rates;

  7.       int dir = 0, nrate, enough;

  8.       sc->sc_stats.ast_rate_calls++;
  9.       /*

  10.        * Rate control

  11.        * XXX: very primitive version.

  12.        */

  13.       enough = (on->on_tx_ok + on->on_tx_err >= 10); //这两参数是从ath_rate_tx_complete中获得的,onoe算法要统计10次以上的发送结果才又有动作
  14.       /* no packet reached -> down */

  15.       if (on->on_tx_err > 0 && on->on_tx_ok == 0)  //如果压根就没有任何一次发送成功,速率控制的方向是递减,也就是算法中的第一中情况

  16.            dir = -1;

  17.       /* all packets needs retry in average -> down */

  18.       if (enough && on->on_tx_ok < on->on_tx_retr) //就是算法中的第二种情况,基本上所有的包都需要重传,降低速率

  19.            dir = -1;

  20.        //ath_rate_raise初始值定义为10,判断用于10%的一个变量

  21.     //如果没有发生传输失败,并且少于10%的包需要重传,增加速率,也就是第四钟情况

  22. /* no error and less than rate_raise% of packets need retry -> up */

  23.       if (enough && on->on_tx_err == 0 &&

  24.           on->on_tx_retr < (on->on_tx_ok * ath_rate_raise) / 100)

  25.            dir = 1;

  26.       DPRINTF(sc, "%s: ok %d err %d retr %d upper %d dir %d\n",

  27.            ether_sprintf(ni->ni_macaddr),

  28.            on->on_tx_ok, on->on_tx_err, on->on_tx_retr,

  29.            on->on_tx_upper, dir);

  30.        nrate = ni->ni_txrate; //目前使用的速率,实际上是一个大于等于0 的编号

  31.       switch (dir) {

  32.       case 0:  //不增加也不减少

  33.            if (enough && on->on_tx_upper > 0)

  34.                  on->on_tx_upper--;  

  35. // on_tx_upper定义为信用值

  36. //如果发送超过了10次,并且超过10%的包需要重传,信用值on_tx_upper减小

  37.            break;

  38.       case -1: //减少速率,

  39.            if (nrate > 0) {

  40.                  nrate--; //如果大于0,减小速率

  41.                  sc->sc_stats.ast_rate_drop++;

  42.            }

  43.            on->on_tx_upper = 0; //将信用值复位置0

  44.            break;

  45.       case 1:

  46.            /* raise rate if we hit rate_raise_threshold */

  47.            if (++on->on_tx_upper < ath_rate_raise_threshold)

  48.                  break; //信用值加1,如果信用值没有达到阈值,那么直接退出,

  49.            on->on_tx_upper = 0; //否则,增加速率,将信用值复位置0

  50.            if (nrate + 1 < rs->rs_nrates) {

  51.                  nrate++;

  52.                  sc->sc_stats.ast_rate_raise++;

  53.            }

  54.            break;

  55.       }

  56.       if (nrate != ni->ni_txrate) {  // 如果速率发生了改变,更新速率

  57.            DPRINTF(sc, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n",

  58.                __func__,

  59.                (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL) / 2,

  60.                (rs->rs_rates[nrate] & IEEE80211_RATE_VAL) / 2,

  61.                on->on_tx_ok, on->on_tx_err, on->on_tx_retr);

  62.            ath_rate_update(sc, ni, nrate);

  63.       } else if (enough) //如果速率没有发生改变,发送次数已经大约10次了,重新复位

  64.            on->on_tx_ok = on->on_tx_err = on->on_tx_retr = 0; //复位

  65. }


  66. //速率更新的代码

  67. static void

  68. ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate)

  69. {
  70. // ath_rate_ctl函数仅仅是确定了合适使用的速率,然而,atheor网卡需要在发送描述符中写入r0/c0,r1/c1, r2/c2, r3/c3四个速率和retry对,如果填充这四个发送对呢?
  71. r0速率,就是判断的最佳发送速率,r1就是最佳速率的下一个速率(如果r0已经是最低速率,那么r1为0);
  72. r2是r1的下一个速率,r3是r2的下一个速率,对于retry次数,分别设置为4,2,2,2
  73.       on->on_tx_rix0 = sc->sc_rixmap[ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL];

  74.       on->on_tx_rate0 = rt->info[on->on_tx_rix0].rateCode;

  75. on->on_tx_try0 = 1 + 3;          /* 4 tries at rate 0 */  //速率r0的设置,就是最佳速率rate
  76. if (--rate >= 0) { //速率r1的设置,就是最佳速率rate的下一个速率

  77.                   rix = sc->sc_rixmap[ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];

  78.                  on->on_tx_rate1 = rt->info[rix].rateCode;

  79.                  on->on_tx_rate1sp = on->on_tx_rate1 |

  80.                       rt->info[rix].shortPreamble;

  81.            } else

  82.                  on->on_tx_rate1 = on->on_tx_rate1sp = 0;

  83. ……….
复制代码
速率r1/c1, r2/c2,  r3/c3是通过ath_rate_setupxtxdesc函数写入硬件的,这是与硬件相关的函数,
  1. ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,

  2.       struct ath_desc *ds, int shortPreamble, size_t frame_size, u_int8_t rix)

  3. {

  4.       struct onoe_node *on = ATH_NODE_ONOE(an);
  5.       ath_hal_setupxtxdesc(sc->sc_ah, ds

  6.            , on->on_tx_rate1sp, 2 /* series 1 */

  7.            , on->on_tx_rate2sp, 2 /* series 2 */

  8.            , on->on_tx_rate3sp, 2 /* series 3 */

  9.       );

  10. }
复制代码
速率r0/c0 是通过ath_hal_setuptxdesc函数写入硬件的,
  1.          ath_hal_setuptxdesc(ah, ds

  2.                      , pktlen          /* packet length */

  3.                      , hdrlen          /* header length */

  4.                      , atype           /* Atheros packet type */

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

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

  7.                      , keyix           /* key cache index */
复制代码
该函数在if_ath.c 中每次ath_tx_start函数进行发送的时候调用
阅读(2756) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~