Blame view

net/mac80211/mesh.c 44.2 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
2e3c87368   Luis Carlos Cobo   mac80211: support...
2
  /*
264d9b7d8   Rui Paulo   mac80211: update ...
3
   * Copyright (c) 2008, 2009 open80211s Ltd.
2a333a0db   Johannes Berg   mac80211: avoid u...
4
   * Copyright (C) 2018 - 2020 Intel Corporation
2e3c87368   Luis Carlos Cobo   mac80211: support...
5
6
   * Authors:    Luis Carlos Cobo <luisca@cozybit.com>
   * 	       Javier Cardona <javier@cozybit.com>
2e3c87368   Luis Carlos Cobo   mac80211: support...
7
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
8
  #include <linux/slab.h>
51ceddade   Luis Carlos Cobo   mac80211: use 4-b...
9
  #include <asm/unaligned.h>
2e3c87368   Luis Carlos Cobo   mac80211: support...
10
11
  #include "ieee80211_i.h"
  #include "mesh.h"
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
12
  #include "driver-ops.h"
2e3c87368   Luis Carlos Cobo   mac80211: support...
13

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

2e3c87368   Luis Carlos Cobo   mac80211: support...
22
23
  void ieee80211s_init(void)
  {
2e3c87368   Luis Carlos Cobo   mac80211: support...
24
25
26
27
28
29
30
  	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...
31
32
  	if (!mesh_allocated)
  		return;
2e3c87368   Luis Carlos Cobo   mac80211: support...
33
34
  	kmem_cache_destroy(rm_cache);
  }
34f11cd32   Kees Cook   mac80211: Convert...
35
  static void ieee80211_mesh_housekeeping_timer(struct timer_list *t)
472dbc45d   Johannes Berg   mac80211: split o...
36
  {
34f11cd32   Kees Cook   mac80211: Convert...
37
38
  	struct ieee80211_sub_if_data *sdata =
  		from_timer(sdata, t, u.mesh.housekeeping_timer);
472dbc45d   Johannes Berg   mac80211: split o...
39
40
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
6b9ac4425   Rui Paulo   mesh: use set_bit...
41
  	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
5bb644a0f   Johannes Berg   mac80211: cancel/...
42

64592c8fc   Johannes Berg   mac80211: use com...
43
  	ieee80211_queue_work(&local->hw, &sdata->work);
472dbc45d   Johannes Berg   mac80211: split o...
44
  }
2e3c87368   Luis Carlos Cobo   mac80211: support...
45
46
47
  /**
   * mesh_matches_local - check if the config of a mesh point matches ours
   *
f698d856f   Jasper Bryant-Greene   replace net_devic...
48
   * @sdata: local mesh subif
f743ff490   Thomas Pedersen   mac80211: refacto...
49
   * @ie: information elements of a management frame from the mesh peer
2e3c87368   Luis Carlos Cobo   mac80211: support...
50
51
52
53
   *
   * 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...
54
55
  bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
  			struct ieee802_11_elems *ie)
2e3c87368   Luis Carlos Cobo   mac80211: support...
56
  {
472dbc45d   Johannes Berg   mac80211: split o...
57
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
f743ff490   Thomas Pedersen   mac80211: refacto...
58
  	u32 basic_rates = 0;
4bf88530b   Johannes Berg   mac80211: convert...
59
  	struct cfg80211_chan_def sta_chan_def;
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
60
  	struct ieee80211_supported_band *sband;
2a333a0db   Johannes Berg   mac80211: avoid u...
61
  	u32 vht_cap_info = 0;
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
  	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);
2a333a0db   Johannes Berg   mac80211: avoid u...
94
95
96
97
98
  
  	if (ie->vht_cap_elem)
  		vht_cap_info = le32_to_cpu(ie->vht_cap_elem->vht_cap_info);
  
  	ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info,
7eb26df29   Johannes Berg   mac80211: add abi...
99
100
  				   ie->vht_operation, ie->ht_operation,
  				   &sta_chan_def);
57fa5e85d   Johannes Berg   mac80211: determi...
101
  	ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, &sta_chan_def);
c85fb53c4   Bob Copeland   mac80211: impleme...
102

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

739522baa   Thomas Pedersen   mac80211: set HT ...
107
  	return true;
2e3c87368   Luis Carlos Cobo   mac80211: support...
108
109
110
111
112
113
  }
  
  /**
   * 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...
114
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
115
  bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
2e3c87368   Luis Carlos Cobo   mac80211: support...
116
  {
136cfa286   Rui Paulo   mac80211: use a s...
117
  	return (ie->mesh_config->meshconf_cap &
bf7cd94dc   Johannes Berg   mac80211: clean u...
118
  			IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
2e3c87368   Luis Carlos Cobo   mac80211: support...
119
120
121
  }
  
  /**
2c53040f0   Ben Hutchings   net: Fix (nearly-...
122
   * mesh_accept_plinks_update - update accepting_plink in local mesh beacons
2e3c87368   Luis Carlos Cobo   mac80211: support...
123
   *
d0709a651   Johannes Berg   mac80211: RCU-ify...
124
   * @sdata: mesh interface in which mesh beacons are going to be updated
df3238189   Marco Porsch   mac80211: fix unn...
125
126
   *
   * Returns: beacon changed flag if the beacon content changed.
2e3c87368   Luis Carlos Cobo   mac80211: support...
127
   */
df3238189   Marco Porsch   mac80211: fix unn...
128
  u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
2e3c87368   Luis Carlos Cobo   mac80211: support...
129
  {
2e3c87368   Luis Carlos Cobo   mac80211: support...
130
  	bool free_plinks;
df3238189   Marco Porsch   mac80211: fix unn...
131
  	u32 changed = 0;
2e3c87368   Luis Carlos Cobo   mac80211: support...
132
133
134
  
  	/* 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...
135
136
137
  	 * 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...
138
139
  	 */
  	free_plinks = mesh_plink_availables(sdata);
df3238189   Marco Porsch   mac80211: fix unn...
140
141
142
143
144
145
  	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...
146
  }
45b5028e8   Thomas Pedersen   mac80211: fix mes...
147
148
149
150
151
152
153
154
  /*
   * 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...
155
  	u32 changed = mesh_plink_deactivate(sta);
fe7a7c576   Bob Copeland   mac80211: mesh: f...
156

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

0aa7fabbd   Bob Copeland   mac80211: mesh: h...
213
214
  	if (!rmc)
  		return -1;
2e3c87368   Luis Carlos Cobo   mac80211: support...
215
  	/* Don't care about endianness since only match matters */
51ceddade   Luis Carlos Cobo   mac80211: use 4-b...
216
217
  	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...
218
  	hlist_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
2e3c87368   Luis Carlos Cobo   mac80211: support...
219
220
  		++entries;
  		if (time_after(jiffies, p->exp_time) ||
bf7cd94dc   Johannes Berg   mac80211: clean u...
221
  		    entries == RMC_QUEUE_MAX_LEN) {
47a0489ce   Bob Copeland   mac80211: mesh: u...
222
  			hlist_del(&p->list);
2e3c87368   Luis Carlos Cobo   mac80211: support...
223
224
  			kmem_cache_free(rm_cache, p);
  			--entries;
bf7cd94dc   Johannes Berg   mac80211: clean u...
225
  		} else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa))
