Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+0 −18
Original line number Diff line number Diff line
@@ -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,
+2 −2
Original line number Diff line number Diff line
@@ -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;
+8 −2
Original line number Diff line number Diff line
@@ -662,9 +662,15 @@ 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:
	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);
		break;
+48 −41
Original line number Diff line number Diff line
@@ -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_CONFIRM) {
			pos = skb_put(skb, 4);
			/* two-byte status code followed by two-byte AID */
	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) {
			/* 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);
	if (include_plid) {
	pos += 2;
	if (include_plid) {
		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();

+18 −0
Original line number Diff line number Diff line
@@ -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;
Loading