Blame view

net/mac80211/mesh.c 21.4 KB
2e3c87368   Luis Carlos Cobo   mac80211: support...
1
  /*
264d9b7d8   Rui Paulo   mac80211: update ...
2
   * Copyright (c) 2008, 2009 open80211s Ltd.
2e3c87368   Luis Carlos Cobo   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   Tejun Heo   include cleanup: ...
10
  #include <linux/slab.h>
51ceddade   Luis Carlos Cobo   mac80211: use 4-b...
11
  #include <asm/unaligned.h>
2e3c87368   Luis Carlos Cobo   mac80211: support...
12
13
  #include "ieee80211_i.h"
  #include "mesh.h"
3491707a0   Rui Paulo   mac80211: update ...
14
15
  #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
  #define MESHCONF_CAPAB_FORWARDING    0x08
2e3c87368   Luis Carlos Cobo   mac80211: support...
16

5bb644a0f   Johannes Berg   mac80211: cancel/...
17
18
  #define TMR_RUNNING_HK	0
  #define TMR_RUNNING_MP	1
e304bfd30   Rui Paulo   mac80211: impleme...
19
  #define TMR_RUNNING_MPR	2
5bb644a0f   Johannes Berg   mac80211: cancel/...
20

2e3c87368   Luis Carlos Cobo   mac80211: support...
21
22
  int mesh_allocated;
  static struct kmem_cache *rm_cache;
25d49e4d6   Thomas Pedersen   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   Luis Carlos Cobo   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   Johannes Berg   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   Rui Paulo   mesh: use set_bit...
51
  	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
5bb644a0f   Johannes Berg   mac80211: cancel/...
52
53
54
55
56
  
  	if (local->quiescing) {
  		set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
  		return;
  	}
64592c8fc   Johannes Berg   mac80211: use com...
57
  	ieee80211_queue_work(&local->hw, &sdata->work);
472dbc45d   Johannes Berg   mac80211: split o...
58
  }
2e3c87368   Luis Carlos Cobo   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   Jasper Bryant-Greene   replace net_devic...
63
   * @sdata: local mesh subif
2e3c87368   Luis Carlos Cobo   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   Jasper Bryant-Greene   replace net_devic...
68
  bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
69
  {
472dbc45d   Johannes Berg   mac80211: split o...
70
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
739522baa   Thomas Pedersen   mac80211: set HT ...
71
  	struct ieee80211_local *local = sdata->local;
2e3c87368   Luis Carlos Cobo   mac80211: support...
72

2e3c87368   Luis Carlos Cobo   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   Thomas Pedersen   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   Luis Carlos Cobo   mac80211: support...
97

739522baa   Thomas Pedersen   mac80211: set HT ...
98
99
  	return true;
  mismatch:
2e3c87368   Luis Carlos Cobo   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   Luis Carlos Cobo   mac80211: support...
107
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
108
  bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
2e3c87368   Luis Carlos Cobo   mac80211: support...
109
  {
136cfa286   Rui Paulo   mac80211: use a s...
110
  	return (ie->mesh_config->meshconf_cap &
3491707a0   Rui Paulo   mac80211: update ...
111
  	    MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
2e3c87368   Luis Carlos Cobo   mac80211: support...
112
113
114
115
116
  }
  
  /**
   * mesh_accept_plinks_update: update accepting_plink in local mesh beacons
   *
d0709a651   Johannes Berg   mac80211: RCU-ify...
117
   * @sdata: mesh interface in which mesh beacons are going to be updated
2e3c87368   Luis Carlos Cobo   mac80211: support...
118
   */
d0709a651   Johannes Berg   mac80211: RCU-ify...
119
  void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
