mac80211解析之发送速率控制
mac80211的模块初始化的时候,也初始化了minstrel,minstrel是调用速率控制函数模快,通过tx.c中的ieee80211_tx_h_rate_ctrl句柄填充结构体ieee80211_tx_info的速率变量ieee80211_tx_rate。
模块初始化后调用了ieee80211_rate_control_register进行速率控制注册,注册了定义好的速率控制操作结构体mac80211_minstrel_ht,内容如下:
static const struct rate_control_ops mac80211_minstrel_ht = {.name = "minstrel_ht",.tx_status = minstrel_ht_tx_status,.get_rate = minstrel_ht_get_rate,.rate_init = minstrel_ht_rate_init,.rate_update = minstrel_ht_rate_update,.alloc_sta = minstrel_ht_alloc_sta,.free_sta = minstrel_ht_free_sta,.alloc = minstrel_ht_alloc,.free = minstrel_ht_free,
#ifdef CPTCFG_MAC80211_DEBUGFS.add_sta_debugfs = minstrel_ht_add_sta_debugfs,.remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
#endif.get_expected_throughput = minstrel_ht_get_expected_throughput,
};
其中minstrel_ht_get_rate函数,这个函数在高速率控制函数rc80211_minstrel_ht.c文件中,内容如下:
static void
minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,struct ieee80211_tx_rate_control *txrc)
{const struct mcs_group *sample_group;struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);struct ieee80211_tx_rate *rate = &info->status.rates[0];struct minstrel_ht_sta_priv *msp = priv_sta;struct minstrel_ht_sta *mi = &msp->ht;struct minstrel_priv *mp = priv;int sample_idx;if (rate_control_send_low(sta, priv_sta, txrc))return;if (!msp->is_ht)return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);info->flags |= mi->tx_flags;minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);#ifdef CPTCFG_MAC80211_DEBUGFSif (mp->fixed_rate_idx != -1)return;
#endif/* Don't use EAPOL frames for sampling on non-mrr hw */if (mp->hw->max_rates == 1 &&(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))sample_idx = -1;elsesample_idx = minstrel_get_sample_rate(mp, mi);mi->total_packets++;/* wraparound */if (mi->total_packets == ~0) {mi->total_packets = 0;mi->sample_packets = 0;}if (sample_idx < 0)return;sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;rate->count = 1;if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);rate->idx = mp->cck_rates[idx];rate->flags = 0;return;}rate->idx = sample_idx % MCS_GROUP_RATES +(sample_group->streams - 1) * 8;rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
}
表示站点信息的结构体ieee80211_sta,定义如下:
/*** struct ieee80211_sta - station table entry** A station table entry represents a station we are possibly* communicating with. Since stations are RCU-managed in* mac80211, any ieee80211_sta pointer you get access to must* either be protected by rcu_read_lock() explicitly or implicitly,* or you must take good care to not use such a pointer after a* call to your sta_remove callback that removed it.*/
struct ieee80211_sta {u32 supp_rates[IEEE80211_NUM_BANDS];u8 addr[ETH_ALEN];u16 aid;struct ieee80211_sta_ht_cap ht_cap;struct ieee80211_sta_vht_cap vht_cap;bool wme;u8 uapsd_queues;u8 max_sp;u8 rx_nss;enum ieee80211_sta_rx_bandwidth bandwidth;enum ieee80211_smps_mode smps_mode;struct ieee80211_sta_rates __rcu *rates;bool tdls;/* must be last */u8 drv_priv[0] __aligned(sizeof(void *));
};
minstrel_ht_get_rate函数中rate_control_send_low函数是进行低速发送,内容如下:
bool rate_control_send_low(struct ieee80211_sta *pubsta,void *priv_sta,struct ieee80211_tx_rate_control *txrc)
{struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);struct ieee80211_supported_band *sband = txrc->sband;struct sta_info *sta;int mcast_rate;bool use_basicrate = false;if (!pubsta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {__rate_control_send_low(txrc->hw, sband, pubsta, info,txrc->rate_idx_mask);if (!pubsta && txrc->bss) {mcast_rate = txrc->bss_conf->mcast_rate[sband->band];if (mcast_rate > 0) {info->control.rates[0].idx = mcast_rate - 1;return true;}use_basicrate = true;} else if (pubsta) {sta = container_of(pubsta, struct sta_info, sta);if (ieee80211_vif_is_mesh(&sta->sdata->vif))use_basicrate = true;}if (use_basicrate)rc_send_low_basicrate(&info->control.rates[0].idx,txrc->bss_conf->basic_rates,sband);return true;}return false;
}
如果不是数据帧或没有ACK,则调用__rate_control_send_low函数,该函数内容如下:
static void __rate_control_send_low(struct ieee80211_hw *hw,struct ieee80211_supported_band *sband,struct ieee80211_sta *sta,struct ieee80211_tx_info *info,u32 rate_mask)
{int i;u32 rate_flags =ieee80211_chandef_rate_flags(&hw->conf.chandef);if ((sband->band == IEEE80211_BAND_2GHZ) &&(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))rate_flags |= IEEE80211_RATE_ERP_G;info->control.rates[0].idx = 0;for (i = 0; i < sband->n_bitrates; i++) {if (!(rate_mask & BIT(i)))continue;if ((rate_flags & sband->bitrates[i].flags) != rate_flags)continue;if (!rate_supported(sta, sband->band, i))continue;info->control.rates[0].idx = i;break;}WARN_ON_ONCE(i == sband->n_bitrates);info->control.rates[0].count =(info->flags & IEEE80211_TX_CTL_NO_ACK) ?1 : hw->max_rate_tries;info->control.skip_table = 1;
}
其中用到发送tx速率控制结构体ieee80211_tx_rate_control ,定义如下:
/*** struct ieee80211_tx_rate_control - rate control information for/from RC algo*/
struct ieee80211_tx_rate_control {struct ieee80211_hw *hw;struct ieee80211_supported_band *sband;struct ieee80211_bss_conf *bss_conf;struct sk_buff *skb;struct ieee80211_tx_rate reported_rate;bool rts, short_preamble;u8 max_rate_idx;u32 rate_idx_mask;u8 *rate_idx_mcs_mask;bool bss;
};
发送tx速率结构体ieee80211_tx_rate,定义如下:
/*** struct ieee80211_tx_rate - rate selection/status* * A value of -1 for @idx indicates an invalid rate and, if used* in an array of retry rates, that no more rates should be tried.** When used for transmit status reporting, the driver should* always report the rate along with the flags it used.** &struct ieee80211_tx_info contains an array of these structs* in the control information, and it will be filled by the rate* control algorithm according to what should be sent. For example,* if this array contains, in the format { <idx>, <count> } the* information* { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 }* then this means that the frame should be transmitted* up to twice at rate 3, up to twice at rate 2, and up to four* times at rate 1 if it doesn't get acknowledged. Say it gets* acknowledged by the peer after the fifth attempt, the status* information should then contain* { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ...* since it was transmitted twice at rate 3, twice at rate 2* and once at rate 1 after which we received an acknowledgement.*/
struct ieee80211_tx_rate {s8 idx;u16 count:5,flags:11;
} __packed;
发送速率tx的数据信息结构体ieee80211_tx_info ,定义如下:
/*** struct ieee80211_tx_info - skb transmit information** This structure is placed in skb->cb for three uses:* (1) mac80211 TX control - mac80211 tells the driver what to do* (2) driver internal use (if applicable)* (3) TX status information - driver tells mac80211 what happened** @flags: transmit info flags, defined above* @band: the band to transmit on (use for checking for races)* @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC* @ack_frame_id: internal frame ID for TX status, used internally* @control: union for control data* @status: union for status data* @driver_data: array of driver_data pointers* @ampdu_ack_len: number of acked aggregated frames.* relevant only if IEEE80211_TX_STAT_AMPDU was set.* @ampdu_len: number of aggregated frames.* relevant only if IEEE80211_TX_STAT_AMPDU was set.* @ack_signal: signal strength of the ACK frame*/
struct ieee80211_tx_info {/* common information */u32 flags;u8 band;u8 hw_queue;u16 ack_frame_id;union {struct {union {/* rate control */struct {struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];s8 rts_cts_rate_idx;u8 use_rts:1;u8 use_cts_prot:1;u8 short_preamble:1;u8 skip_table:1;/* 2 bytes free */};/* only needed before rate control */unsigned long jiffies;};/* NB: vif can be NULL for injected frames */struct ieee80211_vif *vif;struct ieee80211_key_conf *hw_key;u32 flags;/* 4 bytes free */} control;struct {struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];s32 ack_signal;u8 ampdu_ack_len;u8 ampdu_len;u8 antenna;void *status_driver_data[21 / sizeof(void *)];} status;struct {struct ieee80211_tx_rate driver_rates[IEEE80211_TX_MAX_RATES];u8 pad[4];void *rate_driver_data[IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)];};void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)];};
};
使用简单速率控制则调用minstrel_get_sample_rate函数来实现,内容如下:
static int
minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
{struct minstrel_rate_stats *mr;struct minstrel_mcs_group_data *mg;unsigned int sample_dur, sample_group;int sample_idx = 0;if (mi->sample_wait > 0) {mi->sample_wait--;return -1;}if (!mi->sample_tries)return -1;sample_group = mi->sample_group;mg = &mi->groups[sample_group];sample_idx = sample_table[mg->column][mg->index];minstrel_next_sample_idx(mi);if (!(mg->supported & BIT(sample_idx)))return -1;mr = &mg->rates[sample_idx];sample_idx += sample_group * MCS_GROUP_RATES;/** Sampling might add some overhead (RTS, no aggregation)* to the frame. Hence, don't use sampling for the currently* used rates.*/if (sample_idx == mi->max_tp_rate ||sample_idx == mi->max_tp_rate2 ||sample_idx == mi->max_prob_rate)return -1;/** Do not sample if the probability is already higher than 95%* to avoid wasting airtime.*/if (mr->probability > MINSTREL_FRAC(95, 100))return -1;/** Make sure that lower rates get sampled only occasionally,* if the link is working perfectly.*/sample_dur = minstrel_get_duration(sample_idx);if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) &&(mi->max_prob_streams <minstrel_mcs_groups[sample_group].streams ||sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {if (mr->sample_skipped < 20)return -1;if (mi->sample_slow++ > 2)return -1;}mi->sample_tries--;return sample_idx;
}
经过速率算法的计算后得到结果,其实最后修改速率的结果传递了minstrel_ht_get_rate函数最后的rate->idx和rate->flags:
rate->idx = sample_idx % MCS_GROUP_RATES +(sample_group->streams - 1) * 8;
rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
可以根据rate结构体ieee80211_tx_rate,自定义符合要求的idx和flags来实现速率的控制和修改。
————————————————
版权声明:本文为CSDN博主「viewsky11」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/viewsky11/article/details/56843450
mac80211解析之发送速率控制相关推荐
- java socket 报文解析_java socket解析和发送二进制报文工具(附java和C++转化问题)
解析: 首先是读取字节: /*** 读取输入流中指定字节的长度 * * 输入流 * *@paramlength 指定长度 *@return指定长度的字节数组*/ public static byte[ ...
- matlab解析单片机发送数据的一种简单方法
matlab解析单片机发送数据的一种简单方法 经常使用单片机的同学,应该会经常面对这样一种情况,那就是对单片机采回的某些数据绘图.再处理等应用.大家经常用的两款软件,比如匿名的地面站,它通过固定的数据 ...
- fifaonline3服务器位置,fifaonline3 无法解析服务器发送的参数是怎么回事?
fifaonline3 无法解析服务器发送的参数是怎么回事? 本人姓罗名本:这是账号问题,跟网络无关,手动打完一局联赛,等比分出完就可以了 发布于 2020-06-01 06:02:05 丿欣少:无法 ...
- Teams Bot如何解析和发送 at 用户
之前有好些看博客的开发者问我有什么较好的方法来解析 at 信息.用户在channel里发消息给 bot 的时候,通常需要 at bot的名字,当然在消息文字中可能还会 at 其他用户,比如 bot的名 ...
- 【EventBus】EventBus 源码解析 ( 事件发送 | postToSubscription 方法 | EventBus 线程模式处理细节 )
文章目录 一.事件发送 postSingleEventForEventType 方法 二.事件发送 postToSubscription 方法 三.事件发送 invokeSubscriber 方法 一 ...
- 使用VS code 创建 Azure Functions,从blob触发,解析,发送至Service Bus
场景: 某设备定时于每天23:00左右将一天的运行日志.devicelogtxt上传到Azure Blob,期待Blob文件上传后, 自动通过Azure Functions 解析文件并将文件内容写入到 ...
- linux sendto 源码,Linux内核源代码解析——用户发送数据包的起源之sendto
Jack:我想知道用户如何把数据发送到内核空间的? 我:你觉得哪里比较难理解呢? Jack:一般程序员会在程序里通过socket变量获得一个文件描述符,然后通过write把定义好的字符串写入到该描述符 ...
- 【EventBus】EventBus 源码解析 ( 事件发送 | 线程池中执行订阅方法 )
文章目录 一.EventBus 中主线程支持类 二.EventBus 中 AsyncPoster 分析 三.AsyncPoster 线程池 Runnable 任务类 一.EventBus 中主线程支持 ...
- UDP通信——使用python通过UDP通信来发送和解析数据
UDP通信--使用python通过UDP通信来发送和解析数据 经常我们要发送的信息是结构化的数据,此时发送和接收数据结构就是一个很基本的工作,怎样来实现呢? 发送和接收数据结构我们要用到 python ...
最新文章
- OpenCV中图像Mat,二维指针和CxImage类之间的转换
- JAVA代码实现多级树结构封装对象
- LG P990开机黑屏,但能进入系统的解决办法
- android 更改edittext内容,Android如何实时更改edittext的内容
- Quartz调度源码分析
- Java8 FlatMap的使用
- windows性能监视器基本指标
- 怎样将计算机和电视机连接网络,家里怎么连接网络到电视机,让电脑和电视都可以上网。...
- ios逆向工具theos安装和使用tweak替换和卸载
- Linux team多网卡绑定
- Android 开启混淆后序列化的问题 Parcelable encountered IOException writing serializable object
- RuntimeError: generator raised StopIteration(python带我起飞报错)
- 乐器php毕业论文,打击乐器在音乐课堂教学中的应用
- 《学习之道》读书笔记
- CAD的图导入PADS 做板框(转)
- 数模新版视频课程第11讲.时间序列分析
- 处理solr时遇到的问题
- Corba 学习笔记 (一)
- Simple Mover
- 【PTA】名人堂与代金券
热门文章
- 解决intellij IEDA mapper.xml文件警告以及could not autowire的错误提示
- 补充知识:三元运算和逻辑运算
- FZU-2218 Simple String Problem(状态压缩DP)
- Apache Ant运行时Unable to locate tools.jar解决方法
- [Spring MVC] - JSP + Freemarker视图解释器整合
- Remote System Upgrade With Cyclone III Devices
- jsp中未登录用户也可以浏览页面的功能实现代码
- 总结这阵子的FPGA工作
- [projectEuler.net]12
- mysql打包备份数据到_thinkPHP使用pclzip打包备份mysql数据库的方法