mac80211: update mesh peering frame format
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>
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 0750987..819954a 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -736,19 +736,6 @@
__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 @@
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,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d86a15d..d29d11a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2291,7 +2291,7 @@
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 @@
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;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 1990869..da5e981 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -662,8 +662,14 @@
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);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 2cf2212..1a00d0f 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
/* 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();
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fe2c2a7..3fb6dea 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2220,6 +2220,24 @@
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;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 844ddb0..eef82f7 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1158,9 +1158,9 @@
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;