Blame view

net/mac80211/mesh_plink.c 22.3 KB
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
1
  /*
264d9b7d8   Rui Paulo   mac80211: update ...
2
   * Copyright (c) 2008, 2009 open80211s Ltd.
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
3
4
5
6
7
8
   * Author:     Luis Carlos Cobo <luisca@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: ...
9
  #include <linux/gfp.h>
902acc789   Johannes Berg   mac80211: clean u...
10
11
  #include <linux/kernel.h>
  #include <linux/random.h>
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
12
  #include "ieee80211_i.h"
2c8dccc77   Johannes Berg   mac80211: rename ...
13
  #include "rate.h"
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
14
  #include "mesh.h"
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
15
16
17
18
19
20
  
  #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
  #define mpl_dbg(fmt, args...)	printk(KERN_DEBUG fmt, ##args)
  #else
  #define mpl_dbg(fmt, args...)	do { (void)(0); } while (0)
  #endif
8db098507   Thomas Pedersen   mac80211: update ...
21
22
  #define PLINK_GET_LLID(p) (p + 2)
  #define PLINK_GET_PLID(p) (p + 4)
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
23
24
25
  
  #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
  				jiffies + HZ * t / 1000))
472dbc45d   Johannes Berg   mac80211: split o...
26
27
28
29
30
  #define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
  #define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
  #define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
  #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
  #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
31

c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
32
33
34
35
36
37
38
39
40
41
42
  enum plink_event {
  	PLINK_UNDEFINED,
  	OPN_ACPT,
  	OPN_RJCT,
  	OPN_IGNR,
  	CNF_ACPT,
  	CNF_RJCT,
  	CNF_IGNR,
  	CLS_ACPT,
  	CLS_IGNR
  };
ba4a14e10   Thomas Pedersen   mac80211: notify ...
43
44
45
  static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
  		enum ieee80211_self_protected_actioncode action,
  		u8 *da, __le16 llid, __le16 plid, __le16 reason);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
46
47
48
  static inline
  void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
  {
472dbc45d   Johannes Berg   mac80211: split o...
49
  	atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
d0709a651   Johannes Berg   mac80211: RCU-ify...
50
  	mesh_accept_plinks_update(sdata);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
51
52
53
54
55
  }
  
  static inline
  void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
  {
472dbc45d   Johannes Berg   mac80211: split o...
56
  	atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
d0709a651   Johannes Berg   mac80211: RCU-ify...
57
  	mesh_accept_plinks_update(sdata);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
58
59
60
61
62
  }
  
  /**
   * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
   *
23c7a29cd   Rui Paulo   mac80211: fix typ...
63
   * @sta: mesh peer link to restart
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
64
   *
07346f81e   Johannes Berg   mac80211: proper ...
65
   * Locking: this function must be called holding sta->lock
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
66
67
68
   */
  static inline void mesh_plink_fsm_restart(struct sta_info *sta)
  {
57cf8043a   Javier Cardona   nl80211: Move pee...
69
  	sta->plink_state = NL80211_PLINK_LISTEN;
37659ff8e   Luis Carlos Cobo   mac80211: fix mes...
70
71
  	sta->llid = sta->plid = sta->reason = 0;
  	sta->plink_retries = 0;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
72
  }
93e5deb1a   Johannes Berg   mac80211: automat...
73
74
75
76
  /*
   * NOTE: This is just an alias for sta_info_alloc(), see notes
   *       on it in the lifecycle management section!
   */
03e4497eb   Johannes Berg   mac80211: fix sta...
77
  static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
739522baa   Thomas Pedersen   mac80211: set HT ...
78
79
  					 u8 *hw_addr, u32 rates,
  					 struct ieee802_11_elems *elems)
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
80
  {
d0709a651   Johannes Berg   mac80211: RCU-ify...
81
  	struct ieee80211_local *local = sdata->local;
739522baa   Thomas Pedersen   mac80211: set HT ...
82
  	struct ieee80211_supported_band *sband;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
83
  	struct sta_info *sta;
739522baa   Thomas Pedersen   mac80211: set HT ...
84
  	sband = local->hw.wiphy->bands[local->oper_channel->band];
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
85
  	if (local->num_sta >= MESH_MAX_PLINKS)
73651ee63   Johannes Berg   mac80211: split s...
86
  		return NULL;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
87

34e895075   Johannes Berg   mac80211: allow s...
88
  	sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
73651ee63   Johannes Berg   mac80211: split s...
89
90
  	if (!sta)
  		return NULL;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
91

d9a7ddb05   Johannes Berg   mac80211: refacto...
92
93
94
  	sta_info_move_state(sta, IEEE80211_STA_AUTH);
  	sta_info_move_state(sta, IEEE80211_STA_ASSOC);
  	sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
c2c98fdeb   Johannes Berg   mac80211: optimis...
95
  	set_sta_flag(sta, WLAN_STA_WME);
d9a7ddb05   Johannes Berg   mac80211: refacto...
96

323ce79a9   Johannes Berg   mac80211: share s...
97
  	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
739522baa   Thomas Pedersen   mac80211: set HT ...
98
  	if (elems->ht_cap_elem)
ef96a8420   Ben Greear   mac80211: Support...
99
100
  		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
  						  elems->ht_cap_elem,
739522baa   Thomas Pedersen   mac80211: set HT ...
101
  						  &sta->sta.ht_cap);
b973c31a9   Christian Lamparter   mac80211: initial...
102
  	rate_control_rate_init(sta);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
103
104
105
106
107
  
  	return sta;
  }
  
  /**
c93701976   John W. Linville   mac80211: avoid s...
108
   * __mesh_plink_deactivate - deactivate mesh peer link
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
109
110
111
112
113
   *
   * @sta: mesh peer link to deactivate
   *
   * All mesh paths with this peer as next hop will be flushed
   *
07346f81e   Johannes Berg   mac80211: proper ...
114
   * Locking: the caller must hold sta->lock
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
115
   */
