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