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 /net/mac80211/mesh_plink.c | |
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>
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r-- | net/mac80211/mesh_plink.c | 89 |
1 files changed, 48 insertions, 41 deletions
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 | ||