2e3c87368   Luis Carlos Cobo   mac80211: support...
226
227
228
229
  			return -1;
  	}
  
  	p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
d15b84590   Joe Perches   mac80211: Remove ...
230
  	if (!p)
2e3c87368   Luis Carlos Cobo   mac80211: support...
231
  		return 0;
d15b84590   Joe Perches   mac80211: Remove ...
232

2e3c87368   Luis Carlos Cobo   mac80211: support...
233
234
235
  	p->seqnum = seqnum;
  	p->exp_time = jiffies + RMC_TIMEOUT;
  	memcpy(p->sa, sa, ETH_ALEN);
47a0489ce   Bob Copeland   mac80211: mesh: u...
236
  	hlist_add_head(&p->list, &rmc->bucket[idx]);
2e3c87368   Luis Carlos Cobo   mac80211: support...
237
238
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
239
240
  int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
  			 struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
241
242
243
244
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	u8 *pos, neighbors;
  	u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
4a6ecd35f   Bob Copeland   mac80211: mesh: a...
245
  	bool is_connected_to_gate = ifmsh->num_gates > 0 ||
01d66fbd5   Bob Copeland   {nl,mac}80211: ad...
246
247
  		ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol ||
  		ifmsh->mshcfg.dot11MeshConnectedToMeshGate;
184eebe66   Markus Theil   cfg80211/mac80211...
248
  	bool is_connected_to_as = ifmsh->mshcfg.dot11MeshConnectedToAuthServer;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
249
250
251
252
253
254
255
  
  	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 ...
256
257
  	/* save a pointer for quick updates in pre-tbtt */
  	ifmsh->meshconf_offset = pos - skb->data;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
258
259
260
261
262
263
264
265
266
267
268
  	/* 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...
269
  	neighbors = atomic_read(&ifmsh->estab_plinks);
e05ecccdf   Jacob Minshall   mac80211: set mes...
270
  	neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS);
184eebe66   Markus Theil   cfg80211/mac80211...
271
272
273
  	*pos++ = (is_connected_to_as << 7) |
  		 (neighbors << 1) |
  		 is_connected_to_gate;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
274
  	/* Mesh capability */
b60e527a7   Chun-Yeow Yeoh   mac80211: set for...
275
276
277
  	*pos = 0x00;
  	*pos |= ifmsh->mshcfg.dot11MeshForwarding ?
  			IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00;
dbf498fba   Javier Cardona   mac80211: Impleme...
278
  	*pos |= ifmsh->accepting_plinks ?
bf7cd94dc   Johannes Berg   mac80211: clean u...
279
  			IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
3f52b7e32   Marco Porsch   mac80211: mesh po...
280
281
  	/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
  	*pos |= ifmsh->ps_peers_deep_sleep ?
bf7cd94dc   Johannes Berg   mac80211: clean u...
282
  			IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
283
284
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
285
  int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  {
  	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...
301
302
  static int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata,
  				    struct sk_buff *skb)
3f52b7e32   Marco Porsch   mac80211: mesh po...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  {
  	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...
323
324
  int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
  			struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
325
326
327
328
329
330
331
332
333
334
  {
  	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...
335
  	if (offset < ifmsh->ie_len) {
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
336
337
338
339
  		len = ifmsh->ie_len - offset;
  		data = ifmsh->ie + offset;
  		if (skb_tailroom(skb) < len)
  			return -ENOMEM;
59ae1d127   Johannes Berg   networking: intro...
340
  		skb_put_data(skb, data, len);
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
341
342
343
344
  	}
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
345
  int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
346
347
348
349
350
351
352
353
354
  {
  	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...
355
356
357
  	data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len);
  	if (!data)
  		return 0;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
358

a40a8c17b   Bob Copeland   mac80211: fix mes...
359
360
361
362
  	len = data[1] + 2;
  
  	if (skb_tailroom(skb) < len)
  		return -ENOMEM;
59ae1d127   Johannes Berg   networking: intro...
363
  	skb_put_data(skb, data, len);
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
364
365
366
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
367
368
  static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata,
  				 struct sk_buff *skb)
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
369
  {
55de908ab   Johannes Berg   mac80211: use cha...
370
371
  	struct ieee80211_chanctx_conf *chanctx_conf;
  	struct ieee80211_channel *chan;
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
372
  	u8 *pos;
2e3c87368   Luis Carlos Cobo   mac80211: support...
373

082ebb0c2   Thomas Pedersen   mac80211: fix mes...
374
375
  	if (skb_tailroom(skb) < 3)
  		return -ENOMEM;
55de908ab   Johannes Berg   mac80211: use cha...
376
377
378
379
380
381
  	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...
382
  	chan = chanctx_conf->def.chan;
55de908ab   Johannes Berg   mac80211: use cha...
383
  	rcu_read_unlock();
601513aa2   Emanuel Taube   mac80211: Add the...
384
385
386
387
  	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...
388

082ebb0c2   Thomas Pedersen   mac80211: fix mes...
389
  	return 0;
2e3c87368   Luis Carlos Cobo   mac80211: support...
390
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
391
392
  int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
  		       struct sk_buff *skb)
176f36086   Thomas Pedersen   mac80211: add HT ...
393
  {
176f36086   Thomas Pedersen   mac80211: add HT ...
394
395
  	struct ieee80211_supported_band *sband;
  	u8 *pos;
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
396
397
398
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return -EINVAL;
607ca9ea3   Rajkumar Manoharan   mac80211: do not ...
399
400
401
  	/* HT not allowed in 6 GHz */
  	if (sband->band == NL80211_BAND_6GHZ)
  		return 0;
176f36086   Thomas Pedersen   mac80211: add HT ...
402
  	if (!sband->ht_cap.ht_supported ||
0418a4458   Simon Wunderlich   mac80211: fix var...
403
404
405
  	    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 ...
406
407
408
409
410
411
  		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...
412
  	ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
176f36086   Thomas Pedersen   mac80211: add HT ...
413
414
415
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
416
417
  int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
  			struct sk_buff *skb)
176f36086   Thomas Pedersen   mac80211: add HT ...
418
419
  {
  	struct ieee80211_local *local = sdata->local;
55de908ab   Johannes Berg   mac80211: use cha...
420
421
  	struct ieee80211_chanctx_conf *chanctx_conf;
  	struct ieee80211_channel *channel;
55de908ab   Johannes Berg   mac80211: use cha...
422
423
  	struct ieee80211_supported_band *sband;
  	struct ieee80211_sta_ht_cap *ht_cap;
176f36086   Thomas Pedersen   mac80211: add HT ...
424
  	u8 *pos;
55de908ab   Johannes Berg   mac80211: use cha...
425
426
427
428
429
430
  	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...
431
  	channel = chanctx_conf->def.chan;
55de908ab   Johannes Berg   mac80211: use cha...
432
433
434
435
  	rcu_read_unlock();
  
  	sband = local->hw.wiphy->bands[channel->band];
  	ht_cap = &sband->ht_cap;
607ca9ea3   Rajkumar Manoharan   mac80211: do not ...
436
437
438
  	/* HT not allowed in 6 GHz */
  	if (sband->band == NL80211_BAND_6GHZ)
  		return 0;
c85fb53c4   Bob Copeland   mac80211: impleme...
439
440
441
442
  	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 ...
443
  		return 0;
074d46d1d   Johannes Berg   wireless: rename ...
444
  	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
176f36086   Thomas Pedersen   mac80211: add HT ...
445
  		return -ENOMEM;
074d46d1d   Johannes Berg   wireless: rename ...
446
  	pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
4bf88530b   Johannes Berg   mac80211: convert...
447
  	ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
57f255f58   Arik Nemtsov   mac80211: TDLS: a...
448
449
  				   sdata->vif.bss_conf.ht_operation_mode,
  				   false);
176f36086   Thomas Pedersen   mac80211: add HT ...
450
451
452
  
  	return 0;
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
453

c85fb53c4   Bob Copeland   mac80211: impleme...
454
455
456
  int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata,
  			struct sk_buff *skb)
  {
c85fb53c4   Bob Copeland   mac80211: impleme...
457
458
  	struct ieee80211_supported_band *sband;
  	u8 *pos;
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
459
460
461
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return -EINVAL;
607ca9ea3   Rajkumar Manoharan   mac80211: do not ...
462
463
464
  	/* VHT not allowed in 6 GHz */
  	if (sband->band == NL80211_BAND_6GHZ)
  		return 0;
c85fb53c4   Bob Copeland   mac80211: impleme...
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
495
496
497
498
499
500
  	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;
607ca9ea3   Rajkumar Manoharan   mac80211: do not ...
501
502
503
  	/* VHT not allowed in 6 GHz */
  	if (sband->band == NL80211_BAND_6GHZ)
  		return 0;
c85fb53c4   Bob Copeland   mac80211: impleme...
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  	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;
  }
60ad72da5   Sven Eckelmann   mac80211: impleme...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata,
  		       struct sk_buff *skb, u8 ie_len)
  {
  	const struct ieee80211_sta_he_cap *he_cap;
  	struct ieee80211_supported_band *sband;
  	u8 *pos;
  
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return -EINVAL;
  
  	he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT);
  
  	if (!he_cap ||
  	    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) < ie_len)
  		return -ENOMEM;
  
  	pos = skb_put(skb, ie_len);
  	ieee80211_ie_build_he_cap(pos, he_cap, pos + ie_len);
  
  	return 0;
  }
  
  int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata,
  			struct sk_buff *skb)
  {
  	const struct ieee80211_sta_he_cap *he_cap;
  	struct ieee80211_supported_band *sband;
d1b7524b3   Rajkumar Manoharan   mac80211: build H...
552
  	u32 len;
60ad72da5   Sven Eckelmann   mac80211: impleme...
553
554
555
556
557
558
559
560
561
562
563
564
  	u8 *pos;
  
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return -EINVAL;
  
  	he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT);
  	if (!he_cap ||
  	    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;
d1b7524b3   Rajkumar Manoharan   mac80211: build H...
565
566
567
568
569
  	len = 2 + 1 + sizeof(struct ieee80211_he_operation);
  	if (sdata->vif.bss_conf.chandef.chan->band == NL80211_BAND_6GHZ)
  		len += sizeof(struct ieee80211_he_6ghz_oper);
  
  	if (skb_tailroom(skb) < len)
60ad72da5   Sven Eckelmann   mac80211: impleme...
570
  		return -ENOMEM;
d1b7524b3   Rajkumar Manoharan   mac80211: build H...
571
572
  	pos = skb_put(skb, len);
  	ieee80211_ie_build_he_oper(pos, &sdata->vif.bss_conf.chandef);
60ad72da5   Sven Eckelmann   mac80211: impleme...
573
574
575
  
  	return 0;
  }
