Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/mac80211/mesh_plink.c
15109 views
1
/*
2
* Copyright (c) 2008, 2009 open80211s Ltd.
3
* Author: Luis Carlos Cobo <[email protected]>
4
*
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation.
8
*/
9
#include <linux/gfp.h>
10
#include <linux/kernel.h>
11
#include <linux/random.h>
12
#include "ieee80211_i.h"
13
#include "rate.h"
14
#include "mesh.h"
15
16
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
17
#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
18
#else
19
#define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
20
#endif
21
22
#define PLINK_GET_LLID(p) (p + 4)
23
#define PLINK_GET_PLID(p) (p + 6)
24
25
#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
26
jiffies + HZ * t / 1000))
27
28
/* Peer link cancel reasons, all subject to ANA approval */
29
#define MESH_LINK_CANCELLED 2
30
#define MESH_MAX_NEIGHBORS 3
31
#define MESH_CAPABILITY_POLICY_VIOLATION 4
32
#define MESH_CLOSE_RCVD 5
33
#define MESH_MAX_RETRIES 6
34
#define MESH_CONFIRM_TIMEOUT 7
35
#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS 8
36
#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9
37
#define MESH_SECURITY_FAILED_VERIFICATION 10
38
39
#define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
40
#define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
41
#define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
42
#define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
43
#define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
44
45
enum plink_frame_type {
46
PLINK_OPEN = 1,
47
PLINK_CONFIRM,
48
PLINK_CLOSE
49
};
50
51
enum plink_event {
52
PLINK_UNDEFINED,
53
OPN_ACPT,
54
OPN_RJCT,
55
OPN_IGNR,
56
CNF_ACPT,
57
CNF_RJCT,
58
CNF_IGNR,
59
CLS_ACPT,
60
CLS_IGNR
61
};
62
63
static inline
64
void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
65
{
66
atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
67
mesh_accept_plinks_update(sdata);
68
}
69
70
static inline
71
void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
72
{
73
atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
74
mesh_accept_plinks_update(sdata);
75
}
76
77
/**
78
* mesh_plink_fsm_restart - restart a mesh peer link finite state machine
79
*
80
* @sta: mesh peer link to restart
81
*
82
* Locking: this function must be called holding sta->lock
83
*/
84
static inline void mesh_plink_fsm_restart(struct sta_info *sta)
85
{
86
sta->plink_state = NL80211_PLINK_LISTEN;
87
sta->llid = sta->plid = sta->reason = 0;
88
sta->plink_retries = 0;
89
}
90
91
/*
92
* NOTE: This is just an alias for sta_info_alloc(), see notes
93
* on it in the lifecycle management section!
94
*/
95
static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
96
u8 *hw_addr, u32 rates)
97
{
98
struct ieee80211_local *local = sdata->local;
99
struct sta_info *sta;
100
101
if (local->num_sta >= MESH_MAX_PLINKS)
102
return NULL;
103
104
sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
105
if (!sta)
106
return NULL;
107
108
sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
109
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
110
rate_control_rate_init(sta);
111
112
return sta;
113
}
114
115
/**
116
* __mesh_plink_deactivate - deactivate mesh peer link
117
*
118
* @sta: mesh peer link to deactivate
119
*
120
* All mesh paths with this peer as next hop will be flushed
121
*
122
* Locking: the caller must hold sta->lock
123
*/
124
static bool __mesh_plink_deactivate(struct sta_info *sta)
125
{
126
struct ieee80211_sub_if_data *sdata = sta->sdata;
127
bool deactivated = false;
128
129
if (sta->plink_state == NL80211_PLINK_ESTAB) {
130
mesh_plink_dec_estab_count(sdata);
131
deactivated = true;
132
}
133
sta->plink_state = NL80211_PLINK_BLOCKED;
134
mesh_path_flush_by_nexthop(sta);
135
136
return deactivated;
137
}
138
139
/**
140
* mesh_plink_deactivate - deactivate mesh peer link
141
*
142
* @sta: mesh peer link to deactivate
143
*
144
* All mesh paths with this peer as next hop will be flushed
145
*/
146
void mesh_plink_deactivate(struct sta_info *sta)
147
{
148
struct ieee80211_sub_if_data *sdata = sta->sdata;
149
bool deactivated;
150
151
spin_lock_bh(&sta->lock);
152
deactivated = __mesh_plink_deactivate(sta);
153
spin_unlock_bh(&sta->lock);
154
155
if (deactivated)
156
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
157
}
158
159
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
160
enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
161
__le16 reason) {
162
struct ieee80211_local *local = sdata->local;
163
struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
164
sdata->u.mesh.ie_len);
165
struct ieee80211_mgmt *mgmt;
166
bool include_plid = false;
167
static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
168
u8 *pos;
169
int ie_len;
170
171
if (!skb)
172
return -1;
173
skb_reserve(skb, local->hw.extra_tx_headroom);
174
/* 25 is the size of the common mgmt part (24) plus the size of the
175
* common action part (1)
176
*/
177
mgmt = (struct ieee80211_mgmt *)
178
skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
179
memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
180
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
181
IEEE80211_STYPE_ACTION);
182
memcpy(mgmt->da, da, ETH_ALEN);
183
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
184
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
185
mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
186
mgmt->u.action.u.plink_action.action_code = action;
187
188
if (action == PLINK_CLOSE)
189
mgmt->u.action.u.plink_action.aux = reason;
190
else {
191
mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
192
if (action == PLINK_CONFIRM) {
193
pos = skb_put(skb, 4);
194
/* two-byte status code followed by two-byte AID */
195
memset(pos, 0, 2);
196
memcpy(pos + 2, &plid, 2);
197
}
198
mesh_mgmt_ies_add(skb, sdata);
199
}
200
201
/* Add Peer Link Management element */
202
switch (action) {
203
case PLINK_OPEN:
204
ie_len = 6;
205
break;
206
case PLINK_CONFIRM:
207
ie_len = 8;
208
include_plid = true;
209
break;
210
case PLINK_CLOSE:
211
default:
212
if (!plid)
213
ie_len = 8;
214
else {
215
ie_len = 10;
216
include_plid = true;
217
}
218
break;
219
}
220
221
pos = skb_put(skb, 2 + ie_len);
222
*pos++ = WLAN_EID_PEER_LINK;
223
*pos++ = ie_len;
224
memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto));
225
pos += 4;
226
memcpy(pos, &llid, 2);
227
if (include_plid) {
228
pos += 2;
229
memcpy(pos, &plid, 2);
230
}
231
if (action == PLINK_CLOSE) {
232
pos += 2;
233
memcpy(pos, &reason, 2);
234
}
235
236
ieee80211_tx_skb(sdata, skb);
237
return 0;
238
}
239
240
void mesh_neighbour_update(u8 *hw_addr, u32 rates,
241
struct ieee80211_sub_if_data *sdata,
242
struct ieee802_11_elems *elems)
243
{
244
struct ieee80211_local *local = sdata->local;
245
struct sta_info *sta;
246
247
rcu_read_lock();
248
249
sta = sta_info_get(sdata, hw_addr);
250
if (!sta) {
251
rcu_read_unlock();
252
/* Userspace handles peer allocation when security is enabled
253
* */
254
if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
255
cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
256
elems->ie_start, elems->total_len,
257
GFP_KERNEL);
258
else
259
sta = mesh_plink_alloc(sdata, hw_addr, rates);
260
if (!sta)
261
return;
262
if (sta_info_insert_rcu(sta)) {
263
rcu_read_unlock();
264
return;
265
}
266
}
267
268
sta->last_rx = jiffies;
269
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
270
if (mesh_peer_accepts_plinks(elems) &&
271
sta->plink_state == NL80211_PLINK_LISTEN &&
272
sdata->u.mesh.accepting_plinks &&
273
sdata->u.mesh.mshcfg.auto_open_plinks)
274
mesh_plink_open(sta);
275
276
rcu_read_unlock();
277
}
278
279
static void mesh_plink_timer(unsigned long data)
280
{
281
struct sta_info *sta;
282
__le16 llid, plid, reason;
283
struct ieee80211_sub_if_data *sdata;
284
285
/*
286
* This STA is valid because sta_info_destroy() will
287
* del_timer_sync() this timer after having made sure
288
* it cannot be readded (by deleting the plink.)
289
*/
290
sta = (struct sta_info *) data;
291
292
if (sta->sdata->local->quiescing) {
293
sta->plink_timer_was_running = true;
294
return;
295
}
296
297
spin_lock_bh(&sta->lock);
298
if (sta->ignore_plink_timer) {
299
sta->ignore_plink_timer = false;
300
spin_unlock_bh(&sta->lock);
301
return;
302
}
303
mpl_dbg("Mesh plink timer for %pM fired on state %d\n",
304
sta->sta.addr, sta->plink_state);
305
reason = 0;
306
llid = sta->llid;
307
plid = sta->plid;
308
sdata = sta->sdata;
309
310
switch (sta->plink_state) {
311
case NL80211_PLINK_OPN_RCVD:
312
case NL80211_PLINK_OPN_SNT:
313
/* retry timer */
314
if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
315
u32 rand;
316
mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n",
317
sta->sta.addr, sta->plink_retries,
318
sta->plink_timeout);
319
get_random_bytes(&rand, sizeof(u32));
320
sta->plink_timeout = sta->plink_timeout +
321
rand % sta->plink_timeout;
322
++sta->plink_retries;
323
mod_plink_timer(sta, sta->plink_timeout);
324
spin_unlock_bh(&sta->lock);
325
mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
326
0, 0);
327
break;
328
}
329
reason = cpu_to_le16(MESH_MAX_RETRIES);
330
/* fall through on else */
331
case NL80211_PLINK_CNF_RCVD:
332
/* confirm timer */
333
if (!reason)
334
reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
335
sta->plink_state = NL80211_PLINK_HOLDING;
336
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
337
spin_unlock_bh(&sta->lock);
338
mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid,
339
reason);
340
break;
341
case NL80211_PLINK_HOLDING:
342
/* holding timer */
343
del_timer(&sta->plink_timer);
344
mesh_plink_fsm_restart(sta);
345
spin_unlock_bh(&sta->lock);
346
break;
347
default:
348
spin_unlock_bh(&sta->lock);
349
break;
350
}
351
}
352
353
#ifdef CONFIG_PM
354
void mesh_plink_quiesce(struct sta_info *sta)
355
{
356
if (del_timer_sync(&sta->plink_timer))
357
sta->plink_timer_was_running = true;
358
}
359
360
void mesh_plink_restart(struct sta_info *sta)
361
{
362
if (sta->plink_timer_was_running) {
363
add_timer(&sta->plink_timer);
364
sta->plink_timer_was_running = false;
365
}
366
}
367
#endif
368
369
static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
370
{
371
sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
372
sta->plink_timer.data = (unsigned long) sta;
373
sta->plink_timer.function = mesh_plink_timer;
374
sta->plink_timeout = timeout;
375
add_timer(&sta->plink_timer);
376
}
377
378
int mesh_plink_open(struct sta_info *sta)
379
{
380
__le16 llid;
381
struct ieee80211_sub_if_data *sdata = sta->sdata;
382
383
if (!test_sta_flags(sta, WLAN_STA_AUTH))
384
return -EPERM;
385
386
spin_lock_bh(&sta->lock);
387
get_random_bytes(&llid, 2);
388
sta->llid = llid;
389
if (sta->plink_state != NL80211_PLINK_LISTEN) {
390
spin_unlock_bh(&sta->lock);
391
return -EBUSY;
392
}
393
sta->plink_state = NL80211_PLINK_OPN_SNT;
394
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
395
spin_unlock_bh(&sta->lock);
396
mpl_dbg("Mesh plink: starting establishment with %pM\n",
397
sta->sta.addr);
398
399
return mesh_plink_frame_tx(sdata, PLINK_OPEN,
400
sta->sta.addr, llid, 0, 0);
401
}
402
403
void mesh_plink_block(struct sta_info *sta)
404
{
405
struct ieee80211_sub_if_data *sdata = sta->sdata;
406
bool deactivated;
407
408
spin_lock_bh(&sta->lock);
409
deactivated = __mesh_plink_deactivate(sta);
410
sta->plink_state = NL80211_PLINK_BLOCKED;
411
spin_unlock_bh(&sta->lock);
412
413
if (deactivated)
414
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
415
}
416
417
418
void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
419
size_t len, struct ieee80211_rx_status *rx_status)
420
{
421
struct ieee80211_local *local = sdata->local;
422
struct ieee802_11_elems elems;
423
struct sta_info *sta;
424
enum plink_event event;
425
enum plink_frame_type ftype;
426
size_t baselen;
427
bool deactivated, matches_local = true;
428
u8 ie_len;
429
u8 *baseaddr;
430
__le16 plid, llid, reason;
431
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
432
static const char *mplstates[] = {
433
[NL80211_PLINK_LISTEN] = "LISTEN",
434
[NL80211_PLINK_OPN_SNT] = "OPN-SNT",
435
[NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
436
[NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
437
[NL80211_PLINK_ESTAB] = "ESTAB",
438
[NL80211_PLINK_HOLDING] = "HOLDING",
439
[NL80211_PLINK_BLOCKED] = "BLOCKED"
440
};
441
#endif
442
443
/* need action_code, aux */
444
if (len < IEEE80211_MIN_ACTION_SIZE + 3)
445
return;
446
447
if (is_multicast_ether_addr(mgmt->da)) {
448
mpl_dbg("Mesh plink: ignore frame from multicast address");
449
return;
450
}
451
452
baseaddr = mgmt->u.action.u.plink_action.variable;
453
baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
454
if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) {
455
baseaddr += 4;
456
baselen += 4;
457
}
458
ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
459
if (!elems.peer_link) {
460
mpl_dbg("Mesh plink: missing necessary peer link ie\n");
461
return;
462
}
463
if (elems.rsn_len &&
464
sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
465
mpl_dbg("Mesh plink: can't establish link with secure peer\n");
466
return;
467
}
468
469
ftype = mgmt->u.action.u.plink_action.action_code;
470
ie_len = elems.peer_link_len;
471
if ((ftype == PLINK_OPEN && ie_len != 6) ||
472
(ftype == PLINK_CONFIRM && ie_len != 8) ||
473
(ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) {
474
mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
475
ftype, ie_len);
476
return;
477
}
478
479
if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) {
480
mpl_dbg("Mesh plink: missing necessary ie\n");
481
return;
482
}
483
/* Note the lines below are correct, the llid in the frame is the plid
484
* from the point of view of this host.
485
*/
486
memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2);
487
if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10))
488
memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
489
490
rcu_read_lock();
491
492
sta = sta_info_get(sdata, mgmt->sa);
493
if (!sta && ftype != PLINK_OPEN) {
494
mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
495
rcu_read_unlock();
496
return;
497
}
498
499
if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) {
500
mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
501
rcu_read_unlock();
502
return;
503
}
504
505
if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
506
rcu_read_unlock();
507
return;
508
}
509
510
/* Now we will figure out the appropriate event... */
511
event = PLINK_UNDEFINED;
512
if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) {
513
matches_local = false;
514
switch (ftype) {
515
case PLINK_OPEN:
516
event = OPN_RJCT;
517
break;
518
case PLINK_CONFIRM:
519
event = CNF_RJCT;
520
break;
521
case PLINK_CLOSE:
522
/* avoid warning */
523
break;
524
}
525
}
526
527
if (!sta && !matches_local) {
528
rcu_read_unlock();
529
reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
530
llid = 0;
531
mesh_plink_frame_tx(sdata, PLINK_CLOSE, mgmt->sa, llid,
532
plid, reason);
533
return;
534
} else if (!sta) {
535
/* ftype == PLINK_OPEN */
536
u32 rates;
537
538
rcu_read_unlock();
539
540
if (!mesh_plink_free_count(sdata)) {
541
mpl_dbg("Mesh plink error: no more free plinks\n");
542
return;
543
}
544
545
rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
546
sta = mesh_plink_alloc(sdata, mgmt->sa, rates);
547
if (!sta) {
548
mpl_dbg("Mesh plink error: plink table full\n");
549
return;
550
}
551
if (sta_info_insert_rcu(sta)) {
552
rcu_read_unlock();
553
return;
554
}
555
event = OPN_ACPT;
556
spin_lock_bh(&sta->lock);
557
} else if (matches_local) {
558
spin_lock_bh(&sta->lock);
559
switch (ftype) {
560
case PLINK_OPEN:
561
if (!mesh_plink_free_count(sdata) ||
562
(sta->plid && sta->plid != plid))
563
event = OPN_IGNR;
564
else
565
event = OPN_ACPT;
566
break;
567
case PLINK_CONFIRM:
568
if (!mesh_plink_free_count(sdata) ||
569
(sta->llid != llid || sta->plid != plid))
570
event = CNF_IGNR;
571
else
572
event = CNF_ACPT;
573
break;
574
case PLINK_CLOSE:
575
if (sta->plink_state == NL80211_PLINK_ESTAB)
576
/* Do not check for llid or plid. This does not
577
* follow the standard but since multiple plinks
578
* per sta are not supported, it is necessary in
579
* order to avoid a livelock when MP A sees an
580
* establish peer link to MP B but MP B does not
581
* see it. This can be caused by a timeout in
582
* B's peer link establishment or B beign
583
* restarted.
584
*/
585
event = CLS_ACPT;
586
else if (sta->plid != plid)
587
event = CLS_IGNR;
588
else if (ie_len == 7 && sta->llid != llid)
589
event = CLS_IGNR;
590
else
591
event = CLS_ACPT;
592
break;
593
default:
594
mpl_dbg("Mesh plink: unknown frame subtype\n");
595
spin_unlock_bh(&sta->lock);
596
rcu_read_unlock();
597
return;
598
}
599
} else {
600
spin_lock_bh(&sta->lock);
601
}
602
603
mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
604
mgmt->sa, mplstates[sta->plink_state],
605
le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
606
event);
607
reason = 0;
608
switch (sta->plink_state) {
609
/* spin_unlock as soon as state is updated at each case */
610
case NL80211_PLINK_LISTEN:
611
switch (event) {
612
case CLS_ACPT:
613
mesh_plink_fsm_restart(sta);
614
spin_unlock_bh(&sta->lock);
615
break;
616
case OPN_ACPT:
617
sta->plink_state = NL80211_PLINK_OPN_RCVD;
618
sta->plid = plid;
619
get_random_bytes(&llid, 2);
620
sta->llid = llid;
621
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
622
spin_unlock_bh(&sta->lock);
623
mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
624
0, 0);
625
mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr,
626
llid, plid, 0);
627
break;
628
default:
629
spin_unlock_bh(&sta->lock);
630
break;
631
}
632
break;
633
634
case NL80211_PLINK_OPN_SNT:
635
switch (event) {
636
case OPN_RJCT:
637
case CNF_RJCT:
638
reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
639
case CLS_ACPT:
640
if (!reason)
641
reason = cpu_to_le16(MESH_CLOSE_RCVD);
642
sta->reason = reason;
643
sta->plink_state = NL80211_PLINK_HOLDING;
644
if (!mod_plink_timer(sta,
645
dot11MeshHoldingTimeout(sdata)))
646
sta->ignore_plink_timer = true;
647
648
llid = sta->llid;
649
spin_unlock_bh(&sta->lock);
650
mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
651
plid, reason);
652
break;
653
case OPN_ACPT:
654
/* retry timer is left untouched */
655
sta->plink_state = NL80211_PLINK_OPN_RCVD;
656
sta->plid = plid;
657
llid = sta->llid;
658
spin_unlock_bh(&sta->lock);
659
mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
660
plid, 0);
661
break;
662
case CNF_ACPT:
663
sta->plink_state = NL80211_PLINK_CNF_RCVD;
664
if (!mod_plink_timer(sta,
665
dot11MeshConfirmTimeout(sdata)))
666
sta->ignore_plink_timer = true;
667
668
spin_unlock_bh(&sta->lock);
669
break;
670
default:
671
spin_unlock_bh(&sta->lock);
672
break;
673
}
674
break;
675
676
case NL80211_PLINK_OPN_RCVD:
677
switch (event) {
678
case OPN_RJCT:
679
case CNF_RJCT:
680
reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
681
case CLS_ACPT:
682
if (!reason)
683
reason = cpu_to_le16(MESH_CLOSE_RCVD);
684
sta->reason = reason;
685
sta->plink_state = NL80211_PLINK_HOLDING;
686
if (!mod_plink_timer(sta,
687
dot11MeshHoldingTimeout(sdata)))
688
sta->ignore_plink_timer = true;
689
690
llid = sta->llid;
691
spin_unlock_bh(&sta->lock);
692
mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
693
plid, reason);
694
break;
695
case OPN_ACPT:
696
llid = sta->llid;
697
spin_unlock_bh(&sta->lock);
698
mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
699
plid, 0);
700
break;
701
case CNF_ACPT:
702
del_timer(&sta->plink_timer);
703
sta->plink_state = NL80211_PLINK_ESTAB;
704
spin_unlock_bh(&sta->lock);
705
mesh_plink_inc_estab_count(sdata);
706
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
707
mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
708
sta->sta.addr);
709
break;
710
default:
711
spin_unlock_bh(&sta->lock);
712
break;
713
}
714
break;
715
716
case NL80211_PLINK_CNF_RCVD:
717
switch (event) {
718
case OPN_RJCT:
719
case CNF_RJCT:
720
reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
721
case CLS_ACPT:
722
if (!reason)
723
reason = cpu_to_le16(MESH_CLOSE_RCVD);
724
sta->reason = reason;
725
sta->plink_state = NL80211_PLINK_HOLDING;
726
if (!mod_plink_timer(sta,
727
dot11MeshHoldingTimeout(sdata)))
728
sta->ignore_plink_timer = true;
729
730
llid = sta->llid;
731
spin_unlock_bh(&sta->lock);
732
mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
733
plid, reason);
734
break;
735
case OPN_ACPT:
736
del_timer(&sta->plink_timer);
737
sta->plink_state = NL80211_PLINK_ESTAB;
738
spin_unlock_bh(&sta->lock);
739
mesh_plink_inc_estab_count(sdata);
740
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
741
mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
742
sta->sta.addr);
743
mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
744
plid, 0);
745
break;
746
default:
747
spin_unlock_bh(&sta->lock);
748
break;
749
}
750
break;
751
752
case NL80211_PLINK_ESTAB:
753
switch (event) {
754
case CLS_ACPT:
755
reason = cpu_to_le16(MESH_CLOSE_RCVD);
756
sta->reason = reason;
757
deactivated = __mesh_plink_deactivate(sta);
758
sta->plink_state = NL80211_PLINK_HOLDING;
759
llid = sta->llid;
760
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
761
spin_unlock_bh(&sta->lock);
762
if (deactivated)
763
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
764
mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
765
plid, reason);
766
break;
767
case OPN_ACPT:
768
llid = sta->llid;
769
spin_unlock_bh(&sta->lock);
770
mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
771
plid, 0);
772
break;
773
default:
774
spin_unlock_bh(&sta->lock);
775
break;
776
}
777
break;
778
case NL80211_PLINK_HOLDING:
779
switch (event) {
780
case CLS_ACPT:
781
if (del_timer(&sta->plink_timer))
782
sta->ignore_plink_timer = 1;
783
mesh_plink_fsm_restart(sta);
784
spin_unlock_bh(&sta->lock);
785
break;
786
case OPN_ACPT:
787
case CNF_ACPT:
788
case OPN_RJCT:
789
case CNF_RJCT:
790
llid = sta->llid;
791
reason = sta->reason;
792
spin_unlock_bh(&sta->lock);
793
mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr,
794
llid, plid, reason);
795
break;
796
default:
797
spin_unlock_bh(&sta->lock);
798
}
799
break;
800
default:
801
/* should not get here, PLINK_BLOCKED is dealt with at the
802
* beginning of the function
803
*/
804
spin_unlock_bh(&sta->lock);
805
break;
806
}
807
808
rcu_read_unlock();
809
}
810
811