Merge branch 'exynos-drm' of git://git.infradead.org/users/kmpark/linux-samsung into...
[pandora-kernel.git] / net / mac80211 / util.c
index ddeb1b9..eca0fad 100644 (file)
 
 #include <net/mac80211.h>
 #include <linux/netdevice.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 #include <linux/bitmap.h>
-#include <linux/crc32.h>
 #include <net/net_namespace.h>
 #include <net/cfg80211.h>
 #include <net/rtnetlink.h>
@@ -368,14 +368,14 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 }
 
-int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
-                                 struct sk_buff_head *skbs,
-                                 void (*fn)(void *data), void *data)
+void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
+                                  struct sk_buff_head *skbs,
+                                  void (*fn)(void *data), void *data)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct sk_buff *skb;
        unsigned long flags;
-       int queue, ret = 0, i;
+       int queue, i;
 
        spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
        for (i = 0; i < hw->queues; i++)
@@ -390,7 +390,6 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
                        continue;
                }
 
-               ret++;
                queue = skb_get_queue_mapping(skb);
                __skb_queue_tail(&local->pending[queue], skb);
        }
@@ -402,14 +401,12 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
                __ieee80211_wake_queue(hw, i,
                        IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
-       return ret;
 }
 
-int ieee80211_add_pending_skbs(struct ieee80211_local *local,
-                              struct sk_buff_head *skbs)
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                               struct sk_buff_head *skbs)
 {
-       return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
+       ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
 }
 
 void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
@@ -573,172 +570,6 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
        ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
 }
 
-u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
-                              struct ieee802_11_elems *elems,
-                              u64 filter, u32 crc)
-{
-       size_t left = len;
-       u8 *pos = start;
-       bool calc_crc = filter != 0;
-
-       memset(elems, 0, sizeof(*elems));
-       elems->ie_start = start;
-       elems->total_len = len;
-
-       while (left >= 2) {
-               u8 id, elen;
-
-               id = *pos++;
-               elen = *pos++;
-               left -= 2;
-
-               if (elen > left)
-                       break;
-
-               if (calc_crc && id < 64 && (filter & (1ULL << id)))
-                       crc = crc32_be(crc, pos - 2, elen + 2);
-
-               switch (id) {
-               case WLAN_EID_SSID:
-                       elems->ssid = pos;
-                       elems->ssid_len = elen;
-                       break;
-               case WLAN_EID_SUPP_RATES:
-                       elems->supp_rates = pos;
-                       elems->supp_rates_len = elen;
-                       break;
-               case WLAN_EID_FH_PARAMS:
-                       elems->fh_params = pos;
-                       elems->fh_params_len = elen;
-                       break;
-               case WLAN_EID_DS_PARAMS:
-                       elems->ds_params = pos;
-                       elems->ds_params_len = elen;
-                       break;
-               case WLAN_EID_CF_PARAMS:
-                       elems->cf_params = pos;
-                       elems->cf_params_len = elen;
-                       break;
-               case WLAN_EID_TIM:
-                       if (elen >= sizeof(struct ieee80211_tim_ie)) {
-                               elems->tim = (void *)pos;
-                               elems->tim_len = elen;
-                       }
-                       break;
-               case WLAN_EID_IBSS_PARAMS:
-                       elems->ibss_params = pos;
-                       elems->ibss_params_len = elen;
-                       break;
-               case WLAN_EID_CHALLENGE:
-                       elems->challenge = pos;
-                       elems->challenge_len = elen;
-                       break;
-               case WLAN_EID_VENDOR_SPECIFIC:
-                       if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
-                           pos[2] == 0xf2) {
-                               /* Microsoft OUI (00:50:F2) */
-
-                               if (calc_crc)
-                                       crc = crc32_be(crc, pos - 2, elen + 2);
-
-                               if (pos[3] == 1) {
-                                       /* OUI Type 1 - WPA IE */
-                                       elems->wpa = pos;
-                                       elems->wpa_len = elen;
-                               } else if (elen >= 5 && pos[3] == 2) {
-                                       /* OUI Type 2 - WMM IE */
-                                       if (pos[4] == 0) {
-                                               elems->wmm_info = pos;
-                                               elems->wmm_info_len = elen;
-                                       } else if (pos[4] == 1) {
-                                               elems->wmm_param = pos;
-                                               elems->wmm_param_len = elen;
-                                       }
-                               }
-                       }
-                       break;
-               case WLAN_EID_RSN:
-                       elems->rsn = pos;
-                       elems->rsn_len = elen;
-                       break;
-               case WLAN_EID_ERP_INFO:
-                       elems->erp_info = pos;
-                       elems->erp_info_len = elen;
-                       break;
-               case WLAN_EID_EXT_SUPP_RATES:
-                       elems->ext_supp_rates = pos;
-                       elems->ext_supp_rates_len = elen;
-                       break;
-               case WLAN_EID_HT_CAPABILITY:
-                       if (elen >= sizeof(struct ieee80211_ht_cap))
-                               elems->ht_cap_elem = (void *)pos;
-                       break;
-               case WLAN_EID_HT_INFORMATION:
-                       if (elen >= sizeof(struct ieee80211_ht_info))
-                               elems->ht_info_elem = (void *)pos;
-                       break;
-               case WLAN_EID_MESH_ID:
-                       elems->mesh_id = pos;
-                       elems->mesh_id_len = elen;
-                       break;
-               case WLAN_EID_MESH_CONFIG:
-                       if (elen >= sizeof(struct ieee80211_meshconf_ie))
-                               elems->mesh_config = (void *)pos;
-                       break;
-               case WLAN_EID_PEER_LINK:
-                       elems->peer_link = pos;
-                       elems->peer_link_len = elen;
-                       break;
-               case WLAN_EID_PREQ:
-                       elems->preq = pos;
-                       elems->preq_len = elen;
-                       break;
-               case WLAN_EID_PREP:
-                       elems->prep = pos;
-                       elems->prep_len = elen;
-                       break;
-               case WLAN_EID_PERR:
-                       elems->perr = pos;
-                       elems->perr_len = elen;
-                       break;
-               case WLAN_EID_RANN:
-                       if (elen >= sizeof(struct ieee80211_rann_ie))
-                               elems->rann = (void *)pos;
-                       break;
-               case WLAN_EID_CHANNEL_SWITCH:
-                       elems->ch_switch_elem = pos;
-                       elems->ch_switch_elem_len = elen;
-                       break;
-               case WLAN_EID_QUIET:
-                       if (!elems->quiet_elem) {
-                               elems->quiet_elem = pos;
-                               elems->quiet_elem_len = elen;
-                       }
-                       elems->num_of_quiet_elem++;
-                       break;
-               case WLAN_EID_COUNTRY:
-                       elems->country_elem = pos;
-                       elems->country_elem_len = elen;
-                       break;
-               case WLAN_EID_PWR_CONSTRAINT:
-                       elems->pwr_constr_elem = pos;
-                       elems->pwr_constr_elem_len = elen;
-                       break;
-               case WLAN_EID_TIMEOUT_INTERVAL:
-                       elems->timeout_int = pos;
-                       elems->timeout_int_len = elen;
-                       break;
-               default:
-                       break;
-               }
-
-               left -= elen;
-               pos += elen;
-       }
-
-       return crc;
-}
-
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
@@ -799,8 +630,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 
                qparam.uapsd = false;
 
-               local->tx_conf[queue] = qparam;
-               drv_conf_tx(local, queue, &qparam);
+               sdata->tx_conf[queue] = qparam;
+               drv_conf_tx(local, sdata, queue, &qparam);
        }
 
        /* after reinitialize QoS TX queues setting to default,
@@ -874,11 +705,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
                            sizeof(*mgmt) + 6 + extra_len);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
-                      "frame\n", sdata->name);
+       if (!skb)
                return;
-       }
+
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
@@ -1031,11 +860,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
 
        /* FIXME: come up with a proper value */
        buf = kmalloc(200 + ie_len, GFP_KERNEL);