24a2042cb   Rajkumar Manoharan   mac80211: add HE ...
576
577
578
  int mesh_add_he_6ghz_cap_ie(struct ieee80211_sub_if_data *sdata,
  			    struct sk_buff *skb)
  {
65ad3ef9f   Rajkumar Manoharan   mac80211: fix war...
579
580
581
582
583
584
585
586
587
588
589
590
  	struct ieee80211_supported_band *sband;
  	const struct ieee80211_sband_iftype_data *iftd;
  
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return -EINVAL;
  
  	iftd = ieee80211_get_sband_iftype_data(sband,
  					       NL80211_IFTYPE_MESH_POINT);
  	/* The device doesn't support HE in mesh mode or at all */
  	if (!iftd)
  		return 0;
24a2042cb   Rajkumar Manoharan   mac80211: add HE ...
591
592
593
  	ieee80211_ie_build_he_6ghz_cap(sdata, skb);
  	return 0;
  }
34f11cd32   Kees Cook   mac80211: Convert...
594
  static void ieee80211_mesh_path_timer(struct timer_list *t)
2e3c87368   Luis Carlos Cobo   mac80211: support...
595
596
  {
  	struct ieee80211_sub_if_data *sdata =
34f11cd32   Kees Cook   mac80211: Convert...
597
  		from_timer(sdata, t, u.mesh.mesh_path_timer);
5bb644a0f   Johannes Berg   mac80211: cancel/...
598

690205f18   Stanislaw Gruszka   mac80211: cleanup...
599
  	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
2e3c87368   Luis Carlos Cobo   mac80211: support...
600
  }
34f11cd32   Kees Cook   mac80211: Convert...
601
  static void ieee80211_mesh_path_root_timer(struct timer_list *t)
e304bfd30   Rui Paulo   mac80211: impleme...
602
603
  {
  	struct ieee80211_sub_if_data *sdata =
34f11cd32   Kees Cook   mac80211: Convert...
604
  		from_timer(sdata, t, u.mesh.mesh_path_root_timer);
e304bfd30   Rui Paulo   mac80211: impleme...
605
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
e304bfd30   Rui Paulo   mac80211: impleme...
606
607
  
  	set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
690205f18   Stanislaw Gruszka   mac80211: cleanup...
608
  	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
e304bfd30   Rui Paulo   mac80211: impleme...
609
  }
63c5723bc   Rui Paulo   mac80211: add nl8...
610
611
  void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
  {
dbb912cd4   Chun-Yeow Yeoh   mac80211: invoke ...
612
  	if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)
63c5723bc   Rui Paulo   mac80211: add nl8...
613
614
615
616
617
618
619
  		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...
620
  /**
3c5772a52   Javier Cardona   mac80211: Use 3-a...
621
   * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
bf7cd94dc   Johannes Berg   mac80211: clean u...
622
   * @hdr:	802.11 frame header
3c5772a52   Javier Cardona   mac80211: Use 3-a...
623
624
   * @fc:		frame control field
   * @meshda:	destination address in the mesh
13880a3b5   Randy Dunlap   net: mac80211: me...
625
   * @meshsa:	source address in the mesh.  Same as TA, as frame is
3c5772a52   Javier Cardona   mac80211: Use 3-a...
626
627
628
629
   *              locally originated.
   *
   * Return the length of the 802.11 (does not include a mesh control header)
   */
