Commit 8db09850 authored by Thomas Pedersen's avatar Thomas Pedersen Committed by John W. Linville

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: default avatarThomas Pedersen <thomas@cozybit.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 54ef656b
...@@ -736,19 +736,6 @@ struct ieee80211_mgmt { ...@@ -736,19 +736,6 @@ struct ieee80211_mgmt {
__le16 params; __le16 params;
__le16 reason_code; __le16 reason_code;
} __attribute__((packed)) delba; } __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 { struct {
u8 action_code; u8 action_code;
u8 variable[0]; u8 variable[0];
...@@ -1200,11 +1187,6 @@ enum ieee80211_eid { ...@@ -1200,11 +1187,6 @@ enum ieee80211_eid {
WLAN_EID_MESH_ID = 114, WLAN_EID_MESH_ID = 114,
WLAN_EID_LINK_METRIC_REPORT = 115, WLAN_EID_LINK_METRIC_REPORT = 115,
WLAN_EID_CONGESTION_NOTIFICATION = 116, 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_PEER_MGMT = 117,
WLAN_EID_CHAN_SWITCH_PARAM = 118, WLAN_EID_CHAN_SWITCH_PARAM = 118,
WLAN_EID_MESH_AWAKE_WINDOW = 119, WLAN_EID_MESH_AWAKE_WINDOW = 119,
......
...@@ -2291,7 +2291,7 @@ struct ieee802_11_elems { ...@@ -2291,7 +2291,7 @@ struct ieee802_11_elems {
struct ieee80211_ht_info *ht_info_elem; struct ieee80211_ht_info *ht_info_elem;
struct ieee80211_meshconf_ie *mesh_config; struct ieee80211_meshconf_ie *mesh_config;
u8 *mesh_id; u8 *mesh_id;
u8 *peer_link; u8 *peering;
u8 *preq; u8 *preq;
u8 *prep; u8 *prep;
u8 *perr; u8 *perr;
...@@ -2318,7 +2318,7 @@ struct ieee802_11_elems { ...@@ -2318,7 +2318,7 @@ struct ieee802_11_elems {
u8 wmm_info_len; u8 wmm_info_len;
u8 wmm_param_len; u8 wmm_param_len;
u8 mesh_id_len; u8 mesh_id_len;
u8 peer_link_len; u8 peering_len;
u8 preq_len; u8 preq_len;
u8 prep_len; u8 prep_len;
u8 perr_len; u8 perr_len;
......
...@@ -662,9 +662,15 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, ...@@ -662,9 +662,15 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rx_status *rx_status) struct ieee80211_rx_status *rx_status)
{ {
switch (mgmt->u.action.category) { switch (mgmt->u.action.category) {
case WLAN_CATEGORY_MESH_ACTION: 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); mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
break; break;
}
break;
case WLAN_CATEGORY_MESH_PATH_SEL: case WLAN_CATEGORY_MESH_PATH_SEL:
mesh_rx_path_sel_frame(sdata, mgmt, len); mesh_rx_path_sel_frame(sdata, mgmt, len);
break; break;
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#define mpl_dbg(fmt, args...) do { (void)(0); } while (0) #define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
#endif #endif
#define PLINK_GET_LLID(p) (p + 4) #define PLINK_GET_LLID(p) (p + 2)
#define PLINK_GET_PLID(p) (p + 6) #define PLINK_GET_PLID(p) (p + 4)
#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
jiffies + HZ * t / 1000)) jiffies + HZ * t / 1000))
...@@ -147,9 +147,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, ...@@ -147,9 +147,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
sdata->u.mesh.ie_len); sdata->u.mesh.ie_len);
struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt;
bool include_plid = false; bool include_plid = false;
static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; int ie_len = 4;
u16 peering_proto = 0;
u8 *pos; u8 *pos;
int ie_len;
if (!skb) if (!skb)
return -1; return -1;
...@@ -158,24 +158,23 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, ...@@ -158,24 +158,23 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
* common action part (1) * common action part (1)
*/ */
mgmt = (struct ieee80211_mgmt *) mgmt = (struct ieee80211_mgmt *)
skb_put(skb, 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.plink_action)); memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot));
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION); IEEE80211_STYPE_ACTION);
memcpy(mgmt->da, da, ETH_ALEN); memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION; mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
mgmt->u.action.u.plink_action.action_code = action; mgmt->u.action.u.self_prot.action_code = action;
if (action == WLAN_SP_MESH_PEERING_CLOSE) if (action != WLAN_SP_MESH_PEERING_CLOSE) {
mgmt->u.action.u.plink_action.aux = reason; /* capability info */
else { pos = skb_put(skb, 2);
mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
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); memset(pos, 0, 2);
if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
/* AID */
pos = skb_put(skb, 2);
memcpy(pos + 2, &plid, 2); memcpy(pos + 2, &plid, 2);
} }
if (mesh_add_srates_ie(skb, sdata) || if (mesh_add_srates_ie(skb, sdata) ||
...@@ -184,42 +183,50 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *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_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata)) mesh_add_meshconf_ie(skb, sdata))
return -1; 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) { switch (action) {
case WLAN_SP_MESH_PEERING_OPEN: case WLAN_SP_MESH_PEERING_OPEN:
ie_len = 6;
break; break;
case WLAN_SP_MESH_PEERING_CONFIRM: case WLAN_SP_MESH_PEERING_CONFIRM:
ie_len = 8; ie_len += 2;
include_plid = true; include_plid = true;
break; break;
case WLAN_SP_MESH_PEERING_CLOSE: case WLAN_SP_MESH_PEERING_CLOSE:
default: if (plid) {
if (!plid) ie_len += 2;
ie_len = 8;
else {
ie_len = 10;
include_plid = true; include_plid = true;
} }
ie_len += 2; /* reason code */
break; break;
default:
return -EINVAL;
} }
if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
return -ENOMEM;
pos = skb_put(skb, 2 + ie_len); pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PEER_LINK; *pos++ = WLAN_EID_PEER_MGMT;
*pos++ = ie_len; *pos++ = ie_len;
memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto)); memcpy(pos, &peering_proto, 2);
pos += 4; pos += 2;
memcpy(pos, &llid, 2); memcpy(pos, &llid, 2);
if (include_plid) {
pos += 2; pos += 2;
if (include_plid) {
memcpy(pos, &plid, 2); memcpy(pos, &plid, 2);
pos += 2;
} }
if (action == WLAN_SP_MESH_PEERING_CLOSE) { if (action == WLAN_SP_MESH_PEERING_CLOSE) {
pos += 2;
memcpy(pos, &reason, 2); memcpy(pos, &reason, 2);
pos += 2;
} }
if (mesh_add_vendor_ies(skb, sdata))
return -1;
ieee80211_tx_skb(sdata, skb); ieee80211_tx_skb(sdata, skb);
return 0; return 0;
...@@ -437,15 +444,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m ...@@ -437,15 +444,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
return; return;
} }
baseaddr = mgmt->u.action.u.plink_action.variable; baseaddr = mgmt->u.action.u.self_prot.variable;
baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
if (mgmt->u.action.u.plink_action.action_code == if (mgmt->u.action.u.self_prot.action_code ==
WLAN_SP_MESH_PEERING_CONFIRM) { WLAN_SP_MESH_PEERING_CONFIRM) {
baseaddr += 4; baseaddr += 4;
baselen += 4; baselen += 4;
} }
ieee802_11_parse_elems(baseaddr, len - baselen, &elems); 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"); mpl_dbg("Mesh plink: missing necessary peer link ie\n");
return; return;
} }
...@@ -455,12 +462,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m ...@@ -455,12 +462,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
return; return;
} }
ftype = mgmt->u.action.u.plink_action.action_code; ftype = mgmt->u.action.u.self_prot.action_code;
ie_len = elems.peer_link_len; ie_len = elems.peering_len;
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 6) || if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
(ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 8) || (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 8 (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
&& ie_len != 10)) { && ie_len != 8)) {
mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
ftype, ie_len); ftype, ie_len);
return; return;
...@@ -474,10 +481,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m ...@@ -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 /* Note the lines below are correct, the llid in the frame is the plid
* from the point of view of this host. * 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 || if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 10)) (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
rcu_read_lock(); rcu_read_lock();
......
...@@ -2220,6 +2220,24 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) ...@@ -2220,6 +2220,24 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto handled; goto handled;
} }
break; 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: case WLAN_CATEGORY_MESH_ACTION:
if (!ieee80211_vif_is_mesh(&sdata->vif)) if (!ieee80211_vif_is_mesh(&sdata->vif))
break; break;
......
...@@ -1158,9 +1158,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, ...@@ -1158,9 +1158,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
if (elen >= sizeof(struct ieee80211_meshconf_ie)) if (elen >= sizeof(struct ieee80211_meshconf_ie))
elems->mesh_config = (void *)pos; elems->mesh_config = (void *)pos;
break; break;
case WLAN_EID_PEER_LINK: case WLAN_EID_PEER_MGMT:
elems->peer_link = pos; elems->peering = pos;
elems->peer_link_len = elen; elems->peering_len = elen;
break; break;
case WLAN_EID_PREQ: case WLAN_EID_PREQ:
elems->preq = pos; elems->preq = pos;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment