/*** 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 *));
};
/*** 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;
}