Chinaunix首页 | 论坛 | 博客
  • 博客访问: 52463
  • 博文数量: 22
  • 博客积分: 945
  • 博客等级: 准尉
  • 技术积分: 180
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-08 13:26
文章分类

全部博文(22)

文章存档

2011年(3)

2010年(19)

我的朋友

分类: LINUX

2010-08-08 15:29:21

使用iwconfig命令可以设置速率: 1、iwconfig源代码阅读首先下载iwconfig.c代码,源代码包为\wireless_tools.29目录先看执行 iwconfig eth0 的命令的执行过程:调用main函数,因为是两个参数: if(argc == 2) print_info(skfd, argv[1], NULL, 0); print_info调用 get_info(int skfd, char * ifname, struct wireless_info * info) 将网卡的各种信息打印出来。下面与打印发送速率为例,说明调用过程,get_info函数里面: /* Get bit rate */ if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0) { info->has_bitrate = 1; memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam)); } 对信息的获取都是通过iw_get_ext函数来实现的,通过参数SIOCGIWRATE来识别不同的内容。iwlib.h文件定义了iw_get_ext: static inline int iw_get_ext(int skfd, /* Socket to the kernel */ const char * ifname, /* Device name */ int request, /* WE ID */ struct iwreq * pwrq) /* Fixed part of the request */ { /* Set device name */ strncpy(pwrq->ifr_name, ifname, IFNAMSIZ); /* Do the request */ return(ioctl(skfd, request, pwrq)); } 因此,真正对网卡其他参数的实现是通过ioctl函数实现的,ioctl是驱动程序的基本功能,因此,如果自己想编写一个对网卡参数设置的程序,也应该使用ioctl函数。下面在看使用iwconfig eth0 rate auto命令执行情况;main函数,当输入参数大于2的时候,调用: goterr = set_info(skfd, argv + 2, argc - 2, argv[1]); set_info函数调用iwcmd = find_command(args[0]); 用来查找命令,所有的命令都存放在一个表中,只要查找这个表即可: static const struct iwconfig_entry iwconfig_cmds[] = { { "essid", set_essid_info, 1, SIOCSIWESSID, "Set ESSID", "{NNN|any|on|off}" }, { "mode", set_mode_info, 1, SIOCSIWMODE, "Set Mode", "{managed|ad-hoc|master|...}" }, { "freq", set_freq_info, 1, SIOCSIWFREQ, "Set Frequency", "N.NNN[k|M|G]" }, { "channel", set_freq_info, 1, SIOCSIWFREQ, "Set Frequency", "N" }, { "bit", set_bitrate_info, 1, SIOCSIWRATE, "Set Bit Rate", "{N[k|M|G]|auto|fixed}" }, { "rate", set_bitrate_info, 1, SIOCSIWRATE, "Set Bit Rate", "{N[k|M|G]|auto|fixed}" }, { "enc", set_enc_info, 1, SIOCSIWENCODE, "Set Encode", "{NNNN-NNNN|off}" }, { "key", set_enc_info, 1, SIOCSIWENCODE, "Set Encode", "{NNNN-NNNN|off}" }, { "power", set_power_info, 1, SIOCSIWPOWER, "Set Power Management", "{period N|timeout N|saving N|off}" }, #ifndef WE_ESSENTIAL { "nickname", set_nick_info, 1, SIOCSIWNICKN, "Set Nickname", "NNN" }, { "nwid", set_nwid_info, 1, SIOCSIWNWID, "Set NWID", "{NN|on|off}" }, { "ap", set_apaddr_info, 1, SIOCSIWAP, "Set AP Address", "{N|off|auto}" }, { "txpower", set_txpower_info, 1, SIOCSIWTXPOW, "Set Tx Power", "{NmW|NdBm|off|auto}" }, { "sens", set_sens_info, 1, SIOCSIWSENS, "Set Sensitivity", "N" }, { "retry", set_retry_info, 1, SIOCSIWRETRY, "Set Retry Limit", "{limit N|lifetime N}" }, { "rts", set_rts_info, 1, SIOCSIWRTS, "Set RTS Threshold", "{N|auto|fixed|off}" }, { "frag", set_frag_info, 1, SIOCSIWFRAG, "Set Fragmentation Threshold", "{N|auto|fixed|off}" }, { "modulation", set_modulation_info, 1, SIOCGIWMODUL, "Set Modulation", "{11g|11a|CCK|OFDMg|...}" }, #endif /* WE_ESSENTIAL */ { "commit", set_commit_info, 0, SIOCSIWCOMMIT, "Commit changes", "" }, { NULL, NULL, 0, 0, NULL, NULL }, }; 当第三个参数为rate的时候,就会自动调用set_bitrate_info函数,该函数的定义为: set_bitrate_info static int set_bitrate_info(int skfd, char * ifname, char * args[], /* Command line args */ int count) /* Args count */ { struct iwreq wrq; int i = 1; wrq.u.bitrate.flags = 0; if(!strcasecmp(args[0], "auto")) { wrq.u.bitrate.value = -1; wrq.u.bitrate.fixed = 0; } else { if(!strcasecmp(args[0], "fixed")) { /* Get old bitrate */ if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) < 0) return(IWERR_GET_EXT); wrq.u.bitrate.fixed = 1; } else /* Should be a numeric value */ { double brate; char * unit; brate = strtod(args[0], &unit); if(unit == args[0]) { errarg = 0; return(IWERR_ARG_TYPE); } if(unit != NULL) { if(unit[0] == 'G') brate *= GIGA; if(unit[0] == 'M') brate *= MEGA; if(unit[0] == 'k') brate *= KILO; } wrq.u.bitrate.value = (long) brate; wrq.u.bitrate.fixed = 1; /* Check for an additional argument */ if((i < count) && (!strcasecmp(args[i], "auto"))) { wrq.u.bitrate.fixed = 0; ++i; } if((i < count) && (!strcasecmp(args[i], "fixed"))) { wrq.u.bitrate.fixed = 1; ++i; } if((i < count) && (!strcasecmp(args[i], "unicast"))) { wrq.u.bitrate.flags |= IW_BITRATE_UNICAST; ++i; } if((i < count) && (!strcasecmp(args[i], "broadcast"))) { wrq.u.bitrate.flags |= IW_BITRATE_BROADCAST; ++i; } } } if(iw_set_ext(skfd, ifname, SIOCSIWRATE, &wrq) < 0) return(IWERR_SET_EXT); /* Var args */ return(i); } 也就是说,如果选择auto,那么设置变量bitrate.fixed=0,最后调用iw_set_ext(skfd, ifname, SIOCSIWRATE, &wrq)函数,这个函数也是直接与网卡相关的。与iw_get_ext函数一样,iw_set_ext也是通过SIOCGIWRATE来识别的: static inline int iw_set_ext(int skfd, /* Socket to the kernel */ const char * ifname, /* Device name */ int request, /* WE ID */ struct iwreq * pwrq) /* Fixed part of the request */ { /* Set device name */ strncpy(pwrq->ifr_name, ifname, IFNAMSIZ); /* Do the request */ return(ioctl(skfd, request, pwrq)); } 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,增加速率; 相关代码为: //每次发送完数据后,都会调用该函数,来判断发送的结果,成功还是失败,以及重传的次数 void ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, const struct ath_desc *ds) { struct onoe_node *on = ATH_NODE_ONOE(an); if (ds->ds_txstat.ts_status == 0) //如果ts_status为0,表明发送成功 on->on_tx_ok++; //统计发送成功和发送失败的次数, else on->on_tx_err++; //统计重传的次数,长重传加上短重传,适用于不同的长度,一般来说应该是一个为0,而另外一个不为0, on->on_tx_retr += ds->ds_txstat.ts_shortretry + ds->ds_txstat.ts_longretry; if (jiffies >= on->on_nextcheck) { //判断现在的时间,每大约1秒钟执行一次速率控制 ath_rate_ctl(sc, &an->an_node); /* XXX halve rate for station mode */ on->on_nextcheck = jiffies + (ath_rateinterval * HZ) / 1000; //ath_rateinterval定义为1000, } } //这个是速率控制函数 static void ath_rate_ctl(void *arg, struct ieee80211_node *ni) { struct ath_softc *sc = arg; struct onoe_node *on = ATH_NODE_ONOE(ATH_NODE(ni)); struct ieee80211_rateset *rs = &ni->ni_rates; int dir = 0, nrate, enough; sc->sc_stats.ast_rate_calls++; /* * Rate control * XXX: very primitive version. */ enough = (on->on_tx_ok + on->on_tx_err >= 10); //这两参数是从ath_rate_tx_complete中获得的,onoe算法要统计10次以上的发送结果才又有动作 /* no packet reached -> down */ if (on->on_tx_err > 0 && on->on_tx_ok == 0) //如果压根就没有任何一次发送成功,速率控制的方向是递减,也就是算法中的第一中情况 dir = -1; /* all packets needs retry in average -> down */ if (enough && on->on_tx_ok < on->on_tx_retr) //就是算法中的第二种情况,基本上所有的包都需要重传,降低速率 dir = -1; //ath_rate_raise初始值定义为10,判断用于10%的一个变量 //如果没有发生传输失败,并且少于10%的包需要重传,增加速率,也就是第四钟情况 /* no error and less than rate_raise% of packets need retry -> up */ if (enough && on->on_tx_err == 0 && on->on_tx_retr < (on->on_tx_ok * ath_rate_raise) / 100) dir = 1; DPRINTF(sc, "%s: ok %d err %d retr %d upper %d dir %d\n", ether_sprintf(ni->ni_macaddr), on->on_tx_ok, on->on_tx_err, on->on_tx_retr, on->on_tx_upper, dir); nrate = ni->ni_txrate; //目前使用的速率,实际上是一个大于等于0的编号 switch (dir) { case 0: //不增加也不减少 if (enough && on->on_tx_upper > 0) on->on_tx_upper--; // on_tx_upper定义为信用值 //如果发送超过了10次,并且超过10%的包需要重传,信用值on_tx_upper减小 break; case -1: //减少速率, if (nrate > 0) { nrate--; //如果大于0,减小速率 sc->sc_stats.ast_rate_drop++; } on->on_tx_upper = 0; //将信用值复位置0 break; case 1: /* raise rate if we hit rate_raise_threshold */ if (++on->on_tx_upper < ath_rate_raise_threshold) break; //信用值加1,如果信用值没有达到阈值,那么直接退出, on->on_tx_upper = 0; //否则,增加速率,将信用值复位置0 if (nrate + 1 < rs->rs_nrates) { nrate++; sc->sc_stats.ast_rate_raise++; } break; } if (nrate != ni->ni_txrate) { //如果速率发生了改变,更新速率 DPRINTF(sc, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n", __func__, (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL) / 2, (rs->rs_rates[nrate] & IEEE80211_RATE_VAL) / 2, on->on_tx_ok, on->on_tx_err, on->on_tx_retr); ath_rate_update(sc, ni, nrate); } else if (enough) //如果速率没有发生改变,发送次数已经大约10次了,重新复位 on->on_tx_ok = on->on_tx_err = on->on_tx_retr = 0; //复位 }
阅读(1077) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~