Blame view
net/mac80211/mesh.c
21.4 KB
2e3c87368 mac80211: support... |
1 |
/* |
264d9b7d8 mac80211: update ... |
2 |
* Copyright (c) 2008, 2009 open80211s Ltd. |
2e3c87368 mac80211: support... |
3 4 5 6 7 8 9 |
* Authors: Luis Carlos Cobo <luisca@cozybit.com> * Javier Cardona <javier@cozybit.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ |
5a0e3ad6a include cleanup: ... |
10 |
#include <linux/slab.h> |
51ceddade mac80211: use 4-b... |
11 |
#include <asm/unaligned.h> |
2e3c87368 mac80211: support... |
12 13 |
#include "ieee80211_i.h" #include "mesh.h" |
3491707a0 mac80211: update ... |
14 15 |
#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 #define MESHCONF_CAPAB_FORWARDING 0x08 |
2e3c87368 mac80211: support... |
16 |
|
5bb644a0f mac80211: cancel/... |
17 18 |
#define TMR_RUNNING_HK 0 #define TMR_RUNNING_MP 1 |
e304bfd30 mac80211: impleme... |
19 |
#define TMR_RUNNING_MPR 2 |
5bb644a0f mac80211: cancel/... |
20 |
|
2e3c87368 mac80211: support... |
21 22 |
int mesh_allocated; static struct kmem_cache *rm_cache; |
25d49e4d6 mac80211: update ... |
23 24 25 26 27 28 29 30 31 32 |
#ifdef CONFIG_MAC80211_MESH bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt) { return (mgmt->u.action.u.mesh_action.action_code == WLAN_MESH_ACTION_HWMP_PATH_SELECTION); } #else bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt) { return false; } #endif |
2e3c87368 mac80211: support... |
33 34 35 36 37 38 39 40 41 42 43 44 45 |
void ieee80211s_init(void) { mesh_pathtbl_init(); mesh_allocated = 1; rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry), 0, 0, NULL); } void ieee80211s_stop(void) { mesh_pathtbl_unregister(); kmem_cache_destroy(rm_cache); } |
472dbc45d mac80211: split o... |
46 47 48 49 50 |
static void ieee80211_mesh_housekeeping_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata = (void *) data; struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
6b9ac4425 mesh: use set_bit... |
51 |
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
5bb644a0f mac80211: cancel/... |
52 53 54 55 56 |
if (local->quiescing) { set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); return; } |
64592c8fc mac80211: use com... |
57 |
ieee80211_queue_work(&local->hw, &sdata->work); |
472dbc45d mac80211: split o... |
58 |
} |
2e3c87368 mac80211: support... |
59 60 61 62 |
/** * mesh_matches_local - check if the config of a mesh point matches ours * * @ie: information elements of a management frame from the mesh peer |
f698d856f replace net_devic... |
63 |
* @sdata: local mesh subif |
2e3c87368 mac80211: support... |
64 65 66 67 |
* * This function checks if the mesh configuration of a mesh point matches the * local mesh configuration, i.e. if both nodes belong to the same mesh network. */ |
f698d856f replace net_devic... |
68 |
bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
69 |
{ |
472dbc45d mac80211: split o... |
70 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
739522baa mac80211: set HT ... |
71 |
struct ieee80211_local *local = sdata->local; |
2e3c87368 mac80211: support... |
72 |
|
2e3c87368 mac80211: support... |
73 74 75 76 77 78 79 80 81 82 |
/* * As support for each feature is added, check for matching * - On mesh config capabilities * - Power Save Support En * - Sync support enabled * - Sync support active * - Sync support required from peer * - MDA enabled * - Power management control on fc */ |
739522baa mac80211: set HT ... |
83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
if (!(ifmsh->mesh_id_len == ie->mesh_id_len && memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) && (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) && (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) && (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) && (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) goto mismatch; /* disallow peering with mismatched channel types for now */ if (ie->ht_info_elem && (local->_oper_channel_type != ieee80211_ht_info_to_channel_type(ie->ht_info_elem))) goto mismatch; |
2e3c87368 mac80211: support... |
97 |
|
739522baa mac80211: set HT ... |
98 99 |
return true; mismatch: |
2e3c87368 mac80211: support... |
100 101 102 103 104 105 106 |
return false; } /** * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links * * @ie: information elements of a management frame from the mesh peer |
2e3c87368 mac80211: support... |
107 |
*/ |
f698d856f replace net_devic... |
108 |
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
2e3c87368 mac80211: support... |
109 |
{ |
136cfa286 mac80211: use a s... |
110 |
return (ie->mesh_config->meshconf_cap & |
3491707a0 mac80211: update ... |
111 |
MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; |
2e3c87368 mac80211: support... |
112 113 114 115 116 |
} /** * mesh_accept_plinks_update: update accepting_plink in local mesh beacons * |
d0709a651 mac80211: RCU-ify... |
117 |
* @sdata: mesh interface in which mesh beacons are going to be updated |
2e3c87368 mac80211: support... |
118 |
*/ |
d0709a651 mac80211: RCU-ify... |
119 |
void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
120 |
{ |
2e3c87368 mac80211: support... |
121 122 123 124 |
bool free_plinks; /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, * the mesh interface might be able to establish plinks with peers that |
b4e08ea14 mac80211: add PLI... |
125 126 127 |
* are already on the table but are not on PLINK_ESTAB state. However, * in general the mesh interface is not accepting peer link requests * from new peers, and that must be reflected in the beacon |
2e3c87368 mac80211: support... |
128 129 |
*/ free_plinks = mesh_plink_availables(sdata); |
472dbc45d mac80211: split o... |
130 131 |
if (free_plinks != sdata->u.mesh.accepting_plinks) ieee80211_mesh_housekeeping_timer((unsigned long) sdata); |
2e3c87368 mac80211: support... |
132 |
} |
f698d856f replace net_devic... |
133 |
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
134 |
{ |
2e3c87368 mac80211: support... |
135 |
int i; |
472dbc45d mac80211: split o... |
136 137 |
sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); if (!sdata->u.mesh.rmc) |
2e3c87368 mac80211: support... |
138 |
return -ENOMEM; |
472dbc45d mac80211: split o... |
139 |
sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; |
2e3c87368 mac80211: support... |
140 |
for (i = 0; i < RMC_BUCKETS; i++) |
472dbc45d mac80211: split o... |
141 |
INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list); |
2e3c87368 mac80211: support... |
142 143 |
return 0; } |
f698d856f replace net_devic... |
144 |
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
145 |
{ |
472dbc45d mac80211: split o... |
146 |
struct mesh_rmc *rmc = sdata->u.mesh.rmc; |
2e3c87368 mac80211: support... |
147 148 |
struct rmc_entry *p, *n; int i; |
472dbc45d mac80211: split o... |
149 |
if (!sdata->u.mesh.rmc) |
2e3c87368 mac80211: support... |
150 151 152 153 154 155 156 157 158 |
return; for (i = 0; i < RMC_BUCKETS; i++) list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) { list_del(&p->list); kmem_cache_free(rm_cache, p); } kfree(rmc); |
472dbc45d mac80211: split o... |
159 |
sdata->u.mesh.rmc = NULL; |
2e3c87368 mac80211: support... |
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
} /** * mesh_rmc_check - Check frame in recent multicast cache and add if absent. * * @sa: source address * @mesh_hdr: mesh_header * * Returns: 0 if the frame is not in the cache, nonzero otherwise. * * Checks using the source address and the mesh sequence number if we have * received this frame lately. If the frame is not in the cache, it is added to * it. */ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, |
f698d856f replace net_devic... |
175 |
struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
176 |
{ |
472dbc45d mac80211: split o... |
177 |
struct mesh_rmc *rmc = sdata->u.mesh.rmc; |
2e3c87368 mac80211: support... |
178 179 180 181 182 183 |
u32 seqnum = 0; int entries = 0; u8 idx; struct rmc_entry *p, *n; /* Don't care about endianness since only match matters */ |
51ceddade mac80211: use 4-b... |
184 185 |
memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask; |
2e3c87368 mac80211: support... |
186 187 188 189 190 191 192 |
list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) { ++entries; if (time_after(jiffies, p->exp_time) || (entries == RMC_QUEUE_MAX_LEN)) { list_del(&p->list); kmem_cache_free(rm_cache, p); --entries; |
f64f9e719 net: Move && and ... |
193 194 |
} else if ((seqnum == p->seqnum) && (memcmp(sa, p->sa, ETH_ALEN) == 0)) |
2e3c87368 mac80211: support... |
195 196 197 198 |
return -1; } p = kmem_cache_alloc(rm_cache, GFP_ATOMIC); |
d15b84590 mac80211: Remove ... |
199 |
if (!p) |
2e3c87368 mac80211: support... |
200 |
return 0; |
d15b84590 mac80211: Remove ... |
201 |
|
2e3c87368 mac80211: support... |
202 203 204 205 206 207 |
p->seqnum = seqnum; p->exp_time = jiffies + RMC_TIMEOUT; memcpy(p->sa, sa, ETH_ALEN); list_add(&p->list, &rmc->bucket[idx].list); return 0; } |
082ebb0c2 mac80211: fix mes... |
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
int mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 *pos, neighbors; u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie); if (skb_tailroom(skb) < 2 + meshconf_len) return -ENOMEM; pos = skb_put(skb, 2 + meshconf_len); *pos++ = WLAN_EID_MESH_CONFIG; *pos++ = meshconf_len; /* Active path selection protocol ID */ *pos++ = ifmsh->mesh_pp_id; /* Active path selection metric ID */ *pos++ = ifmsh->mesh_pm_id; /* Congestion control mode identifier */ *pos++ = ifmsh->mesh_cc_id; /* Synchronization protocol identifier */ *pos++ = ifmsh->mesh_sp_id; /* Authentication Protocol identifier */ *pos++ = ifmsh->mesh_auth_id; /* Mesh Formation Info - number of neighbors */ neighbors = atomic_read(&ifmsh->mshstats.estab_plinks); /* Number of neighbor mesh STAs or 15 whichever is smaller */ neighbors = (neighbors > 15) ? 15 : neighbors; *pos++ = neighbors << 1; /* Mesh capability */ ifmsh->accepting_plinks = mesh_plink_availables(sdata); *pos = MESHCONF_CAPAB_FORWARDING; *pos++ |= ifmsh->accepting_plinks ? MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; *pos++ = 0x00; return 0; } int mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 *pos; if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len) return -ENOMEM; pos = skb_put(skb, 2 + ifmsh->mesh_id_len); *pos++ = WLAN_EID_MESH_ID; *pos++ = ifmsh->mesh_id_len; if (ifmsh->mesh_id_len) memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len); return 0; } int mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 offset, len; const u8 *data; if (!ifmsh->ie || !ifmsh->ie_len) return 0; /* fast-forward to vendor IEs */ offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0); if (offset) { len = ifmsh->ie_len - offset; data = ifmsh->ie + offset; if (skb_tailroom(skb) < len) return -ENOMEM; memcpy(skb_put(skb, len), data, len); } return 0; } int mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 len = 0; const u8 *data; if (!ifmsh->ie || !ifmsh->ie_len) return 0; /* find RSN IE */ data = ifmsh->ie; while (data < ifmsh->ie + ifmsh->ie_len) { if (*data == WLAN_EID_RSN) { len = data[1] + 2; break; } data++; } if (len) { if (skb_tailroom(skb) < len) return -ENOMEM; memcpy(skb_put(skb, len), data, len); } return 0; } |
082ebb0c2 mac80211: fix mes... |
317 318 319 320 321 322 |
int mesh_add_ds_params_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; u8 *pos; |
2e3c87368 mac80211: support... |
323 |
|
082ebb0c2 mac80211: fix mes... |
324 325 326 327 |
if (skb_tailroom(skb) < 3) return -ENOMEM; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
be125c60e mac80211: add the... |
328 329 330 331 332 333 |
if (sband->band == IEEE80211_BAND_2GHZ) { pos = skb_put(skb, 2 + 1); *pos++ = WLAN_EID_DS_PARAMS; *pos++ = 1; *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); } |
082ebb0c2 mac80211: fix mes... |
334 |
return 0; |
2e3c87368 mac80211: support... |
335 |
} |
176f36086 mac80211: add HT ... |
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
int mesh_add_ht_cap_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; u8 *pos; sband = local->hw.wiphy->bands[local->oper_channel->band]; if (!sband->ht_cap.ht_supported || local->_oper_channel_type == NL80211_CHAN_NO_HT) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) return -ENOMEM; pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap)); |
ef96a8420 mac80211: Support... |
352 |
ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); |
176f36086 mac80211: add HT ... |
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
return 0; } int mesh_add_ht_info_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_channel *channel = local->oper_channel; enum nl80211_channel_type channel_type = local->_oper_channel_type; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[channel->band]; struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; u8 *pos; if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_info)) return -ENOMEM; pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_info)); ieee80211_ie_build_ht_info(pos, ht_cap, channel, channel_type); return 0; } |
2e3c87368 mac80211: support... |
379 380 381 382 |
static void ieee80211_mesh_path_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata = (struct ieee80211_sub_if_data *) data; |
472dbc45d mac80211: split o... |
383 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
133b82263 mac80211: make ma... |
384 |
struct ieee80211_local *local = sdata->local; |
2e3c87368 mac80211: support... |
385 |
|
5bb644a0f mac80211: cancel/... |
386 387 388 389 |
if (local->quiescing) { set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); return; } |
64592c8fc mac80211: use com... |
390 |
ieee80211_queue_work(&local->hw, &sdata->work); |
2e3c87368 mac80211: support... |
391 |
} |
e304bfd30 mac80211: impleme... |
392 393 394 395 396 397 398 399 400 401 402 403 404 |
static void ieee80211_mesh_path_root_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata = (struct ieee80211_sub_if_data *) data; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); if (local->quiescing) { set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); return; } |
64592c8fc mac80211: use com... |
405 |
ieee80211_queue_work(&local->hw, &sdata->work); |
e304bfd30 mac80211: impleme... |
406 |
} |
63c5723bc mac80211: add nl8... |
407 408 409 410 411 412 413 414 415 416 |
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) { if (ifmsh->mshcfg.dot11MeshHWMPRootMode) set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); else { clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); /* stop running timer */ del_timer_sync(&ifmsh->mesh_path_root_timer); } } |
902acc789 mac80211: clean u... |
417 |
/** |
3c5772a52 mac80211: Use 3-a... |
418 419 420 421 422 423 424 425 426 |
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame * @hdr: 802.11 frame header * @fc: frame control field * @meshda: destination address in the mesh * @meshsa: source address address in the mesh. Same as TA, as frame is * locally originated. * * Return the length of the 802.11 (does not include a mesh control header) */ |
15ff63653 mac80211: use fix... |
427 428 429 |
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, const u8 *meshda, const u8 *meshsa) { |
3c5772a52 mac80211: Use 3-a... |
430 431 432 433 434 435 436 437 |
if (is_multicast_ether_addr(meshda)) { *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA TA SA */ memcpy(hdr->addr1, meshda, ETH_ALEN); memcpy(hdr->addr2, meshsa, ETH_ALEN); memcpy(hdr->addr3, meshsa, ETH_ALEN); return 24; } else { |
2154c81c3 mac80211: Mesh da... |
438 |
*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
3c5772a52 mac80211: Use 3-a... |
439 440 441 442 443 444 445 446 447 448 |
/* RA TA DA SA */ memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */ memcpy(hdr->addr2, meshsa, ETH_ALEN); memcpy(hdr->addr3, meshda, ETH_ALEN); memcpy(hdr->addr4, meshsa, ETH_ALEN); return 30; } } /** |
902acc789 mac80211: clean u... |
449 450 451 |
* ieee80211_new_mesh_header - create a new mesh header * @meshhdr: uninitialized mesh header * @sdata: mesh interface to be used |
61ad53945 mac80211: Remove ... |
452 453 454 455 456 |
* @addr4or5: 1st address in the ae header, which may correspond to address 4 * (if addr6 is NULL) or address 5 (if addr6 is present). It may * be NULL. * @addr6: 2nd address in the ae header, which corresponds to addr6 of the * mesh frame |
902acc789 mac80211: clean u... |
457 458 459 460 |
* * Return the header length. */ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
61ad53945 mac80211: Remove ... |
461 462 |
struct ieee80211_sub_if_data *sdata, char *addr4or5, char *addr6) |
902acc789 mac80211: clean u... |
463 |
{ |
3c5772a52 mac80211: Use 3-a... |
464 |
int aelen = 0; |
61ad53945 mac80211: Remove ... |
465 |
BUG_ON(!addr4or5 && addr6); |
0c3cee72a net/mac80211: Cor... |
466 |
memset(meshhdr, 0, sizeof(*meshhdr)); |
472dbc45d mac80211: split o... |
467 468 469 |
meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); sdata->u.mesh.mesh_seqnum++; |
61ad53945 mac80211: Remove ... |
470 |
if (addr4or5 && !addr6) { |
3c5772a52 mac80211: Use 3-a... |
471 472 |
meshhdr->flags |= MESH_FLAGS_AE_A4; aelen += ETH_ALEN; |
61ad53945 mac80211: Remove ... |
473 474 |
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); } else if (addr4or5 && addr6) { |
3c5772a52 mac80211: Use 3-a... |
475 476 |
meshhdr->flags |= MESH_FLAGS_AE_A5_A6; aelen += 2 * ETH_ALEN; |
61ad53945 mac80211: Remove ... |
477 478 |
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); |
3c5772a52 mac80211: Use 3-a... |
479 480 |
} return 6 + aelen; |
902acc789 mac80211: clean u... |
481 |
} |
472dbc45d mac80211: split o... |
482 483 484 485 486 487 488 489 |
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_mesh *ifmsh) { bool free_plinks; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: running mesh housekeeping ", |
47846c9b0 mac80211: reduce ... |
490 |
sdata->name); |
472dbc45d mac80211: split o... |
491 492 493 494 495 496 497 |
#endif ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); mesh_path_expire(sdata); free_plinks = mesh_plink_availables(sdata); if (free_plinks != sdata->u.mesh.accepting_plinks) |
2d0ddec5b mac80211: unify c... |
498 |
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
472dbc45d mac80211: split o... |
499 |
|
472dbc45d mac80211: split o... |
500 501 502 |
mod_timer(&ifmsh->housekeeping_timer, round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); } |
e304bfd30 mac80211: impleme... |
503 504 505 506 507 508 |
static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; mesh_path_tx_root_frame(sdata); mod_timer(&ifmsh->mesh_path_root_timer, |
c61336611 mac80211: mesh ga... |
509 510 |
round_jiffies(TU_TO_EXP_TIME( ifmsh->mshcfg.dot11MeshHWMPRannInterval))); |
e304bfd30 mac80211: impleme... |
511 |
} |
5bb644a0f mac80211: cancel/... |
512 513 514 515 |
#ifdef CONFIG_PM void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
5ee68e5b3 mac80211: mesh ga... |
516 |
/* use atomic bitops in case all timers fire at the same time */ |
5bb644a0f mac80211: cancel/... |
517 518 519 520 521 |
if (del_timer_sync(&ifmsh->housekeeping_timer)) set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); if (del_timer_sync(&ifmsh->mesh_path_timer)) set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); |
e304bfd30 mac80211: impleme... |
522 523 |
if (del_timer_sync(&ifmsh->mesh_path_root_timer)) set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); |
5bb644a0f mac80211: cancel/... |
524 525 526 527 528 529 530 531 532 533 |
} void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running)) add_timer(&ifmsh->housekeeping_timer); if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) add_timer(&ifmsh->mesh_path_timer); |
e304bfd30 mac80211: impleme... |
534 535 |
if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) add_timer(&ifmsh->mesh_path_root_timer); |
63c5723bc mac80211: add nl8... |
536 |
ieee80211_mesh_root_setup(ifmsh); |
5bb644a0f mac80211: cancel/... |
537 538 |
} #endif |
472dbc45d mac80211: split o... |
539 540 541 542 543 |
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; |
09b174702 mac80211: move me... |
544 545 546 547 |
local->fif_other_bss++; /* mesh ifaces must set allmulti to forward mcast traffic */ atomic_inc(&local->iff_allmultis); ieee80211_configure_filter(local); |
c7108a711 mac80211: Send me... |
548 549 550 |
ifmsh->mesh_cc_id = 0; /* Disabled */ ifmsh->mesh_sp_id = 0; /* Neighbor Offset */ ifmsh->mesh_auth_id = 0; /* Disabled */ |
6b9ac4425 mesh: use set_bit... |
551 |
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
63c5723bc mac80211: add nl8... |
552 |
ieee80211_mesh_root_setup(ifmsh); |
64592c8fc mac80211: use com... |
553 |
ieee80211_queue_work(&local->hw, &sdata->work); |
5b3658342 mac80211: Assign ... |
554 |
sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; |
2d0ddec5b mac80211: unify c... |
555 |
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
5b3658342 mac80211: Assign ... |
556 557 |
BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON_INT); |
472dbc45d mac80211: split o... |
558 559 560 561 |
} void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) { |
09b174702 mac80211: move me... |
562 |
struct ieee80211_local *local = sdata->local; |
29cbe68c5 cfg80211/mac80211... |
563 564 565 566 567 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; ifmsh->mesh_id_len = 0; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); sta_info_flush(local, NULL); |
09b174702 mac80211: move me... |
568 |
|
472dbc45d mac80211: split o... |
569 |
del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
e304bfd30 mac80211: impleme... |
570 |
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
472dbc45d mac80211: split o... |
571 |
/* |
b7413430d mac80211: fix wor... |
572 573 574 575 576 577 |
* If the timer fired while we waited for it, it will have * requeued the work. Now the work will be running again * but will not rearm the timer again because it checks * whether the interface is running, which, at this point, * it no longer is. */ |
64592c8fc mac80211: use com... |
578 |
cancel_work_sync(&sdata->work); |
09b174702 mac80211: move me... |
579 580 581 582 |
local->fif_other_bss--; atomic_dec(&local->iff_allmultis); ieee80211_configure_filter(local); |
472dbc45d mac80211: split o... |
583 584 585 586 587 588 589 590 |
} static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { |
c6a1fa12d mac80211: minor c... |
591 |
struct ieee80211_local *local = sdata->local; |
472dbc45d mac80211: split o... |
592 593 |
struct ieee802_11_elems elems; struct ieee80211_channel *channel; |
881d948c2 wireless: restric... |
594 |
u32 supp_rates = 0; |
472dbc45d mac80211: split o... |
595 596 597 598 599 600 |
size_t baselen; int freq; enum ieee80211_band band = rx_status->band; /* ignore ProbeResp to foreign address */ if (stype == IEEE80211_STYPE_PROBE_RESP && |
47846c9b0 mac80211: reduce ... |
601 |
compare_ether_addr(mgmt->da, sdata->vif.addr)) |
472dbc45d mac80211: split o... |
602 603 604 605 606 607 608 609 |
return; baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; if (baselen > len) return; ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, &elems); |
5cff5e01e mac80211: ignore ... |
610 |
/* ignore beacons from secure mesh peers if our security is off */ |
b130e5cec nl80211: Introduc... |
611 |
if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) |
5cff5e01e mac80211: ignore ... |
612 |
return; |
472dbc45d mac80211: split o... |
613 |
if (elems.ds_params && elems.ds_params_len == 1) |
59eb21a65 cfg80211: Extend ... |
614 |
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); |
472dbc45d mac80211: split o... |
615 616 617 618 619 620 621 622 623 624 625 |
else freq = rx_status->freq; channel = ieee80211_get_channel(local->hw.wiphy, freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) return; if (elems.mesh_id && elems.mesh_config && mesh_matches_local(&elems, sdata)) { supp_rates = ieee80211_sta_get_rates(local, &elems, band); |
1570ca592 mac80211: send no... |
626 |
mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); |
472dbc45d mac80211: split o... |
627 628 629 630 631 632 633 634 635 |
} } static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { switch (mgmt->u.action.category) { |
8db098507 mac80211: update ... |
636 637 638 639 640 641 642 643 |
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; } |
472dbc45d mac80211: split o... |
644 |
break; |
25d49e4d6 mac80211: update ... |
645 646 647 |
case WLAN_CATEGORY_MESH_ACTION: if (mesh_action_is_path_sel(mgmt)) mesh_rx_path_sel_frame(sdata, mgmt, len); |
472dbc45d mac80211: split o... |
648 649 650 |
break; } } |
1fa57d017 mac80211: use com... |
651 652 |
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
472dbc45d mac80211: split o... |
653 654 |
{ struct ieee80211_rx_status *rx_status; |
472dbc45d mac80211: split o... |
655 656 |
struct ieee80211_mgmt *mgmt; u16 stype; |
f1d58c252 mac80211: push rx... |
657 |
rx_status = IEEE80211_SKB_RXCB(skb); |
472dbc45d mac80211: split o... |
658 659 660 661 662 663 664 665 666 667 668 669 670 |
mgmt = (struct ieee80211_mgmt *) skb->data; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; switch (stype) { case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len, rx_status); break; case IEEE80211_STYPE_ACTION: ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); break; } |
472dbc45d mac80211: split o... |
671 |
} |
1fa57d017 mac80211: use com... |
672 |
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) |
472dbc45d mac80211: split o... |
673 |
{ |
472dbc45d mac80211: split o... |
674 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
472dbc45d mac80211: split o... |
675 676 677 678 679 |
if (ifmsh->preq_queue_len && time_after(jiffies, ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) mesh_path_start_discovery(sdata); |
18889231e mac80211: Move mp... |
680 681 |
if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) mesh_mpath_table_grow(); |
dcac908ba mac80211:mesh_mpp... |
682 |
if (test_and_clear_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags)) |
18889231e mac80211: Move mp... |
683 684 685 |
mesh_mpp_table_grow(); if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) |
472dbc45d mac80211: split o... |
686 |
ieee80211_mesh_housekeeping(sdata, ifmsh); |
e304bfd30 mac80211: impleme... |
687 688 689 |
if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) ieee80211_mesh_rootpath(sdata); |
472dbc45d mac80211: split o... |
690 691 692 693 694 695 696 697 698 |
} void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) if (ieee80211_vif_is_mesh(&sdata->vif)) |
64592c8fc mac80211: use com... |
699 |
ieee80211_queue_work(&local->hw, &sdata->work); |
472dbc45d mac80211: split o... |
700 701 |
rcu_read_unlock(); } |
902acc789 mac80211: clean u... |
702 703 |
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) { |
472dbc45d mac80211: split o... |
704 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
472dbc45d mac80211: split o... |
705 706 707 |
setup_timer(&ifmsh->housekeeping_timer, ieee80211_mesh_housekeeping_timer, (unsigned long) sdata); |
472dbc45d mac80211: split o... |
708 |
|
472dbc45d mac80211: split o... |
709 710 |
ifmsh->accepting_plinks = true; ifmsh->preq_id = 0; |
d19b3bf63 mac80211: replace... |
711 |
ifmsh->sn = 0; |
5ee68e5b3 mac80211: mesh ga... |
712 |
ifmsh->num_gates = 0; |
472dbc45d mac80211: split o... |
713 |
atomic_set(&ifmsh->mpaths, 0); |
f698d856f replace net_devic... |
714 |
mesh_rmc_init(sdata); |
472dbc45d mac80211: split o... |
715 |
ifmsh->last_preq = jiffies; |
dca7e9430 {nl,cfg,mac}80211... |
716 |
ifmsh->next_perr = jiffies; |
902acc789 mac80211: clean u... |
717 718 719 |
/* Allocate all mesh structures when creating the first mesh interface. */ if (!mesh_allocated) ieee80211s_init(); |
472dbc45d mac80211: split o... |
720 |
setup_timer(&ifmsh->mesh_path_timer, |
902acc789 mac80211: clean u... |
721 722 |
ieee80211_mesh_path_timer, (unsigned long) sdata); |
e304bfd30 mac80211: impleme... |
723 724 725 |
setup_timer(&ifmsh->mesh_path_root_timer, ieee80211_mesh_path_root_timer, (unsigned long) sdata); |
472dbc45d mac80211: split o... |
726 727 728 |
INIT_LIST_HEAD(&ifmsh->preq_queue.list); spin_lock_init(&ifmsh->mesh_preq_queue_lock); } |