When an assoc_resp is received the network structure is not completely
[sfrench/cifs-2.6.git] / net / ieee80211 / ieee80211_rx.c
index 8bcdbabae3a1ed3f3034ab262ea3bfa3878aa8cb..8d87d66c2a3492118102bc96f8bf8c3936c92341 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
  * <jkmaline@cc.hut.fi>
  * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
- * Copyright (c) 2004, Intel Corporation
+ * Copyright (c) 2004-2005, Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -409,7 +409,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                return 1;
        }
 
-       if (ieee->host_decrypt) {
+       if (is_multicast_ether_addr(hdr->addr1) ? ieee->host_mc_decrypt :
+           ieee->host_decrypt) {
                int idx = 0;
                if (skb->len >= hdrlen + 3)
                        idx = skb->data[hdrlen + 3] >> 6;
@@ -916,174 +917,23 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
        return rc;
 }
 
-static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
-                                      *frame, struct ieee80211_rx_stats *stats)
-{
-       struct ieee80211_network network_resp;
-       struct ieee80211_network *network = &network_resp;
-       struct ieee80211_info_element *info_element;
-       struct net_device *dev = ieee->dev;
-       u16 left;
-
-       network->flags = 0;
-       network->qos_data.active = 0;
-       network->qos_data.supported = 0;
-       network->qos_data.param_count = 0;
-       network->qos_data.old_param_count = 0;
-
-       //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF);
-       network->atim_window = le16_to_cpu(frame->aid);
-       network->listen_interval = le16_to_cpu(frame->status);
-
-       info_element = frame->info_element;
-       left = stats->len - sizeof(*frame);
-
-       while (left >= sizeof(struct ieee80211_info_element)) {
-               if (sizeof(struct ieee80211_info_element) +
-                   info_element->len > left) {
-                       IEEE80211_DEBUG_QOS("ASSOC RESP: parse failed: "
-                                           "info_element->len + 2 > left : "
-                                           "info_element->len+2=%zd left=%d, id=%d.\n",
-                                           info_element->len +
-                                           sizeof(struct
-                                                  ieee80211_info_element),
-                                           left, info_element->id);
-                       return 1;
-               }
-
-               switch (info_element->id) {
-               case MFIE_TYPE_SSID:
-                       if (ieee80211_is_empty_essid(info_element->data,
-                                                    info_element->len)) {
-                               network->flags |= NETWORK_EMPTY_ESSID;
-                               break;
-                       }
-
-                       network->ssid_len = min(info_element->len,
-                                               (u8) IW_ESSID_MAX_SIZE);
-                       memcpy(network->ssid, info_element->data,
-                              network->ssid_len);
-                       if (network->ssid_len < IW_ESSID_MAX_SIZE)
-                               memset(network->ssid + network->ssid_len, 0,
-                                      IW_ESSID_MAX_SIZE - network->ssid_len);
-
-                       IEEE80211_DEBUG_QOS("MFIE_TYPE_SSID: '%s' len=%d.\n",
-                                           network->ssid, network->ssid_len);
-                       break;
-
-               case MFIE_TYPE_TIM:
-                       IEEE80211_DEBUG_QOS("MFIE_TYPE_TIM: ignored\n");
-                       break;
-
-               case MFIE_TYPE_IBSS_SET:
-                       IEEE80211_DEBUG_QOS("MFIE_TYPE_IBSS_SET: ignored\n");
-                       break;
-
-               case MFIE_TYPE_CHALLENGE:
-                       IEEE80211_DEBUG_QOS("MFIE_TYPE_CHALLENGE: ignored\n");
-                       break;
-
-               case MFIE_TYPE_GENERIC:
-                       IEEE80211_DEBUG_QOS("MFIE_TYPE_GENERIC: %d bytes\n",
-                                           info_element->len);
-                       ieee80211_parse_qos_info_param_IE(info_element,
-                                                         network);
-                       break;
-
-               case MFIE_TYPE_RSN:
-                       IEEE80211_DEBUG_QOS("MFIE_TYPE_RSN: %d bytes\n",
-                                           info_element->len);
-                       break;
-
-               case MFIE_TYPE_QOS_PARAMETER:
-                       printk("QoS Error need to parse QOS_PARAMETER IE\n");
-                       break;
-
-               default:
-                       IEEE80211_DEBUG_QOS("unsupported IE %d\n",
-                                           info_element->id);
-                       break;
-               }
-
-               left -= sizeof(struct ieee80211_info_element) +
-                   info_element->len;
-               info_element = (struct ieee80211_info_element *)
-                   &info_element->data[info_element->len];
-       }
-
-       if (ieee->handle_assoc_response != NULL)
-               ieee->handle_assoc_response(dev, frame, network);
-
-       return 0;
-}
-
-/***************************************************/
-
-static inline int ieee80211_is_ofdm_rate(u8 rate)
-{
-       switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
-       case IEEE80211_OFDM_RATE_6MB:
-       case IEEE80211_OFDM_RATE_9MB:
-       case IEEE80211_OFDM_RATE_12MB:
-       case IEEE80211_OFDM_RATE_18MB:
-       case IEEE80211_OFDM_RATE_24MB:
-       case IEEE80211_OFDM_RATE_36MB:
-       case IEEE80211_OFDM_RATE_48MB:
-       case IEEE80211_OFDM_RATE_54MB:
-               return 1;
-       }
-       return 0;
-}
-
-static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
-                                        *beacon,
-                                        struct ieee80211_network *network,
-                                        struct ieee80211_rx_stats *stats)
+static int ieee80211_parse_info_param(struct ieee80211_info_element *info_element,
+                                       u16 length, struct ieee80211_network *network)
 {
+       u8 i;
 #ifdef CONFIG_IEEE80211_DEBUG
        char rates_str[64];
        char *p;
 #endif
-       struct ieee80211_info_element *info_element;
-       u16 left;
-       u8 i;
-       network->qos_data.active = 0;
-       network->qos_data.supported = 0;
-       network->qos_data.param_count = 0;
 
-       /* Pull out fixed field data */
-       memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
-       network->capability = le16_to_cpu(beacon->capability);
-       network->last_scanned = jiffies;
-       network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]);
-       network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]);
-       network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
-       /* Where to pull this? beacon->listen_interval; */
-       network->listen_interval = 0x0A;
-       network->rates_len = network->rates_ex_len = 0;
-       network->last_associate = 0;
-       network->ssid_len = 0;
-       network->flags = 0;
-       network->atim_window = 0;
-       network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
-               0x3 : 0x0;
-
-       if (stats->freq == IEEE80211_52GHZ_BAND) {
-               /* for A band (No DS info) */
-               network->channel = stats->received_channel;
-       } else
-               network->flags |= NETWORK_HAS_CCK;
-
-       network->wpa_ie_len = 0;
-       network->rsn_ie_len = 0;
-
-       info_element = beacon->info_element;
-       left = stats->len - sizeof(*beacon);
-       while (left >= sizeof(*info_element)) {
-               if (sizeof(*info_element) + info_element->len > left) {
-                       IEEE80211_DEBUG_SCAN
-                           ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n",
-                            info_element->len + sizeof(*info_element), left);
+       while (length >= sizeof(*info_element)) {
+               if (sizeof(*info_element) + info_element->len > length) {
+                       IEEE80211_DEBUG_MGMT("Info elem: parse failed: "
+                                           "info_element->len + 2 > left : "
+                                           "info_element->len+2=%zd left=%d, id=%d.\n",
+                                           info_element->len +
+                                           sizeof(*info_element),
+                                           length, info_element->id);
                        return 1;
                }
 
@@ -1103,8 +953,8 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
                                memset(network->ssid + network->ssid_len, 0,
                                       IW_ESSID_MAX_SIZE - network->ssid_len);
 
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n",
-                                            network->ssid, network->ssid_len);
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n",
+                                           network->ssid, network->ssid_len);
                        break;
 
                case MFIE_TYPE_RATES:
@@ -1130,7 +980,7 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
                                }
                        }
 
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n",
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n",
                                             rates_str, network->rates_len);
                        break;
 
@@ -1157,47 +1007,46 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
                                }
                        }
 
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
                                             rates_str, network->rates_ex_len);
                        break;
 
                case MFIE_TYPE_DS_SET:
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n",
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n",
                                             info_element->data[0]);
-                       if (stats->freq == IEEE80211_24GHZ_BAND)
-                               network->channel = info_element->data[0];
+                       network->channel = info_element->data[0];
                        break;
 
                case MFIE_TYPE_FH_SET:
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n");
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n");
                        break;
 
                case MFIE_TYPE_CF_SET:
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n");
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n");
                        break;
 
                case MFIE_TYPE_TIM:
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_TIM: ignored\n");
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: ignored\n");
                        break;
 
                case MFIE_TYPE_ERP_INFO:
                        network->erp_value = info_element->data[0];
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_ERP_SET: %d\n",
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
                                             network->erp_value);
                        break;
 
                case MFIE_TYPE_IBSS_SET:
                        network->atim_window = info_element->data[0];
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: %d\n",
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n",
                                             network->atim_window);
                        break;
 
                case MFIE_TYPE_CHALLENGE:
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n");
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n");
                        break;
 
                case MFIE_TYPE_GENERIC:
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n",
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n",
                                             info_element->len);
                        if (!ieee80211_parse_qos_info_param_IE(info_element,
                                                               network))
@@ -1216,7 +1065,7 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
                        break;
 
                case MFIE_TYPE_RSN:
-                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n",
+                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n",
                                             info_element->len);
                        network->rsn_ie_len = min(info_element->len + 2,
                                                  MAX_WPA_IE_LEN);