15ff63653   Johannes Berg   mac80211: use fix...
630
631
632
  int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
  				  const u8 *meshda, const u8 *meshsa)
  {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
633
634
635
636
637
638
639
640
  	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...
641
  		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
3c5772a52   Javier Cardona   mac80211: Use 3-a...
642
  		/* RA TA DA SA */
c84a67a2f   Joe Perches   mac80211: Use eth...
643
  		eth_zero_addr(hdr->addr1);   /* RA is resolved later */
3c5772a52   Javier Cardona   mac80211: Use 3-a...
644
645
646
647
648
649
650
651
  		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...
652
   * ieee80211_new_mesh_header - create a new mesh header
902acc789   Johannes Berg   mac80211: clean u...
653
   * @sdata:	mesh interface to be used
bf7cd94dc   Johannes Berg   mac80211: clean u...
654
   * @meshhdr:    uninitialized mesh header
61ad53945   Javier Cardona   mac80211: Remove ...
655
656
657
658
659
   * @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...
660
661
662
   *
   * Return the header length.
   */
5edfcee5e   Andrzej Hajda   mac80211: make ie...
663
664
665
  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...
666
  {
bf7cd94dc   Johannes Berg   mac80211: clean u...
667
668
  	if (WARN_ON(!addr4or5 && addr6))
  		return 0;
0c3cee72a   Julia Lawall   net/mac80211: Cor...
669
  	memset(meshhdr, 0, sizeof(*meshhdr));
bf7cd94dc   Johannes Berg   mac80211: clean u...
670

472dbc45d   Johannes Berg   mac80211: split o...
671
  	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
bf7cd94dc   Johannes Berg   mac80211: clean u...
672
673
  
  	/* FIXME: racy -- TX on multiple queues can be concurrent */
472dbc45d   Johannes Berg   mac80211: split o...
674
675
  	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
  	sdata->u.mesh.mesh_seqnum++;
bf7cd94dc   Johannes Berg   mac80211: clean u...
676

61ad53945   Javier Cardona   mac80211: Remove ...
677
  	if (addr4or5 && !addr6) {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
678
  		meshhdr->flags |= MESH_FLAGS_AE_A4;
61ad53945   Javier Cardona   mac80211: Remove ...
679
  		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
bf7cd94dc   Johannes Berg   mac80211: clean u...
680
  		return 2 * ETH_ALEN;
61ad53945   Javier Cardona   mac80211: Remove ...
681
  	} else if (addr4or5 && addr6) {
3c5772a52   Javier Cardona   mac80211: Use 3-a...
682
  		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
61ad53945   Javier Cardona   mac80211: Remove ...
683
684
  		memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
  		memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
bf7cd94dc   Johannes Berg   mac80211: clean u...
685
  		return 3 * ETH_ALEN;
3c5772a52   Javier Cardona   mac80211: Use 3-a...
686
  	}
bf7cd94dc   Johannes Berg   mac80211: clean u...
687
688
  
  	return ETH_ALEN;
902acc789   Johannes Berg   mac80211: clean u...
689
  }
bf7cd94dc   Johannes Berg   mac80211: clean u...
690
  static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
472dbc45d   Johannes Berg   mac80211: split o...
691
  {
bf7cd94dc   Johannes Berg   mac80211: clean u...
692
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
df3238189   Marco Porsch   mac80211: fix unn...
693
  	u32 changed;
472dbc45d   Johannes Berg   mac80211: split o...
694

31f909a2c   Masashi Honma   nl/mac80211: allo...
695
696
  	if (ifmsh->mshcfg.plink_timeout > 0)
  		ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
472dbc45d   Johannes Berg   mac80211: split o...
697
  	mesh_path_expire(sdata);
df3238189   Marco Porsch   mac80211: fix unn...
698
  	changed = mesh_accept_plinks_update(sdata);
2b5e19677   Thomas Pedersen   mac80211: cache m...
699
  	ieee80211_mbss_info_change_notify(sdata, changed);
472dbc45d   Johannes Berg   mac80211: split o...
700

472dbc45d   Johannes Berg   mac80211: split o...
701
  	mod_timer(&ifmsh->housekeeping_timer,
bf7cd94dc   Johannes Berg   mac80211: clean u...
702
703
  		  round_jiffies(jiffies +
  				IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
472dbc45d   Johannes Berg   mac80211: split o...
704
  }
e304bfd30   Rui Paulo   mac80211: impleme...
705
706
707
  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...
708
  	u32 interval;
e304bfd30   Rui Paulo   mac80211: impleme...
709
710
  
  	mesh_path_tx_root_frame(sdata);
a69cc44fe   Chun-Yeow Yeoh   mac80211: impleme...
711
712
713
714
715
  
  	if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN)
  		interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
  	else
  		interval = ifmsh->mshcfg.dot11MeshHWMProotInterval;
e304bfd30   Rui Paulo   mac80211: impleme...
716
  	mod_timer(&ifmsh->mesh_path_root_timer,
a69cc44fe   Chun-Yeow Yeoh   mac80211: impleme...
717
  		  round_jiffies(TU_TO_EXP_TIME(interval)));
e304bfd30   Rui Paulo   mac80211: impleme...
718
  }
2b5e19677   Thomas Pedersen   mac80211: cache m...
719
720
721
722
723
724
725
726
  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...
727
  	struct mesh_csa_settings *csa;
57fbcce37   Johannes Berg   cfg80211: remove ...
728
  	enum nl80211_band band;
60ad72da5   Sven Eckelmann   mac80211: impleme...
729
  	u8 ie_len_he_cap;
2b5e19677   Thomas Pedersen   mac80211: cache m...
730
731
  	u8 *pos;
  	struct ieee80211_sub_if_data *sdata;
4c121fd69   Johannes Berg   mac80211: use off...
732
  	int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon);
2b5e19677   Thomas Pedersen   mac80211: cache m...
733
734
735
736
737
738
  
  	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();
60ad72da5   Sven Eckelmann   mac80211: impleme...
739
740
  	ie_len_he_cap = ieee80211_ie_len_he_cap(sdata,
  						NL80211_IFTYPE_MESH_POINT);
2b5e19677   Thomas Pedersen   mac80211: cache m...
741
742
  	head_len = hdr_len +
  		   2 + /* NULL SSID */
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
743
744
  		   /* Channel Switch Announcement */
  		   2 + sizeof(struct ieee80211_channel_sw_ie) +
08a7e621f   Masahiro Yamada   scripts/spelling....
745
  		   /* Mesh Channel Switch Parameters */
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
746
  		   2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
