Blame view

net/mac80211/mesh.c 40.5 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"
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
14
  #include "driver-ops.h"
2e3c87368   Luis Carlos Cobo   mac80211: support...
15

bf7cd94dc   Johannes Berg   mac80211: clean u...
16
  static int mesh_allocated;
2e3c87368   Luis Carlos Cobo   mac80211: support...
17
  static struct kmem_cache *rm_cache;
25d49e4d6   Thomas Pedersen   mac80211: update ...
18
19
20
21
22
  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);
  }
25d49e4d6   Thomas Pedersen   mac80211: update ...
23

2e3c87368   Luis Carlos Cobo   mac80211: support...
24
25
  void ieee80211s_init(void)
  {
2e3c87368   Luis Carlos Cobo   mac80211: support...
26
27
28
29
30
31
32
  	mesh_allocated = 1;
  	rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
  				     0, 0, NULL);
  }
  
  void ieee80211s_stop(void)
  {
bf7cd94dc   Johannes Berg   mac80211: clean u...
33
34
  	if (!mesh_allocated)
  		return;
2e3c87368   Luis Carlos Cobo   mac80211: support...
35
36
  	kmem_cache_destroy(rm_cache);
  }
472dbc45d   Johannes Berg   mac80211: split o...
37
38
39
40
41
  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...
42
  	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
5bb644a0f   Johannes Berg   mac80211: cancel/...
43

64592c8fc   Johannes Berg   mac80211: use com...
44
  	ieee80211_queue_work(&local->hw, &sdata->work);
472dbc45d   Johannes Berg   mac80211: split o...
45
  }
2e3c87368   Luis Carlos Cobo   mac80211: support...
46
47
48
  /**
   * mesh_matches_local - check if the config of a mesh point matches ours
   *
f698d856f   Jasper Bryant-Greene   replace net_devic...
49
   * @sdata: local mesh subif
f743ff490   Thomas Pedersen   mac80211: refacto...
50
   * @ie: information elements of a management frame from the mesh peer
2e3c87368   Luis Carlos Cobo   mac80211: support...
51
52
53
54
   *
   * 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.
   */
f743ff490   Thomas Pedersen   mac80211: refacto...
55
56
  bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
  			struct ieee802_11_elems *ie)
2e3c87368   Luis Carlos Cobo   mac80211: support...
57
  {
472dbc45d   Johannes Berg   mac80211: split o...
58
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
f743ff490   Thomas Pedersen   mac80211: refacto...
59
  	u32 basic_rates = 0;
4bf88530b   Johannes Berg   mac80211: convert...
60
  	struct cfg80211_chan_def sta_chan_def;
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
61
  	struct ieee80211_supported_band *sband;
2e3c87368   Luis Carlos Cobo   mac80211: support...
62

2e3c87368   Luis Carlos Cobo   mac80211: support...
63
64
65
66
67
68
69
70
71
72
  	/*
  	 * 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 ...
73
74
75
76
77
78
79
  	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)))
bf7cd94dc   Johannes Berg   mac80211: clean u...
80
  		return false;
739522baa   Thomas Pedersen   mac80211: set HT ...
81

21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
82
83
84
85
86
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return false;
  
  	ieee80211_sta_get_rates(sdata, ie, sband->band,
f743ff490   Thomas Pedersen   mac80211: refacto...
87
  				&basic_rates);
fe40cb627   Ashok Nagarajan   mac80211: Check b...
88
  	if (sdata->vif.bss_conf.basic_rates != basic_rates)
bf7cd94dc   Johannes Berg   mac80211: clean u...
89
  		return false;
fe40cb627   Ashok Nagarajan   mac80211: Check b...
90

8ac3c7041   Johannes Berg   mac80211: refacto...
91
92
93
94
  	cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
  				NL80211_CHAN_NO_HT);
  	ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
  	ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
c85fb53c4   Bob Copeland   mac80211: impleme...
95

4bf88530b   Johannes Berg   mac80211: convert...
96
97
  	if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
  					 &sta_chan_def))
bf7cd94dc   Johannes Berg   mac80211: clean u...
98
  		return false;
2e3c87368   Luis Carlos Cobo   mac80211: support...
99

739522baa   Thomas Pedersen   mac80211: set HT ...
100
  	return true;
2e3c87368   Luis Carlos Cobo   mac80211: support...
101
102
103
104
105
106
  }
  
  /**
   * 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 &
bf7cd94dc   Johannes Berg   mac80211: clean u...
111
  			IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
2e3c87368   Luis Carlos Cobo   mac80211: support...
112
113
114
  }
  
  /**
2c53040f0   Ben Hutchings   net: Fix (nearly-...
115
   * mesh_accept_plinks_update - update accepting_plink in local mesh beacons
2e3c87368   Luis Carlos Cobo   mac80211: support...
116
   *
d0709a651   Johannes Berg   mac80211: RCU-ify...
117
   * @sdata: mesh interface in which mesh beacons are going to be updated
df3238189   Marco Porsch   mac80211: fix unn...
118
119
   *
   * Returns: beacon changed flag if the beacon content changed.
2e3c87368   Luis Carlos Cobo   mac80211: support...
120
   */
df3238189   Marco Porsch   mac80211: fix unn...
121
  u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
122
  {
2e3c87368   Luis Carlos Cobo   mac80211: support...
123
  	bool free_plinks;
df3238189   Marco Porsch   mac80211: fix unn...
124
  	u32 changed = 0;
2e3c87368   Luis Carlos Cobo   mac80211: support...
125
126
127
  
  	/* 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...
128
129
130
  	 * 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...
131
132
  	 */
  	free_plinks = mesh_plink_availables(sdata);
df3238189   Marco Porsch   mac80211: fix unn...
133
134
135
136
137
138
  	if (free_plinks != sdata->u.mesh.accepting_plinks) {
  		sdata->u.mesh.accepting_plinks = free_plinks;
  		changed = BSS_CHANGED_BEACON;
  	}
  
  	return changed;
2e3c87368   Luis Carlos Cobo   mac80211: support...
139
  }
45b5028e8   Thomas Pedersen   mac80211: fix mes...
140
141
142
143
144
145
146
147
  /*
   * mesh_sta_cleanup - clean up any mesh sta state
   *
   * @sta: mesh sta to clean up.
   */
  void mesh_sta_cleanup(struct sta_info *sta)
  {
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
efc401f49   Bob Copeland   mac80211: use com...
148
  	u32 changed = mesh_plink_deactivate(sta);
fe7a7c576   Bob Copeland   mac80211: mesh: f...
149

f81a9deda   Thomas Pedersen   mac80211: update ...
150
  	if (changed)
2b5e19677   Thomas Pedersen   mac80211: cache m...
151
  		ieee80211_mbss_info_change_notify(sdata, changed);
45b5028e8   Thomas Pedersen   mac80211: fix mes...
152
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
153
  int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
154
  {
2e3c87368   Luis Carlos Cobo   mac80211: support...
155
  	int i;
472dbc45d   Johannes Berg   mac80211: split o...
156
157
  	sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
  	if (!sdata->u.mesh.rmc)
2e3c87368   Luis Carlos Cobo   mac80211: support...
158
  		return -ENOMEM;
472dbc45d   Johannes Berg   mac80211: split o...
159
  	sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
2e3c87368   Luis Carlos Cobo   mac80211: support...
160
  	for (i = 0; i < RMC_BUCKETS; i++)
47a0489ce   Bob Copeland   mac80211: mesh: u...
161
  		INIT_HLIST_HEAD(&sdata->u.mesh.rmc->bucket[i]);
2e3c87368   Luis Carlos Cobo   mac80211: support...
162
163
  	return 0;
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
164
  void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
165
  {
472dbc45d   Johannes Berg   mac80211: split o...
166
  	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
47a0489ce   Bob Copeland   mac80211: mesh: u...
167
168
  	struct rmc_entry *p;
  	struct hlist_node *n;
2e3c87368   Luis Carlos Cobo   mac80211: support...
169
  	int i;
472dbc45d   Johannes Berg   mac80211: split o...
170
  	if (!sdata->u.mesh.rmc)
2e3c87368   Luis Carlos Cobo   mac80211: support...
171
  		return;
bf7cd94dc   Johannes Berg   mac80211: clean u...
172
  	for (i = 0; i < RMC_BUCKETS; i++) {
47a0489ce   Bob Copeland   mac80211: mesh: u...
173
174
  		hlist_for_each_entry_safe(p, n, &rmc->bucket[i], list) {
  			hlist_del(&p->list);
2e3c87368   Luis Carlos Cobo   mac80211: support...
175
176
  			kmem_cache_free(rm_cache, p);
  		}
bf7cd94dc   Johannes Berg   mac80211: clean u...
177
  	}
2e3c87368   Luis Carlos Cobo   mac80211: support...
178
179
  
  	kfree(rmc);
472dbc45d   Johannes Berg   mac80211: split o...
180
  	sdata->u.mesh.rmc = NULL;
2e3c87368   Luis Carlos Cobo   mac80211: support...
181
182
183
184
185
  }
  
  /**
   * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
   *
bf7cd94dc   Johannes Berg   mac80211: clean u...
186
   * @sdata:	interface
2e3c87368   Luis Carlos Cobo   mac80211: support...
187
188
189
190
191
192
193
194
195
   * @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.
   */
bf7cd94dc   Johannes Berg   mac80211: clean u...
196
197
  int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
  		   const u8 *sa, struct ieee80211s_hdr *mesh_hdr)
2e3c87368   Luis Carlos Cobo   mac80211: support...
198
  {
472dbc45d   Johannes Berg   mac80211: split o...
199
  	struct mesh_rmc *rmc = sdata->u.mesh.rmc;
2e3c87368   Luis Carlos Cobo   mac80211: support...
200
201
202
  	u32 seqnum = 0;
  	int entries = 0;
  	u8 idx;
47a0489ce   Bob Copeland   mac80211: mesh: u...
203
204
  	struct rmc_entry *p;
  	struct hlist_node *n;
2e3c87368   Luis Carlos Cobo   mac80211: support...
205

0aa7fabbd   Bob Copeland   mac80211: mesh: h...
206
207
  	if (!rmc)
  		return -1;
2e3c87368   Luis Carlos Cobo   mac80211: support...
208
  	/* Don't care about endianness since only match matters */
51ceddade   Luis Carlos Cobo   mac80211: use 4-b...
209
210
  	memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
  	idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
47a0489ce   Bob Copeland   mac80211: mesh: u...
211
  	hlist_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
2e3c87368   Luis Carlos Cobo   mac80211: support...
212
213
  		++entries;
  		if (time_after(jiffies, p->exp_time) ||
bf7cd94dc   Johannes Berg   mac80211: clean u...
214
  		    entries == RMC_QUEUE_MAX_LEN) {
47a0489ce   Bob Copeland   mac80211: mesh: u...
215
  			hlist_del(&p->list);
2e3c87368   Luis Carlos Cobo   mac80211: support...
216
217
  			kmem_cache_free(rm_cache, p);
  			--entries;
bf7cd94dc   Johannes Berg   mac80211: clean u...
218
  		} else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa))
2e3c87368   Luis Carlos Cobo   mac80211: support...
219
220
221
222
  			return -1;
  	}
  
  	p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