120
  {
2e3c87368   Luis Carlos Cobo   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   Luis Carlos Cobo   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   Luis Carlos Cobo   mac80211: support...
128
129
  	 */
  	free_plinks = mesh_plink_availables(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
130
131
  	if (free_plinks != sdata->u.mesh.accepting_plinks)
  		ieee80211_mesh_housekeeping_timer((unsigned long) sdata);
2e3c87368   Luis Carlos Cobo   mac80211: support...
132
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
133
  int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
134
  {
2e3c87368   Luis Carlos Cobo   mac80211: support...
135
  	int i;
472dbc45d   Johannes Berg   mac80211: split o...
136
137
  	sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
  	if (!sdata->u.mesh.rmc)
2e3c87368   Luis Carlos Cobo   mac80211: support...
138
  		return -ENOMEM;
472dbc45d   Johannes Berg   mac80211: split o...
139
  	sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
2e3c87368   Luis Carlos Cobo   mac80211: support...
140
  	for (i = 0; i < RMC_BUCKETS; i++)
472dbc45d   Johannes Berg   mac80211: split o...
141
  		INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list);
2e3c87368   Luis Carlos Cobo   mac80211: support...
142
143
  	return 0;
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
144
  void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
145
  {
472dbc45d   Johannes Berg   mac80211: split o...
146
  	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
2e3c87368   Luis Carlos Cobo   mac80211: support...
147
148
  	struct rmc_entry *p, *n;
  	int i;
472dbc45d   Johannes Berg   mac80211: split o...
149
  	if (!sdata->u.mesh.rmc)
2e3c87368   Luis Carlos Cobo   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   Johannes Berg   mac80211: split o...
159
  	sdata->u.mesh.rmc = NULL;
2e3c87368   Luis Carlos Cobo   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   Jasper Bryant-Greene   replace net_devic...
175
  		   struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
176
  {
472dbc45d   Johannes Berg   mac80211: split o...
177
  	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
2e3c87368   Luis Carlos Cobo   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   Luis Carlos Cobo   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   Luis Carlos Cobo   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   Joe Perches   net: Move && and ...
193
194
  		} else if ((seqnum == p->seqnum) &&
  			   (memcmp(sa, p->sa, ETH_ALEN) == 0))
2e3c87368   Luis Carlos Cobo   mac80211: support...
195
196
197
198
  			return -1;
  	}
  
  	p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
d15b84590   Joe Perches   mac80211: Remove ...
199
  	if (!p)
2e3c87368   Luis Carlos Cobo   mac80211: support...
200
  		return 0;
d15b84590   Joe Perches   mac80211: Remove ...
201

2e3c87368   Luis Carlos Cobo   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   Thomas Pedersen   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   Thomas Pedersen   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   Luis Carlos Cobo   mac80211: support...
323

082ebb0c2   Thomas Pedersen   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   Rui Paulo   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   Thomas Pedersen   mac80211: fix mes...
334
  	return 0;
2e3c87368   Luis Carlos Cobo   mac80211: support...
335
  }
176f36086   Thomas Pedersen   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   Ben Greear   mac80211: Support...
352
  	ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
176f36086   Thomas Pedersen   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   Luis Carlos Cobo   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   Johannes Berg   mac80211: split o...
383
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
133b82263   Johannes Berg   mac80211: make ma...
384
  	struct ieee80211_local *local = sdata->local;
2e3c87368   Luis Carlos Cobo   mac80211: support...
385

5bb644a0f   Johannes Berg   mac80211: cancel/...
386
387
388
389
  	if (local->quiescing) {
  		set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
  		return;
  	}
64592c8fc   Johannes Berg   mac80211: use com...
390
  	ieee80211_queue_work(&local->hw, &sdata->work);
2e3c87368   Luis Carlos Cobo   mac80211: support...
391
  }
e304bfd30   Rui Paulo   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   Johannes Berg   mac80211: use com...
405
  	ieee80211_queue_work(&local->hw, &sdata->work);
e304bfd30   Rui Paulo   mac80211: impleme...
406
  }
63c5723bc   Rui Paulo   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   Johannes Berg   mac80211: clean u...
417
  /**
3c5772a52   Javier Cardona   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   Johannes Berg   mac80211: use fix...
427
428
429
  int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
  				  const u8 *meshda, const u8 *meshsa)
  {
3c5772a52   Javier Cardona   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   Javier Cardona   mac80211: Mesh da...
438
  		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
3c5772a52   Javier Cardona   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   Johannes Berg   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   Javier Cardona   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   Johannes Berg   mac80211: clean u...
457
458
459
460
   *
   * Return the header length.
   */
  int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
61ad53945   Javier Cardona   mac80211: Remove ...
461
462
  		struct ieee80211_sub_if_data *sdata, char *addr4or5,
  		char *addr6)