c93701976   John W. Linville   mac80211: avoid s...
116
  static bool __mesh_plink_deactivate(struct sta_info *sta)
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
117
  {
d0709a651   Johannes Berg   mac80211: RCU-ify...
118
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
c93701976   John W. Linville   mac80211: avoid s...
119
  	bool deactivated = false;
d0709a651   Johannes Berg   mac80211: RCU-ify...
120

57cf8043a   Javier Cardona   nl80211: Move pee...
121
  	if (sta->plink_state == NL80211_PLINK_ESTAB) {
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
122
  		mesh_plink_dec_estab_count(sdata);
c93701976   John W. Linville   mac80211: avoid s...
123
124
  		deactivated = true;
  	}
57cf8043a   Javier Cardona   nl80211: Move pee...
125
  	sta->plink_state = NL80211_PLINK_BLOCKED;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
126
  	mesh_path_flush_by_nexthop(sta);
c93701976   John W. Linville   mac80211: avoid s...
127
128
  
  	return deactivated;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
129
  }
902acc789   Johannes Berg   mac80211: clean u...
130
  /**
c93701976   John W. Linville   mac80211: avoid s...
131
   * mesh_plink_deactivate - deactivate mesh peer link
902acc789   Johannes Berg   mac80211: clean u...
132
133
134
135
136
137
138
   *
   * @sta: mesh peer link to deactivate
   *
   * All mesh paths with this peer as next hop will be flushed
   */
  void mesh_plink_deactivate(struct sta_info *sta)
  {
c93701976   John W. Linville   mac80211: avoid s...
139
140
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
  	bool deactivated;
07346f81e   Johannes Berg   mac80211: proper ...
141
  	spin_lock_bh(&sta->lock);
c93701976   John W. Linville   mac80211: avoid s...
142
  	deactivated = __mesh_plink_deactivate(sta);
ba4a14e10   Thomas Pedersen   mac80211: notify ...
143
144
145
146
  	sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
  	mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
  			    sta->sta.addr, sta->llid, sta->plid,
  			    sta->reason);
07346f81e   Johannes Berg   mac80211: proper ...
147
  	spin_unlock_bh(&sta->lock);
c93701976   John W. Linville   mac80211: avoid s...
148
149
150
  
  	if (deactivated)
  		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
902acc789   Johannes Berg   mac80211: clean u...
151
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
152
  static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
54ef656b0   Thomas Pedersen   mac80211: update ...
153
154
  		enum ieee80211_self_protected_actioncode action,
  		u8 *da, __le16 llid, __le16 plid, __le16 reason) {
f698d856f   Jasper Bryant-Greene   replace net_devic...
155
  	struct ieee80211_local *local = sdata->local;
3b69a9c5f   Thomas Pedersen   mac80211: comment...
156
  	struct sk_buff *skb;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
157
158
  	struct ieee80211_mgmt *mgmt;
  	bool include_plid = false;
8db098507   Thomas Pedersen   mac80211: update ...
159
  	u16 peering_proto = 0;
3b69a9c5f   Thomas Pedersen   mac80211: comment...
160
161
162
163
164
165
166
167
168
169
170
171
  	u8 *pos, ie_len = 4;
  	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
  		      sizeof(mgmt->u.action.u.self_prot);
  
  	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
  			    hdr_len +
  			    2 + /* capability info */
  			    2 + /* AID */
  			    2 + 8 + /* supported rates */
  			    2 + (IEEE80211_MAX_SUPP_RATES - 8) +
  			    2 + sdata->u.mesh.mesh_id_len +
  			    2 + sizeof(struct ieee80211_meshconf_ie) +
176f36086   Thomas Pedersen   mac80211: add HT ...
172
173
  			    2 + sizeof(struct ieee80211_ht_cap) +
  			    2 + sizeof(struct ieee80211_ht_info) +
3b69a9c5f   Thomas Pedersen   mac80211: comment...
174
175
  			    2 + 8 + /* peering IE */
  			    sdata->u.mesh.ie_len);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
176
177
178
  	if (!skb)
  		return -1;
  	skb_reserve(skb, local->hw.extra_tx_headroom);
3b69a9c5f   Thomas Pedersen   mac80211: comment...
179
180
  	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
  	memset(mgmt, 0, hdr_len);
e7827a703   Harvey Harrison   mac80211: remove ...
181
182
  	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  					  IEEE80211_STYPE_ACTION);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
183
  	memcpy(mgmt->da, da, ETH_ALEN);
47846c9b0   Johannes Berg   mac80211: reduce ...
184
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
915b5c50f   Javier Cardona   open80211s: Stop ...
185
  	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
8db098507   Thomas Pedersen   mac80211: update ...
186
187
  	mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
  	mgmt->u.action.u.self_prot.action_code = action;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
188

8db098507   Thomas Pedersen   mac80211: update ...
189
190
191
192
  	if (action != WLAN_SP_MESH_PEERING_CLOSE) {
  		/* capability info */
  		pos = skb_put(skb, 2);
  		memset(pos, 0, 2);
54ef656b0   Thomas Pedersen   mac80211: update ...
193
  		if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
8db098507   Thomas Pedersen   mac80211: update ...
194
195
  			/* AID */
  			pos = skb_put(skb, 2);
77fa76bb7   Rui Paulo   mac80211: set the...
196
  			memcpy(pos + 2, &plid, 2);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
197
  		}
768db3438   Arik Nemtsov   mac80211: standar...
198
199
  		if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
  		    ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
082ebb0c2   Thomas Pedersen   mac80211: fix mes...
200
201
202
203
  		    mesh_add_rsn_ie(skb, sdata) ||
  		    mesh_add_meshid_ie(skb, sdata) ||
  		    mesh_add_meshconf_ie(skb, sdata))
  			return -1;