d15b84590   Joe Perches   mac80211: Remove ...
223
  	if (!p)
2e3c87368   Luis Carlos Cobo   mac80211: support...
224
  		return 0;
d15b84590   Joe Perches   mac80211: Remove ...
225

2e3c87368   Luis Carlos Cobo   mac80211: support...
226
227
228
  	p->seqnum = seqnum;
  	p->exp_time = jiffies + RMC_TIMEOUT;
  	memcpy(p->sa, sa, ETH_ALEN);
47a0489ce   Bob Copeland   mac80211: mesh: u...
229
  	hlist_add_head(&p->list, &rmc->bucket[idx]);
2e3c87368   Luis Carlos Cobo   mac80211: support...
230
231
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
232
233
  int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
  			 struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
234
235
236
237
238
239
240
241
242
243
244
  {
  	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;
43552be1d   Thomas Pedersen   mac80211: update ...
245
246
  	/* save a pointer for quick updates in pre-tbtt */
  	ifmsh->meshconf_offset = pos - skb->data;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
247
248
249
250
251
252
253
254
255
256
257
  	/* 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 */
1258d9761   Ashok Nagarajan   mac80211: move ou...
258
  	neighbors = atomic_read(&ifmsh->estab_plinks);
e05ecccdf   Jacob Minshall   mac80211: set mes...
259
  	neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS);
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
260
261
  	*pos++ = neighbors << 1;
  	/* Mesh capability */
b60e527a7   Chun-Yeow Yeoh   mac80211: set for...
262
263
264
  	*pos = 0x00;
  	*pos |= ifmsh->mshcfg.dot11MeshForwarding ?
  			IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00;
dbf498fba   Javier Cardona   mac80211: Impleme...
265
  	*pos |= ifmsh->accepting_plinks ?
bf7cd94dc   Johannes Berg   mac80211: clean u...
266
  			IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
3f52b7e32   Marco Porsch   mac80211: mesh po...
267
268
  	/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
  	*pos |= ifmsh->ps_peers_deep_sleep ?
bf7cd94dc   Johannes Berg   mac80211: clean u...
269
  			IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
270
271
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
272
  int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  {
  	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;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
288
289
  static int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata,
  				    struct sk_buff *skb)
3f52b7e32   Marco Porsch   mac80211: mesh po...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	u8 *pos;
  
  	/* see IEEE802.11-2012 13.14.6 */
  	if (ifmsh->ps_peers_light_sleep == 0 &&
  	    ifmsh->ps_peers_deep_sleep == 0 &&
  	    ifmsh->nonpeer_pm == NL80211_MESH_POWER_ACTIVE)
  		return 0;
  
  	if (skb_tailroom(skb) < 4)
  		return -ENOMEM;
  
  	pos = skb_put(skb, 2 + 2);
  	*pos++ = WLAN_EID_MESH_AWAKE_WINDOW;
  	*pos++ = 2;
  	put_unaligned_le16(ifmsh->mshcfg.dot11MeshAwakeWindowDuration, pos);
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
310
311
  int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
  			struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
312
313
314
315
316
317
318
319
320
321
  {
  	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);
da7061c82   Thorsten Horstmann   mac80211: Fix add...
322
  	if (offset < ifmsh->ie_len) {
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
323
324
325
326
  		len = ifmsh->ie_len - offset;
  		data = ifmsh->ie + offset;
  		if (skb_tailroom(skb) < len)
  			return -ENOMEM;
59ae1d127   Johannes Berg   networking: intro...
327
  		skb_put_data(skb, data, len);
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
328
329
330
331
  	}
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
332
  int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
333
334
335
336
337
338
339
340
341
  {
  	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 */
a40a8c17b   Bob Copeland   mac80211: fix mes...
342
343
344
  	data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len);
  	if (!data)
  		return 0;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
345

a40a8c17b   Bob Copeland   mac80211: fix mes...
346
347
348
349
  	len = data[1] + 2;
  
  	if (skb_tailroom(skb) < len)
  		return -ENOMEM;
59ae1d127   Johannes Berg   networking: intro...
350
  	skb_put_data(skb, data, len);
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
351
352
353
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
354
355
  static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata,
  				 struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
356
  {
55de908ab   Johannes Berg   mac80211: use cha...
357
358
  	struct ieee80211_chanctx_conf *chanctx_conf;
  	struct ieee80211_channel *chan;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
359
  	u8 *pos;
2e3c87368   Luis Carlos Cobo   mac80211: support...
360

082ebb0c2   Thomas Pedersen   mac80211: fix mes...
361
362
  	if (skb_tailroom(skb) < 3)
  		return -ENOMEM;
55de908ab   Johannes Berg   mac80211: use cha...
363
364
365
366
367
368
  	rcu_read_lock();
  	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  	if (WARN_ON(!chanctx_conf)) {
  		rcu_read_unlock();
  		return -EINVAL;
  	}
4bf88530b   Johannes Berg   mac80211: convert...
369
  	chan = chanctx_conf->def.chan;
55de908ab   Johannes Berg   mac80211: use cha...
370
  	rcu_read_unlock();
601513aa2   Emanuel Taube   mac80211: Add the...
371
372
373
374
  	pos = skb_put(skb, 2 + 1);
  	*pos++ = WLAN_EID_DS_PARAMS;
  	*pos++ = 1;
  	*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
be125c60e   Rui Paulo   mac80211: add the...
375

082ebb0c2   Thomas Pedersen   mac80211: fix mes...
376
  	return 0;
2e3c87368   Luis Carlos Cobo   mac80211: support...
377
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
378
379
  int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
  		       struct sk_buff *skb)
