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