8db098507   Thomas Pedersen   mac80211: update ...
204
205
206
  	} else {	/* WLAN_SP_MESH_PEERING_CLOSE */
  		if (mesh_add_meshid_ie(skb, sdata))
  			return -1;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
207
  	}
8db098507   Thomas Pedersen   mac80211: update ...
208
  	/* Add Mesh Peering Management element */
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
209
  	switch (action) {
54ef656b0   Thomas Pedersen   mac80211: update ...
210
  	case WLAN_SP_MESH_PEERING_OPEN:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
211
  		break;
54ef656b0   Thomas Pedersen   mac80211: update ...
212
  	case WLAN_SP_MESH_PEERING_CONFIRM:
8db098507   Thomas Pedersen   mac80211: update ...
213
  		ie_len += 2;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
214
215
  		include_plid = true;
  		break;
54ef656b0   Thomas Pedersen   mac80211: update ...
216
  	case WLAN_SP_MESH_PEERING_CLOSE:
8db098507   Thomas Pedersen   mac80211: update ...
217
218
  		if (plid) {
  			ie_len += 2;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
219
220
  			include_plid = true;
  		}
8db098507   Thomas Pedersen   mac80211: update ...
221
  		ie_len += 2;	/* reason code */
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
222
  		break;
8db098507   Thomas Pedersen   mac80211: update ...
223
224
  	default:
  		return -EINVAL;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
225
  	}
8db098507   Thomas Pedersen   mac80211: update ...
226
227
  	if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
  		return -ENOMEM;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
228
  	pos = skb_put(skb, 2 + ie_len);
8db098507   Thomas Pedersen   mac80211: update ...
229
  	*pos++ = WLAN_EID_PEER_MGMT;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
230
  	*pos++ = ie_len;
8db098507   Thomas Pedersen   mac80211: update ...
231
232
  	memcpy(pos, &peering_proto, 2);
  	pos += 2;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
233
  	memcpy(pos, &llid, 2);
8db098507   Thomas Pedersen   mac80211: update ...
234
  	pos += 2;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
235
  	if (include_plid) {
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
236
  		memcpy(pos, &plid, 2);
8db098507   Thomas Pedersen   mac80211: update ...
237
  		pos += 2;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
238
  	}
54ef656b0   Thomas Pedersen   mac80211: update ...
239
  	if (action == WLAN_SP_MESH_PEERING_CLOSE) {
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
240
  		memcpy(pos, &reason, 2);
8db098507   Thomas Pedersen   mac80211: update ...
241
  		pos += 2;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
242
  	}
176f36086   Thomas Pedersen   mac80211: add HT ...
243
244
245
246
247
248
  
  	if (action != WLAN_SP_MESH_PEERING_CLOSE) {
  		if (mesh_add_ht_cap_ie(skb, sdata) ||
  		    mesh_add_ht_info_ie(skb, sdata))
  			return -1;
  	}
8db098507   Thomas Pedersen   mac80211: update ...
249
250
  	if (mesh_add_vendor_ies(skb, sdata))
  		return -1;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
251

62ae67be3   Johannes Berg   mac80211: remove ...
252
  	ieee80211_tx_skb(sdata, skb);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
253
254
  	return 0;
  }
1570ca592   Javier Cardona   mac80211: send no...
255
256
257
  void mesh_neighbour_update(u8 *hw_addr, u32 rates,
  		struct ieee80211_sub_if_data *sdata,
  		struct ieee802_11_elems *elems)
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
258
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
259
  	struct ieee80211_local *local = sdata->local;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
260
  	struct sta_info *sta;
d0709a651   Johannes Berg   mac80211: RCU-ify...
261
  	rcu_read_lock();
abe60632f   Johannes Berg   mac80211: make st...
262
  	sta = sta_info_get(sdata, hw_addr);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
263
  	if (!sta) {
34e895075   Johannes Berg   mac80211: allow s...
264
  		rcu_read_unlock();
1570ca592   Javier Cardona   mac80211: send no...
265
266
  		/* Userspace handles peer allocation when security is enabled
  		 * */
b130e5cec   Javier Cardona   nl80211: Introduc...
267
  		if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
1570ca592   Javier Cardona   mac80211: send no...
268
269
270
271
  			cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
  					elems->ie_start, elems->total_len,
  					GFP_KERNEL);
  		else
739522baa   Thomas Pedersen   mac80211: set HT ...
272
  			sta = mesh_plink_alloc(sdata, hw_addr, rates, elems);
34e895075   Johannes Berg   mac80211: allow s...
273
  		if (!sta)
73651ee63   Johannes Berg   mac80211: split s...
274
  			return;
34e895075   Johannes Berg   mac80211: allow s...
275
  		if (sta_info_insert_rcu(sta)) {
d0709a651   Johannes Berg   mac80211: RCU-ify...
276
  			rcu_read_unlock();
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
277
  			return;
d0709a651   Johannes Berg   mac80211: RCU-ify...
278
  		}
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
279
280
281
  	}
  
  	sta->last_rx = jiffies;
323ce79a9   Johannes Berg   mac80211: share s...
282
  	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
1570ca592   Javier Cardona   mac80211: send no...
283
  	if (mesh_peer_accepts_plinks(elems) &&
57cf8043a   Javier Cardona   nl80211: Move pee...
284
  			sta->plink_state == NL80211_PLINK_LISTEN &&
472dbc45d   Johannes Berg   mac80211: split o...
285
286
  			sdata->u.mesh.accepting_plinks &&
  			sdata->u.mesh.mshcfg.auto_open_plinks)
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
287
  		mesh_plink_open(sta);
