The following changes since commit aeb042d56adfcd536bad5cd018caeb74143181a5:
  John W. Linville:
        Merge git://git.kernel.org/.../torvalds/linux-2.6

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git 
upstream-jgarzik

Zhu Yi:
      ieee80211: Add 802.11h data type and structures
      ieee80211: Add helpers for IBSS DFS handling
      ieee80211: Add 802.11h information element parsing

 include/net/ieee80211.h          |  163 +++++++++++++++++++++++++++++++++++++-
 net/ieee80211/ieee80211_module.c |   18 ++++
 net/ieee80211/ieee80211_rx.c     |  109 ++++++++++++++++++++++++-
 3 files changed, 281 insertions(+), 9 deletions(-)

diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index 5673ccf..ff6ef9e 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -300,6 +300,23 @@ enum ieee80211_reasoncode {
        WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
 };
 
+/* Action categories - 802.11h */
+enum ieee80211_actioncategories {
+       WLAN_ACTION_SPECTRUM_MGMT = 0,
+       /* Reserved 1-127  */
+       /* Error    128-255 */
+};
+
+/* Action details - 802.11h */
+enum ieee80211_actiondetails {
+       WLAN_ACTION_CATEGORY_MEASURE_REQUEST = 0,
+       WLAN_ACTION_CATEGORY_MEASURE_REPORT = 1,
+       WLAN_ACTION_CATEGORY_TPC_REQUEST = 2,
+       WLAN_ACTION_CATEGORY_TPC_REPORT = 3,
+       WLAN_ACTION_CATEGORY_CHANNEL_SWITCH = 4,
+       /* 5 - 255 Reserved */
+};
+
 #define IEEE80211_STATMASK_SIGNAL (1<<0)
 #define IEEE80211_STATMASK_RSSI (1<<1)
 #define IEEE80211_STATMASK_NOISE (1<<2)
@@ -378,6 +395,8 @@ struct ieee80211_rx_stats {
        u8 mask;
        u8 freq;
        u16 len;
+       u64 tsf;
+       u32 beacon_time;
 };
 
 /* IEEE 802.11 requires that STA supports concurrent reception of at least
@@ -609,6 +628,28 @@ struct ieee80211_auth {
        struct ieee80211_info_element info_element[0];
 } __attribute__ ((packed));
 
+struct ieee80211_channel_switch {
+       u8 id;
+       u8 len;
+       u8 mode;
+       u8 channel;
+       u8 count;
+} __attribute__ ((packed));
+
+struct ieee80211_action {
+       struct ieee80211_hdr_3addr header;
+       u8 category;
+       u8 action;
+       union {
+               struct ieee80211_action_exchange {
+                       u8 token;
+                       struct ieee80211_info_element info_element[0];
+               } exchange;
+               struct ieee80211_channel_switch channel_switch;
+
+       } format;
+} __attribute__ ((packed));
+
 struct ieee80211_disassoc {
        struct ieee80211_hdr_3addr header;
        __le16 reason;
@@ -693,7 +734,15 @@ struct ieee80211_txb {
 /* QoS structure */
 #define NETWORK_HAS_QOS_PARAMETERS      (1<<3)
 #define NETWORK_HAS_QOS_INFORMATION     (1<<4)
-#define NETWORK_HAS_QOS_MASK            (NETWORK_HAS_QOS_PARAMETERS | 
NETWORK_HAS_QOS_INFORMATION)
+#define NETWORK_HAS_QOS_MASK            (NETWORK_HAS_QOS_PARAMETERS | \
+                                        NETWORK_HAS_QOS_INFORMATION)
+
+/* 802.11h */
+#define NETWORK_HAS_POWER_CONSTRAINT    (1<<5)
+#define NETWORK_HAS_CSA                 (1<<6)
+#define NETWORK_HAS_QUIET               (1<<7)
+#define NETWORK_HAS_IBSS_DFS            (1<<8)
+#define NETWORK_HAS_TPC_REPORT          (1<<9)
 
 #define QOS_QUEUE_NUM                   4
 #define QOS_OUI_LEN                     3