176f36086   Thomas Pedersen   mac80211: add HT ...
380
  {
176f36086   Thomas Pedersen   mac80211: add HT ...
381
382
  	struct ieee80211_supported_band *sband;
  	u8 *pos;
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
383
384
385
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return -EINVAL;
176f36086   Thomas Pedersen   mac80211: add HT ...
386
  	if (!sband->ht_cap.ht_supported ||
0418a4458   Simon Wunderlich   mac80211: fix var...
387
388
389
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
176f36086   Thomas Pedersen   mac80211: add HT ...
390
391
392
393
394
395
  		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...
396
  	ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
176f36086   Thomas Pedersen   mac80211: add HT ...
397
398
399
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
400
401
  int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
  			struct sk_buff *skb)
176f36086   Thomas Pedersen   mac80211: add HT ...
402
403
  {
  	struct ieee80211_local *local = sdata->local;
55de908ab   Johannes Berg   mac80211: use cha...
404
405
  	struct ieee80211_chanctx_conf *chanctx_conf;
  	struct ieee80211_channel *channel;
55de908ab   Johannes Berg   mac80211: use cha...
406
407
  	struct ieee80211_supported_band *sband;
  	struct ieee80211_sta_ht_cap *ht_cap;
176f36086   Thomas Pedersen   mac80211: add HT ...
408
  	u8 *pos;
55de908ab   Johannes Berg   mac80211: use cha...
409
410
411
412
413
414
  	rcu_read_lock();
  	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  	if (WARN_ON(!chanctx_conf)) {
  		rcu_read_unlock();
  		return -EINVAL;
  	}
4bf88530b   Johannes Berg   mac80211: convert...
415
  	channel = chanctx_conf->def.chan;
55de908ab   Johannes Berg   mac80211: use cha...
416
417
418
419
  	rcu_read_unlock();
  
  	sband = local->hw.wiphy->bands[channel->band];
  	ht_cap = &sband->ht_cap;
c85fb53c4   Bob Copeland   mac80211: impleme...
420
421
422
423
  	if (!ht_cap->ht_supported ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
176f36086   Thomas Pedersen   mac80211: add HT ...
424
  		return 0;
074d46d1d   Johannes Berg   wireless: rename ...
425
  	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
176f36086   Thomas Pedersen   mac80211: add HT ...
426
  		return -ENOMEM;
074d46d1d   Johannes Berg   wireless: rename ...
427
  	pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
4bf88530b   Johannes Berg   mac80211: convert...
428
  	ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
57f255f58   Arik Nemtsov   mac80211: TDLS: a...
429
430
  				   sdata->vif.bss_conf.ht_operation_mode,
  				   false);
176f36086   Thomas Pedersen   mac80211: add HT ...
431
432
433
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
434

c85fb53c4   Bob Copeland   mac80211: impleme...
435
436
437
  int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata,
  			struct sk_buff *skb)
  {
c85fb53c4   Bob Copeland   mac80211: impleme...
438
439
  	struct ieee80211_supported_band *sband;
  	u8 *pos;
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
440
441
442
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return -EINVAL;
c85fb53c4   Bob Copeland   mac80211: impleme...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
  	if (!sband->vht_cap.vht_supported ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
  		return 0;
  
  	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap))
  		return -ENOMEM;
  
  	pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_cap));
  	ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, sband->vht_cap.cap);
  
  	return 0;
  }
  
  int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
  			 struct sk_buff *skb)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_chanctx_conf *chanctx_conf;
  	struct ieee80211_channel *channel;
  	struct ieee80211_supported_band *sband;
  	struct ieee80211_sta_vht_cap *vht_cap;
  	u8 *pos;
  
  	rcu_read_lock();
  	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  	if (WARN_ON(!chanctx_conf)) {
  		rcu_read_unlock();
  		return -EINVAL;
  	}
  	channel = chanctx_conf->def.chan;
  	rcu_read_unlock();
  
  	sband = local->hw.wiphy->bands[channel->band];
  	vht_cap = &sband->vht_cap;
  
  	if (!vht_cap->vht_supported ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
  	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
  		return 0;
  
  	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_operation))
  		return -ENOMEM;
  
  	pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation));
  	ieee80211_ie_build_vht_oper(pos, vht_cap,
  				    &sdata->vif.bss_conf.chandef);
  
  	return 0;
  }
2e3c87368   Luis Carlos Cobo   mac80211: support...
495
496
497
498
  static void ieee80211_mesh_path_timer(unsigned long data)
  {
  	struct ieee80211_sub_if_data *sdata =
  		(struct ieee80211_sub_if_data *) data;
5bb644a0f   Johannes Berg   mac80211: cancel/...
499

690205f18   Stanislaw Gruszka   mac80211: cleanup...
500
  	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
2e3c87368   Luis Carlos Cobo   mac80211: support...
501
  }
e304bfd30   Rui Paulo   mac80211: impleme...
502
503
504
505
506
  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;
e304bfd30   Rui Paulo   mac80211: impleme...
507
508
  
  	set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
690205f18   Stanislaw Gruszka   mac80211: cleanup...
509
  	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
e304bfd30   Rui Paulo   mac80211: impleme...
510
  }
63c5723bc   Rui Paulo   mac80211: add nl8...
511
512
  void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
  {
dbb912cd4   Chun-Yeow Yeoh   mac80211: invoke ...
513
  	if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)
63c5723bc   Rui Paulo   mac80211: add nl8...
514
515
516
517
518
519
520
  		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...
521
  /**
3c5772a52   Javier Cardona   mac80211: Use 3-a...
522
   * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
bf7cd94dc   Johannes Berg   mac80211: clean u...
523
   * @hdr:	802.11 frame header
3c5772a52   Javier Cardona   mac80211: Use 3-a...
524
525
526
527
528
529
530
   * @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...
531
532
533
  int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
  				  const u8 *meshda, const u8 *meshsa)
  {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
534
535
536
537
538
539
540
541
  	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...
542
  		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
3c5772a52   Javier Cardona   mac80211: Use 3-a...
543
  		/* RA TA DA SA */
c84a67a2f   Joe Perches   mac80211: Use eth...
544
  		eth_zero_addr(hdr->addr1);   /* RA is resolved later */
3c5772a52   Javier Cardona   mac80211: Use 3-a...
545
546
547
548
549
550
551
552
  		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...
553
   * ieee80211_new_mesh_header - create a new mesh header
902acc789   Johannes Berg   mac80211: clean u...
554
   * @sdata:	mesh interface to be used
bf7cd94dc   Johannes Berg   mac80211: clean u...
555
   * @meshhdr:    uninitialized mesh header
61ad53945   Javier Cardona   mac80211: Remove ...
556
557
558
559
560
   * @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...
561
562
563
   *
   * Return the header length.
   */
5edfcee5e   Andrzej Hajda   mac80211: make ie...
564
565
566
  unsigned int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
  				       struct ieee80211s_hdr *meshhdr,
  				       const char *addr4or5, const char *addr6)