75d627d53   Simon Wunderlich   mac80211: mesh: s...
747
748
749
  		   /* 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...
750
751
752
753
754
755
756
757
  		   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...
758
759
  		   2 + sizeof(struct ieee80211_vht_cap) +
  		   2 + sizeof(struct ieee80211_vht_operation) +
60ad72da5   Sven Eckelmann   mac80211: impleme...
760
761
  		   ie_len_he_cap +
  		   2 + 1 + sizeof(struct ieee80211_he_operation) +
d1b7524b3   Rajkumar Manoharan   mac80211: build H...
762
  			   sizeof(struct ieee80211_he_6ghz_oper) +
24a2042cb   Rajkumar Manoharan   mac80211: add HE ...
763
  		   2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
2b5e19677   Thomas Pedersen   mac80211: cache m...
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
  		   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...
780
  	mgmt = skb_put_zero(skb, hdr_len);
2b5e19677   Thomas Pedersen   mac80211: cache m...
781
782
783
784
785
786
787
788
789
790
791
792
793
794
  	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...
795
796
797
  	rcu_read_lock();
  	csa = rcu_dereference(ifmsh->csa);
  	if (csa) {
75d627d53   Simon Wunderlich   mac80211: mesh: s...
798
799
800
801
  		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: ...
802
  		pos = skb_put_zero(skb, ie_len);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
803
804
805
806
807
  		*pos++ = WLAN_EID_CHANNEL_SWITCH;
  		*pos++ = 3;
  		*pos++ = 0x0;
  		*pos++ = ieee80211_frequency_to_channel(
  				csa->settings.chandef.chan->center_freq);
8552a434b   John Crispin   mac80211: rename ...
808
809
  		bcn->cntdwn_current_counter = csa->settings.count;
  		bcn->cntdwn_counter_offsets[0] = hdr_len + 6;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
810
811
812
  		*pos++ = csa->settings.count;
  		*pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
  		*pos++ = 6;
0cb4d4dce   Luciano Coelho   mac80211: refacto...
813
  		if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) {
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
814
815
816
817
818
819
820
821
822
  			*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...
823
  		put_unaligned_le16(ifmsh->pre_value, pos);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
824
  		pos += 2;
75d627d53   Simon Wunderlich   mac80211: mesh: s...
825
826
827
828
  
  		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: ...
829
  			pos = skb_put_zero(skb, ie_len);
75d627d53   Simon Wunderlich   mac80211: mesh: s...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  
  			*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: ...
845
  			pos = skb_put_zero(skb, ie_len);
75d627d53   Simon Wunderlich   mac80211: mesh: s...
846
847
848
849
850
851
852
853
854
855
  
  			*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...
856
857
  	}
  	rcu_read_unlock();
2b5e19677   Thomas Pedersen   mac80211: cache m...
858
  	if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
bf7cd94dc   Johannes Berg   mac80211: clean u...
859
  	    mesh_add_ds_params_ie(sdata, skb))
2b5e19677   Thomas Pedersen   mac80211: cache m...
860
861
862
863
864
865
866
867
868
869
  		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...
870
871
872
873
874
875
  	    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...
876
877
  	    mesh_add_vht_cap_ie(sdata, skb) ||
  	    mesh_add_vht_oper_ie(sdata, skb) ||
60ad72da5   Sven Eckelmann   mac80211: impleme...
878
879
  	    mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) ||
  	    mesh_add_he_oper_ie(sdata, skb) ||
24a2042cb   Rajkumar Manoharan   mac80211: add HE ...
880
  	    mesh_add_he_6ghz_cap_ie(sdata, skb) ||
bf7cd94dc   Johannes Berg   mac80211: clean u...
881
  	    mesh_add_vendor_ies(sdata, skb))
2b5e19677   Thomas Pedersen   mac80211: cache m...
882
883
884
885
  		goto out_free;
  
  	bcn->tail_len = skb->len;
  	memcpy(bcn->tail, skb->data, bcn->tail_len);
43552be1d   Thomas Pedersen   mac80211: update ...
886
887
  	bcn->meshconf = (struct ieee80211_meshconf_ie *)
  					(bcn->tail + ifmsh->meshconf_offset);
2b5e19677   Thomas Pedersen   mac80211: cache m...
888
889
890
891
892
893
894
895
896
897
898
  
  	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...
899
  ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata)
2b5e19677   Thomas Pedersen   mac80211: cache m...
900
  {
2b5e19677   Thomas Pedersen   mac80211: cache m...
901
902
  	struct beacon_data *old_bcn;
  	int ret;
2b5e19677   Thomas Pedersen   mac80211: cache m...
903

8d61ffa5e   Johannes Berg   cfg80211/mac80211...
904
905
906
  	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...
907
908
  	if (ret)
  		/* just reuse old beacon */
8d61ffa5e   Johannes Berg   cfg80211/mac80211...
909
  		return ret;
2b5e19677   Thomas Pedersen   mac80211: cache m...
910
911
912
  
  	if (old_bcn)
  		kfree_rcu(old_bcn, rcu_head);
8d61ffa5e   Johannes Berg   cfg80211/mac80211...
913
  	return 0;
2b5e19677   Thomas Pedersen   mac80211: cache m...
914
915
916
917
918
  }
  
  void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
  				       u32 changed)
  {
f81a9deda   Thomas Pedersen   mac80211: update ...
919
920
921
922
923
924
925
926
927
928
929
930
  	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...
931
932
933
  }
  
  int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
472dbc45d   Johannes Berg   mac80211: split o...
934
935
936
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct ieee80211_local *local = sdata->local;
f4eabc918   Chun-Yeow Yeoh   mac80211: use sho...
937
938
939
940
  	u32 changed = BSS_CHANGED_BEACON |
  		      BSS_CHANGED_BEACON_ENABLED |
  		      BSS_CHANGED_HT |
  		      BSS_CHANGED_BASIC_RATES |
dcbe73ca5   Pradeep Kumar Chitrapu   mac80211: notify ...
941
942
  		      BSS_CHANGED_BEACON_INT |
  		      BSS_CHANGED_MCAST_RATE;
472dbc45d   Johannes Berg   mac80211: split o...
943

09b174702   Johannes Berg   mac80211: move me...
944
945
946
947
  	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...
948
  	ifmsh->mesh_cc_id = 0;	/* Disabled */
dbf498fba   Javier Cardona   mac80211: Impleme...
949
950
  	/* register sync ops from extensible synchronization framework */
  	ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id);
dbf498fba   Javier Cardona   mac80211: Impleme...
951
  	ifmsh->sync_offset_clockdrift_max = 0;
6b9ac4425   Rui Paulo   mesh: use set_bit...
952
  	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
63c5723bc   Rui Paulo   mac80211: add nl8...
953
  	ieee80211_mesh_root_setup(ifmsh);
64592c8fc   Johannes Berg   mac80211: use com...
954
  	ieee80211_queue_work(&local->hw, &sdata->work);
70c33eaae   Ashok Nagarajan   {nl,cfg,mac}80211...
955
956
  	sdata->vif.bss_conf.ht_operation_mode =
  				ifmsh->mshcfg.ht_opmode;
d6a832288   Johannes Berg   mac80211: track e...
957
  	sdata->vif.bss_conf.enable_beacon = true;
f4eabc918   Chun-Yeow Yeoh   mac80211: use sho...
958

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

2b5e19677   Thomas Pedersen   mac80211: cache m...
961
962
963
964
  	if (ieee80211_mesh_build_beacon(ifmsh)) {
  		ieee80211_stop_mesh(sdata);
  		return -ENOMEM;
  	}
057d5f4ba   Thomas Pedersen   mac80211: sync dt...
965
  	ieee80211_recalc_dtim(local, sdata);
f4eabc918   Chun-Yeow Yeoh   mac80211: use sho...
966
  	ieee80211_bss_info_change_notify(sdata, changed);
c405c6298   Johannes Berg   mac80211: manage ...
967
968
  
  	netif_carrier_on(sdata->dev);
2b5e19677   Thomas Pedersen   mac80211: cache m...
969
  	return 0;
