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>
This commit is contained in:
committed by
John W. Linville
parent
54ef656b05
commit
8db098507c
@@ -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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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,8 +662,14 @@ 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:
|
||||||
mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
|
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;
|
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);
|
||||||
|
@@ -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,
|
|||||||
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,
|
|||||||
* 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);
|
memset(pos, 0, 2);
|
||||||
if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
|
if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
|
||||||
pos = skb_put(skb, 4);
|
/* AID */
|
||||||
/* two-byte status code followed by two-byte AID */
|
pos = skb_put(skb, 2);
|
||||||
memset(pos, 0, 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,
|
|||||||
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);
|
||||||
|
pos += 2;
|
||||||
if (include_plid) {
|
if (include_plid) {
|
||||||
pos += 2;
|
|
||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
/* 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)
|
|||||||
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,
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user