mac80211: Add capability to enable/disable beaconing
[safe/jmp/linux-2.6] / net / mac80211 / mlme.c
index f0d4249..ec40047 100644 (file)
@@ -73,7 +73,7 @@ static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie)
 
 static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
                                      struct ieee80211_supported_band *sband,
-                                     u64 *rates)
+                                     u32 *rates)
 {
        int i, j, count;
        *rates = 0;
@@ -93,14 +93,14 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
 }
 
 /* also used by mesh code */
-u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
                            struct ieee802_11_elems *elems,
                            enum ieee80211_band band)
 {
        struct ieee80211_supported_band *sband;
        struct ieee80211_rate *bitrates;
        size_t num_rates;
-       u64 supp_rates;
+       u32 supp_rates;
        int i, j;
        sband = local->hw.wiphy->bands[band];
 
@@ -131,6 +131,12 @@ u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
 
 /* frame sending functions */
 
+static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len)
+{
+       if (ies)
+               memcpy(skb_put(skb, ies_len), ies, ies_len);
+}
+
 /* also used by scanning code */
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              u8 *ssid, size_t ssid_len)
@@ -142,7 +148,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
        u8 *pos, *supp_rates, *esupp_rates = NULL;
        int i;
 
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200);
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
+                           sdata->u.sta.ie_probereq_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
                       "request\n", sdata->dev->name);
@@ -189,6 +196,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                *pos = rate->bitrate / 5;
        }
 
+       add_extra_ies(skb, sdata->u.sta.ie_probereq,
+                     sdata->u.sta.ie_probereq_len);
+
        ieee80211_tx_skb(sdata, skb, 0);
 }
 
@@ -202,7 +212,8 @@ static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_mgmt *mgmt;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-                           sizeof(*mgmt) + 6 + extra_len);
+                           sizeof(*mgmt) + 6 + extra_len +
+                           sdata->u.sta.ie_auth_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
                       "frame\n", sdata->dev->name);
@@ -225,6 +236,7 @@ static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        mgmt->u.auth.status_code = cpu_to_le16(0);
        if (extra)
                memcpy(skb_put(skb, extra_len), extra, extra_len);
+       add_extra_ies(skb, sdata->u.sta.ie_auth, sdata->u.sta.ie_auth_len);
 
        ieee80211_tx_skb(sdata, skb, encrypt);
 }
@@ -235,17 +247,26 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos, *ies, *ht_ie;
+       u8 *pos, *ies, *ht_ie, *e_ies;
        int i, len, count, rates_len, supp_rates_len;
        u16 capab;
        struct ieee80211_bss *bss;
        int wmm = 0;
        struct ieee80211_supported_band *sband;
-       u64 rates = 0;
+       u32 rates = 0;
+       size_t e_ies_len;
+
+       if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
+               e_ies = sdata->u.sta.ie_reassocreq;
+               e_ies_len = sdata->u.sta.ie_reassocreq_len;
+       } else {
+               e_ies = sdata->u.sta.ie_assocreq;
+               e_ies_len = sdata->u.sta.ie_assocreq_len;
+       }
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
                            sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
-                           ifsta->ssid_len);
+                           ifsta->ssid_len + e_ies_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
                       "frame\n", sdata->dev->name);
@@ -436,6 +457,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
                memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
        }
 
+       add_extra_ies(skb, e_ies, e_ies_len);
+
        kfree(ifsta->assocreq_ies);
        ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
        ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL);
@@ -453,8 +476,19 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
+       u8 *ies;
+       size_t ies_len;
 
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
+       if (stype == IEEE80211_STYPE_DEAUTH) {
+               ies = sdata->u.sta.ie_deauth;
+               ies_len = sdata->u.sta.ie_deauth_len;
+       } else {
+               ies = sdata->u.sta.ie_disassoc;
+               ies_len = sdata->u.sta.ie_disassoc_len;
+       }
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) +
+                           ies_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for "
                       "deauth/disassoc frame\n", sdata->dev->name);
@@ -472,6 +506,8 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
        /* u.deauth.reason_code == u.disassoc.reason_code */
        mgmt->u.deauth.reason_code = cpu_to_le16(reason);
 
+       add_extra_ies(skb, ies, ies_len);
+
        ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED);
 }
 
@@ -1246,7 +1282,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
        struct sta_info *sta;
-       u64 rates, basic_rates;
+       u32 rates, basic_rates;
        u16 capab_info, status_code, aid;
        struct ieee802_11_elems elems;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
@@ -1281,9 +1317,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 
        if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
-           elems.assoc_comeback && elems.assoc_comeback_len == 4) {
+           elems.timeout_int && elems.timeout_int_len == 5 &&
+           elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
                u32 tu, ms;
-               tu = get_unaligned_le32(elems.assoc_comeback);
+               tu = get_unaligned_le32(elems.timeout_int + 1);
                ms = tu * 1024 / 1000;
                printk(KERN_DEBUG "%s: AP rejected association temporarily; "
                       "comeback duration %u TU (%u ms)\n",
@@ -1473,7 +1510,8 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_supported_band *sband;
        union iwreq_data wrqu;
 
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
+                           sdata->u.sta.ie_proberesp_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
                       "response\n", sdata->dev->name);
@@ -1556,9 +1594,13 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                memcpy(pos, &bss->supp_rates[8], rates);
        }
 
+       add_extra_ies(skb, sdata->u.sta.ie_proberesp,
+                     sdata->u.sta.ie_proberesp_len);
+
        ifsta->probe_resp = skb;
 
-       ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+       ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
+                                  IEEE80211_IFCC_BEACON_ENABLED);
 
 
        rates = 0;
@@ -1598,7 +1640,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        struct sta_info *sta;
        struct ieee80211_channel *channel;
        u64 beacon_timestamp, rx_timestamp;
-       u64 supp_rates = 0;
+       u32 supp_rates = 0;
        enum ieee80211_band band = rx_status->band;
 
        if (elems->ds_params && elems->ds_params_len == 1)
@@ -1619,7 +1661,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
                sta = sta_info_get(local, mgmt->sa);
                if (sta) {
-                       u64 prev_rates;
+                       u32 prev_rates;
 
                        prev_rates = sta->sta.supp_rates[band];
                        /* make sure mandatory rates are always added */
@@ -2485,7 +2527,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
  * must be callable in atomic context.
  */
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
-                                       u8 *bssid,u8 *addr, u64 supp_rates)
+                                       u8 *bssid,u8 *addr, u32 supp_rates)
 {
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;