d0709a651   Johannes Berg   mac80211: RCU-ify...
288
  	rcu_read_unlock();
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
289
290
291
292
293
294
  }
  
  static void mesh_plink_timer(unsigned long data)
  {
  	struct sta_info *sta;
  	__le16 llid, plid, reason;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
295
  	struct ieee80211_sub_if_data *sdata;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
296

d0709a651   Johannes Berg   mac80211: RCU-ify...
297
298
299
300
301
  	/*
  	 * This STA is valid because sta_info_destroy() will
  	 * del_timer_sync() this timer after having made sure
  	 * it cannot be readded (by deleting the plink.)
  	 */
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
302
  	sta = (struct sta_info *) data;
5bb644a0f   Johannes Berg   mac80211: cancel/...
303
304
305
306
  	if (sta->sdata->local->quiescing) {
  		sta->plink_timer_was_running = true;
  		return;
  	}
07346f81e   Johannes Berg   mac80211: proper ...
307
  	spin_lock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
308
309
  	if (sta->ignore_plink_timer) {
  		sta->ignore_plink_timer = false;
07346f81e   Johannes Berg   mac80211: proper ...
310
  		spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
311
312
  		return;
  	}
0c68ae260   Johannes Berg   mac80211: convert...
313
314
315
  	mpl_dbg("Mesh plink timer for %pM fired on state %d
  ",
  		sta->sta.addr, sta->plink_state);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
316
317
318
  	reason = 0;
  	llid = sta->llid;
  	plid = sta->plid;
d0709a651   Johannes Berg   mac80211: RCU-ify...
319
  	sdata = sta->sdata;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
320
321
  
  	switch (sta->plink_state) {
57cf8043a   Javier Cardona   nl80211: Move pee...
322
323
  	case NL80211_PLINK_OPN_RCVD:
  	case NL80211_PLINK_OPN_SNT:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
324
325
326
  		/* retry timer */
  		if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
  			u32 rand;
0c68ae260   Johannes Berg   mac80211: convert...
327
328
329
330
  			mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d
  ",
  				sta->sta.addr, sta->plink_retries,
  				sta->plink_timeout);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
331
332
333
334
  			get_random_bytes(&rand, sizeof(u32));
  			sta->plink_timeout = sta->plink_timeout +
  					     rand % sta->plink_timeout;
  			++sta->plink_retries;
d0709a651   Johannes Berg   mac80211: RCU-ify...
335
  			mod_plink_timer(sta, sta->plink_timeout);
07346f81e   Johannes Berg   mac80211: proper ...
336
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
337
338
  			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
  					    sta->sta.addr, llid, 0, 0);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
339
340
  			break;
  		}
54ef656b0   Thomas Pedersen   mac80211: update ...
341
  		reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
342
  		/* fall through on else */
57cf8043a   Javier Cardona   nl80211: Move pee...
343
  	case NL80211_PLINK_CNF_RCVD:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
344
345
  		/* confirm timer */
  		if (!reason)
54ef656b0   Thomas Pedersen   mac80211: update ...
346
  			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
57cf8043a   Javier Cardona   nl80211: Move pee...
347
  		sta->plink_state = NL80211_PLINK_HOLDING;
d0709a651   Johannes Berg   mac80211: RCU-ify...
348
  		mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
07346f81e   Johannes Berg   mac80211: proper ...
349
  		spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
350
351
  		mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
  				    sta->sta.addr, llid, plid, reason);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
352
  		break;
57cf8043a   Javier Cardona   nl80211: Move pee...
353
  	case NL80211_PLINK_HOLDING:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
354
  		/* holding timer */
d0709a651   Johannes Berg   mac80211: RCU-ify...
355
  		del_timer(&sta->plink_timer);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
356
  		mesh_plink_fsm_restart(sta);
07346f81e   Johannes Berg   mac80211: proper ...
357
  		spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
358
359
  		break;
  	default:
07346f81e   Johannes Berg   mac80211: proper ...
360
  		spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
361
362
  		break;
  	}
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
363
  }
5bb644a0f   Johannes Berg   mac80211: cancel/...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  #ifdef CONFIG_PM
  void mesh_plink_quiesce(struct sta_info *sta)
  {
  	if (del_timer_sync(&sta->plink_timer))
  		sta->plink_timer_was_running = true;
  }
  
  void mesh_plink_restart(struct sta_info *sta)
  {
  	if (sta->plink_timer_was_running) {
  		add_timer(&sta->plink_timer);
  		sta->plink_timer_was_running = false;
  	}
  }
  #endif
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
379
380
381
382
383
384
  static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
  {
  	sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
  	sta->plink_timer.data = (unsigned long) sta;
  	sta->plink_timer.function = mesh_plink_timer;
  	sta->plink_timeout = timeout;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
385
386
387
388
389
390
  	add_timer(&sta->plink_timer);
  }
  
  int mesh_plink_open(struct sta_info *sta)
  {
  	__le16 llid;
d0709a651   Johannes Berg   mac80211: RCU-ify...
391
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
392

c2c98fdeb   Johannes Berg   mac80211: optimis...
393
  	if (!test_sta_flag(sta, WLAN_STA_AUTH))
53e805111   Javier Cardona   mac80211: ignore ...
394
  		return -EPERM;
07346f81e   Johannes Berg   mac80211: proper ...
395
  	spin_lock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
396
397
  	get_random_bytes(&llid, 2);
  	sta->llid = llid;
57cf8043a   Javier Cardona   nl80211: Move pee...
398
  	if (sta->plink_state != NL80211_PLINK_LISTEN) {
07346f81e   Johannes Berg   mac80211: proper ...
399
  		spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
400
401
  		return -EBUSY;
  	}
57cf8043a   Javier Cardona   nl80211: Move pee...
402
  	sta->plink_state = NL80211_PLINK_OPN_SNT;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
403
  	mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
07346f81e   Johannes Berg   mac80211: proper ...
404
  	spin_unlock_bh(&sta->lock);
0c68ae260   Johannes Berg   mac80211: convert...
405
406
407
  	mpl_dbg("Mesh plink: starting establishment with %pM
  ",
  		sta->sta.addr);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
408

54ef656b0   Thomas Pedersen   mac80211: update ...
409
  	return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
17741cdc2   Johannes Berg   mac80211: share S...
410
  				   sta->sta.addr, llid, 0, 0);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
