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