mac80211: update mesh peering frame format
authorThomas Pedersen <thomas@cozybit.com>
Sat, 13 Aug 2011 03:01:00 +0000 (20:01 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 22 Aug 2011 18:46:00 +0000 (14:46 -0400)
This patch updates the mesh peering frames to the format specified in
the recently ratified 802.11s standard. Several changes took place to
make this happen:

- Change RX path to handle new self-protected frames
- Add new Peering management IE
- Remove old Peer Link IE
- Remove old plink_action field in ieee80211_mgmt header

These changes by themselves would either break peering, or work by
coincidence, so squash them all into this patch.

Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/linux/ieee80211.h
include/net/cfg80211.h
net/mac80211/mesh.c
net/mac80211/mesh_plink.c
net/mac80211/rx.c
net/wireless/util.c

index 0750987..819954a 100644 (file)
@@ -736,19 +736,6 @@ struct ieee80211_mgmt {
                                        __le16 params;
                                        __le16 reason_code;
                                } __attribute__((packed)) delba;
-                               struct{
-                                       u8 action_code;
-                                       /* capab_info for open and confirm,
-                                        * reason for close
-                                        */
-                                       __le16 aux;
-                                       /* Followed in plink_confirm by status
-                                        * code, AID and supported rates,
-                                        * and directly by supported rates in
-                                        * plink_open and plink_close
-                                        */
-                                       u8 variable[0];
-                               } __attribute__((packed)) plink_action;
                                struct {
                                        u8 action_code;
                                        u8 variable[0];
@@ -1200,11 +1187,6 @@ enum ieee80211_eid {
        WLAN_EID_MESH_ID = 114,
        WLAN_EID_LINK_METRIC_REPORT = 115,
        WLAN_EID_CONGESTION_NOTIFICATION = 116,
-       /* Note that the Peer Link IE has been replaced with the similar
-        * Peer Management IE.  We will keep the former definition until mesh
-        * code is changed to comply with latest 802.11s drafts.
-        */
-       WLAN_EID_PEER_LINK = 55,  /* no longer in 802.11s drafts */
        WLAN_EID_PEER_MGMT = 117,
        WLAN_EID_CHAN_SWITCH_PARAM = 118,
        WLAN_EID_MESH_AWAKE_WINDOW = 119,
index d86a15d..d29d11a 100644 (file)
@@ -2291,7 +2291,7 @@ struct ieee802_11_elems {
        struct ieee80211_ht_info *ht_info_elem;
        struct ieee80211_meshconf_ie *mesh_config;
        u8 *mesh_id;
-       u8 *peer_link;
+       u8 *peering;
        u8 *preq;
        u8 *prep;
        u8 *perr;
@@ -2318,7 +2318,7 @@ struct ieee802_11_elems {
        u8 wmm_info_len;
        u8 wmm_param_len;
        u8 mesh_id_len;
-       u8 peer_link_len;
+       u8 peering_len;
        u8 preq_len;
        u8 prep_len;
        u8 perr_len;
index 1990869..da5e981 100644 (file)
@@ -662,8 +662,14 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
                                          struct ieee80211_rx_status *rx_status)
 {
        switch (mgmt->u.action.category) {
-       case WLAN_CATEGORY_MESH_ACTION:
-               mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+       case WLAN_CATEGORY_SELF_PROTECTED:
+               switch (mgmt->u.action.u.self_prot.action_code) {
+               case WLAN_SP_MESH_PEERING_OPEN:
+               case WLAN_SP_MESH_PEERING_CLOSE:
+               case WLAN_SP_MESH_PEERING_CONFIRM:
+                       mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+                       break;
+               }
                break;
        case WLAN_CATEGORY_MESH_PATH_SEL:
                mesh_rx_path_sel_frame(sdata, mgmt, len);
index 2cf2212..1a00d0f 100644 (file)
@@ -19,8 +19,8 @@
 #define mpl_dbg(fmt, args...)  do { (void)(0); } while (0)
 #endif
 
-#define PLINK_GET_LLID(p) (p + 4)
-#define PLINK_GET_PLID(p) (p + 6)
+#define PLINK_GET_LLID(p) (p + 2)
+#define PLINK_GET_PLID(p) (p + 4)
 
 #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
                                jiffies + HZ * t / 1000))
@@ -147,9 +147,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                        sdata->u.mesh.ie_len);
        struct ieee80211_mgmt *mgmt;
        bool include_plid = false;
-       static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
+       int ie_len = 4;
+       u16 peering_proto = 0;
        u8 *pos;
-       int ie_len;
 
        if (!skb)
                return -1;
@@ -158,24 +158,23 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
         * common action part (1)
         */
        mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
+               skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot));
+       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot));
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
-       mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
-       mgmt->u.action.u.plink_action.action_code = action;
+       mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
+       mgmt->u.action.u.self_prot.action_code = action;
 
-       if (action == WLAN_SP_MESH_PEERING_CLOSE)
-               mgmt->u.action.u.plink_action.aux = reason;
-       else {
-               mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
+       if (action != WLAN_SP_MESH_PEERING_CLOSE) {
+               /* capability info */
+               pos = skb_put(skb, 2);
+               memset(pos, 0, 2);
                if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
-                       pos = skb_put(skb, 4);
-                       /* two-byte status code followed by two-byte AID */
-                       memset(pos, 0, 2);
+                       /* AID */
+                       pos = skb_put(skb, 2);
                        memcpy(pos + 2, &plid, 2);
                }
                if (mesh_add_srates_ie(skb, sdata) ||
@@ -184,42 +183,50 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                    mesh_add_meshid_ie(skb, sdata) ||
                    mesh_add_meshconf_ie(skb, sdata))
                        return -1;
+       } else {        /* WLAN_SP_MESH_PEERING_CLOSE */
+               if (mesh_add_meshid_ie(skb, sdata))
+                       return -1;
        }
 
-       /* Add Peer Link Management element */
+       /* Add Mesh Peering Management element */
        switch (action) {
        case WLAN_SP_MESH_PEERING_OPEN:
-               ie_len = 6;
                break;
        case WLAN_SP_MESH_PEERING_CONFIRM:
-               ie_len = 8;
+               ie_len += 2;
                include_plid = true;
                break;
        case WLAN_SP_MESH_PEERING_CLOSE:
-       default:
-               if (!plid)
-                       ie_len = 8;
-               else {
-                       ie_len = 10;
+               if (plid) {
+                       ie_len += 2;
                        include_plid = true;
                }
+               ie_len += 2;    /* reason code */
                break;
+       default:
+               return -EINVAL;
        }
 
+       if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
+               return -ENOMEM;
+
        pos = skb_put(skb, 2 + ie_len);
-       *pos++ = WLAN_EID_PEER_LINK;
+       *pos++ = WLAN_EID_PEER_MGMT;
        *pos++ = ie_len;
-       memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto));
-       pos += 4;
+       memcpy(pos, &peering_proto, 2);
+       pos += 2;
        memcpy(pos, &llid, 2);
+       pos += 2;
        if (include_plid) {
-               pos += 2;
                memcpy(pos, &plid, 2);
+               pos += 2;
        }
        if (action == WLAN_SP_MESH_PEERING_CLOSE) {
-               pos += 2;
                memcpy(pos, &reason, 2);
+               pos += 2;
        }
+       if (mesh_add_vendor_ies(skb, sdata))
+               return -1;
 
        ieee80211_tx_skb(sdata, skb);
        return 0;
@@ -437,15 +444,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                return;
        }
 
-       baseaddr = mgmt->u.action.u.plink_action.variable;
-       baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
-       if (mgmt->u.action.u.plink_action.action_code ==
+       baseaddr = mgmt->u.action.u.self_prot.variable;
+       baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
+       if (mgmt->u.action.u.self_prot.action_code ==
                                                WLAN_SP_MESH_PEERING_CONFIRM) {
                baseaddr += 4;
                baselen += 4;
        }
        ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
-       if (!elems.peer_link) {
+       if (!elems.peering) {
                mpl_dbg("Mesh plink: missing necessary peer link ie\n");
                return;
        }
@@ -455,12 +462,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                return;
        }
 
-       ftype = mgmt->u.action.u.plink_action.action_code;
-       ie_len = elems.peer_link_len;
-       if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 6) ||
-           (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 8) ||
-           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 8
-                                                       && ie_len != 10)) {
+       ftype = mgmt->u.action.u.self_prot.action_code;
+       ie_len = elems.peering_len;
+       if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
+           (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
+           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
+                                                       && ie_len != 8)) {
                mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
                    ftype, ie_len);
                return;
@@ -474,10 +481,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
        /* Note the lines below are correct, the llid in the frame is the plid
         * from the point of view of this host.
         */
-       memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2);
+       memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
        if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
-           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 10))
-               memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
+           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
+               memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
 
        rcu_read_lock();
 
index fe2c2a7..3fb6dea 100644 (file)
@@ -2220,6 +2220,24 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                        goto handled;
                }
                break;
+       case WLAN_CATEGORY_SELF_PROTECTED:
+               switch (mgmt->u.action.u.self_prot.action_code) {
+               case WLAN_SP_MESH_PEERING_OPEN:
+               case WLAN_SP_MESH_PEERING_CLOSE:
+               case WLAN_SP_MESH_PEERING_CONFIRM:
+                       if (!ieee80211_vif_is_mesh(&sdata->vif))
+                               goto invalid;
+                       if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+                               /* userspace handles this frame */
+                               break;
+                       goto queue;
+               case WLAN_SP_MGK_INFORM:
+               case WLAN_SP_MGK_ACK:
+                       if (!ieee80211_vif_is_mesh(&sdata->vif))
+                               goto invalid;
+                       break;
+               }
+               break;
        case WLAN_CATEGORY_MESH_ACTION:
                if (!ieee80211_vif_is_mesh(&sdata->vif))
                        break;
index 844ddb0..eef82f7 100644 (file)
@@ -1158,9 +1158,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                        if (elen >= sizeof(struct ieee80211_meshconf_ie))
                                elems->mesh_config = (void *)pos;
                        break;
-               case WLAN_EID_PEER_LINK:
-                       elems->peer_link = pos;
-                       elems->peer_link_len = elen;
+               case WLAN_EID_PEER_MGMT:
+                       elems->peering = pos;
+                       elems->peering_len = elen;
                        break;
                case WLAN_EID_PREQ:
                        elems->preq = pos;