mesh_plink.c revision bf7cd94dcc71682cd6af4a9028f95307b7db41c5
1ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand/*
2ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * Copyright (c) 2008, 2009 open80211s Ltd.
3ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * Author:     Luis Carlos Cobo <luisca@cozybit.com>
4ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand *
5ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * This program is free software; you can redistribute it and/or modify
6ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * it under the terms of the GNU General Public License version 2 as
7ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * published by the Free Software Foundation.
8ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand */
9ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#include <linux/gfp.h>
10ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#include <linux/kernel.h>
11ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#include <linux/random.h>
12ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#include "ieee80211_i.h"
13ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#include "rate.h"
14ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#include "mesh.h"
15ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
16ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#define PLINK_GET_LLID(p) (p + 2)
17ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#define PLINK_GET_PLID(p) (p + 4)
18ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
19ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
20ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand				jiffies + HZ * t / 1000))
217a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
22ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand/* We only need a valid sta if user configured a minimum rssi_threshold. */
23ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand#define rssi_threshold_check(sta, sdata) \
24ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		(sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\
25ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		(sta && (s8) -ewma_read(&sta->avg_signal) > \
26ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		sdata->u.mesh.mshcfg.rssi_threshold))
27ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
28ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levandenum plink_event {
29ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	PLINK_UNDEFINED,
30ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	OPN_ACPT,
31ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	OPN_RJCT,
32ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	OPN_IGNR,
33ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	CNF_ACPT,
34ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	CNF_RJCT,
35ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	CNF_IGNR,
36ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	CLS_ACPT,
37ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	CLS_IGNR
38ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand};
39ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
40ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levandstatic int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
41ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			       enum ieee80211_self_protected_actioncode action,
42ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			       u8 *da, __le16 llid, __le16 plid, __le16 reason);
43ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
44ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand/**
45ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
46ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand *
47ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * @sta: mesh peer link to restart
48ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand *
49ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * Locking: this function must be called holding sta->lock
50af1c51fcb2aea23ec2dfe73b7d66515d1622e689Marcelo Tosatti */
51ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levandstatic inline void mesh_plink_fsm_restart(struct sta_info *sta)
52ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand{
53ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	sta->plink_state = NL80211_PLINK_LISTEN;
54ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	sta->llid = sta->plid = sta->reason = 0;
55ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	sta->plink_retries = 0;
56ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand}
57ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
58ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand/*
59ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * mesh_set_short_slot_time - enable / disable ERP short slot time.
60ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand *
61ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * The standard indirectly mandates mesh STAs to turn off short slot time by
62ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * disallowing advertising this (802.11-2012 8.4.1.4), but that doesn't mean we
63ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * can't be sneaky about it. Enable short slot time if all mesh STAs in the
64ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * MBSS support ERP rates.
65ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand *
66ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * Returns BSS_CHANGED_ERP_SLOT or 0 for no change.
67ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand */
68ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levandstatic u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata)
69ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand{
70ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	struct ieee80211_local *local = sdata->local;
71ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
72ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
73ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	struct sta_info *sta;
74ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	u32 erp_rates = 0, changed = 0;
7590da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao	int i;
76ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	bool short_slot = false;
77ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
787a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	if (band == IEEE80211_BAND_5GHZ) {
79ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		/* (IEEE 802.11-2012 19.4.5) */
80ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		short_slot = true;
81ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		goto out;
82ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	} else if (band != IEEE80211_BAND_2GHZ ||
83ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		   (band == IEEE80211_BAND_2GHZ &&
84ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		    local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
85ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		goto out;
86ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
87ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	for (i = 0; i < sband->n_bitrates; i++)
88ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		if (sband->bitrates[i].flags & IEEE80211_RATE_ERP_G)
89ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			erp_rates |= BIT(i);
907a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
917a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	if (!erp_rates)
927a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		goto out;
937a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
947a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	rcu_read_lock();
957a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	list_for_each_entry_rcu(sta, &local->sta_list, list) {
967a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		if (sdata != sta->sdata ||
977a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		    sta->plink_state != NL80211_PLINK_ESTAB)
987a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand			continue;
997a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
1007a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		short_slot = false;
1017a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		if (erp_rates & sta->sta.supp_rates[band])
1027a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand			short_slot = true;
1037a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		 else
1047a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand			break;
1057a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	}
1067a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	rcu_read_unlock();
107ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
108ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levandout:
109ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	if (sdata->vif.bss_conf.use_short_slot != short_slot) {
110ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		sdata->vif.bss_conf.use_short_slot = short_slot;
111ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		changed = BSS_CHANGED_ERP_SLOT;
112ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		mpl_dbg(sdata, "mesh_plink %pM: ERP short slot time %d\n",
1137a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand			sdata->vif.addr, short_slot);
114ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	}
115ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	return changed;
116ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand}
117ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
118ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand/**
119dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand * mesh_set_ht_prot_mode - set correct HT protection mode
120ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand *
121ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT
122ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * mesh STA in a MBSS. Three HT protection modes are supported for now, non-HT
123ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * mixed mode, 20MHz-protection and no-protection mode. non-HT mixed mode is
124ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * selected if any non-HT peers are present in our MBSS.  20MHz-protection mode
125ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * is selected if all peers in our 20/40MHz MBSS support HT and atleast one
126ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * HT20 peer is present. Otherwise no-protection mode is selected.
127ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand */
128ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levandstatic u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
129ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand{
130ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	struct ieee80211_local *local = sdata->local;
131ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	struct sta_info *sta;
132ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	u32 changed = 0;
133ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	u16 ht_opmode;
134ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	bool non_ht_sta = false, ht20_sta = false;
135ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
136ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
137ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		return 0;
138ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
139ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	rcu_read_lock();
140ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	list_for_each_entry_rcu(sta, &local->sta_list, list) {
141ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		if (sdata != sta->sdata ||
1427a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		    sta->plink_state != NL80211_PLINK_ESTAB)
1437a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand			continue;
1447a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
1457a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		switch (sta->ch_width) {
1467a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand		case NL80211_CHAN_WIDTH_20_NOHT:
147ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			mpl_dbg(sdata,
148ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand				"mesh_plink %pM: nonHT sta (%pM) is present\n",
149ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand				sdata->vif.addr, sta->sta.addr);
150ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			non_ht_sta = true;
151ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			goto out;
152ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		case NL80211_CHAN_WIDTH_20:
153ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			mpl_dbg(sdata,
154ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand				"mesh_plink %pM: HT20 sta (%pM) is present\n",
155ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand				sdata->vif.addr, sta->sta.addr);
156ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			ht20_sta = true;
157ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		default:
158ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			break;
159ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		}
160ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	}
161ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levandout:
162ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	rcu_read_unlock();
163ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
164ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	if (non_ht_sta)
165ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
166ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	else if (ht20_sta &&
167ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		 sdata->vif.bss_conf.chandef.width > NL80211_CHAN_WIDTH_20)
168ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
169ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	else
170ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
171ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
172ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
173ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
174ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
175ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		changed = BSS_CHANGED_HT;
176ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		mpl_dbg(sdata,
177ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			"mesh_plink %pM: protection mode changed to %d\n",
178ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			sdata->vif.addr, ht_opmode);
179ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	}
1807a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
181ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	return changed;
182ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand}
183dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand
184ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand/**
185ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * __mesh_plink_deactivate - deactivate mesh peer link
1867a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand *
1877a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand * @sta: mesh peer link to deactivate
1887a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand *
1897a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand * All mesh paths with this peer as next hop will be flushed
1907a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand * Returns beacon changed flag if the beacon content changed.
191ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand *
192ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * Locking: the caller must hold sta->lock
193ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand */
194ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levandstatic u32 __mesh_plink_deactivate(struct sta_info *sta)
1957a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand{
196ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	struct ieee80211_sub_if_data *sdata = sta->sdata;
1977a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	u32 changed = 0;
198ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand
199ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	if (sta->plink_state == NL80211_PLINK_ESTAB)
200ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		changed = mesh_plink_dec_estab_count(sdata);
2017a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	sta->plink_state = NL80211_PLINK_BLOCKED;
2027a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	mesh_path_flush_by_nexthop(sta);
2037a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
2047a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	ieee80211_mps_sta_status_update(sta);
2057a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	changed |= ieee80211_mps_local_status_update(sdata);
2067a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
2077a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	return changed;
2087a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand}
2097a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
210ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand/**
211ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand * mesh_plink_deactivate - deactivate mesh peer link
2127a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand *
2137a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand * @sta: mesh peer link to deactivate
2147a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand *
2157a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand * All mesh paths with this peer as next hop will be flushed
2167a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand */
2177a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levandu32 mesh_plink_deactivate(struct sta_info *sta)
2187a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand{
2197a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	struct ieee80211_sub_if_data *sdata = sta->sdata;
2207a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	u32 changed;
2217a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
2227a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	spin_lock_bh(&sta->lock);
2237a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	changed = __mesh_plink_deactivate(sta);
224ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
225ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
226ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			    sta->sta.addr, sta->llid, sta->plid,
2277a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand			    sta->reason);
2287a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	spin_unlock_bh(&sta->lock);
2297a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
2307a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	return changed;
2317a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand}
2327a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
2337a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levandstatic int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
2347a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand			       enum ieee80211_self_protected_actioncode action,
2357a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand			       u8 *da, __le16 llid, __le16 plid, __le16 reason)
2367a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand{
2377a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	struct ieee80211_local *local = sdata->local;
2387a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	struct sk_buff *skb;
2397a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	struct ieee80211_tx_info *info;
2407a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	struct ieee80211_mgmt *mgmt;
241ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand	bool include_plid = false;
2427a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	u16 peering_proto = 0;
2437a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	u8 *pos, ie_len = 4;
2447a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
245ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand		      sizeof(mgmt->u.action.u.self_prot);
2467a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	int err = -ENOMEM;
2477a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand
2487a4eb7fd50d4df99fc1f623e6d90680d9fca3d82Geoff Levand	skb = dev_alloc_skb(local->tx_headroom +
249ad75a41085d80c8ce5e885962c15779935f8267eGeoff Levand			    hdr_len +
250			    2 + /* capability info */
251			    2 + /* AID */
252			    2 + 8 + /* supported rates */
253			    2 + (IEEE80211_MAX_SUPP_RATES - 8) +
254			    2 + sdata->u.mesh.mesh_id_len +
255			    2 + sizeof(struct ieee80211_meshconf_ie) +
256			    2 + sizeof(struct ieee80211_ht_cap) +
257			    2 + sizeof(struct ieee80211_ht_operation) +
258			    2 + 8 + /* peering IE */
259			    sdata->u.mesh.ie_len);
260	if (!skb)
261		return -1;
262	info = IEEE80211_SKB_CB(skb);
263	skb_reserve(skb, local->tx_headroom);
264	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
265	memset(mgmt, 0, hdr_len);
266	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
267					  IEEE80211_STYPE_ACTION);
268	memcpy(mgmt->da, da, ETH_ALEN);
269	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
270	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
271	mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
272	mgmt->u.action.u.self_prot.action_code = action;
273
274	if (action != WLAN_SP_MESH_PEERING_CLOSE) {
275		enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
276
277		/* capability info */
278		pos = skb_put(skb, 2);
279		memset(pos, 0, 2);
280		if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
281			/* AID */
282			pos = skb_put(skb, 2);
283			memcpy(pos + 2, &plid, 2);
284		}
285		if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
286		    ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
287		    mesh_add_rsn_ie(sdata, skb) ||
288		    mesh_add_meshid_ie(sdata, skb) ||
289		    mesh_add_meshconf_ie(sdata, skb))
290			goto free;
291	} else {	/* WLAN_SP_MESH_PEERING_CLOSE */
292		info->flags |= IEEE80211_TX_CTL_NO_ACK;
293		if (mesh_add_meshid_ie(sdata, skb))
294			goto free;
295	}
296
297	/* Add Mesh Peering Management element */
298	switch (action) {
299	case WLAN_SP_MESH_PEERING_OPEN:
300		break;
301	case WLAN_SP_MESH_PEERING_CONFIRM:
302		ie_len += 2;
303		include_plid = true;
304		break;
305	case WLAN_SP_MESH_PEERING_CLOSE:
306		if (plid) {
307			ie_len += 2;
308			include_plid = true;
309		}
310		ie_len += 2;	/* reason code */
311		break;
312	default:
313		err = -EINVAL;
314		goto free;
315	}
316
317	if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
318		goto free;
319
320	pos = skb_put(skb, 2 + ie_len);
321	*pos++ = WLAN_EID_PEER_MGMT;
322	*pos++ = ie_len;
323	memcpy(pos, &peering_proto, 2);
324	pos += 2;
325	memcpy(pos, &llid, 2);
326	pos += 2;
327	if (include_plid) {
328		memcpy(pos, &plid, 2);
329		pos += 2;
330	}
331	if (action == WLAN_SP_MESH_PEERING_CLOSE) {
332		memcpy(pos, &reason, 2);
333		pos += 2;
334	}
335
336	if (action != WLAN_SP_MESH_PEERING_CLOSE) {
337		if (mesh_add_ht_cap_ie(sdata, skb) ||
338		    mesh_add_ht_oper_ie(sdata, skb))
339			goto free;
340	}
341
342	if (mesh_add_vendor_ies(sdata, skb))
343		goto free;
344
345	ieee80211_tx_skb(sdata, skb);
346	return 0;
347free:
348	kfree_skb(skb);
349	return err;
350}
351
352static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
353			       struct sta_info *sta,
354			       struct ieee802_11_elems *elems, bool insert)
355{
356	struct ieee80211_local *local = sdata->local;
357	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
358	struct ieee80211_supported_band *sband;
359	u32 rates, basic_rates = 0, changed = 0;
360
361	sband = local->hw.wiphy->bands[band];
362	rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates);
363
364	spin_lock_bh(&sta->lock);
365	sta->last_rx = jiffies;
366
367	/* rates and capabilities don't change during peering */
368	if (sta->plink_state == NL80211_PLINK_ESTAB)
369		goto out;
370
371	if (sta->sta.supp_rates[band] != rates)
372		changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
373	sta->sta.supp_rates[band] = rates;
374	if (elems->ht_cap_elem &&
375	    sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
376		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
377						  elems->ht_cap_elem, sta);
378	else
379		memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
380
381	if (elems->ht_operation) {
382		struct cfg80211_chan_def chandef;
383
384		if (!(elems->ht_operation->ht_param &
385		      IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
386			sta->sta.bandwidth = IEEE80211_STA_RX_BW_20;
387		ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
388					     elems->ht_operation, &chandef);
389		if (sta->ch_width != chandef.width)
390			changed |= IEEE80211_RC_BW_CHANGED;
391		sta->ch_width = chandef.width;
392	}
393
394	if (insert)
395		rate_control_rate_init(sta);
396	else
397		rate_control_rate_update(local, sband, sta, changed);
398out:
399	spin_unlock_bh(&sta->lock);
400}
401
402static struct sta_info *
403__mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
404{
405	struct sta_info *sta;
406
407	if (sdata->local->num_sta >= MESH_MAX_PLINKS)
408		return NULL;
409
410	sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
411	if (!sta)
412		return NULL;
413
414	sta->plink_state = NL80211_PLINK_LISTEN;
415	init_timer(&sta->plink_timer);
416
417	sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
418	sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
419	sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
420
421	set_sta_flag(sta, WLAN_STA_WME);
422
423	return sta;
424}
425
426static struct sta_info *
427mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr,
428		    struct ieee802_11_elems *elems)
429{
430	struct sta_info *sta = NULL;
431
432	/* Userspace handles peer allocation when security is enabled */
433	if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
434		cfg80211_notify_new_peer_candidate(sdata->dev, addr,
435						   elems->ie_start,
436						   elems->total_len,
437						   GFP_KERNEL);
438	else
439		sta = __mesh_sta_info_alloc(sdata, addr);
440
441	return sta;
442}
443
444/*
445 * mesh_sta_info_get - return mesh sta info entry for @addr.
446 *
447 * @sdata: local meshif
448 * @addr: peer's address
449 * @elems: IEs from beacon or mesh peering frame.
450 *
451 * Return existing or newly allocated sta_info under RCU read lock.
452 * (re)initialize with given IEs.
453 */
454static struct sta_info *
455mesh_sta_info_get(struct ieee80211_sub_if_data *sdata,
456		  u8 *addr, struct ieee802_11_elems *elems) __acquires(RCU)
457{
458	struct sta_info *sta = NULL;
459
460	rcu_read_lock();
461	sta = sta_info_get(sdata, addr);
462	if (sta) {
463		mesh_sta_info_init(sdata, sta, elems, false);
464	} else {
465		rcu_read_unlock();
466		/* can't run atomic */
467		sta = mesh_sta_info_alloc(sdata, addr, elems);
468		if (!sta) {
469			rcu_read_lock();
470			return NULL;
471		}
472
473		mesh_sta_info_init(sdata, sta, elems, true);
474
475		if (sta_info_insert_rcu(sta))
476			return NULL;
477	}
478
479	return sta;
480}
481
482/*
483 * mesh_neighbour_update - update or initialize new mesh neighbor.
484 *
485 * @sdata: local meshif
486 * @addr: peer's address
487 * @elems: IEs from beacon or mesh peering frame
488 *
489 * Initiates peering if appropriate.
490 */
491void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
492			   u8 *hw_addr,
493			   struct ieee802_11_elems *elems)
494{
495	struct sta_info *sta;
496	u32 changed = 0;
497
498	sta = mesh_sta_info_get(sdata, hw_addr, elems);
499	if (!sta)
500		goto out;
501
502	if (mesh_peer_accepts_plinks(elems) &&
503	    sta->plink_state == NL80211_PLINK_LISTEN &&
504	    sdata->u.mesh.accepting_plinks &&
505	    sdata->u.mesh.mshcfg.auto_open_plinks &&
506	    rssi_threshold_check(sta, sdata))
507		changed = mesh_plink_open(sta);
508
509	ieee80211_mps_frame_release(sta, elems);
510out:
511	rcu_read_unlock();
512	ieee80211_mbss_info_change_notify(sdata, changed);
513}
514
515static void mesh_plink_timer(unsigned long data)
516{
517	struct sta_info *sta;
518	__le16 llid, plid, reason;
519	struct ieee80211_sub_if_data *sdata;
520	struct mesh_config *mshcfg;
521
522	/*
523	 * This STA is valid because sta_info_destroy() will
524	 * del_timer_sync() this timer after having made sure
525	 * it cannot be readded (by deleting the plink.)
526	 */
527	sta = (struct sta_info *) data;
528
529	if (sta->sdata->local->quiescing) {
530		sta->plink_timer_was_running = true;
531		return;
532	}
533
534	spin_lock_bh(&sta->lock);
535	if (sta->ignore_plink_timer) {
536		sta->ignore_plink_timer = false;
537		spin_unlock_bh(&sta->lock);
538		return;
539	}
540	mpl_dbg(sta->sdata,
541		"Mesh plink timer for %pM fired on state %d\n",
542		sta->sta.addr, sta->plink_state);
543	reason = 0;
544	llid = sta->llid;
545	plid = sta->plid;
546	sdata = sta->sdata;
547	mshcfg = &sdata->u.mesh.mshcfg;
548
549	switch (sta->plink_state) {
550	case NL80211_PLINK_OPN_RCVD:
551	case NL80211_PLINK_OPN_SNT:
552		/* retry timer */
553		if (sta->plink_retries < mshcfg->dot11MeshMaxRetries) {
554			u32 rand;
555			mpl_dbg(sta->sdata,
556				"Mesh plink for %pM (retry, timeout): %d %d\n",
557				sta->sta.addr, sta->plink_retries,
558				sta->plink_timeout);
559			get_random_bytes(&rand, sizeof(u32));
560			sta->plink_timeout = sta->plink_timeout +
561					     rand % sta->plink_timeout;
562			++sta->plink_retries;
563			mod_plink_timer(sta, sta->plink_timeout);
564			spin_unlock_bh(&sta->lock);
565			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
566					    sta->sta.addr, llid, 0, 0);
567			break;
568		}
569		reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
570		/* fall through on else */
571	case NL80211_PLINK_CNF_RCVD:
572		/* confirm timer */
573		if (!reason)
574			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
575		sta->plink_state = NL80211_PLINK_HOLDING;
576		mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
577		spin_unlock_bh(&sta->lock);
578		mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
579				    sta->sta.addr, llid, plid, reason);
580		break;
581	case NL80211_PLINK_HOLDING:
582		/* holding timer */
583		del_timer(&sta->plink_timer);
584		mesh_plink_fsm_restart(sta);
585		spin_unlock_bh(&sta->lock);
586		break;
587	default:
588		spin_unlock_bh(&sta->lock);
589		break;
590	}
591}
592
593#ifdef CONFIG_PM
594void mesh_plink_quiesce(struct sta_info *sta)
595{
596	if (!ieee80211_vif_is_mesh(&sta->sdata->vif))
597		return;
598
599	/* no kernel mesh sta timers have been initialized */
600	if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
601		return;
602
603	if (del_timer_sync(&sta->plink_timer))
604		sta->plink_timer_was_running = true;
605}
606
607void mesh_plink_restart(struct sta_info *sta)
608{
609	if (sta->plink_timer_was_running) {
610		add_timer(&sta->plink_timer);
611		sta->plink_timer_was_running = false;
612	}
613}
614#endif
615
616static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
617{
618	sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
619	sta->plink_timer.data = (unsigned long) sta;
620	sta->plink_timer.function = mesh_plink_timer;
621	sta->plink_timeout = timeout;
622	add_timer(&sta->plink_timer);
623}
624
625u32 mesh_plink_open(struct sta_info *sta)
626{
627	__le16 llid;
628	struct ieee80211_sub_if_data *sdata = sta->sdata;
629	u32 changed;
630
631	if (!test_sta_flag(sta, WLAN_STA_AUTH))
632		return 0;
633
634	spin_lock_bh(&sta->lock);
635	get_random_bytes(&llid, 2);
636	sta->llid = llid;
637	if (sta->plink_state != NL80211_PLINK_LISTEN &&
638	    sta->plink_state != NL80211_PLINK_BLOCKED) {
639		spin_unlock_bh(&sta->lock);
640		return 0;
641	}
642	sta->plink_state = NL80211_PLINK_OPN_SNT;
643	mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout);
644	spin_unlock_bh(&sta->lock);
645	mpl_dbg(sdata,
646		"Mesh plink: starting establishment with %pM\n",
647		sta->sta.addr);
648
649	/* set the non-peer mode to active during peering */
650	changed = ieee80211_mps_local_status_update(sdata);
651
652	mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
653			    sta->sta.addr, llid, 0, 0);
654	return changed;
655}
656
657u32 mesh_plink_block(struct sta_info *sta)
658{
659	u32 changed;
660
661	spin_lock_bh(&sta->lock);
662	changed = __mesh_plink_deactivate(sta);
663	sta->plink_state = NL80211_PLINK_BLOCKED;
664	spin_unlock_bh(&sta->lock);
665
666	return changed;
667}
668
669
670void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
671			 struct ieee80211_mgmt *mgmt, size_t len,
672			 struct ieee80211_rx_status *rx_status)
673{
674	struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
675	struct ieee802_11_elems elems;
676	struct sta_info *sta;
677	enum plink_event event;
678	enum ieee80211_self_protected_actioncode ftype;
679	size_t baselen;
680	bool matches_local = true;
681	u8 ie_len;
682	u8 *baseaddr;
683	u32 changed = 0;
684	__le16 plid, llid, reason;
685	static const char * const mplstates[] = {
686		[NL80211_PLINK_LISTEN] = "LISTEN",
687		[NL80211_PLINK_OPN_SNT] = "OPN-SNT",
688		[NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
689		[NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
690		[NL80211_PLINK_ESTAB] = "ESTAB",
691		[NL80211_PLINK_HOLDING] = "HOLDING",
692		[NL80211_PLINK_BLOCKED] = "BLOCKED"
693	};
694
695	/* need action_code, aux */
696	if (len < IEEE80211_MIN_ACTION_SIZE + 3)
697		return;
698
699	if (is_multicast_ether_addr(mgmt->da)) {
700		mpl_dbg(sdata,
701			"Mesh plink: ignore frame from multicast address\n");
702		return;
703	}
704
705	baseaddr = mgmt->u.action.u.self_prot.variable;
706	baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
707	if (mgmt->u.action.u.self_prot.action_code ==
708						WLAN_SP_MESH_PEERING_CONFIRM) {
709		baseaddr += 4;
710		baselen += 4;
711	}
712	ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
713
714	if (!elems.peering) {
715		mpl_dbg(sdata,
716			"Mesh plink: missing necessary peer link ie\n");
717		return;
718	}
719
720	if (elems.rsn_len &&
721	    sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
722		mpl_dbg(sdata,
723			"Mesh plink: can't establish link with secure peer\n");
724		return;
725	}
726
727	ftype = mgmt->u.action.u.self_prot.action_code;
728	ie_len = elems.peering_len;
729	if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
730	    (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
731	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
732							&& ie_len != 8)) {
733		mpl_dbg(sdata,
734			"Mesh plink: incorrect plink ie length %d %d\n",
735			ftype, ie_len);
736		return;
737	}
738
739	if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
740	    (!elems.mesh_id || !elems.mesh_config)) {
741		mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
742		return;
743	}
744	/* Note the lines below are correct, the llid in the frame is the plid
745	 * from the point of view of this host.
746	 */
747	memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
748	if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
749	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
750		memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
751
752	/* WARNING: Only for sta pointer, is dropped & re-acquired */
753	rcu_read_lock();
754
755	sta = sta_info_get(sdata, mgmt->sa);
756	if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
757		mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
758		rcu_read_unlock();
759		return;
760	}
761
762	if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
763	    !rssi_threshold_check(sta, sdata)) {
764		mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
765			mgmt->sa);
766		rcu_read_unlock();
767		return;
768	}
769
770	if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
771		mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
772		rcu_read_unlock();
773		return;
774	}
775
776	if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
777		rcu_read_unlock();
778		return;
779	}
780
781	/* Now we will figure out the appropriate event... */
782	event = PLINK_UNDEFINED;
783	if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
784	    !mesh_matches_local(sdata, &elems)) {
785		matches_local = false;
786		switch (ftype) {
787		case WLAN_SP_MESH_PEERING_OPEN:
788			event = OPN_RJCT;
789			break;
790		case WLAN_SP_MESH_PEERING_CONFIRM:
791			event = CNF_RJCT;
792			break;
793		default:
794			break;
795		}
796	}
797
798	if (!sta && !matches_local) {
799		rcu_read_unlock();
800		reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
801		llid = 0;
802		mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
803				    mgmt->sa, llid, plid, reason);
804		return;
805	} else if (!sta) {
806		/* ftype == WLAN_SP_MESH_PEERING_OPEN */
807		if (!mesh_plink_free_count(sdata)) {
808			mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
809			rcu_read_unlock();
810			return;
811		}
812		event = OPN_ACPT;
813	} else if (matches_local) {
814		switch (ftype) {
815		case WLAN_SP_MESH_PEERING_OPEN:
816			if (!mesh_plink_free_count(sdata) ||
817			    (sta->plid && sta->plid != plid))
818				event = OPN_IGNR;
819			else
820				event = OPN_ACPT;
821			break;
822		case WLAN_SP_MESH_PEERING_CONFIRM:
823			if (!mesh_plink_free_count(sdata) ||
824			    (sta->llid != llid || sta->plid != plid))
825				event = CNF_IGNR;
826			else
827				event = CNF_ACPT;
828			break;
829		case WLAN_SP_MESH_PEERING_CLOSE:
830			if (sta->plink_state == NL80211_PLINK_ESTAB)
831				/* Do not check for llid or plid. This does not
832				 * follow the standard but since multiple plinks
833				 * per sta are not supported, it is necessary in
834				 * order to avoid a livelock when MP A sees an
835				 * establish peer link to MP B but MP B does not
836				 * see it. This can be caused by a timeout in
837				 * B's peer link establishment or B beign
838				 * restarted.
839				 */
840				event = CLS_ACPT;
841			else if (sta->plid != plid)
842				event = CLS_IGNR;
843			else if (ie_len == 7 && sta->llid != llid)
844				event = CLS_IGNR;
845			else
846				event = CLS_ACPT;
847			break;
848		default:
849			mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
850			rcu_read_unlock();
851			return;
852		}
853	}
854
855	if (event == OPN_ACPT) {
856		rcu_read_unlock();
857		/* allocate sta entry if necessary and update info */
858		sta = mesh_sta_info_get(sdata, mgmt->sa, &elems);
859		if (!sta) {
860			mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
861			rcu_read_unlock();
862			return;
863		}
864	}
865
866	mpl_dbg(sdata,
867		"Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
868		mgmt->sa, mplstates[sta->plink_state],
869		le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
870		event);
871	reason = 0;
872	spin_lock_bh(&sta->lock);
873	switch (sta->plink_state) {
874		/* spin_unlock as soon as state is updated at each case */
875	case NL80211_PLINK_LISTEN:
876		switch (event) {
877		case CLS_ACPT:
878			mesh_plink_fsm_restart(sta);
879			spin_unlock_bh(&sta->lock);
880			break;
881		case OPN_ACPT:
882			sta->plink_state = NL80211_PLINK_OPN_RCVD;
883			sta->plid = plid;
884			get_random_bytes(&llid, 2);
885			sta->llid = llid;
886			mesh_plink_timer_set(sta,
887					     mshcfg->dot11MeshRetryTimeout);
888
889			/* set the non-peer mode to active during peering */
890			changed |= ieee80211_mps_local_status_update(sdata);
891
892			spin_unlock_bh(&sta->lock);
893			mesh_plink_frame_tx(sdata,
894					    WLAN_SP_MESH_PEERING_OPEN,
895					    sta->sta.addr, llid, 0, 0);
896			mesh_plink_frame_tx(sdata,
897					    WLAN_SP_MESH_PEERING_CONFIRM,
898					    sta->sta.addr, llid, plid, 0);
899			break;
900		default:
901			spin_unlock_bh(&sta->lock);
902			break;
903		}
904		break;
905
906	case NL80211_PLINK_OPN_SNT:
907		switch (event) {
908		case OPN_RJCT:
909		case CNF_RJCT:
910			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
911		case CLS_ACPT:
912			if (!reason)
913				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
914			sta->reason = reason;
915			sta->plink_state = NL80211_PLINK_HOLDING;
916			if (!mod_plink_timer(sta,
917					     mshcfg->dot11MeshHoldingTimeout))
918				sta->ignore_plink_timer = true;
919
920			llid = sta->llid;
921			spin_unlock_bh(&sta->lock);
922			mesh_plink_frame_tx(sdata,
923					    WLAN_SP_MESH_PEERING_CLOSE,
924					    sta->sta.addr, llid, plid, reason);
925			break;
926		case OPN_ACPT:
927			/* retry timer is left untouched */
928			sta->plink_state = NL80211_PLINK_OPN_RCVD;
929			sta->plid = plid;
930			llid = sta->llid;
931			spin_unlock_bh(&sta->lock);
932			mesh_plink_frame_tx(sdata,
933					    WLAN_SP_MESH_PEERING_CONFIRM,
934					    sta->sta.addr, llid, plid, 0);
935			break;
936		case CNF_ACPT:
937			sta->plink_state = NL80211_PLINK_CNF_RCVD;
938			if (!mod_plink_timer(sta,
939					     mshcfg->dot11MeshConfirmTimeout))
940				sta->ignore_plink_timer = true;
941
942			spin_unlock_bh(&sta->lock);
943			break;
944		default:
945			spin_unlock_bh(&sta->lock);
946			break;
947		}
948		break;
949
950	case NL80211_PLINK_OPN_RCVD:
951		switch (event) {
952		case OPN_RJCT:
953		case CNF_RJCT:
954			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
955		case CLS_ACPT:
956			if (!reason)
957				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
958			sta->reason = reason;
959			sta->plink_state = NL80211_PLINK_HOLDING;
960			if (!mod_plink_timer(sta,
961					     mshcfg->dot11MeshHoldingTimeout))
962				sta->ignore_plink_timer = true;
963
964			llid = sta->llid;
965			spin_unlock_bh(&sta->lock);
966			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
967					    sta->sta.addr, llid, plid, reason);
968			break;
969		case OPN_ACPT:
970			llid = sta->llid;
971			spin_unlock_bh(&sta->lock);
972			mesh_plink_frame_tx(sdata,
973					    WLAN_SP_MESH_PEERING_CONFIRM,
974					    sta->sta.addr, llid, plid, 0);
975			break;
976		case CNF_ACPT:
977			del_timer(&sta->plink_timer);
978			sta->plink_state = NL80211_PLINK_ESTAB;
979			spin_unlock_bh(&sta->lock);
980			changed |= mesh_plink_inc_estab_count(sdata);
981			changed |= mesh_set_ht_prot_mode(sdata);
982			changed |= mesh_set_short_slot_time(sdata);
983			mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
984				sta->sta.addr);
985			ieee80211_mps_sta_status_update(sta);
986			changed |= ieee80211_mps_set_sta_local_pm(sta,
987						       mshcfg->power_mode);
988			break;
989		default:
990			spin_unlock_bh(&sta->lock);
991			break;
992		}
993		break;
994
995	case NL80211_PLINK_CNF_RCVD:
996		switch (event) {
997		case OPN_RJCT:
998		case CNF_RJCT:
999			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
1000		case CLS_ACPT:
1001			if (!reason)
1002				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
1003			sta->reason = reason;
1004			sta->plink_state = NL80211_PLINK_HOLDING;
1005			if (!mod_plink_timer(sta,
1006					     mshcfg->dot11MeshHoldingTimeout))
1007				sta->ignore_plink_timer = true;
1008
1009			llid = sta->llid;
1010			spin_unlock_bh(&sta->lock);
1011			mesh_plink_frame_tx(sdata,
1012					    WLAN_SP_MESH_PEERING_CLOSE,
1013					    sta->sta.addr, llid, plid, reason);
1014			break;
1015		case OPN_ACPT:
1016			del_timer(&sta->plink_timer);
1017			sta->plink_state = NL80211_PLINK_ESTAB;
1018			spin_unlock_bh(&sta->lock);
1019			changed |= mesh_plink_inc_estab_count(sdata);
1020			changed |= mesh_set_ht_prot_mode(sdata);
1021			changed |= mesh_set_short_slot_time(sdata);
1022			mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
1023				sta->sta.addr);
1024			mesh_plink_frame_tx(sdata,
1025					    WLAN_SP_MESH_PEERING_CONFIRM,
1026					    sta->sta.addr, llid, plid, 0);
1027			ieee80211_mps_sta_status_update(sta);
1028			changed |= ieee80211_mps_set_sta_local_pm(sta,
1029							mshcfg->power_mode);
1030			break;
1031		default:
1032			spin_unlock_bh(&sta->lock);
1033			break;
1034		}
1035		break;
1036
1037	case NL80211_PLINK_ESTAB:
1038		switch (event) {
1039		case CLS_ACPT:
1040			reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
1041			sta->reason = reason;
1042			changed |= __mesh_plink_deactivate(sta);
1043			sta->plink_state = NL80211_PLINK_HOLDING;
1044			llid = sta->llid;
1045			mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
1046			spin_unlock_bh(&sta->lock);
1047			changed |= mesh_set_ht_prot_mode(sdata);
1048			changed |= mesh_set_short_slot_time(sdata);
1049			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
1050					    sta->sta.addr, llid, plid, reason);
1051			break;
1052		case OPN_ACPT:
1053			llid = sta->llid;
1054			spin_unlock_bh(&sta->lock);
1055			mesh_plink_frame_tx(sdata,
1056					    WLAN_SP_MESH_PEERING_CONFIRM,
1057					    sta->sta.addr, llid, plid, 0);
1058			break;
1059		default:
1060			spin_unlock_bh(&sta->lock);
1061			break;
1062		}
1063		break;
1064	case NL80211_PLINK_HOLDING:
1065		switch (event) {
1066		case CLS_ACPT:
1067			if (del_timer(&sta->plink_timer))
1068				sta->ignore_plink_timer = 1;
1069			mesh_plink_fsm_restart(sta);
1070			spin_unlock_bh(&sta->lock);
1071			break;
1072		case OPN_ACPT:
1073		case CNF_ACPT:
1074		case OPN_RJCT:
1075		case CNF_RJCT:
1076			llid = sta->llid;
1077			reason = sta->reason;
1078			spin_unlock_bh(&sta->lock);
1079			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
1080					    sta->sta.addr, llid, plid, reason);
1081			break;
1082		default:
1083			spin_unlock_bh(&sta->lock);
1084		}
1085		break;
1086	default:
1087		/* should not get here, PLINK_BLOCKED is dealt with at the
1088		 * beginning of the function
1089		 */
1090		spin_unlock_bh(&sta->lock);
1091		break;
1092	}
1093
1094	rcu_read_unlock();
1095
1096	if (changed)
1097		ieee80211_mbss_info_change_notify(sdata, changed);
1098}
1099