@@ -749,6 +798,91 @@ struct ieee80211_tim_parameters {
 
 /*******************************************************/
 
+enum {                         /* ieee80211_basic_report.map */
+       IEEE80211_BASIC_MAP_BSS = (1 << 0),
+       IEEE80211_BASIC_MAP_OFDM = (1 << 1),
+       IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
+       IEEE80211_BASIC_MAP_RADAR = (1 << 3),
+       IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
+       /* Bits 5-7 are reserved */
+
+};
+struct ieee80211_basic_report {
+       u8 channel;
+       __le64 start_time;
+       __le16 duration;
+       u8 map;
+} __attribute__ ((packed));
+
+enum {                         /* ieee80211_measurement_request.mode */
+       /* Bit 0 is reserved */
+       IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
+       IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
+       IEEE80211_MEASUREMENT_REPORT = (1 << 3),
+       /* Bits 4-7 are reserved */
+};
+
+enum {
+       IEEE80211_REPORT_BASIC = 0,     /* required */
+       IEEE80211_REPORT_CCA = 1,       /* optional */
+       IEEE80211_REPORT_RPI = 2,       /* optional */
+       /* 3-255 reserved */
+};
+
+struct ieee80211_measurement_params {
+       u8 channel;
+       __le64 start_time;
+       __le16 duration;
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_request {
+       struct ieee80211_info_element ie;
+       u8 token;
+       u8 mode;
+       u8 type;
+       struct ieee80211_measurement_params params[0];
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_report {
+       struct ieee80211_info_element ie;
+       u8 token;
+       u8 mode;
+       u8 type;
+       union {
+               struct ieee80211_basic_report basic[0];
+       } u;
+} __attribute__ ((packed));
+
+struct ieee80211_tpc_report {
+       u8 transmit_power;
+       u8 link_margin;
+} __attribute__ ((packed));
+
+struct ieee80211_channel_map {
+       u8 channel;
+       u8 map;
+} __attribute__ ((packed));
+
+struct ieee80211_ibss_dfs {
+       struct ieee80211_info_element ie;
+       u8 owner[ETH_ALEN];
+       u8 recovery_interval;
+       struct ieee80211_channel_map channel_map[0];
+};
+
+struct ieee80211_csa {
+       u8 mode;
+       u8 channel;
+       u8 count;
+} __attribute__ ((packed));
+
+struct ieee80211_quiet {
+       u8 count;
+       u8 period;
+       u8 duration;
+       u8 offset;
+} __attribute__ ((packed));
+
 struct ieee80211_network {
        /* These entries are used to identify a unique network */
        u8 bssid[ETH_ALEN];
@@ -768,7 +902,7 @@ struct ieee80211_network {
        u8 rates_ex_len;
        unsigned long last_scanned;
        u8 mode;
-       u8 flags;
+       u32 flags;
        u32 last_associate;
        u32 time_stamp[2];
        u16 beacon_interval;
@@ -780,6 +914,25 @@ struct ieee80211_network {
        u8 rsn_ie[MAX_WPA_IE_LEN];
        size_t rsn_ie_len;
        struct ieee80211_tim_parameters tim;
+
+       /* 802.11h info */
+
+       /* Power Constraint - mandatory if spctrm mgmt required */
+       u8 power_constraint;
+
+       /* TPC Report - mandatory if spctrm mgmt required */
+       struct ieee80211_tpc_report tpc_report;
+
+       /* IBSS DFS - mandatory if spctrm mgmt required and IBSS
+        * NOTE: This is variable length and so must be allocated dynamically */
+       struct ieee80211_ibss_dfs *ibss_dfs;
+
+       /* Channel Switch Announcement - optional if spctrm mgmt required */
+       struct ieee80211_csa csa;
+
+       /* Quiet - optional if spctrm mgmt required */
+       struct ieee80211_quiet quiet;
+
        struct list_head list;
 };
 
@@ -925,7 +1078,10 @@ struct ieee80211_device {
        int (*handle_auth) (struct net_device * dev,
                            struct ieee80211_auth * auth);
        int (*handle_deauth) (struct net_device * dev,
-                             struct ieee80211_auth * auth);
+                             struct ieee80211_deauth * auth);
+       int (*handle_action) (struct net_device * dev,
+                             struct ieee80211_action * action,
+                             struct ieee80211_rx_stats * stats);
        int (*handle_disassoc) (struct net_device * dev,
                                struct ieee80211_disassoc * assoc);
        int (*handle_beacon) (struct net_device * dev,
@@ -1094,6 +1250,7 @@ extern int ieee80211_rx(struct ieee80211
 extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                             struct ieee80211_hdr_4addr *header,
                             struct ieee80211_rx_stats *stats);
+extern void ieee80211_network_reset(struct ieee80211_network *network);
 
 /* ieee80211_geo.c */
 extern const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index 90d18b7..5f67c68 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -82,10 +82,28 @@ static int ieee80211_networks_allocate(s
        return 0;
 }
 
+void ieee80211_network_reset(struct ieee80211_network *network)
+{
+       if (!network)
+               return;
+
+       if (network->ibss_dfs) {
+               kfree(network->ibss_dfs);
+               network->ibss_dfs = NULL;
+       }
+}
+
 static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
 {
+       int i;
+
        if (!ieee->networks)
                return;
+
+       for (i = 0; i < MAX_NETWORK_COUNT; i++)
+               if (ieee->networks[i].ibss_dfs)
+                       kfree(ieee->networks[i].ibss_dfs);
+
        kfree(ieee->networks);
        ieee->networks = NULL;
 }
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index de402b7..a4ebc22 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -937,6 +937,45 @@ static int ieee80211_parse_qos_info_para
        return rc;
 }
 
+#ifdef CONFIG_IEEE80211_DEBUG
+#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x
+
+static const char *get_info_element_string(u16 id)
+{
+       switch (id) {
+               MFIE_STRING(SSID);
+               MFIE_STRING(RATES);
+               MFIE_STRING(FH_SET);
+               MFIE_STRING(DS_SET);
+               MFIE_STRING(CF_SET);
+               MFIE_STRING(TIM);
+               MFIE_STRING(IBSS_SET);
+               MFIE_STRING(COUNTRY);
+               MFIE_STRING(HOP_PARAMS);
+               MFIE_STRING(HOP_TABLE);
+               MFIE_STRING(REQUEST);
+               MFIE_STRING(CHALLENGE);
+               MFIE_STRING(POWER_CONSTRAINT);
+               MFIE_STRING(POWER_CAPABILITY);
+               MFIE_STRING(TPC_REQUEST);
+               MFIE_STRING(TPC_REPORT);
+               MFIE_STRING(SUPP_CHANNELS);
+               MFIE_STRING(CSA);
+               MFIE_STRING(MEASURE_REQUEST);
+               MFIE_STRING(MEASURE_REPORT);
+               MFIE_STRING(QUIET);
+               MFIE_STRING(IBSS_DFS);
+               MFIE_STRING(ERP_INFO);
+               MFIE_STRING(RSN);
+               MFIE_STRING(RATES_EX);
+               MFIE_STRING(GENERIC);
+               MFIE_STRING(QOS_PARAMETER);
+       default:
+               return "UNKNOWN";
+       }
+}
+#endif
+
 static int ieee80211_parse_info_param(struct ieee80211_info_element
                                      *info_element, u16 length,
                                      struct ieee80211_network *network)
@@ -1100,10 +1139,49 @@ static int ieee80211_parse_info_param(st
                        printk(KERN_ERR
                               "QoS Error need to parse QOS_PARAMETER IE\n");
                        break;
+                       /* 802.11h */
+               case MFIE_TYPE_POWER_CONSTRAINT:
+                       network->power_constraint = info_element->data[0];
+                       network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
+                       break;
+
+               case MFIE_TYPE_CSA:
+                       network->power_constraint = info_element->data[0];
+                       network->flags |= NETWORK_HAS_CSA;
+                       break;
+
+               case MFIE_TYPE_QUIET:
+                       network->quiet.count = info_element->data[0];
+                       network->quiet.period = info_element->data[1];
+                       network->quiet.duration = info_element->data[2];
+                       network->quiet.offset = info_element->data[3];
+                       network->flags |= NETWORK_HAS_QUIET;
+                       break;
+
+               case MFIE_TYPE_IBSS_DFS:
+                       if (network->ibss_dfs)
+                               break;
+                       network->ibss_dfs =
+                           kmalloc(info_element->len, GFP_ATOMIC);
+                       if (!network->ibss_dfs)
+                               return 1;
+                       memcpy(network->ibss_dfs, info_element->data,
+                              info_element->len);
+                       network->flags |= NETWORK_HAS_IBSS_DFS;
+                       break;
+
+               case MFIE_TYPE_TPC_REPORT:
+                       network->tpc_report.transmit_power =
+                           info_element->data[0];
+                       network->tpc_report.link_margin = info_element->data[1];
+                       network->flags |= NETWORK_HAS_TPC_REPORT;
+                       break;
 
                default:
-                       IEEE80211_DEBUG_MGMT("unsupported IE %d\n",
-                                            info_element->id);
+                       IEEE80211_DEBUG_MGMT
+                           ("Unsupported info element: %s (%d)\n",
+                            get_info_element_string(info_element->id),
+                            info_element->id);
                        break;
                }
 
@@ -1119,7 +1197,9 @@ static int ieee80211_parse_info_param(st
 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_resp = {
+               .ibss_dfs = NULL,
+       };
        struct ieee80211_network *network = &network_resp;
        struct net_device *dev = ieee->dev;
 
@@ -1262,6 +1342,9 @@ static void update_network(struct ieee80
        int qos_active;
        u8 old_param;
 
+       ieee80211_network_reset(dst);
+       dst->ibss_dfs = src->ibss_dfs;
+
        memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
        dst->capability = src->capability;
        memcpy(dst->rates, src->rates, src->rates_len);
@@ -1323,7 +1406,9 @@ static void ieee80211_process_probe_resp
                                                    *stats)
 {
        struct net_device *dev = ieee->dev;
-       struct ieee80211_network network;
+       struct ieee80211_network network = {
+               .ibss_dfs = NULL,
+       };
        struct ieee80211_network *target;
        struct ieee80211_network *oldest = NULL;
 #ifdef CONFIG_IEEE80211_DEBUG
@@ -1398,6 +1483,7 @@ static void ieee80211_process_probe_resp
                                             escape_essid(target->ssid,
                                                          target->ssid_len),
                                             MAC_ARG(target->bssid));
+                       ieee80211_network_reset(target);
                } else {
                        /* Otherwise just pull from the free list */
                        target = list_entry(ieee->network_free_list.next,
@@ -1416,6 +1502,7 @@ static void ieee80211_process_probe_resp
                                     "BEACON" : "PROBE RESPONSE");
 #endif
                memcpy(target, &network, sizeof(*target));
+               network.ibss_dfs = NULL;
                list_add_tail(&target->list, &ieee->network_list);
        } else {
                IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
@@ -1427,6 +1514,7 @@ static void ieee80211_process_probe_resp
                                                frame_ctl)) ?
                                     "BEACON" : "PROBE RESPONSE");
                update_network(target, &network);
+               network.ibss_dfs = NULL;
        }
 
        spin_unlock_irqrestore(&ieee->lock, flags);
@@ -1511,10 +1599,19 @@ void ieee80211_rx_mgt(struct ieee80211_d
                                              header);
                break;
 
+       case IEEE80211_STYPE_ACTION:
+               IEEE80211_DEBUG_MGMT("ACTION\n");
+               if (ieee->handle_action)
+                       ieee->handle_action(ieee->dev,
+                                           (struct ieee80211_action *)
+                                           header, stats);
+               break;
+
        case IEEE80211_STYPE_DEAUTH:
-               printk("DEAUTH from AP\n");
+               IEEE80211_DEBUG_MGMT("DEAUTH\n");
                if (ieee->handle_deauth != NULL)
-                       ieee->handle_deauth(ieee->dev, (struct ieee80211_auth *)
+                       ieee->handle_deauth(ieee->dev,
+                                           (struct ieee80211_deauth *)
                                            header);
                break;
        default:
-- 
John W. Linville
[EMAIL PROTECTED]
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to