diff options
author | Thomas Pedersen <thomas@cozybit.com> | 2011-08-12 23:01:00 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-08-22 14:46:00 -0400 |
commit | 8db098507c5cbe499061d0f6aea426a36e7c72d7 (patch) | |
tree | bf7062fff64f56ae376cb16ffa5c3cd85c09296b | |
parent | 54ef656b05103f700ff8fc2aaf0382cfd0e54fe4 (diff) |
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>
-rw-r--r-- | include/linux/ieee80211.h | 18 | ||||
-rw-r--r-- | include/net/cfg80211.h | 4 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 10 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 89 | ||||
-rw-r--r-- | net/mac80211/rx.c | 18 | ||||
-rw-r--r-- | net/wireless/util.c | 6 |
6 files changed, 79 insertions, 66 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 0750987f2a1d..819954a607f1 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -736,19 +736,6 @@ struct ieee80211_mgmt { | |||
736 | __le16 params; | 736 | __le16 params; |
737 | __le16 reason_code; | 737 | __le16 reason_code; |
738 | } __attribute__((packed)) delba; | 738 | } __attribute__((packed)) delba; |
739 | struct{ | ||
740 | u8 action_code; | ||
741 | /* capab_info for open and confirm, | ||
742 | * reason for close | ||
743 | */ | ||
744 | __le16 aux; | ||
745 | /* Followed in plink_confirm by status | ||
746 | * code, AID and supported rates, | ||
747 | * and directly by supported rates in | ||
748 | * plink_open and plink_close | ||
749 | */ | ||
750 | u8 variable[0]; | ||
751 | } __attribute__((packed)) plink_action; | ||
752 | struct { | 739 | struct { |
753 | u8 action_code; | 740 | u8 action_code; |
754 | u8 variable[0]; | 741 | u8 variable[0]; |
@@ -1200,11 +1187,6 @@ enum ieee80211_eid { | |||
1200 | WLAN_EID_MESH_ID = 114, | 1187 | WLAN_EID_MESH_ID = 114, |
1201 | WLAN_EID_LINK_METRIC_REPORT = 115, | 1188 | WLAN_EID_LINK_METRIC_REPORT = 115, |
1202 | WLAN_EID_CONGESTION_NOTIFICATION = 116, | 1189 | WLAN_EID_CONGESTION_NOTIFICATION = 116, |
1203 | /* Note that the Peer Link IE has been replaced with the similar | ||
1204 | * Peer Management IE. We will keep the former definition until mesh | ||
1205 | * code is changed to comply with latest 802.11s drafts. | ||
1206 | */ | ||
1207 | WLAN_EID_PEER_LINK = 55, /* no longer in 802.11s drafts */ | ||
1208 | WLAN_EID_PEER_MGMT = 117, | 1190 | WLAN_EID_PEER_MGMT = 117, |
1209 | WLAN_EID_CHAN_SWITCH_PARAM = 118, | 1191 | WLAN_EID_CHAN_SWITCH_PARAM = 118, |
1210 | WLAN_EID_MESH_AWAKE_WINDOW = 119, | 1192 | WLAN_EID_MESH_AWAKE_WINDOW = 119, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d86a15d87e58..d29d11a31f5a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -2291,7 +2291,7 @@ struct ieee802_11_elems { | |||
2291 | struct ieee80211_ht_info *ht_info_elem; | 2291 | struct ieee80211_ht_info *ht_info_elem; |
2292 | struct ieee80211_meshconf_ie *mesh_config; | 2292 | struct ieee80211_meshconf_ie *mesh_config; |
2293 | u8 *mesh_id; | 2293 | u8 *mesh_id; |
2294 | u8 *peer_link; | 2294 | u8 *peering; |
2295 | u8 *preq; | 2295 | u8 *preq; |
2296 | u8 *prep; | 2296 | u8 *prep; |
2297 | u8 *perr; | 2297 | u8 *perr; |
@@ -2318,7 +2318,7 @@ struct ieee802_11_elems { | |||
2318 | u8 wmm_info_len; | 2318 | u8 wmm_info_len; |
2319 | u8 wmm_param_len; | 2319 | u8 wmm_param_len; |
2320 | u8 mesh_id_len; | 2320 | u8 mesh_id_len; |
2321 | u8 peer_link_len; | 2321 | u8 peering_len; |
2322 | u8 preq_len; | 2322 | u8 preq_len; |
2323 | u8 prep_len; | 2323 | u8 prep_len; |
2324 | u8 perr_len; | 2324 | u8 perr_len; |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 1990869033e1..da5e981c4833 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -662,8 +662,14 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
662 | struct ieee80211_rx_status *rx_status) | 662 | struct ieee80211_rx_status *rx_status) |
663 | { | 663 | { |
664 | switch (mgmt->u.action.category) { | 664 | switch (mgmt->u.action.category) { |
665 | case WLAN_CATEGORY_MESH_ACTION: | 665 | case WLAN_CATEGORY_SELF_PROTECTED: |
666 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 666 | switch (mgmt->u.action.u.self_prot.action_code) { |
667 | case WLAN_SP_MESH_PEERING_OPEN: | ||
668 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
669 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
670 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | ||
671 | break; | ||
672 | } | ||
667 | break; | 673 | break; |
668 | case WLAN_CATEGORY_MESH_PATH_SEL: | 674 | case WLAN_CATEGORY_MESH_PATH_SEL: |
669 | mesh_rx_path_sel_frame(sdata, mgmt, len); | 675 | mesh_rx_path_sel_frame(sdata, mgmt, len); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 2cf22127d324..1a00d0f701c3 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -19,8 +19,8 @@ | |||
19 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) | 19 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #define PLINK_GET_LLID(p) (p + 4) | 22 | #define PLINK_GET_LLID(p) (p + 2) |
23 | #define PLINK_GET_PLID(p) (p + 6) | 23 | #define PLINK_GET_PLID(p) (p + 4) |
24 | 24 | ||
25 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | 25 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ |
26 | jiffies + HZ * t / 1000)) | 26 | jiffies + HZ * t / 1000)) |
@@ -147,9 +147,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
147 | sdata->u.mesh.ie_len); | 147 | sdata->u.mesh.ie_len); |
148 | struct ieee80211_mgmt *mgmt; | 148 | struct ieee80211_mgmt *mgmt; |
149 | bool include_plid = false; | 149 | bool include_plid = false; |
150 | static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; | 150 | int ie_len = 4; |
151 | u16 peering_proto = 0; | ||
151 | u8 *pos; | 152 | u8 *pos; |
152 | int ie_len; | ||
153 | 153 | ||
154 | if (!skb) | 154 | if (!skb) |
155 | return -1; | 155 | return -1; |
@@ -158,24 +158,23 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
158 | * common action part (1) | 158 | * common action part (1) |
159 | */ | 159 | */ |
160 | mgmt = (struct ieee80211_mgmt *) | 160 | mgmt = (struct ieee80211_mgmt *) |
161 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action)); | 161 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot)); |
162 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action)); | 162 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot)); |
163 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 163 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
164 | IEEE80211_STYPE_ACTION); | 164 | IEEE80211_STYPE_ACTION); |
165 | memcpy(mgmt->da, da, ETH_ALEN); | 165 | memcpy(mgmt->da, da, ETH_ALEN); |
166 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | 166 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
167 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | 167 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
168 | mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION; | 168 | mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED; |
169 | mgmt->u.action.u.plink_action.action_code = action; | 169 | mgmt->u.action.u.self_prot.action_code = action; |
170 | 170 | ||
171 | if (action == WLAN_SP_MESH_PEERING_CLOSE) | 171 | if (action != WLAN_SP_MESH_PEERING_CLOSE) { |
172 | mgmt->u.action.u.plink_action.aux = reason; | 172 | /* capability info */ |
173 | else { | 173 | pos = skb_put(skb, 2); |
174 | mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0); | 174 | memset(pos, 0, 2); |
175 | if (action == WLAN_SP_MESH_PEERING_CONFIRM) { | 175 | if (action == WLAN_SP_MESH_PEERING_CONFIRM) { |
176 | pos = skb_put(skb, 4); | 176 | /* AID */ |
177 | /* two-byte status code followed by two-byte AID */ | 177 | pos = skb_put(skb, 2); |
178 | memset(pos, 0, 2); | ||
179 | memcpy(pos + 2, &plid, 2); | 178 | memcpy(pos + 2, &plid, 2); |
180 | } | 179 | } |
181 | if (mesh_add_srates_ie(skb, sdata) || | 180 | if (mesh_add_srates_ie(skb, sdata) || |
@@ -184,42 +183,50 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
184 | mesh_add_meshid_ie(skb, sdata) || | 183 | mesh_add_meshid_ie(skb, sdata) || |
185 | mesh_add_meshconf_ie(skb, sdata)) | 184 | mesh_add_meshconf_ie(skb, sdata)) |
186 | return -1; | 185 | return -1; |
186 | } else { /* WLAN_SP_MESH_PEERING_CLOSE */ | ||
187 | if (mesh_add_meshid_ie(skb, sdata)) | ||
188 | return -1; | ||
187 | } | 189 | } |
188 | 190 | ||
189 | /* Add Peer Link Management element */ | 191 | /* Add Mesh Peering Management element */ |
190 | switch (action) { | 192 | switch (action) { |
191 | case WLAN_SP_MESH_PEERING_OPEN: | 193 | case WLAN_SP_MESH_PEERING_OPEN: |
192 | ie_len = 6; | ||
193 | break; | 194 | break; |
194 | case WLAN_SP_MESH_PEERING_CONFIRM: | 195 | case WLAN_SP_MESH_PEERING_CONFIRM: |
195 | ie_len = 8; | 196 | ie_len += 2; |
196 | include_plid = true; | 197 | include_plid = true; |
197 | break; | 198 | break; |
198 | case WLAN_SP_MESH_PEERING_CLOSE: | 199 | case WLAN_SP_MESH_PEERING_CLOSE: |
199 | default: | 200 | if (plid) { |
200 | if (!plid) | 201 | ie_len += 2; |
201 | ie_len = 8; | ||
202 | else { | ||
203 | ie_len = 10; | ||
204 | include_plid = true; | 202 | include_plid = true; |
205 | } | 203 | } |
204 | ie_len += 2; /* reason code */ | ||
206 | break; | 205 | break; |
206 | default: | ||
207 | return -EINVAL; | ||
207 | } | 208 | } |
208 | 209 | ||
210 | if (WARN_ON(skb_tailroom(skb) < 2 + ie_len)) | ||
211 | return -ENOMEM; | ||
212 | |||
209 | pos = skb_put(skb, 2 + ie_len); | 213 | pos = skb_put(skb, 2 + ie_len); |
210 | *pos++ = WLAN_EID_PEER_LINK; | 214 | *pos++ = WLAN_EID_PEER_MGMT; |
211 | *pos++ = ie_len; | 215 | *pos++ = ie_len; |
212 | memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto)); | 216 | memcpy(pos, &peering_proto, 2); |
213 | pos += 4; | 217 | pos += 2; |
214 | memcpy(pos, &llid, 2); | 218 | memcpy(pos, &llid, 2); |
219 | pos += 2; | ||
215 | if (include_plid) { | 220 | if (include_plid) { |
216 | pos += 2; | ||
217 | memcpy(pos, &plid, 2); | 221 | memcpy(pos, &plid, 2); |
222 | pos += 2; | ||
218 | } | 223 | } |
219 | if (action == WLAN_SP_MESH_PEERING_CLOSE) { | 224 | if (action == WLAN_SP_MESH_PEERING_CLOSE) { |
220 | pos += 2; | ||
221 | memcpy(pos, &reason, 2); | 225 | memcpy(pos, &reason, 2); |
226 | pos += 2; | ||
222 | } | 227 | } |
228 | if (mesh_add_vendor_ies(skb, sdata)) | ||
229 | return -1; | ||
223 | 230 | ||
224 | ieee80211_tx_skb(sdata, skb); | 231 | ieee80211_tx_skb(sdata, skb); |
225 | return 0; | 232 | return 0; |
@@ -437,15 +444,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
437 | return; | 444 | return; |
438 | } | 445 | } |
439 | 446 | ||
440 | baseaddr = mgmt->u.action.u.plink_action.variable; | 447 | baseaddr = mgmt->u.action.u.self_prot.variable; |
441 | baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; | 448 | baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; |
442 | if (mgmt->u.action.u.plink_action.action_code == | 449 | if (mgmt->u.action.u.self_prot.action_code == |
443 | WLAN_SP_MESH_PEERING_CONFIRM) { | 450 | WLAN_SP_MESH_PEERING_CONFIRM) { |
444 | baseaddr += 4; | 451 | baseaddr += 4; |
445 | baselen += 4; | 452 | baselen += 4; |
446 | } | 453 | } |
447 | ieee802_11_parse_elems(baseaddr, len - baselen, &elems); | 454 | ieee802_11_parse_elems(baseaddr, len - baselen, &elems); |
448 | if (!elems.peer_link) { | 455 | if (!elems.peering) { |
449 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); | 456 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); |
450 | return; | 457 | return; |
451 | } | 458 | } |
@@ -455,12 +462,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
455 | return; | 462 | return; |
456 | } | 463 | } |
457 | 464 | ||
458 | ftype = mgmt->u.action.u.plink_action.action_code; | 465 | ftype = mgmt->u.action.u.self_prot.action_code; |
459 | ie_len = elems.peer_link_len; | 466 | ie_len = elems.peering_len; |
460 | if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 6) || | 467 | if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || |
461 | (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 8) || | 468 | (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || |
462 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 8 | 469 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 |
463 | && ie_len != 10)) { | 470 | && ie_len != 8)) { |
464 | mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", | 471 | mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", |
465 | ftype, ie_len); | 472 | ftype, ie_len); |
466 | return; | 473 | return; |
@@ -474,10 +481,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
474 | /* Note the lines below are correct, the llid in the frame is the plid | 481 | /* Note the lines below are correct, the llid in the frame is the plid |
475 | * from the point of view of this host. | 482 | * from the point of view of this host. |
476 | */ | 483 | */ |
477 | memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); | 484 | memcpy(&plid, PLINK_GET_LLID(elems.peering), 2); |
478 | if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || | 485 | if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || |
479 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 10)) | 486 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) |
480 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); | 487 | memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); |
481 | 488 | ||
482 | rcu_read_lock(); | 489 | rcu_read_lock(); |
483 | 490 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fe2c2a717793..3fb6dea36536 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -2220,6 +2220,24 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2220 | goto handled; | 2220 | goto handled; |
2221 | } | 2221 | } |
2222 | break; | 2222 | break; |
2223 | case WLAN_CATEGORY_SELF_PROTECTED: | ||
2224 | switch (mgmt->u.action.u.self_prot.action_code) { | ||
2225 | case WLAN_SP_MESH_PEERING_OPEN: | ||
2226 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
2227 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
2228 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | ||
2229 | goto invalid; | ||
2230 | if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) | ||
2231 | /* userspace handles this frame */ | ||
2232 | break; | ||
2233 | goto queue; | ||
2234 | case WLAN_SP_MGK_INFORM: | ||
2235 | case WLAN_SP_MGK_ACK: | ||
2236 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | ||
2237 | goto invalid; | ||
2238 | break; | ||
2239 | } | ||
2240 | break; | ||
2223 | case WLAN_CATEGORY_MESH_ACTION: | 2241 | case WLAN_CATEGORY_MESH_ACTION: |
2224 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2242 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2225 | break; | 2243 | break; |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 844ddb0aa653..eef82f79554d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -1158,9 +1158,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
1158 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) | 1158 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) |
1159 | elems->mesh_config = (void *)pos; | 1159 | elems->mesh_config = (void *)pos; |
1160 | break; | 1160 | break; |
1161 | case WLAN_EID_PEER_LINK: | 1161 | case WLAN_EID_PEER_MGMT: |
1162 | elems->peer_link = pos; | 1162 | elems->peering = pos; |
1163 | elems->peer_link_len = elen; | 1163 | elems->peering_len = elen; |
1164 | break; | 1164 | break; |
1165 | case WLAN_EID_PREQ: | 1165 | case WLAN_EID_PREQ: |
1166 | elems->preq = pos; | 1166 | elems->preq = pos; |