|
@@ -505,106 +505,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|
|
return TX_CONTINUE;
|
|
|
}
|
|
|
|
|
|
-static ieee80211_tx_result
|
|
|
-ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
|
|
-{
|
|
|
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
|
|
|
- size_t hdrlen, per_fragm, num_fragm, payload_len, left;
|
|
|
- struct sk_buff **frags, *first, *frag;
|
|
|
- int i;
|
|
|
- u16 seq;
|
|
|
- u8 *pos;
|
|
|
- int frag_threshold = tx->local->fragmentation_threshold;
|
|
|
-
|
|
|
- if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
|
|
|
- return TX_CONTINUE;
|
|
|
-
|
|
|
- first = tx->skb;
|
|
|
-
|
|
|
- hdrlen = ieee80211_get_hdrlen(tx->fc);
|
|
|
- payload_len = first->len - hdrlen;
|
|
|
- per_fragm = frag_threshold - hdrlen - FCS_LEN;
|
|
|
- num_fragm = DIV_ROUND_UP(payload_len, per_fragm);
|
|
|
-
|
|
|
- frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC);
|
|
|
- if (!frags)
|
|
|
- goto fail;
|
|
|
-
|
|
|
- hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
|
|
|
- seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
|
|
|
- pos = first->data + hdrlen + per_fragm;
|
|
|
- left = payload_len - per_fragm;
|
|
|
- for (i = 0; i < num_fragm - 1; i++) {
|
|
|
- struct ieee80211_hdr *fhdr;
|
|
|
- size_t copylen;
|
|
|
-
|
|
|
- if (left <= 0)
|
|
|
- goto fail;
|
|
|
-
|
|
|
- /* reserve enough extra head and tail room for possible
|
|
|
- * encryption */
|
|
|
- frag = frags[i] =
|
|
|
- dev_alloc_skb(tx->local->tx_headroom +
|
|
|
- frag_threshold +
|
|
|
- IEEE80211_ENCRYPT_HEADROOM +
|
|
|
- IEEE80211_ENCRYPT_TAILROOM);
|
|
|
- if (!frag)
|
|
|
- goto fail;
|
|
|
- /* Make sure that all fragments use the same priority so
|
|
|
- * that they end up using the same TX queue */
|
|
|
- frag->priority = first->priority;
|
|
|
- skb_reserve(frag, tx->local->tx_headroom +
|
|
|
- IEEE80211_ENCRYPT_HEADROOM);
|
|
|
- fhdr = (struct ieee80211_hdr *) skb_put(frag, 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));
|
|
|
- copylen = left > per_fragm ? per_fragm : left;
|
|
|
- memcpy(skb_put(frag, copylen), pos, copylen);
|
|
|
-
|
|
|
- pos += copylen;
|
|
|
- left -= copylen;
|
|
|
- }
|
|
|
- skb_trim(first, hdrlen + per_fragm);
|
|
|
-
|
|
|
- tx->num_extra_frag = num_fragm - 1;
|
|
|
- tx->extra_frag = frags;
|
|
|
-
|
|
|
- return TX_CONTINUE;
|
|
|
-
|
|
|
- fail:
|
|
|
- printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
|
|
|
- if (frags) {
|
|
|
- for (i = 0; i < num_fragm - 1; i++)
|
|
|
- if (frags[i])
|
|
|
- dev_kfree_skb(frags[i]);
|
|
|
- kfree(frags);
|
|
|
- }
|
|
|
- I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
|
|
|
- return TX_DROP;
|
|
|
-}
|
|
|
-
|
|
|
-static ieee80211_tx_result
|
|
|
-ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
|
|
|
-{
|
|
|
- if (!tx->key)
|
|
|
- return TX_CONTINUE;
|
|
|
-
|
|
|
- switch (tx->key->conf.alg) {
|
|
|
- case ALG_WEP:
|
|
|
- return ieee80211_crypto_wep_encrypt(tx);
|
|
|
- case ALG_TKIP:
|
|
|
- return ieee80211_crypto_tkip_encrypt(tx);
|
|
|
- case ALG_CCMP:
|
|
|
- return ieee80211_crypto_ccmp_encrypt(tx);
|
|
|
- }
|
|
|
-
|
|
|
- /* not reached */
|
|
|
- WARN_ON(1);
|
|
|
- return TX_DROP;
|
|
|
-}
|
|
|
-
|
|
|
static ieee80211_tx_result
|
|
|
ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|
|
{
|
|
@@ -747,26 +647,114 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
|
|
control->rts_cts_rate_idx = 0;
|
|
|
}
|
|
|
|
|
|
- if (tx->sta) {
|
|
|
+ if (tx->sta)
|
|
|
control->aid = tx->sta->aid;
|
|
|
- tx->sta->tx_packets++;
|
|
|
- tx->sta->tx_fragments++;
|
|
|
- tx->sta->tx_bytes += tx->skb->len;
|
|
|
- if (tx->extra_frag) {
|
|
|
- int i;
|
|
|
- tx->sta->tx_fragments += tx->num_extra_frag;
|
|
|
- for (i = 0; i < tx->num_extra_frag; i++) {
|
|
|
- tx->sta->tx_bytes +=
|
|
|
- tx->extra_frag[i]->len;
|
|
|
- }
|
|
|
- }
|
|
|
+
|
|
|
+ return TX_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static ieee80211_tx_result
|
|
|
+ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
|
|
+{
|
|
|
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
|
|
|
+ size_t hdrlen, per_fragm, num_fragm, payload_len, left;
|
|
|
+ struct sk_buff **frags, *first, *frag;
|
|
|
+ int i;
|
|
|
+ u16 seq;
|
|
|
+ u8 *pos;
|
|
|
+ int frag_threshold = tx->local->fragmentation_threshold;
|
|
|
+
|
|
|
+ if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
|
|
|
+ return TX_CONTINUE;
|
|
|
+
|
|
|
+ first = tx->skb;
|
|
|
+
|
|
|
+ hdrlen = ieee80211_get_hdrlen(tx->fc);
|
|
|
+ payload_len = first->len - hdrlen;
|
|
|
+ per_fragm = frag_threshold - hdrlen - FCS_LEN;
|
|
|
+ num_fragm = DIV_ROUND_UP(payload_len, per_fragm);
|
|
|
+
|
|
|
+ frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC);
|
|
|
+ if (!frags)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
|
|
|
+ seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
|
|
|
+ pos = first->data + hdrlen + per_fragm;
|
|
|
+ left = payload_len - per_fragm;
|
|
|
+ for (i = 0; i < num_fragm - 1; i++) {
|
|
|
+ struct ieee80211_hdr *fhdr;
|
|
|
+ size_t copylen;
|
|
|
+
|
|
|
+ if (left <= 0)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ /* reserve enough extra head and tail room for possible
|
|
|
+ * encryption */
|
|
|
+ frag = frags[i] =
|
|
|
+ dev_alloc_skb(tx->local->tx_headroom +
|
|
|
+ frag_threshold +
|
|
|
+ IEEE80211_ENCRYPT_HEADROOM +
|
|
|
+ IEEE80211_ENCRYPT_TAILROOM);
|
|
|
+ if (!frag)
|
|
|
+ goto fail;
|
|
|
+ /* Make sure that all fragments use the same priority so
|
|
|
+ * that they end up using the same TX queue */
|
|
|
+ frag->priority = first->priority;
|
|
|
+ skb_reserve(frag, tx->local->tx_headroom +
|
|
|
+ IEEE80211_ENCRYPT_HEADROOM);
|
|
|
+ fhdr = (struct ieee80211_hdr *) skb_put(frag, 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));
|
|
|
+ copylen = left > per_fragm ? per_fragm : left;
|
|
|
+ memcpy(skb_put(frag, copylen), pos, copylen);
|
|
|
+
|
|
|
+ pos += copylen;
|
|
|
+ left -= copylen;
|
|
|
}
|
|
|
+ skb_trim(first, hdrlen + per_fragm);
|
|
|
+
|
|
|
+ tx->num_extra_frag = num_fragm - 1;
|
|
|
+ tx->extra_frag = frags;
|
|
|
|
|
|
return TX_CONTINUE;
|
|
|
+
|
|
|
+ fail:
|
|
|
+ printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
|
|
|
+ if (frags) {
|
|
|
+ for (i = 0; i < num_fragm - 1; i++)
|
|
|
+ if (frags[i])
|
|
|
+ dev_kfree_skb(frags[i]);
|
|
|
+ kfree(frags);
|
|
|
+ }
|
|
|
+ I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
|
|
|
+ return TX_DROP;
|
|
|
}
|
|
|
|
|
|
static ieee80211_tx_result
|
|
|
-ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx)
|
|
|
+ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
|
|
|
+{
|
|
|
+ if (!tx->key)
|
|
|
+ return TX_CONTINUE;
|
|
|
+
|
|
|
+ switch (tx->key->conf.alg) {
|
|
|
+ case ALG_WEP:
|
|
|
+ return ieee80211_crypto_wep_encrypt(tx);
|
|
|
+ case ALG_TKIP:
|
|
|
+ return ieee80211_crypto_tkip_encrypt(tx);
|
|
|
+ case ALG_CCMP:
|
|
|
+ return ieee80211_crypto_ccmp_encrypt(tx);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* not reached */
|
|
|
+ WARN_ON(1);
|
|
|
+ return TX_DROP;
|
|
|
+}
|
|
|
+
|
|
|
+static ieee80211_tx_result
|
|
|
+ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
|
|
|
{
|
|
|
struct ieee80211_local *local = tx->local;
|
|
|
struct sk_buff *skb = tx->skb;
|
|
@@ -822,6 +810,20 @@ ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx)
|
|
|
tx->sta->channel_use_raw += load;
|
|
|
tx->sdata->channel_use_raw += load;
|
|
|
|
|
|
+ if (tx->sta) {
|
|
|
+ tx->sta->tx_packets++;
|
|
|
+ tx->sta->tx_fragments++;
|
|
|
+ tx->sta->tx_bytes += tx->skb->len;
|
|
|
+ if (tx->extra_frag) {
|
|
|
+ int i;
|
|
|
+ tx->sta->tx_fragments += tx->num_extra_frag;
|
|
|
+ for (i = 0; i < tx->num_extra_frag; i++) {
|
|
|
+ tx->sta->tx_bytes +=
|
|
|
+ tx->extra_frag[i]->len;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return TX_CONTINUE;
|
|
|
}
|
|
|
|
|
@@ -834,11 +836,11 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] =
|
|
|
ieee80211_tx_h_ps_buf,
|
|
|
ieee80211_tx_h_select_key,
|
|
|
ieee80211_tx_h_michael_mic_add,
|
|
|
- ieee80211_tx_h_fragment,
|
|
|
- ieee80211_tx_h_encrypt,
|
|
|
ieee80211_tx_h_rate_ctrl,
|
|
|
ieee80211_tx_h_misc,
|
|
|
- ieee80211_tx_h_load_stats,
|
|
|
+ ieee80211_tx_h_fragment,
|
|
|
+ ieee80211_tx_h_encrypt,
|
|
|
+ ieee80211_tx_h_stats,
|
|
|
NULL
|
|
|
};
|
|
|
|