aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Pedersen <thomas@cozybit.com>2011-08-12 23:01:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-22 14:46:00 -0400
commit8db098507c5cbe499061d0f6aea426a36e7c72d7 (patch)
treebf7062fff64f56ae376cb16ffa5c3cd85c09296b
parent54ef656b05103f700ff8fc2aaf0382cfd0e54fe4 (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.h18
-rw-r--r--include/net/cfg80211.h4
-rw-r--r--net/mac80211/mesh.c10
-rw-r--r--net/mac80211/mesh_plink.c89
-rw-r--r--net/mac80211/rx.c18
-rw-r--r--net/wireless/util.c6
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;