902acc789   Johannes Berg   mac80211: clean u...
463
  {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
464
  	int aelen = 0;
61ad53945   Javier Cardona   mac80211: Remove ...
465
  	BUG_ON(!addr4or5 && addr6);
0c3cee72a   Julia Lawall   net/mac80211: Cor...
466
  	memset(meshhdr, 0, sizeof(*meshhdr));
472dbc45d   Johannes Berg   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   Javier Cardona   mac80211: Remove ...
470
  	if (addr4or5 && !addr6) {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
471
472
  		meshhdr->flags |= MESH_FLAGS_AE_A4;
  		aelen += ETH_ALEN;
61ad53945   Javier Cardona   mac80211: Remove ...
473
474
  		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
  	} else if (addr4or5 && addr6) {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
475
476
  		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
  		aelen += 2 * ETH_ALEN;
61ad53945   Javier Cardona   mac80211: Remove ...
477
478
  		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
  		memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
3c5772a52   Javier Cardona   mac80211: Use 3-a...
479
480
  	}
  	return 6 + aelen;
902acc789   Johannes Berg   mac80211: clean u...
481
  }
472dbc45d   Johannes Berg   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   Johannes Berg   mac80211: reduce ...
490
  	       sdata->name);
472dbc45d   Johannes Berg   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   Johannes Berg   mac80211: unify c...
498
  		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
472dbc45d   Johannes Berg   mac80211: split o...
499

472dbc45d   Johannes Berg   mac80211: split o...
500
501
502
  	mod_timer(&ifmsh->housekeeping_timer,
  		  round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
  }
e304bfd30   Rui Paulo   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   Thomas Pedersen   mac80211: mesh ga...
509
510
  		  round_jiffies(TU_TO_EXP_TIME(
  				  ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
e304bfd30   Rui Paulo   mac80211: impleme...
511
  }
5bb644a0f   Johannes Berg   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   Javier Cardona   mac80211: mesh ga...
516
  	/* use atomic bitops in case all timers fire at the same time */
5bb644a0f   Johannes Berg   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   Rui Paulo   mac80211: impleme...
522
523
  	if (del_timer_sync(&ifmsh->mesh_path_root_timer))
  		set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
5bb644a0f   Johannes Berg   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   Rui Paulo   mac80211: impleme...
534
535
  	if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running))
  		add_timer(&ifmsh->mesh_path_root_timer);
63c5723bc   Rui Paulo   mac80211: add nl8...
536
  	ieee80211_mesh_root_setup(ifmsh);
5bb644a0f   Johannes Berg   mac80211: cancel/...
537
538
  }
  #endif
472dbc45d   Johannes Berg   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   Johannes Berg   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   Javier Cardona   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   Rui Paulo   mesh: use set_bit...
551
  	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
63c5723bc   Rui Paulo   mac80211: add nl8...
552
  	ieee80211_mesh_root_setup(ifmsh);
64592c8fc   Johannes Berg   mac80211: use com...
553
  	ieee80211_queue_work(&local->hw, &sdata->work);
5b3658342   Javier Cardona   mac80211: Assign ...
554
  	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
2d0ddec5b   Johannes Berg   mac80211: unify c...
555
  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
5b3658342   Javier Cardona   mac80211: Assign ...
556
557
  						BSS_CHANGED_BEACON_ENABLED |
  						BSS_CHANGED_BEACON_INT);
472dbc45d   Johannes Berg   mac80211: split o...
558
559
560
561
  }
  
  void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
  {
09b174702   Johannes Berg   mac80211: move me...
562
  	struct ieee80211_local *local = sdata->local;
29cbe68c5   Johannes Berg   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   Johannes Berg   mac80211: move me...
568

472dbc45d   Johannes Berg   mac80211: split o...
569
  	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
e304bfd30   Rui Paulo   mac80211: impleme...
570
  	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
472dbc45d   Johannes Berg   mac80211: split o...
571
  	/*
b7413430d   Johannes Berg   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   Johannes Berg   mac80211: use com...
578
  	cancel_work_sync(&sdata->work);
09b174702   Johannes Berg   mac80211: move me...
579
580
581
582
  
  	local->fif_other_bss--;
  	atomic_dec(&local->iff_allmultis);
  	ieee80211_configure_filter(local);
472dbc45d   Johannes Berg   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   Johannes Berg   mac80211: minor c...
591
  	struct ieee80211_local *local = sdata->local;
472dbc45d   Johannes Berg   mac80211: split o...
592
593
  	struct ieee802_11_elems elems;
  	struct ieee80211_channel *channel;
881d948c2   Johannes Berg   wireless: restric...
594
  	u32 supp_rates = 0;
472dbc45d   Johannes Berg   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   Johannes Berg   mac80211: reduce ...
601
  	    compare_ether_addr(mgmt->da, sdata->vif.addr))
472dbc45d   Johannes Berg   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   Javier Cardona   mac80211: ignore ...
610
  	/* ignore beacons from secure mesh peers if our security is off */
b130e5cec   Javier Cardona   nl80211: Introduc...
611
  	if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE)