411
412
413
414
  }
  
  void mesh_plink_block(struct sta_info *sta)
  {
c93701976   John W. Linville   mac80211: avoid s...
415
416
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
  	bool deactivated;
07346f81e   Johannes Berg   mac80211: proper ...
417
  	spin_lock_bh(&sta->lock);
c93701976   John W. Linville   mac80211: avoid s...
418
  	deactivated = __mesh_plink_deactivate(sta);
57cf8043a   Javier Cardona   nl80211: Move pee...
419
  	sta->plink_state = NL80211_PLINK_BLOCKED;
07346f81e   Johannes Berg   mac80211: proper ...
420
  	spin_unlock_bh(&sta->lock);
c93701976   John W. Linville   mac80211: avoid s...
421
422
423
  
  	if (deactivated)
  		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
424
  }
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
425

f698d856f   Jasper Bryant-Greene   replace net_devic...
426
  void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
427
428
  			 size_t len, struct ieee80211_rx_status *rx_status)
  {
d0709a651   Johannes Berg   mac80211: RCU-ify...
429
  	struct ieee80211_local *local = sdata->local;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
430
431
432
  	struct ieee802_11_elems elems;
  	struct sta_info *sta;
  	enum plink_event event;
54ef656b0   Thomas Pedersen   mac80211: update ...
433
  	enum ieee80211_self_protected_actioncode ftype;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
434
  	size_t baselen;
d12c74528   Christian Lamparter   mac80211: fix pos...
435
  	bool deactivated, matches_local = true;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
436
437
438
  	u8 ie_len;
  	u8 *baseaddr;
  	__le16 plid, llid, reason;
1460dd158   Rui Paulo   mac80211: improve...
439
440
  #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
  	static const char *mplstates[] = {
57cf8043a   Javier Cardona   nl80211: Move pee...
441
442
443
444
445
446
447
  		[NL80211_PLINK_LISTEN] = "LISTEN",
  		[NL80211_PLINK_OPN_SNT] = "OPN-SNT",
  		[NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
  		[NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
  		[NL80211_PLINK_ESTAB] = "ESTAB",
  		[NL80211_PLINK_HOLDING] = "HOLDING",
  		[NL80211_PLINK_BLOCKED] = "BLOCKED"
1460dd158   Rui Paulo   mac80211: improve...
448
449
  	};
  #endif
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
450

9c80d3dc2   Johannes Berg   mac80211: fix act...
451
452
453
  	/* need action_code, aux */
  	if (len < IEEE80211_MIN_ACTION_SIZE + 3)
  		return;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
454
455
456
457
  	if (is_multicast_ether_addr(mgmt->da)) {
  		mpl_dbg("Mesh plink: ignore frame from multicast address");
  		return;
  	}
8db098507   Thomas Pedersen   mac80211: update ...
458
459
460
  	baseaddr = mgmt->u.action.u.self_prot.variable;
  	baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
  	if (mgmt->u.action.u.self_prot.action_code ==
54ef656b0   Thomas Pedersen   mac80211: update ...
461
  						WLAN_SP_MESH_PEERING_CONFIRM) {
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
462
  		baseaddr += 4;
70bdb6b27   David Woo   mac80211: Fix inv...
463
  		baselen += 4;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
464
465
  	}
  	ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
8db098507   Thomas Pedersen   mac80211: update ...
466
  	if (!elems.peering) {
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
467
468
469
470
  		mpl_dbg("Mesh plink: missing necessary peer link ie
  ");
  		return;
  	}
b130e5cec   Javier Cardona   nl80211: Introduc...
471
472
  	if (elems.rsn_len &&
  			sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
5cff5e01e   Javier Cardona   mac80211: ignore ...
473
474
475
476
  		mpl_dbg("Mesh plink: can't establish link with secure peer
  ");
  		return;
  	}
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
477

8db098507   Thomas Pedersen   mac80211: update ...
478
479
480
481
482
483
  	ftype = mgmt->u.action.u.self_prot.action_code;
  	ie_len = elems.peering_len;
  	if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
  	    (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
  	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
  							&& ie_len != 8)) {
0938393f0   Rui Paulo   mac80211: update ...
484
485
486
  		mpl_dbg("Mesh plink: incorrect plink ie length %d %d
  ",
  		    ftype, ie_len);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
487
488
  		return;
  	}
54ef656b0   Thomas Pedersen   mac80211: update ...
489
490
  	if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
  				(!elems.mesh_id || !elems.mesh_config)) {
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
491
492
493
494
495
496
497
  		mpl_dbg("Mesh plink: missing necessary ie
  ");
  		return;
  	}
  	/* Note the lines below are correct, the llid in the frame is the plid
  	 * from the point of view of this host.
  	 */
8db098507   Thomas Pedersen   mac80211: update ...
498
  	memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
54ef656b0   Thomas Pedersen   mac80211: update ...
499
  	if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
8db098507   Thomas Pedersen   mac80211: update ...
500
501
  	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
  		memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
502

d0709a651   Johannes Berg   mac80211: RCU-ify...
503
  	rcu_read_lock();
abe60632f   Johannes Berg   mac80211: make st...
504
  	sta = sta_info_get(sdata, mgmt->sa);
54ef656b0   Thomas Pedersen   mac80211: update ...
505
  	if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
506
507
  		mpl_dbg("Mesh plink: cls or cnf from unknown peer
  ");
d0709a651   Johannes Berg   mac80211: RCU-ify...
508
  		rcu_read_unlock();
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
509
510
  		return;
  	}
c2c98fdeb   Johannes Berg   mac80211: optimis...
511
  	if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
53e805111   Javier Cardona   mac80211: ignore ...
512
513
514
515
516
  		mpl_dbg("Mesh plink: Action frame from non-authed peer
  ");
  		rcu_read_unlock();
  		return;
  	}
57cf8043a   Javier Cardona   nl80211: Move pee...
517
  	if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
d0709a651   Johannes Berg   mac80211: RCU-ify...
518
  		rcu_read_unlock();
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
519
520
521
522
523
  		return;
  	}
  
  	/* Now we will figure out the appropriate event... */
  	event = PLINK_UNDEFINED;
54ef656b0   Thomas Pedersen   mac80211: update ...
524
525
  	if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
  	    (!mesh_matches_local(&elems, sdata))) {
d12c74528   Christian Lamparter   mac80211: fix pos...
526
  		matches_local = false;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
527
  		switch (ftype) {
54ef656b0   Thomas Pedersen   mac80211: update ...
528
  		case WLAN_SP_MESH_PEERING_OPEN:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
529
530
  			event = OPN_RJCT;
  			break;
54ef656b0   Thomas Pedersen   mac80211: update ...
531
  		case WLAN_SP_MESH_PEERING_CONFIRM:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
532
533
  			event = CNF_RJCT;
  			break;
54ef656b0   Thomas Pedersen   mac80211: update ...
534
  		default:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
535
536
  			break;
  		}
d12c74528   Christian Lamparter   mac80211: fix pos...
537
538
539
540
  	}
  
  	if (!sta && !matches_local) {
  		rcu_read_unlock();
54ef656b0   Thomas Pedersen   mac80211: update ...
541
  		reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
d12c74528   Christian Lamparter   mac80211: fix pos...
542
  		llid = 0;
54ef656b0   Thomas Pedersen   mac80211: update ...
543
544
  		mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
  				    mgmt->sa, llid, plid, reason);
d12c74528   Christian Lamparter   mac80211: fix pos...
545
  		return;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
546
  	} else if (!sta) {
54ef656b0   Thomas Pedersen   mac80211: update ...
547
  		/* ftype == WLAN_SP_MESH_PEERING_OPEN */
881d948c2   Johannes Berg   wireless: restric...
548
  		u32 rates;
34e895075   Johannes Berg   mac80211: allow s...
549
550
  
  		rcu_read_unlock();
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
551
552
553
554
555
556
557
  		if (!mesh_plink_free_count(sdata)) {
  			mpl_dbg("Mesh plink error: no more free plinks
  ");
  			return;
  		}
  
  		rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
739522baa   Thomas Pedersen   mac80211: set HT ...
558
  		sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems);
73651ee63   Johannes Berg   mac80211: split s...
559
  		if (!sta) {
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
560
561
562
563
  			mpl_dbg("Mesh plink error: plink table full
  ");
  			return;
  		}
34e895075   Johannes Berg   mac80211: allow s...
564
  		if (sta_info_insert_rcu(sta)) {
73651ee63   Johannes Berg   mac80211: split s...
565
566
567
  			rcu_read_unlock();
  			return;
  		}
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
568
  		event = OPN_ACPT;
07346f81e   Johannes Berg   mac80211: proper ...
569
  		spin_lock_bh(&sta->lock);
d12c74528   Christian Lamparter   mac80211: fix pos...
570
  	} else if (matches_local) {
07346f81e   Johannes Berg   mac80211: proper ...
571
  		spin_lock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
572
  		switch (ftype) {
54ef656b0   Thomas Pedersen   mac80211: update ...
573
  		case WLAN_SP_MESH_PEERING_OPEN:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
574
  			if (!mesh_plink_free_count(sdata) ||
d0709a651   Johannes Berg   mac80211: RCU-ify...
575
  			    (sta->plid && sta->plid != plid))
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
576
577
578
579
  				event = OPN_IGNR;
  			else
  				event = OPN_ACPT;
  			break;
54ef656b0   Thomas Pedersen   mac80211: update ...
580
  		case WLAN_SP_MESH_PEERING_CONFIRM:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
581
  			if (!mesh_plink_free_count(sdata) ||
d0709a651   Johannes Berg   mac80211: RCU-ify...
582
  			    (sta->llid != llid || sta->plid != plid))
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
583
584
585
586
  				event = CNF_IGNR;
  			else
  				event = CNF_ACPT;
  			break;
54ef656b0   Thomas Pedersen   mac80211: update ...
587
  		case WLAN_SP_MESH_PEERING_CLOSE:
57cf8043a   Javier Cardona   nl80211: Move pee...
588
  			if (sta->plink_state == NL80211_PLINK_ESTAB)
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
  				/* Do not check for llid or plid. This does not
  				 * follow the standard but since multiple plinks
  				 * per sta are not supported, it is necessary in
  				 * order to avoid a livelock when MP A sees an
  				 * establish peer link to MP B but MP B does not
  				 * see it. This can be caused by a timeout in
  				 * B's peer link establishment or B beign
  				 * restarted.
  				 */
  				event = CLS_ACPT;
  			else if (sta->plid != plid)
  				event = CLS_IGNR;
  			else if (ie_len == 7 && sta->llid != llid)
  				event = CLS_IGNR;
  			else
  				event = CLS_ACPT;
  			break;
  		default:
  			mpl_dbg("Mesh plink: unknown frame subtype
  ");
07346f81e   Johannes Berg   mac80211: proper ...
609
  			spin_unlock_bh(&sta->lock);
d0709a651   Johannes Berg   mac80211: RCU-ify...
610
  			rcu_read_unlock();
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
611
612
  			return;
  		}
d12c74528   Christian Lamparter   mac80211: fix pos...
613
614
  	} else {
  		spin_lock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
615
  	}
1460dd158   Rui Paulo   mac80211: improve...
616
617
618
  	mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d
  ",
  		mgmt->sa, mplstates[sta->plink_state],
0c68ae260   Johannes Berg   mac80211: convert...
619
620
  		le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
  		event);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
621
622
623
  	reason = 0;
  	switch (sta->plink_state) {
  		/* spin_unlock as soon as state is updated at each case */
57cf8043a   Javier Cardona   nl80211: Move pee...
624
  	case NL80211_PLINK_LISTEN:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
625
626
627
  		switch (event) {
  		case CLS_ACPT:
  			mesh_plink_fsm_restart(sta);
07346f81e   Johannes Berg   mac80211: proper ...
628
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
629
630
  			break;
  		case OPN_ACPT:
57cf8043a   Javier Cardona   nl80211: Move pee...
631
  			sta->plink_state = NL80211_PLINK_OPN_RCVD;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
632
633
634
635
  			sta->plid = plid;
  			get_random_bytes(&llid, 2);
  			sta->llid = llid;
  			mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
07346f81e   Johannes Berg   mac80211: proper ...
636
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
637
638
639
640
641
642
  			mesh_plink_frame_tx(sdata,
  					    WLAN_SP_MESH_PEERING_OPEN,
  					    sta->sta.addr, llid, 0, 0);
  			mesh_plink_frame_tx(sdata,
  					    WLAN_SP_MESH_PEERING_CONFIRM,
  					    sta->sta.addr, llid, plid, 0);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
643
644
  			break;
  		default:
07346f81e   Johannes Berg   mac80211: proper ...
645
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
646
647
648
  			break;
  		}
  		break;
57cf8043a   Javier Cardona   nl80211: Move pee...
649
  	case NL80211_PLINK_OPN_SNT:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
650
651
652
  		switch (event) {
  		case OPN_RJCT:
  		case CNF_RJCT:
54ef656b0   Thomas Pedersen   mac80211: update ...
653
  			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
654
655
  		case CLS_ACPT:
  			if (!reason)
54ef656b0   Thomas Pedersen   mac80211: update ...
656
  				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
657
  			sta->reason = reason;
57cf8043a   Javier Cardona   nl80211: Move pee...
658
  			sta->plink_state = NL80211_PLINK_HOLDING;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
659
660
661
662
663
  			if (!mod_plink_timer(sta,
  					     dot11MeshHoldingTimeout(sdata)))
  				sta->ignore_plink_timer = true;
  
  			llid = sta->llid;
07346f81e   Johannes Berg   mac80211: proper ...
664
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
665
666
667
  			mesh_plink_frame_tx(sdata,
  					    WLAN_SP_MESH_PEERING_CLOSE,
  					    sta->sta.addr, llid, plid, reason);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
668
669
670
  			break;
  		case OPN_ACPT:
  			/* retry timer is left untouched */
57cf8043a   Javier Cardona   nl80211: Move pee...
671
  			sta->plink_state = NL80211_PLINK_OPN_RCVD;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
672
673
  			sta->plid = plid;
  			llid = sta->llid;
07346f81e   Johannes Berg   mac80211: proper ...
674
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
675
676
677
  			mesh_plink_frame_tx(sdata,
  					    WLAN_SP_MESH_PEERING_CONFIRM,
  					    sta->sta.addr, llid, plid, 0);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
678
679
  			break;
  		case CNF_ACPT:
57cf8043a   Javier Cardona   nl80211: Move pee...
680
  			sta->plink_state = NL80211_PLINK_CNF_RCVD;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
681
682
683
  			if (!mod_plink_timer(sta,
  					     dot11MeshConfirmTimeout(sdata)))
  				sta->ignore_plink_timer = true;
07346f81e   Johannes Berg   mac80211: proper ...
684
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
685
686
  			break;
  		default:
07346f81e   Johannes Berg   mac80211: proper ...
687
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
688
689
690
  			break;
  		}
  		break;
57cf8043a   Javier Cardona   nl80211: Move pee...
691
  	case NL80211_PLINK_OPN_RCVD:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
692
693
694
  		switch (event) {
  		case OPN_RJCT:
  		case CNF_RJCT:
54ef656b0   Thomas Pedersen   mac80211: update ...
695
  			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
696
697
  		case CLS_ACPT:
  			if (!reason)
54ef656b0   Thomas Pedersen   mac80211: update ...
698
  				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
699
  			sta->reason = reason;
57cf8043a   Javier Cardona   nl80211: Move pee...
700
  			sta->plink_state = NL80211_PLINK_HOLDING;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
701
702
703
704
705
  			if (!mod_plink_timer(sta,
  					     dot11MeshHoldingTimeout(sdata)))
  				sta->ignore_plink_timer = true;
  
  			llid = sta->llid;
07346f81e   Johannes Berg   mac80211: proper ...
706
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
707
708
  			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
  					    sta->sta.addr, llid, plid, reason);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
709
710
711
  			break;
  		case OPN_ACPT:
  			llid = sta->llid;
07346f81e   Johannes Berg   mac80211: proper ...
712
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
713
714
715
  			mesh_plink_frame_tx(sdata,
  					    WLAN_SP_MESH_PEERING_CONFIRM,
  					    sta->sta.addr, llid, plid, 0);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
716
717
  			break;
  		case CNF_ACPT:
d0709a651   Johannes Berg   mac80211: RCU-ify...
718
  			del_timer(&sta->plink_timer);
57cf8043a   Javier Cardona   nl80211: Move pee...
719
  			sta->plink_state = NL80211_PLINK_ESTAB;
07346f81e   Johannes Berg   mac80211: proper ...
720
  			spin_unlock_bh(&sta->lock);
c93701976   John W. Linville   mac80211: avoid s...
721
722
  			mesh_plink_inc_estab_count(sdata);
  			ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
0c68ae260   Johannes Berg   mac80211: convert...
723
724
725
  			mpl_dbg("Mesh plink with %pM ESTABLISHED
  ",
  				sta->sta.addr);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
726
727
  			break;
  		default:
07346f81e   Johannes Berg   mac80211: proper ...
728
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
729
730
731
  			break;
  		}
  		break;
57cf8043a   Javier Cardona   nl80211: Move pee...
732
  	case NL80211_PLINK_CNF_RCVD:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
733
734
735
  		switch (event) {
  		case OPN_RJCT:
  		case CNF_RJCT:
54ef656b0   Thomas Pedersen   mac80211: update ...
736
  			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
737
738
  		case CLS_ACPT:
  			if (!reason)
54ef656b0   Thomas Pedersen   mac80211: update ...
739
  				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
740
  			sta->reason = reason;
57cf8043a   Javier Cardona   nl80211: Move pee...
741
  			sta->plink_state = NL80211_PLINK_HOLDING;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
742
743
744
745
746
  			if (!mod_plink_timer(sta,
  					     dot11MeshHoldingTimeout(sdata)))
  				sta->ignore_plink_timer = true;
  
  			llid = sta->llid;
07346f81e   Johannes Berg   mac80211: proper ...
747
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
748
749
750
  			mesh_plink_frame_tx(sdata,
  					    WLAN_SP_MESH_PEERING_CLOSE,
  					    sta->sta.addr, llid, plid, reason);
ff59dc76e   Johannes Berg   mac80211: add mis...
751
  			break;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
752
  		case OPN_ACPT:
d0709a651   Johannes Berg   mac80211: RCU-ify...
753
  			del_timer(&sta->plink_timer);
57cf8043a   Javier Cardona   nl80211: Move pee...
754
  			sta->plink_state = NL80211_PLINK_ESTAB;
07346f81e   Johannes Berg   mac80211: proper ...
755
  			spin_unlock_bh(&sta->lock);
c93701976   John W. Linville   mac80211: avoid s...
756
757
  			mesh_plink_inc_estab_count(sdata);
  			ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
0c68ae260   Johannes Berg   mac80211: convert...
758
759
760
  			mpl_dbg("Mesh plink with %pM ESTABLISHED
  ",
  				sta->sta.addr);
54ef656b0   Thomas Pedersen   mac80211: update ...
761
762
763
  			mesh_plink_frame_tx(sdata,
  					    WLAN_SP_MESH_PEERING_CONFIRM,
  					    sta->sta.addr, llid, plid, 0);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
764
765
  			break;
  		default:
07346f81e   Johannes Berg   mac80211: proper ...
766
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
767
768
769
  			break;
  		}
  		break;
57cf8043a   Javier Cardona   nl80211: Move pee...
770
  	case NL80211_PLINK_ESTAB:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
771
772
  		switch (event) {
  		case CLS_ACPT:
54ef656b0   Thomas Pedersen   mac80211: update ...
773
  			reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
774
  			sta->reason = reason;
c93701976   John W. Linville   mac80211: avoid s...
775
  			deactivated = __mesh_plink_deactivate(sta);
57cf8043a   Javier Cardona   nl80211: Move pee...
776
  			sta->plink_state = NL80211_PLINK_HOLDING;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
777
  			llid = sta->llid;
d0709a651   Johannes Berg   mac80211: RCU-ify...
778
  			mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
07346f81e   Johannes Berg   mac80211: proper ...
779
  			spin_unlock_bh(&sta->lock);
c93701976   John W. Linville   mac80211: avoid s...
780
781
  			if (deactivated)
  				ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
54ef656b0   Thomas Pedersen   mac80211: update ...
782
783
  			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
  					    sta->sta.addr, llid, plid, reason);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
784
785
786
  			break;
  		case OPN_ACPT:
  			llid = sta->llid;
07346f81e   Johannes Berg   mac80211: proper ...
787
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
788
789
790
  			mesh_plink_frame_tx(sdata,
  					    WLAN_SP_MESH_PEERING_CONFIRM,
  					    sta->sta.addr, llid, plid, 0);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
791
792
  			break;
  		default:
07346f81e   Johannes Berg   mac80211: proper ...
793
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
794
795
796
  			break;
  		}
  		break;
57cf8043a   Javier Cardona   nl80211: Move pee...
797
  	case NL80211_PLINK_HOLDING:
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
798
799
  		switch (event) {
  		case CLS_ACPT:
d0709a651   Johannes Berg   mac80211: RCU-ify...
800
  			if (del_timer(&sta->plink_timer))
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
801
  				sta->ignore_plink_timer = 1;
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
802
  			mesh_plink_fsm_restart(sta);
07346f81e   Johannes Berg   mac80211: proper ...
803
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
804
805
806
807
808
809
810
  			break;
  		case OPN_ACPT:
  		case CNF_ACPT:
  		case OPN_RJCT:
  		case CNF_RJCT:
  			llid = sta->llid;
  			reason = sta->reason;
07346f81e   Johannes Berg   mac80211: proper ...
811
  			spin_unlock_bh(&sta->lock);
54ef656b0   Thomas Pedersen   mac80211: update ...
812
813
  			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
  					    sta->sta.addr, llid, plid, reason);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
814
815
  			break;
  		default:
07346f81e   Johannes Berg   mac80211: proper ...
816
  			spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
817
818
819
  		}
  		break;
  	default:
b4e08ea14   Luis Carlos Cobo   mac80211: add PLI...
820
  		/* should not get here, PLINK_BLOCKED is dealt with at the
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
821
  		 * beginning of the function
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
822
  		 */
07346f81e   Johannes Berg   mac80211: proper ...
823
  		spin_unlock_bh(&sta->lock);
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
824
825
  		break;
  	}
d0709a651   Johannes Berg   mac80211: RCU-ify...
826
827
  
  	rcu_read_unlock();
c3896d2ca   Luis Carlos Cobo   mac80211: mesh pe...
828
  }