472dbc45d   Johannes Berg   mac80211: split o...
970
971
972
973
  }
  
  void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
  {
09b174702   Johannes Berg   mac80211: move me...
974
  	struct ieee80211_local *local = sdata->local;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
975
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2b5e19677   Thomas Pedersen   mac80211: cache m...
976
  	struct beacon_data *bcn;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
977

c405c6298   Johannes Berg   mac80211: manage ...
978
  	netif_carrier_off(sdata->dev);
c37a54ac3   Maital Hahn   mac80211: mesh: f...
979
980
  	/* flush STAs and mpaths on this iface */
  	sta_info_flush(sdata);
0112fa557   Pradeep Kumar Chitrapu   mac80211: free pe...
981
  	ieee80211_free_keys(sdata, true);
c37a54ac3   Maital Hahn   mac80211: mesh: f...
982
  	mesh_path_flush_by_iface(sdata);
0d466b9c6   Thomas Pedersen   mac80211: improve...
983
  	/* stop the beacon */
29cbe68c5   Johannes Berg   cfg80211/mac80211...
984
  	ifmsh->mesh_id_len = 0;
d6a832288   Johannes Berg   mac80211: track e...
985
  	sdata->vif.bss_conf.enable_beacon = false;
08fad438b   Jouni Malinen   mac80211: TX lega...
986
  	sdata->beacon_rate_set = false;
d6a832288   Johannes Berg   mac80211: track e...
987
  	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
29cbe68c5   Johannes Berg   cfg80211/mac80211...
988
  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
c37a54ac3   Maital Hahn   mac80211: mesh: f...
989
990
  
  	/* remove beacon */
2b5e19677   Thomas Pedersen   mac80211: cache m...
991
  	bcn = rcu_dereference_protected(ifmsh->beacon,
8d61ffa5e   Johannes Berg   cfg80211/mac80211...
992
  					lockdep_is_held(&sdata->wdev.mtx));
0c2bef462   Monam Agarwal   mac80211: use RCU...
993
  	RCU_INIT_POINTER(ifmsh->beacon, NULL);
2b5e19677   Thomas Pedersen   mac80211: cache m...
994
  	kfree_rcu(bcn, rcu_head);
0d466b9c6   Thomas Pedersen   mac80211: improve...
995

3f52b7e32   Marco Porsch   mac80211: mesh po...
996
997
998
  	/* 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...
999
  	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
e304bfd30   Rui Paulo   mac80211: impleme...
1000
  	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
dd4c9260e   Johannes Berg   mac80211: cancel ...
1001
  	del_timer_sync(&sdata->u.mesh.mesh_path_timer);
09b174702   Johannes Berg   mac80211: move me...
1002

f81a9deda   Thomas Pedersen   mac80211: update ...
1003
1004
1005
  	/* 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...
1006
1007
1008
  	local->fif_other_bss--;
  	atomic_dec(&local->iff_allmultis);
  	ieee80211_configure_filter(local);
472dbc45d   Johannes Berg   mac80211: split o...
1009
  }
5d55371b2   Benjamin Berg   mac80211: mesh: m...
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
  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...
1024
1025
1026
1027
1028
1029
  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...
1030
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
1031
  	struct ieee80211_supported_band *sband;
0cb4d4dce   Luciano Coelho   mac80211: refacto...
1032
  	int err;
2a333a0db   Johannes Berg   mac80211: avoid u...
1033
  	u32 sta_flags, vht_cap_info = 0;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1034

dbd72850d   Michal Kazior   mac80211: add mis...
1035
  	sdata_assert_lock(sdata);
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
1036
1037
1038
  	sband = ieee80211_get_sband(sdata);
  	if (!sband)
  		return false;
71ec289e6   Simon Wunderlich   mac80211: enable ...
1039
  	sta_flags = 0;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1040
1041
1042
  	switch (sdata->vif.bss_conf.chandef.width) {
  	case NL80211_CHAN_WIDTH_20_NOHT:
  		sta_flags |= IEEE80211_STA_DISABLE_HT;
fc0561dc6   Gustavo A. R. Silva   mac80211: Use fal...
1043
  		fallthrough;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1044
1045
  	case NL80211_CHAN_WIDTH_20:
  		sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
fc0561dc6   Gustavo A. R. Silva   mac80211: Use fal...
1046
  		fallthrough;
71ec289e6   Simon Wunderlich   mac80211: enable ...
1047
1048
  	case NL80211_CHAN_WIDTH_40:
  		sta_flags |= IEEE80211_STA_DISABLE_VHT;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1049
1050
1051
1052
  		break;
  	default:
  		break;
  	}
2a333a0db   Johannes Berg   mac80211: avoid u...
1053
1054
1055
  	if (elems->vht_cap_elem)
  		vht_cap_info =
  			le32_to_cpu(elems->vht_cap_elem->vht_cap_info);
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1056
  	memset(&params, 0, sizeof(params));
21a8e9dd5   Mohammed Shafi Shajakhan   mac80211: Fix pos...
1057
  	err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band,
2a333a0db   Johannes Berg   mac80211: avoid u...
1058
  					   vht_cap_info,
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1059
1060
1061
1062
1063
1064
  					   sta_flags, sdata->vif.addr,
  					   &csa_ie);
  	if (err < 0)
  		return false;
  	if (err)
  		return false;
5d55371b2   Benjamin Berg   mac80211: mesh: m...
1065
1066
1067
1068
1069
  	/* 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...
1070
1071
  	params.chandef = csa_ie.chandef;
  	params.count = csa_ie.count;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1072
  	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
0ab2e55d3   Benjamin Berg   mac80211: mesh: A...
1073
1074
1075
  				     IEEE80211_CHAN_DISABLED) ||
  	    !cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef,
  				     NL80211_IFTYPE_MESH_POINT)) {
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  		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...
1088
1089
  					    &params.chandef,
  					    NL80211_IFTYPE_MESH_POINT);
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1090
1091
  	if (err < 0)
  		return false;
0ab2e55d3   Benjamin Berg   mac80211: mesh: A...
1092
1093
1094
1095
1096
1097
1098
1099
1100
  	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...
1101
  		return false;
0ab2e55d3   Benjamin Berg   mac80211: mesh: A...
1102
  	}
2beb6dab2   Luciano Coelho   cfg80211/mac80211...
1103
1104
  
  	params.radar_required = err;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1105

0cb4d4dce   Luciano Coelho   mac80211: refacto...
1106
1107
1108
1109
1110
1111
1112
  	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...
1113
1114
1115
1116
1117
1118
1119
  
  	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...
1120
  	if (beacon) {
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1121
  		ifmsh->chsw_ttl = csa_ie.ttl - 1;
3f718fd84   Chun-Yeow Yeoh   mac80211: fix the...
1122
1123
1124
1125
  		if (ifmsh->pre_value >= csa_ie.pre_value)
  			return false;
  		ifmsh->pre_value = csa_ie.pre_value;
  	}
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1126

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

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

0cb4d4dce   Luciano Coelho   mac80211: refacto...
1132
1133
1134
  	if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev,
  				     &params) < 0)
  		return false;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1135
1136
  
  	return true;
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1137
  }
9fb04b501   Thomas Pedersen   mac80211: generat...
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  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 ...
1149
  	u8 *pos;
9fb04b501   Thomas Pedersen   mac80211: generat...
1150

9fb04b501   Thomas Pedersen   mac80211: generat...
1151
1152
1153
1154
  	pos = mgmt->u.probe_req.variable;
  	baselen = (u8 *) pos - (u8 *) mgmt;
  	if (baselen > len)
  		return;
4abb52a46   Sara Sharon   mac80211: pass bs...
1155
1156
  	ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid,
  			       NULL);
9fb04b501   Thomas Pedersen   mac80211: generat...
1157

a4ef66a91   Chun-Yeow Yeoh   mac80211: only re...
1158
1159
  	if (!elems.mesh_id)
  		return;
9fb04b501   Thomas Pedersen   mac80211: generat...
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
  	/* 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...
1183
1184
  	skb_put_data(presp, bcn->head, bcn->head_len);
  	skb_put_data(presp, bcn->tail, bcn->tail_len);
9fb04b501   Thomas Pedersen   mac80211: generat...
1185
1186
1187
1188
  	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...
1189
1190
1191
1192
1193
  	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...
1194
1195
1196
1197
1198
1199
  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...
1200
  	struct ieee80211_local *local = sdata->local;
dbf498fba   Javier Cardona   mac80211: Impleme...
1201
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
472dbc45d   Johannes Berg   mac80211: split o...
1202
1203
  	struct ieee802_11_elems elems;
  	struct ieee80211_channel *channel;
472dbc45d   Johannes Berg   mac80211: split o...
1204
1205
  	size_t baselen;
  	int freq;
57fbcce37   Johannes Berg   cfg80211: remove ...
1206
  	enum nl80211_band band = rx_status->band;
472dbc45d   Johannes Berg   mac80211: split o...
1207
1208
1209
  
  	/* ignore ProbeResp to foreign address */
  	if (stype == IEEE80211_STYPE_PROBE_RESP &&
b203ca391   Joe Perches   mac80211: Convert...
1210
  	    !ether_addr_equal(mgmt->da, sdata->vif.addr))
472dbc45d   Johannes Berg   mac80211: split o...
1211
1212
1213
1214
1215
1216
1217
  		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,
4abb52a46   Sara Sharon   mac80211: pass bs...
1218
  			       false, &elems, mgmt->bssid, NULL);
