mac80211解析七
2017-02-24 17:22
471 查看
mac80211的模块初始化的时候,也初始化了minstrel,minstrel是调用速率控制函数模快,通过tx.c中的
模块初始化后调用了
其中
表示站点信息的结构体
如果不是数据帧或没有ACK,则调用
其中用到发送tx速率控制结构体
发送tx速率结构体
发送速率tx的数据信息结构体
使用简单速率控制则调用
经过速率算法的计算后得到结果,其实最后修改速率的结果传递了
可以根据rate结构体
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_DEBUGFS if (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; else sample_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来实现速率的控制和修改。
相关文章推荐
- 80211学习笔记
- mac80211源码分析
- cfg80211 subsystem中的wiphy
- cfg80211 subsystem中的cfg80211_ops
- mac80211概览
- mac80211解析一
- mac80211解析二
- mac80211解析三
- mac80211解析四
- mac80211解析五
- mac80211解析六
- wireless-tools源码分析-iwpriv
- Wireless基本概念
- mac80211 代码分析
- linux Wireless基础知识(cfg80211 mac80211 nl80211)
- rt2860v2源码解析四
- mac80211解析八
- wifi配置工具iw源码解析
- 随机数的产生
- MyBatis Generator generatorConfig.xml配置详解