5cff5e01e   Javier Cardona   mac80211: ignore ...
612
  		return;
472dbc45d   Johannes Berg   mac80211: split o...
613
  	if (elems.ds_params && elems.ds_params_len == 1)
59eb21a65   Bruno Randolf   cfg80211: Extend ...
614
  		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
472dbc45d   Johannes Berg   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   Javier Cardona   mac80211: send no...
626
  		mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems);
472dbc45d   Johannes Berg   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   Thomas Pedersen   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   Johannes Berg   mac80211: split o...
644
  		break;
25d49e4d6   Thomas Pedersen   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   Johannes Berg   mac80211: split o...
648
649
650
  		break;
  	}
  }
1fa57d017   Johannes Berg   mac80211: use com...
651
652
  void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
  				   struct sk_buff *skb)
472dbc45d   Johannes Berg   mac80211: split o...
653
654
  {
  	struct ieee80211_rx_status *rx_status;
472dbc45d   Johannes Berg   mac80211: split o...
655
656
  	struct ieee80211_mgmt *mgmt;
  	u16 stype;
f1d58c252   Johannes Berg   mac80211: push rx...
657
  	rx_status = IEEE80211_SKB_RXCB(skb);
472dbc45d   Johannes Berg   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   Johannes Berg   mac80211: split o...
671
  }
1fa57d017   Johannes Berg   mac80211: use com...
672
  void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
472dbc45d   Johannes Berg   mac80211: split o...
673
  {
472dbc45d   Johannes Berg   mac80211: split o...
674
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
472dbc45d   Johannes Berg   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   Javier Cardona   mac80211: Move mp...
680
681
  	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
  		mesh_mpath_table_grow();
dcac908ba   Nick Ledovskikh   mac80211:mesh_mpp...
682
  	if (test_and_clear_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags))
18889231e   Javier Cardona   mac80211: Move mp...
683
684
685
  		mesh_mpp_table_grow();
  
  	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
472dbc45d   Johannes Berg   mac80211: split o...
686
  		ieee80211_mesh_housekeeping(sdata, ifmsh);
e304bfd30   Rui Paulo   mac80211: impleme...
687
688
689
  
  	if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
  		ieee80211_mesh_rootpath(sdata);
472dbc45d   Johannes Berg   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   Johannes Berg   mac80211: use com...
699
  			ieee80211_queue_work(&local->hw, &sdata->work);
472dbc45d   Johannes Berg   mac80211: split o...
700
701
  	rcu_read_unlock();
  }
902acc789   Johannes Berg   mac80211: clean u...
702
703
  void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
  {
472dbc45d   Johannes Berg   mac80211: split o...
704
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
472dbc45d   Johannes Berg   mac80211: split o...
705
706
707
  	setup_timer(&ifmsh->housekeeping_timer,
  		    ieee80211_mesh_housekeeping_timer,
  		    (unsigned long) sdata);
472dbc45d   Johannes Berg   mac80211: split o...
708

472dbc45d   Johannes Berg   mac80211: split o...
709
710
  	ifmsh->accepting_plinks = true;
  	ifmsh->preq_id = 0;
d19b3bf63   Rui Paulo   mac80211: replace...
711
  	ifmsh->sn = 0;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
712
  	ifmsh->num_gates = 0;
472dbc45d   Johannes Berg   mac80211: split o...
713
  	atomic_set(&ifmsh->mpaths, 0);
f698d856f   Jasper Bryant-Greene   replace net_devic...
714
  	mesh_rmc_init(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
715
  	ifmsh->last_preq = jiffies;
dca7e9430   Thomas Pedersen   {nl,cfg,mac}80211...
716
  	ifmsh->next_perr = jiffies;
902acc789   Johannes Berg   mac80211: clean u...
717
718
719
  	/* Allocate all mesh structures when creating the first mesh interface. */
  	if (!mesh_allocated)
  		ieee80211s_init();
472dbc45d   Johannes Berg   mac80211: split o...
720
  	setup_timer(&ifmsh->mesh_path_timer,
902acc789   Johannes Berg   mac80211: clean u...
721
722
  		    ieee80211_mesh_path_timer,
  		    (unsigned long) sdata);
e304bfd30   Rui Paulo   mac80211: impleme...
723
724
725
  	setup_timer(&ifmsh->mesh_path_root_timer,
  		    ieee80211_mesh_path_root_timer,
  		    (unsigned long) sdata);
472dbc45d   Johannes Berg   mac80211: split o...
726
727
728
  	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
  	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
  }