902acc789   Johannes Berg   mac80211: clean u...
567
  {
bf7cd94dc   Johannes Berg   mac80211: clean u...
568
569
  	if (WARN_ON(!addr4or5 && addr6))
  		return 0;
0c3cee72a   Julia Lawall   net/mac80211: Cor...
570
  	memset(meshhdr, 0, sizeof(*meshhdr));
bf7cd94dc   Johannes Berg   mac80211: clean u...
571

472dbc45d   Johannes Berg   mac80211: split o...
572
  	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
bf7cd94dc   Johannes Berg   mac80211: clean u...
573
574
  
  	/* FIXME: racy -- TX on multiple queues can be concurrent */
472dbc45d   Johannes Berg   mac80211: split o...
575
576
  	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
  	sdata->u.mesh.mesh_seqnum++;
bf7cd94dc   Johannes Berg   mac80211: clean u...
577

61ad53945   Javier Cardona   mac80211: Remove ...
578
  	if (addr4or5 && !addr6) {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
579
  		meshhdr->flags |= MESH_FLAGS_AE_A4;
61ad53945   Javier Cardona   mac80211: Remove ...
580
  		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
bf7cd94dc   Johannes Berg   mac80211: clean u...
581
  		return 2 * ETH_ALEN;
61ad53945   Javier Cardona   mac80211: Remove ...
582
  	} else if (addr4or5 && addr6) {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
583
  		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
61ad53945   Javier Cardona   mac80211: Remove ...
584
585
  		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
  		memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
bf7cd94dc   Johannes Berg   mac80211: clean u...
586
  		return 3 * ETH_ALEN;
3c5772a52   Javier Cardona   mac80211: Use 3-a...
587
  	}
bf7cd94dc   Johannes Berg   mac80211: clean u...
588
589
  
  	return ETH_ALEN;
902acc789   Johannes Berg   mac80211: clean u...
590
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
591
  static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
472dbc45d   Johannes Berg   mac80211: split o...
592
  {
bf7cd94dc   Johannes Berg   mac80211: clean u...
593
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
df3238189   Marco Porsch   mac80211: fix unn...
594
  	u32 changed;
472dbc45d   Johannes Berg   mac80211: split o...
595

31f909a2c   Masashi Honma   nl/mac80211: allo...
596
597
  	if (ifmsh->mshcfg.plink_timeout > 0)
  		ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
472dbc45d   Johannes Berg   mac80211: split o...
598
  	mesh_path_expire(sdata);
df3238189   Marco Porsch   mac80211: fix unn...
599
  	changed = mesh_accept_plinks_update(sdata);
2b5e19677   Thomas Pedersen   mac80211: cache m...
600
  	ieee80211_mbss_info_change_notify(sdata, changed);
472dbc45d   Johannes Berg   mac80211: split o...
601

472dbc45d   Johannes Berg   mac80211: split o...
602
  	mod_timer(&ifmsh->housekeeping_timer,
bf7cd94dc   Johannes Berg   mac80211: clean u...
603
604
  		  round_jiffies(jiffies +
  				IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
472dbc45d   Johannes Berg   mac80211: split o...
605
  }
e304bfd30   Rui Paulo   mac80211: impleme...
606
607
608
  static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
a69cc44fe   Chun-Yeow Yeoh   mac80211: impleme...
609
  	u32 interval;
e304bfd30   Rui Paulo   mac80211: impleme...
610
611
  
  	mesh_path_tx_root_frame(sdata);
a69cc44fe   Chun-Yeow Yeoh   mac80211: impleme...
612
613
614
615
616
  
  	if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN)
  		interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
  	else
  		interval = ifmsh->mshcfg.dot11MeshHWMProotInterval;
e304bfd30   Rui Paulo   mac80211: impleme...
617
  	mod_timer(&ifmsh->mesh_path_root_timer,
a69cc44fe   Chun-Yeow Yeoh   mac80211: impleme...
618
  		  round_jiffies(TU_TO_EXP_TIME(interval)));
e304bfd30   Rui Paulo   mac80211: impleme...
619
  }
2b5e19677   Thomas Pedersen   mac80211: cache m...
620
621
622
623
624
625
626
627
  static int
  ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
  {
  	struct beacon_data *bcn;
  	int head_len, tail_len;
  	struct sk_buff *skb;
  	struct ieee80211_mgmt *mgmt;
  	struct ieee80211_chanctx_conf *chanctx_conf;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
628
  	struct mesh_csa_settings *csa;
57fbcce37   Johannes Berg   cfg80211: remove ...
629
  	enum nl80211_band band;
2b5e19677   Thomas Pedersen   mac80211: cache m...
630
631
632
633
634
635
636
637
638
639
640
641
642
  	u8 *pos;
  	struct ieee80211_sub_if_data *sdata;
  	int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
  		      sizeof(mgmt->u.beacon);
  
  	sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
  	rcu_read_lock();
  	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  	band = chanctx_conf->def.chan->band;
  	rcu_read_unlock();
  
  	head_len = hdr_len +
  		   2 + /* NULL SSID */
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
643
644
  		   /* Channel Switch Announcement */
  		   2 + sizeof(struct ieee80211_channel_sw_ie) +
08a7e621f   Masahiro Yamada   scripts/spelling....
645
  		   /* Mesh Channel Switch Parameters */
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
646
  		   2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
75d627d53   Simon Wunderlich   mac80211: mesh: s...
647
648
649
  		   /* Channel Switch Wrapper + Wide Bandwidth CSA IE */
  		   2 + 2 + sizeof(struct ieee80211_wide_bw_chansw_ie) +
  		   2 + sizeof(struct ieee80211_sec_chan_offs_ie) +
2b5e19677   Thomas Pedersen   mac80211: cache m...
650
651
652
653
654
655
656
657
  		   2 + 8 + /* supported rates */
  		   2 + 3; /* DS params */
  	tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
  		   2 + sizeof(struct ieee80211_ht_cap) +
  		   2 + sizeof(struct ieee80211_ht_operation) +
  		   2 + ifmsh->mesh_id_len +
  		   2 + sizeof(struct ieee80211_meshconf_ie) +
  		   2 + sizeof(__le16) + /* awake window */
c85fb53c4   Bob Copeland   mac80211: impleme...
658
659
  		   2 + sizeof(struct ieee80211_vht_cap) +
  		   2 + sizeof(struct ieee80211_vht_operation) +
2b5e19677   Thomas Pedersen   mac80211: cache m...
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
  		   ifmsh->ie_len;
  
  	bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
  	/* need an skb for IE builders to operate on */
  	skb = dev_alloc_skb(max(head_len, tail_len));
  
  	if (!bcn || !skb)
  		goto out_free;
  
  	/*
  	 * pointers go into the block we allocated,
  	 * memory is | beacon_data | head | tail |
  	 */
  	bcn->head = ((u8 *) bcn) + sizeof(*bcn);
  
  	/* fill in the head */
b080db585   Johannes Berg   networking: conve...
676
  	mgmt = skb_put_zero(skb, hdr_len);
2b5e19677   Thomas Pedersen   mac80211: cache m...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  					  IEEE80211_STYPE_BEACON);
  	eth_broadcast_addr(mgmt->da);
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
  	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
  	ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt);
  	mgmt->u.beacon.beacon_int =
  		cpu_to_le16(sdata->vif.bss_conf.beacon_int);
  	mgmt->u.beacon.capab_info |= cpu_to_le16(
  		sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
  
  	pos = skb_put(skb, 2);
  	*pos++ = WLAN_EID_SSID;
  	*pos++ = 0x0;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
691
692
693
  	rcu_read_lock();
  	csa = rcu_dereference(ifmsh->csa);
  	if (csa) {
75d627d53   Simon Wunderlich   mac80211: mesh: s...
694
695
696
697
  		enum nl80211_channel_type ct;
  		struct cfg80211_chan_def *chandef;
  		int ie_len = 2 + sizeof(struct ieee80211_channel_sw_ie) +
  			     2 + sizeof(struct ieee80211_mesh_chansw_params_ie);
e45a79da8   Johannes Berg   skbuff/mac80211: ...
698
  		pos = skb_put_zero(skb, ie_len);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
699
700
701
702
703
  		*pos++ = WLAN_EID_CHANNEL_SWITCH;
  		*pos++ = 3;
  		*pos++ = 0x0;
  		*pos++ = ieee80211_frequency_to_channel(
  				csa->settings.chandef.chan->center_freq);
8df734e86   Chun-Yeow Yeoh   mac80211: fix the...
704
  		bcn->csa_current_counter = csa->settings.count;
af296bdb8   Michal Kazior   mac80211: move cs...
705
  		bcn->csa_counter_offsets[0] = hdr_len + 6;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
706
707
708
  		*pos++ = csa->settings.count;
  		*pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
  		*pos++ = 6;
0cb4d4dce   Luciano Coelho   mac80211: refacto...
709
  		if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) {
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
710
711
712
713
714
715
716
717
718
  			*pos++ = ifmsh->mshcfg.dot11MeshTTL;
  			*pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
  		} else {
  			*pos++ = ifmsh->chsw_ttl;
  		}
  		*pos++ |= csa->settings.block_tx ?
  			  WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
  		put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
  		pos += 2;
ca91dc97b   Chun-Yeow Yeoh   mac80211: use put...
719
  		put_unaligned_le16(ifmsh->pre_value, pos);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
720
  		pos += 2;
75d627d53   Simon Wunderlich   mac80211: mesh: s...
721
722
723
724
  
  		switch (csa->settings.chandef.width) {
  		case NL80211_CHAN_WIDTH_40:
  			ie_len = 2 + sizeof(struct ieee80211_sec_chan_offs_ie);
e45a79da8   Johannes Berg   skbuff/mac80211: ...
725
  			pos = skb_put_zero(skb, ie_len);
75d627d53   Simon Wunderlich   mac80211: mesh: s...
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
  
  			*pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
  			*pos++ = 1;				    /* len */
  			ct = cfg80211_get_chandef_type(&csa->settings.chandef);
  			if (ct == NL80211_CHAN_HT40PLUS)
  				*pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
  			else
  				*pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
  			break;
  		case NL80211_CHAN_WIDTH_80:
  		case NL80211_CHAN_WIDTH_80P80:
  		case NL80211_CHAN_WIDTH_160:
  			/* Channel Switch Wrapper + Wide Bandwidth CSA IE */
  			ie_len = 2 + 2 +
  				 sizeof(struct ieee80211_wide_bw_chansw_ie);
e45a79da8   Johannes Berg   skbuff/mac80211: ...
741
  			pos = skb_put_zero(skb, ie_len);
75d627d53   Simon Wunderlich   mac80211: mesh: s...
742
743
744
745
746
747
748
749
750
751
  
  			*pos++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER; /* EID */
  			*pos++ = 5;				  /* len */
  			/* put sub IE */
  			chandef = &csa->settings.chandef;
  			ieee80211_ie_build_wide_bw_cs(pos, chandef);
  			break;
  		default:
  			break;
  		}
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
752
753
  	}
  	rcu_read_unlock();
