ieee80211_node.c revision 116742
1/*-
2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 *    redistribution must be conditioned upon including a substantially
14 *    similar Disclaimer requirement for further binary redistribution.
15 * 3. Neither the names of the above-listed copyright holders nor the names
16 *    of any contributors may be used to endorse or promote products derived
17 *    from this software without specific prior written permission.
18 *
19 * Alternatively, this software may be distributed under the terms of the
20 * GNU General Public License ("GPL") version 2 as published by the Free
21 * Software Foundation.
22 *
23 * NO WARRANTY
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGES.
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_node.c 116742 2003-06-23 16:55:01Z sam $");
39
40#include "opt_inet.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/mbuf.h>
45#include <sys/malloc.h>
46#include <sys/kernel.h>
47#include <sys/socket.h>
48#include <sys/sockio.h>
49#include <sys/endian.h>
50#include <sys/errno.h>
51#include <sys/bus.h>
52#include <sys/proc.h>
53#include <sys/sysctl.h>
54
55#include <machine/atomic.h>
56
57#include <net/if.h>
58#include <net/if_dl.h>
59#include <net/if_media.h>
60#include <net/if_arp.h>
61#include <net/ethernet.h>
62#include <net/if_llc.h>
63
64#include <net80211/ieee80211_var.h>
65
66#include <net/bpf.h>
67
68#ifdef INET
69#include <netinet/in.h>
70#include <netinet/if_ether.h>
71#endif
72
73static struct ieee80211_node *ieee80211_node_alloc(struct ieee80211com *);
74static void ieee80211_node_free(struct ieee80211com *, struct ieee80211_node *);
75static void ieee80211_node_copy(struct ieee80211com *,
76		struct ieee80211_node *, const struct ieee80211_node *);
77static void ieee80211_setup_node(struct ieee80211com *ic,
78		struct ieee80211_node *ni, u_int8_t *macaddr);
79static void _ieee80211_free_node(struct ieee80211com *,
80		struct ieee80211_node *);
81
82void
83ieee80211_node_attach(struct ifnet *ifp)
84{
85	struct ieee80211com *ic = (void *)ifp;
86
87	/* XXX need unit */
88	mtx_init(&ic->ic_nodelock, ifp->if_name, "802.11 node table", MTX_DEF);
89	TAILQ_INIT(&ic->ic_node);
90	ic->ic_node_alloc = ieee80211_node_alloc;
91	ic->ic_node_free = ieee80211_node_free;
92	ic->ic_node_copy = ieee80211_node_copy;
93	ic->ic_bss = (*ic->ic_node_alloc)(ic);
94	/* XXX KASSERT != NULL? */
95}
96
97void
98ieee80211_node_detach(struct ifnet *ifp)
99{
100	struct ieee80211com *ic = (void *)ifp;
101
102	if (ic->ic_bss != NULL)
103		(*ic->ic_node_free)(ic, ic->ic_bss);
104	ieee80211_free_allnodes(ic);
105	mtx_destroy(&ic->ic_nodelock);
106}
107
108/*
109 * AP scanning support.
110 */
111
112/*
113 * Initialize the active channel set based on the set
114 * of available channels and the current PHY mode.
115 */
116void
117ieee80211_reset_scan(struct ifnet *ifp)
118{
119	struct ieee80211com *ic = (void *)ifp;
120
121	memcpy(ic->ic_chan_scan, ic->ic_chan_active,
122		sizeof(ic->ic_chan_active));
123}
124
125/*
126 * Begin an active scan.
127 */
128void
129ieee80211_begin_scan(struct ifnet *ifp, struct ieee80211_node *ni)
130{
131	struct ieee80211com *ic = (void *)ifp;
132
133	if (ifp->if_flags & IFF_DEBUG)
134		if_printf(ifp, "begin %s scan\n",
135			ic->ic_opmode != IEEE80211_M_HOSTAP ?
136				"active" : "passive");
137
138	ieee80211_reset_scan(ifp);
139	/*
140	 * Flush any previously seen AP's.  Note that this
141	 * assumes we don't act as both an AP and a station,
142	 * otherwise we'll potentially flush state of stations
143	 * associated with us.
144	 */
145	ieee80211_free_allnodes(ic);
146
147	clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, ni->ni_chan));
148	if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
149		ic->ic_flags |= IEEE80211_F_ASCAN;
150		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
151	}
152}
153
154/*
155 * Switch to the next channel marked for scanning.
156 */
157void
158ieee80211_next_scan(struct ifnet *ifp)
159{
160	struct ieee80211com *ic = (void *)ifp;
161	struct ieee80211_channel *chan;
162
163	chan = ic->ic_bss->ni_chan;
164	for (;;) {
165		if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX])
166			chan = &ic->ic_channels[0];
167		if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) {
168			/*
169			 * Honor channels marked passive-only
170			 * during an active scan.
171			 */
172			if ((ic->ic_flags & IEEE80211_F_ASCAN) == 0 ||
173			    (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
174				break;
175		}
176		if (chan == ic->ic_bss->ni_chan) {
177			ieee80211_end_scan(ifp);
178			return;
179		}
180	}
181	clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan));
182	IEEE80211_DPRINTF(("ieee80211_next_scan: chan %d->%d\n",
183	    ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan),
184	    ieee80211_chan2ieee(ic, chan)));
185	ic->ic_bss->ni_chan = chan;
186	ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1);
187}
188
189void
190ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
191{
192	struct ieee80211_node *ni;
193	struct ifnet *ifp = &ic->ic_if;
194
195	ni = ic->ic_bss;
196	if (ifp->if_flags & IFF_DEBUG)
197		if_printf(ifp, "creating ibss\n");
198	ic->ic_flags |= IEEE80211_F_SIBSS;
199	ni->ni_chan = chan;
200	ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
201	IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
202	IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
203	if (ic->ic_opmode == IEEE80211_M_IBSS)
204		ni->ni_bssid[0] |= 0x02;	/* local bit for IBSS */
205	ni->ni_esslen = ic->ic_des_esslen;
206	memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
207	ni->ni_rssi = 0;
208	ni->ni_rstamp = 0;
209	ni->ni_rantenna = 0;
210	memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
211	ni->ni_intval = ic->ic_lintval;
212	ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
213	if (ic->ic_flags & IEEE80211_F_WEPON)
214		ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
215	if (ic->ic_phytype == IEEE80211_T_FH) {
216		ni->ni_fhdwell = 200;	/* XXX */
217		ni->ni_fhindex = 1;
218	}
219	ieee80211_new_state(ifp, IEEE80211_S_RUN, -1);
220}
221
222/*
223 * Complete a scan of potential channels.
224 */
225void
226ieee80211_end_scan(struct ifnet *ifp)
227{
228	struct ieee80211com *ic = (void *)ifp;
229	struct ieee80211_node *ni, *nextbs, *selbs;
230	u_int8_t rate;
231	int i, fail;
232
233	ic->ic_flags &= ~IEEE80211_F_ASCAN;
234	ni = TAILQ_FIRST(&ic->ic_node);
235
236	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
237		/* XXX off stack? */
238		u_char occupied[roundup(IEEE80211_CHAN_MAX, NBBY)];
239		/*
240		 * The passive scan to look for existing AP's completed,
241		 * select a channel to camp on.  Identify the channels
242		 * that already have one or more AP's and try to locate
243		 * an unnoccupied one.  If that fails, pick a random
244		 * channel from the active set.
245		 */
246		for (; ni != NULL; ni = nextbs) {
247			ieee80211_ref_node(ni);
248			nextbs = TAILQ_NEXT(ni, ni_list);
249			setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan));
250			ieee80211_free_node(ic, ni);
251		}
252		for (i = 0; i < IEEE80211_CHAN_MAX; i++)
253			if (isset(ic->ic_chan_active, i) && isclr(occupied, i))
254				break;
255		if (i == IEEE80211_CHAN_MAX) {
256			fail = arc4random() & 3;	/* random 0-3 */
257			for (i = 0; i < IEEE80211_CHAN_MAX; i++)
258				if (isset(ic->ic_chan_active, i) && fail-- == 0)
259					break;
260		}
261		ieee80211_create_ibss(ic, &ic->ic_channels[i]);
262		return;
263	}
264	if (ni == NULL) {
265		IEEE80211_DPRINTF(("%s: no scan candidate\n", __func__));
266  notfound:
267		if (ic->ic_opmode == IEEE80211_M_IBSS &&
268		    (ic->ic_flags & IEEE80211_F_IBSSON) &&
269		    ic->ic_des_esslen != 0) {
270			ieee80211_create_ibss(ic, ic->ic_ibss_chan);
271			return;
272		}
273		/*
274		 * Reset the list of channels to scan and start again.
275		 */
276		ieee80211_reset_scan(ifp);
277		ieee80211_next_scan(ifp);
278		return;
279	}
280	selbs = NULL;
281	if (ifp->if_flags & IFF_DEBUG)
282		if_printf(ifp, "\tmacaddr          bssid         chan  rssi rate ant flag  wep  essid\n");
283	for (; ni != NULL; ni = nextbs) {
284		ieee80211_ref_node(ni);
285		nextbs = TAILQ_NEXT(ni, ni_list);
286		if (ni->ni_fails) {
287			/*
288			 * The configuration of the access points may change
289			 * during my scan.  So delete the entry for the AP
290			 * and retry to associate if there is another beacon.
291			 */
292			if (ni->ni_fails++ > 2)
293				ieee80211_free_node(ic, ni);
294			continue;
295		}
296		fail = 0;
297		if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
298			fail |= 0x01;
299		if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
300		    ni->ni_chan != ic->ic_des_chan)
301			fail |= 0x01;
302		if (ic->ic_opmode == IEEE80211_M_IBSS) {
303			if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
304				fail |= 0x02;
305		} else {
306			if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
307				fail |= 0x02;
308		}
309		if (ic->ic_flags & IEEE80211_F_WEPON) {
310			if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
311				fail |= 0x04;
312		} else {
313			if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
314				fail |= 0x04;
315		}
316		rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO);
317		if (rate & IEEE80211_RATE_BASIC)
318			fail |= 0x08;
319		if (ic->ic_des_esslen != 0 &&
320		    (ni->ni_esslen != ic->ic_des_esslen ||
321		     memcmp(ni->ni_essid, ic->ic_des_essid,
322		     ic->ic_des_esslen != 0)))
323			fail |= 0x10;
324		if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
325		    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
326			fail |= 0x20;
327		if (ifp->if_flags & IFF_DEBUG) {
328			printf(" %c %s", fail ? '-' : '+',
329			    ether_sprintf(ni->ni_macaddr));
330			printf(" %s%c", ether_sprintf(ni->ni_bssid),
331			    fail & 0x20 ? '!' : ' ');
332			printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan),
333				fail & 0x01 ? '!' : ' ');
334			printf(" %+4d", ni->ni_rssi);
335			printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
336			    fail & 0x08 ? '!' : ' ');
337			printf(" %3d", ni->ni_rantenna);
338			printf(" %4s%c",
339			    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
340			    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
341			    "????",
342			    fail & 0x02 ? '!' : ' ');
343			printf(" %3s%c ",
344			    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?
345			    "wep" : "no",
346			    fail & 0x04 ? '!' : ' ');
347			ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
348			printf("%s\n", fail & 0x10 ? "!" : "");
349		}
350		if (!fail) {
351			if (selbs == NULL)
352				selbs = ni;
353			else if (ni->ni_rssi > selbs->ni_rssi) {
354				ieee80211_unref_node(&selbs);
355				selbs = ni;
356			} else
357				ieee80211_unref_node(&ni);
358		} else {
359			ieee80211_unref_node(&ni);
360		}
361	}
362	if (selbs == NULL)
363		goto notfound;
364	(*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
365	if (ic->ic_opmode == IEEE80211_M_IBSS) {
366		ieee80211_fix_rate(ic, ic->ic_bss, IEEE80211_F_DOFRATE |
367		    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
368		if (ic->ic_bss->ni_rates.rs_nrates == 0) {
369			selbs->ni_fails++;
370			ieee80211_unref_node(&selbs);
371			goto notfound;
372		}
373		ieee80211_unref_node(&selbs);
374		ieee80211_new_state(ifp, IEEE80211_S_RUN, -1);
375	} else {
376		ieee80211_unref_node(&selbs);
377		ieee80211_new_state(ifp, IEEE80211_S_AUTH, -1);
378	}
379}
380
381static struct ieee80211_node *
382ieee80211_node_alloc(struct ieee80211com *ic)
383{
384	return malloc(sizeof(struct ieee80211_node), M_DEVBUF,
385		M_NOWAIT | M_ZERO);
386}
387
388static void
389ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
390{
391	free(ni, M_DEVBUF);
392}
393
394static void
395ieee80211_node_copy(struct ieee80211com *ic,
396	struct ieee80211_node *dst, const struct ieee80211_node *src)
397{
398	*dst = *src;
399}
400
401static void
402ieee80211_setup_node(struct ieee80211com *ic,
403	struct ieee80211_node *ni, u_int8_t *macaddr)
404{
405	int hash;
406
407	IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
408	hash = IEEE80211_NODE_HASH(macaddr);
409	ni->ni_refcnt = 1;		/* mark referenced */
410	mtx_lock(&ic->ic_nodelock);
411	TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list);
412	LIST_INSERT_HEAD(&ic->ic_hash[hash], ni, ni_hash);
413	/*
414	 * Note we don't enable the inactive timer when acting
415	 * as a station.  Nodes created in this mode represent
416	 * AP's identified while scanning.  If we time them out
417	 * then several things happen: we can't return the data
418	 * to users to show the list of AP's we encountered, and
419	 * more importantly, we'll incorrectly deauthenticate
420	 * ourself because the inactivity timer will kick us off.
421	 */
422	if (ic->ic_opmode != IEEE80211_M_STA)
423		ic->ic_inact_timer = IEEE80211_INACT_WAIT;
424	mtx_unlock(&ic->ic_nodelock);
425}
426
427struct ieee80211_node *
428ieee80211_alloc_node(struct ieee80211com *ic, u_int8_t *macaddr)
429{
430	struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic);
431	if (ni != NULL)
432		ieee80211_setup_node(ic, ni, macaddr);
433	return ni;
434}
435
436struct ieee80211_node *
437ieee80211_dup_bss(struct ieee80211com *ic, u_int8_t *macaddr)
438{
439	struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic);
440	if (ni != NULL) {
441		memcpy(ni, ic->ic_bss, sizeof(struct ieee80211_node));
442		ieee80211_setup_node(ic, ni, macaddr);
443	}
444	return ni;
445}
446
447struct ieee80211_node *
448ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr)
449{
450	struct ieee80211_node *ni;
451	int hash;
452
453	hash = IEEE80211_NODE_HASH(macaddr);
454	mtx_lock(&ic->ic_nodelock);
455	LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
456		if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
457			atomic_add_int(&ni->ni_refcnt, 1); /* mark referenced */
458			break;
459		}
460	}
461	mtx_unlock(&ic->ic_nodelock);
462	return ni;
463}
464
465/*
466 * Like find but search based on the channel too.
467 */
468struct ieee80211_node *
469ieee80211_lookup_node(struct ieee80211com *ic,
470	u_int8_t *macaddr, struct ieee80211_channel *chan)
471{
472	struct ieee80211_node *ni;
473	int hash;
474
475	hash = IEEE80211_NODE_HASH(macaddr);
476	mtx_lock(&ic->ic_nodelock);
477	LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
478		if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && ni->ni_chan == chan) {
479			atomic_add_int(&ni->ni_refcnt, 1);/* mark referenced */
480			break;
481		}
482	}
483	mtx_unlock(&ic->ic_nodelock);
484	return ni;
485}
486
487static void
488_ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
489{
490	TAILQ_REMOVE(&ic->ic_node, ni, ni_list);
491	LIST_REMOVE(ni, ni_hash);
492	if (TAILQ_EMPTY(&ic->ic_node))
493		ic->ic_inact_timer = 0;
494	(*ic->ic_node_free)(ic, ni);
495}
496
497void
498ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
499{
500	/* XXX need equivalent of atomic_dec_and_test */
501	atomic_subtract_int(&ni->ni_refcnt, 1);
502	if (atomic_cmpset_int(&ni->ni_refcnt, 0, 1)) {
503		mtx_lock(&ic->ic_nodelock);
504		_ieee80211_free_node(ic, ni);
505		mtx_unlock(&ic->ic_nodelock);
506	}
507}
508
509void
510ieee80211_free_allnodes(struct ieee80211com *ic)
511{
512	struct ieee80211_node *ni;
513
514	mtx_lock(&ic->ic_nodelock);
515	while ((ni = TAILQ_FIRST(&ic->ic_node)) != NULL)
516		_ieee80211_free_node(ic, ni);
517	mtx_unlock(&ic->ic_nodelock);
518}
519
520void
521ieee80211_timeout_nodes(struct ieee80211com *ic)
522{
523	struct ieee80211_node *ni, *nextbs;
524
525	mtx_lock(&ic->ic_nodelock);
526	for (ni = TAILQ_FIRST(&ic->ic_node); ni != NULL;) {
527		if (++ni->ni_inact <= IEEE80211_INACT_MAX) {
528			ni = TAILQ_NEXT(ni, ni_list);
529			continue;
530		}
531		/* NB: don't honor reference count */
532		IEEE80211_DPRINTF(("station %s timed out "
533			    "due to inactivity (%u secs)\n",
534			    ether_sprintf(ni->ni_macaddr),
535			    ni->ni_inact));
536		nextbs = TAILQ_NEXT(ni, ni_list);
537		IEEE80211_SEND_MGMT(ic, ni,
538		    IEEE80211_FC0_SUBTYPE_DEAUTH,
539		    IEEE80211_REASON_AUTH_EXPIRE);
540		_ieee80211_free_node(ic, ni);
541		ni = nextbs;
542	}
543	if (!TAILQ_EMPTY(&ic->ic_node))
544		ic->ic_inact_timer = IEEE80211_INACT_WAIT;
545	mtx_unlock(&ic->ic_nodelock);
546}
547
548void
549ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f, void *arg)
550{
551	struct ieee80211_node *ni;
552
553	mtx_lock(&ic->ic_nodelock);
554	TAILQ_FOREACH(ni, &ic->ic_node, ni_list)
555		(*f)(arg, ni);
556	mtx_unlock(&ic->ic_nodelock);
557}
558