mac80211: split managed/ibss code a little more
authorJohannes Berg <johannes@sipsolutions.net>
Tue, 10 Feb 2009 20:26:03 +0000 (21:26 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 13 Feb 2009 18:46:03 +0000 (13:46 -0500)
It appears that you can completely mess up mac80211 in IBSS
mode by sending it a disassoc or deauth: it'll stop queues
and do a lot more but not ever do anything again. Fix this
by not handling all those frames in IBSS mode,

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/mlme.c

index 3323974..fbb766a 100644 (file)
@@ -808,9 +808,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        bss_info_changed |= BSS_CHANGED_ASSOC;
        ifsta->flags |= IEEE80211_STA_ASSOCIATED;
 
-       if (sdata->vif.type != NL80211_IFTYPE_STATION)
-               return;
-
        bss = ieee80211_rx_bss_get(local, ifsta->bssid,
                                   conf->channel->center_freq,
                                   ifsta->ssid, ifsta->ssid_len);
@@ -1169,6 +1166,30 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
                            elems.challenge_len + 2, 1);
 }
 
+static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
+                                       struct ieee80211_if_sta *ifsta,
+                                       struct ieee80211_mgmt *mgmt,
+                                       size_t len)
+{
+       u16 auth_alg, auth_transaction, status_code;
+
+       if (len < 24 + 6)
+               return;
+
+       auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+       auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+       status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+       /*
+        * IEEE 802.11 standard does not require authentication in IBSS
+        * networks and most implementations do not seem to use it.
+        * However, try to reply to authentication attempts if someone
+        * has actually implemented this.
+        */
+       if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
+               ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
+}
+
 static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                                   struct ieee80211_if_sta *ifsta,
                                   struct ieee80211_mgmt *mgmt,
@@ -1176,38 +1197,22 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 {
        u16 auth_alg, auth_transaction, status_code;
 
-       if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
-           sdata->vif.type != NL80211_IFTYPE_ADHOC)
+       if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE)
                return;
 
        if (len < 24 + 6)
                return;
 
-       if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-           memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
+       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
                return;
 
-       if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-           memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
+       if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
        auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
        auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
        status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
-       if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-               /*
-                * IEEE 802.11 standard does not require authentication in IBSS
-                * networks and most implementations do not seem to use it.
-                * However, try to reply to authentication attempts if someone
-                * has actually implemented this.
-                */
-               if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
-                       return;
-               ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
-               return;
-       }
-
        if (auth_alg != ifsta->auth_alg ||
            auth_transaction != ifsta->auth_transaction)
                return;
@@ -1762,74 +1767,85 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        /* was just updated in ieee80211_bss_info_update */
        beacon_timestamp = bss->cbss.tsf;
 
-       /*
-        * In STA mode, the remaining parameters should not be overridden
-        * by beacons because they're not necessarily accurate there.
-        */
-       if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-           bss->last_probe_resp && beacon) {
-               ieee80211_rx_bss_put(local, bss);
-               return;
-       }
+       if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
+               goto put_bss;
 
        /* check if we need to merge IBSS */