2b5e19677   Thomas Pedersen   mac80211: cache m...
754
  	if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
bf7cd94dc   Johannes Berg   mac80211: clean u...
755
  	    mesh_add_ds_params_ie(sdata, skb))
2b5e19677   Thomas Pedersen   mac80211: cache m...
756
757
758
759
760
761
762
763
764
765
  		goto out_free;
  
  	bcn->head_len = skb->len;
  	memcpy(bcn->head, skb->data, bcn->head_len);
  
  	/* now the tail */
  	skb_trim(skb, 0);
  	bcn->tail = bcn->head + bcn->head_len;
  
  	if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
bf7cd94dc   Johannes Berg   mac80211: clean u...
766
767
768
769
770
771
  	    mesh_add_rsn_ie(sdata, skb) ||
  	    mesh_add_ht_cap_ie(sdata, skb) ||
  	    mesh_add_ht_oper_ie(sdata, skb) ||
  	    mesh_add_meshid_ie(sdata, skb) ||
  	    mesh_add_meshconf_ie(sdata, skb) ||
  	    mesh_add_awake_window_ie(sdata, skb) ||
c85fb53c4   Bob Copeland   mac80211: impleme...
772
773
  	    mesh_add_vht_cap_ie(sdata, skb) ||
  	    mesh_add_vht_oper_ie(sdata, skb) ||
bf7cd94dc   Johannes Berg   mac80211: clean u...
774
  	    mesh_add_vendor_ies(sdata, skb))
2b5e19677   Thomas Pedersen   mac80211: cache m...
775
776
777
778
  		goto out_free;
  
  	bcn->tail_len = skb->len;
  	memcpy(bcn->tail, skb->data, bcn->tail_len);
43552be1d   Thomas Pedersen   mac80211: update ...
779
780
  	bcn->meshconf = (struct ieee80211_meshconf_ie *)
  					(bcn->tail + ifmsh->meshconf_offset);
2b5e19677   Thomas Pedersen   mac80211: cache m...
781
782
783
784
785
786
787
788
789
790
791
  
  	dev_kfree_skb(skb);
  	rcu_assign_pointer(ifmsh->beacon, bcn);
  	return 0;
  out_free:
  	kfree(bcn);
  	dev_kfree_skb(skb);
  	return -ENOMEM;
  }
  
  static int
8d61ffa5e   Johannes Berg   cfg80211/mac80211...
792
  ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata)
2b5e19677   Thomas Pedersen   mac80211: cache m...
793
  {
2b5e19677   Thomas Pedersen   mac80211: cache m...
794
795
  	struct beacon_data *old_bcn;
  	int ret;
2b5e19677   Thomas Pedersen   mac80211: cache m...
796

8d61ffa5e   Johannes Berg   cfg80211/mac80211...
797
798
799
  	old_bcn = rcu_dereference_protected(sdata->u.mesh.beacon,
  					    lockdep_is_held(&sdata->wdev.mtx));
  	ret = ieee80211_mesh_build_beacon(&sdata->u.mesh);
2b5e19677   Thomas Pedersen   mac80211: cache m...
800
801
  	if (ret)
  		/* just reuse old beacon */
8d61ffa5e   Johannes Berg   cfg80211/mac80211...
802
  		return ret;
2b5e19677   Thomas Pedersen   mac80211: cache m...
803
804
805
  
  	if (old_bcn)
  		kfree_rcu(old_bcn, rcu_head);
8d61ffa5e   Johannes Berg   cfg80211/mac80211...
806
  	return 0;
2b5e19677   Thomas Pedersen   mac80211: cache m...
807
808
809
810
811
  }
  
  void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
  				       u32 changed)
  {
f81a9deda   Thomas Pedersen   mac80211: update ...
812
813
814
815
816
817
818
819
820
821
822
823
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	unsigned long bits = changed;
  	u32 bit;
  
  	if (!bits)
  		return;
  
  	/* if we race with running work, worst case this work becomes a noop */
  	for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
  		set_bit(bit, &ifmsh->mbss_changed);
  	set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
  	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
2b5e19677   Thomas Pedersen   mac80211: cache m...
824
825
826
  }
  
  int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
472dbc45d   Johannes Berg   mac80211: split o...
827
828
829
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct ieee80211_local *local = sdata->local;
f4eabc918   Chun-Yeow Yeoh   mac80211: use sho...
830
831
832
833
834
  	u32 changed = BSS_CHANGED_BEACON |
  		      BSS_CHANGED_BEACON_ENABLED |
  		      BSS_CHANGED_HT |
  		      BSS_CHANGED_BASIC_RATES |
  		      BSS_CHANGED_BEACON_INT;
472dbc45d   Johannes Berg   mac80211: split o...
835

09b174702   Johannes Berg   mac80211: move me...
836
837
838
839
  	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...
840
  	ifmsh->mesh_cc_id = 0;	/* Disabled */
dbf498fba   Javier Cardona   mac80211: Impleme...
841
842
  	/* register sync ops from extensible synchronization framework */
  	ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id);
dbf498fba   Javier Cardona   mac80211: Impleme...
843
  	ifmsh->sync_offset_clockdrift_max = 0;
6b9ac4425   Rui Paulo   mesh: use set_bit...
844
  	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
63c5723bc   Rui Paulo   mac80211: add nl8...
845
  	ieee80211_mesh_root_setup(ifmsh);
64592c8fc   Johannes Berg   mac80211: use com...
846
  	ieee80211_queue_work(&local->hw, &sdata->work);
70c33eaae   Ashok Nagarajan   {nl,cfg,mac}80211...
847
848
  	sdata->vif.bss_conf.ht_operation_mode =
  				ifmsh->mshcfg.ht_opmode;
d6a832288   Johannes Berg   mac80211: track e...
849
  	sdata->vif.bss_conf.enable_beacon = true;
f4eabc918   Chun-Yeow Yeoh   mac80211: use sho...
850

39886b618   Thomas Pedersen   mac80211: consoli...
851
  	changed |= ieee80211_mps_local_status_update(sdata);
3f52b7e32   Marco Porsch   mac80211: mesh po...
852

2b5e19677   Thomas Pedersen   mac80211: cache m...
853
854
855
856
  	if (ieee80211_mesh_build_beacon(ifmsh)) {
  		ieee80211_stop_mesh(sdata);
  		return -ENOMEM;
  	}
057d5f4ba   Thomas Pedersen   mac80211: sync dt...
857
  	ieee80211_recalc_dtim(local, sdata);
f4eabc918   Chun-Yeow Yeoh   mac80211: use sho...
858
  	ieee80211_bss_info_change_notify(sdata, changed);
c405c6298   Johannes Berg   mac80211: manage ...
859
860
  
  	netif_carrier_on(sdata->dev);
2b5e19677   Thomas Pedersen   mac80211: cache m...
861
  	return 0;
472dbc45d   Johannes Berg   mac80211: split o...
862
863
864
865
  }
  
  void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
  {
09b174702   Johannes Berg   mac80211: move me...
866
  	struct ieee80211_local *local = sdata->local;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
867
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2b5e19677   Thomas Pedersen   mac80211: cache m...
868
  	struct beacon_data *bcn;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
869

c405c6298   Johannes Berg   mac80211: manage ...
870
  	netif_carrier_off(sdata->dev);
c37a54ac3   Maital Hahn   mac80211: mesh: f...
871
872
873
  	/* flush STAs and mpaths on this iface */
  	sta_info_flush(sdata);
  	mesh_path_flush_by_iface(sdata);
0d466b9c6   Thomas Pedersen   mac80211: improve...
874
  	/* stop the beacon */
29cbe68c5   Johannes Berg   cfg80211/mac80211...
875
  	ifmsh->mesh_id_len = 0;
d6a832288   Johannes Berg   mac80211: track e...
876
877
  	sdata->vif.bss_conf.enable_beacon = false;
  	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
29cbe68c5   Johannes Berg   cfg80211/mac80211...
878
  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
c37a54ac3   Maital Hahn   mac80211: mesh: f...
879
880
  
  	/* remove beacon */
2b5e19677   Thomas Pedersen   mac80211: cache m...
881
  	bcn = rcu_dereference_protected(ifmsh->beacon,
8d61ffa5e   Johannes Berg   cfg80211/mac80211...
882
  					lockdep_is_held(&sdata->wdev.mtx));
0c2bef462   Monam Agarwal   mac80211: use RCU...
883
  	RCU_INIT_POINTER(ifmsh->beacon, NULL);
2b5e19677   Thomas Pedersen   mac80211: cache m...
884
  	kfree_rcu(bcn, rcu_head);
0d466b9c6   Thomas Pedersen   mac80211: improve...
885

3f52b7e32   Marco Porsch   mac80211: mesh po...
886
887
888
  	/* free all potentially still buffered group-addressed frames */
  	local->total_ps_buffered -= skb_queue_len(&ifmsh->ps.bc_buf);
  	skb_queue_purge(&ifmsh->ps.bc_buf);
472dbc45d   Johannes Berg   mac80211: split o...
889
  	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
e304bfd30   Rui Paulo   mac80211: impleme...
890
  	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
dd4c9260e   Johannes Berg   mac80211: cancel ...
891
  	del_timer_sync(&sdata->u.mesh.mesh_path_timer);
09b174702   Johannes Berg   mac80211: move me...
892

f81a9deda   Thomas Pedersen   mac80211: update ...
893
894
895
  	/* clear any mesh work (for next join) we may have accrued */
  	ifmsh->wrkq_flags = 0;
  	ifmsh->mbss_changed = 0;
09b174702   Johannes Berg   mac80211: move me...
896
897
898
  	local->fif_other_bss--;
  	atomic_dec(&local->iff_allmultis);
  	ieee80211_configure_filter(local);
472dbc45d   Johannes Berg   mac80211: split o...
899
  }