472dbc45d   Johannes Berg   mac80211: split o...
1219

9a90bc819   Thomas Pedersen   mac80211: mesh ST...
1220
1221
1222
1223
  	/* 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 ...
1224
  		return;
1cd8e88e1   Johannes Berg   mac80211: check D...
1225
  	if (elems.ds_params)
59eb21a65   Bruno Randolf   cfg80211: Extend ...
1226
  		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
472dbc45d   Johannes Berg   mac80211: split o...
1227
1228
1229
1230
1231
1232
1233
  	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...
1234
1235
1236
1237
1238
1239
1240
  	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)
ecbc12ad6   Bob Copeland   {nl,mac}80211: ad...
1241
1242
  			mesh_neighbour_update(sdata, mgmt->sa, &elems,
  					      rx_status);
93e2d04a1   Tamizh chelvam   mac80211: fix cha...
1243
1244
1245
1246
  
  		if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT &&
  		    !sdata->vif.csa_active)
  			ieee80211_mesh_process_chnswitch(sdata, &elems, true);
ed92a9b5d   Masashi Honma   mac80211: mesh: d...
1247
  	}
dbf498fba   Javier Cardona   mac80211: Impleme...
1248
1249
1250
1251
  
  	if (ifmsh->sync_ops)
  		ifmsh->sync_ops->rx_bcn_presp(sdata,
  			stype, mgmt, &elems, rx_status);
472dbc45d   Johannes Berg   mac80211: split o...
1252
  }
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1253
1254
1255
1256
1257
  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...
1258
  	int changed = 0;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1259
1260
  
  	/* Reset the TTL value and Initiator flag */
0cb4d4dce   Luciano Coelho   mac80211: refacto...
1261
  	ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1262
1263
1264
  	ifmsh->chsw_ttl = 0;
  
  	/* Remove the CSA and MCSP elements from the beacon */
551842446   Thomas Pedersen   mac80211: mesh: f...
1265
1266
  	tmp_csa_settings = rcu_dereference_protected(ifmsh->csa,
  					    lockdep_is_held(&sdata->wdev.mtx));
0c2bef462   Monam Agarwal   mac80211: use RCU...
1267
  	RCU_INIT_POINTER(ifmsh->csa, NULL);
66e01cf99   Luciano Coelho   mac80211: only se...
1268
1269
  	if (tmp_csa_settings)
  		kfree_rcu(tmp_csa_settings, rcu_head);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1270
1271
1272
  	ret = ieee80211_mesh_rebuild_beacon(sdata);
  	if (ret)
  		return -EINVAL;
faf046e72   Michal Kazior   mac80211: batch C...
1273
  	changed |= BSS_CHANGED_BEACON;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1274
1275
1276
  
  	mcsa_dbg(sdata, "complete switching to center freq %d MHz",
  		 sdata->vif.bss_conf.chandef.chan->center_freq);
faf046e72   Michal Kazior   mac80211: batch C...
1277
  	return changed;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1278
1279
1280
  }
  
  int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
66e01cf99   Luciano Coelho   mac80211: only se...
1281
  			      struct cfg80211_csa_settings *csa_settings)
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1282
1283
1284
1285
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct mesh_csa_settings *tmp_csa_settings;
  	int ret = 0;
551842446   Thomas Pedersen   mac80211: mesh: f...
1286
  	lockdep_assert_held(&sdata->wdev.mtx);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
  	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...
1300
  		RCU_INIT_POINTER(ifmsh->csa, NULL);
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1301
1302
1303
  		kfree_rcu(tmp_csa_settings, rcu_head);
  		return ret;
  	}
b58e81e96   Luciano Coelho   mac80211: align i...
1304
  	return BSS_CHANGED_BEACON;
b8456a14e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1305
  }
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1306
  static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
c4de37ee2   Peter Oh   mac80211: mesh: f...
1307
1308
  			       struct ieee80211_mgmt *mgmt, size_t len,
  			       struct ieee802_11_elems *elems)
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1309
1310
1311
1312
  {
  	struct ieee80211_mgmt *mgmt_fwd;
  	struct sk_buff *skb;
  	struct ieee80211_local *local = sdata->local;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1313
1314
1315
1316
1317
  
  	skb = dev_alloc_skb(local->tx_headroom + len);
  	if (!skb)
  		return -ENOMEM;
  	skb_reserve(skb, local->tx_headroom);
4df864c1d   Johannes Berg   networking: make ...
1318
  	mgmt_fwd = skb_put(skb, len);
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1319

c4de37ee2   Peter Oh   mac80211: mesh: f...
1320
1321
1322
  	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...
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
  
  	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...
1339
  	bool fwd_csa = true;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1340
  	size_t baselen;
3f718fd84   Chun-Yeow Yeoh   mac80211: fix the...
1341
  	u8 *pos;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1342
1343
1344
1345
1346
1347
1348
1349
  
  	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);
4abb52a46   Sara Sharon   mac80211: pass bs...
1350
1351
  	ieee802_11_parse_elems(pos, len - baselen, true, &elems,
  			       mgmt->bssid, NULL);
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1352

93e2d04a1   Tamizh chelvam   mac80211: fix cha...
1353
1354
  	if (!mesh_matches_local(sdata, &elems))
  		return;
3f718fd84   Chun-Yeow Yeoh   mac80211: fix the...
1355
1356
  	ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
  	if (!--ifmsh->chsw_ttl)
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1357
1358
1359
1360
1361
1362
1363
  		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...
