cfg80211: remove enum ieee80211_band
[cascardo/linux.git] / net / wireless / util.c
index f75f601..f360398 100644 (file)
@@ -47,7 +47,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
        if (WARN_ON(!sband))
                return 1;
 
-       if (sband->band == IEEE80211_BAND_2GHZ) {
+       if (sband->band == NL80211_BAND_2GHZ) {
                if (scan_width == NL80211_BSS_CHAN_WIDTH_5 ||
                    scan_width == NL80211_BSS_CHAN_WIDTH_10)
                        mandatory_flag = IEEE80211_RATE_MANDATORY_G;
@@ -65,26 +65,26 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
 }
 EXPORT_SYMBOL(ieee80211_mandatory_rates);
 
-int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band)
+int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
 {
        /* see 802.11 17.3.8.3.2 and Annex J
         * there are overlapping channel numbers in 5GHz and 2GHz bands */
        if (chan <= 0)
                return 0; /* not supported */
        switch (band) {
-       case IEEE80211_BAND_2GHZ:
+       case NL80211_BAND_2GHZ:
                if (chan == 14)
                        return 2484;
                else if (chan < 14)
                        return 2407 + chan * 5;
                break;
-       case IEEE80211_BAND_5GHZ:
+       case NL80211_BAND_5GHZ:
                if (chan >= 182 && chan <= 196)
                        return 4000 + chan * 5;
                else
                        return 5000 + chan * 5;
                break;
-       case IEEE80211_BAND_60GHZ:
+       case NL80211_BAND_60GHZ:
                if (chan < 5)
                        return 56160 + chan * 2160;
                break;
@@ -116,11 +116,11 @@ EXPORT_SYMBOL(ieee80211_frequency_to_channel);
 struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
                                                  int freq)
 {
-       enum ieee80211_band band;
+       enum nl80211_band band;
        struct ieee80211_supported_band *sband;
        int i;
 
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+       for (band = 0; band < NUM_NL80211_BANDS; band++) {
                sband = wiphy->bands[band];
 
                if (!sband)
@@ -137,12 +137,12 @@ struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
 EXPORT_SYMBOL(__ieee80211_get_channel);
 
 static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
-                                    enum ieee80211_band band)
+                                    enum nl80211_band band)
 {
        int i, want;
 
        switch (band) {
-       case IEEE80211_BAND_5GHZ:
+       case NL80211_BAND_5GHZ:
                want = 3;
                for (i = 0; i < sband->n_bitrates; i++) {
                        if (sband->bitrates[i].bitrate == 60 ||
@@ -155,7 +155,7 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
                }
                WARN_ON(want);
                break;
-       case IEEE80211_BAND_2GHZ:
+       case NL80211_BAND_2GHZ:
                want = 7;
                for (i = 0; i < sband->n_bitrates; i++) {
                        if (sband->bitrates[i].bitrate == 10) {
@@ -185,12 +185,12 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
                }
                WARN_ON(want != 0 && want != 3 && want != 6);
                break;
-       case IEEE80211_BAND_60GHZ:
+       case NL80211_BAND_60GHZ:
                /* check for mandatory HT MCS 1..4 */
                WARN_ON(!sband->ht_cap.ht_supported);
                WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e);
                break;
-       case IEEE80211_NUM_BANDS:
+       case NUM_NL80211_BANDS:
                WARN_ON(1);
                break;
        }
@@ -198,9 +198,9 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
 
 void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
 {
-       enum ieee80211_band band;
+       enum nl80211_band band;
 
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+       for (band = 0; band < NUM_NL80211_BANDS; band++)
                if (wiphy->bands[band])
                        set_mandatory_flags_band(wiphy->bands[band], band);
 }
@@ -636,7 +636,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
        /* Update skb pointers to various headers since this modified frame
         * is going to go through Linux networking code that may potentially
         * need things like pointer to IP header. */
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb_set_network_header(skb, nh_pos);
        skb_set_transport_header(skb, h_pos);
 
@@ -644,73 +644,147 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
 }
 EXPORT_SYMBOL(ieee80211_data_from_8023);
 
+static void
+__frame_add_frag(struct sk_buff *skb, struct page *page,
+                void *ptr, int len, int size)
+{
+       struct skb_shared_info *sh = skb_shinfo(skb);
+       int page_offset;
+
+       atomic_inc(&page->_count);
+       page_offset = ptr - page_address(page);
+       skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size);
+}
+
+static void
+__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
+                           int offset, int len)
+{
+       struct skb_shared_info *sh = skb_shinfo(skb);
+       const skb_frag_t *frag = &sh->frags[-1];
+       struct page *frag_page;
+       void *frag_ptr;
+       int frag_len, frag_size;
+       int head_size = skb->len - skb->data_len;
+       int cur_len;
+
+       frag_page = virt_to_head_page(skb->head);
+       frag_ptr = skb->data;
+       frag_size = head_size;
+
+       while (offset >= frag_size) {
+               offset -= frag_size;
+               frag++;
+               frag_page = skb_frag_page(frag);
+               frag_ptr = skb_frag_address(frag);
+               frag_size = skb_frag_size(frag);
+       }
+
+       frag_ptr += offset;
+       frag_len = frag_size - offset;
+
+       cur_len = min(len, frag_len);
+
+       __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
+       len -= cur_len;
+
+       while (len > 0) {
+               frag++;
+               frag_len = skb_frag_size(frag);
+               cur_len = min(len, frag_len);
+               __frame_add_frag(frame, skb_frag_page(frag),
+                                skb_frag_address(frag), cur_len, frag_len);
+               len -= cur_len;
+       }
+}
+
+static struct sk_buff *
+__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
+                      int offset, int len, bool reuse_frag)
+{
+       struct sk_buff *frame;
+       int cur_len = len;
+
+       if (skb->len - offset < len)
+               return NULL;
+
+       /*
+        * When reusing framents, copy some data to the head to simplify
+        * ethernet header handling and speed up protocol header processing
+        * in the stack later.
+        */
+       if (reuse_frag)
+               cur_len = min_t(int, len, 32);
+
+       /*
+        * Allocate and reserve two bytes more for payload
+        * alignment since sizeof(struct ethhdr) is 14.
+        */
+       frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
+
+       skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
+       skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
+
+       len -= cur_len;
+       if (!len)
+               return frame;
+
+       offset += cur_len;
+       __ieee80211_amsdu_copy_frag(skb, frame, offset, len);
+
+       return frame;
+}
 
 void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
                              const u8 *addr, enum nl80211_iftype iftype,
                              const unsigned int extra_headroom,
                              bool has_80211_header)
 {
+       unsigned int hlen = ALIGN(extra_headroom, 4);
        struct sk_buff *frame = NULL;
        u16 ethertype;
        u8 *payload;
-       const struct ethhdr *eth;
-       int remaining, err;
-       u8 dst[ETH_ALEN], src[ETH_ALEN];
-
-       if (skb_linearize(skb))
-               goto out;
+       int offset = 0, remaining, err;
+       struct ethhdr eth;
+       bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
+       bool reuse_skb = false;
+       bool last = false;
 
        if (has_80211_header) {
-               err = ieee80211_data_to_8023(skb, addr, iftype);
+               err = __ieee80211_data_to_8023(skb, &eth, addr, iftype);
                if (err)
                        goto out;
-
-               /* skip the wrapping header */
-               eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
-               if (!eth)
-                       goto out;
-       } else {
-               eth = (struct ethhdr *) skb->data;
        }
 
-       while (skb != frame) {
+       while (!last) {
+               unsigned int subframe_len;
+               int len;
                u8 padding;
-               __be16 len = eth->h_proto;
-               unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
-
-               remaining = skb->len;
-               memcpy(dst, eth->h_dest, ETH_ALEN);
-               memcpy(src, eth->h_source, ETH_ALEN);
 
+               skb_copy_bits(skb, offset, &eth, sizeof(eth));
+               len = ntohs(eth.h_proto);
+               subframe_len = sizeof(struct ethhdr) + len;
                padding = (4 - subframe_len) & 0x3;
+
                /* the last MSDU has no padding */
+               remaining = skb->len - offset;
                if (subframe_len > remaining)
                        goto purge;
 
-               skb_pull(skb, sizeof(struct ethhdr));
+               offset += sizeof(struct ethhdr);
                /* reuse skb for the last subframe */
-               if (remaining <= subframe_len + padding)
+               last = remaining <= subframe_len + padding;
+               if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
+                       skb_pull(skb, offset);
                        frame = skb;
-               else {
-                       unsigned int hlen = ALIGN(extra_headroom, 4);
-                       /*
-                        * Allocate and reserve two bytes more for payload
-                        * alignment since sizeof(struct ethhdr) is 14.
-                        */
-                       frame = dev_alloc_skb(hlen + subframe_len + 2);
+                       reuse_skb = true;
+               } else {
+                       frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
+                                                      reuse_frag);
                        if (!frame)
                                goto purge;
 
-                       skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
-                       memcpy(skb_put(frame, ntohs(len)), skb->data,
-                               ntohs(len));
-
-                       eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
-                                                       padding);
-                       if (!eth) {
-                               dev_kfree_skb(frame);
-                               goto purge;
-                       }
+                       offset += len + padding;
                }
 
                skb_reset_network_header(frame);
@@ -719,24 +793,20 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 
                payload = frame->data;
                ethertype = (payload[6] << 8) | payload[7];
-
                if (likely((ether_addr_equal(payload, rfc1042_header) &&
                            ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
                           ether_addr_equal(payload, bridge_tunnel_header))) {
-                       /* remove RFC1042 or Bridge-Tunnel
-                        * encapsulation and replace EtherType */
-                       skb_pull(frame, 6);
-                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-               } else {
-                       memcpy(skb_push(frame, sizeof(__be16)), &len,
-                               sizeof(__be16));
-                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+                       eth.h_proto = htons(ethertype);
+                       skb_pull(frame, ETH_ALEN + 2);
                }
+
+               memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
                __skb_queue_tail(list, frame);
        }
 
+       if (!reuse_skb)
+               dev_kfree_skb(skb);
+
        return;
 
  purge:
@@ -1329,22 +1399,22 @@ size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
 EXPORT_SYMBOL(ieee80211_ie_split_ric);
 
 bool ieee80211_operating_class_to_band(u8 operating_class,
-                                      enum ieee80211_band *band)
+                                      enum nl80211_band *band)
 {
        switch (operating_class) {
        case 112:
        case 115 ... 127:
        case 128 ... 130:
-               *band = IEEE80211_BAND_5GHZ;
+               *band = NL80211_BAND_5GHZ;
                return true;
        case 81:
        case 82:
        case 83:
        case 84:
-               *band = IEEE80211_BAND_2GHZ;
+               *band = NL80211_BAND_2GHZ;
                return true;
        case 180:
-               *band = IEEE80211_BAND_60GHZ;
+               *band = NL80211_BAND_60GHZ;
                return true;
        }
 
@@ -1656,10 +1726,10 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
 
 unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)
 {
-       enum ieee80211_band band;
+       enum nl80211_band band;
        unsigned int n_channels = 0;
 
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+       for (band = 0; band < NUM_NL80211_BANDS; band++)
                if (wiphy->bands[band])
                        n_channels += wiphy->bands[band]->n_channels;