|
@@ -46,13 +46,20 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
|
struct ieee80211_local *local = tx->local;
|
|
struct ieee80211_local *local = tx->local;
|
|
struct ieee80211_supported_band *sband;
|
|
struct ieee80211_supported_band *sband;
|
|
struct ieee80211_hdr *hdr;
|
|
struct ieee80211_hdr *hdr;
|
|
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
|
|
+
|
|
|
|
+ /* assume HW handles this */
|
|
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* uh huh? */
|
|
|
|
+ if (WARN_ON_ONCE(info->control.rates[0].idx < 0))
|
|
|
|
+ return 0;
|
|
|
|
|
|
sband = local->hw.wiphy->bands[tx->channel->band];
|
|
sband = local->hw.wiphy->bands[tx->channel->band];
|
|
- txrate = &sband->bitrates[tx->rate_idx];
|
|
|
|
|
|
+ txrate = &sband->bitrates[info->control.rates[0].idx];
|
|
|
|
|
|
- erp = 0;
|
|
|
|
- if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
|
|
|
|
- erp = txrate->flags & IEEE80211_RATE_ERP_G;
|
|
|
|
|
|
+ erp = txrate->flags & IEEE80211_RATE_ERP_G;
|
|
|
|
|
|
/*
|
|
/*
|
|
* data and mgmt (except PS Poll):
|
|
* data and mgmt (except PS Poll):
|
|
@@ -437,140 +444,154 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|
static ieee80211_tx_result debug_noinline
|
|
static ieee80211_tx_result debug_noinline
|
|
ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|
ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|
{
|
|
{
|
|
- struct rate_selection rsel;
|
|
|
|
- struct ieee80211_supported_band *sband;
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
|
|
+ struct ieee80211_hdr *hdr = (void *)tx->skb->data;
|
|
|
|
+ struct ieee80211_supported_band *sband;
|
|
|
|
+ struct ieee80211_rate *rate;
|
|
|
|
+ int i, len;
|
|
|
|
+ bool inval = false, rts = false, short_preamble = false;
|
|
|
|
+ struct ieee80211_tx_rate_control txrc;
|
|
|
|
|
|
- sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
|
|
|
|
+ memset(&txrc, 0, sizeof(txrc));
|
|
|
|
|
|
- if (likely(tx->rate_idx < 0)) {
|
|
|
|
- rate_control_get_rate(tx->sdata, sband, tx->sta,
|
|
|
|
- tx->skb, &rsel);
|
|
|
|
- if (tx->sta)
|
|
|
|
- tx->sta->last_txrate_idx = rsel.rate_idx;
|
|
|
|
- tx->rate_idx = rsel.rate_idx;
|
|
|
|
- if (unlikely(rsel.probe_idx >= 0)) {
|
|
|
|
- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
|
|
- tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
|
|
|
|
- info->control.retries[0].rate_idx = tx->rate_idx;
|
|
|
|
- info->control.retries[0].limit = tx->local->hw.max_altrate_tries;
|
|
|
|
- tx->rate_idx = rsel.probe_idx;
|
|
|
|
- } else if (info->control.retries[0].limit == 0)
|
|
|
|
- info->control.retries[0].rate_idx = -1;
|
|
|
|
-
|
|
|
|
- if (unlikely(tx->rate_idx < 0))
|
|
|
|
- return TX_DROP;
|
|
|
|
- } else
|
|
|
|
- info->control.retries[0].rate_idx = -1;
|
|
|
|
|
|
+ sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
|
|
|
|
- if (tx->sdata->vif.bss_conf.use_cts_prot &&
|
|
|
|
- (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
|
|
|
|
- tx->last_frag_rate_idx = tx->rate_idx;
|
|
|
|
- if (rsel.probe_idx >= 0)
|
|
|
|
- tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
|
|
|
|
- else
|
|
|
|
- tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
|
|
|
|
- tx->rate_idx = rsel.nonerp_idx;
|
|
|
|
- info->tx_rate_idx = rsel.nonerp_idx;
|
|
|
|
- info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
|
|
- } else {
|
|
|
|
- tx->last_frag_rate_idx = tx->rate_idx;
|
|
|
|
- info->tx_rate_idx = tx->rate_idx;
|
|
|
|
|
|
+ len = min_t(int, tx->skb->len + FCS_LEN,
|
|
|
|
+ tx->local->fragmentation_threshold);
|
|
|
|
+
|
|
|
|
+ /* set up the tx rate control struct we give the RC algo */
|
|
|
|
+ txrc.hw = local_to_hw(tx->local);
|
|
|
|
+ txrc.sband = sband;
|
|
|
|
+ txrc.bss_conf = &tx->sdata->vif.bss_conf;
|
|
|
|
+ txrc.skb = tx->skb;
|
|
|
|
+ txrc.reported_rate.idx = -1;
|
|
|
|
+ txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
|
|
|
|
+
|
|
|
|
+ /* set up RTS protection if desired */
|
|
|
|
+ if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD &&
|
|
|
|
+ len > tx->local->rts_threshold) {
|
|
|
|
+ txrc.rts = rts = true;
|
|
}
|
|
}
|
|
- info->tx_rate_idx = tx->rate_idx;
|
|
|
|
|
|
|
|
- return TX_CONTINUE;
|
|
|
|
-}
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Use short preamble if the BSS can handle it, but not for
|
|
|
|
+ * management frames unless we know the receiver can handle
|
|
|
|
+ * that -- the management frame might be to a station that
|
|
|
|
+ * just wants a probe response.
|
|
|
|
+ */
|
|
|
|
+ if (tx->sdata->vif.bss_conf.use_short_preamble &&
|
|
|
|
+ (ieee80211_is_data(hdr->frame_control) ||
|
|
|
|
+ (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
|
|
|
|
+ txrc.short_preamble = short_preamble = true;
|
|
|
|
|
|
-static ieee80211_tx_result debug_noinline
|
|
|
|
-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
|
|
|
-{
|
|
|
|
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
|
|
|
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
|
|
- struct ieee80211_supported_band *sband;
|
|
|
|
|
|
|
|
- sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
|
|
|
|
+ rate_control_get_rate(tx->sdata, tx->sta, &txrc);
|
|
|
|
+
|
|
|
|
+ if (unlikely(info->control.rates[0].idx < 0))
|
|
|
|
+ return TX_DROP;
|
|
|
|
+
|
|
|
|
+ if (txrc.reported_rate.idx < 0)
|
|
|
|
+ txrc.reported_rate = info->control.rates[0];
|
|
|
|
|
|
if (tx->sta)
|
|
if (tx->sta)
|
|
- info->control.sta = &tx->sta->sta;
|
|
|
|
|
|
+ tx->sta->last_tx_rate = txrc.reported_rate;
|
|
|
|
|
|
- if (!info->control.retry_limit) {
|
|
|
|
- if (!is_multicast_ether_addr(hdr->addr1)) {
|
|
|
|
- int len = min_t(int, tx->skb->len + FCS_LEN,
|
|
|
|
- tx->local->fragmentation_threshold);
|
|
|
|
- if (len > tx->local->rts_threshold
|
|
|
|
- && tx->local->rts_threshold <
|
|
|
|
- IEEE80211_MAX_RTS_THRESHOLD) {
|
|
|
|
- info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS;
|
|
|
|
- info->flags |=
|
|
|
|
- IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
|
|
|
|
- info->control.retry_limit =
|
|
|
|
- tx->local->hw.conf.long_frame_max_tx_count - 1;
|
|
|
|
- } else {
|
|
|
|
- info->control.retry_limit =
|
|
|
|
- tx->local->hw.conf.short_frame_max_tx_count - 1;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- info->control.retry_limit = 1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (unlikely(!info->control.rates[0].count))
|
|
|
|
+ info->control.rates[0].count = 1;
|
|
|
|
|
|
- if (tx->flags & IEEE80211_TX_FRAGMENTED) {
|
|
|
|
- /* Do not use multiple retry rates when sending fragmented
|
|
|
|
- * frames.
|
|
|
|
- * TODO: The last fragment could still use multiple retry
|
|
|
|
- * rates. */
|
|
|
|
- info->control.retries[0].rate_idx = -1;
|
|
|
|
|
|
+ if (is_multicast_ether_addr(hdr->addr1)) {
|
|
|
|
+ /*
|
|
|
|
+ * XXX: verify the rate is in the basic rateset
|
|
|
|
+ */
|
|
|
|
+ return TX_CONTINUE;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Use CTS protection for unicast frames sent using extended rates if
|
|
|
|
- * there are associated non-ERP stations and RTS/CTS is not configured
|
|
|
|
- * for the frame. */
|
|
|
|
- if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
|
|
|
|
- (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
|
|
|
|
- (tx->flags & IEEE80211_TX_UNICAST) &&
|
|
|
|
- tx->sdata->vif.bss_conf.use_cts_prot &&
|
|
|
|
- !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
|
|
|
|
- info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
|
|
|
|
-
|
|
|
|
- /* Transmit data frames using short preambles if the driver supports
|
|
|
|
- * short preambles at the selected rate and short preambles are
|
|
|
|
- * available on the network at the current point in time. */
|
|
|
|
- if (ieee80211_is_data(hdr->frame_control) &&
|
|
|
|
- (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
|
|
|
|
- tx->sdata->vif.bss_conf.use_short_preamble &&
|
|
|
|
- (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
|
|
|
|
- info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * set up the RTS/CTS rate as the fastest basic rate
|
|
|
|
+ * that is not faster than the data rate
|
|
|
|
+ *
|
|
|
|
+ * XXX: Should this check all retry rates?
|
|
|
|
+ */
|
|
|
|
+ if (!(info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
|
|
|
|
+ s8 baserate = 0;
|
|
|
|
+
|
|
|
|
+ rate = &sband->bitrates[info->control.rates[0].idx];
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
|
+ /* must be a basic rate */
|
|
|
|
+ if (!(tx->sdata->vif.bss_conf.basic_rates & BIT(i)))
|
|
|
|
+ continue;
|
|
|
|
+ /* must not be faster than the data rate */
|
|
|
|
+ if (sband->bitrates[i].bitrate > rate->bitrate)
|
|
|
|
+ continue;
|
|
|
|
+ /* maximum */
|
|
|
|
+ if (sband->bitrates[baserate].bitrate <
|
|
|
|
+ sband->bitrates[i].bitrate)
|
|
|
|
+ baserate = i;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ info->control.rts_cts_rate_idx = baserate;
|
|
}
|
|
}
|
|
|
|
|
|
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
|
|
|
|
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
|
|
|
|
- struct ieee80211_rate *rate;
|
|
|
|
- s8 baserate = -1;
|
|
|
|
- int idx;
|
|
|
|
|
|
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
|
|
+ /*
|
|
|
|
+ * make sure there's no valid rate following
|
|
|
|
+ * an invalid one, just in case drivers don't
|
|
|
|
+ * take the API seriously to stop at -1.
|
|
|
|
+ */
|
|
|
|
+ if (inval) {
|
|
|
|
+ info->control.rates[i].idx = -1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (info->control.rates[i].idx < 0) {
|
|
|
|
+ inval = true;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
|
|
- /* Do not use multiple retry rates when using RTS/CTS */
|
|
|
|
- info->control.retries[0].rate_idx = -1;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * For now assume MCS is already set up correctly, this
|
|
|
|
+ * needs to be fixed.
|
|
|
|
+ */
|
|
|
|
+ if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) {
|
|
|
|
+ WARN_ON(info->control.rates[i].idx > 76);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
|
|
- /* Use min(data rate, max base rate) as CTS/RTS rate */
|
|
|
|
- rate = &sband->bitrates[tx->rate_idx];
|
|
|
|
|
|
+ /* set up RTS protection if desired */
|
|
|
|
+ if (rts)
|
|
|
|
+ info->control.rates[i].flags |=
|
|
|
|
+ IEEE80211_TX_RC_USE_RTS_CTS;
|
|
|
|
|
|
- for (idx = 0; idx < sband->n_bitrates; idx++) {
|
|
|
|
- if (sband->bitrates[idx].bitrate > rate->bitrate)
|
|
|
|
- continue;
|
|
|
|
- if (tx->sdata->vif.bss_conf.basic_rates & BIT(idx) &&
|
|
|
|
- (baserate < 0 ||
|
|
|
|
- (sband->bitrates[baserate].bitrate
|
|
|
|
- < sband->bitrates[idx].bitrate)))
|
|
|
|
- baserate = idx;
|
|
|
|
|
|
+ /* RC is busted */
|
|
|
|
+ if (WARN_ON(info->control.rates[i].idx >=
|
|
|
|
+ sband->n_bitrates)) {
|
|
|
|
+ info->control.rates[i].idx = -1;
|
|
|
|
+ continue;
|
|
}
|
|
}
|
|
|
|
|
|
- if (baserate >= 0)
|
|
|
|
- info->control.rts_cts_rate_idx = baserate;
|
|
|
|
- else
|
|
|
|
- info->control.rts_cts_rate_idx = 0;
|
|
|
|
|
|
+ rate = &sband->bitrates[info->control.rates[i].idx];
|
|
|
|
+
|
|
|
|
+ /* set up short preamble */
|
|
|
|
+ if (short_preamble &&
|
|
|
|
+ rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
|
|
|
+ info->control.rates[i].flags |=
|
|
|
|
+ IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
|
|
|
|
+
|
|
|
|
+ /* set up G protection */
|
|
|
|
+ if (!rts && tx->sdata->vif.bss_conf.use_cts_prot &&
|
|
|
|
+ rate->flags & IEEE80211_RATE_ERP_G)
|
|
|
|
+ info->control.rates[i].flags |=
|
|
|
|
+ IEEE80211_TX_RC_USE_CTS_PROTECT;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ return TX_CONTINUE;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static ieee80211_tx_result debug_noinline
|
|
|
|
+ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
|
|
|
+{
|
|
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
|
|
+
|
|
if (tx->sta)
|
|
if (tx->sta)
|
|
info->control.sta = &tx->sta->sta;
|
|
info->control.sta = &tx->sta->sta;
|
|
|
|
|
|
@@ -678,6 +699,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
|
left = payload_len - per_fragm;
|
|
left = payload_len - per_fragm;
|
|
for (i = 0; i < num_fragm - 1; i++) {
|
|
for (i = 0; i < num_fragm - 1; i++) {
|
|
struct ieee80211_hdr *fhdr;
|
|
struct ieee80211_hdr *fhdr;
|
|
|
|
+ struct ieee80211_tx_info *info;
|
|
size_t copylen;
|
|
size_t copylen;
|
|
|
|
|
|
if (left <= 0)
|
|
if (left <= 0)
|
|
@@ -692,20 +714,45 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
|
IEEE80211_ENCRYPT_TAILROOM);
|
|
IEEE80211_ENCRYPT_TAILROOM);
|
|
if (!frag)
|
|
if (!frag)
|
|
goto fail;
|
|
goto fail;
|
|
|
|
+
|
|
/* Make sure that all fragments use the same priority so
|
|
/* Make sure that all fragments use the same priority so
|
|
* that they end up using the same TX queue */
|
|
* that they end up using the same TX queue */
|
|
frag->priority = first->priority;
|
|
frag->priority = first->priority;
|
|
|
|
+
|
|
skb_reserve(frag, tx->local->tx_headroom +
|
|
skb_reserve(frag, tx->local->tx_headroom +
|
|
IEEE80211_ENCRYPT_HEADROOM);
|
|
IEEE80211_ENCRYPT_HEADROOM);
|
|
|
|
+
|
|
|
|
+ /* copy TX information */
|
|
|
|
+ info = IEEE80211_SKB_CB(frag);
|
|
|
|
+ memcpy(info, first->cb, sizeof(frag->cb));
|
|
|
|
+
|
|
|
|
+ /* copy/fill in 802.11 header */
|
|
fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
|
|
fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
|
|
memcpy(fhdr, first->data, hdrlen);
|
|
memcpy(fhdr, first->data, hdrlen);
|
|
- if (i == num_fragm - 2)
|
|
|
|
- fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
|
|
|
|
fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
|
|
fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
|
|
|
|
+
|
|
|
|
+ if (i == num_fragm - 2) {
|
|
|
|
+ /* clear MOREFRAGS bit for the last fragment */
|
|
|
|
+ fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
|
|
|
|
+ } else {
|
|
|
|
+ /*
|
|
|
|
+ * No multi-rate retries for fragmented frames, that
|
|
|
|
+ * would completely throw off the NAV at other STAs.
|
|
|
|
+ */
|
|
|
|
+ info->control.rates[1].idx = -1;
|
|
|
|
+ info->control.rates[2].idx = -1;
|
|
|
|
+ info->control.rates[3].idx = -1;
|
|
|
|
+ info->control.rates[4].idx = -1;
|
|
|
|
+ BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
|
|
|
|
+ info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* copy data */
|
|
copylen = left > per_fragm ? per_fragm : left;
|
|
copylen = left > per_fragm ? per_fragm : left;
|
|
memcpy(skb_put(frag, copylen), pos, copylen);
|
|
memcpy(skb_put(frag, copylen), pos, copylen);
|
|
- memcpy(frag->cb, first->cb, sizeof(frag->cb));
|
|
|
|
|
|
+
|
|
skb_copy_queue_mapping(frag, first);
|
|
skb_copy_queue_mapping(frag, first);
|
|
|
|
+
|
|
frag->do_not_encrypt = first->do_not_encrypt;
|
|
frag->do_not_encrypt = first->do_not_encrypt;
|
|
|
|
|
|
pos += copylen;
|
|
pos += copylen;
|
|
@@ -765,12 +812,10 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
|
|
tx->extra_frag[0]->len);
|
|
tx->extra_frag[0]->len);
|
|
|
|
|
|
for (i = 0; i < tx->num_extra_frag; i++) {
|
|
for (i = 0; i < tx->num_extra_frag; i++) {
|
|
- if (i + 1 < tx->num_extra_frag) {
|
|
|
|
|
|
+ if (i + 1 < tx->num_extra_frag)
|
|
next_len = tx->extra_frag[i + 1]->len;
|
|
next_len = tx->extra_frag[i + 1]->len;
|
|
- } else {
|
|
|
|
|
|
+ else
|
|
next_len = 0;
|
|
next_len = 0;
|
|
- tx->rate_idx = tx->last_frag_rate_idx;
|
|
|
|
- }
|
|
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
|
|
hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
|
|
hdr->duration_id = ieee80211_duration(tx, 0, next_len);
|
|
hdr->duration_id = ieee80211_duration(tx, 0, next_len);
|
|
@@ -823,7 +868,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
|
|
(struct ieee80211_radiotap_header *) skb->data;
|
|
(struct ieee80211_radiotap_header *) skb->data;
|
|
struct ieee80211_supported_band *sband;
|
|
struct ieee80211_supported_band *sband;
|
|
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
|
|
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
|
|
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
|
|
|
|
sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
|
|
|
|
@@ -837,8 +881,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
|
|
*/
|
|
*/
|
|
|
|
|
|
while (!ret) {
|
|
while (!ret) {
|
|
- int i, target_rate;
|
|
|
|
-
|
|
|
|
ret = ieee80211_radiotap_iterator_next(&iterator);
|
|
ret = ieee80211_radiotap_iterator_next(&iterator);
|
|
|
|
|
|
if (ret)
|
|
if (ret)
|
|
@@ -852,38 +894,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
|
|
* get_unaligned((type *)iterator.this_arg) to dereference
|
|
* get_unaligned((type *)iterator.this_arg) to dereference
|
|
* iterator.this_arg for type "type" safely on all arches.
|
|
* iterator.this_arg for type "type" safely on all arches.
|
|
*/
|
|
*/
|
|
- case IEEE80211_RADIOTAP_RATE:
|
|
|
|
- /*
|
|
|
|
- * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
|
|
|
|
- * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
|
|
|
|
- */
|
|
|
|
- target_rate = (*iterator.this_arg) * 5;
|
|
|
|
- for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
|
- struct ieee80211_rate *r;
|
|
|
|
-
|
|
|
|
- r = &sband->bitrates[i];
|
|
|
|
-
|
|
|
|
- if (r->bitrate == target_rate) {
|
|
|
|
- tx->rate_idx = i;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case IEEE80211_RADIOTAP_ANTENNA:
|
|
|
|
- /*
|
|
|
|
- * radiotap uses 0 for 1st ant, mac80211 is 1 for
|
|
|
|
- * 1st ant
|
|
|
|
- */
|
|
|
|
- info->antenna_sel_tx = (*iterator.this_arg) + 1;
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
-#if 0
|
|
|
|
- case IEEE80211_RADIOTAP_DBM_TX_POWER:
|
|
|
|
- control->power_level = *iterator.this_arg;
|
|
|
|
- break;
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
case IEEE80211_RADIOTAP_FLAGS:
|
|
case IEEE80211_RADIOTAP_FLAGS:
|
|
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
|
|
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
|
|
/*
|
|
/*
|
|
@@ -949,8 +959,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
|
|
tx->local = local;
|
|
tx->local = local;
|
|
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
tx->channel = local->hw.conf.channel;
|
|
tx->channel = local->hw.conf.channel;
|
|
- tx->rate_idx = -1;
|
|
|
|
- tx->last_frag_rate_idx = -1;
|
|
|
|
/*
|
|
/*
|
|
* Set this flag (used below to indicate "automatic fragmentation"),
|
|
* Set this flag (used below to indicate "automatic fragmentation"),
|
|
* it will be cleared/left by radiotap as desired.
|
|
* it will be cleared/left by radiotap as desired.
|
|
@@ -1051,23 +1059,11 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
|
|
if (!tx->extra_frag[i])
|
|
if (!tx->extra_frag[i])
|
|
continue;
|
|
continue;
|
|
info = IEEE80211_SKB_CB(tx->extra_frag[i]);
|
|
info = IEEE80211_SKB_CB(tx->extra_frag[i]);
|
|
- info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS |
|
|
|
|
- IEEE80211_TX_CTL_USE_CTS_PROTECT |
|
|
|
|
- IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
|
|
|
|
|
+ info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
|
IEEE80211_TX_CTL_FIRST_FRAGMENT);
|
|
IEEE80211_TX_CTL_FIRST_FRAGMENT);
|
|
if (netif_subqueue_stopped(local->mdev,
|
|
if (netif_subqueue_stopped(local->mdev,
|
|
tx->extra_frag[i]))
|
|
tx->extra_frag[i]))
|
|
return IEEE80211_TX_FRAG_AGAIN;
|
|
return IEEE80211_TX_FRAG_AGAIN;
|
|
- if (i == tx->num_extra_frag) {
|
|
|
|
- info->tx_rate_idx = tx->last_frag_rate_idx;
|
|
|
|
-
|
|
|
|
- if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
|
|
|
|
- info->flags |=
|
|
|
|
- IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
|
|
- else
|
|
|
|
- info->flags &=
|
|
|
|
- ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
|
|
- }
|
|
|
|
|
|
|
|
ret = local->ops->tx(local_to_hw(local),
|
|
ret = local->ops->tx(local_to_hw(local),
|
|
tx->extra_frag[i]);
|
|
tx->extra_frag[i]);
|
|
@@ -1204,9 +1200,6 @@ retry:
|
|
store->skb = skb;
|
|
store->skb = skb;
|
|
store->extra_frag = tx.extra_frag;
|
|
store->extra_frag = tx.extra_frag;
|
|
store->num_extra_frag = tx.num_extra_frag;
|
|
store->num_extra_frag = tx.num_extra_frag;
|
|
- store->last_frag_rate_idx = tx.last_frag_rate_idx;
|
|
|
|
- store->last_frag_rate_ctrl_probe =
|
|
|
|
- !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
|
|
|
|
}
|
|
}
|
|
out:
|
|
out:
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
@@ -1763,10 +1756,7 @@ void ieee80211_tx_pending(unsigned long data)
|
|
store = &local->pending_packet[i];
|
|
store = &local->pending_packet[i];
|
|
tx.extra_frag = store->extra_frag;
|
|
tx.extra_frag = store->extra_frag;
|
|
tx.num_extra_frag = store->num_extra_frag;
|
|
tx.num_extra_frag = store->num_extra_frag;
|
|
- tx.last_frag_rate_idx = store->last_frag_rate_idx;
|
|
|
|
tx.flags = 0;
|
|
tx.flags = 0;
|
|
- if (store->last_frag_rate_ctrl_probe)
|
|
|
|
- tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
|
|
|
|
ret = __ieee80211_tx(local, store->skb, &tx);
|
|
ret = __ieee80211_tx(local, store->skb, &tx);
|
|
if (ret) {
|
|
if (ret) {
|
|
if (ret == IEEE80211_TX_FRAG_AGAIN)
|
|
if (ret == IEEE80211_TX_FRAG_AGAIN)
|
|
@@ -1854,7 +1844,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|
struct ieee80211_sub_if_data *sdata = NULL;
|
|
struct ieee80211_sub_if_data *sdata = NULL;
|
|
struct ieee80211_if_ap *ap = NULL;
|
|
struct ieee80211_if_ap *ap = NULL;
|
|
struct ieee80211_if_sta *ifsta = NULL;
|
|
struct ieee80211_if_sta *ifsta = NULL;
|
|
- struct rate_selection rsel;
|
|
|
|
struct beacon_data *beacon;
|
|
struct beacon_data *beacon;
|
|
struct ieee80211_supported_band *sband;
|
|
struct ieee80211_supported_band *sband;
|
|
enum ieee80211_band band = local->hw.conf.channel->band;
|
|
enum ieee80211_band band = local->hw.conf.channel->band;
|
|
@@ -1958,32 +1947,23 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|
skb->do_not_encrypt = 1;
|
|
skb->do_not_encrypt = 1;
|
|
|
|
|
|
info->band = band;
|
|
info->band = band;
|
|
- rate_control_get_rate(sdata, sband, NULL, skb, &rsel);
|
|
|
|
-
|
|
|
|
- if (unlikely(rsel.rate_idx < 0)) {
|
|
|
|
- if (net_ratelimit()) {
|
|
|
|
- printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
|
|
|
|
- "no rate found\n",
|
|
|
|
- wiphy_name(local->hw.wiphy));
|
|
|
|
- }
|
|
|
|
- dev_kfree_skb_any(skb);
|
|
|
|
- skb = NULL;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
|
|
+ /*
|
|
|
|
+ * XXX: For now, always use the lowest rate
|
|
|
|
+ */
|
|
|
|
+ info->control.rates[0].idx = 0;
|
|
|
|
+ info->control.rates[0].count = 1;
|
|
|
|
+ info->control.rates[1].idx = -1;
|
|
|
|
+ info->control.rates[2].idx = -1;
|
|
|
|
+ info->control.rates[3].idx = -1;
|
|
|
|
+ info->control.rates[4].idx = -1;
|
|
|
|
+ BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
|
|
|
|
|
|
info->control.vif = vif;
|
|
info->control.vif = vif;
|
|
- info->tx_rate_idx = rsel.rate_idx;
|
|
|
|
|
|
|
|
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
|
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
|
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
|
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
|
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
|
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
|
- if (sdata->vif.bss_conf.use_short_preamble &&
|
|
|
|
- sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
|
|
|
- info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
|
|
|
|
-
|
|
|
|
- info->control.retry_limit = 1;
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
|
|
+ out:
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
return skb;
|
|
return skb;
|
|
}
|
|
}
|