mac80211: don't report selected IBSS when not found
[pandora-kernel.git] / net / mac80211 / mlme.c
index a5e5c31..b404537 100644 (file)
@@ -44,7 +44,7 @@
 #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
 #define IEEE80211_SCAN_INTERVAL (2 * HZ)
 #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
-#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ)
+#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
 
 #define IEEE80211_PROBE_DELAY (HZ / 33)
 #define IEEE80211_CHANNEL_TIME (HZ / 33)
@@ -547,15 +547,14 @@ static void ieee80211_set_associated(struct net_device *dev,
                        sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
                }
 
-               netif_carrier_on(dev);
                ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
                memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
                memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
                ieee80211_sta_send_associnfo(dev, ifsta);
        } else {
+               netif_carrier_off(dev);
                ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid);
                ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
-               netif_carrier_off(dev);
                ieee80211_reset_erp_info(dev);
 
                sdata->bss_conf.assoc_ht = 0;
@@ -569,6 +568,10 @@ static void ieee80211_set_associated(struct net_device *dev,
 
        sdata->bss_conf.assoc = assoc;
        ieee80211_bss_info_change_notify(sdata, changed);
+
+       if (assoc)
+               netif_carrier_on(dev);
+
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 }
@@ -665,6 +668,26 @@ static void ieee80211_authenticate(struct net_device *dev,
        mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
 }
 
+static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
+                                     struct ieee80211_supported_band *sband,
+                                     u64 *rates)
+{
+       int i, j, count;
+       *rates = 0;
+       count = 0;
+       for (i = 0; i < bss->supp_rates_len; i++) {
+               int rate = (bss->supp_rates[i] & 0x7F) * 5;
+
+               for (j = 0; j < sband->n_bitrates; j++)
+                       if (sband->bitrates[j].bitrate == rate) {
+                               *rates |= BIT(j);
+                               count++;
+                               break;
+                       }
+       }
+
+       return count;
+}
 
 static void ieee80211_send_assoc(struct net_device *dev,
                                 struct ieee80211_if_sta *ifsta)
@@ -673,11 +696,12 @@ static void ieee80211_send_assoc(struct net_device *dev,
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        u8 *pos, *ies;
-       int i, len;
+       int i, len, count, rates_len, supp_rates_len;
        u16 capab;
        struct ieee80211_sta_bss *bss;
        int wmm = 0;
        struct ieee80211_supported_band *sband;
+       u64 rates = 0;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
                            sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
@@ -709,7 +733,17 @@ static void ieee80211_send_assoc(struct net_device *dev,
                if (bss->wmm_ie) {
                        wmm = 1;
                }
+
+               /* get all rates supported by the device and the AP as
+                * some APs don't like getting a superset of their rates
+                * in the association request (e.g. D-Link DAP 1353 in
+                * b-only mode) */
+               rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+
                ieee80211_rx_bss_put(dev, bss);
+       } else {
+               rates = ~0;
+               rates_len = sband->n_bitrates;
        }
 
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
@@ -740,24 +774,36 @@ static void ieee80211_send_assoc(struct net_device *dev,
        *pos++ = ifsta->ssid_len;
        memcpy(pos, ifsta->ssid, ifsta->ssid_len);
 
+       /* add all rates which were marked to be used above */
+       supp_rates_len = rates_len;
+       if (supp_rates_len > 8)
+               supp_rates_len = 8;
+
        len = sband->n_bitrates;
-       if (len > 8)
-               len = 8;
-       pos = skb_put(skb, len + 2);
+       pos = skb_put(skb, supp_rates_len + 2);
        *pos++ = WLAN_EID_SUPP_RATES;
-       *pos++ = len;
-       for (i = 0; i < len; i++) {
-               int rate = sband->bitrates[i].bitrate;
-               *pos++ = (u8) (rate / 5);
-       }
+       *pos++ = supp_rates_len;
 
-       if (sband->n_bitrates > len) {
-               pos = skb_put(skb, sband->n_bitrates - len + 2);
-               *pos++ = WLAN_EID_EXT_SUPP_RATES;
-               *pos++ = sband->n_bitrates - len;
-               for (i = len; i < sband->n_bitrates; i++) {
+       count = 0;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if (BIT(i) & rates) {
                        int rate = sband->bitrates[i].bitrate;
                        *pos++ = (u8) (rate / 5);
+                       if (++count == 8)
+                               break;
+               }
+       }
+
+       if (count == 8) {
+               pos = skb_put(skb, rates_len - count + 2);
+               *pos++ = WLAN_EID_EXT_SUPP_RATES;
+               *pos++ = rates_len - count;
+
+               for (i++; i < sband->n_bitrates; i++) {
+                       if (BIT(i) & rates) {
+                               int rate = sband->bitrates[i].bitrate;
+                               *pos++ = (u8) (rate / 5);
+                       }
                }
        }
 
@@ -1282,7 +1328,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 
        /* prepare reordering buffer */
        tid_agg_rx->reorder_buf =
-               kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC);
+               kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
        if (!tid_agg_rx->reorder_buf) {
                if (net_ratelimit())
                        printk(KERN_ERR "can not allocate reordering buffer "
@@ -1291,7 +1337,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
                goto end;
        }
        memset(tid_agg_rx->reorder_buf, 0,
-               buf_size * sizeof(struct sk_buf *));
+               buf_size * sizeof(struct sk_buff *));
 
        if (local->ops->ampdu_action)
                ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
@@ -1571,7 +1617,7 @@ void sta_addba_resp_timer_expired(unsigned long data)
         * only one argument, and both sta_info and TID are needed, so init
         * flow in sta_info_create gives the TID as data, while the timer_to_id
         * array gives the sta through container_of */
-       u16 tid = *(int *)data;
+       u16 tid = *(u8 *)data;
        struct sta_info *temp_sta = container_of((void *)data,
                struct sta_info, timer_to_tid[tid]);
 
@@ -1619,7 +1665,7 @@ timer_expired_exit:
 void sta_rx_agg_session_timer_expired(unsigned long data)
 {
        /* not an elegant detour, but there is no choice as the timer passes
-        * only one argument, and verious sta_info are needed here, so init
+        * only one argument, and various sta_info are needed here, so init
         * flow in sta_info_create gives the TID as data, while the timer_to_id
         * array gives the sta through container_of */
        u8 *ptid = (u8 *)data;
@@ -2293,6 +2339,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        u8 *pos;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_supported_band *sband;
+       union iwreq_data wrqu;
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
@@ -2315,13 +2362,10 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        sdata->drop_unencrypted = bss->capability &
                WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-       res = ieee80211_set_freq(local, bss->freq);
+       res = ieee80211_set_freq(dev, bss->freq);
 
-       if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
-               printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
-                      "%d MHz\n", dev->name, local->oper_channel->center_freq);
-               return -1;
-       }
+       if (res)
+               return res;
 
        /* Set beacon template */
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
@@ -2436,7 +2480,9 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        ifsta->state = IEEE80211_IBSS_JOINED;
        mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
 
-       ieee80211_rx_bss_put(dev, bss);
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 
        return res;
 }