@@ -1225,21 +1074,120 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
                        break;
 
                case MFIE_TYPE_QOS_PARAMETER:
-                       printk(KERN_ERR
-                              "QoS Error need to parse QOS_PARAMETER IE\n");
+                       printk(KERN_ERR "QoS Error need to parse QOS_PARAMETER IE\n");
                        break;
 
                default:
-                       IEEE80211_DEBUG_SCAN("unsupported IE %d\n",
-                                            info_element->id);
+                       IEEE80211_DEBUG_MGMT("unsupported IE %d\n",
+                                           info_element->id);
                        break;
                }
 
-               left -= sizeof(*info_element) + info_element->len;
-               info_element = (struct ieee80211_info_element *)
-                   &info_element->data[info_element->len];
+               length -= sizeof(*info_element) + info_element->len;
+               info_element = (struct ieee80211_info_element *) &info_element->data[info_element->len];
+       }
+
+       return 0;
+}
+
+static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
+                                      *frame, struct ieee80211_rx_stats *stats)
+{
+       struct ieee80211_network network_resp;
+       struct ieee80211_network *network = &network_resp;
+       struct net_device *dev = ieee->dev;
+
+       network->flags = 0;
+       network->qos_data.active = 0;
+       network->qos_data.supported = 0;
+       network->qos_data.param_count = 0;
+       network->qos_data.old_param_count = 0;
+
+       //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF);
+       network->atim_window = le16_to_cpu(frame->aid);
+       network->listen_interval = le16_to_cpu(frame->status);
+       memcpy(network->bssid, frame->header.addr3, ETH_ALEN);
+       network->capability = le16_to_cpu(frame->capability);
+       network->last_scanned = jiffies;
+       network->rates_len = network->rates_ex_len = 0;
+       network->last_associate = 0;
+       network->ssid_len = 0;
+       network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0;
+
+       if (stats->freq == IEEE80211_52GHZ_BAND) {
+               /* for A band (No DS info) */
+               network->channel = stats->received_channel;
+       } else
+               network->flags |= NETWORK_HAS_CCK;
+
+       network->wpa_ie_len = 0;
+       network->rsn_ie_len = 0;
+
+       if(ieee80211_parse_info_param(frame->info_element, stats->len - sizeof(*frame), network))
+               return 1;
+
+       network->mode = 0;
+       if (stats->freq == IEEE80211_52GHZ_BAND)
+               network->mode = IEEE_A;
+       else {
+               if (network->flags & NETWORK_HAS_OFDM)
+                       network->mode |= IEEE_G;
+               if (network->flags & NETWORK_HAS_CCK)
+                       network->mode |= IEEE_B;
        }
 
+       if (ieee80211_is_empty_essid(network->ssid, network->ssid_len))
+               network->flags |= NETWORK_EMPTY_ESSID;
+
+       memcpy(&network->stats, stats, sizeof(network->stats));
+
+       if (ieee->handle_assoc_response != NULL)
+               ieee->handle_assoc_response(dev, frame, network);
+
+       return 0;
+}
+
+/***************************************************/
+
+static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
+                                        *beacon,
+                                        struct ieee80211_network *network,
+                                        struct ieee80211_rx_stats *stats)
+{
+       network->qos_data.active = 0;
+       network->qos_data.supported = 0;
+       network->qos_data.param_count = 0;
+       network->qos_data.old_param_count = 0;
+
+       /* Pull out fixed field data */
+       memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
+       network->capability = le16_to_cpu(beacon->capability);
+       network->last_scanned = jiffies;
+       network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]);
+       network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]);
+       network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
+       /* Where to pull this? beacon->listen_interval; */
+       network->listen_interval = 0x0A;
+       network->rates_len = network->rates_ex_len = 0;
+       network->last_associate = 0;
+       network->ssid_len = 0;
+       network->flags = 0;
+       network->atim_window = 0;
+       network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
+           0x3 : 0x0;
+
+       if (stats->freq == IEEE80211_52GHZ_BAND) {
+               /* for A band (No DS info) */
+               network->channel = stats->received_channel;
+       } else
+               network->flags |= NETWORK_HAS_CCK;
+
+       network->wpa_ie_len = 0;
+       network->rsn_ie_len = 0;
+
+       if(ieee80211_parse_info_param(beacon->info_element, stats->len - sizeof(*beacon), network))
+               return 1;
+
        network->mode = 0;
        if (stats->freq == IEEE80211_52GHZ_BAND)
                network->mode = IEEE_A;
@@ -1533,6 +1481,12 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                                              header);
                break;
 
+       case IEEE80211_STYPE_DEAUTH:
+               printk("DEAUTH from AP\n");
+               if (ieee->handle_deauth != NULL)
+                       ieee->handle_deauth(ieee->dev, (struct ieee80211_auth *)
+                                           header);
+               break;
        default:
                IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
                                     WLAN_FC_GET_STYPE(le16_to_cpu