5d55371b2   Benjamin Berg   mac80211: mesh: m...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
  static void ieee80211_mesh_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
  {
  	int err;
  
  	/* if the current channel is a DFS channel, mark the channel as
  	 * unavailable.
  	 */
  	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
  					    &sdata->vif.bss_conf.chandef,
  					    NL80211_IFTYPE_MESH_POINT);
  	if (err > 0)
  		cfg80211_radar_event(sdata->local->hw.wiphy,
  				     &sdata->vif.bss_conf.chandef, GFP_ATOMIC);
  }
33a45867c   Chun-Yeow Yeoh   mac80211: process...
914
915
916
917
918
919
  static bool
  ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
  				 struct ieee802_11_elems *elems, bool beacon)
  {
  	struct cfg80211_csa_settings params;
  	struct ieee80211_csa_ie csa_ie;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
920
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
921
  	struct ieee80211_supported_band *sband;
0cb4d4dce   Luciano Coelho   mac80211: refacto...
922
  	int err;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
923
  	u32 sta_flags;
dbd72850d   Michal Kazior   mac80211: add mis...
924
  	sdata_assert_lock(sdata);
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
925
926
927
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return false;
71ec289e6   Simon Wunderlich   mac80211: enable ...
928
  	sta_flags = 0;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
929
930
931
932
933
  	switch (sdata->vif.bss_conf.chandef.width) {
  	case NL80211_CHAN_WIDTH_20_NOHT:
  		sta_flags |= IEEE80211_STA_DISABLE_HT;
  	case NL80211_CHAN_WIDTH_20:
  		sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
71ec289e6   Simon Wunderlich   mac80211: enable ...
934
935
  	case NL80211_CHAN_WIDTH_40:
  		sta_flags |= IEEE80211_STA_DISABLE_VHT;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
936
937
938
939
940
941
  		break;
  	default:
  		break;
  	}
  
  	memset(&params, 0, sizeof(params));
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
942
  	err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band,
33a45867c   Chun-Yeow Yeoh   mac80211: process...
943
944
945
946
947
948
  					   sta_flags, sdata->vif.addr,
  					   &csa_ie);
  	if (err < 0)
  		return false;
  	if (err)
  		return false;
5d55371b2   Benjamin Berg   mac80211: mesh: m...
949
950
951
952
953
  	/* Mark the channel unavailable if the reason for the switch is
  	 * regulatory.
  	 */
  	if (csa_ie.reason_code == WLAN_REASON_MESH_CHAN_REGULATORY)
  		ieee80211_mesh_csa_mark_radar(sdata);
33a45867c   Chun-Yeow Yeoh   mac80211: process...
954
955
  	params.chandef = csa_ie.chandef;
  	params.count = csa_ie.count;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
956
  	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
0ab2e55d3   Benjamin Berg   mac80211: mesh: A...
957
958
959
  				     IEEE80211_CHAN_DISABLED) ||
  	    !cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef,
  				     NL80211_IFTYPE_MESH_POINT)) {
33a45867c   Chun-Yeow Yeoh   mac80211: process...
960
961
962
963
964
965
966
967
968
969
970
971
  		sdata_info(sdata,
  			   "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting
  ",
  			   sdata->vif.addr,
  			   params.chandef.chan->center_freq,
  			   params.chandef.width,
  			   params.chandef.center_freq1,
  			   params.chandef.center_freq2);
  		return false;
  	}
  
  	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
2beb6dab2   Luciano Coelho   cfg80211/mac80211...
972
973
  					    &params.chandef,
  					    NL80211_IFTYPE_MESH_POINT);
33a45867c   Chun-Yeow Yeoh   mac80211: process...
974
975
  	if (err < 0)
  		return false;
0ab2e55d3   Benjamin Berg   mac80211: mesh: A...
976
977
978
979
980
981
982
983
984
  	if (err > 0 && !ifmsh->userspace_handles_dfs) {
  		sdata_info(sdata,
  			   "mesh STA %pM switches to channel requiring DFS (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting
  ",
  			   sdata->vif.addr,
  			   params.chandef.chan->center_freq,
  			   params.chandef.width,
  			   params.chandef.center_freq1,
  			   params.chandef.center_freq2);
33a45867c   Chun-Yeow Yeoh   mac80211: process...
985
  		return false;
0ab2e55d3   Benjamin Berg   mac80211: mesh: A...
986
  	}
2beb6dab2   Luciano Coelho   cfg80211/mac80211...
987
988
  
  	params.radar_required = err;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
989

0cb4d4dce   Luciano Coelho   mac80211: refacto...
990
991
992
993
994
995
996
  	if (cfg80211_chandef_identical(&params.chandef,
  				       &sdata->vif.bss_conf.chandef)) {
  		mcsa_dbg(sdata,
  			 "received csa with an identical chandef, ignoring
  ");
  		return true;
  	}
33a45867c   Chun-Yeow Yeoh   mac80211: process...
997
998
999
1000
1001
1002
1003
  
  	mcsa_dbg(sdata,
  		 "received channel switch announcement to go to channel %d MHz
  ",
  		 params.chandef.chan->center_freq);
  
  	params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
3f718fd84   Chun-Yeow Yeoh   mac80211: fix the...
1004
  	if (beacon) {
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1005
  		ifmsh->chsw_ttl = csa_ie.ttl - 1;
3f718fd84   Chun-Yeow Yeoh   mac80211: fix the...
1006
1007
1008
1009
  		if (ifmsh->pre_value >= csa_ie.pre_value)
  			return false;
  		ifmsh->pre_value = csa_ie.pre_value;
  	}
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1010

0cb4d4dce   Luciano Coelho   mac80211: refacto...
1011
  	if (ifmsh->chsw_ttl >= ifmsh->mshcfg.dot11MeshTTL)
3f718fd84   Chun-Yeow Yeoh   mac80211: fix the...
1012
  		return false;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1013

0cb4d4dce   Luciano Coelho   mac80211: refacto...
1014
  	ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_REPEATER;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1015

0cb4d4dce   Luciano Coelho   mac80211: refacto...
1016
1017
1018
  	if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev,
  				     &params) < 0)
  		return false;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1019
1020
  
  	return true;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1021
  }
9fb04b501   Thomas Pedersen   mac80211: generat...
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
  static void
  ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
  			    struct ieee80211_mgmt *mgmt, size_t len)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct sk_buff *presp;
  	struct beacon_data *bcn;
  	struct ieee80211_mgmt *hdr;
  	struct ieee802_11_elems elems;
  	size_t baselen;
511044ea0   Johannes Berg   mac80211: remove ...
1033
  	u8 *pos;
9fb04b501   Thomas Pedersen   mac80211: generat...
1034

9fb04b501   Thomas Pedersen   mac80211: generat...
1035
1036
1037
1038
  	pos = mgmt->u.probe_req.variable;
  	baselen = (u8 *) pos - (u8 *) mgmt;
  	if (baselen > len)
  		return;
b2e506bfc   Johannes Berg   mac80211: parse V...
1039
  	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
9fb04b501   Thomas Pedersen   mac80211: generat...
1040

a4ef66a91   Chun-Yeow Yeoh   mac80211: only re...
1041
1042
  	if (!elems.mesh_id)
  		return;
