|
@@ -141,14 +141,18 @@ int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
|
|
|
dur = 16; /* SIFS + signal ext */
|
|
|
dur += 16; /* IEEE 802.11-2012 18.3.2.4: T_PREAMBLE = 16 usec */
|
|
|
dur += 4; /* IEEE 802.11-2012 18.3.2.4: T_SIGNAL = 4 usec */
|
|
|
- dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
|
|
|
- 4 * rate); /* T_SYM x N_SYM */
|
|
|
|
|
|
/* IEEE 802.11-2012 18.3.2.4: all values above are:
|
|
|
* * times 4 for 5 MHz
|
|
|
* * times 2 for 10 MHz
|
|
|
*/
|
|
|
dur *= 1 << shift;
|
|
|
+
|
|
|
+ /* rates should already consider the channel bandwidth,
|
|
|
+ * don't apply divisor again.
|
|
|
+ */
|
|
|
+ dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
|
|
|
+ 4 * rate); /* T_SYM x N_SYM */
|
|
|
} else {
|
|
|
/*
|
|
|
* 802.11b or 802.11g with 802.11b compatibility:
|
|
@@ -205,7 +209,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
|
|
|
struct ieee80211_rate *rate;
|
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
bool short_preamble;
|
|
|
- int erp, shift = 0;
|
|
|
+ int erp, shift = 0, bitrate;
|
|
|
u16 dur;
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
|
|
@@ -224,14 +228,16 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
|
|
|
shift = ieee80211_vif_get_shift(vif);
|
|
|
}
|
|
|
|
|
|
+ bitrate = DIV_ROUND_UP(rate->bitrate, 1 << shift);
|
|
|
+
|
|
|
/* CTS duration */
|
|
|
- dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate,
|
|
|
+ dur = ieee80211_frame_duration(sband->band, 10, bitrate,
|
|
|
erp, short_preamble, shift);
|
|
|
/* Data frame duration */
|
|
|
- dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
|
|
|
+ dur += ieee80211_frame_duration(sband->band, frame_len, bitrate,
|
|
|
erp, short_preamble, shift);
|
|
|
/* ACK duration */
|
|
|
- dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
|
|
|
+ dur += ieee80211_frame_duration(sband->band, 10, bitrate,
|
|
|
erp, short_preamble, shift);
|
|
|
|
|
|
return cpu_to_le16(dur);
|
|
@@ -247,7 +253,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
|
|
|
struct ieee80211_rate *rate;
|
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
bool short_preamble;
|
|
|
- int erp, shift = 0;
|
|
|
+ int erp, shift = 0, bitrate;
|
|
|
u16 dur;
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
|
|
@@ -265,12 +271,14 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
|
|
|
shift = ieee80211_vif_get_shift(vif);
|
|
|
}
|
|
|
|
|
|
+ bitrate = DIV_ROUND_UP(rate->bitrate, 1 << shift);
|
|
|
+
|
|
|
/* Data frame duration */
|
|
|
- dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
|
|
|
+ dur = ieee80211_frame_duration(sband->band, frame_len, bitrate,
|
|
|
erp, short_preamble, shift);
|
|
|
if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
|
/* ACK duration */
|
|
|
- dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
|
|
|
+ dur += ieee80211_frame_duration(sband->band, 10, bitrate,
|
|
|
erp, short_preamble, shift);
|
|
|
}
|
|
|
|
|
@@ -1175,7 +1183,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
|
|
|
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
|
|
size_t buffer_len, const u8 *ie, size_t ie_len,
|
|
|
enum ieee80211_band band, u32 rate_mask,
|
|
|
- u8 channel)
|
|
|
+ struct cfg80211_chan_def *chandef)
|
|
|
{
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
u8 *pos = buffer, *end = buffer + buffer_len;
|
|
@@ -1184,16 +1192,26 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
|
|
u8 rates[32];
|
|
|
int num_rates;
|
|
|
int ext_rates_len;
|
|
|
+ int shift;
|
|
|
+ u32 rate_flags;
|
|
|
|
|
|
sband = local->hw.wiphy->bands[band];
|
|
|
if (WARN_ON_ONCE(!sband))
|
|
|
return 0;
|
|
|
|
|
|
+ rate_flags = ieee80211_chandef_rate_flags(chandef);
|
|
|
+ shift = ieee80211_chandef_get_shift(chandef);
|
|
|
+
|
|
|
num_rates = 0;
|
|
|
for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
if ((BIT(i) & rate_mask) == 0)
|
|
|
continue; /* skip rate */
|
|
|
- rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5);
|
|
|
+ if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ rates[num_rates++] =
|
|
|
+ (u8) DIV_ROUND_UP(sband->bitrates[i].bitrate,
|
|
|
+ (1 << shift) * 5);
|
|
|
}
|
|
|
|
|
|
supp_rates_len = min_t(int, num_rates, 8);
|
|
@@ -1233,12 +1251,13 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
|
|
pos += ext_rates_len;
|
|
|
}
|
|
|
|
|
|
- if (channel && sband->band == IEEE80211_BAND_2GHZ) {
|
|
|
+ if (chandef->chan && sband->band == IEEE80211_BAND_2GHZ) {
|
|
|
if (end - pos < 3)
|
|
|
goto out_err;
|
|
|
*pos++ = WLAN_EID_DS_PARAMS;
|
|
|
*pos++ = 1;
|
|
|
- *pos++ = channel;
|
|
|
+ *pos++ = ieee80211_frequency_to_channel(
|
|
|
+ chandef->chan->center_freq);
|
|
|
}
|
|
|
|
|
|
/* insert custom IEs that go before HT */
|
|
@@ -1303,9 +1322,9 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
|
|
bool directed)
|
|
|
{
|
|
|
struct ieee80211_local *local = sdata->local;
|
|
|
+ struct cfg80211_chan_def chandef;
|
|
|
struct sk_buff *skb;
|
|
|
struct ieee80211_mgmt *mgmt;
|
|
|
- u8 chan_no;
|
|
|
int ies_len;
|
|
|
|
|
|
/*
|
|
@@ -1313,10 +1332,11 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
|
|
* in order to maximize the chance that we get a response. Some
|
|
|
* badly-behaved APs don't respond when this parameter is included.
|
|
|
*/
|
|
|
+ chandef.width = sdata->vif.bss_conf.chandef.width;
|
|
|
if (directed)
|
|
|
- chan_no = 0;
|
|
|
+ chandef.chan = NULL;
|
|
|
else
|
|
|
- chan_no = ieee80211_frequency_to_channel(chan->center_freq);
|
|
|
+ chandef.chan = chan;
|
|
|
|
|
|
skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
|
|
|
ssid, ssid_len, 100 + ie_len);
|
|
@@ -1326,7 +1346,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
|
|
ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb),
|
|
|
skb_tailroom(skb),
|
|
|
ie, ie_len, chan->band,
|
|
|
- ratemask, chan_no);
|
|
|
+ ratemask, &chandef);
|
|
|
skb_put(skb, ies_len);
|
|
|
|
|
|
if (dst) {
|
|
@@ -1360,16 +1380,19 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
|
|
|
+u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
|
|
|
struct ieee802_11_elems *elems,
|
|
|
enum ieee80211_band band, u32 *basic_rates)
|
|
|
{
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
struct ieee80211_rate *bitrates;
|
|
|
size_t num_rates;
|
|
|
- u32 supp_rates;
|
|
|
- int i, j;
|
|
|
- sband = local->hw.wiphy->bands[band];
|
|
|
+ u32 supp_rates, rate_flags;
|
|
|
+ int i, j, shift;
|
|
|
+ sband = sdata->local->hw.wiphy->bands[band];
|
|
|
+
|
|
|
+ rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
|
|
|
+ shift = ieee80211_vif_get_shift(&sdata->vif);
|
|
|
|
|
|
if (WARN_ON(!sband))
|
|
|
return 1;
|
|
@@ -1394,7 +1417,15 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
|
|
|
continue;
|
|
|
|
|
|
for (j = 0; j < num_rates; j++) {
|
|
|
- if (bitrates[j].bitrate == own_rate) {
|
|
|
+ int brate;
|
|
|
+ if ((rate_flags & sband->bitrates[j].flags)
|
|
|
+ != rate_flags)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ brate = DIV_ROUND_UP(sband->bitrates[j].bitrate,
|
|
|
+ 1 << shift);
|
|
|
+
|
|
|
+ if (brate == own_rate) {
|
|
|
supp_rates |= BIT(j);
|
|
|
if (basic_rates && is_basic)
|
|
|
*basic_rates |= BIT(j);
|
|
@@ -2017,18 +2048,56 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
|
|
cfg80211_chandef_create(chandef, control_chan, channel_type);
|
|
|
}
|
|
|
|
|
|
+int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
|
|
|
+ const struct ieee80211_supported_band *sband,
|
|
|
+ const u8 *srates, int srates_len, u32 *rates)
|
|
|
+{
|
|
|
+ u32 rate_flags = ieee80211_chandef_rate_flags(chandef);
|
|
|
+ int shift = ieee80211_chandef_get_shift(chandef);
|
|
|
+ struct ieee80211_rate *br;
|
|
|
+ int brate, rate, i, j, count = 0;
|
|
|
+
|
|
|
+ *rates = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < srates_len; i++) {
|
|
|
+ rate = srates[i] & 0x7f;
|
|
|
+
|
|
|
+ for (j = 0; j < sband->n_bitrates; j++) {
|
|
|
+ br = &sband->bitrates[j];
|
|
|
+ if ((rate_flags & br->flags) != rate_flags)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5);
|
|
|
+ if (brate == rate) {
|
|
|
+ *rates |= BIT(j);
|
|
|
+ count++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
|
|
|
struct sk_buff *skb, bool need_basic,
|
|
|
enum ieee80211_band band)
|
|
|
{
|
|
|
struct ieee80211_local *local = sdata->local;
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
- int rate;
|
|
|
+ int rate, shift;
|
|
|
u8 i, rates, *pos;
|
|
|
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
|
|
|
+ u32 rate_flags;
|
|
|
|
|
|
+ shift = ieee80211_vif_get_shift(&sdata->vif);
|
|
|
+ rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
|
|
|
sband = local->hw.wiphy->bands[band];
|
|
|
- rates = sband->n_bitrates;
|
|
|
+ rates = 0;
|
|
|
+ for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
+ if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
|
|
|
+ continue;
|
|
|
+ rates++;
|
|
|
+ }
|
|
|
if (rates > 8)
|
|
|
rates = 8;
|
|
|
|
|
@@ -2040,10 +2109,15 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
|
|
|
*pos++ = rates;
|
|
|
for (i = 0; i < rates; i++) {
|
|
|
u8 basic = 0;
|
|
|
+ if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
|
|
|
+ continue;
|
|
|
+
|
|
|
if (need_basic && basic_rates & BIT(i))
|
|
|
basic = 0x80;
|
|
|
rate = sband->bitrates[i].bitrate;
|
|
|
- *pos++ = basic | (u8) (rate / 5);
|
|
|
+ rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
|
|
|
+ 5 * (1 << shift));
|
|
|
+ *pos++ = basic | (u8) rate;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -2055,12 +2129,22 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
|
|
|
{
|
|
|
struct ieee80211_local *local = sdata->local;
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
- int rate;
|
|
|
+ int rate, skip, shift;
|
|
|
u8 i, exrates, *pos;
|
|
|
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
|
|
|
+ u32 rate_flags;
|
|
|
+
|
|
|
+ rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
|
|
|
+ shift = ieee80211_vif_get_shift(&sdata->vif);
|
|
|
|
|
|
sband = local->hw.wiphy->bands[band];
|
|
|
- exrates = sband->n_bitrates;
|
|
|
+ exrates = 0;
|
|
|
+ for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
+ if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
|
|
|
+ continue;
|
|
|
+ exrates++;
|
|
|
+ }
|
|
|
+
|
|
|
if (exrates > 8)
|
|
|
exrates -= 8;
|
|
|
else
|
|
@@ -2073,12 +2157,19 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
|
|
|
pos = skb_put(skb, exrates + 2);
|
|
|
*pos++ = WLAN_EID_EXT_SUPP_RATES;
|
|
|
*pos++ = exrates;
|
|
|
+ skip = 0;
|
|
|
for (i = 8; i < sband->n_bitrates; i++) {
|
|
|
u8 basic = 0;
|
|
|
+ if ((rate_flags & sband->bitrates[i].flags)
|
|
|
+ != rate_flags)
|
|
|
+ continue;
|
|
|
+ if (skip++ < 8)
|
|
|
+ continue;
|
|
|
if (need_basic && basic_rates & BIT(i))
|
|
|
basic = 0x80;
|
|
|
- rate = sband->bitrates[i].bitrate;
|
|
|
- *pos++ = basic | (u8) (rate / 5);
|
|
|
+ rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
|
|
|
+ 5 * (1 << shift));
|
|
|
+ *pos++ = basic | (u8) rate;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
@@ -2162,9 +2253,17 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
|
|
|
ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
|
|
} else {
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
+ int shift = 0;
|
|
|
+ int bitrate;
|
|
|
+
|
|
|
+ if (status->flag & RX_FLAG_10MHZ)
|
|
|
+ shift = 1;
|
|
|
+ if (status->flag & RX_FLAG_5MHZ)
|
|
|
+ shift = 2;
|
|
|
|
|
|
sband = local->hw.wiphy->bands[status->band];
|
|
|
- ri.legacy = sband->bitrates[status->rate_idx].bitrate;
|
|
|
+ bitrate = sband->bitrates[status->rate_idx].bitrate;
|
|
|
+ ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
|
|
|
}
|
|
|
|
|
|
rate = cfg80211_calculate_bitrate(&ri);
|