1753c7e08SAugustin Cavalier /*-
2*86021fd4SAugustin Cavalier * SPDX-License-Identifier: BSD-2-Clause
38244a9baSAugustin Cavalier *
4753c7e08SAugustin Cavalier * Copyright (c) 2001 Atsushi Onoe
5753c7e08SAugustin Cavalier * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
6753c7e08SAugustin Cavalier * All rights reserved.
7753c7e08SAugustin Cavalier *
8753c7e08SAugustin Cavalier * Redistribution and use in source and binary forms, with or without
9753c7e08SAugustin Cavalier * modification, are permitted provided that the following conditions
10753c7e08SAugustin Cavalier * are met:
11753c7e08SAugustin Cavalier * 1. Redistributions of source code must retain the above copyright
12753c7e08SAugustin Cavalier * notice, this list of conditions and the following disclaimer.
13753c7e08SAugustin Cavalier * 2. Redistributions in binary form must reproduce the above copyright
14753c7e08SAugustin Cavalier * notice, this list of conditions and the following disclaimer in the
15753c7e08SAugustin Cavalier * documentation and/or other materials provided with the distribution.
16753c7e08SAugustin Cavalier *
17753c7e08SAugustin Cavalier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18753c7e08SAugustin Cavalier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19753c7e08SAugustin Cavalier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20753c7e08SAugustin Cavalier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21753c7e08SAugustin Cavalier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22753c7e08SAugustin Cavalier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23753c7e08SAugustin Cavalier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24753c7e08SAugustin Cavalier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25753c7e08SAugustin Cavalier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26753c7e08SAugustin Cavalier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27753c7e08SAugustin Cavalier */
28753c7e08SAugustin Cavalier
29753c7e08SAugustin Cavalier #include <sys/cdefs.h>
30753c7e08SAugustin Cavalier #include "opt_wlan.h"
31753c7e08SAugustin Cavalier
32753c7e08SAugustin Cavalier #include <sys/param.h>
33753c7e08SAugustin Cavalier #include <sys/systm.h>
34753c7e08SAugustin Cavalier #include <sys/mbuf.h>
35753c7e08SAugustin Cavalier #include <sys/malloc.h>
36753c7e08SAugustin Cavalier #include <sys/kernel.h>
37753c7e08SAugustin Cavalier
38753c7e08SAugustin Cavalier #include <sys/socket.h>
39753c7e08SAugustin Cavalier
40753c7e08SAugustin Cavalier #include <net/if.h>
41753c7e08SAugustin Cavalier #include <net/if_var.h>
42753c7e08SAugustin Cavalier #include <net/if_media.h>
43753c7e08SAugustin Cavalier #include <net/ethernet.h>
44753c7e08SAugustin Cavalier
45753c7e08SAugustin Cavalier #include <net80211/ieee80211_var.h>
46753c7e08SAugustin Cavalier #include <net80211/ieee80211_input.h>
47753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_SUPERG
48753c7e08SAugustin Cavalier #include <net80211/ieee80211_superg.h>
49753c7e08SAugustin Cavalier #endif
50753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_TDMA
51753c7e08SAugustin Cavalier #include <net80211/ieee80211_tdma.h>
52753c7e08SAugustin Cavalier #endif
53753c7e08SAugustin Cavalier #include <net80211/ieee80211_wds.h>
54753c7e08SAugustin Cavalier #include <net80211/ieee80211_mesh.h>
55753c7e08SAugustin Cavalier #include <net80211/ieee80211_ratectl.h>
568244a9baSAugustin Cavalier #include <net80211/ieee80211_vht.h>
57753c7e08SAugustin Cavalier
58753c7e08SAugustin Cavalier #include <net/bpf.h>
59753c7e08SAugustin Cavalier
60*86021fd4SAugustin Cavalier #ifdef IEEE80211_DEBUG_REFCNT
61*86021fd4SAugustin Cavalier #define __debrefcnt_used
62*86021fd4SAugustin Cavalier #else
63*86021fd4SAugustin Cavalier #define __debrefcnt_used __unused
64*86021fd4SAugustin Cavalier #endif
65*86021fd4SAugustin Cavalier
66753c7e08SAugustin Cavalier /*
67753c7e08SAugustin Cavalier * IEEE80211_NODE_HASHSIZE must be a power of 2.
68753c7e08SAugustin Cavalier */
69753c7e08SAugustin Cavalier CTASSERT((IEEE80211_NODE_HASHSIZE & (IEEE80211_NODE_HASHSIZE-1)) == 0);
70753c7e08SAugustin Cavalier
71753c7e08SAugustin Cavalier /*
72753c7e08SAugustin Cavalier * Association id's are managed with a bit vector.
73753c7e08SAugustin Cavalier */
74753c7e08SAugustin Cavalier #define IEEE80211_AID_SET(_vap, b) \
75753c7e08SAugustin Cavalier ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] |= \
76753c7e08SAugustin Cavalier (1 << (IEEE80211_AID(b) % 32)))
77753c7e08SAugustin Cavalier #define IEEE80211_AID_CLR(_vap, b) \
78753c7e08SAugustin Cavalier ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] &= \
79753c7e08SAugustin Cavalier ~(1 << (IEEE80211_AID(b) % 32)))
80753c7e08SAugustin Cavalier #define IEEE80211_AID_ISSET(_vap, b) \
81753c7e08SAugustin Cavalier ((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32)))
82753c7e08SAugustin Cavalier
83753c7e08SAugustin Cavalier static int ieee80211_sta_join1(struct ieee80211_node *);
84753c7e08SAugustin Cavalier
85*86021fd4SAugustin Cavalier static struct ieee80211_node *ieee80211_alloc_node(
86*86021fd4SAugustin Cavalier struct ieee80211_node_table *, struct ieee80211vap *,
87*86021fd4SAugustin Cavalier const uint8_t macaddr[IEEE80211_ADDR_LEN], const char *, int);
88753c7e08SAugustin Cavalier static struct ieee80211_node *node_alloc(struct ieee80211vap *,
89753c7e08SAugustin Cavalier const uint8_t [IEEE80211_ADDR_LEN]);
905cad57c4SJérôme Duval static int node_init(struct ieee80211_node *);
91753c7e08SAugustin Cavalier static void node_cleanup(struct ieee80211_node *);
92753c7e08SAugustin Cavalier static void node_free(struct ieee80211_node *);
93753c7e08SAugustin Cavalier static void node_age(struct ieee80211_node *);
94753c7e08SAugustin Cavalier static int8_t node_getrssi(const struct ieee80211_node *);
95753c7e08SAugustin Cavalier static void node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *);
96753c7e08SAugustin Cavalier static void node_getmimoinfo(const struct ieee80211_node *,
97753c7e08SAugustin Cavalier struct ieee80211_mimo_info *);
98753c7e08SAugustin Cavalier
99*86021fd4SAugustin Cavalier static void __ieee80211_free_node(struct ieee80211_node *);
100753c7e08SAugustin Cavalier
101753c7e08SAugustin Cavalier static void node_reclaim(struct ieee80211_node_table *nt,
102753c7e08SAugustin Cavalier struct ieee80211_node *ni);
103753c7e08SAugustin Cavalier static void ieee80211_node_table_init(struct ieee80211com *ic,
104753c7e08SAugustin Cavalier struct ieee80211_node_table *nt, const char *name,
105753c7e08SAugustin Cavalier int inact, int keymaxix);
106753c7e08SAugustin Cavalier static void ieee80211_node_table_reset(struct ieee80211_node_table *,
107753c7e08SAugustin Cavalier struct ieee80211vap *);
108753c7e08SAugustin Cavalier static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt);
1095cad57c4SJérôme Duval static void ieee80211_vap_erp_timeout(struct ieee80211vap *);
110753c7e08SAugustin Cavalier
111753c7e08SAugustin Cavalier MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
112753c7e08SAugustin Cavalier MALLOC_DEFINE(M_80211_NODE_IE, "80211nodeie", "802.11 node ie");
113753c7e08SAugustin Cavalier
114753c7e08SAugustin Cavalier void
ieee80211_node_attach(struct ieee80211com * ic)115753c7e08SAugustin Cavalier ieee80211_node_attach(struct ieee80211com *ic)
116753c7e08SAugustin Cavalier {
117753c7e08SAugustin Cavalier /* XXX really want maxlen enforced per-sta */
118753c7e08SAugustin Cavalier ieee80211_ageq_init(&ic->ic_stageq, ic->ic_max_keyix * 8,
119753c7e08SAugustin Cavalier "802.11 staging q");
120753c7e08SAugustin Cavalier ieee80211_node_table_init(ic, &ic->ic_sta, "station",
121753c7e08SAugustin Cavalier IEEE80211_INACT_INIT, ic->ic_max_keyix);
122753c7e08SAugustin Cavalier callout_init(&ic->ic_inact, 1);
123753c7e08SAugustin Cavalier callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
124753c7e08SAugustin Cavalier ieee80211_node_timeout, ic);
125753c7e08SAugustin Cavalier
126753c7e08SAugustin Cavalier ic->ic_node_alloc = node_alloc;
1275cad57c4SJérôme Duval ic->ic_node_init = node_init;
128753c7e08SAugustin Cavalier ic->ic_node_free = node_free;
129753c7e08SAugustin Cavalier ic->ic_node_cleanup = node_cleanup;
130753c7e08SAugustin Cavalier ic->ic_node_age = node_age;
131753c7e08SAugustin Cavalier ic->ic_node_drain = node_age; /* NB: same as age */
132753c7e08SAugustin Cavalier ic->ic_node_getrssi = node_getrssi;
133753c7e08SAugustin Cavalier ic->ic_node_getsignal = node_getsignal;
134753c7e08SAugustin Cavalier ic->ic_node_getmimoinfo = node_getmimoinfo;
135753c7e08SAugustin Cavalier
136753c7e08SAugustin Cavalier /*
137753c7e08SAugustin Cavalier * Set flags to be propagated to all vap's;
138753c7e08SAugustin Cavalier * these define default behaviour/configuration.
139753c7e08SAugustin Cavalier */
140753c7e08SAugustin Cavalier ic->ic_flags_ext |= IEEE80211_FEXT_INACT; /* inactivity processing */
141753c7e08SAugustin Cavalier }
142753c7e08SAugustin Cavalier
143753c7e08SAugustin Cavalier void
ieee80211_node_detach(struct ieee80211com * ic)144753c7e08SAugustin Cavalier ieee80211_node_detach(struct ieee80211com *ic)
145753c7e08SAugustin Cavalier {
146753c7e08SAugustin Cavalier
147753c7e08SAugustin Cavalier callout_drain(&ic->ic_inact);
148753c7e08SAugustin Cavalier ieee80211_node_table_cleanup(&ic->ic_sta);
149753c7e08SAugustin Cavalier ieee80211_ageq_drain(&ic->ic_stageq);
150753c7e08SAugustin Cavalier ieee80211_ageq_cleanup(&ic->ic_stageq);
151753c7e08SAugustin Cavalier }
152753c7e08SAugustin Cavalier
153753c7e08SAugustin Cavalier void
ieee80211_node_vattach(struct ieee80211vap * vap)154753c7e08SAugustin Cavalier ieee80211_node_vattach(struct ieee80211vap *vap)
155753c7e08SAugustin Cavalier {
156753c7e08SAugustin Cavalier /* NB: driver can override */
157753c7e08SAugustin Cavalier vap->iv_max_aid = IEEE80211_AID_DEF;
158753c7e08SAugustin Cavalier
159*86021fd4SAugustin Cavalier /* default station inactivity timer settings */
160753c7e08SAugustin Cavalier vap->iv_inact_init = IEEE80211_INACT_INIT;
161753c7e08SAugustin Cavalier vap->iv_inact_auth = IEEE80211_INACT_AUTH;
162753c7e08SAugustin Cavalier vap->iv_inact_run = IEEE80211_INACT_RUN;
163753c7e08SAugustin Cavalier vap->iv_inact_probe = IEEE80211_INACT_PROBE;
164753c7e08SAugustin Cavalier
165753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_INACT,
166753c7e08SAugustin Cavalier "%s: init %u auth %u run %u probe %u\n", __func__,
167753c7e08SAugustin Cavalier vap->iv_inact_init, vap->iv_inact_auth,
168753c7e08SAugustin Cavalier vap->iv_inact_run, vap->iv_inact_probe);
169753c7e08SAugustin Cavalier }
170753c7e08SAugustin Cavalier
171753c7e08SAugustin Cavalier void
ieee80211_node_latevattach(struct ieee80211vap * vap)172753c7e08SAugustin Cavalier ieee80211_node_latevattach(struct ieee80211vap *vap)
173753c7e08SAugustin Cavalier {
174*86021fd4SAugustin Cavalier
175*86021fd4SAugustin Cavalier /* XXX should ieee80211_vap_attach(), our only caller hold the lock? */
176*86021fd4SAugustin Cavalier IEEE80211_UNLOCK_ASSERT(vap->iv_ic);
177*86021fd4SAugustin Cavalier
178753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
179753c7e08SAugustin Cavalier /* XXX should we allow max aid to be zero? */
180753c7e08SAugustin Cavalier if (vap->iv_max_aid < IEEE80211_AID_MIN) {
181753c7e08SAugustin Cavalier vap->iv_max_aid = IEEE80211_AID_MIN;
182753c7e08SAugustin Cavalier if_printf(vap->iv_ifp,
183753c7e08SAugustin Cavalier "WARNING: max aid too small, changed to %d\n",
184753c7e08SAugustin Cavalier vap->iv_max_aid);
185753c7e08SAugustin Cavalier }
186753c7e08SAugustin Cavalier vap->iv_aid_bitmap = (uint32_t *) IEEE80211_MALLOC(
187753c7e08SAugustin Cavalier howmany(vap->iv_max_aid, 32) * sizeof(uint32_t),
188753c7e08SAugustin Cavalier M_80211_NODE,
189753c7e08SAugustin Cavalier IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
190753c7e08SAugustin Cavalier if (vap->iv_aid_bitmap == NULL) {
191753c7e08SAugustin Cavalier /* XXX no way to recover */
192753c7e08SAugustin Cavalier printf("%s: no memory for AID bitmap, max aid %d!\n",
193753c7e08SAugustin Cavalier __func__, vap->iv_max_aid);
194753c7e08SAugustin Cavalier vap->iv_max_aid = 0;
195753c7e08SAugustin Cavalier }
196753c7e08SAugustin Cavalier }
197753c7e08SAugustin Cavalier
198*86021fd4SAugustin Cavalier IEEE80211_LOCK(vap->iv_ic);
199753c7e08SAugustin Cavalier ieee80211_reset_bss(vap);
200*86021fd4SAugustin Cavalier IEEE80211_UNLOCK(vap->iv_ic);
201753c7e08SAugustin Cavalier
202753c7e08SAugustin Cavalier vap->iv_auth = ieee80211_authenticator_get(vap->iv_bss->ni_authmode);
203753c7e08SAugustin Cavalier }
204753c7e08SAugustin Cavalier
205753c7e08SAugustin Cavalier void
ieee80211_node_vdetach(struct ieee80211vap * vap)206753c7e08SAugustin Cavalier ieee80211_node_vdetach(struct ieee80211vap *vap)
207753c7e08SAugustin Cavalier {
208753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
209753c7e08SAugustin Cavalier
210*86021fd4SAugustin Cavalier /* XXX should ieee80211_vap_detach(), our only caller hold the lock? */
211*86021fd4SAugustin Cavalier IEEE80211_UNLOCK_ASSERT(vap->iv_ic);
212*86021fd4SAugustin Cavalier
213753c7e08SAugustin Cavalier ieee80211_node_table_reset(&ic->ic_sta, vap);
214*86021fd4SAugustin Cavalier IEEE80211_LOCK(ic);
215753c7e08SAugustin Cavalier if (vap->iv_bss != NULL) {
216753c7e08SAugustin Cavalier ieee80211_free_node(vap->iv_bss);
217*86021fd4SAugustin Cavalier vap->iv_update_bss(vap, NULL);
218753c7e08SAugustin Cavalier }
219*86021fd4SAugustin Cavalier IEEE80211_UNLOCK(ic);
220753c7e08SAugustin Cavalier if (vap->iv_aid_bitmap != NULL) {
221753c7e08SAugustin Cavalier IEEE80211_FREE(vap->iv_aid_bitmap, M_80211_NODE);
222753c7e08SAugustin Cavalier vap->iv_aid_bitmap = NULL;
223753c7e08SAugustin Cavalier }
224753c7e08SAugustin Cavalier }
225753c7e08SAugustin Cavalier
226753c7e08SAugustin Cavalier /*
227753c7e08SAugustin Cavalier * Port authorize/unauthorize interfaces for use by an authenticator.
228753c7e08SAugustin Cavalier */
229753c7e08SAugustin Cavalier
230753c7e08SAugustin Cavalier void
ieee80211_node_authorize(struct ieee80211_node * ni)231753c7e08SAugustin Cavalier ieee80211_node_authorize(struct ieee80211_node *ni)
232753c7e08SAugustin Cavalier {
233753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
234753c7e08SAugustin Cavalier
235753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_AUTH;
236753c7e08SAugustin Cavalier ni->ni_inact_reload = vap->iv_inact_run;
237753c7e08SAugustin Cavalier ni->ni_inact = ni->ni_inact_reload;
238753c7e08SAugustin Cavalier
239753c7e08SAugustin Cavalier IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
240753c7e08SAugustin Cavalier "%s: inact_reload %u", __func__, ni->ni_inact_reload);
241753c7e08SAugustin Cavalier }
242753c7e08SAugustin Cavalier
243753c7e08SAugustin Cavalier void
ieee80211_node_unauthorize(struct ieee80211_node * ni)244753c7e08SAugustin Cavalier ieee80211_node_unauthorize(struct ieee80211_node *ni)
245753c7e08SAugustin Cavalier {
246753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
247753c7e08SAugustin Cavalier
248753c7e08SAugustin Cavalier ni->ni_flags &= ~IEEE80211_NODE_AUTH;
249753c7e08SAugustin Cavalier ni->ni_inact_reload = vap->iv_inact_auth;
250753c7e08SAugustin Cavalier if (ni->ni_inact > ni->ni_inact_reload)
251753c7e08SAugustin Cavalier ni->ni_inact = ni->ni_inact_reload;
252753c7e08SAugustin Cavalier
253753c7e08SAugustin Cavalier IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
254753c7e08SAugustin Cavalier "%s: inact_reload %u inact %u", __func__,
255753c7e08SAugustin Cavalier ni->ni_inact_reload, ni->ni_inact);
256753c7e08SAugustin Cavalier }
257753c7e08SAugustin Cavalier
258753c7e08SAugustin Cavalier /*
259753c7e08SAugustin Cavalier * Fix tx parameters for a node according to ``association state''.
260753c7e08SAugustin Cavalier */
261753c7e08SAugustin Cavalier void
ieee80211_node_setuptxparms(struct ieee80211_node * ni)262753c7e08SAugustin Cavalier ieee80211_node_setuptxparms(struct ieee80211_node *ni)
263753c7e08SAugustin Cavalier {
264753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
265753c7e08SAugustin Cavalier enum ieee80211_phymode mode;
266753c7e08SAugustin Cavalier
2678244a9baSAugustin Cavalier if (ni->ni_flags & IEEE80211_NODE_VHT) {
2688244a9baSAugustin Cavalier if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
2698244a9baSAugustin Cavalier mode = IEEE80211_MODE_VHT_5GHZ;
2708244a9baSAugustin Cavalier else
2718244a9baSAugustin Cavalier mode = IEEE80211_MODE_VHT_2GHZ;
2728244a9baSAugustin Cavalier } else if (ni->ni_flags & IEEE80211_NODE_HT) {
273753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
274753c7e08SAugustin Cavalier mode = IEEE80211_MODE_11NA;
275753c7e08SAugustin Cavalier else
276753c7e08SAugustin Cavalier mode = IEEE80211_MODE_11NG;
277753c7e08SAugustin Cavalier } else { /* legacy rate handling */
278753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_ST(ni->ni_chan))
279753c7e08SAugustin Cavalier mode = IEEE80211_MODE_STURBO_A;
280753c7e08SAugustin Cavalier else if (IEEE80211_IS_CHAN_HALF(ni->ni_chan))
281753c7e08SAugustin Cavalier mode = IEEE80211_MODE_HALF;
282753c7e08SAugustin Cavalier else if (IEEE80211_IS_CHAN_QUARTER(ni->ni_chan))
283753c7e08SAugustin Cavalier mode = IEEE80211_MODE_QUARTER;
284753c7e08SAugustin Cavalier /* NB: 108A should be handled as 11a */
285753c7e08SAugustin Cavalier else if (IEEE80211_IS_CHAN_A(ni->ni_chan))
286753c7e08SAugustin Cavalier mode = IEEE80211_MODE_11A;
287753c7e08SAugustin Cavalier else if (IEEE80211_IS_CHAN_108G(ni->ni_chan) ||
288753c7e08SAugustin Cavalier (ni->ni_flags & IEEE80211_NODE_ERP))
289753c7e08SAugustin Cavalier mode = IEEE80211_MODE_11G;
290753c7e08SAugustin Cavalier else
291753c7e08SAugustin Cavalier mode = IEEE80211_MODE_11B;
292753c7e08SAugustin Cavalier }
293753c7e08SAugustin Cavalier ni->ni_txparms = &vap->iv_txparms[mode];
294753c7e08SAugustin Cavalier }
295753c7e08SAugustin Cavalier
296753c7e08SAugustin Cavalier /*
297753c7e08SAugustin Cavalier * Set/change the channel. The rate set is also updated as
298753c7e08SAugustin Cavalier * to insure a consistent view by drivers.
299753c7e08SAugustin Cavalier * XXX should be private but hostap needs it to deal with CSA
300753c7e08SAugustin Cavalier */
301753c7e08SAugustin Cavalier void
ieee80211_node_set_chan(struct ieee80211_node * ni,struct ieee80211_channel * chan)302753c7e08SAugustin Cavalier ieee80211_node_set_chan(struct ieee80211_node *ni,
303753c7e08SAugustin Cavalier struct ieee80211_channel *chan)
304753c7e08SAugustin Cavalier {
305753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
306753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
307753c7e08SAugustin Cavalier enum ieee80211_phymode mode;
308753c7e08SAugustin Cavalier
309753c7e08SAugustin Cavalier KASSERT(chan != IEEE80211_CHAN_ANYC, ("no channel"));
310753c7e08SAugustin Cavalier
311753c7e08SAugustin Cavalier ni->ni_chan = chan;
312753c7e08SAugustin Cavalier mode = ieee80211_chan2mode(chan);
313753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_HT(chan)) {
314753c7e08SAugustin Cavalier /*
315753c7e08SAugustin Cavalier * We must install the legacy rate est in ni_rates and the
316753c7e08SAugustin Cavalier * HT rate set in ni_htrates.
317753c7e08SAugustin Cavalier */
318753c7e08SAugustin Cavalier ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan);
319753c7e08SAugustin Cavalier /*
320753c7e08SAugustin Cavalier * Setup bss tx parameters based on operating mode. We
321753c7e08SAugustin Cavalier * use legacy rates when operating in a mixed HT+non-HT bss
322753c7e08SAugustin Cavalier * and non-ERP rates in 11g for mixed ERP+non-ERP bss.
323753c7e08SAugustin Cavalier */
324753c7e08SAugustin Cavalier if (mode == IEEE80211_MODE_11NA &&
325753c7e08SAugustin Cavalier (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0)
326753c7e08SAugustin Cavalier mode = IEEE80211_MODE_11A;
327753c7e08SAugustin Cavalier else if (mode == IEEE80211_MODE_11NG &&
328753c7e08SAugustin Cavalier (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0)
329753c7e08SAugustin Cavalier mode = IEEE80211_MODE_11G;
330753c7e08SAugustin Cavalier if (mode == IEEE80211_MODE_11G &&
331753c7e08SAugustin Cavalier (vap->iv_flags & IEEE80211_F_PUREG) == 0)
332753c7e08SAugustin Cavalier mode = IEEE80211_MODE_11B;
333753c7e08SAugustin Cavalier }
334753c7e08SAugustin Cavalier ni->ni_txparms = &vap->iv_txparms[mode];
335753c7e08SAugustin Cavalier ni->ni_rates = *ieee80211_get_suprates(ic, chan);
336753c7e08SAugustin Cavalier }
337753c7e08SAugustin Cavalier
338753c7e08SAugustin Cavalier static __inline void
copy_bss(struct ieee80211_node * nbss,const struct ieee80211_node * obss)339753c7e08SAugustin Cavalier copy_bss(struct ieee80211_node *nbss, const struct ieee80211_node *obss)
340753c7e08SAugustin Cavalier {
341753c7e08SAugustin Cavalier /* propagate useful state */
342753c7e08SAugustin Cavalier nbss->ni_authmode = obss->ni_authmode;
343753c7e08SAugustin Cavalier nbss->ni_txpower = obss->ni_txpower;
344753c7e08SAugustin Cavalier nbss->ni_vlan = obss->ni_vlan;
345753c7e08SAugustin Cavalier /* XXX statistics? */
346753c7e08SAugustin Cavalier /* XXX legacy WDS bssid? */
347753c7e08SAugustin Cavalier }
348753c7e08SAugustin Cavalier
349753c7e08SAugustin Cavalier void
ieee80211_create_ibss(struct ieee80211vap * vap,struct ieee80211_channel * chan)350753c7e08SAugustin Cavalier ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
351753c7e08SAugustin Cavalier {
352753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
353753c7e08SAugustin Cavalier struct ieee80211_node *ni;
354753c7e08SAugustin Cavalier
355753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
3568244a9baSAugustin Cavalier "%s: creating %s on channel %u%c flags 0x%08x\n", __func__,
357753c7e08SAugustin Cavalier ieee80211_opmode_name[vap->iv_opmode],
358753c7e08SAugustin Cavalier ieee80211_chan2ieee(ic, chan),
3598244a9baSAugustin Cavalier ieee80211_channel_type_char(chan),
3608244a9baSAugustin Cavalier chan->ic_flags);
361753c7e08SAugustin Cavalier
362*86021fd4SAugustin Cavalier ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr,
363*86021fd4SAugustin Cavalier __func__, __LINE__);
364753c7e08SAugustin Cavalier if (ni == NULL) {
365753c7e08SAugustin Cavalier /* XXX recovery? */
366753c7e08SAugustin Cavalier return;
367753c7e08SAugustin Cavalier }
368753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr);
369753c7e08SAugustin Cavalier ni->ni_esslen = vap->iv_des_ssid[0].len;
370753c7e08SAugustin Cavalier memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen);
371753c7e08SAugustin Cavalier if (vap->iv_bss != NULL)
372753c7e08SAugustin Cavalier copy_bss(ni, vap->iv_bss);
373753c7e08SAugustin Cavalier ni->ni_intval = ic->ic_bintval;
374753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_PRIVACY)
375753c7e08SAugustin Cavalier ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
376753c7e08SAugustin Cavalier if (ic->ic_phytype == IEEE80211_T_FH) {
377753c7e08SAugustin Cavalier ni->ni_fhdwell = 200; /* XXX */
378753c7e08SAugustin Cavalier ni->ni_fhindex = 1;
379753c7e08SAugustin Cavalier }
380753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_IBSS) {
381753c7e08SAugustin Cavalier ni->ni_capinfo |= IEEE80211_CAPINFO_IBSS; /* XXX */
382753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_DESBSSID)
383753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid);
384753c7e08SAugustin Cavalier else {
385*86021fd4SAugustin Cavalier net80211_get_random_bytes(ni->ni_bssid,
386*86021fd4SAugustin Cavalier IEEE80211_ADDR_LEN);
387753c7e08SAugustin Cavalier /* clear group bit, add local bit */
388753c7e08SAugustin Cavalier ni->ni_bssid[0] = (ni->ni_bssid[0] &~ 0x01) | 0x02;
389753c7e08SAugustin Cavalier }
390753c7e08SAugustin Cavalier } else if (vap->iv_opmode == IEEE80211_M_AHDEMO) {
391753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_DESBSSID)
392753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid);
393753c7e08SAugustin Cavalier else
394753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_TDMA
395753c7e08SAugustin Cavalier if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
396753c7e08SAugustin Cavalier #endif
397753c7e08SAugustin Cavalier memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN);
398753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_MESH
399753c7e08SAugustin Cavalier } else if (vap->iv_opmode == IEEE80211_M_MBSS) {
400753c7e08SAugustin Cavalier ni->ni_meshidlen = vap->iv_mesh->ms_idlen;
401753c7e08SAugustin Cavalier memcpy(ni->ni_meshid, vap->iv_mesh->ms_id, ni->ni_meshidlen);
402753c7e08SAugustin Cavalier #endif
403753c7e08SAugustin Cavalier }
404753c7e08SAugustin Cavalier /*
405753c7e08SAugustin Cavalier * Fix the channel and related attributes.
406753c7e08SAugustin Cavalier */
407753c7e08SAugustin Cavalier /* clear DFS CAC state on previous channel */
408753c7e08SAugustin Cavalier if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
409753c7e08SAugustin Cavalier ic->ic_bsschan->ic_freq != chan->ic_freq &&
410753c7e08SAugustin Cavalier IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan))
411753c7e08SAugustin Cavalier ieee80211_dfs_cac_clear(ic, ic->ic_bsschan);
412753c7e08SAugustin Cavalier ic->ic_bsschan = chan;
413753c7e08SAugustin Cavalier ieee80211_node_set_chan(ni, chan);
414753c7e08SAugustin Cavalier ic->ic_curmode = ieee80211_chan2mode(chan);
415753c7e08SAugustin Cavalier /*
416753c7e08SAugustin Cavalier * Do mode-specific setup.
417753c7e08SAugustin Cavalier */
418753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_FULL(chan)) {
419753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_ANYG(chan)) {
420753c7e08SAugustin Cavalier /*
421753c7e08SAugustin Cavalier * Use a mixed 11b/11g basic rate set.
422753c7e08SAugustin Cavalier */
423753c7e08SAugustin Cavalier ieee80211_setbasicrates(&ni->ni_rates,
424753c7e08SAugustin Cavalier IEEE80211_MODE_11G);
425753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_PUREG) {
426753c7e08SAugustin Cavalier /*
427753c7e08SAugustin Cavalier * Also mark OFDM rates basic so 11b
428753c7e08SAugustin Cavalier * stations do not join (WiFi compliance).
429753c7e08SAugustin Cavalier */
430753c7e08SAugustin Cavalier ieee80211_addbasicrates(&ni->ni_rates,
431753c7e08SAugustin Cavalier IEEE80211_MODE_11A);
432753c7e08SAugustin Cavalier }
433753c7e08SAugustin Cavalier } else if (IEEE80211_IS_CHAN_B(chan)) {
434753c7e08SAugustin Cavalier /*
435753c7e08SAugustin Cavalier * Force pure 11b rate set.
436753c7e08SAugustin Cavalier */
437753c7e08SAugustin Cavalier ieee80211_setbasicrates(&ni->ni_rates,
438753c7e08SAugustin Cavalier IEEE80211_MODE_11B);
439753c7e08SAugustin Cavalier }
440753c7e08SAugustin Cavalier }
441753c7e08SAugustin Cavalier
4428244a9baSAugustin Cavalier /* XXX TODO: other bits and pieces - eg fast-frames? */
4438244a9baSAugustin Cavalier
4448244a9baSAugustin Cavalier /* If we're an 11n channel then initialise the 11n bits */
4458244a9baSAugustin Cavalier if (IEEE80211_IS_CHAN_VHT(ni->ni_chan)) {
4468244a9baSAugustin Cavalier /* XXX what else? */
4478244a9baSAugustin Cavalier ieee80211_ht_node_init(ni);
4488244a9baSAugustin Cavalier ieee80211_vht_node_init(ni);
4498244a9baSAugustin Cavalier } else if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
4508244a9baSAugustin Cavalier /* XXX what else? */
4518244a9baSAugustin Cavalier ieee80211_ht_node_init(ni);
4528244a9baSAugustin Cavalier }
4538244a9baSAugustin Cavalier
454753c7e08SAugustin Cavalier (void) ieee80211_sta_join1(ieee80211_ref_node(ni));
455753c7e08SAugustin Cavalier }
456753c7e08SAugustin Cavalier
457753c7e08SAugustin Cavalier /*
458753c7e08SAugustin Cavalier * Reset bss state on transition to the INIT state.
459753c7e08SAugustin Cavalier * Clear any stations from the table (they have been
460753c7e08SAugustin Cavalier * deauth'd) and reset the bss node (clears key, rate
461753c7e08SAugustin Cavalier * etc. state).
462753c7e08SAugustin Cavalier */
463753c7e08SAugustin Cavalier void
ieee80211_reset_bss(struct ieee80211vap * vap)464753c7e08SAugustin Cavalier ieee80211_reset_bss(struct ieee80211vap *vap)
465753c7e08SAugustin Cavalier {
466753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
467753c7e08SAugustin Cavalier struct ieee80211_node *ni, *obss;
468753c7e08SAugustin Cavalier
469*86021fd4SAugustin Cavalier IEEE80211_LOCK_ASSERT(ic);
470*86021fd4SAugustin Cavalier
471753c7e08SAugustin Cavalier ieee80211_node_table_reset(&ic->ic_sta, vap);
472753c7e08SAugustin Cavalier /* XXX multi-bss: wrong */
4735cad57c4SJérôme Duval ieee80211_vap_reset_erp(vap);
474753c7e08SAugustin Cavalier
475*86021fd4SAugustin Cavalier ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr,
476*86021fd4SAugustin Cavalier __func__, __LINE__);
477753c7e08SAugustin Cavalier KASSERT(ni != NULL, ("unable to setup initial BSS node"));
478*86021fd4SAugustin Cavalier obss = vap->iv_update_bss(vap, ieee80211_ref_node(ni));
479753c7e08SAugustin Cavalier if (obss != NULL) {
480753c7e08SAugustin Cavalier copy_bss(ni, obss);
481753c7e08SAugustin Cavalier ni->ni_intval = ic->ic_bintval;
482753c7e08SAugustin Cavalier ieee80211_free_node(obss);
483753c7e08SAugustin Cavalier } else
484753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr);
485753c7e08SAugustin Cavalier }
486753c7e08SAugustin Cavalier
487753c7e08SAugustin Cavalier static int
match_ssid(const struct ieee80211_node * ni,int nssid,const struct ieee80211_scan_ssid ssids[])488753c7e08SAugustin Cavalier match_ssid(const struct ieee80211_node *ni,
489753c7e08SAugustin Cavalier int nssid, const struct ieee80211_scan_ssid ssids[])
490753c7e08SAugustin Cavalier {
491753c7e08SAugustin Cavalier int i;
492753c7e08SAugustin Cavalier
493753c7e08SAugustin Cavalier for (i = 0; i < nssid; i++) {
494753c7e08SAugustin Cavalier if (ni->ni_esslen == ssids[i].len &&
495753c7e08SAugustin Cavalier memcmp(ni->ni_essid, ssids[i].ssid, ni->ni_esslen) == 0)
496753c7e08SAugustin Cavalier return 1;
497753c7e08SAugustin Cavalier }
498753c7e08SAugustin Cavalier return 0;
499753c7e08SAugustin Cavalier }
500753c7e08SAugustin Cavalier
501753c7e08SAugustin Cavalier /*
502753c7e08SAugustin Cavalier * Test a node for suitability/compatibility.
503753c7e08SAugustin Cavalier */
504753c7e08SAugustin Cavalier static int
check_bss(struct ieee80211vap * vap,struct ieee80211_node * ni)505753c7e08SAugustin Cavalier check_bss(struct ieee80211vap *vap, struct ieee80211_node *ni)
506753c7e08SAugustin Cavalier {
507753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
508753c7e08SAugustin Cavalier uint8_t rate;
509753c7e08SAugustin Cavalier
510753c7e08SAugustin Cavalier if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
511753c7e08SAugustin Cavalier return 0;
512753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_IBSS) {
513753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
514753c7e08SAugustin Cavalier return 0;
515753c7e08SAugustin Cavalier } else {
516753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
517753c7e08SAugustin Cavalier return 0;
518753c7e08SAugustin Cavalier }
519753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_PRIVACY) {
520753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
521753c7e08SAugustin Cavalier return 0;
522753c7e08SAugustin Cavalier } else {
523753c7e08SAugustin Cavalier /* XXX does this mean privacy is supported or required? */
524753c7e08SAugustin Cavalier if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
525753c7e08SAugustin Cavalier return 0;
526753c7e08SAugustin Cavalier }
527753c7e08SAugustin Cavalier rate = ieee80211_fix_rate(ni, &ni->ni_rates,
528753c7e08SAugustin Cavalier IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
529753c7e08SAugustin Cavalier if (rate & IEEE80211_RATE_BASIC)
530753c7e08SAugustin Cavalier return 0;
531753c7e08SAugustin Cavalier if (vap->iv_des_nssid != 0 &&
532753c7e08SAugustin Cavalier !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid))
533753c7e08SAugustin Cavalier return 0;
534753c7e08SAugustin Cavalier if ((vap->iv_flags & IEEE80211_F_DESBSSID) &&
535753c7e08SAugustin Cavalier !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid))
536753c7e08SAugustin Cavalier return 0;
537753c7e08SAugustin Cavalier return 1;
538753c7e08SAugustin Cavalier }
539753c7e08SAugustin Cavalier
540753c7e08SAugustin Cavalier #ifdef IEEE80211_DEBUG
541753c7e08SAugustin Cavalier /*
542753c7e08SAugustin Cavalier * Display node suitability/compatibility.
543753c7e08SAugustin Cavalier */
544753c7e08SAugustin Cavalier static void
check_bss_debug(struct ieee80211vap * vap,struct ieee80211_node * ni)545753c7e08SAugustin Cavalier check_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni)
546753c7e08SAugustin Cavalier {
547753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
548753c7e08SAugustin Cavalier uint8_t rate;
549753c7e08SAugustin Cavalier int fail;
550753c7e08SAugustin Cavalier
551753c7e08SAugustin Cavalier fail = 0;
552753c7e08SAugustin Cavalier if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
553753c7e08SAugustin Cavalier fail |= 0x01;
554753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_IBSS) {
555753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
556753c7e08SAugustin Cavalier fail |= 0x02;
557753c7e08SAugustin Cavalier } else {
558753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
559753c7e08SAugustin Cavalier fail |= 0x02;
560753c7e08SAugustin Cavalier }
561753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_PRIVACY) {
562753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
563753c7e08SAugustin Cavalier fail |= 0x04;
564753c7e08SAugustin Cavalier } else {
565753c7e08SAugustin Cavalier /* XXX does this mean privacy is supported or required? */
566753c7e08SAugustin Cavalier if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
567753c7e08SAugustin Cavalier fail |= 0x04;
568753c7e08SAugustin Cavalier }
569753c7e08SAugustin Cavalier rate = ieee80211_fix_rate(ni, &ni->ni_rates,
570753c7e08SAugustin Cavalier IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
571753c7e08SAugustin Cavalier if (rate & IEEE80211_RATE_BASIC)
572753c7e08SAugustin Cavalier fail |= 0x08;
573753c7e08SAugustin Cavalier if (vap->iv_des_nssid != 0 &&
574753c7e08SAugustin Cavalier !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid))
575753c7e08SAugustin Cavalier fail |= 0x10;
576753c7e08SAugustin Cavalier if ((vap->iv_flags & IEEE80211_F_DESBSSID) &&
577753c7e08SAugustin Cavalier !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid))
578753c7e08SAugustin Cavalier fail |= 0x20;
579753c7e08SAugustin Cavalier
580753c7e08SAugustin Cavalier printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr));
581753c7e08SAugustin Cavalier printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' ');
582753c7e08SAugustin Cavalier printf(" %3d%c",
583753c7e08SAugustin Cavalier ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' ');
584753c7e08SAugustin Cavalier printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
585753c7e08SAugustin Cavalier fail & 0x08 ? '!' : ' ');
586753c7e08SAugustin Cavalier printf(" %4s%c",
587753c7e08SAugustin Cavalier (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
588753c7e08SAugustin Cavalier (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
589753c7e08SAugustin Cavalier "????",
590753c7e08SAugustin Cavalier fail & 0x02 ? '!' : ' ');
591753c7e08SAugustin Cavalier printf(" %3s%c ",
592753c7e08SAugustin Cavalier (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : "no",
593753c7e08SAugustin Cavalier fail & 0x04 ? '!' : ' ');
594753c7e08SAugustin Cavalier ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
595753c7e08SAugustin Cavalier printf("%s\n", fail & 0x10 ? "!" : "");
596753c7e08SAugustin Cavalier }
597753c7e08SAugustin Cavalier #endif /* IEEE80211_DEBUG */
598753c7e08SAugustin Cavalier
599753c7e08SAugustin Cavalier int
ieee80211_ibss_merge_check(struct ieee80211_node * ni)600753c7e08SAugustin Cavalier ieee80211_ibss_merge_check(struct ieee80211_node *ni)
601753c7e08SAugustin Cavalier {
602753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
603753c7e08SAugustin Cavalier
604753c7e08SAugustin Cavalier if (ni == vap->iv_bss ||
605753c7e08SAugustin Cavalier IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) {
606753c7e08SAugustin Cavalier /* unchanged, nothing to do */
607753c7e08SAugustin Cavalier return 0;
608753c7e08SAugustin Cavalier }
609753c7e08SAugustin Cavalier
610753c7e08SAugustin Cavalier if (!check_bss(vap, ni)) {
611753c7e08SAugustin Cavalier /* capabilities mismatch */
612753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
613753c7e08SAugustin Cavalier "%s: merge failed, capabilities mismatch\n", __func__);
614753c7e08SAugustin Cavalier #ifdef IEEE80211_DEBUG
615753c7e08SAugustin Cavalier if (ieee80211_msg_assoc(vap))
616753c7e08SAugustin Cavalier check_bss_debug(vap, ni);
617753c7e08SAugustin Cavalier #endif
618753c7e08SAugustin Cavalier vap->iv_stats.is_ibss_capmismatch++;
619753c7e08SAugustin Cavalier return 0;
620753c7e08SAugustin Cavalier }
621753c7e08SAugustin Cavalier
622753c7e08SAugustin Cavalier return 1;
623753c7e08SAugustin Cavalier }
624753c7e08SAugustin Cavalier
625753c7e08SAugustin Cavalier /*
6268244a9baSAugustin Cavalier * Check if the given node should populate the node table.
6278244a9baSAugustin Cavalier *
6288244a9baSAugustin Cavalier * We need to be in "see all beacons for all ssids" mode in order
6298244a9baSAugustin Cavalier * to do IBSS merges, however this means we will populate nodes for
6308244a9baSAugustin Cavalier * /all/ IBSS SSIDs, versus just the one we care about.
6318244a9baSAugustin Cavalier *
6328244a9baSAugustin Cavalier * So this check ensures the node can actually belong to our IBSS
6338244a9baSAugustin Cavalier * configuration. For now it simply checks the SSID.
6348244a9baSAugustin Cavalier */
6358244a9baSAugustin Cavalier int
ieee80211_ibss_node_check_new(struct ieee80211_node * ni,const struct ieee80211_scanparams * scan)6368244a9baSAugustin Cavalier ieee80211_ibss_node_check_new(struct ieee80211_node *ni,
6378244a9baSAugustin Cavalier const struct ieee80211_scanparams *scan)
6388244a9baSAugustin Cavalier {
6398244a9baSAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
6408244a9baSAugustin Cavalier int i;
6418244a9baSAugustin Cavalier
6428244a9baSAugustin Cavalier /*
6438244a9baSAugustin Cavalier * If we have no SSID and no scan SSID, return OK.
6448244a9baSAugustin Cavalier */
6458244a9baSAugustin Cavalier if (vap->iv_des_nssid == 0 && scan->ssid == NULL)
6468244a9baSAugustin Cavalier goto ok;
6478244a9baSAugustin Cavalier
6488244a9baSAugustin Cavalier /*
6498244a9baSAugustin Cavalier * If we have one of (SSID, scan SSID) then return error.
6508244a9baSAugustin Cavalier */
6518244a9baSAugustin Cavalier if (!! (vap->iv_des_nssid == 0) != !! (scan->ssid == NULL))
6528244a9baSAugustin Cavalier goto mismatch;
6538244a9baSAugustin Cavalier
6548244a9baSAugustin Cavalier /*
6558244a9baSAugustin Cavalier * Double-check - we need scan SSID.
6568244a9baSAugustin Cavalier */
6578244a9baSAugustin Cavalier if (scan->ssid == NULL)
6588244a9baSAugustin Cavalier goto mismatch;
6598244a9baSAugustin Cavalier
6608244a9baSAugustin Cavalier /*
6618244a9baSAugustin Cavalier * Check if the scan SSID matches the SSID list for the VAP.
6628244a9baSAugustin Cavalier */
6638244a9baSAugustin Cavalier for (i = 0; i < vap->iv_des_nssid; i++) {
6648244a9baSAugustin Cavalier /* Sanity length check */
6658244a9baSAugustin Cavalier if (vap->iv_des_ssid[i].len != scan->ssid[1])
6668244a9baSAugustin Cavalier continue;
6678244a9baSAugustin Cavalier
6688244a9baSAugustin Cavalier /* Note: SSID in the scan entry is the IE format */
6698244a9baSAugustin Cavalier if (memcmp(vap->iv_des_ssid[i].ssid, scan->ssid + 2,
6708244a9baSAugustin Cavalier vap->iv_des_ssid[i].len) == 0)
6718244a9baSAugustin Cavalier goto ok;
6728244a9baSAugustin Cavalier }
6738244a9baSAugustin Cavalier
6748244a9baSAugustin Cavalier mismatch:
6758244a9baSAugustin Cavalier return (0);
6768244a9baSAugustin Cavalier ok:
6778244a9baSAugustin Cavalier return (1);
6788244a9baSAugustin Cavalier }
6798244a9baSAugustin Cavalier
6808244a9baSAugustin Cavalier /*
681753c7e08SAugustin Cavalier * Handle 802.11 ad hoc network merge. The
682753c7e08SAugustin Cavalier * convention, set by the Wireless Ethernet Compatibility Alliance
683753c7e08SAugustin Cavalier * (WECA), is that an 802.11 station will change its BSSID to match
684753c7e08SAugustin Cavalier * the "oldest" 802.11 ad hoc network, on the same channel, that
685753c7e08SAugustin Cavalier * has the station's desired SSID. The "oldest" 802.11 network
686753c7e08SAugustin Cavalier * sends beacons with the greatest TSF timestamp.
687753c7e08SAugustin Cavalier *
688753c7e08SAugustin Cavalier * The caller is assumed to validate TSF's before attempting a merge.
689753c7e08SAugustin Cavalier *
690753c7e08SAugustin Cavalier * Return !0 if the BSSID changed, 0 otherwise.
691753c7e08SAugustin Cavalier */
692753c7e08SAugustin Cavalier int
ieee80211_ibss_merge(struct ieee80211_node * ni)693753c7e08SAugustin Cavalier ieee80211_ibss_merge(struct ieee80211_node *ni)
694753c7e08SAugustin Cavalier {
695753c7e08SAugustin Cavalier #ifdef IEEE80211_DEBUG
696753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
697753c7e08SAugustin Cavalier #endif
698753c7e08SAugustin Cavalier
699753c7e08SAugustin Cavalier if (! ieee80211_ibss_merge_check(ni))
700753c7e08SAugustin Cavalier return 0;
701753c7e08SAugustin Cavalier
702753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
703753c7e08SAugustin Cavalier "%s: new bssid %s: %s preamble, %s slot time%s\n", __func__,
704753c7e08SAugustin Cavalier ether_sprintf(ni->ni_bssid),
7055cad57c4SJérôme Duval vap->iv_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
7065cad57c4SJérôme Duval vap->iv_flags&IEEE80211_F_SHSLOT ? "short" : "long",
7075cad57c4SJérôme Duval vap->iv_flags&IEEE80211_F_USEPROT ? ", protection" : ""
708753c7e08SAugustin Cavalier );
709753c7e08SAugustin Cavalier return ieee80211_sta_join1(ieee80211_ref_node(ni));
710753c7e08SAugustin Cavalier }
711753c7e08SAugustin Cavalier
712753c7e08SAugustin Cavalier /*
713753c7e08SAugustin Cavalier * Calculate HT channel promotion flags for all vaps.
714753c7e08SAugustin Cavalier * This assumes ni_chan have been setup for each vap.
715753c7e08SAugustin Cavalier */
716753c7e08SAugustin Cavalier static int
gethtadjustflags(struct ieee80211com * ic)717753c7e08SAugustin Cavalier gethtadjustflags(struct ieee80211com *ic)
718753c7e08SAugustin Cavalier {
719753c7e08SAugustin Cavalier struct ieee80211vap *vap;
720753c7e08SAugustin Cavalier int flags;
721753c7e08SAugustin Cavalier
722753c7e08SAugustin Cavalier flags = 0;
723753c7e08SAugustin Cavalier /* XXX locking */
724753c7e08SAugustin Cavalier TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
725753c7e08SAugustin Cavalier if (vap->iv_state < IEEE80211_S_RUN)
726753c7e08SAugustin Cavalier continue;
727753c7e08SAugustin Cavalier switch (vap->iv_opmode) {
728753c7e08SAugustin Cavalier case IEEE80211_M_WDS:
729753c7e08SAugustin Cavalier case IEEE80211_M_STA:
730753c7e08SAugustin Cavalier case IEEE80211_M_AHDEMO:
731753c7e08SAugustin Cavalier case IEEE80211_M_HOSTAP:
732753c7e08SAugustin Cavalier case IEEE80211_M_IBSS:
733753c7e08SAugustin Cavalier case IEEE80211_M_MBSS:
734753c7e08SAugustin Cavalier flags |= ieee80211_htchanflags(vap->iv_bss->ni_chan);
735753c7e08SAugustin Cavalier break;
736753c7e08SAugustin Cavalier default:
737753c7e08SAugustin Cavalier break;
738753c7e08SAugustin Cavalier }
739753c7e08SAugustin Cavalier }
740753c7e08SAugustin Cavalier return flags;
741753c7e08SAugustin Cavalier }
742753c7e08SAugustin Cavalier
743753c7e08SAugustin Cavalier /*
7448244a9baSAugustin Cavalier * Calculate VHT channel promotion flags for all vaps.
7458244a9baSAugustin Cavalier * This assumes ni_chan have been setup for each vap.
7468244a9baSAugustin Cavalier */
7478244a9baSAugustin Cavalier static int
getvhtadjustflags(struct ieee80211com * ic)7488244a9baSAugustin Cavalier getvhtadjustflags(struct ieee80211com *ic)
7498244a9baSAugustin Cavalier {
7508244a9baSAugustin Cavalier struct ieee80211vap *vap;
7518244a9baSAugustin Cavalier int flags;
7528244a9baSAugustin Cavalier
7538244a9baSAugustin Cavalier flags = 0;
7548244a9baSAugustin Cavalier /* XXX locking */
7558244a9baSAugustin Cavalier TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
7568244a9baSAugustin Cavalier if (vap->iv_state < IEEE80211_S_RUN)
7578244a9baSAugustin Cavalier continue;
7588244a9baSAugustin Cavalier switch (vap->iv_opmode) {
7598244a9baSAugustin Cavalier case IEEE80211_M_WDS:
7608244a9baSAugustin Cavalier case IEEE80211_M_STA:
7618244a9baSAugustin Cavalier case IEEE80211_M_AHDEMO:
7628244a9baSAugustin Cavalier case IEEE80211_M_HOSTAP:
7638244a9baSAugustin Cavalier case IEEE80211_M_IBSS:
7648244a9baSAugustin Cavalier case IEEE80211_M_MBSS:
7658244a9baSAugustin Cavalier flags |= ieee80211_vhtchanflags(vap->iv_bss->ni_chan);
7668244a9baSAugustin Cavalier break;
7678244a9baSAugustin Cavalier default:
7688244a9baSAugustin Cavalier break;
7698244a9baSAugustin Cavalier }
7708244a9baSAugustin Cavalier }
7718244a9baSAugustin Cavalier return flags;
7728244a9baSAugustin Cavalier }
7738244a9baSAugustin Cavalier
7748244a9baSAugustin Cavalier /*
775753c7e08SAugustin Cavalier * Check if the current channel needs to change based on whether
776753c7e08SAugustin Cavalier * any vap's are using HT20/HT40. This is used to sync the state
777753c7e08SAugustin Cavalier * of ic_curchan after a channel width change on a running vap.
7788244a9baSAugustin Cavalier *
7798244a9baSAugustin Cavalier * Same applies for VHT.
780753c7e08SAugustin Cavalier */
781753c7e08SAugustin Cavalier void
ieee80211_sync_curchan(struct ieee80211com * ic)782753c7e08SAugustin Cavalier ieee80211_sync_curchan(struct ieee80211com *ic)
783753c7e08SAugustin Cavalier {
784753c7e08SAugustin Cavalier struct ieee80211_channel *c;
785753c7e08SAugustin Cavalier
786753c7e08SAugustin Cavalier c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, gethtadjustflags(ic));
7878244a9baSAugustin Cavalier c = ieee80211_vht_adjust_channel(ic, c, getvhtadjustflags(ic));
7888244a9baSAugustin Cavalier
789753c7e08SAugustin Cavalier if (c != ic->ic_curchan) {
790753c7e08SAugustin Cavalier ic->ic_curchan = c;
791753c7e08SAugustin Cavalier ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
792753c7e08SAugustin Cavalier ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
793753c7e08SAugustin Cavalier IEEE80211_UNLOCK(ic);
794753c7e08SAugustin Cavalier ic->ic_set_channel(ic);
795753c7e08SAugustin Cavalier ieee80211_radiotap_chan_change(ic);
796753c7e08SAugustin Cavalier IEEE80211_LOCK(ic);
797753c7e08SAugustin Cavalier }
798753c7e08SAugustin Cavalier }
799753c7e08SAugustin Cavalier
800753c7e08SAugustin Cavalier /*
801753c7e08SAugustin Cavalier * Setup the current channel. The request channel may be
802753c7e08SAugustin Cavalier * promoted if other vap's are operating with HT20/HT40.
803753c7e08SAugustin Cavalier */
804753c7e08SAugustin Cavalier void
ieee80211_setupcurchan(struct ieee80211com * ic,struct ieee80211_channel * c)805753c7e08SAugustin Cavalier ieee80211_setupcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
806753c7e08SAugustin Cavalier {
807753c7e08SAugustin Cavalier if (ic->ic_htcaps & IEEE80211_HTC_HT) {
808753c7e08SAugustin Cavalier int flags = gethtadjustflags(ic);
809753c7e08SAugustin Cavalier /*
810753c7e08SAugustin Cavalier * Check for channel promotion required to support the
811753c7e08SAugustin Cavalier * set of running vap's. This assumes we are called
812753c7e08SAugustin Cavalier * after ni_chan is setup for each vap.
813753c7e08SAugustin Cavalier */
8148244a9baSAugustin Cavalier /* XXX VHT? */
815753c7e08SAugustin Cavalier /* NB: this assumes IEEE80211_FHT_USEHT40 > IEEE80211_FHT_HT */
816753c7e08SAugustin Cavalier if (flags > ieee80211_htchanflags(c))
817753c7e08SAugustin Cavalier c = ieee80211_ht_adjust_channel(ic, c, flags);
818753c7e08SAugustin Cavalier }
8198244a9baSAugustin Cavalier
8208244a9baSAugustin Cavalier /*
8218244a9baSAugustin Cavalier * VHT promotion - this will at least promote to VHT20/40
8228244a9baSAugustin Cavalier * based on what HT has done; it may further promote the
8238244a9baSAugustin Cavalier * channel to VHT80 or above.
8248244a9baSAugustin Cavalier */
825*86021fd4SAugustin Cavalier if (ic->ic_vht_cap.vht_cap_info != 0) {
8268244a9baSAugustin Cavalier int flags = getvhtadjustflags(ic);
8278244a9baSAugustin Cavalier if (flags > ieee80211_vhtchanflags(c))
8288244a9baSAugustin Cavalier c = ieee80211_vht_adjust_channel(ic, c, flags);
8298244a9baSAugustin Cavalier }
8308244a9baSAugustin Cavalier
831753c7e08SAugustin Cavalier ic->ic_bsschan = ic->ic_curchan = c;
832753c7e08SAugustin Cavalier ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
833753c7e08SAugustin Cavalier ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
834753c7e08SAugustin Cavalier }
835753c7e08SAugustin Cavalier
836753c7e08SAugustin Cavalier /*
837753c7e08SAugustin Cavalier * Change the current channel. The channel change is guaranteed to have
838753c7e08SAugustin Cavalier * happened before the next state change.
839753c7e08SAugustin Cavalier */
840753c7e08SAugustin Cavalier void
ieee80211_setcurchan(struct ieee80211com * ic,struct ieee80211_channel * c)841753c7e08SAugustin Cavalier ieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
842753c7e08SAugustin Cavalier {
843753c7e08SAugustin Cavalier ieee80211_setupcurchan(ic, c);
844753c7e08SAugustin Cavalier ieee80211_runtask(ic, &ic->ic_chan_task);
845753c7e08SAugustin Cavalier }
846753c7e08SAugustin Cavalier
847753c7e08SAugustin Cavalier void
ieee80211_update_chw(struct ieee80211com * ic)848753c7e08SAugustin Cavalier ieee80211_update_chw(struct ieee80211com *ic)
849753c7e08SAugustin Cavalier {
850753c7e08SAugustin Cavalier
851753c7e08SAugustin Cavalier ieee80211_setupcurchan(ic, ic->ic_curchan);
852753c7e08SAugustin Cavalier ieee80211_runtask(ic, &ic->ic_chw_task);
853753c7e08SAugustin Cavalier }
854753c7e08SAugustin Cavalier
855753c7e08SAugustin Cavalier /*
856753c7e08SAugustin Cavalier * Join the specified IBSS/BSS network. The node is assumed to
857753c7e08SAugustin Cavalier * be passed in with a held reference.
858753c7e08SAugustin Cavalier */
859753c7e08SAugustin Cavalier static int
ieee80211_sta_join1(struct ieee80211_node * selbs)860753c7e08SAugustin Cavalier ieee80211_sta_join1(struct ieee80211_node *selbs)
861753c7e08SAugustin Cavalier {
862753c7e08SAugustin Cavalier struct ieee80211vap *vap = selbs->ni_vap;
863753c7e08SAugustin Cavalier struct ieee80211com *ic = selbs->ni_ic;
864753c7e08SAugustin Cavalier struct ieee80211_node *obss;
865753c7e08SAugustin Cavalier int canreassoc;
866753c7e08SAugustin Cavalier
867753c7e08SAugustin Cavalier /*
868753c7e08SAugustin Cavalier * Committed to selbs, setup state.
869753c7e08SAugustin Cavalier */
870*86021fd4SAugustin Cavalier IEEE80211_LOCK(ic); /* XXX may recurse here, check callers. */
871*86021fd4SAugustin Cavalier obss = vap->iv_update_bss(vap, selbs); /* NB: caller assumed to bump refcnt */
872*86021fd4SAugustin Cavalier IEEE80211_UNLOCK(ic);
873753c7e08SAugustin Cavalier /*
874753c7e08SAugustin Cavalier * Check if old+new node have the same address in which
875753c7e08SAugustin Cavalier * case we can reassociate when operating in sta mode.
876753c7e08SAugustin Cavalier */
877*86021fd4SAugustin Cavalier /* XXX We'll not be in RUN anymore as iv_state got updated already? */
878753c7e08SAugustin Cavalier canreassoc = (obss != NULL &&
879753c7e08SAugustin Cavalier vap->iv_state == IEEE80211_S_RUN &&
880753c7e08SAugustin Cavalier IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr));
881753c7e08SAugustin Cavalier if (obss != NULL) {
882753c7e08SAugustin Cavalier struct ieee80211_node_table *nt = obss->ni_table;
883753c7e08SAugustin Cavalier
884753c7e08SAugustin Cavalier copy_bss(selbs, obss);
885*86021fd4SAugustin Cavalier if (nt != NULL) {
886753c7e08SAugustin Cavalier ieee80211_node_decref(obss); /* iv_bss reference */
887753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
888753c7e08SAugustin Cavalier node_reclaim(nt, obss); /* station table reference */
889753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
890*86021fd4SAugustin Cavalier } else {
891*86021fd4SAugustin Cavalier ieee80211_free_node(obss); /* iv_bss reference */
892*86021fd4SAugustin Cavalier }
893753c7e08SAugustin Cavalier
894753c7e08SAugustin Cavalier obss = NULL; /* NB: guard against later use */
895753c7e08SAugustin Cavalier }
896753c7e08SAugustin Cavalier
897753c7e08SAugustin Cavalier /*
898753c7e08SAugustin Cavalier * Delete unusable rates; we've already checked
899753c7e08SAugustin Cavalier * that the negotiated rate set is acceptable.
900753c7e08SAugustin Cavalier */
901753c7e08SAugustin Cavalier ieee80211_fix_rate(vap->iv_bss, &vap->iv_bss->ni_rates,
902753c7e08SAugustin Cavalier IEEE80211_F_DODEL | IEEE80211_F_JOIN);
903753c7e08SAugustin Cavalier
904753c7e08SAugustin Cavalier ieee80211_setcurchan(ic, selbs->ni_chan);
905753c7e08SAugustin Cavalier /*
906753c7e08SAugustin Cavalier * Set the erp state (mostly the slot time) to deal with
907753c7e08SAugustin Cavalier * the auto-select case; this should be redundant if the
908753c7e08SAugustin Cavalier * mode is locked.
909753c7e08SAugustin Cavalier */
9105cad57c4SJérôme Duval ieee80211_vap_reset_erp(vap);
911753c7e08SAugustin Cavalier ieee80211_wme_initparams(vap);
912753c7e08SAugustin Cavalier
913753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_STA) {
914753c7e08SAugustin Cavalier if (canreassoc) {
915753c7e08SAugustin Cavalier /* Reassociate */
916753c7e08SAugustin Cavalier ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1);
917753c7e08SAugustin Cavalier } else {
918753c7e08SAugustin Cavalier /*
919753c7e08SAugustin Cavalier * Act as if we received a DEAUTH frame in case we
920753c7e08SAugustin Cavalier * are invoked from the RUN state. This will cause
921753c7e08SAugustin Cavalier * us to try to re-authenticate if we are operating
922753c7e08SAugustin Cavalier * as a station.
923753c7e08SAugustin Cavalier */
924*86021fd4SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_AUTH,
925*86021fd4SAugustin Cavalier "%s %p<%s> %s -> AUTH, FC0_SUBTYPE_DEAUTH\n",
926*86021fd4SAugustin Cavalier __func__, selbs, ether_sprintf(selbs->ni_macaddr),
927*86021fd4SAugustin Cavalier ieee80211_state_name[vap->iv_state]);
928753c7e08SAugustin Cavalier ieee80211_new_state(vap, IEEE80211_S_AUTH,
929753c7e08SAugustin Cavalier IEEE80211_FC0_SUBTYPE_DEAUTH);
930753c7e08SAugustin Cavalier }
931753c7e08SAugustin Cavalier } else
932753c7e08SAugustin Cavalier ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
933753c7e08SAugustin Cavalier return 1;
934753c7e08SAugustin Cavalier }
935753c7e08SAugustin Cavalier
936753c7e08SAugustin Cavalier int
ieee80211_sta_join(struct ieee80211vap * vap,struct ieee80211_channel * chan,const struct ieee80211_scan_entry * se)937753c7e08SAugustin Cavalier ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
938753c7e08SAugustin Cavalier const struct ieee80211_scan_entry *se)
939753c7e08SAugustin Cavalier {
940753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
941753c7e08SAugustin Cavalier struct ieee80211_node *ni;
9428244a9baSAugustin Cavalier int do_ht = 0;
943753c7e08SAugustin Cavalier
944*86021fd4SAugustin Cavalier ni = ieee80211_alloc_node(&ic->ic_sta, vap, se->se_macaddr,
945*86021fd4SAugustin Cavalier __func__, __LINE__);
946753c7e08SAugustin Cavalier if (ni == NULL) {
947753c7e08SAugustin Cavalier /* XXX msg */
948753c7e08SAugustin Cavalier return 0;
949753c7e08SAugustin Cavalier }
950753c7e08SAugustin Cavalier
951753c7e08SAugustin Cavalier /*
952753c7e08SAugustin Cavalier * Expand scan state into node's format.
953753c7e08SAugustin Cavalier * XXX may not need all this stuff
954753c7e08SAugustin Cavalier */
955753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid);
956753c7e08SAugustin Cavalier ni->ni_esslen = se->se_ssid[1];
957753c7e08SAugustin Cavalier memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen);
958753c7e08SAugustin Cavalier ni->ni_tstamp.tsf = se->se_tstamp.tsf;
959753c7e08SAugustin Cavalier ni->ni_intval = se->se_intval;
960753c7e08SAugustin Cavalier ni->ni_capinfo = se->se_capinfo;
961753c7e08SAugustin Cavalier ni->ni_chan = chan;
962753c7e08SAugustin Cavalier ni->ni_timoff = se->se_timoff;
963753c7e08SAugustin Cavalier ni->ni_fhdwell = se->se_fhdwell;
964753c7e08SAugustin Cavalier ni->ni_fhindex = se->se_fhindex;
965753c7e08SAugustin Cavalier ni->ni_erp = se->se_erp;
966753c7e08SAugustin Cavalier IEEE80211_RSSI_LPF(ni->ni_avgrssi, se->se_rssi);
967753c7e08SAugustin Cavalier ni->ni_noise = se->se_noise;
968753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_STA) {
969753c7e08SAugustin Cavalier /* NB: only infrastructure mode requires an associd */
970753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_ASSOCID;
971753c7e08SAugustin Cavalier }
972753c7e08SAugustin Cavalier
973753c7e08SAugustin Cavalier if (ieee80211_ies_init(&ni->ni_ies, se->se_ies.data, se->se_ies.len)) {
974753c7e08SAugustin Cavalier ieee80211_ies_expand(&ni->ni_ies);
975753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_SUPERG
976753c7e08SAugustin Cavalier if (ni->ni_ies.ath_ie != NULL)
977753c7e08SAugustin Cavalier ieee80211_parse_ath(ni, ni->ni_ies.ath_ie);
978753c7e08SAugustin Cavalier #endif
979753c7e08SAugustin Cavalier if (ni->ni_ies.htcap_ie != NULL)
980753c7e08SAugustin Cavalier ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
981753c7e08SAugustin Cavalier if (ni->ni_ies.htinfo_ie != NULL)
982753c7e08SAugustin Cavalier ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
983753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_MESH
984753c7e08SAugustin Cavalier if (ni->ni_ies.meshid_ie != NULL)
985753c7e08SAugustin Cavalier ieee80211_parse_meshid(ni, ni->ni_ies.meshid_ie);
986753c7e08SAugustin Cavalier #endif
987753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_TDMA
988753c7e08SAugustin Cavalier if (ni->ni_ies.tdma_ie != NULL)
989753c7e08SAugustin Cavalier ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie);
990753c7e08SAugustin Cavalier #endif
9918244a9baSAugustin Cavalier if (ni->ni_ies.vhtcap_ie != NULL)
9928244a9baSAugustin Cavalier ieee80211_parse_vhtcap(ni, ni->ni_ies.vhtcap_ie);
9938244a9baSAugustin Cavalier if (ni->ni_ies.vhtopmode_ie != NULL)
9948244a9baSAugustin Cavalier ieee80211_parse_vhtopmode(ni, ni->ni_ies.vhtopmode_ie);
9958244a9baSAugustin Cavalier
9968244a9baSAugustin Cavalier /* XXX parse BSSLOAD IE */
9978244a9baSAugustin Cavalier /* XXX parse TXPWRENV IE */
9988244a9baSAugustin Cavalier /* XXX parse APCHANREP IE */
999753c7e08SAugustin Cavalier }
1000753c7e08SAugustin Cavalier
1001753c7e08SAugustin Cavalier vap->iv_dtim_period = se->se_dtimperiod;
1002753c7e08SAugustin Cavalier vap->iv_dtim_count = 0;
1003753c7e08SAugustin Cavalier
1004753c7e08SAugustin Cavalier /* NB: must be after ni_chan is setup */
1005753c7e08SAugustin Cavalier ieee80211_setup_rates(ni, se->se_rates, se->se_xrates,
1006753c7e08SAugustin Cavalier IEEE80211_F_DOSORT);
1007753c7e08SAugustin Cavalier if (ieee80211_iserp_rateset(&ni->ni_rates))
1008753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_ERP;
1009753c7e08SAugustin Cavalier
1010753c7e08SAugustin Cavalier /*
1011753c7e08SAugustin Cavalier * Setup HT state for this node if it's available, otherwise
1012753c7e08SAugustin Cavalier * non-STA modes won't pick this state up.
1013753c7e08SAugustin Cavalier *
1014753c7e08SAugustin Cavalier * For IBSS and related modes that don't go through an
1015753c7e08SAugustin Cavalier * association request/response, the only appropriate place
1016753c7e08SAugustin Cavalier * to setup the HT state is here.
1017753c7e08SAugustin Cavalier */
1018753c7e08SAugustin Cavalier if (ni->ni_ies.htinfo_ie != NULL &&
1019753c7e08SAugustin Cavalier ni->ni_ies.htcap_ie != NULL &&
1020753c7e08SAugustin Cavalier vap->iv_flags_ht & IEEE80211_FHT_HT) {
1021753c7e08SAugustin Cavalier ieee80211_ht_node_init(ni);
1022753c7e08SAugustin Cavalier ieee80211_ht_updateparams(ni,
1023753c7e08SAugustin Cavalier ni->ni_ies.htcap_ie,
1024753c7e08SAugustin Cavalier ni->ni_ies.htinfo_ie);
10258244a9baSAugustin Cavalier do_ht = 1;
10268244a9baSAugustin Cavalier }
10278244a9baSAugustin Cavalier
10288244a9baSAugustin Cavalier /*
10298244a9baSAugustin Cavalier * Setup VHT state for this node if it's available.
10308244a9baSAugustin Cavalier * Same as the above.
10318244a9baSAugustin Cavalier *
10328244a9baSAugustin Cavalier * For now, don't allow 2GHz VHT operation.
10338244a9baSAugustin Cavalier */
10348244a9baSAugustin Cavalier if (ni->ni_ies.vhtopmode_ie != NULL &&
10358244a9baSAugustin Cavalier ni->ni_ies.vhtcap_ie != NULL &&
1036*86021fd4SAugustin Cavalier vap->iv_vht_flags & IEEE80211_FVHT_VHT) {
10378244a9baSAugustin Cavalier if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
10388244a9baSAugustin Cavalier printf("%s: BSS %6D: 2GHz channel, VHT info; ignoring\n",
10398244a9baSAugustin Cavalier __func__,
10408244a9baSAugustin Cavalier ni->ni_macaddr,
10418244a9baSAugustin Cavalier ":");
10428244a9baSAugustin Cavalier } else {
10438244a9baSAugustin Cavalier ieee80211_vht_node_init(ni);
10448244a9baSAugustin Cavalier ieee80211_vht_updateparams(ni,
10458244a9baSAugustin Cavalier ni->ni_ies.vhtcap_ie,
10468244a9baSAugustin Cavalier ni->ni_ies.vhtopmode_ie);
10478244a9baSAugustin Cavalier ieee80211_setup_vht_rates(ni, ni->ni_ies.vhtcap_ie,
10488244a9baSAugustin Cavalier ni->ni_ies.vhtopmode_ie);
10498244a9baSAugustin Cavalier do_ht = 1;
10508244a9baSAugustin Cavalier }
10518244a9baSAugustin Cavalier }
10528244a9baSAugustin Cavalier
10538244a9baSAugustin Cavalier /* Finally do the node channel change */
10548244a9baSAugustin Cavalier if (do_ht) {
10558244a9baSAugustin Cavalier ieee80211_ht_updateparams_final(ni, ni->ni_ies.htcap_ie,
10568244a9baSAugustin Cavalier ni->ni_ies.htinfo_ie);
1057753c7e08SAugustin Cavalier ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie,
1058753c7e08SAugustin Cavalier IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
1059753c7e08SAugustin Cavalier ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie);
1060753c7e08SAugustin Cavalier }
10618244a9baSAugustin Cavalier
1062753c7e08SAugustin Cavalier /* XXX else check for ath FF? */
1063753c7e08SAugustin Cavalier /* XXX QoS? Difficult given that WME config is specific to a master */
1064753c7e08SAugustin Cavalier
1065753c7e08SAugustin Cavalier ieee80211_node_setuptxparms(ni);
1066753c7e08SAugustin Cavalier ieee80211_ratectl_node_init(ni);
1067753c7e08SAugustin Cavalier
1068753c7e08SAugustin Cavalier return ieee80211_sta_join1(ieee80211_ref_node(ni));
1069753c7e08SAugustin Cavalier }
1070753c7e08SAugustin Cavalier
1071753c7e08SAugustin Cavalier /*
1072753c7e08SAugustin Cavalier * Leave the specified IBSS/BSS network. The node is assumed to
1073753c7e08SAugustin Cavalier * be passed in with a held reference.
1074753c7e08SAugustin Cavalier */
1075753c7e08SAugustin Cavalier void
ieee80211_sta_leave(struct ieee80211_node * ni)1076753c7e08SAugustin Cavalier ieee80211_sta_leave(struct ieee80211_node *ni)
1077753c7e08SAugustin Cavalier {
1078753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
1079753c7e08SAugustin Cavalier
1080753c7e08SAugustin Cavalier ic->ic_node_cleanup(ni);
1081753c7e08SAugustin Cavalier ieee80211_notify_node_leave(ni);
1082753c7e08SAugustin Cavalier }
1083753c7e08SAugustin Cavalier
1084753c7e08SAugustin Cavalier /*
1085753c7e08SAugustin Cavalier * Send a deauthenticate frame and drop the station.
1086753c7e08SAugustin Cavalier */
1087753c7e08SAugustin Cavalier void
ieee80211_node_deauth(struct ieee80211_node * ni,int reason)1088753c7e08SAugustin Cavalier ieee80211_node_deauth(struct ieee80211_node *ni, int reason)
1089753c7e08SAugustin Cavalier {
1090753c7e08SAugustin Cavalier /* NB: bump the refcnt to be sure temporary nodes are not reclaimed */
1091753c7e08SAugustin Cavalier ieee80211_ref_node(ni);
1092753c7e08SAugustin Cavalier if (ni->ni_associd != 0)
1093753c7e08SAugustin Cavalier IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
1094753c7e08SAugustin Cavalier ieee80211_node_leave(ni);
1095753c7e08SAugustin Cavalier ieee80211_free_node(ni);
1096753c7e08SAugustin Cavalier }
1097753c7e08SAugustin Cavalier
1098753c7e08SAugustin Cavalier static struct ieee80211_node *
node_alloc(struct ieee80211vap * vap,const uint8_t macaddr[IEEE80211_ADDR_LEN])1099753c7e08SAugustin Cavalier node_alloc(struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN])
1100753c7e08SAugustin Cavalier {
1101753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1102753c7e08SAugustin Cavalier
1103753c7e08SAugustin Cavalier ni = (struct ieee80211_node *) IEEE80211_MALLOC(sizeof(struct ieee80211_node),
1104753c7e08SAugustin Cavalier M_80211_NODE, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1105753c7e08SAugustin Cavalier return ni;
1106753c7e08SAugustin Cavalier }
1107753c7e08SAugustin Cavalier
11085cad57c4SJérôme Duval static int
node_init(struct ieee80211_node * ni)11095cad57c4SJérôme Duval node_init(struct ieee80211_node *ni)
11105cad57c4SJérôme Duval {
11115cad57c4SJérôme Duval return 0;
11125cad57c4SJérôme Duval }
11135cad57c4SJérôme Duval
1114753c7e08SAugustin Cavalier /*
1115753c7e08SAugustin Cavalier * Initialize an ie blob with the specified data. If previous
1116753c7e08SAugustin Cavalier * data exists re-use the data block. As a side effect we clear
1117753c7e08SAugustin Cavalier * all references to specific ie's; the caller is required to
1118753c7e08SAugustin Cavalier * recalculate them.
1119753c7e08SAugustin Cavalier */
1120753c7e08SAugustin Cavalier int
ieee80211_ies_init(struct ieee80211_ies * ies,const uint8_t * data,int len)1121753c7e08SAugustin Cavalier ieee80211_ies_init(struct ieee80211_ies *ies, const uint8_t *data, int len)
1122753c7e08SAugustin Cavalier {
1123753c7e08SAugustin Cavalier /* NB: assumes data+len are the last fields */
1124753c7e08SAugustin Cavalier memset(ies, 0, offsetof(struct ieee80211_ies, data));
1125753c7e08SAugustin Cavalier if (ies->data != NULL && ies->len != len) {
1126753c7e08SAugustin Cavalier /* data size changed */
1127753c7e08SAugustin Cavalier IEEE80211_FREE(ies->data, M_80211_NODE_IE);
1128753c7e08SAugustin Cavalier ies->data = NULL;
1129753c7e08SAugustin Cavalier }
1130753c7e08SAugustin Cavalier if (ies->data == NULL) {
1131753c7e08SAugustin Cavalier ies->data = (uint8_t *) IEEE80211_MALLOC(len, M_80211_NODE_IE,
1132753c7e08SAugustin Cavalier IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1133753c7e08SAugustin Cavalier if (ies->data == NULL) {
1134753c7e08SAugustin Cavalier ies->len = 0;
1135753c7e08SAugustin Cavalier /* NB: pointers have already been zero'd above */
1136753c7e08SAugustin Cavalier return 0;
1137753c7e08SAugustin Cavalier }
1138753c7e08SAugustin Cavalier }
1139753c7e08SAugustin Cavalier memcpy(ies->data, data, len);
1140753c7e08SAugustin Cavalier ies->len = len;
1141753c7e08SAugustin Cavalier return 1;
1142753c7e08SAugustin Cavalier }
1143753c7e08SAugustin Cavalier
1144753c7e08SAugustin Cavalier /*
1145753c7e08SAugustin Cavalier * Reclaim storage for an ie blob.
1146753c7e08SAugustin Cavalier */
1147753c7e08SAugustin Cavalier void
ieee80211_ies_cleanup(struct ieee80211_ies * ies)1148753c7e08SAugustin Cavalier ieee80211_ies_cleanup(struct ieee80211_ies *ies)
1149753c7e08SAugustin Cavalier {
1150753c7e08SAugustin Cavalier if (ies->data != NULL)
1151753c7e08SAugustin Cavalier IEEE80211_FREE(ies->data, M_80211_NODE_IE);
1152753c7e08SAugustin Cavalier }
1153753c7e08SAugustin Cavalier
1154753c7e08SAugustin Cavalier /*
1155753c7e08SAugustin Cavalier * Expand an ie blob data contents and to fillin individual
1156753c7e08SAugustin Cavalier * ie pointers. The data blob is assumed to be well-formed;
1157753c7e08SAugustin Cavalier * we don't do any validity checking of ie lengths.
1158753c7e08SAugustin Cavalier */
1159753c7e08SAugustin Cavalier void
ieee80211_ies_expand(struct ieee80211_ies * ies)1160753c7e08SAugustin Cavalier ieee80211_ies_expand(struct ieee80211_ies *ies)
1161753c7e08SAugustin Cavalier {
1162753c7e08SAugustin Cavalier uint8_t *ie;
1163753c7e08SAugustin Cavalier int ielen;
1164753c7e08SAugustin Cavalier
1165753c7e08SAugustin Cavalier ie = ies->data;
1166753c7e08SAugustin Cavalier ielen = ies->len;
1167*86021fd4SAugustin Cavalier while (ielen > 1) {
1168*86021fd4SAugustin Cavalier /* Make sure the given IE length fits into the total length. */
1169*86021fd4SAugustin Cavalier if ((2 + ie[1]) > ielen) {
1170*86021fd4SAugustin Cavalier printf("%s: malformed IEs! ies %p { data %p len %d }: "
1171*86021fd4SAugustin Cavalier "ie %u len 2+%u > total len left %d\n",
1172*86021fd4SAugustin Cavalier __func__, ies, ies->data, ies->len,
1173*86021fd4SAugustin Cavalier ie[0], ie[1], ielen);
1174*86021fd4SAugustin Cavalier return;
1175*86021fd4SAugustin Cavalier }
1176753c7e08SAugustin Cavalier switch (ie[0]) {
1177753c7e08SAugustin Cavalier case IEEE80211_ELEMID_VENDOR:
1178753c7e08SAugustin Cavalier if (iswpaoui(ie))
1179753c7e08SAugustin Cavalier ies->wpa_ie = ie;
1180753c7e08SAugustin Cavalier else if (iswmeoui(ie))
1181753c7e08SAugustin Cavalier ies->wme_ie = ie;
1182753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_SUPERG
1183753c7e08SAugustin Cavalier else if (isatherosoui(ie))
1184753c7e08SAugustin Cavalier ies->ath_ie = ie;
1185753c7e08SAugustin Cavalier #endif
1186753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_TDMA
1187753c7e08SAugustin Cavalier else if (istdmaoui(ie))
1188753c7e08SAugustin Cavalier ies->tdma_ie = ie;
1189753c7e08SAugustin Cavalier #endif
1190753c7e08SAugustin Cavalier break;
1191753c7e08SAugustin Cavalier case IEEE80211_ELEMID_RSN:
1192753c7e08SAugustin Cavalier ies->rsn_ie = ie;
1193753c7e08SAugustin Cavalier break;
1194753c7e08SAugustin Cavalier case IEEE80211_ELEMID_HTCAP:
1195753c7e08SAugustin Cavalier ies->htcap_ie = ie;
1196753c7e08SAugustin Cavalier break;
1197753c7e08SAugustin Cavalier case IEEE80211_ELEMID_HTINFO:
1198753c7e08SAugustin Cavalier ies->htinfo_ie = ie;
1199753c7e08SAugustin Cavalier break;
1200753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_MESH
1201753c7e08SAugustin Cavalier case IEEE80211_ELEMID_MESHID:
1202753c7e08SAugustin Cavalier ies->meshid_ie = ie;
1203753c7e08SAugustin Cavalier break;
1204753c7e08SAugustin Cavalier #endif
12058244a9baSAugustin Cavalier case IEEE80211_ELEMID_VHT_CAP:
12068244a9baSAugustin Cavalier ies->vhtcap_ie = ie;
12078244a9baSAugustin Cavalier break;
12088244a9baSAugustin Cavalier case IEEE80211_ELEMID_VHT_OPMODE:
12098244a9baSAugustin Cavalier ies->vhtopmode_ie = ie;
12108244a9baSAugustin Cavalier break;
12118244a9baSAugustin Cavalier case IEEE80211_ELEMID_VHT_PWR_ENV:
12128244a9baSAugustin Cavalier ies->vhtpwrenv_ie = ie;
12138244a9baSAugustin Cavalier break;
12148244a9baSAugustin Cavalier case IEEE80211_ELEMID_BSSLOAD:
12158244a9baSAugustin Cavalier ies->bssload_ie = ie;
12168244a9baSAugustin Cavalier break;
12178244a9baSAugustin Cavalier case IEEE80211_ELEMID_APCHANREP:
12188244a9baSAugustin Cavalier ies->apchanrep_ie = ie;
12198244a9baSAugustin Cavalier break;
1220753c7e08SAugustin Cavalier }
1221753c7e08SAugustin Cavalier ielen -= 2 + ie[1];
1222753c7e08SAugustin Cavalier ie += 2 + ie[1];
1223753c7e08SAugustin Cavalier }
1224753c7e08SAugustin Cavalier }
1225753c7e08SAugustin Cavalier
1226753c7e08SAugustin Cavalier /*
1227753c7e08SAugustin Cavalier * Reclaim any resources in a node and reset any critical
1228753c7e08SAugustin Cavalier * state. Typically nodes are free'd immediately after,
1229753c7e08SAugustin Cavalier * but in some cases the storage may be reused so we need
1230753c7e08SAugustin Cavalier * to insure consistent state (should probably fix that).
1231753c7e08SAugustin Cavalier */
1232753c7e08SAugustin Cavalier static void
node_cleanup(struct ieee80211_node * ni)1233753c7e08SAugustin Cavalier node_cleanup(struct ieee80211_node *ni)
1234753c7e08SAugustin Cavalier {
1235753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
1236753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
1237753c7e08SAugustin Cavalier int i;
1238753c7e08SAugustin Cavalier
1239753c7e08SAugustin Cavalier /* NB: preserve ni_table */
1240753c7e08SAugustin Cavalier if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) {
1241753c7e08SAugustin Cavalier if (vap->iv_opmode != IEEE80211_M_STA)
1242753c7e08SAugustin Cavalier vap->iv_ps_sta--;
1243753c7e08SAugustin Cavalier ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT;
1244753c7e08SAugustin Cavalier IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
1245753c7e08SAugustin Cavalier "power save mode off, %u sta's in ps mode", vap->iv_ps_sta);
1246753c7e08SAugustin Cavalier }
1247753c7e08SAugustin Cavalier /*
12488244a9baSAugustin Cavalier * Cleanup any VHT and HT-related state.
1249753c7e08SAugustin Cavalier */
12508244a9baSAugustin Cavalier if (ni->ni_flags & IEEE80211_NODE_VHT)
12518244a9baSAugustin Cavalier ieee80211_vht_node_cleanup(ni);
1252753c7e08SAugustin Cavalier if (ni->ni_flags & IEEE80211_NODE_HT)
1253753c7e08SAugustin Cavalier ieee80211_ht_node_cleanup(ni);
1254753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_SUPERG
1255753c7e08SAugustin Cavalier /* Always do FF node cleanup; for A-MSDU */
1256753c7e08SAugustin Cavalier ieee80211_ff_node_cleanup(ni);
1257753c7e08SAugustin Cavalier #endif
1258753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_MESH
1259753c7e08SAugustin Cavalier /*
1260753c7e08SAugustin Cavalier * Cleanup any mesh-related state.
1261753c7e08SAugustin Cavalier */
1262753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_MBSS)
1263753c7e08SAugustin Cavalier ieee80211_mesh_node_cleanup(ni);
1264753c7e08SAugustin Cavalier #endif
1265753c7e08SAugustin Cavalier /*
1266753c7e08SAugustin Cavalier * Clear any staging queue entries.
1267753c7e08SAugustin Cavalier */
1268753c7e08SAugustin Cavalier ieee80211_ageq_drain_node(&ic->ic_stageq, ni);
1269753c7e08SAugustin Cavalier
1270753c7e08SAugustin Cavalier /*
1271753c7e08SAugustin Cavalier * Clear AREF flag that marks the authorization refcnt bump
1272753c7e08SAugustin Cavalier * has happened. This is probably not needed as the node
1273753c7e08SAugustin Cavalier * should always be removed from the table so not found but
1274753c7e08SAugustin Cavalier * do it just in case.
1275753c7e08SAugustin Cavalier * Likewise clear the ASSOCID flag as these flags are intended
1276753c7e08SAugustin Cavalier * to be managed in tandem.
1277753c7e08SAugustin Cavalier */
1278753c7e08SAugustin Cavalier ni->ni_flags &= ~(IEEE80211_NODE_AREF | IEEE80211_NODE_ASSOCID);
1279753c7e08SAugustin Cavalier
1280753c7e08SAugustin Cavalier /*
1281753c7e08SAugustin Cavalier * Drain power save queue and, if needed, clear TIM.
1282753c7e08SAugustin Cavalier */
1283753c7e08SAugustin Cavalier if (ieee80211_node_psq_drain(ni) != 0 && vap->iv_set_tim != NULL)
1284753c7e08SAugustin Cavalier vap->iv_set_tim(ni, 0);
1285753c7e08SAugustin Cavalier
1286753c7e08SAugustin Cavalier ni->ni_associd = 0;
1287753c7e08SAugustin Cavalier if (ni->ni_challenge != NULL) {
1288753c7e08SAugustin Cavalier IEEE80211_FREE(ni->ni_challenge, M_80211_NODE);
1289753c7e08SAugustin Cavalier ni->ni_challenge = NULL;
1290753c7e08SAugustin Cavalier }
1291753c7e08SAugustin Cavalier /*
1292753c7e08SAugustin Cavalier * Preserve SSID, WPA, and WME ie's so the bss node is
1293753c7e08SAugustin Cavalier * reusable during a re-auth/re-assoc state transition.
1294753c7e08SAugustin Cavalier * If we remove these data they will not be recreated
1295753c7e08SAugustin Cavalier * because they come from a probe-response or beacon frame
1296753c7e08SAugustin Cavalier * which cannot be expected prior to the association-response.
1297753c7e08SAugustin Cavalier * This should not be an issue when operating in other modes
1298753c7e08SAugustin Cavalier * as stations leaving always go through a full state transition
1299753c7e08SAugustin Cavalier * which will rebuild this state.
1300753c7e08SAugustin Cavalier *
1301753c7e08SAugustin Cavalier * XXX does this leave us open to inheriting old state?
1302753c7e08SAugustin Cavalier */
1303753c7e08SAugustin Cavalier for (i = 0; i < nitems(ni->ni_rxfrag); i++)
1304753c7e08SAugustin Cavalier if (ni->ni_rxfrag[i] != NULL) {
1305753c7e08SAugustin Cavalier m_freem(ni->ni_rxfrag[i]);
1306753c7e08SAugustin Cavalier ni->ni_rxfrag[i] = NULL;
1307753c7e08SAugustin Cavalier }
1308753c7e08SAugustin Cavalier /*
1309753c7e08SAugustin Cavalier * Must be careful here to remove any key map entry w/o a LOR.
1310753c7e08SAugustin Cavalier */
1311753c7e08SAugustin Cavalier ieee80211_node_delucastkey(ni);
1312753c7e08SAugustin Cavalier }
1313753c7e08SAugustin Cavalier
1314753c7e08SAugustin Cavalier static void
node_free(struct ieee80211_node * ni)1315753c7e08SAugustin Cavalier node_free(struct ieee80211_node *ni)
1316753c7e08SAugustin Cavalier {
1317753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
1318753c7e08SAugustin Cavalier
1319753c7e08SAugustin Cavalier ieee80211_ratectl_node_deinit(ni);
1320753c7e08SAugustin Cavalier ic->ic_node_cleanup(ni);
1321753c7e08SAugustin Cavalier ieee80211_ies_cleanup(&ni->ni_ies);
1322753c7e08SAugustin Cavalier ieee80211_psq_cleanup(&ni->ni_psq);
1323753c7e08SAugustin Cavalier IEEE80211_FREE(ni, M_80211_NODE);
1324753c7e08SAugustin Cavalier }
1325753c7e08SAugustin Cavalier
1326753c7e08SAugustin Cavalier static void
node_age(struct ieee80211_node * ni)1327753c7e08SAugustin Cavalier node_age(struct ieee80211_node *ni)
1328753c7e08SAugustin Cavalier {
1329753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
1330753c7e08SAugustin Cavalier
1331753c7e08SAugustin Cavalier /*
1332753c7e08SAugustin Cavalier * Age frames on the power save queue.
1333753c7e08SAugustin Cavalier */
1334753c7e08SAugustin Cavalier if (ieee80211_node_psq_age(ni) != 0 &&
1335753c7e08SAugustin Cavalier ni->ni_psq.psq_len == 0 && vap->iv_set_tim != NULL)
1336753c7e08SAugustin Cavalier vap->iv_set_tim(ni, 0);
1337753c7e08SAugustin Cavalier /*
1338753c7e08SAugustin Cavalier * Age out HT resources (e.g. frames on the
1339753c7e08SAugustin Cavalier * A-MPDU reorder queues).
1340753c7e08SAugustin Cavalier */
1341753c7e08SAugustin Cavalier if (ni->ni_associd != 0 && (ni->ni_flags & IEEE80211_NODE_HT))
1342753c7e08SAugustin Cavalier ieee80211_ht_node_age(ni);
1343753c7e08SAugustin Cavalier }
1344753c7e08SAugustin Cavalier
1345753c7e08SAugustin Cavalier static int8_t
node_getrssi(const struct ieee80211_node * ni)1346753c7e08SAugustin Cavalier node_getrssi(const struct ieee80211_node *ni)
1347753c7e08SAugustin Cavalier {
1348753c7e08SAugustin Cavalier uint32_t avgrssi = ni->ni_avgrssi;
1349753c7e08SAugustin Cavalier int32_t rssi;
1350753c7e08SAugustin Cavalier
1351753c7e08SAugustin Cavalier if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER)
1352753c7e08SAugustin Cavalier return 0;
1353753c7e08SAugustin Cavalier rssi = IEEE80211_RSSI_GET(avgrssi);
1354753c7e08SAugustin Cavalier return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi;
1355753c7e08SAugustin Cavalier }
1356753c7e08SAugustin Cavalier
1357753c7e08SAugustin Cavalier static void
node_getsignal(const struct ieee80211_node * ni,int8_t * rssi,int8_t * noise)1358753c7e08SAugustin Cavalier node_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise)
1359753c7e08SAugustin Cavalier {
1360753c7e08SAugustin Cavalier *rssi = node_getrssi(ni);
1361753c7e08SAugustin Cavalier *noise = ni->ni_noise;
1362753c7e08SAugustin Cavalier }
1363753c7e08SAugustin Cavalier
1364753c7e08SAugustin Cavalier static void
node_getmimoinfo(const struct ieee80211_node * ni,struct ieee80211_mimo_info * info)1365753c7e08SAugustin Cavalier node_getmimoinfo(const struct ieee80211_node *ni,
1366753c7e08SAugustin Cavalier struct ieee80211_mimo_info *info)
1367753c7e08SAugustin Cavalier {
1368753c7e08SAugustin Cavalier int i;
1369753c7e08SAugustin Cavalier uint32_t avgrssi;
1370753c7e08SAugustin Cavalier int32_t rssi;
1371753c7e08SAugustin Cavalier
1372753c7e08SAugustin Cavalier bzero(info, sizeof(*info));
1373753c7e08SAugustin Cavalier
13748244a9baSAugustin Cavalier for (i = 0; i < MIN(IEEE80211_MAX_CHAINS, ni->ni_mimo_chains); i++) {
13758244a9baSAugustin Cavalier /* Note: for now, just pri20 channel info */
1376753c7e08SAugustin Cavalier avgrssi = ni->ni_mimo_rssi_ctl[i];
1377753c7e08SAugustin Cavalier if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) {
13788244a9baSAugustin Cavalier info->ch[i].rssi[0] = 0;
1379753c7e08SAugustin Cavalier } else {
1380753c7e08SAugustin Cavalier rssi = IEEE80211_RSSI_GET(avgrssi);
13818244a9baSAugustin Cavalier info->ch[i].rssi[0] = rssi < 0 ? 0 : rssi > 127 ? 127 : rssi;
1382753c7e08SAugustin Cavalier }
13838244a9baSAugustin Cavalier info->ch[i].noise[0] = ni->ni_mimo_noise_ctl[i];
1384753c7e08SAugustin Cavalier }
1385753c7e08SAugustin Cavalier
1386753c7e08SAugustin Cavalier /* XXX ext radios? */
1387753c7e08SAugustin Cavalier
1388753c7e08SAugustin Cavalier /* XXX EVM? */
1389753c7e08SAugustin Cavalier }
1390753c7e08SAugustin Cavalier
13918244a9baSAugustin Cavalier static void
ieee80211_add_node_nt(struct ieee80211_node_table * nt,struct ieee80211_node * ni)13928244a9baSAugustin Cavalier ieee80211_add_node_nt(struct ieee80211_node_table *nt,
13938244a9baSAugustin Cavalier struct ieee80211_node *ni)
13948244a9baSAugustin Cavalier {
13958244a9baSAugustin Cavalier struct ieee80211com *ic = nt->nt_ic;
13968244a9baSAugustin Cavalier int hash;
13978244a9baSAugustin Cavalier
13988244a9baSAugustin Cavalier IEEE80211_NODE_LOCK_ASSERT(nt);
13998244a9baSAugustin Cavalier
14008244a9baSAugustin Cavalier hash = IEEE80211_NODE_HASH(ic, ni->ni_macaddr);
14018244a9baSAugustin Cavalier (void) ic; /* XXX IEEE80211_NODE_HASH */
14028244a9baSAugustin Cavalier TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
14038244a9baSAugustin Cavalier LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
14048244a9baSAugustin Cavalier nt->nt_count++;
14058244a9baSAugustin Cavalier ni->ni_table = nt;
14068244a9baSAugustin Cavalier }
14078244a9baSAugustin Cavalier
14088244a9baSAugustin Cavalier static void
ieee80211_del_node_nt(struct ieee80211_node_table * nt,struct ieee80211_node * ni)14098244a9baSAugustin Cavalier ieee80211_del_node_nt(struct ieee80211_node_table *nt,
14108244a9baSAugustin Cavalier struct ieee80211_node *ni)
14118244a9baSAugustin Cavalier {
14128244a9baSAugustin Cavalier
14138244a9baSAugustin Cavalier IEEE80211_NODE_LOCK_ASSERT(nt);
14148244a9baSAugustin Cavalier
14158244a9baSAugustin Cavalier TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
14168244a9baSAugustin Cavalier LIST_REMOVE(ni, ni_hash);
14178244a9baSAugustin Cavalier nt->nt_count--;
14188244a9baSAugustin Cavalier KASSERT(nt->nt_count >= 0,
14198244a9baSAugustin Cavalier ("nt_count is negative (%d)!\n", nt->nt_count));
14208244a9baSAugustin Cavalier ni->ni_table = NULL;
14218244a9baSAugustin Cavalier }
14228244a9baSAugustin Cavalier
1423*86021fd4SAugustin Cavalier static struct ieee80211_node *
ieee80211_alloc_node(struct ieee80211_node_table * nt,struct ieee80211vap * vap,const uint8_t macaddr[IEEE80211_ADDR_LEN],const char * func __debrefcnt_used,int line __debrefcnt_used)1424753c7e08SAugustin Cavalier ieee80211_alloc_node(struct ieee80211_node_table *nt,
1425*86021fd4SAugustin Cavalier struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN],
1426*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
1427753c7e08SAugustin Cavalier {
1428753c7e08SAugustin Cavalier struct ieee80211com *ic = nt->nt_ic;
1429753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1430753c7e08SAugustin Cavalier
1431753c7e08SAugustin Cavalier ni = ic->ic_node_alloc(vap, macaddr);
1432753c7e08SAugustin Cavalier if (ni == NULL) {
1433753c7e08SAugustin Cavalier vap->iv_stats.is_rx_nodealloc++;
1434753c7e08SAugustin Cavalier return NULL;
1435753c7e08SAugustin Cavalier }
1436753c7e08SAugustin Cavalier
1437753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1438753c7e08SAugustin Cavalier "%s %p<%s> in %s table\n", __func__, ni,
1439753c7e08SAugustin Cavalier ether_sprintf(macaddr), nt->nt_name);
1440753c7e08SAugustin Cavalier
1441753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
1442753c7e08SAugustin Cavalier ieee80211_node_initref(ni); /* mark referenced */
1443*86021fd4SAugustin Cavalier #ifdef IEEE80211_DEBUG_REFCNT
1444*86021fd4SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1445*86021fd4SAugustin Cavalier "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,
1446*86021fd4SAugustin Cavalier ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni));
1447*86021fd4SAugustin Cavalier #endif
1448753c7e08SAugustin Cavalier ni->ni_chan = IEEE80211_CHAN_ANYC;
1449753c7e08SAugustin Cavalier ni->ni_authmode = IEEE80211_AUTH_OPEN;
1450753c7e08SAugustin Cavalier ni->ni_txpower = ic->ic_txpowlimit; /* max power */
1451753c7e08SAugustin Cavalier ni->ni_txparms = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1452753c7e08SAugustin Cavalier ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE);
1453753c7e08SAugustin Cavalier ni->ni_avgrssi = IEEE80211_RSSI_DUMMY_MARKER;
1454753c7e08SAugustin Cavalier ni->ni_inact_reload = nt->nt_inact_init;
1455753c7e08SAugustin Cavalier ni->ni_inact = ni->ni_inact_reload;
1456753c7e08SAugustin Cavalier ni->ni_ath_defkeyix = 0x7fff;
1457753c7e08SAugustin Cavalier ieee80211_psq_init(&ni->ni_psq, "unknown");
1458753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_MESH
1459753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_MBSS)
1460753c7e08SAugustin Cavalier ieee80211_mesh_node_init(vap, ni);
1461753c7e08SAugustin Cavalier #endif
1462753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
14638244a9baSAugustin Cavalier ieee80211_add_node_nt(nt, ni);
1464753c7e08SAugustin Cavalier ni->ni_vap = vap;
1465753c7e08SAugustin Cavalier ni->ni_ic = ic;
1466753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
1467753c7e08SAugustin Cavalier
14685cad57c4SJérôme Duval /* handle failure; free node state */
14695cad57c4SJérôme Duval if (ic->ic_node_init(ni) != 0) {
14705cad57c4SJérôme Duval vap->iv_stats.is_rx_nodealloc++;
14715cad57c4SJérôme Duval ieee80211_psq_cleanup(&ni->ni_psq);
14725cad57c4SJérôme Duval ieee80211_ratectl_node_deinit(ni);
1473*86021fd4SAugustin Cavalier __ieee80211_free_node(ni);
14745cad57c4SJérôme Duval return NULL;
14755cad57c4SJérôme Duval }
14765cad57c4SJérôme Duval
1477753c7e08SAugustin Cavalier IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
1478753c7e08SAugustin Cavalier "%s: inact_reload %u", __func__, ni->ni_inact_reload);
1479753c7e08SAugustin Cavalier
1480753c7e08SAugustin Cavalier return ni;
1481753c7e08SAugustin Cavalier }
1482753c7e08SAugustin Cavalier
1483753c7e08SAugustin Cavalier /*
1484753c7e08SAugustin Cavalier * Craft a temporary node suitable for sending a management frame
1485753c7e08SAugustin Cavalier * to the specified station. We craft only as much state as we
1486753c7e08SAugustin Cavalier * need to do the work since the node will be immediately reclaimed
1487753c7e08SAugustin Cavalier * once the send completes.
1488753c7e08SAugustin Cavalier */
1489753c7e08SAugustin Cavalier struct ieee80211_node *
ieee80211_tmp_node(struct ieee80211vap * vap,const uint8_t macaddr[IEEE80211_ADDR_LEN])1490753c7e08SAugustin Cavalier ieee80211_tmp_node(struct ieee80211vap *vap,
1491753c7e08SAugustin Cavalier const uint8_t macaddr[IEEE80211_ADDR_LEN])
1492753c7e08SAugustin Cavalier {
1493753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
1494753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1495753c7e08SAugustin Cavalier
1496753c7e08SAugustin Cavalier ni = ic->ic_node_alloc(vap, macaddr);
1497753c7e08SAugustin Cavalier if (ni != NULL) {
1498753c7e08SAugustin Cavalier struct ieee80211_node *bss = vap->iv_bss;
1499753c7e08SAugustin Cavalier
1500753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1501753c7e08SAugustin Cavalier "%s %p<%s>\n", __func__, ni, ether_sprintf(macaddr));
1502753c7e08SAugustin Cavalier
1503753c7e08SAugustin Cavalier ni->ni_table = NULL; /* NB: pedantic */
1504753c7e08SAugustin Cavalier ni->ni_ic = ic; /* NB: needed to set channel */
1505753c7e08SAugustin Cavalier ni->ni_vap = vap;
1506753c7e08SAugustin Cavalier
1507753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
1508753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid);
1509753c7e08SAugustin Cavalier ieee80211_node_initref(ni); /* mark referenced */
1510*86021fd4SAugustin Cavalier #ifdef IEEE80211_DEBUG_REFCNT
1511*86021fd4SAugustin Cavalier /* Only one caller so we skip func/line passing into the func. */
1512*86021fd4SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1513*86021fd4SAugustin Cavalier "%s (%s:%u) %p<%s> refcnt %d\n", __func__, "", -1, ni,
1514*86021fd4SAugustin Cavalier ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni));
1515*86021fd4SAugustin Cavalier #endif
1516753c7e08SAugustin Cavalier /* NB: required by ieee80211_fix_rate */
1517753c7e08SAugustin Cavalier ieee80211_node_set_chan(ni, bss->ni_chan);
1518753c7e08SAugustin Cavalier ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey,
1519753c7e08SAugustin Cavalier IEEE80211_KEYIX_NONE);
1520753c7e08SAugustin Cavalier ni->ni_txpower = bss->ni_txpower;
1521753c7e08SAugustin Cavalier /* XXX optimize away */
1522753c7e08SAugustin Cavalier ieee80211_psq_init(&ni->ni_psq, "unknown");
1523753c7e08SAugustin Cavalier
1524753c7e08SAugustin Cavalier ieee80211_ratectl_node_init(ni);
15255cad57c4SJérôme Duval
15265cad57c4SJérôme Duval /* handle failure; free node state */
15275cad57c4SJérôme Duval if (ic->ic_node_init(ni) != 0) {
15285cad57c4SJérôme Duval vap->iv_stats.is_rx_nodealloc++;
15295cad57c4SJérôme Duval ieee80211_psq_cleanup(&ni->ni_psq);
15305cad57c4SJérôme Duval ieee80211_ratectl_node_deinit(ni);
1531*86021fd4SAugustin Cavalier __ieee80211_free_node(ni);
15325cad57c4SJérôme Duval return NULL;
15335cad57c4SJérôme Duval }
15345cad57c4SJérôme Duval
1535753c7e08SAugustin Cavalier } else {
1536753c7e08SAugustin Cavalier /* XXX msg */
1537753c7e08SAugustin Cavalier vap->iv_stats.is_rx_nodealloc++;
1538753c7e08SAugustin Cavalier }
1539753c7e08SAugustin Cavalier return ni;
1540753c7e08SAugustin Cavalier }
1541753c7e08SAugustin Cavalier
1542753c7e08SAugustin Cavalier struct ieee80211_node *
ieee80211_dup_bss(struct ieee80211vap * vap,const uint8_t macaddr[IEEE80211_ADDR_LEN])1543753c7e08SAugustin Cavalier ieee80211_dup_bss(struct ieee80211vap *vap,
1544753c7e08SAugustin Cavalier const uint8_t macaddr[IEEE80211_ADDR_LEN])
1545753c7e08SAugustin Cavalier {
1546753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
1547753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1548753c7e08SAugustin Cavalier
1549*86021fd4SAugustin Cavalier ni = ieee80211_alloc_node(&ic->ic_sta, vap, macaddr, __func__, __LINE__);
1550753c7e08SAugustin Cavalier if (ni != NULL) {
1551753c7e08SAugustin Cavalier struct ieee80211_node *bss = vap->iv_bss;
1552753c7e08SAugustin Cavalier /*
1553753c7e08SAugustin Cavalier * Inherit from iv_bss.
1554753c7e08SAugustin Cavalier */
1555753c7e08SAugustin Cavalier copy_bss(ni, bss);
1556753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid);
1557753c7e08SAugustin Cavalier ieee80211_node_set_chan(ni, bss->ni_chan);
1558753c7e08SAugustin Cavalier }
1559753c7e08SAugustin Cavalier return ni;
1560753c7e08SAugustin Cavalier }
1561753c7e08SAugustin Cavalier
1562753c7e08SAugustin Cavalier /*
1563753c7e08SAugustin Cavalier * Create a bss node for a legacy WDS vap. The far end does
1564753c7e08SAugustin Cavalier * not associate so we just create create a new node and
1565753c7e08SAugustin Cavalier * simulate an association. The caller is responsible for
1566753c7e08SAugustin Cavalier * installing the node as the bss node and handling any further
1567753c7e08SAugustin Cavalier * setup work like authorizing the port.
1568753c7e08SAugustin Cavalier */
1569753c7e08SAugustin Cavalier struct ieee80211_node *
ieee80211_node_create_wds(struct ieee80211vap * vap,const uint8_t bssid[IEEE80211_ADDR_LEN],struct ieee80211_channel * chan)1570753c7e08SAugustin Cavalier ieee80211_node_create_wds(struct ieee80211vap *vap,
1571753c7e08SAugustin Cavalier const uint8_t bssid[IEEE80211_ADDR_LEN], struct ieee80211_channel *chan)
1572753c7e08SAugustin Cavalier {
1573753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
1574753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1575753c7e08SAugustin Cavalier
1576753c7e08SAugustin Cavalier /* XXX check if node already in sta table? */
1577*86021fd4SAugustin Cavalier ni = ieee80211_alloc_node(&ic->ic_sta, vap, bssid, __func__, __LINE__);
1578753c7e08SAugustin Cavalier if (ni != NULL) {
1579753c7e08SAugustin Cavalier ni->ni_wdsvap = vap;
1580753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, bssid);
1581753c7e08SAugustin Cavalier /*
1582753c7e08SAugustin Cavalier * Inherit any manually configured settings.
1583753c7e08SAugustin Cavalier */
1584753c7e08SAugustin Cavalier copy_bss(ni, vap->iv_bss);
1585753c7e08SAugustin Cavalier ieee80211_node_set_chan(ni, chan);
1586753c7e08SAugustin Cavalier /* NB: propagate ssid so available to WPA supplicant */
1587753c7e08SAugustin Cavalier ni->ni_esslen = vap->iv_des_ssid[0].len;
1588753c7e08SAugustin Cavalier memcpy(ni->ni_essid, vap->iv_des_ssid[0].ssid, ni->ni_esslen);
1589753c7e08SAugustin Cavalier /* NB: no associd for peer */
1590753c7e08SAugustin Cavalier /*
1591753c7e08SAugustin Cavalier * There are no management frames to use to
1592753c7e08SAugustin Cavalier * discover neighbor capabilities, so blindly
1593753c7e08SAugustin Cavalier * propagate the local configuration.
1594753c7e08SAugustin Cavalier */
1595753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_WME)
1596753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_QOS;
1597753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_SUPERG
1598753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_FF)
1599753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_FF;
1600753c7e08SAugustin Cavalier #endif
16018244a9baSAugustin Cavalier /* XXX VHT */
1602753c7e08SAugustin Cavalier if ((ic->ic_htcaps & IEEE80211_HTC_HT) &&
1603753c7e08SAugustin Cavalier (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
1604753c7e08SAugustin Cavalier /*
1605753c7e08SAugustin Cavalier * Device is HT-capable and HT is enabled for
1606753c7e08SAugustin Cavalier * the vap; setup HT operation. On return
1607753c7e08SAugustin Cavalier * ni_chan will be adjusted to an HT channel.
1608753c7e08SAugustin Cavalier */
1609753c7e08SAugustin Cavalier ieee80211_ht_wds_init(ni);
1610*86021fd4SAugustin Cavalier if (vap->iv_vht_flags & IEEE80211_FVHT_VHT) {
16118244a9baSAugustin Cavalier printf("%s: TODO: vht_wds_init\n", __func__);
16128244a9baSAugustin Cavalier }
1613753c7e08SAugustin Cavalier } else {
1614753c7e08SAugustin Cavalier struct ieee80211_channel *c = ni->ni_chan;
1615753c7e08SAugustin Cavalier /*
1616753c7e08SAugustin Cavalier * Force a legacy channel to be used.
1617753c7e08SAugustin Cavalier */
1618753c7e08SAugustin Cavalier c = ieee80211_find_channel(ic,
1619753c7e08SAugustin Cavalier c->ic_freq, c->ic_flags &~ IEEE80211_CHAN_HT);
1620753c7e08SAugustin Cavalier KASSERT(c != NULL, ("no legacy channel, %u/%x",
1621753c7e08SAugustin Cavalier ni->ni_chan->ic_freq, ni->ni_chan->ic_flags));
1622753c7e08SAugustin Cavalier ni->ni_chan = c;
1623753c7e08SAugustin Cavalier }
1624753c7e08SAugustin Cavalier }
1625753c7e08SAugustin Cavalier return ni;
1626753c7e08SAugustin Cavalier }
1627753c7e08SAugustin Cavalier
1628753c7e08SAugustin Cavalier struct ieee80211_node *
_ieee80211_find_node_locked(struct ieee80211_node_table * nt,const uint8_t macaddr[IEEE80211_ADDR_LEN],const char * func __debrefcnt_used,int line __debrefcnt_used)1629*86021fd4SAugustin Cavalier _ieee80211_find_node_locked(struct ieee80211_node_table *nt,
1630*86021fd4SAugustin Cavalier const uint8_t macaddr[IEEE80211_ADDR_LEN],
1631*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
1632753c7e08SAugustin Cavalier {
1633753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1634753c7e08SAugustin Cavalier int hash;
1635753c7e08SAugustin Cavalier
1636753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK_ASSERT(nt);
1637753c7e08SAugustin Cavalier
1638753c7e08SAugustin Cavalier hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr);
1639753c7e08SAugustin Cavalier LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
1640753c7e08SAugustin Cavalier if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
1641753c7e08SAugustin Cavalier ieee80211_ref_node(ni); /* mark referenced */
1642753c7e08SAugustin Cavalier #ifdef IEEE80211_DEBUG_REFCNT
1643753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
1644753c7e08SAugustin Cavalier "%s (%s:%u) %p<%s> refcnt %d\n", __func__,
1645753c7e08SAugustin Cavalier func, line,
1646753c7e08SAugustin Cavalier ni, ether_sprintf(ni->ni_macaddr),
1647753c7e08SAugustin Cavalier ieee80211_node_refcnt(ni));
1648753c7e08SAugustin Cavalier #endif
1649753c7e08SAugustin Cavalier return ni;
1650753c7e08SAugustin Cavalier }
1651753c7e08SAugustin Cavalier }
1652753c7e08SAugustin Cavalier return NULL;
1653753c7e08SAugustin Cavalier }
1654753c7e08SAugustin Cavalier
1655753c7e08SAugustin Cavalier struct ieee80211_node *
_ieee80211_find_node(struct ieee80211_node_table * nt,const uint8_t macaddr[IEEE80211_ADDR_LEN],const char * func __debrefcnt_used,int line __debrefcnt_used)1656*86021fd4SAugustin Cavalier _ieee80211_find_node(struct ieee80211_node_table *nt,
1657*86021fd4SAugustin Cavalier const uint8_t macaddr[IEEE80211_ADDR_LEN],
1658*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
1659753c7e08SAugustin Cavalier {
1660753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1661753c7e08SAugustin Cavalier
1662753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
1663*86021fd4SAugustin Cavalier ni = _ieee80211_find_node_locked(nt, macaddr, func, line);
1664753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
1665753c7e08SAugustin Cavalier return ni;
1666753c7e08SAugustin Cavalier }
1667753c7e08SAugustin Cavalier
1668753c7e08SAugustin Cavalier struct ieee80211_node *
_ieee80211_find_vap_node_locked(struct ieee80211_node_table * nt,const struct ieee80211vap * vap,const uint8_t macaddr[IEEE80211_ADDR_LEN],const char * func __debrefcnt_used,int line __debrefcnt_used)1669*86021fd4SAugustin Cavalier _ieee80211_find_vap_node_locked(struct ieee80211_node_table *nt,
1670*86021fd4SAugustin Cavalier const struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN],
1671*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
1672753c7e08SAugustin Cavalier {
1673753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1674753c7e08SAugustin Cavalier int hash;
1675753c7e08SAugustin Cavalier
1676753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK_ASSERT(nt);
1677753c7e08SAugustin Cavalier
1678753c7e08SAugustin Cavalier hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr);
1679753c7e08SAugustin Cavalier LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
1680753c7e08SAugustin Cavalier if (ni->ni_vap == vap &&
1681753c7e08SAugustin Cavalier IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
1682753c7e08SAugustin Cavalier ieee80211_ref_node(ni); /* mark referenced */
1683753c7e08SAugustin Cavalier #ifdef IEEE80211_DEBUG_REFCNT
1684753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
1685753c7e08SAugustin Cavalier "%s (%s:%u) %p<%s> refcnt %d\n", __func__,
1686753c7e08SAugustin Cavalier func, line,
1687753c7e08SAugustin Cavalier ni, ether_sprintf(ni->ni_macaddr),
1688753c7e08SAugustin Cavalier ieee80211_node_refcnt(ni));
1689753c7e08SAugustin Cavalier #endif
1690753c7e08SAugustin Cavalier return ni;
1691753c7e08SAugustin Cavalier }
1692753c7e08SAugustin Cavalier }
1693753c7e08SAugustin Cavalier return NULL;
1694753c7e08SAugustin Cavalier }
1695753c7e08SAugustin Cavalier
1696753c7e08SAugustin Cavalier struct ieee80211_node *
_ieee80211_find_vap_node(struct ieee80211_node_table * nt,const struct ieee80211vap * vap,const uint8_t macaddr[IEEE80211_ADDR_LEN],const char * func __debrefcnt_used,int line __debrefcnt_used)1697*86021fd4SAugustin Cavalier _ieee80211_find_vap_node(struct ieee80211_node_table *nt,
1698*86021fd4SAugustin Cavalier const struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN],
1699*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
1700753c7e08SAugustin Cavalier {
1701753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1702753c7e08SAugustin Cavalier
1703753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
1704*86021fd4SAugustin Cavalier ni = _ieee80211_find_vap_node_locked(nt, vap, macaddr, func, line);
1705753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
1706753c7e08SAugustin Cavalier return ni;
1707753c7e08SAugustin Cavalier }
1708753c7e08SAugustin Cavalier
1709753c7e08SAugustin Cavalier /*
1710753c7e08SAugustin Cavalier * Fake up a node; this handles node discovery in adhoc mode.
1711*86021fd4SAugustin Cavalier * Note that for the driver's benefit we treat this like
1712753c7e08SAugustin Cavalier * an association so the driver has an opportunity to setup
1713753c7e08SAugustin Cavalier * it's private state.
1714753c7e08SAugustin Cavalier */
1715753c7e08SAugustin Cavalier struct ieee80211_node *
ieee80211_fakeup_adhoc_node(struct ieee80211vap * vap,const uint8_t macaddr[IEEE80211_ADDR_LEN])1716753c7e08SAugustin Cavalier ieee80211_fakeup_adhoc_node(struct ieee80211vap *vap,
1717753c7e08SAugustin Cavalier const uint8_t macaddr[IEEE80211_ADDR_LEN])
1718753c7e08SAugustin Cavalier {
1719753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1720753c7e08SAugustin Cavalier
1721753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE | IEEE80211_MSG_ASSOC,
1722753c7e08SAugustin Cavalier "%s: mac<%s>\n", __func__, ether_sprintf(macaddr));
1723753c7e08SAugustin Cavalier ni = ieee80211_dup_bss(vap, macaddr);
1724753c7e08SAugustin Cavalier if (ni != NULL) {
1725753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
1726753c7e08SAugustin Cavalier
1727753c7e08SAugustin Cavalier /* XXX no rate negotiation; just dup */
1728753c7e08SAugustin Cavalier ni->ni_rates = vap->iv_bss->ni_rates;
1729753c7e08SAugustin Cavalier if (ieee80211_iserp_rateset(&ni->ni_rates))
1730753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_ERP;
1731753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_AHDEMO) {
1732753c7e08SAugustin Cavalier /*
1733753c7e08SAugustin Cavalier * In adhoc demo mode there are no management
1734753c7e08SAugustin Cavalier * frames to use to discover neighbor capabilities,
1735753c7e08SAugustin Cavalier * so blindly propagate the local configuration
1736753c7e08SAugustin Cavalier * so we can do interesting things (e.g. use
1737753c7e08SAugustin Cavalier * WME to disable ACK's).
1738753c7e08SAugustin Cavalier */
17398244a9baSAugustin Cavalier /*
17408244a9baSAugustin Cavalier * XXX TODO: 11n?
17418244a9baSAugustin Cavalier */
1742753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_WME)
1743753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_QOS;
1744753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_SUPERG
1745753c7e08SAugustin Cavalier if (vap->iv_flags & IEEE80211_F_FF)
1746753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_FF;
1747753c7e08SAugustin Cavalier #endif
1748753c7e08SAugustin Cavalier }
1749753c7e08SAugustin Cavalier ieee80211_node_setuptxparms(ni);
1750753c7e08SAugustin Cavalier ieee80211_ratectl_node_init(ni);
17518244a9baSAugustin Cavalier
17528244a9baSAugustin Cavalier /*
17538244a9baSAugustin Cavalier * XXX TODO: 11n? At least 20MHz, at least A-MPDU RX,
17548244a9baSAugustin Cavalier * not A-MPDU TX; not 11n rates, etc. We'll cycle
17558244a9baSAugustin Cavalier * that after we hear that we can indeed do 11n
17568244a9baSAugustin Cavalier * (either by a beacon frame or by a probe response.)
17578244a9baSAugustin Cavalier */
17588244a9baSAugustin Cavalier
17598244a9baSAugustin Cavalier /*
17608244a9baSAugustin Cavalier * This is the first time we see the node.
17618244a9baSAugustin Cavalier */
1762753c7e08SAugustin Cavalier if (ic->ic_newassoc != NULL)
1763753c7e08SAugustin Cavalier ic->ic_newassoc(ni, 1);
17648244a9baSAugustin Cavalier
17658244a9baSAugustin Cavalier /*
17668244a9baSAugustin Cavalier * Kick off a probe request to the given node;
17678244a9baSAugustin Cavalier * we will then use the probe response to update
17688244a9baSAugustin Cavalier * 11n/etc configuration state.
17698244a9baSAugustin Cavalier *
17708244a9baSAugustin Cavalier * XXX TODO: this isn't guaranteed, and until we get
17718244a9baSAugustin Cavalier * a probe response, we won't be able to actually
17728244a9baSAugustin Cavalier * do anything 802.11n related to the node.
17738244a9baSAugustin Cavalier * So if this does indeed work, maybe we should hold
17748244a9baSAugustin Cavalier * off on sending responses until we get the probe
17758244a9baSAugustin Cavalier * response, or just default to some sensible subset
17768244a9baSAugustin Cavalier * of 802.11n behaviour (eg always allow aggregation
17778244a9baSAugustin Cavalier * negotiation TO us, but not FROM us, etc) so we
17788244a9baSAugustin Cavalier * aren't entirely busted.
17798244a9baSAugustin Cavalier */
17808244a9baSAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_IBSS) {
17818244a9baSAugustin Cavalier ieee80211_send_probereq(ni, /* node */
17828244a9baSAugustin Cavalier vap->iv_myaddr, /* SA */
17838244a9baSAugustin Cavalier ni->ni_macaddr, /* DA */
17848244a9baSAugustin Cavalier vap->iv_bss->ni_bssid, /* BSSID */
17858244a9baSAugustin Cavalier vap->iv_bss->ni_essid,
17868244a9baSAugustin Cavalier vap->iv_bss->ni_esslen); /* SSID */
17878244a9baSAugustin Cavalier }
17888244a9baSAugustin Cavalier
1789753c7e08SAugustin Cavalier /* XXX not right for 802.1x/WPA */
1790753c7e08SAugustin Cavalier ieee80211_node_authorize(ni);
1791753c7e08SAugustin Cavalier }
1792753c7e08SAugustin Cavalier return ni;
1793753c7e08SAugustin Cavalier }
1794753c7e08SAugustin Cavalier
1795753c7e08SAugustin Cavalier void
ieee80211_init_neighbor(struct ieee80211_node * ni,const struct ieee80211_frame * wh,const struct ieee80211_scanparams * sp)1796753c7e08SAugustin Cavalier ieee80211_init_neighbor(struct ieee80211_node *ni,
1797753c7e08SAugustin Cavalier const struct ieee80211_frame *wh,
1798753c7e08SAugustin Cavalier const struct ieee80211_scanparams *sp)
1799753c7e08SAugustin Cavalier {
18008244a9baSAugustin Cavalier int do_ht_setup = 0, do_vht_setup = 0;
1801753c7e08SAugustin Cavalier
1802753c7e08SAugustin Cavalier ni->ni_esslen = sp->ssid[1];
1803753c7e08SAugustin Cavalier memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]);
1804753c7e08SAugustin Cavalier IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
1805753c7e08SAugustin Cavalier memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp));
1806753c7e08SAugustin Cavalier ni->ni_intval = sp->bintval;
1807753c7e08SAugustin Cavalier ni->ni_capinfo = sp->capinfo;
1808753c7e08SAugustin Cavalier ni->ni_chan = ni->ni_ic->ic_curchan;
1809753c7e08SAugustin Cavalier ni->ni_fhdwell = sp->fhdwell;
1810753c7e08SAugustin Cavalier ni->ni_fhindex = sp->fhindex;
1811753c7e08SAugustin Cavalier ni->ni_erp = sp->erp;
1812753c7e08SAugustin Cavalier ni->ni_timoff = sp->timoff;
1813753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_MESH
1814753c7e08SAugustin Cavalier if (ni->ni_vap->iv_opmode == IEEE80211_M_MBSS)
1815753c7e08SAugustin Cavalier ieee80211_mesh_init_neighbor(ni, wh, sp);
1816753c7e08SAugustin Cavalier #endif
1817753c7e08SAugustin Cavalier if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) {
1818753c7e08SAugustin Cavalier ieee80211_ies_expand(&ni->ni_ies);
1819753c7e08SAugustin Cavalier if (ni->ni_ies.wme_ie != NULL)
1820753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_QOS;
1821753c7e08SAugustin Cavalier else
1822753c7e08SAugustin Cavalier ni->ni_flags &= ~IEEE80211_NODE_QOS;
1823753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_SUPERG
1824753c7e08SAugustin Cavalier if (ni->ni_ies.ath_ie != NULL)
1825753c7e08SAugustin Cavalier ieee80211_parse_ath(ni, ni->ni_ies.ath_ie);
1826753c7e08SAugustin Cavalier #endif
1827753c7e08SAugustin Cavalier if (ni->ni_ies.htcap_ie != NULL)
1828753c7e08SAugustin Cavalier ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
1829753c7e08SAugustin Cavalier if (ni->ni_ies.htinfo_ie != NULL)
1830753c7e08SAugustin Cavalier ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
1831753c7e08SAugustin Cavalier
18328244a9baSAugustin Cavalier if (ni->ni_ies.vhtcap_ie != NULL)
18338244a9baSAugustin Cavalier ieee80211_parse_vhtcap(ni, ni->ni_ies.vhtcap_ie);
18348244a9baSAugustin Cavalier if (ni->ni_ies.vhtopmode_ie != NULL)
18358244a9baSAugustin Cavalier ieee80211_parse_vhtopmode(ni, ni->ni_ies.vhtopmode_ie);
18368244a9baSAugustin Cavalier
1837753c7e08SAugustin Cavalier if ((ni->ni_ies.htcap_ie != NULL) &&
1838753c7e08SAugustin Cavalier (ni->ni_ies.htinfo_ie != NULL) &&
1839753c7e08SAugustin Cavalier (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_HT)) {
1840753c7e08SAugustin Cavalier do_ht_setup = 1;
1841753c7e08SAugustin Cavalier }
18428244a9baSAugustin Cavalier
18438244a9baSAugustin Cavalier if ((ni->ni_ies.vhtcap_ie != NULL) &&
18448244a9baSAugustin Cavalier (ni->ni_ies.vhtopmode_ie != NULL) &&
1845*86021fd4SAugustin Cavalier (ni->ni_vap->iv_vht_flags & IEEE80211_FVHT_VHT)) {
18468244a9baSAugustin Cavalier do_vht_setup = 1;
18478244a9baSAugustin Cavalier }
1848753c7e08SAugustin Cavalier }
1849753c7e08SAugustin Cavalier
1850753c7e08SAugustin Cavalier /* NB: must be after ni_chan is setup */
1851753c7e08SAugustin Cavalier ieee80211_setup_rates(ni, sp->rates, sp->xrates,
1852753c7e08SAugustin Cavalier IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1853753c7e08SAugustin Cavalier IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1854753c7e08SAugustin Cavalier
1855753c7e08SAugustin Cavalier /*
1856753c7e08SAugustin Cavalier * If the neighbor is HT compatible, flip that on.
1857753c7e08SAugustin Cavalier */
1858753c7e08SAugustin Cavalier if (do_ht_setup) {
1859753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
1860753c7e08SAugustin Cavalier "%s: doing HT setup\n", __func__);
1861753c7e08SAugustin Cavalier ieee80211_ht_node_init(ni);
1862753c7e08SAugustin Cavalier ieee80211_ht_updateparams(ni,
1863753c7e08SAugustin Cavalier ni->ni_ies.htcap_ie,
1864753c7e08SAugustin Cavalier ni->ni_ies.htinfo_ie);
18658244a9baSAugustin Cavalier
18668244a9baSAugustin Cavalier if (do_vht_setup) {
18678244a9baSAugustin Cavalier if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
18688244a9baSAugustin Cavalier printf("%s: BSS %6D: 2GHz channel, VHT info; ignoring\n",
18698244a9baSAugustin Cavalier __func__,
18708244a9baSAugustin Cavalier ni->ni_macaddr,
18718244a9baSAugustin Cavalier ":");
18728244a9baSAugustin Cavalier } else {
18738244a9baSAugustin Cavalier ieee80211_vht_node_init(ni);
18748244a9baSAugustin Cavalier ieee80211_vht_updateparams(ni,
18758244a9baSAugustin Cavalier ni->ni_ies.vhtcap_ie,
18768244a9baSAugustin Cavalier ni->ni_ies.vhtopmode_ie);
18778244a9baSAugustin Cavalier ieee80211_setup_vht_rates(ni,
18788244a9baSAugustin Cavalier ni->ni_ies.vhtcap_ie,
18798244a9baSAugustin Cavalier ni->ni_ies.vhtopmode_ie);
18808244a9baSAugustin Cavalier }
18818244a9baSAugustin Cavalier }
18828244a9baSAugustin Cavalier
18838244a9baSAugustin Cavalier /*
18848244a9baSAugustin Cavalier * Finally do the channel upgrade/change based
18858244a9baSAugustin Cavalier * on the HT/VHT configuration.
18868244a9baSAugustin Cavalier */
18878244a9baSAugustin Cavalier ieee80211_ht_updateparams_final(ni, ni->ni_ies.htcap_ie,
18888244a9baSAugustin Cavalier ni->ni_ies.htinfo_ie);
1889753c7e08SAugustin Cavalier ieee80211_setup_htrates(ni,
1890753c7e08SAugustin Cavalier ni->ni_ies.htcap_ie,
1891753c7e08SAugustin Cavalier IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
1892753c7e08SAugustin Cavalier ieee80211_setup_basic_htrates(ni,
1893753c7e08SAugustin Cavalier ni->ni_ies.htinfo_ie);
18948244a9baSAugustin Cavalier
1895753c7e08SAugustin Cavalier ieee80211_node_setuptxparms(ni);
1896753c7e08SAugustin Cavalier ieee80211_ratectl_node_init(ni);
18978244a9baSAugustin Cavalier
18988244a9baSAugustin Cavalier /* Reassociate; we're now 11n/11ac */
18998244a9baSAugustin Cavalier /*
19008244a9baSAugustin Cavalier * XXX TODO: this is the wrong thing to do -
19018244a9baSAugustin Cavalier * we're calling it with isnew=1 so the ath(4)
19028244a9baSAugustin Cavalier * driver reinitialises the rate tables.
19038244a9baSAugustin Cavalier * This "mostly" works for ath(4), but it won't
19048244a9baSAugustin Cavalier * be right for firmware devices which allocate
19058244a9baSAugustin Cavalier * node states.
19068244a9baSAugustin Cavalier *
19078244a9baSAugustin Cavalier * So, do we just create a new node and delete
19088244a9baSAugustin Cavalier * the old one? Or?
19098244a9baSAugustin Cavalier */
19108244a9baSAugustin Cavalier if (ni->ni_ic->ic_newassoc)
19118244a9baSAugustin Cavalier ni->ni_ic->ic_newassoc(ni, 1);
1912753c7e08SAugustin Cavalier }
1913753c7e08SAugustin Cavalier }
1914753c7e08SAugustin Cavalier
1915753c7e08SAugustin Cavalier /*
1916753c7e08SAugustin Cavalier * Do node discovery in adhoc mode on receipt of a beacon
1917753c7e08SAugustin Cavalier * or probe response frame. Note that for the driver's
1918*86021fd4SAugustin Cavalier * benefit we treat this like an association so the
1919753c7e08SAugustin Cavalier * driver has an opportunity to setup it's private state.
1920753c7e08SAugustin Cavalier */
1921753c7e08SAugustin Cavalier struct ieee80211_node *
ieee80211_add_neighbor(struct ieee80211vap * vap,const struct ieee80211_frame * wh,const struct ieee80211_scanparams * sp)1922753c7e08SAugustin Cavalier ieee80211_add_neighbor(struct ieee80211vap *vap,
1923753c7e08SAugustin Cavalier const struct ieee80211_frame *wh,
1924753c7e08SAugustin Cavalier const struct ieee80211_scanparams *sp)
1925753c7e08SAugustin Cavalier {
1926753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1927753c7e08SAugustin Cavalier
1928753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
1929753c7e08SAugustin Cavalier "%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2));
1930753c7e08SAugustin Cavalier ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */
1931753c7e08SAugustin Cavalier if (ni != NULL) {
1932753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
1933753c7e08SAugustin Cavalier
1934753c7e08SAugustin Cavalier ieee80211_init_neighbor(ni, wh, sp);
1935753c7e08SAugustin Cavalier if (ieee80211_iserp_rateset(&ni->ni_rates))
1936753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_ERP;
1937753c7e08SAugustin Cavalier ieee80211_node_setuptxparms(ni);
1938753c7e08SAugustin Cavalier ieee80211_ratectl_node_init(ni);
1939753c7e08SAugustin Cavalier if (ic->ic_newassoc != NULL)
1940753c7e08SAugustin Cavalier ic->ic_newassoc(ni, 1);
1941753c7e08SAugustin Cavalier /* XXX not right for 802.1x/WPA */
1942753c7e08SAugustin Cavalier ieee80211_node_authorize(ni);
1943753c7e08SAugustin Cavalier }
1944753c7e08SAugustin Cavalier return ni;
1945753c7e08SAugustin Cavalier }
1946753c7e08SAugustin Cavalier
1947753c7e08SAugustin Cavalier #define IS_PROBEREQ(wh) \
1948753c7e08SAugustin Cavalier ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK|IEEE80211_FC0_SUBTYPE_MASK)) \
1949753c7e08SAugustin Cavalier == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ))
1950753c7e08SAugustin Cavalier #define IS_BCAST_PROBEREQ(wh) \
1951753c7e08SAugustin Cavalier (IS_PROBEREQ(wh) && IEEE80211_IS_MULTICAST( \
1952753c7e08SAugustin Cavalier ((const struct ieee80211_frame *)(wh))->i_addr3))
1953753c7e08SAugustin Cavalier
1954753c7e08SAugustin Cavalier static __inline struct ieee80211_node *
_find_rxnode(struct ieee80211_node_table * nt,const struct ieee80211_frame_min * wh,const char * func __debrefcnt_used,int line __debrefcnt_used)1955753c7e08SAugustin Cavalier _find_rxnode(struct ieee80211_node_table *nt,
1956*86021fd4SAugustin Cavalier const struct ieee80211_frame_min *wh,
1957*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
1958753c7e08SAugustin Cavalier {
1959753c7e08SAugustin Cavalier if (IS_BCAST_PROBEREQ(wh))
1960753c7e08SAugustin Cavalier return NULL; /* spam bcast probe req to all vap's */
1961*86021fd4SAugustin Cavalier return _ieee80211_find_node_locked(nt, wh->i_addr2, func, line);
1962753c7e08SAugustin Cavalier }
1963753c7e08SAugustin Cavalier
1964753c7e08SAugustin Cavalier /*
1965753c7e08SAugustin Cavalier * Locate the node for sender, track state, and then pass the
1966753c7e08SAugustin Cavalier * (referenced) node up to the 802.11 layer for its use. Note
1967753c7e08SAugustin Cavalier * we can return NULL if the sender is not in the table.
1968753c7e08SAugustin Cavalier */
1969753c7e08SAugustin Cavalier struct ieee80211_node *
_ieee80211_find_rxnode(struct ieee80211com * ic,const struct ieee80211_frame_min * wh,const char * func __debrefcnt_used,int line __debrefcnt_used)1970*86021fd4SAugustin Cavalier _ieee80211_find_rxnode(struct ieee80211com *ic,
1971*86021fd4SAugustin Cavalier const struct ieee80211_frame_min *wh,
1972*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
1973753c7e08SAugustin Cavalier {
1974753c7e08SAugustin Cavalier struct ieee80211_node_table *nt;
1975753c7e08SAugustin Cavalier struct ieee80211_node *ni;
1976753c7e08SAugustin Cavalier
1977753c7e08SAugustin Cavalier nt = &ic->ic_sta;
1978753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
1979*86021fd4SAugustin Cavalier ni = _find_rxnode(nt, wh, func, line);
1980753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
1981753c7e08SAugustin Cavalier
1982753c7e08SAugustin Cavalier return ni;
1983753c7e08SAugustin Cavalier }
1984753c7e08SAugustin Cavalier
1985753c7e08SAugustin Cavalier /*
1986753c7e08SAugustin Cavalier * Like ieee80211_find_rxnode but use the supplied h/w
1987753c7e08SAugustin Cavalier * key index as a hint to locate the node in the key
1988753c7e08SAugustin Cavalier * mapping table. If an entry is present at the key
1989753c7e08SAugustin Cavalier * index we return it; otherwise do a normal lookup and
1990753c7e08SAugustin Cavalier * update the mapping table if the station has a unicast
1991753c7e08SAugustin Cavalier * key assigned to it.
1992753c7e08SAugustin Cavalier */
1993753c7e08SAugustin Cavalier struct ieee80211_node *
_ieee80211_find_rxnode_withkey(struct ieee80211com * ic,const struct ieee80211_frame_min * wh,ieee80211_keyix keyix,const char * func __debrefcnt_used,int line __debrefcnt_used)1994*86021fd4SAugustin Cavalier _ieee80211_find_rxnode_withkey(struct ieee80211com *ic,
1995753c7e08SAugustin Cavalier const struct ieee80211_frame_min *wh, ieee80211_keyix keyix,
1996*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
1997753c7e08SAugustin Cavalier {
1998753c7e08SAugustin Cavalier struct ieee80211_node_table *nt;
1999753c7e08SAugustin Cavalier struct ieee80211_node *ni;
2000753c7e08SAugustin Cavalier
2001753c7e08SAugustin Cavalier nt = &ic->ic_sta;
2002753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
2003753c7e08SAugustin Cavalier if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax)
2004753c7e08SAugustin Cavalier ni = nt->nt_keyixmap[keyix];
2005753c7e08SAugustin Cavalier else
2006753c7e08SAugustin Cavalier ni = NULL;
2007753c7e08SAugustin Cavalier if (ni == NULL) {
2008*86021fd4SAugustin Cavalier ni = _find_rxnode(nt, wh, func, line);
2009753c7e08SAugustin Cavalier if (ni != NULL && nt->nt_keyixmap != NULL) {
2010753c7e08SAugustin Cavalier /*
2011753c7e08SAugustin Cavalier * If the station has a unicast key cache slot
2012753c7e08SAugustin Cavalier * assigned update the key->node mapping table.
2013753c7e08SAugustin Cavalier */
2014753c7e08SAugustin Cavalier keyix = ni->ni_ucastkey.wk_rxkeyix;
2015753c7e08SAugustin Cavalier /* XXX can keyixmap[keyix] != NULL? */
2016753c7e08SAugustin Cavalier if (keyix < nt->nt_keyixmax &&
2017753c7e08SAugustin Cavalier nt->nt_keyixmap[keyix] == NULL) {
2018753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap,
2019753c7e08SAugustin Cavalier IEEE80211_MSG_NODE,
2020753c7e08SAugustin Cavalier "%s: add key map entry %p<%s> refcnt %d\n",
2021753c7e08SAugustin Cavalier __func__, ni, ether_sprintf(ni->ni_macaddr),
2022753c7e08SAugustin Cavalier ieee80211_node_refcnt(ni)+1);
2023753c7e08SAugustin Cavalier nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni);
2024753c7e08SAugustin Cavalier }
2025753c7e08SAugustin Cavalier }
2026753c7e08SAugustin Cavalier } else {
2027753c7e08SAugustin Cavalier if (IS_BCAST_PROBEREQ(wh))
2028753c7e08SAugustin Cavalier ni = NULL; /* spam bcast probe req to all vap's */
2029753c7e08SAugustin Cavalier else
2030753c7e08SAugustin Cavalier ieee80211_ref_node(ni);
2031753c7e08SAugustin Cavalier }
2032753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
2033753c7e08SAugustin Cavalier
2034753c7e08SAugustin Cavalier return ni;
2035753c7e08SAugustin Cavalier }
2036753c7e08SAugustin Cavalier #undef IS_BCAST_PROBEREQ
2037753c7e08SAugustin Cavalier #undef IS_PROBEREQ
2038753c7e08SAugustin Cavalier
2039753c7e08SAugustin Cavalier /*
2040753c7e08SAugustin Cavalier * Return a reference to the appropriate node for sending
2041753c7e08SAugustin Cavalier * a data frame. This handles node discovery in adhoc networks.
2042753c7e08SAugustin Cavalier */
2043753c7e08SAugustin Cavalier struct ieee80211_node *
_ieee80211_find_txnode(struct ieee80211vap * vap,const uint8_t macaddr[IEEE80211_ADDR_LEN],const char * func __debrefcnt_used,int line __debrefcnt_used)2044*86021fd4SAugustin Cavalier _ieee80211_find_txnode(struct ieee80211vap *vap,
2045753c7e08SAugustin Cavalier const uint8_t macaddr[IEEE80211_ADDR_LEN],
2046*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
2047753c7e08SAugustin Cavalier {
2048753c7e08SAugustin Cavalier struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta;
2049753c7e08SAugustin Cavalier struct ieee80211_node *ni;
2050753c7e08SAugustin Cavalier
2051753c7e08SAugustin Cavalier /*
2052753c7e08SAugustin Cavalier * The destination address should be in the node table
2053753c7e08SAugustin Cavalier * unless this is a multicast/broadcast frame. We can
2054753c7e08SAugustin Cavalier * also optimize station mode operation, all frames go
2055753c7e08SAugustin Cavalier * to the bss node.
2056753c7e08SAugustin Cavalier */
2057753c7e08SAugustin Cavalier /* XXX can't hold lock across dup_bss 'cuz of recursive locking */
2058753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
2059753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_STA ||
2060753c7e08SAugustin Cavalier vap->iv_opmode == IEEE80211_M_WDS ||
2061753c7e08SAugustin Cavalier IEEE80211_IS_MULTICAST(macaddr))
2062753c7e08SAugustin Cavalier ni = ieee80211_ref_node(vap->iv_bss);
2063753c7e08SAugustin Cavalier else
2064*86021fd4SAugustin Cavalier ni = _ieee80211_find_node_locked(nt, macaddr, func, line);
2065753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
2066753c7e08SAugustin Cavalier
2067753c7e08SAugustin Cavalier if (ni == NULL) {
2068753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_IBSS ||
2069753c7e08SAugustin Cavalier vap->iv_opmode == IEEE80211_M_AHDEMO) {
2070753c7e08SAugustin Cavalier /*
2071753c7e08SAugustin Cavalier * In adhoc mode cons up a node for the destination.
2072753c7e08SAugustin Cavalier * Note that we need an additional reference for the
2073753c7e08SAugustin Cavalier * caller to be consistent with
2074753c7e08SAugustin Cavalier * ieee80211_find_node_locked.
2075753c7e08SAugustin Cavalier */
20768244a9baSAugustin Cavalier /*
20778244a9baSAugustin Cavalier * XXX TODO: this doesn't fake up 11n state; we need
20788244a9baSAugustin Cavalier * to find another way to get it upgraded.
20798244a9baSAugustin Cavalier */
2080753c7e08SAugustin Cavalier ni = ieee80211_fakeup_adhoc_node(vap, macaddr);
2081753c7e08SAugustin Cavalier if (ni != NULL)
2082753c7e08SAugustin Cavalier (void) ieee80211_ref_node(ni);
2083753c7e08SAugustin Cavalier } else {
2084753c7e08SAugustin Cavalier IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, macaddr,
2085753c7e08SAugustin Cavalier "no node, discard frame (%s)", __func__);
2086753c7e08SAugustin Cavalier vap->iv_stats.is_tx_nonode++;
2087753c7e08SAugustin Cavalier }
2088753c7e08SAugustin Cavalier }
2089753c7e08SAugustin Cavalier return ni;
2090753c7e08SAugustin Cavalier }
2091753c7e08SAugustin Cavalier
2092*86021fd4SAugustin Cavalier struct ieee80211_node *
_ieee80211_ref_node(struct ieee80211_node * ni,const char * func __debrefcnt_used,int line __debrefcnt_used)2093*86021fd4SAugustin Cavalier _ieee80211_ref_node(struct ieee80211_node *ni,
2094*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
2095*86021fd4SAugustin Cavalier {
2096*86021fd4SAugustin Cavalier
2097*86021fd4SAugustin Cavalier #ifdef IEEE80211_DEBUG_REFCNT
2098*86021fd4SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
2099*86021fd4SAugustin Cavalier "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,
2100*86021fd4SAugustin Cavalier ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
2101*86021fd4SAugustin Cavalier #endif
2102*86021fd4SAugustin Cavalier ieee80211_node_incref(ni);
2103*86021fd4SAugustin Cavalier return (ni);
2104*86021fd4SAugustin Cavalier }
2105*86021fd4SAugustin Cavalier
2106753c7e08SAugustin Cavalier static void
__ieee80211_free_node(struct ieee80211_node * ni)2107*86021fd4SAugustin Cavalier __ieee80211_free_node(struct ieee80211_node *ni)
2108753c7e08SAugustin Cavalier {
2109753c7e08SAugustin Cavalier struct ieee80211_node_table *nt = ni->ni_table;
2110753c7e08SAugustin Cavalier
2111753c7e08SAugustin Cavalier /*
2112753c7e08SAugustin Cavalier * NB: careful about referencing the vap as it may be
2113753c7e08SAugustin Cavalier * gone if the last reference was held by a driver.
2114753c7e08SAugustin Cavalier * We know the com will always be present so it's safe
2115753c7e08SAugustin Cavalier * to use ni_ic below to reclaim resources.
2116753c7e08SAugustin Cavalier */
2117753c7e08SAugustin Cavalier #if 0
2118753c7e08SAugustin Cavalier IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2119753c7e08SAugustin Cavalier "%s %p<%s> in %s table\n", __func__, ni,
2120753c7e08SAugustin Cavalier ether_sprintf(ni->ni_macaddr),
2121753c7e08SAugustin Cavalier nt != NULL ? nt->nt_name : "<gone>");
2122753c7e08SAugustin Cavalier #endif
2123753c7e08SAugustin Cavalier if (ni->ni_associd != 0) {
2124753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
2125753c7e08SAugustin Cavalier if (vap->iv_aid_bitmap != NULL)
2126753c7e08SAugustin Cavalier IEEE80211_AID_CLR(vap, ni->ni_associd);
2127753c7e08SAugustin Cavalier }
21288244a9baSAugustin Cavalier if (nt != NULL)
21298244a9baSAugustin Cavalier ieee80211_del_node_nt(nt, ni);
2130753c7e08SAugustin Cavalier ni->ni_ic->ic_node_free(ni);
2131753c7e08SAugustin Cavalier }
2132753c7e08SAugustin Cavalier
2133753c7e08SAugustin Cavalier /*
2134753c7e08SAugustin Cavalier * Clear any entry in the unicast key mapping table.
2135753c7e08SAugustin Cavalier */
2136753c7e08SAugustin Cavalier static int
node_clear_keyixmap(struct ieee80211_node_table * nt,struct ieee80211_node * ni)2137753c7e08SAugustin Cavalier node_clear_keyixmap(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
2138753c7e08SAugustin Cavalier {
2139753c7e08SAugustin Cavalier ieee80211_keyix keyix;
2140753c7e08SAugustin Cavalier
2141753c7e08SAugustin Cavalier keyix = ni->ni_ucastkey.wk_rxkeyix;
2142753c7e08SAugustin Cavalier if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
2143753c7e08SAugustin Cavalier nt->nt_keyixmap[keyix] == ni) {
2144753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
2145753c7e08SAugustin Cavalier "%s: %p<%s> clear key map entry %u\n",
2146753c7e08SAugustin Cavalier __func__, ni, ether_sprintf(ni->ni_macaddr), keyix);
2147753c7e08SAugustin Cavalier nt->nt_keyixmap[keyix] = NULL;
2148753c7e08SAugustin Cavalier ieee80211_node_decref(ni);
2149753c7e08SAugustin Cavalier return 1;
2150753c7e08SAugustin Cavalier }
2151753c7e08SAugustin Cavalier
2152753c7e08SAugustin Cavalier return 0;
2153753c7e08SAugustin Cavalier }
2154753c7e08SAugustin Cavalier
2155753c7e08SAugustin Cavalier void
_ieee80211_free_node(struct ieee80211_node * ni,const char * func __debrefcnt_used,int line __debrefcnt_used)2156*86021fd4SAugustin Cavalier _ieee80211_free_node(struct ieee80211_node *ni,
2157*86021fd4SAugustin Cavalier const char *func __debrefcnt_used, int line __debrefcnt_used)
2158753c7e08SAugustin Cavalier {
2159753c7e08SAugustin Cavalier struct ieee80211_node_table *nt = ni->ni_table;
2160753c7e08SAugustin Cavalier
2161753c7e08SAugustin Cavalier #ifdef IEEE80211_DEBUG_REFCNT
2162753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
2163753c7e08SAugustin Cavalier "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,
2164753c7e08SAugustin Cavalier ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1);
2165753c7e08SAugustin Cavalier #endif
2166753c7e08SAugustin Cavalier if (nt != NULL) {
2167753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
2168753c7e08SAugustin Cavalier if (ieee80211_node_dectestref(ni)) {
2169753c7e08SAugustin Cavalier /*
2170753c7e08SAugustin Cavalier * Last reference, reclaim state.
2171753c7e08SAugustin Cavalier */
2172*86021fd4SAugustin Cavalier __ieee80211_free_node(ni);
2173753c7e08SAugustin Cavalier } else if (ieee80211_node_refcnt(ni) == 1)
2174753c7e08SAugustin Cavalier if (node_clear_keyixmap(nt, ni))
2175*86021fd4SAugustin Cavalier __ieee80211_free_node(ni);
2176753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
2177753c7e08SAugustin Cavalier } else {
2178753c7e08SAugustin Cavalier if (ieee80211_node_dectestref(ni))
2179*86021fd4SAugustin Cavalier __ieee80211_free_node(ni);
2180753c7e08SAugustin Cavalier }
2181753c7e08SAugustin Cavalier }
2182753c7e08SAugustin Cavalier
2183753c7e08SAugustin Cavalier /*
2184753c7e08SAugustin Cavalier * Reclaim a unicast key and clear any key cache state.
2185753c7e08SAugustin Cavalier */
2186753c7e08SAugustin Cavalier int
ieee80211_node_delucastkey(struct ieee80211_node * ni)2187753c7e08SAugustin Cavalier ieee80211_node_delucastkey(struct ieee80211_node *ni)
2188753c7e08SAugustin Cavalier {
2189753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
2190753c7e08SAugustin Cavalier struct ieee80211_node_table *nt = &ic->ic_sta;
2191753c7e08SAugustin Cavalier struct ieee80211_node *nikey;
2192753c7e08SAugustin Cavalier ieee80211_keyix keyix;
2193753c7e08SAugustin Cavalier int isowned, status;
2194753c7e08SAugustin Cavalier
2195753c7e08SAugustin Cavalier /*
2196753c7e08SAugustin Cavalier * NB: We must beware of LOR here; deleting the key
2197753c7e08SAugustin Cavalier * can cause the crypto layer to block traffic updates
2198753c7e08SAugustin Cavalier * which can generate a LOR against the node table lock;
2199753c7e08SAugustin Cavalier * grab it here and stash the key index for our use below.
2200753c7e08SAugustin Cavalier *
2201753c7e08SAugustin Cavalier * Must also beware of recursion on the node table lock.
2202753c7e08SAugustin Cavalier * When called from node_cleanup we may already have
2203753c7e08SAugustin Cavalier * the node table lock held. Unfortunately there's no
2204753c7e08SAugustin Cavalier * way to separate out this path so we must do this
2205753c7e08SAugustin Cavalier * conditionally.
2206753c7e08SAugustin Cavalier */
2207753c7e08SAugustin Cavalier isowned = IEEE80211_NODE_IS_LOCKED(nt);
2208753c7e08SAugustin Cavalier if (!isowned)
2209753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
2210753c7e08SAugustin Cavalier nikey = NULL;
2211753c7e08SAugustin Cavalier status = 1; /* NB: success */
2212753c7e08SAugustin Cavalier if (ni->ni_ucastkey.wk_keyix != IEEE80211_KEYIX_NONE) {
2213753c7e08SAugustin Cavalier keyix = ni->ni_ucastkey.wk_rxkeyix;
2214753c7e08SAugustin Cavalier status = ieee80211_crypto_delkey(ni->ni_vap, &ni->ni_ucastkey);
2215753c7e08SAugustin Cavalier if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) {
2216753c7e08SAugustin Cavalier nikey = nt->nt_keyixmap[keyix];
2217753c7e08SAugustin Cavalier nt->nt_keyixmap[keyix] = NULL;
2218753c7e08SAugustin Cavalier }
2219753c7e08SAugustin Cavalier }
2220753c7e08SAugustin Cavalier if (!isowned)
2221753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
2222753c7e08SAugustin Cavalier
2223753c7e08SAugustin Cavalier if (nikey != NULL) {
2224753c7e08SAugustin Cavalier KASSERT(nikey == ni,
2225753c7e08SAugustin Cavalier ("key map out of sync, ni %p nikey %p", ni, nikey));
2226753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
2227753c7e08SAugustin Cavalier "%s: delete key map entry %p<%s> refcnt %d\n",
2228753c7e08SAugustin Cavalier __func__, ni, ether_sprintf(ni->ni_macaddr),
2229753c7e08SAugustin Cavalier ieee80211_node_refcnt(ni)-1);
2230753c7e08SAugustin Cavalier ieee80211_free_node(ni);
2231753c7e08SAugustin Cavalier }
2232753c7e08SAugustin Cavalier return status;
2233753c7e08SAugustin Cavalier }
2234753c7e08SAugustin Cavalier
2235753c7e08SAugustin Cavalier /*
2236753c7e08SAugustin Cavalier * Reclaim a node. If this is the last reference count then
2237753c7e08SAugustin Cavalier * do the normal free work. Otherwise remove it from the node
2238753c7e08SAugustin Cavalier * table and mark it gone by clearing the back-reference.
2239753c7e08SAugustin Cavalier */
2240753c7e08SAugustin Cavalier static void
node_reclaim(struct ieee80211_node_table * nt,struct ieee80211_node * ni)2241753c7e08SAugustin Cavalier node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
2242753c7e08SAugustin Cavalier {
2243753c7e08SAugustin Cavalier
2244753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK_ASSERT(nt);
2245753c7e08SAugustin Cavalier
2246753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
2247753c7e08SAugustin Cavalier "%s: remove %p<%s> from %s table, refcnt %d\n",
2248753c7e08SAugustin Cavalier __func__, ni, ether_sprintf(ni->ni_macaddr),
2249753c7e08SAugustin Cavalier nt->nt_name, ieee80211_node_refcnt(ni)-1);
2250753c7e08SAugustin Cavalier /*
2251753c7e08SAugustin Cavalier * Clear any entry in the unicast key mapping table.
2252753c7e08SAugustin Cavalier * We need to do it here so rx lookups don't find it
2253753c7e08SAugustin Cavalier * in the mapping table even if it's not in the hash
2254753c7e08SAugustin Cavalier * table. We cannot depend on the mapping table entry
2255753c7e08SAugustin Cavalier * being cleared because the node may not be free'd.
2256753c7e08SAugustin Cavalier */
2257753c7e08SAugustin Cavalier (void)node_clear_keyixmap(nt, ni);
2258753c7e08SAugustin Cavalier if (!ieee80211_node_dectestref(ni)) {
2259753c7e08SAugustin Cavalier /*
2260753c7e08SAugustin Cavalier * Other references are present, just remove the
2261753c7e08SAugustin Cavalier * node from the table so it cannot be found. When
2262753c7e08SAugustin Cavalier * the references are dropped storage will be
2263753c7e08SAugustin Cavalier * reclaimed.
2264753c7e08SAugustin Cavalier */
22658244a9baSAugustin Cavalier ieee80211_del_node_nt(nt, ni);
2266753c7e08SAugustin Cavalier } else
2267*86021fd4SAugustin Cavalier __ieee80211_free_node(ni);
2268753c7e08SAugustin Cavalier }
2269753c7e08SAugustin Cavalier
2270753c7e08SAugustin Cavalier /*
2271753c7e08SAugustin Cavalier * Node table support.
2272753c7e08SAugustin Cavalier */
2273753c7e08SAugustin Cavalier
2274753c7e08SAugustin Cavalier static void
ieee80211_node_table_init(struct ieee80211com * ic,struct ieee80211_node_table * nt,const char * name,int inact,int keyixmax)2275753c7e08SAugustin Cavalier ieee80211_node_table_init(struct ieee80211com *ic,
2276753c7e08SAugustin Cavalier struct ieee80211_node_table *nt,
2277753c7e08SAugustin Cavalier const char *name, int inact, int keyixmax)
2278753c7e08SAugustin Cavalier {
2279753c7e08SAugustin Cavalier
2280753c7e08SAugustin Cavalier nt->nt_ic = ic;
2281753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name);
2282753c7e08SAugustin Cavalier TAILQ_INIT(&nt->nt_node);
22838244a9baSAugustin Cavalier nt->nt_count = 0;
2284753c7e08SAugustin Cavalier nt->nt_name = name;
2285753c7e08SAugustin Cavalier nt->nt_inact_init = inact;
2286753c7e08SAugustin Cavalier nt->nt_keyixmax = keyixmax;
2287753c7e08SAugustin Cavalier if (nt->nt_keyixmax > 0) {
2288753c7e08SAugustin Cavalier nt->nt_keyixmap = (struct ieee80211_node **) IEEE80211_MALLOC(
2289753c7e08SAugustin Cavalier keyixmax * sizeof(struct ieee80211_node *),
2290753c7e08SAugustin Cavalier M_80211_NODE,
2291753c7e08SAugustin Cavalier IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
2292753c7e08SAugustin Cavalier if (nt->nt_keyixmap == NULL)
2293753c7e08SAugustin Cavalier ic_printf(ic,
2294753c7e08SAugustin Cavalier "Cannot allocate key index map with %u entries\n",
2295753c7e08SAugustin Cavalier keyixmax);
2296753c7e08SAugustin Cavalier } else
2297753c7e08SAugustin Cavalier nt->nt_keyixmap = NULL;
2298753c7e08SAugustin Cavalier }
2299753c7e08SAugustin Cavalier
2300753c7e08SAugustin Cavalier static void
ieee80211_node_table_reset(struct ieee80211_node_table * nt,struct ieee80211vap * match)2301753c7e08SAugustin Cavalier ieee80211_node_table_reset(struct ieee80211_node_table *nt,
2302753c7e08SAugustin Cavalier struct ieee80211vap *match)
2303753c7e08SAugustin Cavalier {
2304753c7e08SAugustin Cavalier struct ieee80211_node *ni, *next;
2305753c7e08SAugustin Cavalier
2306753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
2307753c7e08SAugustin Cavalier TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) {
2308753c7e08SAugustin Cavalier if (match != NULL && ni->ni_vap != match)
2309753c7e08SAugustin Cavalier continue;
2310753c7e08SAugustin Cavalier /* XXX can this happen? if so need's work */
2311753c7e08SAugustin Cavalier if (ni->ni_associd != 0) {
2312753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
2313753c7e08SAugustin Cavalier
2314753c7e08SAugustin Cavalier if (vap->iv_auth->ia_node_leave != NULL)
2315753c7e08SAugustin Cavalier vap->iv_auth->ia_node_leave(ni);
2316753c7e08SAugustin Cavalier if (vap->iv_aid_bitmap != NULL)
2317753c7e08SAugustin Cavalier IEEE80211_AID_CLR(vap, ni->ni_associd);
2318753c7e08SAugustin Cavalier }
2319753c7e08SAugustin Cavalier ni->ni_wdsvap = NULL; /* clear reference */
2320753c7e08SAugustin Cavalier node_reclaim(nt, ni);
2321753c7e08SAugustin Cavalier }
2322753c7e08SAugustin Cavalier if (match != NULL && match->iv_opmode == IEEE80211_M_WDS) {
2323753c7e08SAugustin Cavalier /*
2324753c7e08SAugustin Cavalier * Make a separate pass to clear references to this vap
2325753c7e08SAugustin Cavalier * held by DWDS entries. They will not be matched above
2326753c7e08SAugustin Cavalier * because ni_vap will point to the ap vap but we still
2327753c7e08SAugustin Cavalier * need to clear ni_wdsvap when the WDS vap is destroyed
2328753c7e08SAugustin Cavalier * and/or reset.
2329753c7e08SAugustin Cavalier */
2330753c7e08SAugustin Cavalier TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next)
2331753c7e08SAugustin Cavalier if (ni->ni_wdsvap == match)
2332753c7e08SAugustin Cavalier ni->ni_wdsvap = NULL;
2333753c7e08SAugustin Cavalier }
2334753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
2335753c7e08SAugustin Cavalier }
2336753c7e08SAugustin Cavalier
2337753c7e08SAugustin Cavalier static void
ieee80211_node_table_cleanup(struct ieee80211_node_table * nt)2338753c7e08SAugustin Cavalier ieee80211_node_table_cleanup(struct ieee80211_node_table *nt)
2339753c7e08SAugustin Cavalier {
2340753c7e08SAugustin Cavalier ieee80211_node_table_reset(nt, NULL);
2341753c7e08SAugustin Cavalier if (nt->nt_keyixmap != NULL) {
2342753c7e08SAugustin Cavalier #ifdef DIAGNOSTIC
2343753c7e08SAugustin Cavalier /* XXX verify all entries are NULL */
2344753c7e08SAugustin Cavalier int i;
2345753c7e08SAugustin Cavalier for (i = 0; i < nt->nt_keyixmax; i++)
2346753c7e08SAugustin Cavalier if (nt->nt_keyixmap[i] != NULL)
2347753c7e08SAugustin Cavalier printf("%s: %s[%u] still active\n", __func__,
2348753c7e08SAugustin Cavalier nt->nt_name, i);
2349753c7e08SAugustin Cavalier #endif
2350753c7e08SAugustin Cavalier IEEE80211_FREE(nt->nt_keyixmap, M_80211_NODE);
2351753c7e08SAugustin Cavalier nt->nt_keyixmap = NULL;
2352753c7e08SAugustin Cavalier }
2353753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK_DESTROY(nt);
2354753c7e08SAugustin Cavalier }
2355753c7e08SAugustin Cavalier
2356753c7e08SAugustin Cavalier static void
timeout_stations(void * arg __unused,struct ieee80211_node * ni)2357753c7e08SAugustin Cavalier timeout_stations(void *arg __unused, struct ieee80211_node *ni)
2358753c7e08SAugustin Cavalier {
2359753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
2360753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
2361753c7e08SAugustin Cavalier
2362753c7e08SAugustin Cavalier /*
2363753c7e08SAugustin Cavalier * Only process stations when in RUN state. This
2364753c7e08SAugustin Cavalier * insures, for example, that we don't timeout an
2365753c7e08SAugustin Cavalier * inactive station during CAC. Note that CSA state
2366753c7e08SAugustin Cavalier * is actually handled in ieee80211_node_timeout as
2367753c7e08SAugustin Cavalier * it applies to more than timeout processing.
2368753c7e08SAugustin Cavalier */
2369753c7e08SAugustin Cavalier if (vap->iv_state != IEEE80211_S_RUN)
2370753c7e08SAugustin Cavalier return;
2371753c7e08SAugustin Cavalier /*
2372753c7e08SAugustin Cavalier * Ignore entries for which have yet to receive an
2373753c7e08SAugustin Cavalier * authentication frame. These are transient and
2374753c7e08SAugustin Cavalier * will be reclaimed when the last reference to them
2375753c7e08SAugustin Cavalier * goes away (when frame xmits complete).
2376753c7e08SAugustin Cavalier */
2377753c7e08SAugustin Cavalier if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
2378753c7e08SAugustin Cavalier vap->iv_opmode == IEEE80211_M_STA) &&
2379753c7e08SAugustin Cavalier (ni->ni_flags & IEEE80211_NODE_AREF) == 0)
2380753c7e08SAugustin Cavalier return;
2381753c7e08SAugustin Cavalier /*
2382753c7e08SAugustin Cavalier * Free fragment if not needed anymore
2383753c7e08SAugustin Cavalier * (last fragment older than 1s).
2384753c7e08SAugustin Cavalier * XXX doesn't belong here, move to node_age
2385753c7e08SAugustin Cavalier */
2386753c7e08SAugustin Cavalier if (ni->ni_rxfrag[0] != NULL &&
2387753c7e08SAugustin Cavalier ticks > ni->ni_rxfragstamp + hz) {
2388753c7e08SAugustin Cavalier m_freem(ni->ni_rxfrag[0]);
2389753c7e08SAugustin Cavalier ni->ni_rxfrag[0] = NULL;
2390753c7e08SAugustin Cavalier }
2391753c7e08SAugustin Cavalier if (ni->ni_inact > 0) {
2392753c7e08SAugustin Cavalier ni->ni_inact--;
2393753c7e08SAugustin Cavalier IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
2394753c7e08SAugustin Cavalier "%s: inact %u inact_reload %u nrates %u",
2395753c7e08SAugustin Cavalier __func__, ni->ni_inact, ni->ni_inact_reload,
2396753c7e08SAugustin Cavalier ni->ni_rates.rs_nrates);
2397753c7e08SAugustin Cavalier }
2398753c7e08SAugustin Cavalier /*
2399753c7e08SAugustin Cavalier * Special case ourself; we may be idle for extended periods
2400753c7e08SAugustin Cavalier * of time and regardless reclaiming our state is wrong.
2401753c7e08SAugustin Cavalier * XXX run ic_node_age
2402753c7e08SAugustin Cavalier */
2403753c7e08SAugustin Cavalier /* XXX before inact decrement? */
2404753c7e08SAugustin Cavalier if (ni == vap->iv_bss)
2405753c7e08SAugustin Cavalier return;
2406753c7e08SAugustin Cavalier if (ni->ni_associd != 0 ||
2407753c7e08SAugustin Cavalier (vap->iv_opmode == IEEE80211_M_IBSS ||
2408753c7e08SAugustin Cavalier vap->iv_opmode == IEEE80211_M_AHDEMO)) {
2409753c7e08SAugustin Cavalier /*
2410753c7e08SAugustin Cavalier * Age/drain resources held by the station.
2411753c7e08SAugustin Cavalier */
2412753c7e08SAugustin Cavalier ic->ic_node_age(ni);
2413753c7e08SAugustin Cavalier /*
2414753c7e08SAugustin Cavalier * Probe the station before time it out. We
2415753c7e08SAugustin Cavalier * send a null data frame which may not be
2416753c7e08SAugustin Cavalier * universally supported by drivers (need it
2417753c7e08SAugustin Cavalier * for ps-poll support so it should be...).
2418753c7e08SAugustin Cavalier *
2419753c7e08SAugustin Cavalier * XXX don't probe the station unless we've
2420753c7e08SAugustin Cavalier * received a frame from them (and have
2421753c7e08SAugustin Cavalier * some idea of the rates they are capable
2422753c7e08SAugustin Cavalier * of); this will get fixed more properly
2423753c7e08SAugustin Cavalier * soon with better handling of the rate set.
2424753c7e08SAugustin Cavalier */
2425753c7e08SAugustin Cavalier if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) &&
2426753c7e08SAugustin Cavalier (0 < ni->ni_inact &&
2427753c7e08SAugustin Cavalier ni->ni_inact <= vap->iv_inact_probe) &&
2428753c7e08SAugustin Cavalier ni->ni_rates.rs_nrates != 0) {
2429753c7e08SAugustin Cavalier IEEE80211_NOTE(vap,
2430753c7e08SAugustin Cavalier IEEE80211_MSG_INACT | IEEE80211_MSG_NODE,
2431753c7e08SAugustin Cavalier ni, "%s",
2432753c7e08SAugustin Cavalier "probe station due to inactivity");
2433753c7e08SAugustin Cavalier /*
2434753c7e08SAugustin Cavalier * Grab a reference so the node cannot
2435753c7e08SAugustin Cavalier * be reclaimed before we send the frame.
2436753c7e08SAugustin Cavalier * ieee80211_send_nulldata understands
2437753c7e08SAugustin Cavalier * we've done this and reclaims the
2438753c7e08SAugustin Cavalier * ref for us as needed.
2439753c7e08SAugustin Cavalier */
2440753c7e08SAugustin Cavalier /* XXX fix this (not required anymore). */
2441753c7e08SAugustin Cavalier ieee80211_ref_node(ni);
2442753c7e08SAugustin Cavalier /* XXX useless */
2443753c7e08SAugustin Cavalier ieee80211_send_nulldata(ni);
2444753c7e08SAugustin Cavalier /* XXX stat? */
2445753c7e08SAugustin Cavalier return;
2446753c7e08SAugustin Cavalier }
2447753c7e08SAugustin Cavalier }
2448753c7e08SAugustin Cavalier if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) &&
2449753c7e08SAugustin Cavalier ni->ni_inact <= 0) {
2450753c7e08SAugustin Cavalier IEEE80211_NOTE(vap,
2451753c7e08SAugustin Cavalier IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni,
2452753c7e08SAugustin Cavalier "station timed out due to inactivity "
2453753c7e08SAugustin Cavalier "(refcnt %u)", ieee80211_node_refcnt(ni));
2454753c7e08SAugustin Cavalier /*
2455753c7e08SAugustin Cavalier * Send a deauthenticate frame and drop the station.
2456753c7e08SAugustin Cavalier * This is somewhat complicated due to reference counts
2457753c7e08SAugustin Cavalier * and locking. At this point a station will typically
2458753c7e08SAugustin Cavalier * have a reference count of 2. ieee80211_node_leave
2459753c7e08SAugustin Cavalier * will do a "free" of the node which will drop the
2460753c7e08SAugustin Cavalier * reference count. But in the meantime a reference
2461753c7e08SAugustin Cavalier * wil be held by the deauth frame. The actual reclaim
2462753c7e08SAugustin Cavalier * of the node will happen either after the tx is
2463753c7e08SAugustin Cavalier * completed or by ieee80211_node_leave.
2464753c7e08SAugustin Cavalier */
2465753c7e08SAugustin Cavalier if (ni->ni_associd != 0) {
2466753c7e08SAugustin Cavalier IEEE80211_SEND_MGMT(ni,
2467753c7e08SAugustin Cavalier IEEE80211_FC0_SUBTYPE_DEAUTH,
2468753c7e08SAugustin Cavalier IEEE80211_REASON_AUTH_EXPIRE);
2469753c7e08SAugustin Cavalier }
2470753c7e08SAugustin Cavalier ieee80211_node_leave(ni);
2471753c7e08SAugustin Cavalier vap->iv_stats.is_node_timeout++;
2472753c7e08SAugustin Cavalier }
2473753c7e08SAugustin Cavalier }
2474753c7e08SAugustin Cavalier
2475753c7e08SAugustin Cavalier /*
2476753c7e08SAugustin Cavalier * Timeout inactive stations and do related housekeeping.
2477753c7e08SAugustin Cavalier */
2478753c7e08SAugustin Cavalier static void
ieee80211_timeout_stations(struct ieee80211com * ic)2479753c7e08SAugustin Cavalier ieee80211_timeout_stations(struct ieee80211com *ic)
2480753c7e08SAugustin Cavalier {
2481753c7e08SAugustin Cavalier struct ieee80211_node_table *nt = &ic->ic_sta;
2482753c7e08SAugustin Cavalier
2483753c7e08SAugustin Cavalier ieee80211_iterate_nodes(nt, timeout_stations, NULL);
2484753c7e08SAugustin Cavalier }
2485753c7e08SAugustin Cavalier
2486753c7e08SAugustin Cavalier /*
2487753c7e08SAugustin Cavalier * Aggressively reclaim resources. This should be used
2488753c7e08SAugustin Cavalier * only in a critical situation to reclaim mbuf resources.
2489753c7e08SAugustin Cavalier */
2490753c7e08SAugustin Cavalier void
ieee80211_drain(struct ieee80211com * ic)2491753c7e08SAugustin Cavalier ieee80211_drain(struct ieee80211com *ic)
2492753c7e08SAugustin Cavalier {
2493753c7e08SAugustin Cavalier struct ieee80211_node_table *nt = &ic->ic_sta;
2494753c7e08SAugustin Cavalier struct ieee80211vap *vap;
2495753c7e08SAugustin Cavalier struct ieee80211_node *ni;
2496753c7e08SAugustin Cavalier
2497753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
2498753c7e08SAugustin Cavalier TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
2499753c7e08SAugustin Cavalier /*
2500753c7e08SAugustin Cavalier * Ignore entries for which have yet to receive an
2501753c7e08SAugustin Cavalier * authentication frame. These are transient and
2502753c7e08SAugustin Cavalier * will be reclaimed when the last reference to them
2503753c7e08SAugustin Cavalier * goes away (when frame xmits complete).
2504753c7e08SAugustin Cavalier */
2505753c7e08SAugustin Cavalier vap = ni->ni_vap;
2506753c7e08SAugustin Cavalier /*
2507753c7e08SAugustin Cavalier * Only process stations when in RUN state. This
2508753c7e08SAugustin Cavalier * insures, for example, that we don't timeout an
2509753c7e08SAugustin Cavalier * inactive station during CAC. Note that CSA state
2510753c7e08SAugustin Cavalier * is actually handled in ieee80211_node_timeout as
2511753c7e08SAugustin Cavalier * it applies to more than timeout processing.
2512753c7e08SAugustin Cavalier */
2513753c7e08SAugustin Cavalier if (vap->iv_state != IEEE80211_S_RUN)
2514753c7e08SAugustin Cavalier continue;
2515753c7e08SAugustin Cavalier /* XXX can vap be NULL? */
2516753c7e08SAugustin Cavalier if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
2517753c7e08SAugustin Cavalier vap->iv_opmode == IEEE80211_M_STA) &&
2518753c7e08SAugustin Cavalier (ni->ni_flags & IEEE80211_NODE_AREF) == 0)
2519753c7e08SAugustin Cavalier continue;
2520753c7e08SAugustin Cavalier /*
2521753c7e08SAugustin Cavalier * Free fragments.
2522753c7e08SAugustin Cavalier * XXX doesn't belong here, move to node_drain
2523753c7e08SAugustin Cavalier */
2524753c7e08SAugustin Cavalier if (ni->ni_rxfrag[0] != NULL) {
2525753c7e08SAugustin Cavalier m_freem(ni->ni_rxfrag[0]);
2526753c7e08SAugustin Cavalier ni->ni_rxfrag[0] = NULL;
2527753c7e08SAugustin Cavalier }
2528753c7e08SAugustin Cavalier /*
2529753c7e08SAugustin Cavalier * Drain resources held by the station.
2530753c7e08SAugustin Cavalier */
2531753c7e08SAugustin Cavalier ic->ic_node_drain(ni);
2532753c7e08SAugustin Cavalier }
2533753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
2534753c7e08SAugustin Cavalier }
2535753c7e08SAugustin Cavalier
2536753c7e08SAugustin Cavalier /*
25375cad57c4SJérôme Duval * Per-ieee80211vap inactivity timer callback.
25385cad57c4SJérôme Duval */
25395cad57c4SJérôme Duval static void
ieee80211_vap_timeout(struct ieee80211vap * vap)25405cad57c4SJérôme Duval ieee80211_vap_timeout(struct ieee80211vap *vap)
25415cad57c4SJérôme Duval {
25425cad57c4SJérôme Duval
25435cad57c4SJérôme Duval IEEE80211_LOCK_ASSERT(vap->iv_ic);
25445cad57c4SJérôme Duval
25455cad57c4SJérôme Duval ieee80211_vap_erp_timeout(vap);
25465cad57c4SJérôme Duval ieee80211_ht_timeout(vap);
25475cad57c4SJérôme Duval ieee80211_vht_timeout(vap);
25485cad57c4SJérôme Duval }
25495cad57c4SJérôme Duval
25505cad57c4SJérôme Duval /*
2551753c7e08SAugustin Cavalier * Per-ieee80211com inactivity timer callback.
2552753c7e08SAugustin Cavalier */
2553753c7e08SAugustin Cavalier void
ieee80211_node_timeout(void * arg)2554753c7e08SAugustin Cavalier ieee80211_node_timeout(void *arg)
2555753c7e08SAugustin Cavalier {
2556753c7e08SAugustin Cavalier struct ieee80211com *ic = arg;
25575cad57c4SJérôme Duval struct ieee80211vap *vap;
2558753c7e08SAugustin Cavalier
2559753c7e08SAugustin Cavalier /*
2560753c7e08SAugustin Cavalier * Defer timeout processing if a channel switch is pending.
2561753c7e08SAugustin Cavalier * We typically need to be mute so not doing things that
2562753c7e08SAugustin Cavalier * might generate frames is good to handle in one place.
2563753c7e08SAugustin Cavalier * Suppressing the station timeout processing may extend the
2564753c7e08SAugustin Cavalier * lifetime of inactive stations (by not decrementing their
2565753c7e08SAugustin Cavalier * idle counters) but this should be ok unless the CSA is
2566753c7e08SAugustin Cavalier * active for an unusually long time.
2567753c7e08SAugustin Cavalier */
2568753c7e08SAugustin Cavalier if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) {
2569753c7e08SAugustin Cavalier ieee80211_scan_timeout(ic);
2570753c7e08SAugustin Cavalier ieee80211_timeout_stations(ic);
2571753c7e08SAugustin Cavalier ieee80211_ageq_age(&ic->ic_stageq, IEEE80211_INACT_WAIT);
2572753c7e08SAugustin Cavalier
2573753c7e08SAugustin Cavalier IEEE80211_LOCK(ic);
25745cad57c4SJérôme Duval TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
25755cad57c4SJérôme Duval ieee80211_vap_timeout(vap);
2576753c7e08SAugustin Cavalier IEEE80211_UNLOCK(ic);
2577753c7e08SAugustin Cavalier }
2578753c7e08SAugustin Cavalier callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
2579753c7e08SAugustin Cavalier ieee80211_node_timeout, ic);
2580753c7e08SAugustin Cavalier }
2581753c7e08SAugustin Cavalier
2582753c7e08SAugustin Cavalier /*
25838244a9baSAugustin Cavalier * The same as ieee80211_iterate_nodes(), but for one vap only.
25848244a9baSAugustin Cavalier */
25858244a9baSAugustin Cavalier int
ieee80211_iterate_nodes_vap(struct ieee80211_node_table * nt,struct ieee80211vap * vap,ieee80211_iter_func * f,void * arg)25868244a9baSAugustin Cavalier ieee80211_iterate_nodes_vap(struct ieee80211_node_table *nt,
25878244a9baSAugustin Cavalier struct ieee80211vap *vap, ieee80211_iter_func *f, void *arg)
25888244a9baSAugustin Cavalier {
25898244a9baSAugustin Cavalier struct ieee80211_node **ni_arr;
25908244a9baSAugustin Cavalier struct ieee80211_node *ni;
25918244a9baSAugustin Cavalier size_t size;
25928244a9baSAugustin Cavalier int count, i;
25938244a9baSAugustin Cavalier
25948244a9baSAugustin Cavalier /*
25958244a9baSAugustin Cavalier * Iterate over the node table and save an array of ref'ed nodes.
2596753c7e08SAugustin Cavalier *
2597753c7e08SAugustin Cavalier * This is separated out from calling the actual node function so that
2598753c7e08SAugustin Cavalier * no LORs will occur.
2599753c7e08SAugustin Cavalier */
2600753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
26018244a9baSAugustin Cavalier count = nt->nt_count;
26028244a9baSAugustin Cavalier size = count * sizeof(struct ieee80211_node *);
26038244a9baSAugustin Cavalier ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE,
26048244a9baSAugustin Cavalier IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
26058244a9baSAugustin Cavalier if (ni_arr == NULL) {
26068244a9baSAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
26078244a9baSAugustin Cavalier return (ENOMEM);
2608753c7e08SAugustin Cavalier }
26098244a9baSAugustin Cavalier
26108244a9baSAugustin Cavalier i = 0;
26118244a9baSAugustin Cavalier TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
26128244a9baSAugustin Cavalier if (vap != NULL && ni->ni_vap != vap)
26138244a9baSAugustin Cavalier continue;
26148244a9baSAugustin Cavalier KASSERT(i < count,
26158244a9baSAugustin Cavalier ("node array overflow (vap %p, i %d, count %d)\n",
26168244a9baSAugustin Cavalier vap, i, count));
2617753c7e08SAugustin Cavalier ni_arr[i] = ieee80211_ref_node(ni);
2618753c7e08SAugustin Cavalier i++;
2619753c7e08SAugustin Cavalier }
2620753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
2621753c7e08SAugustin Cavalier
26228244a9baSAugustin Cavalier for (i = 0; i < count; i++) {
2623753c7e08SAugustin Cavalier if (ni_arr[i] == NULL) /* end of the list */
2624753c7e08SAugustin Cavalier break;
2625753c7e08SAugustin Cavalier (*f)(arg, ni_arr[i]);
2626753c7e08SAugustin Cavalier /* ieee80211_free_node() locks by itself */
2627753c7e08SAugustin Cavalier ieee80211_free_node(ni_arr[i]);
2628753c7e08SAugustin Cavalier }
2629753c7e08SAugustin Cavalier
2630753c7e08SAugustin Cavalier IEEE80211_FREE(ni_arr, M_80211_NODE);
26318244a9baSAugustin Cavalier
26328244a9baSAugustin Cavalier return (0);
26338244a9baSAugustin Cavalier }
26348244a9baSAugustin Cavalier
26358244a9baSAugustin Cavalier /*
26368244a9baSAugustin Cavalier * Just a wrapper, so we don't have to change every ieee80211_iterate_nodes()
26378244a9baSAugustin Cavalier * reference in the source.
26388244a9baSAugustin Cavalier */
26398244a9baSAugustin Cavalier void
ieee80211_iterate_nodes(struct ieee80211_node_table * nt,ieee80211_iter_func * f,void * arg)26408244a9baSAugustin Cavalier ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
26418244a9baSAugustin Cavalier ieee80211_iter_func *f, void *arg)
26428244a9baSAugustin Cavalier {
26438244a9baSAugustin Cavalier /* XXX no way to pass error to the caller. */
26448244a9baSAugustin Cavalier (void) ieee80211_iterate_nodes_vap(nt, NULL, f, arg);
2645753c7e08SAugustin Cavalier }
2646753c7e08SAugustin Cavalier
2647753c7e08SAugustin Cavalier void
ieee80211_dump_node(struct ieee80211_node_table * nt __unused,struct ieee80211_node * ni)2648*86021fd4SAugustin Cavalier ieee80211_dump_node(struct ieee80211_node_table *nt __unused,
2649*86021fd4SAugustin Cavalier struct ieee80211_node *ni)
2650753c7e08SAugustin Cavalier {
2651*86021fd4SAugustin Cavalier printf("%p: mac %s refcnt %d\n", ni,
2652753c7e08SAugustin Cavalier ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni));
2653753c7e08SAugustin Cavalier printf("\tauthmode %u flags 0x%x\n",
2654753c7e08SAugustin Cavalier ni->ni_authmode, ni->ni_flags);
2655753c7e08SAugustin Cavalier printf("\tassocid 0x%x txpower %u vlan %u\n",
2656753c7e08SAugustin Cavalier ni->ni_associd, ni->ni_txpower, ni->ni_vlan);
2657753c7e08SAugustin Cavalier printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n",
2658753c7e08SAugustin Cavalier ni->ni_txseqs[IEEE80211_NONQOS_TID],
2659753c7e08SAugustin Cavalier ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT,
2660753c7e08SAugustin Cavalier ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK,
2661753c7e08SAugustin Cavalier ni->ni_rxfragstamp);
2662753c7e08SAugustin Cavalier printf("\trssi %d noise %d intval %u capinfo 0x%x\n",
2663753c7e08SAugustin Cavalier node_getrssi(ni), ni->ni_noise,
2664753c7e08SAugustin Cavalier ni->ni_intval, ni->ni_capinfo);
2665753c7e08SAugustin Cavalier printf("\tbssid %s essid \"%.*s\" channel %u:0x%x\n",
2666753c7e08SAugustin Cavalier ether_sprintf(ni->ni_bssid),
2667753c7e08SAugustin Cavalier ni->ni_esslen, ni->ni_essid,
2668*86021fd4SAugustin Cavalier (ni->ni_chan != IEEE80211_CHAN_ANYC) ? ni->ni_chan->ic_freq : 0,
2669*86021fd4SAugustin Cavalier (ni->ni_chan != IEEE80211_CHAN_ANYC) ? ni->ni_chan->ic_flags : 0);
2670753c7e08SAugustin Cavalier printf("\tinact %u inact_reload %u txrate %u\n",
2671753c7e08SAugustin Cavalier ni->ni_inact, ni->ni_inact_reload, ni->ni_txrate);
2672753c7e08SAugustin Cavalier printf("\thtcap %x htparam %x htctlchan %u ht2ndchan %u\n",
2673753c7e08SAugustin Cavalier ni->ni_htcap, ni->ni_htparam,
2674753c7e08SAugustin Cavalier ni->ni_htctlchan, ni->ni_ht2ndchan);
26758244a9baSAugustin Cavalier printf("\thtopmode %x htstbc %x htchw %u\n",
2676753c7e08SAugustin Cavalier ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw);
26778244a9baSAugustin Cavalier printf("\tvhtcap %x freq1 %d freq2 %d vhtbasicmcs %x\n",
26788244a9baSAugustin Cavalier ni->ni_vhtcap, (int) ni->ni_vht_chan1, (int) ni->ni_vht_chan2,
26798244a9baSAugustin Cavalier (int) ni->ni_vht_basicmcs);
26808244a9baSAugustin Cavalier /* XXX VHT state */
2681753c7e08SAugustin Cavalier }
2682753c7e08SAugustin Cavalier
2683753c7e08SAugustin Cavalier void
ieee80211_dump_nodes(struct ieee80211_node_table * nt)2684753c7e08SAugustin Cavalier ieee80211_dump_nodes(struct ieee80211_node_table *nt)
2685753c7e08SAugustin Cavalier {
2686753c7e08SAugustin Cavalier ieee80211_iterate_nodes(nt,
2687753c7e08SAugustin Cavalier (ieee80211_iter_func *) ieee80211_dump_node, nt);
2688753c7e08SAugustin Cavalier }
2689753c7e08SAugustin Cavalier
26905cad57c4SJérôme Duval /*
26915cad57c4SJérôme Duval * Iterate over the VAPs and update their ERP beacon IEs.
26925cad57c4SJérôme Duval *
26935cad57c4SJérôme Duval * Note this must be called from the deferred ERP update task paths.
26945cad57c4SJérôme Duval */
26955cad57c4SJérôme Duval void
ieee80211_notify_erp_locked(struct ieee80211com * ic)2696753c7e08SAugustin Cavalier ieee80211_notify_erp_locked(struct ieee80211com *ic)
2697753c7e08SAugustin Cavalier {
2698753c7e08SAugustin Cavalier struct ieee80211vap *vap;
2699753c7e08SAugustin Cavalier
2700753c7e08SAugustin Cavalier IEEE80211_LOCK_ASSERT(ic);
2701753c7e08SAugustin Cavalier
2702753c7e08SAugustin Cavalier TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
2703753c7e08SAugustin Cavalier if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2704753c7e08SAugustin Cavalier ieee80211_beacon_notify(vap, IEEE80211_BEACON_ERP);
2705753c7e08SAugustin Cavalier }
2706753c7e08SAugustin Cavalier
2707753c7e08SAugustin Cavalier /*
2708753c7e08SAugustin Cavalier * Handle a station joining an 11g network.
2709753c7e08SAugustin Cavalier */
2710753c7e08SAugustin Cavalier static void
ieee80211_node_join_11g(struct ieee80211_node * ni)2711753c7e08SAugustin Cavalier ieee80211_node_join_11g(struct ieee80211_node *ni)
2712753c7e08SAugustin Cavalier {
2713753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
27145cad57c4SJérôme Duval struct ieee80211vap *vap = ni->ni_vap;
2715753c7e08SAugustin Cavalier
2716753c7e08SAugustin Cavalier IEEE80211_LOCK_ASSERT(ic);
2717753c7e08SAugustin Cavalier
2718753c7e08SAugustin Cavalier /*
2719753c7e08SAugustin Cavalier * Station isn't capable of short slot time. Bump
2720753c7e08SAugustin Cavalier * the count of long slot time stations and disable
2721753c7e08SAugustin Cavalier * use of short slot time. Note that the actual switch
2722753c7e08SAugustin Cavalier * over to long slot time use may not occur until the
2723753c7e08SAugustin Cavalier * next beacon transmission (per sec. 7.3.1.4 of 11g).
2724753c7e08SAugustin Cavalier */
2725753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
27265cad57c4SJérôme Duval vap->iv_longslotsta++;
2727753c7e08SAugustin Cavalier IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2728753c7e08SAugustin Cavalier "station needs long slot time, count %d",
27295cad57c4SJérôme Duval vap->iv_longslotsta);
27305cad57c4SJérôme Duval /*
27315cad57c4SJérôme Duval * XXX TODO: this may need all VAPs checked!
27325cad57c4SJérôme Duval */
2733753c7e08SAugustin Cavalier if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) {
2734753c7e08SAugustin Cavalier /*
2735753c7e08SAugustin Cavalier * Don't force slot time when switched to turbo
2736753c7e08SAugustin Cavalier * mode as non-ERP stations won't be present; this
2737753c7e08SAugustin Cavalier * need only be done when on the normal G channel.
2738753c7e08SAugustin Cavalier */
27395cad57c4SJérôme Duval ieee80211_vap_set_shortslottime(vap, 0);
2740753c7e08SAugustin Cavalier }
2741753c7e08SAugustin Cavalier }
2742753c7e08SAugustin Cavalier /*
2743753c7e08SAugustin Cavalier * If the new station is not an ERP station
2744753c7e08SAugustin Cavalier * then bump the counter and enable protection
2745753c7e08SAugustin Cavalier * if configured.
2746753c7e08SAugustin Cavalier */
2747753c7e08SAugustin Cavalier if (!ieee80211_iserp_rateset(&ni->ni_rates)) {
27485cad57c4SJérôme Duval vap->iv_nonerpsta++;
2749753c7e08SAugustin Cavalier IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2750753c7e08SAugustin Cavalier "station is !ERP, %d non-ERP stations associated",
27515cad57c4SJérôme Duval vap->iv_nonerpsta);
2752753c7e08SAugustin Cavalier /*
2753753c7e08SAugustin Cavalier * If station does not support short preamble
2754753c7e08SAugustin Cavalier * then we must enable use of Barker preamble.
2755753c7e08SAugustin Cavalier */
2756753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) {
2757753c7e08SAugustin Cavalier IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2758753c7e08SAugustin Cavalier "%s", "station needs long preamble");
27595cad57c4SJérôme Duval vap->iv_flags |= IEEE80211_F_USEBARKER;
27605cad57c4SJérôme Duval vap->iv_flags &= ~IEEE80211_F_SHPREAMBLE;
27615cad57c4SJérôme Duval ieee80211_vap_update_preamble(vap);
2762753c7e08SAugustin Cavalier }
2763753c7e08SAugustin Cavalier /*
2764753c7e08SAugustin Cavalier * If protection is configured and this is the first
2765753c7e08SAugustin Cavalier * indication we should use protection, enable it.
2766753c7e08SAugustin Cavalier */
27675cad57c4SJérôme Duval if (vap->iv_protmode != IEEE80211_PROT_NONE &&
27685cad57c4SJérôme Duval vap->iv_nonerpsta == 1 &&
27695cad57c4SJérôme Duval (vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) {
2770753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
2771753c7e08SAugustin Cavalier "%s: enable use of protection\n", __func__);
27725cad57c4SJérôme Duval vap->iv_flags |= IEEE80211_F_USEPROT;
27735cad57c4SJérôme Duval ieee80211_vap_update_erp_protmode(vap);
2774753c7e08SAugustin Cavalier }
2775753c7e08SAugustin Cavalier } else
2776753c7e08SAugustin Cavalier ni->ni_flags |= IEEE80211_NODE_ERP;
2777753c7e08SAugustin Cavalier }
2778753c7e08SAugustin Cavalier
2779753c7e08SAugustin Cavalier void
ieee80211_node_join(struct ieee80211_node * ni,int resp)2780753c7e08SAugustin Cavalier ieee80211_node_join(struct ieee80211_node *ni, int resp)
2781753c7e08SAugustin Cavalier {
2782753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
2783753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
2784753c7e08SAugustin Cavalier int newassoc;
2785753c7e08SAugustin Cavalier
2786753c7e08SAugustin Cavalier if (ni->ni_associd == 0) {
2787753c7e08SAugustin Cavalier uint16_t aid;
2788753c7e08SAugustin Cavalier
2789753c7e08SAugustin Cavalier KASSERT(vap->iv_aid_bitmap != NULL, ("no aid bitmap"));
2790753c7e08SAugustin Cavalier /*
2791753c7e08SAugustin Cavalier * It would be good to search the bitmap
2792753c7e08SAugustin Cavalier * more efficiently, but this will do for now.
2793753c7e08SAugustin Cavalier */
2794753c7e08SAugustin Cavalier for (aid = 1; aid < vap->iv_max_aid; aid++) {
2795753c7e08SAugustin Cavalier if (!IEEE80211_AID_ISSET(vap, aid))
2796753c7e08SAugustin Cavalier break;
2797753c7e08SAugustin Cavalier }
2798753c7e08SAugustin Cavalier if (aid >= vap->iv_max_aid) {
2799753c7e08SAugustin Cavalier IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_TOOMANY);
2800753c7e08SAugustin Cavalier ieee80211_node_leave(ni);
2801753c7e08SAugustin Cavalier return;
2802753c7e08SAugustin Cavalier }
2803753c7e08SAugustin Cavalier ni->ni_associd = aid | 0xc000;
2804753c7e08SAugustin Cavalier ni->ni_jointime = time_uptime;
2805753c7e08SAugustin Cavalier IEEE80211_LOCK(ic);
2806753c7e08SAugustin Cavalier IEEE80211_AID_SET(vap, ni->ni_associd);
2807753c7e08SAugustin Cavalier vap->iv_sta_assoc++;
2808753c7e08SAugustin Cavalier
2809753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2810753c7e08SAugustin Cavalier ieee80211_ht_node_join(ni);
28118244a9baSAugustin Cavalier if (IEEE80211_IS_CHAN_VHT(ic->ic_bsschan))
28128244a9baSAugustin Cavalier ieee80211_vht_node_join(ni);
2813753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
2814753c7e08SAugustin Cavalier IEEE80211_IS_CHAN_FULL(ic->ic_bsschan))
2815753c7e08SAugustin Cavalier ieee80211_node_join_11g(ni);
2816753c7e08SAugustin Cavalier IEEE80211_UNLOCK(ic);
2817753c7e08SAugustin Cavalier
2818753c7e08SAugustin Cavalier newassoc = 1;
2819753c7e08SAugustin Cavalier } else
2820753c7e08SAugustin Cavalier newassoc = 0;
2821753c7e08SAugustin Cavalier
28228244a9baSAugustin Cavalier /*
28238244a9baSAugustin Cavalier * XXX VHT - should log VHT channel width, etc
28248244a9baSAugustin Cavalier */
2825753c7e08SAugustin Cavalier IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni,
28265cad57c4SJérôme Duval "station associated at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s%s",
2827753c7e08SAugustin Cavalier IEEE80211_NODE_AID(ni),
28285cad57c4SJérôme Duval vap->iv_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long",
28295cad57c4SJérôme Duval vap->iv_flags & IEEE80211_F_SHSLOT ? "short" : "long",
28305cad57c4SJérôme Duval vap->iv_flags & IEEE80211_F_USEPROT ? ", protection" : "",
2831753c7e08SAugustin Cavalier ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
28328244a9baSAugustin Cavalier /* XXX update for VHT string */
2833753c7e08SAugustin Cavalier ni->ni_flags & IEEE80211_NODE_HT ?
2834753c7e08SAugustin Cavalier (ni->ni_chw == 40 ? ", HT40" : ", HT20") : "",
2835753c7e08SAugustin Cavalier ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "",
28365cad57c4SJérôme Duval ni->ni_flags & IEEE80211_NODE_AMSDU ? " (+AMSDU)" : "",
2837753c7e08SAugustin Cavalier ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" :
2838753c7e08SAugustin Cavalier ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "",
2839753c7e08SAugustin Cavalier ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "",
2840753c7e08SAugustin Cavalier IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ?
2841753c7e08SAugustin Cavalier ", fast-frames" : "",
2842753c7e08SAugustin Cavalier IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ?
2843753c7e08SAugustin Cavalier ", turbo" : ""
2844753c7e08SAugustin Cavalier );
2845753c7e08SAugustin Cavalier
2846753c7e08SAugustin Cavalier ieee80211_node_setuptxparms(ni);
2847753c7e08SAugustin Cavalier ieee80211_ratectl_node_init(ni);
2848753c7e08SAugustin Cavalier /* give driver a chance to setup state like ni_txrate */
2849753c7e08SAugustin Cavalier if (ic->ic_newassoc != NULL)
2850753c7e08SAugustin Cavalier ic->ic_newassoc(ni, newassoc);
2851753c7e08SAugustin Cavalier IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_SUCCESS);
2852753c7e08SAugustin Cavalier /* tell the authenticator about new station */
2853753c7e08SAugustin Cavalier if (vap->iv_auth->ia_node_join != NULL)
2854753c7e08SAugustin Cavalier vap->iv_auth->ia_node_join(ni);
2855753c7e08SAugustin Cavalier ieee80211_notify_node_join(ni,
2856753c7e08SAugustin Cavalier resp == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
2857753c7e08SAugustin Cavalier }
2858753c7e08SAugustin Cavalier
2859753c7e08SAugustin Cavalier static void
disable_protection(struct ieee80211vap * vap)28605cad57c4SJérôme Duval disable_protection(struct ieee80211vap *vap)
2861753c7e08SAugustin Cavalier {
28625cad57c4SJérôme Duval struct ieee80211com *ic = vap->iv_ic;
2863753c7e08SAugustin Cavalier
28645cad57c4SJérôme Duval KASSERT(vap->iv_nonerpsta == 0 &&
28655cad57c4SJérôme Duval (vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0,
28665cad57c4SJérôme Duval ("%d non ERP stations, flags 0x%x", vap->iv_nonerpsta,
28675cad57c4SJérôme Duval vap->iv_flags_ext));
28685cad57c4SJérôme Duval
28695cad57c4SJérôme Duval vap->iv_flags &= ~IEEE80211_F_USEPROT;
2870753c7e08SAugustin Cavalier /* XXX verify mode? */
2871753c7e08SAugustin Cavalier if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) {
28725cad57c4SJérôme Duval vap->iv_flags |= IEEE80211_F_SHPREAMBLE;
28735cad57c4SJérôme Duval vap->iv_flags &= ~IEEE80211_F_USEBARKER;
2874753c7e08SAugustin Cavalier }
28755cad57c4SJérôme Duval ieee80211_vap_update_erp_protmode(vap);
28765cad57c4SJérôme Duval ieee80211_vap_update_preamble(vap);
2877753c7e08SAugustin Cavalier }
2878753c7e08SAugustin Cavalier
2879753c7e08SAugustin Cavalier /*
2880753c7e08SAugustin Cavalier * Handle a station leaving an 11g network.
2881753c7e08SAugustin Cavalier */
2882753c7e08SAugustin Cavalier static void
ieee80211_node_leave_11g(struct ieee80211_node * ni)2883753c7e08SAugustin Cavalier ieee80211_node_leave_11g(struct ieee80211_node *ni)
2884753c7e08SAugustin Cavalier {
2885753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
28865cad57c4SJérôme Duval struct ieee80211vap *vap = ni->ni_vap;
2887753c7e08SAugustin Cavalier
2888753c7e08SAugustin Cavalier IEEE80211_LOCK_ASSERT(ic);
2889753c7e08SAugustin Cavalier
2890753c7e08SAugustin Cavalier KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan),
2891753c7e08SAugustin Cavalier ("not in 11g, bss %u:0x%x", ic->ic_bsschan->ic_freq,
2892753c7e08SAugustin Cavalier ic->ic_bsschan->ic_flags));
2893753c7e08SAugustin Cavalier
2894753c7e08SAugustin Cavalier /*
2895753c7e08SAugustin Cavalier * If a long slot station do the slot time bookkeeping.
2896753c7e08SAugustin Cavalier */
2897753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
28985cad57c4SJérôme Duval KASSERT(vap->iv_longslotsta > 0,
28995cad57c4SJérôme Duval ("bogus long slot station count %d", vap->iv_longslotsta));
29005cad57c4SJérôme Duval vap->iv_longslotsta--;
2901753c7e08SAugustin Cavalier IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
2902753c7e08SAugustin Cavalier "long slot time station leaves, count now %d",
29035cad57c4SJérôme Duval vap->iv_longslotsta);
29045cad57c4SJérôme Duval /*
29055cad57c4SJérôme Duval * XXX TODO: this may need all VAPs checked!
29065cad57c4SJérôme Duval */
29075cad57c4SJérôme Duval if (vap->iv_longslotsta == 0) {
2908753c7e08SAugustin Cavalier /*
2909753c7e08SAugustin Cavalier * Re-enable use of short slot time if supported
2910753c7e08SAugustin Cavalier * and not operating in IBSS mode (per spec).
2911753c7e08SAugustin Cavalier */
2912753c7e08SAugustin Cavalier if ((ic->ic_caps & IEEE80211_C_SHSLOT) &&
2913753c7e08SAugustin Cavalier ic->ic_opmode != IEEE80211_M_IBSS) {
2914753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap,
2915753c7e08SAugustin Cavalier IEEE80211_MSG_ASSOC,
2916753c7e08SAugustin Cavalier "%s: re-enable use of short slot time\n",
2917753c7e08SAugustin Cavalier __func__);
29185cad57c4SJérôme Duval ieee80211_vap_set_shortslottime(vap, 1);
2919753c7e08SAugustin Cavalier }
2920753c7e08SAugustin Cavalier }
2921753c7e08SAugustin Cavalier }
2922753c7e08SAugustin Cavalier /*
2923753c7e08SAugustin Cavalier * If a non-ERP station do the protection-related bookkeeping.
2924753c7e08SAugustin Cavalier */
2925753c7e08SAugustin Cavalier if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) {
29265cad57c4SJérôme Duval KASSERT(vap->iv_nonerpsta > 0,
29275cad57c4SJérôme Duval ("bogus non-ERP station count %d", vap->iv_nonerpsta));
29285cad57c4SJérôme Duval vap->iv_nonerpsta--;
2929753c7e08SAugustin Cavalier IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
29305cad57c4SJérôme Duval "non-ERP station leaves, count now %d%s", vap->iv_nonerpsta,
29315cad57c4SJérôme Duval (vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) ?
2932753c7e08SAugustin Cavalier " (non-ERP sta present)" : "");
29335cad57c4SJérôme Duval if (vap->iv_nonerpsta == 0 &&
29345cad57c4SJérôme Duval (vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) {
2935753c7e08SAugustin Cavalier IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
2936753c7e08SAugustin Cavalier "%s: disable use of protection\n", __func__);
29375cad57c4SJérôme Duval disable_protection(vap);
2938753c7e08SAugustin Cavalier }
2939753c7e08SAugustin Cavalier }
2940753c7e08SAugustin Cavalier }
2941753c7e08SAugustin Cavalier
2942753c7e08SAugustin Cavalier /*
2943753c7e08SAugustin Cavalier * Time out presence of an overlapping bss with non-ERP
2944753c7e08SAugustin Cavalier * stations. When operating in hostap mode we listen for
2945753c7e08SAugustin Cavalier * beacons from other stations and if we identify a non-ERP
2946753c7e08SAugustin Cavalier * station is present we enable protection. To identify
2947753c7e08SAugustin Cavalier * when all non-ERP stations are gone we time out this
2948753c7e08SAugustin Cavalier * condition.
2949753c7e08SAugustin Cavalier */
2950753c7e08SAugustin Cavalier static void
ieee80211_vap_erp_timeout(struct ieee80211vap * vap)29515cad57c4SJérôme Duval ieee80211_vap_erp_timeout(struct ieee80211vap *vap)
2952753c7e08SAugustin Cavalier {
2953753c7e08SAugustin Cavalier
29545cad57c4SJérôme Duval IEEE80211_LOCK_ASSERT(vap->iv_ic);
2955753c7e08SAugustin Cavalier
29565cad57c4SJérôme Duval if ((vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) &&
29575cad57c4SJérôme Duval ieee80211_time_after(ticks, vap->iv_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) {
29585cad57c4SJérôme Duval IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
2959753c7e08SAugustin Cavalier "%s", "age out non-ERP sta present on channel");
29605cad57c4SJérôme Duval vap->iv_flags_ext &= ~IEEE80211_FEXT_NONERP_PR;
29615cad57c4SJérôme Duval if (vap->iv_nonerpsta == 0)
29625cad57c4SJérôme Duval disable_protection(vap);
2963753c7e08SAugustin Cavalier }
2964753c7e08SAugustin Cavalier }
2965753c7e08SAugustin Cavalier
2966753c7e08SAugustin Cavalier /*
2967753c7e08SAugustin Cavalier * Handle bookkeeping for station deauthentication/disassociation
2968753c7e08SAugustin Cavalier * when operating as an ap.
2969753c7e08SAugustin Cavalier */
2970753c7e08SAugustin Cavalier void
ieee80211_node_leave(struct ieee80211_node * ni)2971753c7e08SAugustin Cavalier ieee80211_node_leave(struct ieee80211_node *ni)
2972753c7e08SAugustin Cavalier {
2973753c7e08SAugustin Cavalier struct ieee80211com *ic = ni->ni_ic;
2974753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
2975753c7e08SAugustin Cavalier struct ieee80211_node_table *nt = ni->ni_table;
2976753c7e08SAugustin Cavalier
2977753c7e08SAugustin Cavalier IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni,
2978753c7e08SAugustin Cavalier "station with aid %d leaves", IEEE80211_NODE_AID(ni));
2979753c7e08SAugustin Cavalier
2980753c7e08SAugustin Cavalier KASSERT(vap->iv_opmode != IEEE80211_M_STA,
2981753c7e08SAugustin Cavalier ("unexpected operating mode %u", vap->iv_opmode));
2982753c7e08SAugustin Cavalier /*
2983753c7e08SAugustin Cavalier * If node wasn't previously associated all
2984753c7e08SAugustin Cavalier * we need to do is reclaim the reference.
2985753c7e08SAugustin Cavalier */
2986753c7e08SAugustin Cavalier /* XXX ibss mode bypasses 11g and notification */
2987753c7e08SAugustin Cavalier if (ni->ni_associd == 0)
2988753c7e08SAugustin Cavalier goto done;
2989753c7e08SAugustin Cavalier /*
2990753c7e08SAugustin Cavalier * Tell the authenticator the station is leaving.
2991753c7e08SAugustin Cavalier * Note that we must do this before yanking the
2992753c7e08SAugustin Cavalier * association id as the authenticator uses the
2993753c7e08SAugustin Cavalier * associd to locate it's state block.
2994753c7e08SAugustin Cavalier */
2995753c7e08SAugustin Cavalier if (vap->iv_auth->ia_node_leave != NULL)
2996753c7e08SAugustin Cavalier vap->iv_auth->ia_node_leave(ni);
2997753c7e08SAugustin Cavalier
2998753c7e08SAugustin Cavalier IEEE80211_LOCK(ic);
2999753c7e08SAugustin Cavalier IEEE80211_AID_CLR(vap, ni->ni_associd);
3000753c7e08SAugustin Cavalier vap->iv_sta_assoc--;
3001753c7e08SAugustin Cavalier
30028244a9baSAugustin Cavalier if (IEEE80211_IS_CHAN_VHT(ic->ic_bsschan))
30038244a9baSAugustin Cavalier ieee80211_vht_node_leave(ni);
3004753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
3005753c7e08SAugustin Cavalier ieee80211_ht_node_leave(ni);
3006753c7e08SAugustin Cavalier if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) &&
3007753c7e08SAugustin Cavalier IEEE80211_IS_CHAN_FULL(ic->ic_bsschan))
3008753c7e08SAugustin Cavalier ieee80211_node_leave_11g(ni);
3009753c7e08SAugustin Cavalier IEEE80211_UNLOCK(ic);
3010753c7e08SAugustin Cavalier /*
3011753c7e08SAugustin Cavalier * Cleanup station state. In particular clear various
3012753c7e08SAugustin Cavalier * state that might otherwise be reused if the node
3013753c7e08SAugustin Cavalier * is reused before the reference count goes to zero
3014753c7e08SAugustin Cavalier * (and memory is reclaimed).
3015753c7e08SAugustin Cavalier */
3016753c7e08SAugustin Cavalier ieee80211_sta_leave(ni);
3017753c7e08SAugustin Cavalier done:
3018753c7e08SAugustin Cavalier /*
3019753c7e08SAugustin Cavalier * Remove the node from any table it's recorded in and
3020753c7e08SAugustin Cavalier * drop the caller's reference. Removal from the table
3021753c7e08SAugustin Cavalier * is important to insure the node is not reprocessed
3022753c7e08SAugustin Cavalier * for inactivity.
3023753c7e08SAugustin Cavalier */
3024753c7e08SAugustin Cavalier if (nt != NULL) {
3025753c7e08SAugustin Cavalier IEEE80211_NODE_LOCK(nt);
3026753c7e08SAugustin Cavalier node_reclaim(nt, ni);
3027753c7e08SAugustin Cavalier IEEE80211_NODE_UNLOCK(nt);
3028753c7e08SAugustin Cavalier } else
3029753c7e08SAugustin Cavalier ieee80211_free_node(ni);
3030753c7e08SAugustin Cavalier }
3031753c7e08SAugustin Cavalier
3032753c7e08SAugustin Cavalier struct rssiinfo {
3033753c7e08SAugustin Cavalier int rssi_samples;
3034753c7e08SAugustin Cavalier uint32_t rssi_total;
3035753c7e08SAugustin Cavalier };
3036753c7e08SAugustin Cavalier
3037753c7e08SAugustin Cavalier static void
get_hostap_rssi(void * arg,struct ieee80211_node * ni)3038753c7e08SAugustin Cavalier get_hostap_rssi(void *arg, struct ieee80211_node *ni)
3039753c7e08SAugustin Cavalier {
3040753c7e08SAugustin Cavalier struct rssiinfo *info = arg;
3041753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
3042753c7e08SAugustin Cavalier int8_t rssi;
3043753c7e08SAugustin Cavalier
3044753c7e08SAugustin Cavalier /* only associated stations */
3045753c7e08SAugustin Cavalier if (ni->ni_associd == 0)
3046753c7e08SAugustin Cavalier return;
3047753c7e08SAugustin Cavalier rssi = vap->iv_ic->ic_node_getrssi(ni);
3048753c7e08SAugustin Cavalier if (rssi != 0) {
3049753c7e08SAugustin Cavalier info->rssi_samples++;
3050753c7e08SAugustin Cavalier info->rssi_total += rssi;
3051753c7e08SAugustin Cavalier }
3052753c7e08SAugustin Cavalier }
3053753c7e08SAugustin Cavalier
3054753c7e08SAugustin Cavalier static void
get_adhoc_rssi(void * arg,struct ieee80211_node * ni)3055753c7e08SAugustin Cavalier get_adhoc_rssi(void *arg, struct ieee80211_node *ni)
3056753c7e08SAugustin Cavalier {
3057753c7e08SAugustin Cavalier struct rssiinfo *info = arg;
3058753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
3059753c7e08SAugustin Cavalier int8_t rssi;
3060753c7e08SAugustin Cavalier
3061753c7e08SAugustin Cavalier /* only neighbors */
3062753c7e08SAugustin Cavalier /* XXX check bssid */
3063753c7e08SAugustin Cavalier if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
3064753c7e08SAugustin Cavalier return;
3065753c7e08SAugustin Cavalier rssi = vap->iv_ic->ic_node_getrssi(ni);
3066753c7e08SAugustin Cavalier if (rssi != 0) {
3067753c7e08SAugustin Cavalier info->rssi_samples++;
3068753c7e08SAugustin Cavalier info->rssi_total += rssi;
3069753c7e08SAugustin Cavalier }
3070753c7e08SAugustin Cavalier }
3071753c7e08SAugustin Cavalier
3072753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_MESH
3073753c7e08SAugustin Cavalier static void
get_mesh_rssi(void * arg,struct ieee80211_node * ni)3074753c7e08SAugustin Cavalier get_mesh_rssi(void *arg, struct ieee80211_node *ni)
3075753c7e08SAugustin Cavalier {
3076753c7e08SAugustin Cavalier struct rssiinfo *info = arg;
3077753c7e08SAugustin Cavalier struct ieee80211vap *vap = ni->ni_vap;
3078753c7e08SAugustin Cavalier int8_t rssi;
3079753c7e08SAugustin Cavalier
3080753c7e08SAugustin Cavalier /* only neighbors that peered successfully */
3081753c7e08SAugustin Cavalier if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
3082753c7e08SAugustin Cavalier return;
3083753c7e08SAugustin Cavalier rssi = vap->iv_ic->ic_node_getrssi(ni);
3084753c7e08SAugustin Cavalier if (rssi != 0) {
3085753c7e08SAugustin Cavalier info->rssi_samples++;
3086753c7e08SAugustin Cavalier info->rssi_total += rssi;
3087753c7e08SAugustin Cavalier }
3088753c7e08SAugustin Cavalier }
3089753c7e08SAugustin Cavalier #endif /* IEEE80211_SUPPORT_MESH */
3090753c7e08SAugustin Cavalier
3091753c7e08SAugustin Cavalier int8_t
ieee80211_getrssi(struct ieee80211vap * vap)3092753c7e08SAugustin Cavalier ieee80211_getrssi(struct ieee80211vap *vap)
3093753c7e08SAugustin Cavalier {
3094753c7e08SAugustin Cavalier #define NZ(x) ((x) == 0 ? 1 : (x))
3095753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
3096753c7e08SAugustin Cavalier struct rssiinfo info;
3097753c7e08SAugustin Cavalier
3098753c7e08SAugustin Cavalier info.rssi_total = 0;
3099753c7e08SAugustin Cavalier info.rssi_samples = 0;
3100753c7e08SAugustin Cavalier switch (vap->iv_opmode) {
3101753c7e08SAugustin Cavalier case IEEE80211_M_IBSS: /* average of all ibss neighbors */
3102753c7e08SAugustin Cavalier case IEEE80211_M_AHDEMO: /* average of all neighbors */
31038244a9baSAugustin Cavalier ieee80211_iterate_nodes_vap(&ic->ic_sta, vap, get_adhoc_rssi,
31048244a9baSAugustin Cavalier &info);
3105753c7e08SAugustin Cavalier break;
3106753c7e08SAugustin Cavalier case IEEE80211_M_HOSTAP: /* average of all associated stations */
31078244a9baSAugustin Cavalier ieee80211_iterate_nodes_vap(&ic->ic_sta, vap, get_hostap_rssi,
31088244a9baSAugustin Cavalier &info);
3109753c7e08SAugustin Cavalier break;
3110753c7e08SAugustin Cavalier #ifdef IEEE80211_SUPPORT_MESH
3111753c7e08SAugustin Cavalier case IEEE80211_M_MBSS: /* average of all mesh neighbors */
31128244a9baSAugustin Cavalier ieee80211_iterate_nodes_vap(&ic->ic_sta, vap, get_mesh_rssi,
31138244a9baSAugustin Cavalier &info);
3114753c7e08SAugustin Cavalier break;
3115753c7e08SAugustin Cavalier #endif
3116753c7e08SAugustin Cavalier case IEEE80211_M_MONITOR: /* XXX */
3117753c7e08SAugustin Cavalier case IEEE80211_M_STA: /* use stats from associated ap */
3118753c7e08SAugustin Cavalier default:
3119753c7e08SAugustin Cavalier if (vap->iv_bss != NULL)
3120753c7e08SAugustin Cavalier info.rssi_total = ic->ic_node_getrssi(vap->iv_bss);
3121753c7e08SAugustin Cavalier info.rssi_samples = 1;
3122753c7e08SAugustin Cavalier break;
3123753c7e08SAugustin Cavalier }
3124753c7e08SAugustin Cavalier return info.rssi_total / NZ(info.rssi_samples);
3125753c7e08SAugustin Cavalier #undef NZ
3126753c7e08SAugustin Cavalier }
3127753c7e08SAugustin Cavalier
3128753c7e08SAugustin Cavalier void
ieee80211_getsignal(struct ieee80211vap * vap,int8_t * rssi,int8_t * noise)3129753c7e08SAugustin Cavalier ieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise)
3130753c7e08SAugustin Cavalier {
3131753c7e08SAugustin Cavalier
3132753c7e08SAugustin Cavalier if (vap->iv_bss == NULL) /* NB: shouldn't happen */
3133753c7e08SAugustin Cavalier return;
3134753c7e08SAugustin Cavalier vap->iv_ic->ic_node_getsignal(vap->iv_bss, rssi, noise);
3135753c7e08SAugustin Cavalier /* for non-station mode return avg'd rssi accounting */
3136753c7e08SAugustin Cavalier if (vap->iv_opmode != IEEE80211_M_STA)
3137753c7e08SAugustin Cavalier *rssi = ieee80211_getrssi(vap);
3138753c7e08SAugustin Cavalier }
3139