9fb04b501   Thomas Pedersen   mac80211: generat...
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
  	/* 802.11-2012 10.1.4.3.2 */
  	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
  	     !is_broadcast_ether_addr(mgmt->da)) ||
  	    elems.ssid_len != 0)
  		return;
  
  	if (elems.mesh_id_len != 0 &&
  	    (elems.mesh_id_len != ifmsh->mesh_id_len ||
  	     memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
  		return;
  
  	rcu_read_lock();
  	bcn = rcu_dereference(ifmsh->beacon);
  
  	if (!bcn)
  		goto out;
  
  	presp = dev_alloc_skb(local->tx_headroom +
  			      bcn->head_len + bcn->tail_len);
  	if (!presp)
  		goto out;
  
  	skb_reserve(presp, local->tx_headroom);
59ae1d127   Johannes Berg   networking: intro...
1066
1067
  	skb_put_data(presp, bcn->head, bcn->head_len);
  	skb_put_data(presp, bcn->tail, bcn->tail_len);
9fb04b501   Thomas Pedersen   mac80211: generat...
1068
1069
1070
1071
  	hdr = (struct ieee80211_mgmt *) presp->data;
  	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  					 IEEE80211_STYPE_PROBE_RESP);
  	memcpy(hdr->da, mgmt->sa, ETH_ALEN);
9fb04b501   Thomas Pedersen   mac80211: generat...
1072
1073
1074
1075
1076
  	IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
  	ieee80211_tx_skb(sdata, presp);
  out:
  	rcu_read_unlock();
  }
472dbc45d   Johannes Berg   mac80211: split o...
1077
1078
1079
1080
1081
1082
  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...
1083
  	struct ieee80211_local *local = sdata->local;
dbf498fba   Javier Cardona   mac80211: Impleme...
1084
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
472dbc45d   Johannes Berg   mac80211: split o...
1085
1086
  	struct ieee802_11_elems elems;
  	struct ieee80211_channel *channel;
472dbc45d   Johannes Berg   mac80211: split o...
1087
1088
  	size_t baselen;
  	int freq;
57fbcce37   Johannes Berg   cfg80211: remove ...
1089
  	enum nl80211_band band = rx_status->band;
472dbc45d   Johannes Berg   mac80211: split o...
1090
1091
1092
  
  	/* ignore ProbeResp to foreign address */
  	if (stype == IEEE80211_STYPE_PROBE_RESP &&
b203ca391   Joe Perches   mac80211: Convert...
1093
  	    !ether_addr_equal(mgmt->da, sdata->vif.addr))
472dbc45d   Johannes Berg   mac80211: split o...
1094
1095
1096
1097
1098
1099
1100
  		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,
b2e506bfc   Johannes Berg   mac80211: parse V...
1101
  			       false, &elems);
472dbc45d   Johannes Berg   mac80211: split o...
1102

9a90bc819   Thomas Pedersen   mac80211: mesh ST...
1103
1104
1105
1106
  	/* ignore non-mesh or secure / unsecure mismatch */
  	if ((!elems.mesh_id || !elems.mesh_config) ||
  	    (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
  	    (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
5cff5e01e   Javier Cardona   mac80211: ignore ...
1107
  		return;
1cd8e88e1   Johannes Berg   mac80211: check D...
1108
  	if (elems.ds_params)
59eb21a65   Bruno Randolf   cfg80211: Extend ...
1109
  		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
472dbc45d   Johannes Berg   mac80211: split o...
1110
1111
1112
1113
1114
1115
1116
  	else
  		freq = rx_status->freq;
  
  	channel = ieee80211_get_channel(local->hw.wiphy, freq);
  
  	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
  		return;
ed92a9b5d   Masashi Honma   mac80211: mesh: d...
1117
1118
1119
1120
1121
1122
1123
1124
1125
  	if (mesh_matches_local(sdata, &elems)) {
  		mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d
  ",
  			sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal);
  		if (!sdata->u.mesh.user_mpm ||
  		    sdata->u.mesh.mshcfg.rssi_threshold == 0 ||
  		    sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal)
  			mesh_neighbour_update(sdata, mgmt->sa, &elems);
  	}
dbf498fba   Javier Cardona   mac80211: Impleme...
1126
1127
1128
1129
  
  	if (ifmsh->sync_ops)
  		ifmsh->sync_ops->rx_bcn_presp(sdata,
  			stype, mgmt, &elems, rx_status);
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1130

0cb4d4dce   Luciano Coelho   mac80211: refacto...
1131
1132
  	if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT &&
  	    !sdata->vif.csa_active)
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1133
  		ieee80211_mesh_process_chnswitch(sdata, &elems, true);
472dbc45d   Johannes Berg   mac80211: split o...
1134
  }
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1135
1136
1137
1138
1139
  int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct mesh_csa_settings *tmp_csa_settings;
  	int ret = 0;
faf046e72   Michal Kazior   mac80211: batch C...
1140
  	int changed = 0;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1141
1142
  
  	/* Reset the TTL value and Initiator flag */
0cb4d4dce   Luciano Coelho   mac80211: refacto...
1143
  	ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1144
1145
1146
1147
  	ifmsh->chsw_ttl = 0;
  
  	/* Remove the CSA and MCSP elements from the beacon */
  	tmp_csa_settings = rcu_dereference(ifmsh->csa);
0c2bef462   Monam Agarwal   mac80211: use RCU...
1148
  	RCU_INIT_POINTER(ifmsh->csa, NULL);
66e01cf99   Luciano Coelho   mac80211: only se...
1149
1150
  	if (tmp_csa_settings)
  		kfree_rcu(tmp_csa_settings, rcu_head);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1151
1152
1153
  	ret = ieee80211_mesh_rebuild_beacon(sdata);
  	if (ret)
  		return -EINVAL;
faf046e72   Michal Kazior   mac80211: batch C...
1154
  	changed |= BSS_CHANGED_BEACON;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1155
1156
1157
  
  	mcsa_dbg(sdata, "complete switching to center freq %d MHz",
  		 sdata->vif.bss_conf.chandef.chan->center_freq);
faf046e72   Michal Kazior   mac80211: batch C...
1158
  	return changed;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1159
1160
1161
  }
  
  int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
66e01cf99   Luciano Coelho   mac80211: only se...
1162
  			      struct cfg80211_csa_settings *csa_settings)
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct mesh_csa_settings *tmp_csa_settings;
  	int ret = 0;
  
  	tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
  				   GFP_ATOMIC);
  	if (!tmp_csa_settings)
  		return -ENOMEM;
  
  	memcpy(&tmp_csa_settings->settings, csa_settings,
  	       sizeof(struct cfg80211_csa_settings));
  
  	rcu_assign_pointer(ifmsh->csa, tmp_csa_settings);
  
  	ret = ieee80211_mesh_rebuild_beacon(sdata);
  	if (ret) {
  		tmp_csa_settings = rcu_dereference(ifmsh->csa);
0c2bef462   Monam Agarwal   mac80211: use RCU...
1181
  		RCU_INIT_POINTER(ifmsh->csa, NULL);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1182
1183
1184
  		kfree_rcu(tmp_csa_settings, rcu_head);
  		return ret;
  	}
b58e81e96   Luciano Coelho   mac80211: align i...
1185
  	return BSS_CHANGED_BEACON;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1186
  }
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1187
  static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
0f097096b   Peter Oh   mac80211: mesh: f...
1188
1189
  			       struct ieee80211_mgmt *mgmt, size_t len,
  			       struct ieee802_11_elems *elems)
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1190
1191
1192
1193
  {
  	struct ieee80211_mgmt *mgmt_fwd;
  	struct sk_buff *skb;
  	struct ieee80211_local *local = sdata->local;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1194
1195
1196
1197
1198
  
  	skb = dev_alloc_skb(local->tx_headroom + len);
  	if (!skb)
  		return -ENOMEM;
  	skb_reserve(skb, local->tx_headroom);
4df864c1d   Johannes Berg   networking: make ...
1199
  	mgmt_fwd = skb_put(skb, len);
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1200

0f097096b   Peter Oh   mac80211: mesh: f...
1201
1202
1203
  	elems->mesh_chansw_params_ie->mesh_ttl--;
  	elems->mesh_chansw_params_ie->mesh_flags &=
  		~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
  
  	memcpy(mgmt_fwd, mgmt, len);
  	eth_broadcast_addr(mgmt_fwd->da);
  	memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
  	memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
  
  	ieee80211_tx_skb(sdata, skb);
  	return 0;
  }
  
  static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
  			      struct ieee80211_mgmt *mgmt, size_t len)
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct ieee802_11_elems elems;
  	u16 pre_value;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1220
  	bool fwd_csa = true;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1221
  	size_t baselen;
3f718fd84   Chun-Yeow Yeoh   mac80211: fix the...
1222
  	u8 *pos;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1223