@@ -3410,21 +3456,17 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
        struct ieee80211_sta_bss *bss, *selected = NULL;
        int top_rssi = 0, freq;
 
-       if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
-           IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) {
-               ifsta->state = IEEE80211_AUTHENTICATE;
-               ieee80211_sta_reset_auth(dev, ifsta);
-               return 0;
-       }
-
        spin_lock_bh(&local->sta_bss_lock);
        freq = local->oper_channel->center_freq;
        list_for_each_entry(bss, &local->sta_bss_list, list) {
                if (!(bss->capability & WLAN_CAPABILITY_ESS))
                        continue;
 
-               if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
-                   !!sdata->default_key)
+               if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
+                       IEEE80211_STA_AUTO_BSSID_SEL |
+                       IEEE80211_STA_AUTO_CHANNEL_SEL)) &&
+                   (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+                    !!sdata->default_key))
                        continue;
 
                if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) &&
@@ -3449,7 +3491,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
        spin_unlock_bh(&local->sta_bss_lock);
 
        if (selected) {
-               ieee80211_set_freq(local, selected->freq);
+               ieee80211_set_freq(dev, selected->freq);
                if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
                        ieee80211_sta_set_ssid(dev, selected->ssid,
                                               selected->ssid_len);
@@ -3484,6 +3526,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
        struct ieee80211_supported_band *sband;
        u8 bssid[ETH_ALEN], *pos;
        int i;
+       int ret;
        DECLARE_MAC_BUF(mac);
 
 #if 0
@@ -3528,7 +3571,9 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
                *pos++ = (u8) (rate / 5);
        }
 
-       return ieee80211_sta_join_ibss(dev, ifsta, bss);
+       ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
+       ieee80211_rx_bss_put(dev, bss);
+       return ret;
 }
 
 
@@ -3569,17 +3614,22 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
        spin_unlock_bh(&local->sta_bss_lock);
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
-              "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid));
+       if (found)
+               printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
+                      "%s\n", print_mac(mac, bssid),
+                      print_mac(mac2, ifsta->bssid));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
        if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
            (bss = ieee80211_rx_bss_get(dev, bssid,
                                        local->hw.conf.channel->center_freq,
                                        ifsta->ssid, ifsta->ssid_len))) {
+               int ret;
                printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
                       " based on configured SSID\n",
                       dev->name, print_mac(mac, bssid));
-               return ieee80211_sta_join_ibss(dev, ifsta, bss);
+               ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
+               ieee80211_rx_bss_put(dev, bss);
+               return ret;
        }
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
        printk(KERN_DEBUG "   did not try to join ibss\n");
@@ -4056,18 +4106,17 @@ ieee80211_sta_scan_result(struct net_device *dev,
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
-       iwe.u.freq.m = bss->freq;
-       iwe.u.freq.e = 6;
+       iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
+       iwe.u.freq.e = 0;
        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
-       iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
-       iwe.u.freq.e = 0;
+       iwe.u.freq.m = bss->freq;
+       iwe.u.freq.e = 6;
        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
-
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = IWEVQUAL;
        iwe.u.qual.qual = bss->signal;