-       if (!buf) {
-               printk(KERN_DEBUG "%s: failed to allocate temporary IE "
-                      "buffer\n", sdata->name);
+       if (!buf)
                return NULL;
-       }
 
        /*
         * Do not send DS Channel parameter for directed probe requests
@@ -1055,6 +881,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
        skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
                                     ssid, ssid_len,
                                     buf, buf_len);
+       if (!skb)
+               goto out;
 
        if (dst) {
                mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1063,6 +891,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
        }
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+ out:
        kfree(buf);
 
        return skb;
@@ -1071,14 +901,18 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              const u8 *ssid, size_t ssid_len,
                              const u8 *ie, size_t ie_len,
-                             u32 ratemask, bool directed)
+                             u32 ratemask, bool directed, bool no_cck)
 {
        struct sk_buff *skb;
 
        skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len,
                                        ie, ie_len, directed);
-       if (skb)
+       if (skb) {
+               if (no_cck)
+                       IEEE80211_SKB_CB(skb)->flags |=
+                               IEEE80211_TX_CTL_NO_CCK_RATE;
                ieee80211_tx_skb(sdata, skb);
+       }
 }
 
 u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
@@ -1205,14 +1039,22 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
+                       memset(&sta->sta.drv_priv, 0, hw->sta_data_size);
                        WARN_ON(drv_sta_add(local, sdata, &sta->sta));
                }
        }
        mutex_unlock(&local->sta_mtx);
 
        /* reconfigure tx conf */
-       for (i = 0; i < hw->queues; i++)
-               drv_conf_tx(local, i, &local->tx_conf[i]);
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                   !ieee80211_sdata_running(sdata))
+                       continue;
+
+               for (i = 0; i < hw->queues; i++)
+                       drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]);
+       }
 
        /* reconfigure hardware */
        ieee80211_hw_config(local, ~0);
@@ -1248,6 +1090,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        changed |= BSS_CHANGED_IBSS;
                        /* fall through */
                case NL80211_IFTYPE_AP:
+                       changed |= BSS_CHANGED_SSID;
+                       /* fall through */
                case NL80211_IFTYPE_MESH_POINT:
                        changed |= BSS_CHANGED_BEACON |
                                   BSS_CHANGED_BEACON_ENABLED;
@@ -1283,7 +1127,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
                list_for_each_entry(sta, &local->sta_list, list) {
                        ieee80211_sta_tear_down_BA_sessions(sta, true);
-                       clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
+                       clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
                }
 
                mutex_unlock(&local->sta_mtx);
@@ -1522,3 +1366,60 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
        _ieee80211_enable_rssi_reports(sdata, 0, 0);
 }
 EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
+
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       int rate;
+       u8 i, rates, *pos;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       rates = sband->n_bitrates;
+       if (rates > 8)
+               rates = 8;
+
+       if (skb_tailroom(skb) < rates + 2)
+               return -ENOMEM;
+
+       pos = skb_put(skb, rates + 2);
+       *pos++ = WLAN_EID_SUPP_RATES;
+       *pos++ = rates;
+       for (i = 0; i < rates; i++) {
+               rate = sband->bitrates[i].bitrate;
+               *pos++ = (u8) (rate / 5);
+       }
+
+       return 0;
+}
+
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       int rate;
+       u8 i, exrates, *pos;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       exrates = sband->n_bitrates;
+       if (exrates > 8)
+               exrates -= 8;
+       else
+               exrates = 0;
+
+       if (skb_tailroom(skb) < exrates + 2)
+               return -ENOMEM;
+
+       if (exrates) {
+               pos = skb_put(skb, exrates + 2);
+               *pos++ = WLAN_EID_EXT_SUPP_RATES;
+               *pos++ = exrates;
+               for (i = 8; i < sband->n_bitrates; i++) {
+                       rate = sband->bitrates[i].bitrate;
+                       *pos++ = (u8) (rate / 5);
+               }
+       }
+       return 0;
+}