mac80211: handle extended channel switch announcement
authorJohannes Berg <johannes.berg@intel.com>
Tue, 26 Mar 2013 14:17:18 +0000 (15:17 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 16 Apr 2013 13:29:45 +0000 (15:29 +0200)
Handle the (public) extended channel switch announcement
action frames. Parts of the data in these frames isn't
really in IEs, but put it into the elems struct anyway
to simplify the handling.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/linux/ieee80211.h
net/mac80211/mlme.c
net/mac80211/rx.c

index 95621528436c4a3ce766f6652ae9f1160238a41f..ce07161c873504b3ff8222d2ba3bf27830490dfa 100644 (file)
@@ -864,6 +864,11 @@ struct ieee80211_mgmt {
                                        u8 action_code;
                                        u8 variable[0];
                                } __packed chan_switch;
+                               struct{
+                                       u8 action_code;
+                                       struct ieee80211_ext_chansw_ie data;
+                                       u8 variable[0];
+                               } __packed ext_chan_switch;
                                struct{
                                        u8 action_code;
                                        u8 dialog_token;
@@ -1816,6 +1821,7 @@ enum ieee80211_key_len {
 
 /* Public action codes */
 enum ieee80211_pub_actioncode {
+       WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4,
        WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14,
 };
 
index bd581a80e4b7919e3ad7dde1dbb8d1a92cfc60ec..c53aedb47a6a2dcd4e3a0b30da3c392e39825501 100644 (file)
@@ -3100,6 +3100,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        enum rx_mgmt_action rma = RX_MGMT_NONE;
        u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
        u16 fc;
+       struct ieee802_11_elems elems;
+       int ies_len;
 
        rx_status = (struct ieee80211_rx_status *) skb->cb;
        mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -3130,10 +3132,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                break;
        case IEEE80211_STYPE_ACTION:
                if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
-                       struct ieee802_11_elems elems;
-                       int ies_len = skb->len -
-                                     offsetof(struct ieee80211_mgmt,
-                                              u.action.u.chan_switch.variable);
+                       ies_len = skb->len -
+                                 offsetof(struct ieee80211_mgmt,
+                                          u.action.u.chan_switch.variable);
 
                        if (ies_len < 0)
                                break;
@@ -3145,6 +3146,28 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                        if (elems.parse_error)
                                break;
 
+                       ieee80211_sta_process_chanswitch(sdata,
+                                                        rx_status->mactime,
+                                                        &elems);
+               } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
+                       ies_len = skb->len -
+                                 offsetof(struct ieee80211_mgmt,
+                                          u.action.u.ext_chan_switch.variable);
+
+                       if (ies_len < 0)
+                               break;
+
+                       ieee802_11_parse_elems(
+                               mgmt->u.action.u.ext_chan_switch.variable,
+                               ies_len, &elems);
+
+                       if (elems.parse_error)
+                               break;
+
+                       /* for the handling code pretend this was also an IE */
+                       elems.ext_chansw_ie =
+                               &mgmt->u.action.u.ext_chan_switch.data;
+
                        ieee80211_sta_process_chanswitch(sdata,
                                                         rx_status->mactime,
                                                         &elems);
index e9825f15c14c1966fe6fbd07e45fe2d4d2d463c2..643fcf7c9dcd4cf0b15edc9e70b53526701cebe5 100644 (file)
@@ -2424,6 +2424,22 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                }
 
                break;
+       case WLAN_CATEGORY_PUBLIC:
+               if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+                       goto invalid;
+               if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                       break;
+               if (!rx->sta)
+                       break;
+               if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid))
+                       break;
+               if (mgmt->u.action.u.ext_chan_switch.action_code !=
+                               WLAN_PUB_ACTION_EXT_CHANSW_ANN)
+                       break;
+               if (len < offsetof(struct ieee80211_mgmt,
+                                  u.action.u.ext_chan_switch.variable))
+                       goto invalid;
+               goto queue;
        case WLAN_CATEGORY_VHT:
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
                    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&