aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mesh.c')
-rw-r--r--net/mac80211/mesh.c213
1 files changed, 137 insertions, 76 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 29e9980c8e60..a7078fdba8ca 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -13,10 +13,6 @@
13#include "ieee80211_i.h" 13#include "ieee80211_i.h"
14#include "mesh.h" 14#include "mesh.h"
15 15
16#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
17#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
18#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ)
19
20#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 16#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
21#define MESHCONF_CAPAB_FORWARDING 0x08 17#define MESHCONF_CAPAB_FORWARDING 0x08
22 18
@@ -27,6 +23,17 @@
27int mesh_allocated; 23int mesh_allocated;
28static struct kmem_cache *rm_cache; 24static struct kmem_cache *rm_cache;
29 25
26#ifdef CONFIG_MAC80211_MESH
27bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
28{
29 return (mgmt->u.action.u.mesh_action.action_code ==
30 WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
31}
32#else
33bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
34{ return false; }
35#endif
36
30void ieee80211s_init(void) 37void ieee80211s_init(void)
31{ 38{
32 mesh_pathtbl_init(); 39 mesh_pathtbl_init();
@@ -193,10 +200,9 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
193 } 200 }
194 201
195 p = kmem_cache_alloc(rm_cache, GFP_ATOMIC); 202 p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
196 if (!p) { 203 if (!p)
197 printk(KERN_DEBUG "o11s: could not allocate RMC entry\n");
198 return 0; 204 return 0;
199 } 205
200 p->seqnum = seqnum; 206 p->seqnum = seqnum;
201 p->exp_time = jiffies + RMC_TIMEOUT; 207 p->exp_time = jiffies + RMC_TIMEOUT;
202 memcpy(p->sa, sa, ETH_ALEN); 208 memcpy(p->sa, sa, ETH_ALEN);
@@ -204,89 +210,136 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
204 return 0; 210 return 0;
205} 211}
206 212
207void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) 213int
214mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
208{ 215{
209 struct ieee80211_local *local = sdata->local; 216 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
210 struct ieee80211_supported_band *sband; 217 u8 *pos, neighbors;
211 u8 *pos; 218 u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
212 int len, i, rate;
213 u8 neighbors;
214
215 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
216 len = sband->n_bitrates;
217 if (len > 8)
218 len = 8;
219 pos = skb_put(skb, len + 2);
220 *pos++ = WLAN_EID_SUPP_RATES;
221 *pos++ = len;
222 for (i = 0; i < len; i++) {
223 rate = sband->bitrates[i].bitrate;
224 *pos++ = (u8) (rate / 5);
225 }
226
227 if (sband->n_bitrates > len) {
228 pos = skb_put(skb, sband->n_bitrates - len + 2);
229 *pos++ = WLAN_EID_EXT_SUPP_RATES;
230 *pos++ = sband->n_bitrates - len;
231 for (i = len; i < sband->n_bitrates; i++) {
232 rate = sband->bitrates[i].bitrate;
233 *pos++ = (u8) (rate / 5);
234 }
235 }
236
237 if (sband->band == IEEE80211_BAND_2GHZ) {
238 pos = skb_put(skb, 2 + 1);
239 *pos++ = WLAN_EID_DS_PARAMS;
240 *pos++ = 1;
241 *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
242 }
243 219
244 pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); 220 if (skb_tailroom(skb) < 2 + meshconf_len)
245 *pos++ = WLAN_EID_MESH_ID; 221 return -ENOMEM;
246 *pos++ = sdata->u.mesh.mesh_id_len;
247 if (sdata->u.mesh.mesh_id_len)
248 memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
249 222
250 pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie)); 223 pos = skb_put(skb, 2 + meshconf_len);
251 *pos++ = WLAN_EID_MESH_CONFIG; 224 *pos++ = WLAN_EID_MESH_CONFIG;
252 *pos++ = sizeof(struct ieee80211_meshconf_ie); 225 *pos++ = meshconf_len;
253 226
254 /* Active path selection protocol ID */ 227 /* Active path selection protocol ID */
255 *pos++ = sdata->u.mesh.mesh_pp_id; 228 *pos++ = ifmsh->mesh_pp_id;
256
257 /* Active path selection metric ID */ 229 /* Active path selection metric ID */
258 *pos++ = sdata->u.mesh.mesh_pm_id; 230 *pos++ = ifmsh->mesh_pm_id;
259
260 /* Congestion control mode identifier */ 231 /* Congestion control mode identifier */
261 *pos++ = sdata->u.mesh.mesh_cc_id; 232 *pos++ = ifmsh->mesh_cc_id;
262
263 /* Synchronization protocol identifier */ 233 /* Synchronization protocol identifier */
264 *pos++ = sdata->u.mesh.mesh_sp_id; 234 *pos++ = ifmsh->mesh_sp_id;
265
266 /* Authentication Protocol identifier */ 235 /* Authentication Protocol identifier */
267 *pos++ = sdata->u.mesh.mesh_auth_id; 236 *pos++ = ifmsh->mesh_auth_id;
268
269 /* Mesh Formation Info - number of neighbors */ 237 /* Mesh Formation Info - number of neighbors */
270 neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks); 238 neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
271 /* Number of neighbor mesh STAs or 15 whichever is smaller */ 239 /* Number of neighbor mesh STAs or 15 whichever is smaller */
272 neighbors = (neighbors > 15) ? 15 : neighbors; 240 neighbors = (neighbors > 15) ? 15 : neighbors;
273 *pos++ = neighbors << 1; 241 *pos++ = neighbors << 1;
274
275 /* Mesh capability */ 242 /* Mesh capability */
276 sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); 243 ifmsh->accepting_plinks = mesh_plink_availables(sdata);
277 *pos = MESHCONF_CAPAB_FORWARDING; 244 *pos = MESHCONF_CAPAB_FORWARDING;
278 *pos++ |= sdata->u.mesh.accepting_plinks ? 245 *pos++ |= ifmsh->accepting_plinks ?
279 MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; 246 MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
280 *pos++ = 0x00; 247 *pos++ = 0x00;
281 248
282 if (sdata->u.mesh.ie) { 249 return 0;
283 int len = sdata->u.mesh.ie_len; 250}
284 const u8 *data = sdata->u.mesh.ie; 251
285 if (skb_tailroom(skb) > len) 252int
286 memcpy(skb_put(skb, len), data, len); 253mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
254{
255 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
256 u8 *pos;
257
258 if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
259 return -ENOMEM;
260
261 pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
262 *pos++ = WLAN_EID_MESH_ID;
263 *pos++ = ifmsh->mesh_id_len;
264 if (ifmsh->mesh_id_len)
265 memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
266
267 return 0;
268}
269
270int
271mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
272{
273 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
274 u8 offset, len;
275 const u8 *data;
276
277 if (!ifmsh->ie || !ifmsh->ie_len)
278 return 0;
279
280 /* fast-forward to vendor IEs */
281 offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
282
283 if (offset) {
284 len = ifmsh->ie_len - offset;
285 data = ifmsh->ie + offset;
286 if (skb_tailroom(skb) < len)
287 return -ENOMEM;
288 memcpy(skb_put(skb, len), data, len);
287 } 289 }
290
291 return 0;
288} 292}
289 293
294int
295mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
296{
297 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
298 u8 len = 0;
299 const u8 *data;
300
301 if (!ifmsh->ie || !ifmsh->ie_len)
302 return 0;
303
304 /* find RSN IE */
305 data = ifmsh->ie;
306 while (data < ifmsh->ie + ifmsh->ie_len) {
307 if (*data == WLAN_EID_RSN) {
308 len = data[1] + 2;
309 break;
310 }
311 data++;
312 }
313
314 if (len) {
315 if (skb_tailroom(skb) < len)
316 return -ENOMEM;
317 memcpy(skb_put(skb, len), data, len);
318 }
319
320 return 0;
321}
322
323int mesh_add_ds_params_ie(struct sk_buff *skb,
324 struct ieee80211_sub_if_data *sdata)
325{
326 struct ieee80211_local *local = sdata->local;
327 struct ieee80211_supported_band *sband;
328 u8 *pos;
329
330 if (skb_tailroom(skb) < 3)
331 return -ENOMEM;
332
333 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
334 if (sband->band == IEEE80211_BAND_2GHZ) {
335 pos = skb_put(skb, 2 + 1);
336 *pos++ = WLAN_EID_DS_PARAMS;
337 *pos++ = 1;
338 *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
339 }
340
341 return 0;
342}
290 343
291static void ieee80211_mesh_path_timer(unsigned long data) 344static void ieee80211_mesh_path_timer(unsigned long data)
292{ 345{
@@ -352,8 +405,7 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
352 memcpy(hdr->addr3, meshsa, ETH_ALEN); 405 memcpy(hdr->addr3, meshsa, ETH_ALEN);
353 return 24; 406 return 24;
354 } else { 407 } else {
355 *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | 408 *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
356 IEEE80211_FCTL_TODS);
357 /* RA TA DA SA */ 409 /* RA TA DA SA */
358 memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */ 410 memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */
359 memcpy(hdr->addr2, meshsa, ETH_ALEN); 411 memcpy(hdr->addr2, meshsa, ETH_ALEN);
@@ -425,7 +477,8 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
425 477
426 mesh_path_tx_root_frame(sdata); 478 mesh_path_tx_root_frame(sdata);
427 mod_timer(&ifmsh->mesh_path_root_timer, 479 mod_timer(&ifmsh->mesh_path_root_timer,
428 round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); 480 round_jiffies(TU_TO_EXP_TIME(
481 ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
429} 482}
430 483
431#ifdef CONFIG_PM 484#ifdef CONFIG_PM
@@ -433,7 +486,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
433{ 486{
434 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 487 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
435 488
436 /* use atomic bitops in case both timers fire at the same time */ 489 /* use atomic bitops in case all timers fire at the same time */
437 490
438 if (del_timer_sync(&ifmsh->housekeeping_timer)) 491 if (del_timer_sync(&ifmsh->housekeeping_timer))
439 set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); 492 set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -557,11 +610,18 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
557 struct ieee80211_rx_status *rx_status) 610 struct ieee80211_rx_status *rx_status)
558{ 611{
559 switch (mgmt->u.action.category) { 612 switch (mgmt->u.action.category) {
560 case WLAN_CATEGORY_MESH_ACTION: 613 case WLAN_CATEGORY_SELF_PROTECTED:
561 mesh_rx_plink_frame(sdata, mgmt, len, rx_status); 614 switch (mgmt->u.action.u.self_prot.action_code) {
615 case WLAN_SP_MESH_PEERING_OPEN:
616 case WLAN_SP_MESH_PEERING_CLOSE:
617 case WLAN_SP_MESH_PEERING_CONFIRM:
618 mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
619 break;
620 }
562 break; 621 break;
563 case WLAN_CATEGORY_MESH_PATH_SEL: 622 case WLAN_CATEGORY_MESH_ACTION:
564 mesh_rx_path_sel_frame(sdata, mgmt, len); 623 if (mesh_action_is_path_sel(mgmt))
624 mesh_rx_path_sel_frame(sdata, mgmt, len);
565 break; 625 break;
566 } 626 }
567} 627}
@@ -633,6 +693,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
633 ifmsh->accepting_plinks = true; 693 ifmsh->accepting_plinks = true;
634 ifmsh->preq_id = 0; 694 ifmsh->preq_id = 0;
635 ifmsh->sn = 0; 695 ifmsh->sn = 0;
696 ifmsh->num_gates = 0;
636 atomic_set(&ifmsh->mpaths, 0); 697 atomic_set(&ifmsh->mpaths, 0);
637 mesh_rmc_init(sdata); 698 mesh_rmc_init(sdata);
638 ifmsh->last_preq = jiffies; 699 ifmsh->last_preq = jiffies;