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