summaryrefslogtreecommitdiff
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r--net/mac80211/tx.c187
1 files changed, 143 insertions, 44 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 00671ae45b2f..e7b141c55f7a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -59,6 +59,9 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
if (WARN_ON_ONCE(tx->rate.idx < 0))
return 0;
+ if (info->band >= NUM_NL80211_BANDS)
+ return 0;
+
sband = local->hw.wiphy->bands[info->band];
txrate = &sband->bitrates[tx->rate.idx];
@@ -683,7 +686,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
memset(&txrc, 0, sizeof(txrc));
- sband = tx->local->hw.wiphy->bands[info->band];
+ if (info->band < NUM_NL80211_BANDS)
+ sband = tx->local->hw.wiphy->bands[info->band];
+ else
+ return TX_CONTINUE;
len = min_t(u32, tx->skb->len + FCS_LEN,
tx->local->hw.wiphy->frag_threshold);
@@ -1814,7 +1820,7 @@ static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
txh_done:
if (unlikely(res == TX_DROP)) {
- I802_DEBUG_INC(tx->local->tx_handlers_drop);
+ tx->sdata->tx_handlers_drop++;
if (tx->skb)
ieee80211_free_txskb(&tx->local->hw, tx->skb);
else
@@ -1858,7 +1864,7 @@ static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
txh_done:
if (unlikely(res == TX_DROP)) {
- I802_DEBUG_INC(tx->local->tx_handlers_drop);
+ tx->sdata->tx_handlers_drop++;
if (tx->skb)
ieee80211_free_txskb(&tx->local->hw, tx->skb);
else
@@ -1942,6 +1948,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
if (unlikely(res_prepare == TX_DROP)) {
ieee80211_free_txskb(&local->hw, skb);
+ tx.sdata->tx_handlers_drop++;
return true;
} else if (unlikely(res_prepare == TX_QUEUED)) {
return true;
@@ -3728,8 +3735,10 @@ void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
fast_tx->key, &tx);
tx.skb = NULL;
- if (r == TX_DROP)
+ if (r == TX_DROP) {
+ tx.sdata->tx_handlers_drop++;
goto free;
+ }
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
@@ -4882,15 +4891,114 @@ void ieee80211_tx_pending(struct tasklet_struct *t)
/* functions for drivers to get certain frames */
+static void ieee80211_beacon_add_tim_pvb(struct ps_data *ps,
+ struct sk_buff *skb,
+ bool mcast_traffic)
+{
+ int i, n1 = 0, n2;
+
+ /*
+ * Find largest even number N1 so that bits numbered 1 through
+ * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits
+ * (N2 + 1) x 8 through 2007 are 0.
+ */
+ for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
+ if (ps->tim[i]) {
+ n1 = i & 0xfe;
+ break;
+ }
+ }
+ n2 = n1;
+ for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
+ if (ps->tim[i]) {
+ n2 = i;
+ break;
+ }
+ }
+
+ /* Bitmap control */
+ skb_put_u8(skb, n1 | mcast_traffic);
+ /* Part Virt Bitmap */
+ skb_put_data(skb, ps->tim + n1, n2 - n1 + 1);
+}
+
+/*
+ * mac80211 currently supports encoding using block bitmap mode, non
+ * inversed. The current implementation supports up to 1600 AIDs.
+ *
+ * Block bitmap encoding breaks down the AID bitmap into blocks of 64
+ * AIDs. Each block contains between 0 and 8 subblocks. Each subblock
+ * describes 8 AIDs and the presence of a subblock is determined by
+ * the block bitmap.
+ */
+static void ieee80211_s1g_beacon_add_tim_pvb(struct ps_data *ps,
+ struct sk_buff *skb,
+ bool mcast_traffic)
+{
+ int blk;
+
+ /*
+ * Emit a bitmap control block with a page slice number of 31 and a
+ * page index of 0 which indicates as per IEEE80211-2024 9.4.2.5.1
+ * that the entire page (2048 bits) indicated by the page index
+ * is encoded in the partial virtual bitmap.
+ */
+ skb_put_u8(skb, mcast_traffic | (31 << 1));
+
+ /* Emit an encoded block for each non-zero sub-block */
+ for (blk = 0; blk < IEEE80211_MAX_SUPPORTED_S1G_TIM_BLOCKS; blk++) {
+ u8 blk_bmap = 0;
+ int sblk;
+
+ for (sblk = 0; sblk < 8; sblk++) {
+ int sblk_idx = blk * 8 + sblk;
+
+ /*
+ * If the current subblock is non-zero, increase the
+ * number of subblocks to emit for the current block.
+ */
+ if (ps->tim[sblk_idx])
+ blk_bmap |= BIT(sblk);
+ }
+
+ /* If the current block contains no non-zero sublocks */
+ if (!blk_bmap)
+ continue;
+
+ /*
+ * Emit a block control byte for the current encoded block
+ * with an encoding mode of block bitmap (0x0), not inverse
+ * (0x0) and the current block offset (5 bits)
+ */
+ skb_put_u8(skb, blk << 3);
+
+ /*
+ * Emit the block bitmap for the current encoded block which
+ * contains the present subblocks.
+ */
+ skb_put_u8(skb, blk_bmap);
+
+ /* Emit the present subblocks */
+ for (sblk = 0; sblk < 8; sblk++) {
+ int sblk_idx = blk * 8 + sblk;
+
+ if (!(blk_bmap & BIT(sblk)))
+ continue;
+
+ skb_put_u8(skb, ps->tim[sblk_idx]);
+ }
+ }
+}
+
static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
struct ieee80211_link_data *link,
struct ps_data *ps, struct sk_buff *skb,
bool is_template)
{
- u8 *pos, *tim;
- int aid0 = 0;
- int i, have_bits = 0, n1, n2;
+ struct element *tim;
+ bool mcast_traffic = false, have_bits = false;
struct ieee80211_bss_conf *link_conf = link->conf;
+ bool s1g = ieee80211_get_link_sband(link)->band == NL80211_BAND_S1GHZ;
/* Generate bitmap for TIM only if there are any STAs in power save
* mode. */
@@ -4898,7 +5006,8 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
/* in the hope that this is faster than
* checking byte-for-byte */
have_bits = !bitmap_empty((unsigned long *)ps->tim,
- IEEE80211_MAX_AID+1);
+ IEEE80211_MAX_AID + 1);
+
if (!is_template) {
if (ps->dtim_count == 0)
ps->dtim_count = link_conf->dtim_period - 1;
@@ -4906,51 +5015,39 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
ps->dtim_count--;
}
- tim = pos = skb_put(skb, 5);
- *pos++ = WLAN_EID_TIM;
- *pos++ = 3;
- *pos++ = ps->dtim_count;
- *pos++ = link_conf->dtim_period;
+ /* Length is set after parsing the AID bitmap */
+ tim = skb_put(skb, sizeof(struct element));
+ tim->id = WLAN_EID_TIM;
+ skb_put_u8(skb, ps->dtim_count);
+ skb_put_u8(skb, link_conf->dtim_period);
if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf))
- aid0 = 1;
+ mcast_traffic = true;
- ps->dtim_bc_mc = aid0 == 1;
+ ps->dtim_bc_mc = mcast_traffic;
if (have_bits) {
- /* Find largest even number N1 so that bits numbered 1 through
- * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits
- * (N2 + 1) x 8 through 2007 are 0. */
- n1 = 0;
- for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
- if (ps->tim[i]) {
- n1 = i & 0xfe;
- break;
- }
- }
- n2 = n1;
- for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
- if (ps->tim[i]) {
- n2 = i;
- break;
- }
- }
-
- /* Bitmap control */
- *pos++ = n1 | aid0;
- /* Part Virt Bitmap */
- skb_put_data(skb, ps->tim + n1, n2 - n1 + 1);
-
- tim[1] = n2 - n1 + 4;
+ if (s1g)
+ ieee80211_s1g_beacon_add_tim_pvb(ps, skb,
+ mcast_traffic);
+ else
+ ieee80211_beacon_add_tim_pvb(ps, skb, mcast_traffic);
} else {
- *pos++ = aid0; /* Bitmap control */
-
- if (ieee80211_get_link_sband(link)->band != NL80211_BAND_S1GHZ) {
- tim[1] = 4;
+ /*
+ * If there is no buffered unicast traffic for an S1G
+ * interface, we can exclude the bitmap control. This is in
+ * contrast to other phy types as they do include the bitmap
+ * control and pvb even when there is no buffered traffic.
+ */
+ if (!s1g) {
+ /* Bitmap control */
+ skb_put_u8(skb, mcast_traffic);
/* Part Virt Bitmap */
skb_put_u8(skb, 0);
}
}
+
+ tim->datalen = skb_tail_pointer(skb) - tim->data;
}
static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
@@ -6195,7 +6292,9 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
enum nl80211_band band;
rcu_read_lock();
- if (!ieee80211_vif_is_mld(&sdata->vif)) {
+ if (sdata->vif.type == NL80211_IFTYPE_NAN) {
+ band = NUM_NL80211_BANDS;
+ } else if (!ieee80211_vif_is_mld(&sdata->vif)) {
WARN_ON(link_id >= 0);
chanctx_conf =
rcu_dereference(sdata->vif.bss_conf.chanctx_conf);