您的位置:首页 > 其它

mac80211解析七

2017-02-24 17:22 471 查看
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_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来实现速率的控制和修改。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息