-       if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon &&
-           (!(sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)) &&
-           bss->cbss.capability & WLAN_CAPABILITY_IBSS &&
-           bss->cbss.channel == local->oper_channel &&
-           elems->ssid_len == sdata->u.sta.ssid_len &&
+
+       /* merge only on beacons (???) */
+       if (!beacon)
+               goto put_bss;
+
+       /* we use a fixed BSSID */
+       if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)
+               goto put_bss;
+
+       /* not an IBSS */
+       if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))
+               goto put_bss;
+
+       /* different channel */
+       if (bss->cbss.channel != local->oper_channel)
+               goto put_bss;
+
+       /* different SSID */
+       if (elems->ssid_len != sdata->u.sta.ssid_len ||
            memcmp(elems->ssid, sdata->u.sta.ssid,
-                               sdata->u.sta.ssid_len) == 0) {
-               if (rx_status->flag & RX_FLAG_TSFT) {
-                       /* in order for correct IBSS merging we need mactime
-                        *
-                        * since mactime is defined as the time the first data
-                        * symbol of the frame hits the PHY, and the timestamp
-                        * of the beacon is defined as "the time that the data
-                        * symbol containing the first bit of the timestamp is
-                        * transmitted to the PHY plus the transmitting STA’s
-                        * delays through its local PHY from the MAC-PHY
-                        * interface to its interface with the WM"
-                        * (802.11 11.1.2) - equals the time this bit arrives at
-                        * the receiver - we have to take into account the
-                        * offset between the two.
-                        * e.g: at 1 MBit that means mactime is 192 usec earlier
-                        * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
-                        */
-                       int rate;
-                       if (rx_status->flag & RX_FLAG_HT) {
-                               rate = 65; /* TODO: HT rates */
-                       } else {
-                               rate = local->hw.wiphy->bands[band]->
-                                       bitrates[rx_status->rate_idx].bitrate;
-                       }
-                       rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
-               } else if (local && local->ops && local->ops->get_tsf)
-                       /* second best option: get current TSF */
-                       rx_timestamp = local->ops->get_tsf(local_to_hw(local));
+                               sdata->u.sta.ssid_len))
+               goto put_bss;
+
+       if (rx_status->flag & RX_FLAG_TSFT) {
+               /*
+                * For correct IBSS merging we need mactime; since mactime is
+                * defined as the time the first data symbol of the frame hits
+                * the PHY, and the timestamp of the beacon is defined as "the
+                * time that the data symbol containing the first bit of the
+                * timestamp is transmitted to the PHY plus the transmitting
+                * STA's delays through its local PHY from the MAC-PHY
+                * interface to its interface with the WM" (802.11 11.1.2)
+                * - equals the time this bit arrives at the receiver - we have
+                * to take into account the offset between the two.
+                *
+                * E.g. at 1 MBit that means mactime is 192 usec earlier
+                * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
+                */
+               int rate;
+
+               if (rx_status->flag & RX_FLAG_HT)
+                       rate = 65; /* TODO: HT rates */
                else
-                       /* can't merge without knowing the TSF */
-                       rx_timestamp = -1LLU;
+                       rate = local->hw.wiphy->bands[band]->
+                               bitrates[rx_status->rate_idx].bitrate;
+
+               rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
+       } else if (local && local->ops && local->ops->get_tsf)
+               /* second best option: get current TSF */
+               rx_timestamp = local->ops->get_tsf(local_to_hw(local));
+       else
+               /* can't merge without knowing the TSF */
+               rx_timestamp = -1LLU;
+
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-               printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
-                      "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
-                      mgmt->sa, mgmt->bssid,
-                      (unsigned long long)rx_timestamp,
-                      (unsigned long long)beacon_timestamp,
-                      (unsigned long long)(rx_timestamp - beacon_timestamp),
-                      jiffies);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-               if (beacon_timestamp > rx_timestamp) {
+       printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
+              "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+              mgmt->sa, mgmt->bssid,
+              (unsigned long long)rx_timestamp,
+              (unsigned long long)beacon_timestamp,
+              (unsigned long long)(rx_timestamp - beacon_timestamp),
+              jiffies);
+#endif
+
+       if (beacon_timestamp > rx_timestamp) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-                       printk(KERN_DEBUG "%s: beacon TSF higher than "
-                              "local TSF - IBSS merge with BSSID %pM\n",
-                              sdata->dev->name, mgmt->bssid);
+               printk(KERN_DEBUG "%s: beacon TSF higher than "
+                      "local TSF - IBSS merge with BSSID %pM\n",
+                      sdata->dev->name, mgmt->bssid);
 #endif
-                       ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
-                       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
-               }
+               ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
+               ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
        }
 
+ put_bss:
        ieee80211_rx_bss_put(local, bss);
 }
 
@@ -1993,8 +2009,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_mgmt *resp;
        u8 *pos, *end;
 
-       if (sdata->vif.type != NL80211_IFTYPE_ADHOC ||
-           ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||
+       if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||
            len < 24 + 2 || !ifsta->probe_resp)
                return;
 
@@ -2098,31 +2113,54 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
 
-       switch (fc & IEEE80211_FCTL_STYPE) {
-       case IEEE80211_STYPE_PROBE_REQ:
-               ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len);
-               break;
-       case IEEE80211_STYPE_PROBE_RESP:
-               ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status);
-               break;
-       case IEEE80211_STYPE_BEACON:
-               ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
-               break;
-       case IEEE80211_STYPE_AUTH:
-               ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);
-               break;
-       case IEEE80211_STYPE_ASSOC_RESP:
-               ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0);
-               break;
-       case IEEE80211_STYPE_REASSOC_RESP:
-               ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1);
-               break;
-       case IEEE80211_STYPE_DEAUTH:
-               ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);
-               break;
-       case IEEE80211_STYPE_DISASSOC:
-               ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len);
-               break;
+       if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_PROBE_REQ:
+                       ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt,
+                                                   skb->len);
+                       break;
+               case IEEE80211_STYPE_PROBE_RESP:
+                       ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
+                                                    rx_status);
+                       break;
+               case IEEE80211_STYPE_BEACON:
+                       ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+                                                rx_status);
+                       break;
+               case IEEE80211_STYPE_AUTH:
+                       ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt,
+                                                   skb->len);
+                       break;
+               }
+       } else { /* NL80211_IFTYPE_STATION */
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_PROBE_RESP:
+                       ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
+                                                    rx_status);
+                       break;
+               case IEEE80211_STYPE_BEACON:
+                       ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+                                                rx_status);
+                       break;
+               case IEEE80211_STYPE_AUTH:
+                       ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);
+                       break;
+               case IEEE80211_STYPE_ASSOC_RESP:
+                       ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,
+                                                    skb->len, 0);
+                       break;
+               case IEEE80211_STYPE_REASSOC_RESP:
+                       ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,
+                                                    skb->len, 1);
+                       break;
+               case IEEE80211_STYPE_DEAUTH:
+                       ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);
+                       break;
+               case IEEE80211_STYPE_DISASSOC:
+                       ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt,
+                                                  skb->len);
+                       break;
+               }
        }
 
        kfree_skb(skb);