1364
1365
  	if (!sdata->vif.csa_active &&
  	    !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
33a45867c   Chun-Yeow Yeoh   mac80211: process...
1366
1367
1368
  		mcsa_dbg(sdata, "Failed to process CSA action frame");
  		return;
  	}
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1369
1370
  	/* forward or re-broadcast the CSA frame */
  	if (fwd_csa) {
c4de37ee2   Peter Oh   mac80211: mesh: f...
1371
  		if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1372
1373
  			mcsa_dbg(sdata, "Failed to forward the CSA frame");
  	}
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1374
  }
472dbc45d   Johannes Berg   mac80211: split o...
1375
1376
1377
1378
1379
1380
  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 ...
1381
1382
1383
1384
1385
1386
1387
1388
  	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...
1389
  		break;
25d49e4d6   Thomas Pedersen   mac80211: update ...
1390
1391
1392
  	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...
1393
  		break;
8f2535b92   Chun-Yeow Yeoh   mac80211: process...
1394
1395
1396
  	case WLAN_CATEGORY_SPECTRUM_MGMT:
  		mesh_rx_csa_frame(sdata, mgmt, len);
  		break;
472dbc45d   Johannes Berg   mac80211: split o...
1397
1398
  	}
  }
1fa57d017   Johannes Berg   mac80211: use com...
1399
1400
  void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
  				   struct sk_buff *skb)
472dbc45d   Johannes Berg   mac80211: split o...
1401
1402
  {
  	struct ieee80211_rx_status *rx_status;
472dbc45d   Johannes Berg   mac80211: split o...
1403
1404
  	struct ieee80211_mgmt *mgmt;
  	u16 stype;
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1405
1406
1407
  	sdata_lock(sdata);
  
  	/* mesh already went down */
1693d3441   Johannes Berg   mac80211: use sda...
1408
  	if (!sdata->u.mesh.mesh_id_len)
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1409
  		goto out;
f1d58c252   Johannes Berg   mac80211: push rx...
1410
  	rx_status = IEEE80211_SKB_RXCB(skb);
472dbc45d   Johannes Berg   mac80211: split o...
1411
1412
1413
1414
1415
1416
1417
1418
1419
  	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...
1420
1421
1422
  	case IEEE80211_STYPE_PROBE_REQ:
  		ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len);
  		break;
472dbc45d   Johannes Berg   mac80211: split o...
1423
1424
1425
1426
  	case IEEE80211_STYPE_ACTION:
  		ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
  		break;
  	}
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1427
1428
  out:
  	sdata_unlock(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1429
  }
f81a9deda   Thomas Pedersen   mac80211: update ...
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
  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...
1451
  void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
472dbc45d   Johannes Berg   mac80211: split o...
1452
  {
472dbc45d   Johannes Berg   mac80211: split o...
1453
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
472dbc45d   Johannes Berg   mac80211: split o...
1454

ecccd072b   Thomas Pedersen   mac80211: fix mes...
1455
1456
1457
  	sdata_lock(sdata);
  
  	/* mesh already went down */
1693d3441   Johannes Berg   mac80211: use sda...
1458
  	if (!sdata->u.mesh.mesh_id_len)
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1459
  		goto out;
472dbc45d   Johannes Berg   mac80211: split o...
1460
1461
1462
1463
  	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...
1464
  	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
bf7cd94dc   Johannes Berg   mac80211: clean u...
1465
  		ieee80211_mesh_housekeeping(sdata);
e304bfd30   Rui Paulo   mac80211: impleme...
1466
1467
1468
  
  	if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
  		ieee80211_mesh_rootpath(sdata);
dbf498fba   Javier Cardona   mac80211: Impleme...
1469
1470
  
  	if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
445cd452f   Masashi Honma   mac80211: Use app...
1471
  		mesh_sync_adjust_tsf(sdata);
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1472

f81a9deda   Thomas Pedersen   mac80211: update ...
1473
1474
  	if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags))
  		mesh_bss_info_changed(sdata);
ecccd072b   Thomas Pedersen   mac80211: fix mes...
1475
1476
  out:
  	sdata_unlock(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1477
  }
472dbc45d   Johannes Berg   mac80211: split o...
1478

902acc789   Johannes Berg   mac80211: clean u...
1479
1480
  void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
  {
472dbc45d   Johannes Berg   mac80211: split o...
1481
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
ad2d223aa   Johannes Berg   mac80211: assign ...
1482
  	static u8 zero_addr[ETH_ALEN] = {};
472dbc45d   Johannes Berg   mac80211: split o...
1483

34f11cd32   Kees Cook   mac80211: Convert...
1484
1485
  	timer_setup(&ifmsh->housekeeping_timer,
  		    ieee80211_mesh_housekeeping_timer, 0);
472dbc45d   Johannes Berg   mac80211: split o...
1486

472dbc45d   Johannes Berg   mac80211: split o...
1487
  	ifmsh->accepting_plinks = true;
472dbc45d   Johannes Berg   mac80211: split o...
1488
  	atomic_set(&ifmsh->mpaths, 0);
f698d856f   Jasper Bryant-Greene   replace net_devic...
1489
  	mesh_rmc_init(sdata);
472dbc45d   Johannes Berg   mac80211: split o...
1490
  	ifmsh->last_preq = jiffies;
dca7e9430   Thomas Pedersen   {nl,cfg,mac}80211...
1491
  	ifmsh->next_perr = jiffies;
0cb4d4dce   Luciano Coelho   mac80211: refacto...
1492
  	ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
902acc789   Johannes Berg   mac80211: clean u...
1493
1494
1495
  	/* Allocate all mesh structures when creating the first mesh interface. */
  	if (!mesh_allocated)
  		ieee80211s_init();
2bdaf386f   Bob Copeland   mac80211: mesh: m...
1496
1497
  
  	mesh_pathtbl_init(sdata);
34f11cd32   Kees Cook   mac80211: Convert...
1498
1499
1500
  	timer_setup(&ifmsh->mesh_path_timer, ieee80211_mesh_path_timer, 0);
  	timer_setup(&ifmsh->mesh_path_root_timer,
  		    ieee80211_mesh_path_root_timer, 0);
472dbc45d   Johannes Berg   mac80211: split o...
1501
  	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
3f52b7e32   Marco Porsch   mac80211: mesh po...
1502
  	skb_queue_head_init(&ifmsh->ps.bc_buf);
472dbc45d   Johannes Berg   mac80211: split o...
1503
  	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
dbf498fba   Javier Cardona   mac80211: Impleme...
1504
  	spin_lock_init(&ifmsh->sync_offset_lock);
2b5e19677   Thomas Pedersen   mac80211: cache m...
1505
  	RCU_INIT_POINTER(ifmsh->beacon, NULL);
ad2d223aa   Johannes Berg   mac80211: assign ...
1506
1507
  
  	sdata->vif.bss_conf.bssid = zero_addr;
472dbc45d   Johannes Berg   mac80211: split o...
1508
  }
0371a08fb   Bob Copeland   mac80211: mesh: f...
1509
1510
1511
1512
1513
1514
  
  void ieee80211_mesh_teardown_sdata(struct ieee80211_sub_if_data *sdata)
  {
  	mesh_rmc_free(sdata);
  	mesh_pathtbl_unregister(sdata);
  }