Skip to content

Commit

Permalink
mac80211: update mesh peering frame format
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Thomas Pedersen authored and John W. Linville committed Aug 22, 2011
1 parent 54ef656 commit 8db0985
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 66 deletions.
18 changes: 0 additions & 18 deletions include/linux/ieee80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
10 changes: 8 additions & 2 deletions net/mac80211/mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
89 changes: 48 additions & 41 deletions net/mac80211/mesh_plink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand All @@ -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) ||
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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();

Expand Down
18 changes: 18 additions & 0 deletions net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions net/wireless/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 8db0985

Please sign in to comment.