1224
1225
1226
1227
1228
1229
1230
  
  	if (mgmt->u.action.u.measurement.action_code !=
  	    WLAN_ACTION_SPCT_CHL_SWITCH)
  		return;
  
  	pos = mgmt->u.action.u.chan_switch.variable;
  	baselen = offsetof(struct ieee80211_mgmt,
  			   u.action.u.chan_switch.variable);
3b23782f7   Simon Wunderlich   mac80211: mark as...
1231
  	ieee802_11_parse_elems(pos, len - baselen, true, &elems);
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1232

3f718fd84   Chun-Yeow Yeoh   mac80211: fix the...
1233
1234
  	ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
  	if (!--ifmsh->chsw_ttl)
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1235
1236
1237
1238
1239
1240
1241
  		fwd_csa = false;
  
  	pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
  	if (ifmsh->pre_value >= pre_value)
  		return;
  
  	ifmsh->pre_value = pre_value;
0cb4d4dce   Luciano Coelho   mac80211: refacto...
1242
1243
  	if (!sdata->vif.csa_active &&
  	    !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1244
1245
1246
  		mcsa_dbg(sdata, "Failed to process CSA action frame");
  		return;
  	}
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1247
1248
  	/* forward or re-broadcast the CSA frame */
  	if (fwd_csa) {
0f097096b   Peter Oh   mac80211: mesh: f...
1249
  		if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1250
1251
  			mcsa_dbg(sdata, "Failed to forward the CSA frame");
  	}
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1252
  }
472dbc45d   Johannes Berg   mac80211: split o...
1253
1254
1255
1256
1257
1258
  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 ...
1259
1260
1261
1262
1263
1264
1265
1266
  	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...
1267
  		break;
25d49e4d6   Thomas Pedersen   mac80211: update ...
1268
1269
1270
  	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...
1271
  		break;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1272
1273
1274
  	case WLAN_CATEGORY_SPECTRUM_MGMT:
  		mesh_rx_csa_frame(sdata, mgmt, len);
  		break;
472dbc45d   Johannes Berg   mac80211: split o...
1275
1276
  	}
  }
1fa57d017   Johannes Berg   mac80211: use com...
1277
1278
  void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
  				   struct sk_buff *skb)
472dbc45d   Johannes Berg   mac80211: split o...
1279
1280
  {
  	struct ieee80211_rx_status *rx_status;
472dbc45d   Johannes Berg   mac80211: split o...
1281
1282
  	struct ieee80211_mgmt *mgmt;
  	u16 stype;
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1283
1284
1285
  	sdata_lock(sdata);
  
  	/* mesh already went down */
1693d3441   Johannes Berg   mac80211: use sda...
1286
  	if (!sdata->u.mesh.mesh_id_len)
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1287
  		goto out;
f1d58c252   Johannes Berg   mac80211: push rx...
1288
  	rx_status = IEEE80211_SKB_RXCB(skb);
472dbc45d   Johannes Berg   mac80211: split o...
1289
1290
1291
1292
1293
1294
1295
1296
1297
  	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;
9fb04b501   Thomas Pedersen   mac80211: generat...
1298
1299
1300
  	case IEEE80211_STYPE_PROBE_REQ:
  		ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len);
  		break;
472dbc45d   Johannes Berg   mac80211: split o...
1301
1302
1303
1304
  	case IEEE80211_STYPE_ACTION:
  		ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
  		break;
  	}
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1305
1306
  out:
  	sdata_unlock(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1307
  }
f81a9deda   Thomas Pedersen   mac80211: update ...
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
  static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	u32 bit, changed = 0;
  
  	for_each_set_bit(bit, &ifmsh->mbss_changed,
  			 sizeof(changed) * BITS_PER_BYTE) {
  		clear_bit(bit, &ifmsh->mbss_changed);
  		changed |= BIT(bit);
  	}
  
  	if (sdata->vif.bss_conf.enable_beacon &&
  	    (changed & (BSS_CHANGED_BEACON |
  			BSS_CHANGED_HT |
  			BSS_CHANGED_BASIC_RATES |
  			BSS_CHANGED_BEACON_INT)))
  		if (ieee80211_mesh_rebuild_beacon(sdata))
  			return;
  
  	ieee80211_bss_info_change_notify(sdata, changed);
  }
1fa57d017   Johannes Berg   mac80211: use com...
1329
  void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
472dbc45d   Johannes Berg   mac80211: split o...
1330
  {
472dbc45d   Johannes Berg   mac80211: split o...
1331
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
472dbc45d   Johannes Berg   mac80211: split o...
1332

ecccd072b   Thomas Pedersen   mac80211: fix mes...
1333
1334
1335
  	sdata_lock(sdata);
  
  	/* mesh already went down */
1693d3441   Johannes Berg   mac80211: use sda...
1336
  	if (!sdata->u.mesh.mesh_id_len)
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1337
  		goto out;
472dbc45d   Johannes Berg   mac80211: split o...
1338
1339
1340
1341
  	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...
1342
  	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
bf7cd94dc   Johannes Berg   mac80211: clean u...
1343
  		ieee80211_mesh_housekeeping(sdata);
e304bfd30   Rui Paulo   mac80211: impleme...
1344
1345
1346
  
  	if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
  		ieee80211_mesh_rootpath(sdata);
dbf498fba   Javier Cardona   mac80211: Impleme...
1347
1348
  
  	if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
445cd452f   Masashi Honma   mac80211: Use app...
1349
  		mesh_sync_adjust_tsf(sdata);
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1350

f81a9deda   Thomas Pedersen   mac80211: update ...
1351
1352
  	if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags))
  		mesh_bss_info_changed(sdata);
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1353
1354
  out:
  	sdata_unlock(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1355
  }
472dbc45d   Johannes Berg   mac80211: split o...
1356

902acc789   Johannes Berg   mac80211: clean u...
1357
1358
  void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
  {
472dbc45d   Johannes Berg   mac80211: split o...
1359
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
ad2d223aa   Johannes Berg   mac80211: assign ...
1360
  	static u8 zero_addr[ETH_ALEN] = {};
472dbc45d   Johannes Berg   mac80211: split o...
1361

472dbc45d   Johannes Berg   mac80211: split o...
1362
1363
1364
  	setup_timer(&ifmsh->housekeeping_timer,
  		    ieee80211_mesh_housekeeping_timer,
  		    (unsigned long) sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1365

472dbc45d   Johannes Berg   mac80211: split o...
1366
  	ifmsh->accepting_plinks = true;
472dbc45d   Johannes Berg   mac80211: split o...
1367
  	atomic_set(&ifmsh->mpaths, 0);
f698d856f   Jasper Bryant-Greene   replace net_devic...
1368
  	mesh_rmc_init(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1369
  	ifmsh->last_preq = jiffies;
dca7e9430   Thomas Pedersen   {nl,cfg,mac}80211...
1370
  	ifmsh->next_perr = jiffies;
0cb4d4dce   Luciano Coelho   mac80211: refacto...
1371
  	ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
902acc789   Johannes Berg   mac80211: clean u...
1372
1373
1374
  	/* Allocate all mesh structures when creating the first mesh interface. */
  	if (!mesh_allocated)
  		ieee80211s_init();
2bdaf386f   Bob Copeland   mac80211: mesh: m...
1375
1376
  
  	mesh_pathtbl_init(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1377
  	setup_timer(&ifmsh->mesh_path_timer,
902acc789   Johannes Berg   mac80211: clean u...
1378
1379
  		    ieee80211_mesh_path_timer,
  		    (unsigned long) sdata);
e304bfd30   Rui Paulo   mac80211: impleme...
1380
1381
1382
  	setup_timer(&ifmsh->mesh_path_root_timer,
  		    ieee80211_mesh_path_root_timer,
  		    (unsigned long) sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1383
  	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
3f52b7e32   Marco Porsch   mac80211: mesh po...
1384
  	skb_queue_head_init(&ifmsh->ps.bc_buf);
472dbc45d   Johannes Berg   mac80211: split o...
1385
  	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
dbf498fba   Javier Cardona   mac80211: Impleme...
1386
  	spin_lock_init(&ifmsh->sync_offset_lock);
2b5e19677   Thomas Pedersen   mac80211: cache m...
1387
  	RCU_INIT_POINTER(ifmsh->beacon, NULL);
ad2d223aa   Johannes Berg   mac80211: assign ...
1388
1389
  
  	sdata->vif.bss_conf.bssid = zero_addr;
472dbc45d   Johannes Berg   mac80211: split o...
1390
  }
0371a08fb   Bob Copeland   mac80211: mesh: f...
1391
1392
1393
1394
1395
1396
  
  void ieee80211_mesh_teardown_sdata(struct ieee80211_sub_if_data *sdata)
  {
  	mesh_rmc_free(sdata);
  	mesh_pathtbl_unregister(sdata);
  }