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解析之发送速率控制相关推荐

  1. java socket 报文解析_java socket解析和发送二进制报文工具(附java和C++转化问题)

    解析: 首先是读取字节: /*** 读取输入流中指定字节的长度 * * 输入流 * *@paramlength 指定长度 *@return指定长度的字节数组*/ public static byte[ ...

  2. matlab解析单片机发送数据的一种简单方法

    matlab解析单片机发送数据的一种简单方法 经常使用单片机的同学,应该会经常面对这样一种情况,那就是对单片机采回的某些数据绘图.再处理等应用.大家经常用的两款软件,比如匿名的地面站,它通过固定的数据 ...

  3. fifaonline3服务器位置,fifaonline3 无法解析服务器发送的参数是怎么回事?

    fifaonline3 无法解析服务器发送的参数是怎么回事? 本人姓罗名本:这是账号问题,跟网络无关,手动打完一局联赛,等比分出完就可以了 发布于 2020-06-01 06:02:05 丿欣少:无法 ...

  4. Teams Bot如何解析和发送 at 用户

    之前有好些看博客的开发者问我有什么较好的方法来解析 at 信息.用户在channel里发消息给 bot 的时候,通常需要 at bot的名字,当然在消息文字中可能还会 at 其他用户,比如 bot的名 ...

  5. 【EventBus】EventBus 源码解析 ( 事件发送 | postToSubscription 方法 | EventBus 线程模式处理细节 )

    文章目录 一.事件发送 postSingleEventForEventType 方法 二.事件发送 postToSubscription 方法 三.事件发送 invokeSubscriber 方法 一 ...

  6. 使用VS code 创建 Azure Functions,从blob触发,解析,发送至Service Bus

    场景: 某设备定时于每天23:00左右将一天的运行日志.devicelogtxt上传到Azure Blob,期待Blob文件上传后, 自动通过Azure Functions 解析文件并将文件内容写入到 ...

  7. linux sendto 源码,Linux内核源代码解析——用户发送数据包的起源之sendto

    Jack:我想知道用户如何把数据发送到内核空间的? 我:你觉得哪里比较难理解呢? Jack:一般程序员会在程序里通过socket变量获得一个文件描述符,然后通过write把定义好的字符串写入到该描述符 ...

  8. 【EventBus】EventBus 源码解析 ( 事件发送 | 线程池中执行订阅方法 )

    文章目录 一.EventBus 中主线程支持类 二.EventBus 中 AsyncPoster 分析 三.AsyncPoster 线程池 Runnable 任务类 一.EventBus 中主线程支持 ...

  9. UDP通信——使用python通过UDP通信来发送和解析数据

    UDP通信--使用python通过UDP通信来发送和解析数据 经常我们要发送的信息是结构化的数据,此时发送和接收数据结构就是一个很基本的工作,怎样来实现呢? 发送和接收数据结构我们要用到 python ...

最新文章

  1. OpenCV中图像Mat,二维指针和CxImage类之间的转换
  2. JAVA代码实现多级树结构封装对象
  3. LG P990开机黑屏,但能进入系统的解决办法
  4. android 更改edittext内容,Android如何实时更改edittext的内容
  5. Quartz调度源码分析
  6. Java8 FlatMap的使用
  7. windows性能监视器基本指标
  8. 怎样将计算机和电视机连接网络,家里怎么连接网络到电视机,让电脑和电视都可以上网。...
  9. ios逆向工具theos安装和使用tweak替换和卸载
  10. Linux team多网卡绑定
  11. Android 开启混淆后序列化的问题 Parcelable encountered IOException writing serializable object
  12. RuntimeError: generator raised StopIteration(python带我起飞报错)
  13. 乐器php毕业论文,打击乐器在音乐课堂教学中的应用
  14. 《学习之道》读书笔记
  15. CAD的图导入PADS 做板框(转)
  16. 数模新版视频课程第11讲.时间序列分析
  17. 处理solr时遇到的问题
  18. Corba 学习笔记 (一)
  19. Simple Mover
  20. 【PTA】名人堂与代金券

热门文章

  1. 解决intellij IEDA mapper.xml文件警告以及could not autowire的错误提示
  2. 补充知识:三元运算和逻辑运算
  3. FZU-2218 Simple String Problem(状态压缩DP)
  4. Apache Ant运行时Unable to locate tools.jar解决方法
  5. [Spring MVC] - JSP + Freemarker视图解释器整合
  6. Remote System Upgrade With Cyclone III Devices
  7. jsp中未登录用户也可以浏览页面的功能实现代码
  8. 总结这阵子的FPGA工作
  9. [projectEuler.net]12
  10. mysql打包备份数据到_thinkPHP使用pclzip打包备份mysql数据库的方法