summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2005-02-17 18:28:06 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2005-02-17 18:28:06 +0000
commit86f341e75623affacf377939e31182d754a6a584 (patch)
tree962821474198da2e40b249d6aab3cace0c21233e /sys
parent47706ecaf12d67a399225153e56f1d84398bfc5a (diff)
derived from NetBSD:
--- Make the node table into an LRU cache: least-recently used nodes are at the end of the node queue. Change the reference-counting discipline: ni->ni_refcnt indicates how many times net80211 has granted ni to the driver. Every node in the table with ni_refcnt=0 is eligible to be garbage-collected. The mere presence of a node in the table does not any longer indicate its auth/assoc state; nodes have a ni_state variable, now. While I am here, patch ieee80211_find_node_for_beacon to do a "best match" by bssid/ssid/channel, not a "perfect match." This keeps net80211 from caching duplicate nodes in the table. --- ok deraadt@ dlg@, looks good jsg@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/ath.c18
-rw-r--r--sys/dev/ic/atw.c13
-rw-r--r--sys/dev/ic/ral.c24
-rw-r--r--sys/dev/ic/rtw.c16
-rw-r--r--sys/dev/pci/if_ipw.c15
-rw-r--r--sys/dev/pci/if_iwi.c17
-rw-r--r--sys/dev/usb/if_atu.c12
-rw-r--r--sys/net80211/ieee80211.c254
-rw-r--r--sys/net80211/ieee80211.h94
-rw-r--r--sys/net80211/ieee80211_input.c414
-rw-r--r--sys/net80211/ieee80211_ioctl.c11
-rw-r--r--sys/net80211/ieee80211_node.c472
-rw-r--r--sys/net80211/ieee80211_node.h27
-rw-r--r--sys/net80211/ieee80211_output.c19
-rw-r--r--sys/net80211/ieee80211_proto.c6
-rw-r--r--sys/net80211/ieee80211_regdomain.c14
-rw-r--r--sys/net80211/ieee80211_regdomain.h15
-rw-r--r--sys/net80211/ieee80211_var.h27
18 files changed, 944 insertions, 524 deletions
diff --git a/sys/dev/ic/ath.c b/sys/dev/ic/ath.c
index d285edd181d..9afb3eb53ef 100644
--- a/sys/dev/ic/ath.c
+++ b/sys/dev/ic/ath.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ath.c,v 1.6 2005/01/03 19:59:18 jsg Exp $ */
+/* $OpenBSD: ath.c,v 1.7 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ath.c,v 1.37 2004/08/18 21:59:39 dyoung Exp $ */
/*-
@@ -1177,8 +1177,8 @@ ath_start(struct ifnet *ifp)
TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
splx(s);
ifp->if_oerrors++;
- if (ni != NULL && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ if (ni != NULL)
+ ieee80211_release_node(ic, ni);
continue;
}
@@ -2444,10 +2444,7 @@ ath_rx_proc(void *arg, int npending)
* reclamation (e.g. in response to a DEAUTH message)
* so use release_node here instead of unref_node.
*/
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
rx_next:
TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
@@ -2895,8 +2892,7 @@ ath_tx_proc(void *arg, int npending)
* this is a DEAUTH message that was sent and the
* node was timed out due to inactivity.
*/
- if(ni != NULL && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
}
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 0,
bf->bf_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
@@ -2962,11 +2958,11 @@ ath_draintxq(struct ath_softc *sc)
ni = bf->bf_node;
bf->bf_node = NULL;
s = splnet();
- if (ni != NULL && ni != ic->ic_bss) {
+ if (ni != NULL) {
/*
* Reclaim node reference.
*/
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
}
TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
splx(s);
diff --git a/sys/dev/ic/atw.c b/sys/dev/ic/atw.c
index ddf80afe40f..0a32ad5789d 100644
--- a/sys/dev/ic/atw.c
+++ b/sys/dev/ic/atw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atw.c,v 1.28 2005/01/15 05:24:10 brad Exp $ */
+/* $OpenBSD: atw.c,v 1.29 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: atw.c,v 1.69 2004/07/23 07:07:55 dyoung Exp $ */
/*-
@@ -3255,12 +3255,9 @@ atw_rxintr(struct atw_softc *sc)
/*
* The frame may have caused the node to be marked for
* reclamation (e.g. in response to a DEAUTH message)
- * so use free_node here instead of unref_node.
+ * so use release_node here instead of unref_node.
*/
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
}
/* Update the receive pointer. */
@@ -3627,8 +3624,8 @@ atw_start(struct ifnet *ifp)
M_PREPEND(m0, offsetof(struct atw_frame, atw_ihdr), M_DONTWAIT);
- if (ni != NULL && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ if (ni != NULL)
+ ieee80211_release_node(ic, ni);
if (m0 == NULL) {
ifp->if_oerrors++;
diff --git a/sys/dev/ic/ral.c b/sys/dev/ic/ral.c
index 1071b2d9ba7..d7380b5ae55 100644
--- a/sys/dev/ic/ral.c
+++ b/sys/dev/ic/ral.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ral.c,v 1.5 2005/02/17 17:43:31 damien Exp $ */
+/* $OpenBSD: ral.c,v 1.6 2005/02/17 18:28:05 reyk Exp $ */
/*-
* Copyright (c) 2005
@@ -552,8 +552,8 @@ ral_reset_tx_ring(struct ral_softc *sc, struct ral_tx_ring *ring)
data->m = NULL;
}
- if (data->ni != NULL && data->ni != ic->ic_bss) {
- ieee80211_free_node(ic, data->ni);
+ if (data->ni != NULL) {
+ ieee80211_release_node(ic, data->ni);
data->ni = NULL;
}
@@ -596,8 +596,8 @@ ral_free_tx_ring(struct ral_softc *sc, struct ral_tx_ring *ring)
m_freem(data->m);
}
- if (data->ni != NULL && data->ni != ic->ic_bss)
- ieee80211_free_node(ic, data->ni);
+ if (data->ni != NULL)
+ ieee80211_release_node(ic, data->ni);
if (data->map != NULL)
bus_dmamap_destroy(sc->sc_dmat, data->map);
@@ -1030,10 +1030,7 @@ ral_tx_intr(struct ral_softc *sc)
bus_dmamap_unload(sc->sc_dmat, data->map);
m_freem(data->m);
data->m = NULL;
- if (data->ni == ic->ic_bss)
- ieee80211_unref_node(&data->ni);
- else
- ieee80211_free_node(ic, data->ni);
+ ieee80211_release_node(ic, data->ni);
data->ni = NULL;
/* descriptor is no longer valid */
@@ -1101,10 +1098,7 @@ ral_prio_intr(struct ral_softc *sc)
bus_dmamap_unload(sc->sc_dmat, data->map);
m_freem(data->m);
data->m = NULL;
- if (data->ni == ic->ic_bss)
- ieee80211_unref_node(&data->ni);
- else
- ieee80211_free_node(ic, data->ni);
+ ieee80211_release_node(ic, data->ni);
data->ni = NULL;
/* descriptor is no longer valid */
@@ -1757,8 +1751,8 @@ ral_start(struct ifnet *ifp)
bpf_mtap(ic->ic_rawbpf, m0);
#endif
if (ral_tx_data(sc, m0, ni) != 0) {
- if (ni != NULL && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ if (ni != NULL)
+ ieee80211_release_node(ic, ni);
break;
}
}
diff --git a/sys/dev/ic/rtw.c b/sys/dev/ic/rtw.c
index 555ad4730db..de567dacc1a 100644
--- a/sys/dev/ic/rtw.c
+++ b/sys/dev/ic/rtw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtw.c,v 1.16 2005/02/14 12:49:29 jsg Exp $ */
+/* $OpenBSD: rtw.c,v 1.17 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: rtw.c,v 1.29 2004/12/27 19:49:16 dyoung Exp $ */
/*-
* Copyright (c) 2004, 2005 David Young. All rights reserved.
@@ -1234,7 +1234,6 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
struct rtw_rxdesc_blk *rdb;
struct mbuf *m;
- struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
struct ieee80211_frame *wh;
@@ -1393,10 +1392,7 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
#endif /* RTW_DEBUG */
ieee80211_input(&sc->sc_if, m, ni, rssi, htsftl);
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(&sc->sc_ic, ni);
+ ieee80211_release_node(&sc->sc_ic, ni);
next:
rtw_rxdesc_init(rdb, rs, next, 0);
}
@@ -1426,10 +1422,7 @@ rtw_txsoft_release(bus_dma_tag_t dmat, struct ieee80211com *ic,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(dmat, ts->ts_dmamap);
m_freem(m);
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
}
void
@@ -3003,8 +2996,7 @@ post_load_err:
bus_dmamap_unload(sc->sc_dmat, dmamap);
m_freem(m0);
post_dequeue_err:
- if (ni != ic->ic_bss)
- ieee80211_free_node(&sc->sc_ic, ni);
+ ieee80211_release_node(&sc->sc_ic, ni);
return;
}
diff --git a/sys/dev/pci/if_ipw.c b/sys/dev/pci/if_ipw.c
index bc8d3bbb5d4..a15981c12ae 100644
--- a/sys/dev/pci/if_ipw.c
+++ b/sys/dev/pci/if_ipw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ipw.c,v 1.39 2005/01/13 20:52:13 damien Exp $ */
+/* $OpenBSD: if_ipw.c,v 1.40 2005/02/17 18:28:05 reyk Exp $ */
/*-
* Copyright (c) 2004, 2005
@@ -939,10 +939,7 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
/* Send the frame to the upper layer */
ieee80211_input(ifp, m, ni, status->rssi, 0);
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
@@ -1060,8 +1057,8 @@ ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd)
m_freem(sbuf->m);
- if (sbuf->ni != NULL && sbuf->ni != ic->ic_bss)
- ieee80211_free_node(ic, sbuf->ni);
+ if (sbuf->ni != NULL)
+ ieee80211_release_node(ic, sbuf->ni);
/* kill watchdog timer */
sc->sc_tx_timer = 0;
@@ -1385,8 +1382,8 @@ ipw_start(struct ifnet *ifp)
#endif
if (ipw_tx_start(ifp, m, ni) != 0) {
- if (ni != NULL && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ if (ni != NULL)
+ ieee80211_release_node(ic, ni);
break;
}
diff --git a/sys/dev/pci/if_iwi.c b/sys/dev/pci/if_iwi.c
index 7e133400056..437f8e675f6 100644
--- a/sys/dev/pci/if_iwi.c
+++ b/sys/dev/pci/if_iwi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwi.c,v 1.24 2005/01/09 16:47:50 damien Exp $ */
+/* $OpenBSD: if_iwi.c,v 1.25 2005/02/17 18:28:05 reyk Exp $ */
/*-
* Copyright (c) 2004, 2005
@@ -795,10 +795,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i,
/* Send the frame to the upper layer */
ieee80211_input(ifp, m, ni, IWI_RSSIDBM2RAW(frame->rssi_dbm), 0);
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
MGETHDR(buf->m, M_DONTWAIT, MT_DATA);
if (buf->m == NULL) {
@@ -971,8 +968,7 @@ iwi_tx_intr(struct iwi_softc *sc)
bus_dmamap_unload(sc->sc_dmat, buf->map);
m_freem(buf->m);
buf->m = NULL;
- if (buf->ni != ic->ic_bss)
- ieee80211_free_node(ic, buf->ni);
+ ieee80211_release_node(ic, buf->ni);
buf->ni = NULL;
sc->tx_queued--;
@@ -1221,8 +1217,8 @@ iwi_start(struct ifnet *ifp)
#endif
if (iwi_tx_start(ifp, m0, ni) != 0) {
- if (ni != NULL && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ if (ni != NULL)
+ ieee80211_release_node(ic, ni);
break;
}
@@ -2003,8 +1999,7 @@ iwi_stop(struct ifnet *ifp, int disable)
buf->m = NULL;
if (buf->ni != NULL) {
- if (buf->ni != ic->ic_bss)
- ieee80211_free_node(ic, buf->ni);
+ ieee80211_release_node(ic, buf->ni);
buf->ni = NULL;
}
}
diff --git a/sys/dev/usb/if_atu.c b/sys/dev/usb/if_atu.c
index a1b3bc97a38..7394b031268 100644
--- a/sys/dev/usb/if_atu.c
+++ b/sys/dev/usb/if_atu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_atu.c,v 1.50 2005/01/26 13:05:49 dlg Exp $ */
+/* $OpenBSD: if_atu.c,v 1.51 2005/02/17 18:28:05 reyk Exp $ */
/*
* Copyright (c) 2003, 2004
* Daan Vreeken <Danovitsch@Vitsch.net>. All rights reserved.
@@ -1635,10 +1635,7 @@ atu_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
ieee80211_input(ifp, m, ni, h->rssi, UGETDW(h->rx_time));
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
done1:
splx(s);
done:
@@ -1867,9 +1864,8 @@ bad:
cd->atu_tx_inuse--;
splx(s);
/* ifp_if_oerrors++; */
- if (ni != NULL && ni != ic->ic_bss)
- /* reclaim node */
- ieee80211_free_node(ic, ni);
+ if (ni != NULL)
+ ieee80211_release_node(ic, ni);
continue;
}
ifp->if_timer = 5;
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index db9b4d7d610..20af2f2d2ea 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211.c,v 1.3 2004/11/03 20:42:41 claudio Exp $ */
+/* $OpenBSD: ieee80211.c,v 1.4 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */
/*-
@@ -107,13 +107,29 @@ SYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug,
#endif
#endif
-int ieee80211_inact_max = IEEE80211_INACT_MAX;
+int ieee80211_cache_size = IEEE80211_CACHE_SIZE;
#ifdef __NetBSD__
-static int ieee80211_inact_max_nodenum;
+static int ieee80211_cache_size_nodenum;
#endif
+struct ieee80211com_head ieee80211com_head =
+ LIST_HEAD_INITIALIZER(ieee80211com_head);
+
static void ieee80211_setbasicrates(struct ieee80211com *);
+#ifdef __NetBSD__
+static void sysctl_ieee80211_fill_node(struct ieee80211_node *,
+ struct ieee80211_node_sysctl *, int, struct ieee80211_channel *, int);
+static struct ieee80211_node *ieee80211_node_walknext(
+ struct ieee80211_node_walk *);
+static struct ieee80211_node *ieee80211_node_walkfirst(
+ struct ieee80211_node_walk *, u_short);
+static int sysctl_ieee80211_verify(SYSCTLFN_ARGS);
+static int sysctl_ieee80211_node(SYSCTLFN_ARGS);
+#endif /* __NetBSD__ */
+
+#define LOGICALLY_EQUAL(x, y) (!(x) == !(y))
+
#if 0
static const char *ieee80211_phymode_name[] = {
"auto", /* IEEE80211_MODE_AUTO */
@@ -193,6 +209,7 @@ ieee80211_ifattach(struct ifnet *ifp)
ic->ic_lintval = 100; /* default sleep */
ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */
+ LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
ieee80211_node_attach(ifp);
ieee80211_proto_attach(ifp);
}
@@ -205,6 +222,7 @@ ieee80211_ifdetach(struct ifnet *ifp)
ieee80211_proto_detach(ifp);
ieee80211_crypto_detach(ifp);
ieee80211_node_detach(ifp);
+ LIST_REMOVE(ic, ic_list);
#ifdef __FreeBSD__
ifmedia_removeall(&ic->ic_media);
#else
@@ -395,9 +413,6 @@ ieee80211_media_init(struct ifnet *ifp,
if (maxrate)
ifp->if_baudrate = IF_Mbps(maxrate);
- if (ic->ic_max_aid == 0)
- ic->ic_max_aid = IEEE80211_MAX_AID;
-
#undef ADD
}
@@ -631,10 +646,8 @@ ieee80211_watchdog(struct ifnet *ifp)
if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- if (ic->ic_inact_timer && --ic->ic_inact_timer == 0)
- ieee80211_timeout_nodes(ic);
- if (ic->ic_mgt_timer != 0 || ic->ic_inact_timer != 0)
+ if (ic->ic_mgt_timer != 0)
ifp->if_timer = 1;
}
@@ -765,9 +778,15 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
*
* XXX what if we have stations already associated???
* XXX probably not right for autoselect?
+ *
+ * Short preamble is not interoperable with legacy .11b
+ * equipment, so it should not be the default for b or
+ * mixed b/g networks. -dcy
*/
+#if 0
if (ic->ic_caps & IEEE80211_C_SHPREAMBLE)
ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
+#endif
if (mode == IEEE80211_MODE_11G) {
if (ic->ic_caps & IEEE80211_C_SHSLOT)
ic->ic_flags |= IEEE80211_F_SHSLOT;
@@ -926,6 +945,16 @@ ieee80211_media2rate(int mword)
}
#ifdef __NetBSD__
+static void
+ieee80211_clean_all_nodes(int cache_size)
+{
+ struct ieee80211com *ic;
+ LIST_FOREACH(ic, &ieee80211com_head, ic_list) {
+ ic->ic_max_nnodes = cache_size;
+ ieee80211_clean_nodes(ic);
+ }
+}
+
/* TBD factor with sysctl_ath_verify. */
static int
sysctl_ieee80211_verify(SYSCTLFN_ARGS)
@@ -940,19 +969,14 @@ sysctl_ieee80211_verify(SYSCTLFN_ARGS)
if (error || newp == NULL)
return (error);
- IEEE80211_DPRINTF(("%s: t = %d, nodenum = %d, rnodenum = %d\n",
- __func__, t, node.sysctl_num, rnode->sysctl_num));
-
- if (node.sysctl_num == ieee80211_inact_max_nodenum) {
- if (t < 1)
+ if (node.sysctl_num == ieee80211_cache_size_nodenum) {
+ if (t < 0)
return (EINVAL);
- t = roundup(t, IEEE80211_INACT_WAIT) / IEEE80211_INACT_WAIT;
#ifdef IEEE80211_DEBUG
- } else if (node.sysctl_num == ieee80211_debug_nodenum) {
- if (t < 0 || t > 2)
- return (EINVAL);
-#endif /* IEEE80211_DEBUG */
+ } else if (node.sysctl_num != ieee80211_debug_nodenum)
+#else /* IEEE80211_DEBUG */
} else
+#endif /* IEEE80211_DEBUG */
return (EINVAL);
*(int*)rnode->sysctl_data = t;
@@ -961,6 +985,185 @@ sysctl_ieee80211_verify(SYSCTLFN_ARGS)
}
/*
+ * Pointers for testing:
+ *
+ * If there are no interfaces, or else no 802.11 interfaces,
+ * ieee80211_node_walkfirst must return NULL.
+ *
+ * If there is any single 802.11 interface, ieee80211_node_walkfirst
+ * must not return NULL.
+ */
+static struct ieee80211_node *
+ieee80211_node_walkfirst(struct ieee80211_node_walk *nw,
+ u_short if_index)
+{
+ struct ieee80211com *ic;
+ (void)memset(nw, 0, sizeof(*nw));
+
+ nw->nw_ifindex = if_index;
+
+ LIST_FOREACH(ic, &ieee80211com_head, ic_list) {
+ if (if_index != 0 && ic->ic_if.if_index != if_index)
+ continue;
+ nw->nw_ic = ic;
+ nw->nw_ni = ic->ic_bss;
+ break;
+ }
+
+ KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
+
+ return nw->nw_ni;
+}
+
+static struct ieee80211_node *
+ieee80211_node_walknext(struct ieee80211_node_walk *nw)
+{
+ KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
+
+ if (nw->nw_ic == NULL && nw->nw_ni == NULL)
+ return NULL;
+
+ if (nw->nw_ni == nw->nw_ic->ic_bss)
+ nw->nw_ni = TAILQ_FIRST(&nw->nw_ic->ic_node);
+ else
+ nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list);
+
+ if (nw->nw_ni == NULL) {
+ if (nw->nw_ifindex != 0)
+ return NULL;
+
+ nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list);
+ if (nw->nw_ic == NULL)
+ return NULL;
+
+ nw->nw_ni = nw->nw_ic->ic_bss;
+ }
+
+ KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
+
+ return nw->nw_ni;
+}
+
+static void
+sysctl_ieee80211_fill_node(struct ieee80211_node *ni,
+ struct ieee80211_node_sysctl *ns, int ifindex,
+ struct ieee80211_channel *chan0, int is_bss)
+{
+ ns->ns_ifindex = ifindex;
+ ns->ns_capinfo = ni->ni_capinfo;
+ ns->ns_flags = (is_bss) ? IEEE80211_NODE_SYSCTL_F_BSS : 0;
+ (void)memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr));
+ (void)memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid));
+ if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
+ ns->ns_freq = ni->ni_chan->ic_freq;
+ ns->ns_chanflags = ni->ni_chan->ic_flags;
+ ns->ns_chanidx = ni->ni_chan - chan0;
+ } else {
+ ns->ns_freq = ns->ns_chanflags = 0;
+ ns->ns_chanidx = 0;
+ }
+ ns->ns_rssi = ni->ni_rssi;
+ ns->ns_esslen = ni->ni_esslen;
+ (void)memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid));
+ ns->ns_pwrsave = ni->ni_pwrsave;
+ ns->ns_erp = ni->ni_erp;
+ ns->ns_associd = ni->ni_associd;
+ ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT;
+ ns->ns_rstamp = ni->ni_rstamp;
+ ns->ns_rates = ni->ni_rates;
+ ns->ns_txrate = ni->ni_txrate;
+ ns->ns_intval = ni->ni_intval;
+ (void)memcpy(ns->ns_tstamp, ni->ni_tstamp, sizeof(ns->ns_tstamp));
+ ns->ns_txseq = ni->ni_txseq;
+ ns->ns_rxseq = ni->ni_rxseq;
+ ns->ns_fhdwell = ni->ni_fhdwell;
+ ns->ns_fhindex = ni->ni_fhindex;
+ ns->ns_fails = ni->ni_fails;
+}
+
+/* Between two examinations of the sysctl tree, I expect each
+ * interface to add no more than 5 nodes.
+ */
+#define IEEE80211_SYSCTL_NODE_GROWTH 5
+
+static int
+sysctl_ieee80211_node(SYSCTLFN_ARGS)
+{
+ struct ieee80211_node_walk nw;
+ struct ieee80211_node *ni;
+ struct ieee80211_node_sysctl ns;
+ char *dp;
+ u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type;
+ size_t len, needed, eltsize, out_size;
+ int error, s, nelt;
+
+ if (namelen == 1 && name[0] == CTL_QUERY)
+ return (sysctl_query(SYSCTLFN_CALL(rnode)));
+
+ if (namelen != IEEE80211_SYSCTL_NODENAMELEN)
+ return (EINVAL);
+
+ /* ifindex.op.arg.header-type.eltsize.nelt */
+ dp = oldp;
+ len = (oldp != NULL) ? *oldlenp : 0;
+ ifindex = name[IEEE80211_SYSCTL_NODENAME_IF];
+ op = name[IEEE80211_SYSCTL_NODENAME_OP];
+ arg = name[IEEE80211_SYSCTL_NODENAME_ARG];
+ hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE];
+ eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE];
+ nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT];
+ out_size = MIN(sizeof(ns), eltsize);
+
+ if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 ||
+ hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0)
+ return (EINVAL);
+
+ error = 0;
+ needed = 0;
+ ifcount = 0;
+ last_ifindex = 0;
+
+ s = splnet();
+
+ for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL;
+ ni = ieee80211_node_walknext(&nw)) {
+ struct ieee80211com *ic;
+
+ ic = nw.nw_ic;
+ cur_ifindex = ic->ic_if.if_index;
+
+ if (cur_ifindex != last_ifindex) {
+ ifcount++;
+ last_ifindex = cur_ifindex;
+ }
+
+ if (nelt <= 0)
+ continue;
+
+ if (len >= eltsize) {
+ sysctl_ieee80211_fill_node(ni, &ns, cur_ifindex,
+ &ic->ic_channels[0], ni == ic->ic_bss);
+ error = copyout(&ns, dp, out_size);
+ if (error)
+ goto cleanup;
+ dp += eltsize;
+ len -= eltsize;
+ }
+ needed += eltsize;
+ if (nelt != INT_MAX)
+ nelt--;
+ }
+cleanup:
+ splx(s);
+
+ *oldlenp = needed;
+ if (oldp == NULL)
+ *oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize;
+
+ return (error);
+}
+
+/*
* Setup sysctl(3) MIB, net.ieee80211.*
*
* TBD condition CTLFLAG_PERMANENT on being an LKM or not
@@ -987,6 +1190,11 @@ SYSCTL_SETUP(sysctl_ieee80211, "sysctl ieee80211 subtree setup")
NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
goto err;
+ if ((rc = sysctl_createv(clog, 0, &rnode, NULL,
+ CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations",
+ sysctl_ieee80211_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
+ goto err;
+
#ifdef IEEE80211_DEBUG
/* control debugging printfs */
@@ -1001,15 +1209,15 @@ SYSCTL_SETUP(sysctl_ieee80211, "sysctl ieee80211 subtree setup")
#endif /* IEEE80211_DEBUG */
- /* control inactivity timer */
+ /* control LRU cache size */
if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
- "maxinact", SYSCTL_DESCR("Station inactivity timeout"),
- sysctl_ieee80211_verify, 0, &ieee80211_inact_max,
+ "maxnodecache", SYSCTL_DESCR("Maximum station cache size"),
+ sysctl_ieee80211_verify, 0, &ieee80211_cache_size,
0, CTL_CREATE, CTL_EOL)) != 0)
goto err;
- ieee80211_inact_max_nodenum = cnode->sysctl_num;
+ ieee80211_cache_size_nodenum = cnode->sysctl_num;
return;
err:
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h
index a6a4c116981..92f01513b51 100644
--- a/sys/net80211/ieee80211.h
+++ b/sys/net80211/ieee80211.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211.h,v 1.7 2004/12/30 23:32:55 reyk Exp $ */
+/* $OpenBSD: ieee80211.h,v 1.8 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $ */
/*-
@@ -124,6 +124,19 @@ struct ieee80211_mnf {
#define MNF_SETUP_RESP 1
#define MNF_TEARDOWN 2
+ /*
+ * WME/802.11e information element.
+ */
+struct ieee80211_ie_wme {
+ u_int8_t wme_id; /* IEEE80211_ELEMID_VENDOR */
+ u_int8_t wme_len; /* length in bytes */
+ u_int8_t wme_oui[3]; /* 0x00, 0x50, 0xf2 */
+ u_int8_t wme_type; /* OUI type */
+ u_int8_t wme_subtype; /* OUI subtype */
+ u_int8_t wme_version; /* spec revision */
+ u_int8_t wme_info; /* AC info */
+} __packed;
+
/*
* WME/802.11e Tspec Element
*/
@@ -280,7 +293,7 @@ struct ieee80211_frame_cfend { /* NB: also CF-End+CF-Ack */
* octet information[length]
*/
-typedef uint8_t *ieee80211_mgt_beacon_t;
+typedef u_int8_t *ieee80211_mgt_beacon_t;
#define IEEE80211_BEACON_INTERVAL(beacon) \
((beacon)[8] | ((beacon)[9] << 8))
@@ -309,6 +322,8 @@ typedef uint8_t *ieee80211_mgt_beacon_t;
* 802.11i/WPA information element (maximally sized).
*/
struct ieee80211_ie_wpa {
+ u_int8_t wpa_id; /* IEEE80211_ELEMID_VENDOR */
+ u_int8_t wpa_len; /* length in bytes */
u_int8_t wpa_oui[3]; /* 0x00, 0x50, 0xf2 */
u_int8_t wpa_type; /* OUI type */
u_int16_t wpa_version; /* spec revision */
@@ -317,12 +332,15 @@ struct ieee80211_ie_wpa {
u_int32_t wpa_uciphers[8];/* ciphers */
u_int16_t wpa_authselcnt; /* authentication selector cnt*/
u_int32_t wpa_authsels[8];/* selectors */
+ u_int16_t wpa_caps; /* 802.11i capabilities */
+ u_int16_t wpa_pmkidcnt; /* 802.11i pmkid count */
+ u_int16_t wpa_pmkids[8]; /* 802.11i pmkids */
} __packed;
/*
- * Management information elements
+ * Management information element payloads
*/
-struct ieee80211_information {
+union ieee80211_information {
char ssid[IEEE80211_NWID_LEN+1];
struct rates {
u_int8_t *p;
@@ -369,7 +387,6 @@ struct ieee80211_information {
struct ath {
u_int8_t flags;
} ath;
- struct ieee80211_ie_wpa wpa;
};
enum {
@@ -384,6 +401,7 @@ enum {
IEEE80211_ELEMID_CHALLENGE = 16,
/* 17-31 reserved for challenge text extension */
IEEE80211_ELEMID_ERP = 42,
+ IEEE80211_ELEMID_RSN = 48,
IEEE80211_ELEMID_XRATES = 50,
IEEE80211_ELEMID_TPC = 150,
IEEE80211_ELEMID_CCKM = 156,
@@ -426,6 +444,30 @@ enum {
#define WPA_ASE_8021X_UNSPEC 0x01
#define WPA_ASE_8021X_PSK 0x02
+#define RSN_OUI 0xac0f00
+#define RSN_OUI_VERSION 1 /* current supported version */
+
+#define RSN_CSE_NULL 0x00
+#define RSN_CSE_WEP40 0x01
+#define RSN_CSE_TKIP 0x02
+#define RSN_CSE_WRAP 0x03
+#define RSN_CSE_CCMP 0x04
+#define RSN_CSE_WEP104 0x05
+
+#define RSN_ASE_NONE 0x00
+#define RSN_ASE_8021X_UNSPEC 0x01
+#define RSN_ASE_8021X_PSK 0x02
+
+#define WME_OUI 0xf25000
+#define WME_OUI_TYPE 0x02
+#define WME_OUI_VERSION 1
+
+/* WME stream classes */
+#define WME_AC_BE 0 /* best effort */
+#define WME_AC_BK 1 /* background */
+#define WME_AC_VI 2 /* video */
+#define WME_AC_VO 3 /* voice */
+
/*
* AUTH management packets
*
@@ -517,6 +559,17 @@ enum {
IEEE80211_WEP_CRCLEN)
/*
+ * 802.11i defines an extended IV for use with non-WEP ciphers.
+ * When the EXTIV bit is set in the key id byte an additional
+ * 4 bytes immediately follow the IV for TKIP. For CCMP the
+ * EXTIV bit is likewise set but the 8 bytes represent the
+ * CCMP header rather than IV+extended-IV.
+ */
+#define IEEE80211_WEP_EXTIV 0x20
+#define IEEE80211_WEP_EXTIVLEN 4 /* extended IV length */
+#define IEEE80211_WEP_MICLEN 8 /* trailing MIC */
+
+/*
* Maximum acceptable MTU is:
* IEEE80211_MAX_LEN - WEP overhead - CRC -
* QoS overhead - RSN/WPA overhead
@@ -528,17 +581,28 @@ enum {
#define IEEE80211_MAX_LEN (2300 + IEEE80211_CRC_LEN + \
(IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN))
+#define IEEE80211_ACK_LEN \
+ (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
#define IEEE80211_MIN_LEN \
(sizeof(struct ieee80211_frame_min) + IEEE80211_CRC_LEN)
-#define IEEE80211_MAX_AID 2007
-
+/*
+ * The 802.11 spec says at most 2007 stations may be
+ * associated at once. For most AP's this is way more
+ * than is feasible so we use a default of 1800. This
+ * number may be overridden by the driver and/or by
+ * user configuration.
+ */
+#define IEEE80211_AID_MAX 2007
+#define IEEE80211_AID_DEF 1800
+
+#define IEEE80211_AID(b) ((b) &~ 0xc000)
#define IEEE80211_AID_SET(b, w) \
- ((w)[((b) & ~0xc000) / 32] |= (1 << (((b) & ~0xc000) % 32)))
+ ((w)[IEEE80211_AID(b) / 32] |= (1 << (IEEE80211_AID(b) % 32)))
#define IEEE80211_AID_CLR(b, w) \
- ((w)[((b) & ~0xc000) / 32] &= ~(1 << (((b) & ~0xc000) % 32)))
+ ((w)[IEEE80211_AID(b) / 32] &= ~(1 << (IEEE80211_AID(b) % 32)))
#define IEEE80211_AID_ISSET(b, w) \
- ((w)[((b) & ~0xc000) / 32] & (1 << (((b) & ~0xc000) % 32)))
+ ((w)[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32)))
/*
* RTS frame length parameters. The default is specified in
@@ -588,8 +652,14 @@ struct ieee80211_duration {
enum {
IEEE80211_AUTH_NONE = 0,
- IEEE80211_AUTH_OPEN = 1,
- IEEE80211_AUTH_SHARED = 2
+ IEEE80211_AUTH_OPEN = 1, /* open */
+ IEEE80211_AUTH_SHARED = 2, /* shared-key */
+ IEEE80211_AUTH_8021X = 3, /* 802.1x */
+ IEEE80211_AUTH_AUTO = 4, /* auto-select/accept */
+ IEEE80211_AUTH_WPA = 5, /* WPA w/ 802.1x */
+ IEEE80211_AUTH_WPA_PSK = 6, /* WPA w/ preshared key */
+ IEEE80211_AUTH_WPA2 = 7, /* WPA2 w/ 802.1x */
+ IEEE80211_AUTH_WPA2_PSK = 8 /* WPA2 w/ preshared key */
};
#endif /* _NET80211_IEEE80211_H_ */
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index e1c1523c590..f3a87b9cfd6 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,5 +1,5 @@
/* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */
-/* $OpenBSD: ieee80211_input.c,v 1.3 2004/12/06 11:15:14 dlg Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.4 2005/02/17 18:28:05 reyk Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
@@ -126,7 +126,6 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
struct mbuf *m1;
int error, len;
u_int8_t dir, type, subtype;
- u_int8_t *bssid;
u_int16_t rxseq;
#if !defined(__OpenBSD__)
ALTQ_DECL(struct altq_pktattr pktattr;)
@@ -152,9 +151,8 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
wh = mtod(m, struct ieee80211_frame *);
if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
IEEE80211_FC0_VERSION_0) {
- if (ifp->if_flags & IFF_DEBUG)
- if_printf(ifp, "receive packet with wrong version: %x\n",
- wh->i_fc[0]);
+ IEEE80211_DPRINTF(("%s: packet with wrong version: %x\n",
+ __func__, wh->i_fc[0]));
ic->ic_stats.is_rx_badversion++;
goto err;
}
@@ -171,49 +169,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
IEEE80211_DPRINTF2(("%s: frame too short, len %u\n",
__func__, m->m_pkthdr.len));
ic->ic_stats.is_rx_tooshort++;
- goto out; /* XXX */
+ goto out;
}
if (ic->ic_state != IEEE80211_S_SCAN) {
- switch (ic->ic_opmode) {
- case IEEE80211_M_STA:
- if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) {
- /* not interested in */
- IEEE80211_DPRINTF2(("%s: discard frame from "
- "bss %s\n", __func__,
- ether_sprintf(wh->i_addr2)));
- ic->ic_stats.is_rx_wrongbss++;
- goto out;
- }
- break;
- case IEEE80211_M_IBSS:
- case IEEE80211_M_AHDEMO:
- case IEEE80211_M_HOSTAP:
- if (dir == IEEE80211_FC1_DIR_NODS)
- bssid = wh->i_addr3;
- else
- bssid = wh->i_addr1;
- if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) &&
-#ifdef __OpenBSD__
- !IEEE80211_ADDR_EQ(bssid, etherbroadcastaddr) &&
-#else
- !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr) &&
-#endif
- (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
- IEEE80211_FC0_TYPE_DATA) {
- /* not interested in */
- IEEE80211_DPRINTF2(("%s: discard frame from "
- "bss %s\n", __func__,
- ether_sprintf(bssid)));
- ic->ic_stats.is_rx_wrongbss++;
- goto out;
- }
- break;
- case IEEE80211_M_MONITOR:
- goto out;
- default:
- /* XXX catch bad values */
- break;
- }
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
rxseq = ni->ni_rxseq;
@@ -227,6 +185,8 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
goto out;
}
ni->ni_inact = 0;
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ goto out;
}
if (ic->ic_set_tim != NULL &&
@@ -269,6 +229,15 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
ic->ic_stats.is_rx_wrongdir++;
goto out;
}
+ if (ic->ic_state != IEEE80211_S_SCAN &&
+ !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) {
+ /* Source address is not our BSS. */
+ IEEE80211_DPRINTF(
+ ("%s: discard frame from SA %s\n",
+ __func__, ether_sprintf(wh->i_addr2)));
+ ic->ic_stats.is_rx_wrongbss++;
+ goto out;
+ }
if ((ifp->if_flags & IFF_SIMPLEX) &&
IEEE80211_IS_MULTICAST(wh->i_addr1) &&
IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_myaddr)) {
@@ -288,12 +257,46 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
ic->ic_stats.is_rx_wrongdir++;
goto out;
}
+ if (ic->ic_state != IEEE80211_S_SCAN &&
+ !IEEE80211_ADDR_EQ(wh->i_addr3,
+ ic->ic_bss->ni_bssid) &&
+ !IEEE80211_ADDR_EQ(wh->i_addr3,
+#ifdef __OpenBSD__
+ etherbroadcastaddr
+#else
+ ifp->if_broadcastaddr
+#endif
+ )) {
+ /* Destination is not our BSS or broadcast. */
+ IEEE80211_DPRINTF2(
+ ("%s: discard data frame to DA %s\n",
+ __func__, ether_sprintf(wh->i_addr3)));
+ ic->ic_stats.is_rx_wrongbss++;
+ goto out;
+ }
break;
case IEEE80211_M_HOSTAP:
if (dir != IEEE80211_FC1_DIR_TODS) {
ic->ic_stats.is_rx_wrongdir++;
goto out;
}
+ if (ic->ic_state != IEEE80211_S_SCAN &&
+ !IEEE80211_ADDR_EQ(wh->i_addr1,
+ ic->ic_bss->ni_bssid) &&
+ !IEEE80211_ADDR_EQ(wh->i_addr1,
+#ifdef __OpenBSD__
+ etherbroadcastaddr
+#else
+ ifp->if_broadcastaddr
+#endif
+ )) {
+ /* BSS is not us or broadcast. */
+ IEEE80211_DPRINTF2(
+ ("%s: discard data frame to BSS %s\n",
+ __func__, ether_sprintf(wh->i_addr1)));
+ ic->ic_stats.is_rx_wrongbss++;
+ goto out;
+ }
/* check if source STA is associated */
if (ni == ic->ic_bss) {
IEEE80211_DPRINTF(("%s: data from unknown src "
@@ -305,19 +308,17 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_DEAUTH,
IEEE80211_REASON_NOT_AUTHED);
- ieee80211_free_node(ic, ni);
}
ic->ic_stats.is_rx_notassoc++;
goto err;
}
if (ni->ni_associd == 0) {
- IEEE80211_DPRINTF(("ieee80211_input: "
- "data from unassoc src %s\n",
+ IEEE80211_DPRINTF(("%s: "
+ "data from unassoc src %s\n", __func__,
ether_sprintf(wh->i_addr2)));
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_DISASSOC,
IEEE80211_REASON_NOT_ASSOCED);
- ieee80211_unref_node(&ni);
ic->ic_stats.is_rx_notassoc++;
goto err;
}
@@ -345,9 +346,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
#endif
m = ieee80211_decap(ifp, m);
if (m == NULL) {
- IEEE80211_DPRINTF(("ieee80211_input: "
+ IEEE80211_DPRINTF(("%s: "
"decapsulation error for src %s\n",
- ether_sprintf(wh->i_addr2)));
+ __func__, ether_sprintf(wh->i_addr2)));
ic->ic_stats.is_rx_decap++;
goto err;
}
@@ -370,7 +371,6 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
m1 = m;
m = NULL;
}
- ieee80211_free_node(ic, ni);
}
}
if (m1 != NULL) {
@@ -427,12 +427,6 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
ic->ic_stats.is_rx_mgtdiscard++;
goto out;
}
- } else {
- if (ic->ic_opmode != IEEE80211_M_IBSS &&
- subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
- ic->ic_stats.is_rx_mgtdiscard++;
- goto out;
- }
}
if (ifp->if_flags & IFF_DEBUG) {
@@ -486,7 +480,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
goto out;
default:
- IEEE80211_DPRINTF(("%s: bad type %x\n", __func__, type));
+ IEEE80211_DPRINTF(("%s: bad packet type %x\n", __func__, type));
/* should not come here */
break;
}
@@ -540,7 +534,7 @@ ieee80211_decap(struct ifnet *ifp, struct mbuf *m)
break;
case IEEE80211_FC1_DIR_DSTODS:
/* not yet supported */
- IEEE80211_DPRINTF(("%s: DS to DS\n", __func__));
+ IEEE80211_DPRINTF(("%s: discard DS to DS frame\n", __func__));
m_freem(m);
return NULL;
}
@@ -671,21 +665,52 @@ ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni,
} \
} while (0)
+#ifdef IEEE80211_DEBUG
+static void
+ieee80211_ssid_mismatch(struct ieee80211com *ic, const char *tag,
+ u_int8_t mac[IEEE80211_ADDR_LEN], u_int8_t *ssid)
+{
+ printf("[%s] %s req ssid mismatch: ", ether_sprintf(mac), tag);
+ ieee80211_print_essid(ssid + 2, ssid[1]);
+ printf("\n");
+}
+
+#define IEEE80211_VERIFY_SSID(_ni, _ssid, _packet_type) do { \
+ if ((_ssid)[1] != 0 && \
+ ((_ssid)[1] != (_ni)->ni_esslen || \
+ memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) { \
+ if (ieee80211_msg_input(ic)) \
+ ieee80211_ssid_mismatch(ic, _packet_type, \
+ wh->i_addr2, _ssid); \
+ ic->ic_stats.is_rx_ssidmismatch++; \
+ return; \
+ } \
+} while (0)
+#else /* !IEEE80211_DEBUG */
+#define IEEE80211_VERIFY_SSID(_ni, _ssid, _packet_type) do { \
+ if ((_ssid)[1] != 0 && \
+ ((_ssid)[1] != (_ni)->ni_esslen || \
+ memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) { \
+ ic->ic_stats.is_rx_ssidmismatch++; \
+ return; \
+ } \
+} while (0)
+#endif /* !IEEE80211_DEBUG */
+
static void
ieee80211_auth_open(struct ieee80211com *ic, struct ieee80211_frame *wh,
struct ieee80211_node *ni, int rssi, u_int32_t rstamp, u_int16_t seq,
u_int16_t status)
{
struct ifnet *ifp = &ic->ic_if;
- int allocbs;
switch (ic->ic_opmode) {
case IEEE80211_M_IBSS:
if (ic->ic_state != IEEE80211_S_RUN ||
seq != IEEE80211_AUTH_OPEN_REQUEST) {
IEEE80211_DPRINTF(("%s: discard auth from %s; "
- "state %u, seq %u\n", __func__,
- ether_sprintf(wh->i_addr2),
- ic->ic_state, seq));
+ "state %u, seq %u\n", __func__,
+ ether_sprintf(wh->i_addr2),
+ ic->ic_state, seq));
ic->ic_stats.is_rx_bad_auth++;
return;
}
@@ -701,9 +726,9 @@ ieee80211_auth_open(struct ieee80211com *ic, struct ieee80211_frame *wh,
if (ic->ic_state != IEEE80211_S_RUN ||
seq != IEEE80211_AUTH_OPEN_REQUEST) {
IEEE80211_DPRINTF(("%s: discard auth from %s; "
- "state %u, seq %u\n", __func__,
- ether_sprintf(wh->i_addr2),
- ic->ic_state, seq));
+ "state %u, seq %u\n", __func__,
+ ether_sprintf(wh->i_addr2),
+ ic->ic_state, seq));
ic->ic_stats.is_rx_bad_auth++;
return;
}
@@ -717,31 +742,33 @@ ieee80211_auth_open(struct ieee80211com *ic, struct ieee80211_frame *wh,
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
ni->ni_chan = ic->ic_bss->ni_chan;
- allocbs = 1;
- } else
- allocbs = 0;
+ }
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "station %s %s authenticated (open)\n",
ether_sprintf(ni->ni_macaddr),
- (allocbs ? "newly" : "already"));
+ ni->ni_state != IEEE80211_STA_CACHE ?
+ "newly" : "already");
+ ieee80211_node_newstate(ni, IEEE80211_STA_AUTH);
break;
+
case IEEE80211_M_STA:
if (ic->ic_state != IEEE80211_S_AUTH ||
seq != IEEE80211_AUTH_OPEN_RESPONSE) {
ic->ic_stats.is_rx_bad_auth++;
IEEE80211_DPRINTF(("%s: discard auth from %s; "
- "state %u, seq %u\n", __func__,
- ether_sprintf(wh->i_addr2),
- ic->ic_state, seq));
+ "state %u, seq %u\n", __func__,
+ ether_sprintf(wh->i_addr2),
+ ic->ic_state, seq));
return;
}
if (status != 0) {
- if_printf(&ic->ic_if,
- "open authentication failed (reason %d) for %s\n",
- status,
- ether_sprintf(wh->i_addr3));
+ if (ifp->if_flags & IFF_DEBUG)
+ if_printf(&ic->ic_if,
+ "open authentication failed (reason %d) "
+ "for %s\n", status,
+ ether_sprintf(wh->i_addr3));
if (ni != ic->ic_bss)
ni->ni_fails++;
ic->ic_stats.is_rx_auth_fail++;
@@ -763,7 +790,7 @@ ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
{
struct ifnet *ifp = &ic->ic_if;
u_int8_t *challenge = NULL;
- int allocbs, i;
+ int i;
if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
IEEE80211_DPRINTF(("%s: WEP is off\n", __func__));
@@ -824,15 +851,14 @@ ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
ni->ni_chan = ic->ic_bss->ni_chan;
- allocbs = 1;
- } else
- allocbs = 0;
+ }
if (ni->ni_challenge == NULL)
ni->ni_challenge = (u_int32_t*)malloc(
IEEE80211_CHALLENGE_LEN, M_DEVBUF,
M_NOWAIT);
if (ni->ni_challenge == NULL) {
- IEEE80211_DPRINTF(("challenge alloc failed\n"));
+ IEEE80211_DPRINTF(("%s: "
+ "challenge alloc failed\n", __func__));
/* XXX statistic */
return;
}
@@ -843,7 +869,8 @@ ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
if_printf(ifp, "station %s shared key "
"%sauthentication\n",
ether_sprintf(ni->ni_macaddr),
- allocbs ? "" : "re");
+ ni->ni_state != IEEE80211_STA_CACHE ?
+ "" : "re");
break;
case IEEE80211_AUTH_SHARED_RESPONSE:
if (ni == ic->ic_bss) {
@@ -868,6 +895,7 @@ ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
if_printf(ifp, "station %s authenticated "
"(shared key)\n",
ether_sprintf(ni->ni_macaddr));
+ ieee80211_node_newstate(ni, IEEE80211_STA_AUTH);
break;
default:
IEEE80211_DPRINTF(("%s: bad seq %d from %s\n",
@@ -931,11 +959,13 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_node *ni,
int subtype, int rssi, u_int32_t rstamp)
{
+#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
+#define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_frame *wh;
u_int8_t *frm, *efrm;
u_int8_t *ssid, *rates, *xrates;
- int reassoc, resp, newassoc, allocbs;
+ int is_new, reassoc, resp;
wh = mtod(m0, struct ieee80211_frame *);
frm = (u_int8_t *)&wh[1];
@@ -946,14 +976,27 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
u_int8_t *tstamp, *bintval, *capinfo, *country;
u_int8_t chan, bchan, fhindex, erp;
u_int16_t fhdwell;
- int isprobe;
- if (ic->ic_opmode != IEEE80211_M_IBSS &&
+ /*
+ * We process beacon/probe response frames for:
+ * o station mode: to collect state
+ * updates such as 802.11g slot time and for passive
+ * scanning of APs
+ * o adhoc mode: to discover neighbors
+ * o hostap mode: for passive scanning of neighbor APs
+ * o when scanning
+ * In other words, in all modes other than monitor (which
+ * does not process incoming packets) and adhoc-demo (which
+ * does not use management frames at all).
+ */
+#ifdef DIAGNOSTIC
+ if (ic->ic_opmode != IEEE80211_M_STA &&
+ ic->ic_opmode != IEEE80211_M_IBSS &&
+ ic->ic_opmode != IEEE80211_M_HOSTAP &&
ic->ic_state != IEEE80211_S_SCAN) {
- /* XXX: may be useful for background scan */
- return;
+ panic("%s: impossible operating mode", __func__);
}
- isprobe = (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP);
+#endif
/*
* beacon/probe response frame format
@@ -1013,8 +1056,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
case IEEE80211_ELEMID_ERP:
if (frm[1] != 1) {
IEEE80211_DPRINTF(("%s: invalid ERP "
- "element; length %u, expecting "
- "1\n", __func__, frm[1]));
+ "element; length %u, expecting "
+ "1\n", __func__, frm[1]));
ic->ic_stats.is_rx_elem_toobig++;
break;
}
@@ -1022,7 +1065,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
break;
default:
IEEE80211_DPRINTF2(("%s: element id %u/len %u "
- "ignored\n", __func__, *frm, frm[1]));
+ "ignored\n", __func__, *frm, frm[1]));
ic->ic_stats.is_rx_elem_unknown++;
break;
}
@@ -1036,9 +1079,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
#endif
isclr(ic->ic_chan_active, chan)) {
IEEE80211_DPRINTF(("%s: ignore %s with invalid channel "
- "%u\n", __func__,
- isprobe ? "probe response" : "beacon",
- chan));
+ "%u\n", __func__,
+ isprobe ? "probe response" : "beacon", chan));
ic->ic_stats.is_rx_badchan++;
return;
}
@@ -1055,9 +1097,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
* different hop pattern in FH.
*/
IEEE80211_DPRINTF(("%s: ignore %s on channel %u marked "
- "for channel %u\n", __func__,
- isprobe ? "probe response" : "beacon",
- bchan, chan));
+ "for channel %u\n", __func__,
+ isprobe ? "probe response" : "beacon", bchan, chan));
ic->ic_stats.is_rx_chanmismatch++;
return;
}
@@ -1072,14 +1113,14 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
* This may result in a bloat of the scanned AP list but
* it shouldn't be too much.
*/
- ni = ieee80211_lookup_node(ic, wh->i_addr2,
- &ic->ic_channels[chan]);
+ ni = ieee80211_find_node_for_beacon(ic, wh->i_addr2,
+ &ic->ic_channels[chan], ssid);
#ifdef IEEE80211_DEBUG
if (ieee80211_debug &&
(ni == NULL || ic->ic_state == IEEE80211_S_SCAN)) {
printf("%s: %s%s on chan %u (bss chan %u) ",
__func__, (ni == NULL ? "new " : ""),
- isprobe ? "probe response" : "beacon",
+ ISPROBE(subtype) ? "probe response" : "beacon",
chan, bchan);
ieee80211_print_essid(ssid + 2, ssid[1]);
printf(" from %s\n", ether_sprintf(wh->i_addr2));
@@ -1099,11 +1140,11 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
ni = ieee80211_alloc_node(ic, wh->i_addr2);
if (ni == NULL)
return;
- ni->ni_esslen = ssid[1];
- memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
- memcpy(ni->ni_essid, ssid + 2, ssid[1]);
- allocbs = 1;
- } else if (ssid[1] != 0 && (isprobe || ni->ni_esslen == 0)) {
+ is_new = 1;
+ } else
+ is_new = 0;
+
+ if (ssid[1] != 0 && ni->ni_esslen == 0) {
/*
* Update ESSID at probe response to adopt hidden AP by
* Lucent/Cisco, which announces null ESSID in beacon.
@@ -1111,9 +1152,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
ni->ni_esslen = ssid[1];
memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
memcpy(ni->ni_essid, ssid + 2, ssid[1]);
- allocbs = 0;
- } else
- allocbs = 0;
+ }
IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
@@ -1134,10 +1173,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
* Anything else can be discarded (XXX and should be handled
* above so we don't do so much work).
*/
- if (ic->ic_state == IEEE80211_S_SCAN)
- ieee80211_unref_node(&ni); /* NB: do not free */
- else if (ic->ic_opmode == IEEE80211_M_IBSS &&
- allocbs && isprobe) {
+ if (ic->ic_opmode == IEEE80211_M_IBSS || (is_new &&
+ ISPROBE(subtype))) {
/*
* Fake an association so the driver can setup it's
* private state. The rate set has been setup above;
@@ -1145,10 +1182,6 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
*/
if (ic->ic_newassoc)
(*ic->ic_newassoc)(ic, ni, 1);
- /* NB: hold reference */
- } else {
- /* XXX optimize to avoid work done above */
- ieee80211_free_node(ic, ni);
}
break;
}
@@ -1184,29 +1217,15 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
}
IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
- if (ssid[1] != 0 &&
- (ssid[1] != ic->ic_bss->ni_esslen ||
- memcmp(ssid + 2, ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen) != 0)) {
-#ifdef IEEE80211_DEBUG
- if (ieee80211_debug) {
- printf("%s: ssid mismatch ", __func__);
- ieee80211_print_essid(ssid + 2, ssid[1]);
- printf(" from %s\n", ether_sprintf(wh->i_addr2));
- }
-#endif
- ic->ic_stats.is_rx_ssidmismatch++;
- return;
- }
+ IEEE80211_VERIFY_SSID(ic->ic_bss, ssid, "probe");
if (ni == ic->ic_bss) {
ni = ieee80211_dup_bss(ic, wh->i_addr2);
if (ni == NULL)
return;
- IEEE80211_DPRINTF(("%s: new req from %s\n",
- __func__, ether_sprintf(wh->i_addr2)));
- allocbs = 1;
- } else
- allocbs = 0;
+ IEEE80211_DPRINTF(("%s: new probe req from %s\n",
+ __func__, ether_sprintf(wh->i_addr2)));
+ }
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
rate = ieee80211_setup_rates(ic, ni, rates, xrates,
@@ -1214,13 +1233,11 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
| IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
if (rate & IEEE80211_RATE_BASIC) {
IEEE80211_DPRINTF(("%s: rate negotiation failed: %s\n",
- __func__,ether_sprintf(wh->i_addr2)));
+ __func__,ether_sprintf(wh->i_addr2)));
} else {
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
}
- if (allocbs)
- ieee80211_free_node(ic, ni);
break;
}
@@ -1248,8 +1265,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
status);
else {
IEEE80211_DPRINTF(("%s: unsupported authentication "
- "algorithm %d from %s\n",
- __func__, algo, ether_sprintf(wh->i_addr2)));
+ "algorithm %d from %s\n",
+ __func__, algo, ether_sprintf(wh->i_addr2)));
ic->ic_stats.is_rx_auth_unsupported++;
return;
}
@@ -1283,7 +1300,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) {
IEEE80211_DPRINTF(("%s: ignore other bss from %s\n",
- __func__, ether_sprintf(wh->i_addr2)));
+ __func__, ether_sprintf(wh->i_addr2)));
ic->ic_stats.is_rx_assoc_bss++;
return;
}
@@ -1308,27 +1325,20 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
}
IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
- if (ssid[1] != ic->ic_bss->ni_esslen ||
- memcmp(ssid + 2, ic->ic_bss->ni_essid, ssid[1]) != 0) {
-#ifdef IEEE80211_DEBUG
- if (ieee80211_debug) {
- printf("%s: ssid mismatch ", __func__);
- ieee80211_print_essid(ssid + 2, ssid[1]);
- printf(" from %s\n", ether_sprintf(wh->i_addr2));
- }
-#endif
- ic->ic_stats.is_rx_ssidmismatch++;
- return;
- }
- if (ni == ic->ic_bss) {
- IEEE80211_DPRINTF(("%s: not authenticated for %s\n",
- __func__, ether_sprintf(wh->i_addr2)));
+ IEEE80211_VERIFY_SSID(ic->ic_bss, ssid,
+ reassoc ? "reassoc" : "assoc");
+
+ if (ni->ni_state != IEEE80211_STA_AUTH &&
+ ni->ni_state != IEEE80211_STA_ASSOC) {
+ IEEE80211_DPRINTF(
+ ("%s: deny %sassoc from %s, not authenticated\n",
+ __func__, reassoc ? "re" : "",
+ ether_sprintf(wh->i_addr2)));
ni = ieee80211_dup_bss(ic, wh->i_addr2);
if (ni != NULL) {
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_DEAUTH,
IEEE80211_REASON_ASSOC_NOT_AUTHED);
- ieee80211_free_node(ic, ni);
}
ic->ic_stats.is_rx_assoc_notauth++;
return;
@@ -1345,12 +1355,12 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
(capinfo & IEEE80211_CAPINFO_PRIVACY) !=
((ic->ic_flags & IEEE80211_F_WEPON) ?
IEEE80211_CAPINFO_PRIVACY : 0)) {
- IEEE80211_DPRINTF(("%s: capability mismatch %x for %s\n",
- __func__, capinfo, ether_sprintf(wh->i_addr2)));
- IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
- ni->ni_associd = 0;
+ IEEE80211_DPRINTF(("%s: rate mismatch for %s\n",
+ __func__, ether_sprintf(wh->i_addr2)));
+ /* XXX what rate will we send this at? */
IEEE80211_SEND_MGMT(ic, ni, resp,
- IEEE80211_STATUS_CAPINFO);
+ IEEE80211_STATUS_BASIC_RATE);
+ ieee80211_node_leave(ic, ni);
ic->ic_stats.is_rx_assoc_capmismatch++;
return;
}
@@ -1359,7 +1369,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
if (ni->ni_rates.rs_nrates == 0) {
IEEE80211_DPRINTF(("%s: rate mismatch for %s\n",
- __func__, ether_sprintf(wh->i_addr2)));
+ __func__, ether_sprintf(wh->i_addr2)));
IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
ni->ni_associd = 0;
IEEE80211_SEND_MGMT(ic, ni, resp,
@@ -1374,42 +1384,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
ni->ni_chan = ic->ic_bss->ni_chan;
ni->ni_fhdwell = ic->ic_bss->ni_fhdwell;
ni->ni_fhindex = ic->ic_bss->ni_fhindex;
- if (ni->ni_associd == 0) {
- u_int16_t aid;
- /*
- * It would be clever to search the bitmap
- * more efficiently, but this will do for now.
- */
- for (aid = 1; aid < ic->ic_max_aid; aid++) {
- if (!IEEE80211_AID_ISSET(aid,
- ic->ic_aid_bitmap))
- break;
- }
-
- if (ic->ic_bss->ni_associd >= ic->ic_max_aid) {
- IEEE80211_SEND_MGMT(ic, ni, resp,
- IEEE80211_REASON_ASSOC_TOOMANY);
- return;
- } else {
- ni->ni_associd = aid | 0xc000;
- IEEE80211_AID_SET(ni->ni_associd,
- ic->ic_aid_bitmap);
- newassoc = 1;
- }
- } else
- newassoc = 0;
- /* XXX for 11g must turn off short slot time if long
- slot time sta associates */
- IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
- if (ifp->if_flags & IFF_DEBUG)
- if_printf(ifp, "station %s %s associated at aid %d\n",
- (newassoc ? "newly" : "already"),
- ether_sprintf(ni->ni_macaddr),
- ni->ni_associd & ~0xc000);
- /* give driver a chance to setup state like ni_txrate */
- if (ic->ic_newassoc)
- (*ic->ic_newassoc)(ic, ni, newassoc);
+ ieee80211_node_join(ic, ni, resp);
break;
}
@@ -1418,8 +1394,10 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
u_int16_t status;
if (ic->ic_opmode != IEEE80211_M_STA ||
- ic->ic_state != IEEE80211_S_ASSOC)
+ ic->ic_state != IEEE80211_S_ASSOC) {
+ ic->ic_stats.is_rx_mgtdiscard++;
return;
+ }
/*
* asresp frame format
@@ -1439,7 +1417,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
if (status != 0) {
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp,
- "association failed (reason %d) for %s\n",
+ "%sassociation failed (reason %d) for %s\n",
+ ISREASSOC(subtype) ? "re" : "",
status, ether_sprintf(wh->i_addr3));
if (ni != ic->ic_bss)
ni->ni_fails++;
@@ -1489,11 +1468,12 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
case IEEE80211_M_HOSTAP:
if (ni != ic->ic_bss) {
if (ifp->if_flags & IFF_DEBUG)
- if_printf(ifp, "station %s deauthenticated"
- " by peer (reason %d)\n",
- ether_sprintf(ni->ni_macaddr), reason);
- /* node will be free'd on return */
- ieee80211_unref_node(&ni);
+ if_printf(ifp,
+ "station %s deauthenticated "
+ "by peer (reason %d)\n",
+ ether_sprintf(ni->ni_macaddr),
+ reason);
+ ieee80211_node_leave(ic, ni);
}
break;
default:
@@ -1519,13 +1499,12 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
case IEEE80211_M_HOSTAP:
if (ni != ic->ic_bss) {
if (ifp->if_flags & IFF_DEBUG)
- if_printf(ifp, "station %s disassociated"
- " by peer (reason %d)\n",
- ether_sprintf(ni->ni_macaddr), reason);
- IEEE80211_AID_CLR(ni->ni_associd,
- ic->ic_aid_bitmap);
- ni->ni_associd = 0;
- /* XXX node reclaimed how? */
+ if_printf(ifp,
+ "station %s disassociated "
+ "by peer (reason %d)\n",
+ ether_sprintf(ni->ni_macaddr),
+ reason);
+ ieee80211_node_leave(ic, ni);
}
break;
default:
@@ -1535,7 +1514,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
}
default:
IEEE80211_DPRINTF(("%s: mgmt frame with subtype 0x%x not "
- "handled\n", __func__, subtype));
+ "handled\n", __func__, subtype));
ic->ic_stats.is_rx_badsubtype++;
break;
}
@@ -1680,6 +1659,10 @@ ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni,
if (ieee80211_do_slow_print(ic, &did_print)) {
printf("%s: ieee80211_ibss_merge: bssid mismatch %s\n",
ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid));
+ printf("%s: my tsft %ull beacon tsft %ull\n",
+ ic->ic_if.if_xname, local_tsft, beacon_tsft);
+ printf("%s: sync TSF with %s\n",
+ ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr));
}
ic->ic_flags &= ~IEEE80211_F_SIBSS;
@@ -1709,3 +1692,4 @@ ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni,
}
#undef IEEE80211_VERIFY_LENGTH
#undef IEEE80211_VERIFY_ELEMENT
+#undef IEEE80211_VERIFY_SSID
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index 36dd974b946..1aa22730a68 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_ioctl.c,v 1.5 2005/02/15 19:44:15 reyk Exp $ */
+/* $OpenBSD: ieee80211_ioctl.c,v 1.6 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $ */
/*-
@@ -1366,9 +1366,16 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
error = ieee80211_cfgset(ifp, cmd, data);
break;
+#if 0
+ case SIOCG80211ZSTATS:
+#endif
case SIOCG80211STATS:
ifr = (struct ifreq *)data;
copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
+#if 0
+ if (cmd == SIOCG80211ZSTATS)
+ memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
+#endif
break;
case SIOCS80211TXPOWER:
txpower = (struct ieee80211_txpower *)data;
@@ -1426,7 +1433,7 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
IEEE80211_FC0_SUBTYPE_DEAUTH,
IEEE80211_REASON_AUTH_LEAVE);
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
}
break;
case SIOCHOSTAP_GET:
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index a73373f2b5b..f8d70b4e26e 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_node.c,v 1.2 2004/11/02 15:39:02 millert Exp $ */
+/* $OpenBSD: ieee80211_node.c,v 1.3 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */
/*-
@@ -105,8 +105,11 @@ static u_int8_t ieee80211_node_getrssi(struct ieee80211com *,
static void ieee80211_setup_node(struct ieee80211com *ic,
struct ieee80211_node *ni, u_int8_t *macaddr);
-static void _ieee80211_free_node(struct ieee80211com *,
+static void ieee80211_free_node(struct ieee80211com *,
struct ieee80211_node *);
+static struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
+static void ieee80211_node_cleanup(struct ieee80211com *,
+ struct ieee80211_node *);
#ifdef __NetBSD__
MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
@@ -118,17 +121,43 @@ void
ieee80211_node_attach(struct ifnet *ifp)
{
struct ieee80211com *ic = (void *)ifp;
+ int size;
-#ifdef __FreeBSD__
- /* XXX need unit */
IEEE80211_NODE_LOCK_INIT(ic, ifp->if_xname);
-#endif
TAILQ_INIT(&ic->ic_node);
ic->ic_node_alloc = ieee80211_node_alloc;
ic->ic_node_free = ieee80211_node_free;
ic->ic_node_copy = ieee80211_node_copy;
ic->ic_node_getrssi = ieee80211_node_getrssi;
ic->ic_scangen = 1;
+ ic->ic_max_nnodes = ieee80211_cache_size;
+
+ if (ic->ic_max_aid == 0)
+ ic->ic_max_aid = IEEE80211_AID_DEF;
+ else if (ic->ic_max_aid > IEEE80211_AID_MAX)
+ ic->ic_max_aid = IEEE80211_AID_MAX;
+ size = howmany(ic->ic_max_aid, 32) * sizeof(u_int32_t);
+ MALLOC(ic->ic_aid_bitmap, u_int32_t *, size, M_DEVBUF, M_NOWAIT);
+ if (ic->ic_aid_bitmap == NULL) {
+ /* XXX no way to recover */
+ printf("%s: no memory for AID bitmap!\n", __func__);
+ ic->ic_max_aid = 0;
+ }
+ memset(ic->ic_aid_bitmap, 0, size);
+}
+
+static struct ieee80211_node *
+ieee80211_alloc_node_helper(struct ieee80211com *ic)
+{
+ struct ieee80211_node *ni;
+ if (ic->ic_nnodes >= ic->ic_max_nnodes)
+ ieee80211_clean_nodes(ic);
+ if (ic->ic_nnodes >= ic->ic_max_nnodes)
+ return NULL;
+ ni = (*ic->ic_node_alloc)(ic);
+ if (ni != NULL)
+ ic->ic_nnodes++;
+ return ni;
}
void
@@ -137,10 +166,10 @@ ieee80211_node_lateattach(struct ifnet *ifp)
struct ieee80211com *ic = (void *)ifp;
struct ieee80211_node *ni;
- ni = (*ic->ic_node_alloc)(ic);
+ ni = ieee80211_alloc_node_helper(ic);
IASSERT(ni != NULL, ("unable to setup inital BSS node"));
ni->ni_chan = IEEE80211_CHAN_ANYC;
- ic->ic_bss = ni;
+ ic->ic_bss = ieee80211_ref_node(ni);
ic->ic_txpower = IEEE80211_TXPOWER_MAX;
}
@@ -149,12 +178,14 @@ ieee80211_node_detach(struct ifnet *ifp)
{
struct ieee80211com *ic = (void *)ifp;
- if (ic->ic_bss != NULL)
+ if (ic->ic_bss != NULL) {
(*ic->ic_node_free)(ic, ic->ic_bss);
+ ic->ic_bss = NULL;
+ }
ieee80211_free_allnodes(ic);
-#ifdef __FreeBSD__
IEEE80211_NODE_LOCK_DESTROY(ic);
-#endif
+ if (ic->ic_aid_bitmap != NULL)
+ FREE(ic->ic_aid_bitmap, M_DEVBUF);
}
/*
@@ -240,7 +271,7 @@ ieee80211_next_scan(struct ifnet *ifp)
}
}
clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan));
- IEEE80211_DPRINTF(("ieee80211_next_scan: chan %d->%d\n",
+ IEEE80211_DPRINTF(("%s: chan %d->%d\n", __func__,
ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan),
ieee80211_chan2ieee(ic, chan)));
ic->ic_bss->ni_chan = chan;
@@ -261,8 +292,12 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
- if (ic->ic_opmode == IEEE80211_M_IBSS)
- ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */
+ if (ic->ic_opmode == IEEE80211_M_IBSS) {
+ if ((ic->ic_flags & IEEE80211_F_DESBSSID) != 0)
+ IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid);
+ else
+ ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */
+ }
ni->ni_esslen = ic->ic_des_esslen;
memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
ni->ni_rssi = 0;
@@ -353,6 +388,11 @@ ieee80211_end_scan(struct ifnet *ifp)
struct ieee80211_node *ni, *nextbs, *selbs;
int i, fail;
+ if (ifp->if_flags & IFF_DEBUG)
+ if_printf(ifp, "end %s scan\n",
+ (ic->ic_flags & IEEE80211_F_ASCAN) ?
+ "active" : "passive");
+
ic->ic_flags &= ~IEEE80211_F_ASCAN;
ni = TAILQ_FIRST(&ic->ic_node);
@@ -367,10 +407,8 @@ ieee80211_end_scan(struct ifnet *ifp)
* channel from the active set.
*/
for (; ni != NULL; ni = nextbs) {
- ieee80211_ref_node(ni);
nextbs = TAILQ_NEXT(ni, ni_list);
setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan));
- ieee80211_free_node(ic, ni);
}
for (i = 0; i < IEEE80211_CHAN_MAX; i++)
if (isset(ic->ic_chan_active, i) && isclr(occupied, i))
@@ -401,10 +439,8 @@ ieee80211_end_scan(struct ifnet *ifp)
return;
}
selbs = NULL;
- if (ifp->if_flags & IFF_DEBUG)
- if_printf(ifp, "\tmacaddr bssid chan rssi rate flag wep essid\n");
+
for (; ni != NULL; ni = nextbs) {
- ieee80211_ref_node(ni);
nextbs = TAILQ_NEXT(ni, ni_list);
if (ni->ni_fails) {
/*
@@ -419,38 +455,21 @@ ieee80211_end_scan(struct ifnet *ifp)
if (ieee80211_match_bss(ic, ni) == 0) {
if (selbs == NULL)
selbs = ni;
- else if (ni->ni_rssi > selbs->ni_rssi) {
- ieee80211_unref_node(&selbs);
+ else if (ni->ni_rssi > selbs->ni_rssi)
selbs = ni;
- } else
- ieee80211_unref_node(&ni);
- } else {
- ieee80211_unref_node(&ni);
}
}
if (selbs == NULL)
goto notfound;
(*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
+ ieee80211_node_newstate(selbs, IEEE80211_STA_BSS);
if (ic->ic_opmode == IEEE80211_M_IBSS) {
ieee80211_fix_rate(ic, ic->ic_bss, IEEE80211_F_DOFRATE |
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
- if (ic->ic_bss->ni_rates.rs_nrates == 0) {
- selbs->ni_fails++;
- ieee80211_unref_node(&selbs);
+ if (ic->ic_bss->ni_rates.rs_nrates == 0)
goto notfound;
- }
- ieee80211_unref_node(&selbs);
- /*
- * Discard scan set; the nodes have a refcnt of zero
- * and have not asked the driver to setup private
- * node state. Let them be repopulated on demand either
- * through transmission (ieee80211_find_txnode) or receipt
- * of a probe response (to be added).
- */
- ieee80211_free_allnodes(ic);
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
} else {
- ieee80211_unref_node(&selbs);
ieee80211_new_state(ic, IEEE80211_S_AUTH, -1);
}
}
@@ -485,12 +504,18 @@ ieee80211_node_alloc(struct ieee80211com *ic)
}
static void
+ieee80211_node_cleanup(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ if (ni->ni_challenge != NULL) {
+ FREE(ni->ni_challenge, M_DEVBUF);
+ ni->ni_challenge = NULL;
+ }
+}
+
+static void
ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
{
- if (ni->ni_challenge != NULL) {
- FREE(ni->ni_challenge, M_DEVBUF);
- ni->ni_challenge = NULL;
- }
+ ieee80211_node_cleanup(ic, ni);
FREE(ni, M_80211_NODE);
}
@@ -498,6 +523,7 @@ static void
ieee80211_node_copy(struct ieee80211com *ic,
struct ieee80211_node *dst, const struct ieee80211_node *src)
{
+ ieee80211_node_cleanup(ic, dst);
*dst = *src;
dst->ni_challenge = NULL;
}
@@ -513,15 +539,14 @@ ieee80211_setup_node(struct ieee80211com *ic,
struct ieee80211_node *ni, u_int8_t *macaddr)
{
int hash;
- ieee80211_node_critsec_decl(s);
+ IEEE80211_DPRINTF(("%s %s\n", __func__, ether_sprintf(macaddr)));
IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
hash = IEEE80211_NODE_HASH(macaddr);
- ni->ni_refcnt = 1; /* mark referenced */
- ieee80211_node_critsec_begin(ic, s);
- TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list);
- LIST_INSERT_HEAD(&ic->ic_hash[hash], ni, ni_hash);
- /*
+ ieee80211_node_newstate(ni, IEEE80211_STA_CACHE);
+ IEEE80211_NODE_LOCK_BH(ic);
+
+ /*
* Note we don't enable the inactive timer when acting
* as a station. Nodes created in this mode represent
* AP's identified while scanning. If we time them out
@@ -530,15 +555,18 @@ ieee80211_setup_node(struct ieee80211com *ic,
* more importantly, we'll incorrectly deauthenticate
* ourself because the inactivity timer will kick us off.
*/
- if (ic->ic_opmode != IEEE80211_M_STA)
+ if (ic->ic_opmode != IEEE80211_M_STA &&
+ TAILQ_EMPTY(&ic->ic_node))
ic->ic_inact_timer = IEEE80211_INACT_WAIT;
- ieee80211_node_critsec_end(ic, s);
+ TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list);
+ LIST_INSERT_HEAD(&ic->ic_hash[hash], ni, ni_hash);
+ IEEE80211_NODE_UNLOCK_BH(ic);
}
struct ieee80211_node *
ieee80211_alloc_node(struct ieee80211com *ic, u_int8_t *macaddr)
{
- struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic);
+ struct ieee80211_node *ni = ieee80211_alloc_node_helper(ic);
if (ni != NULL)
ieee80211_setup_node(ic, ni, macaddr);
else
@@ -549,7 +577,7 @@ ieee80211_alloc_node(struct ieee80211com *ic, u_int8_t *macaddr)
struct ieee80211_node *
ieee80211_dup_bss(struct ieee80211com *ic, u_int8_t *macaddr)
{
- struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic);
+ struct ieee80211_node *ni = ieee80211_alloc_node_helper(ic);
if (ni != NULL) {
ieee80211_setup_node(ic, ni, macaddr);
/*
@@ -568,14 +596,14 @@ _ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr)
struct ieee80211_node *ni;
int hash;
-#ifdef __FreeBSD__
IEEE80211_NODE_LOCK_ASSERT(ic);
-#endif /* __FreeBSD__ */
hash = IEEE80211_NODE_HASH(macaddr);
LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
- ieee80211_node_incref(ni); /* mark referenced */
+ /* least-recently used is at tail */
+ TAILQ_REMOVE(&ic->ic_node, ni, ni_list);
+ TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list);
return ni;
}
}
@@ -586,23 +614,24 @@ struct ieee80211_node *
ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr)
{
struct ieee80211_node *ni;
- ieee80211_node_critsec_decl(s);
- ieee80211_node_critsec_begin(ic, s);
+ IEEE80211_NODE_LOCK(ic);
ni = _ieee80211_find_node(ic, macaddr);
- ieee80211_node_critsec_end(ic, s);
+ IEEE80211_NODE_UNLOCK(ic);
return ni;
}
/*
* Return a reference to the appropriate node for sending
* a data frame. This handles node discovery in adhoc networks.
+ *
+ * Drivers will call this, so increase the reference count before
+ * returning the node.
*/
struct ieee80211_node *
ieee80211_find_txnode(struct ieee80211com *ic, u_int8_t *macaddr)
{
struct ieee80211_node *ni;
- ieee80211_node_critsec_decl(s);
/*
* The destination address should be in the node table
@@ -610,15 +639,17 @@ ieee80211_find_txnode(struct ieee80211com *ic, u_int8_t *macaddr)
* multicast/broadcast frame.
*/
if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
- return ic->ic_bss;
+ return ieee80211_ref_node(ic->ic_bss);
/* XXX can't hold lock across dup_bss 'cuz of recursive locking */
- ieee80211_node_critsec_begin(ic, s);
+ IEEE80211_NODE_LOCK(ic);
ni = _ieee80211_find_node(ic, macaddr);
- ieee80211_node_critsec_end(ic, s);
- if (ni == NULL &&
- (ic->ic_opmode == IEEE80211_M_IBSS ||
- ic->ic_opmode == IEEE80211_M_AHDEMO)) {
+ IEEE80211_NODE_UNLOCK(ic);
+ if (ni == NULL) {
+ if (ic->ic_opmode != IEEE80211_M_IBSS &&
+ ic->ic_opmode != IEEE80211_M_AHDEMO)
+ return NULL;
+
/*
* Fake up a node; this handles node discovery in
* adhoc mode. Note that for the driver's benefit
@@ -628,32 +659,31 @@ ieee80211_find_txnode(struct ieee80211com *ic, u_int8_t *macaddr)
* XXX need better way to handle this; issue probe
* request so we can deduce rate set, etc.
*/
- ni = ieee80211_dup_bss(ic, macaddr);
- if (ni != NULL) {
- /* XXX no rate negotiation; just dup */
- ni->ni_rates = ic->ic_bss->ni_rates;
- if (ic->ic_newassoc)
- (*ic->ic_newassoc)(ic, ni, 1);
- }
+ if ((ni = ieee80211_dup_bss(ic, macaddr)) == NULL)
+ return NULL;
+ /* XXX no rate negotiation; just dup */
+ ni->ni_rates = ic->ic_bss->ni_rates;
+ if (ic->ic_newassoc)
+ (*ic->ic_newassoc)(ic, ni, 1);
}
- return ni;
+ return ieee80211_ref_node(ni);
}
/*
- * For some types of packet and for some operating modes, it is
- * desirable to process a Rx packet using its sender's node-record
- * instead of the BSS record, when that is possible.
+ * It is usually desirable to process a Rx packet using its sender's
+ * node-record instead of the BSS record.
*
- * - AP mode: it is desirable to keep a node-record for every
- * authenticated/associated station *in the BSS*. For future use,
- * we also track neighboring APs, since they might belong to the
- * same ESSID.
+ * - AP mode: keep a node-record for every authenticated/associated
+ * station *in the BSS*. For future use, we also track neighboring
+ * APs, since they might belong to the same ESS. APs in the same
+ * ESS may bridge packets to each other, forming a Wireless
+ * Distribution System (WDS).
*
- * - IBSS mode: it is desirable to keep a node-record for every
- * station *in the BSS*.
+ * - IBSS mode: keep a node-record for every station *in the BSS*.
+ * Also track neighboring stations by their beacons/probe responses.
*
- * - monitor mode: it is desirable to keep a node-record for every
- * sender, regardless of BSS.
+ * - monitor mode: keep a node-record for every sender, regardless
+ * of BSS.
*
* - STA mode: the only available node-record is the BSS record,
* ic->ic_bss.
@@ -669,23 +699,32 @@ ieee80211_needs_rxnode(struct ieee80211com *ic, struct ieee80211_frame *wh,
u_int8_t **bssid)
{
struct ieee80211_node *bss = ic->ic_bss;
- int needsnode, rc = 0;
-
- if (ic->ic_opmode == IEEE80211_M_STA)
- return 0;
+ int monitor, rc = 0;
- needsnode = (ic->ic_opmode == IEEE80211_M_MONITOR);
+ monitor = (ic->ic_opmode == IEEE80211_M_MONITOR);
*bssid = NULL;
switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
case IEEE80211_FC0_TYPE_CTL:
+ if (!monitor)
+ break;
return (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
IEEE80211_FC0_SUBTYPE_RTS;
-
case IEEE80211_FC0_TYPE_MGT:
*bssid = wh->i_addr3;
- rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid);
+ switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
+ case IEEE80211_FC0_SUBTYPE_BEACON:
+ case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+ rc = 1;
+ break;
+ default:
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ break;
+ rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid) ||
+ IEEE80211_ADDR_EQ(*bssid, etherbroadcastaddr);
+ break;
+ }
break;
case IEEE80211_FC0_TYPE_DATA:
switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
@@ -708,99 +747,128 @@ ieee80211_needs_rxnode(struct ieee80211com *ic, struct ieee80211_frame *wh,
}
break;
}
- return needsnode || rc;
+ return monitor || rc;
}
+/*
+ * Drivers call this, so increase the reference count before returning
+ * the node.
+ */
struct ieee80211_node *
ieee80211_find_rxnode(struct ieee80211com *ic, struct ieee80211_frame *wh)
{
struct ieee80211_node *ni;
const static u_int8_t zero[IEEE80211_ADDR_LEN];
u_int8_t *bssid;
- ieee80211_node_critsec_decl(s);
if (!ieee80211_needs_rxnode(ic, wh, &bssid))
return ieee80211_ref_node(ic->ic_bss);
- ieee80211_node_critsec_begin(ic, s);
+ IEEE80211_NODE_LOCK(ic);
ni = _ieee80211_find_node(ic, wh->i_addr2);
- ieee80211_node_critsec_end(ic, s);
+ IEEE80211_NODE_UNLOCK(ic);
- if (ni == NULL) {
- if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
- if ((ni = ieee80211_dup_bss(ic, wh->i_addr2)) != NULL)
- IEEE80211_ADDR_COPY(ni->ni_bssid,
- (bssid != NULL) ? bssid : zero);
-
- /* XXX see remarks in ieee80211_find_txnode */
- if (ni != NULL) {
- /* XXX no rate negotiation; just dup */
- ni->ni_rates = ic->ic_bss->ni_rates;
- if (ic->ic_newassoc)
- (*ic->ic_newassoc)(ic, ni, 1);
- }
- IEEE80211_DPRINTF(("%s: faked-up node %p for %s\n",
- __func__, ni, ether_sprintf(wh->i_addr2)));
- }
- ni = ieee80211_ref_node((ni == NULL) ? ic->ic_bss : ni);
- }
- IASSERT(ni != NULL, ("%s: null node", __func__));
- return ni;
+ if (ni != NULL)
+ return ieee80211_ref_node(ni);
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+ return ieee80211_ref_node(ic->ic_bss);
+
+ /* XXX see remarks in ieee80211_find_txnode */
+ /* XXX no rate negotiation; just dup */
+ if ((ni = ieee80211_dup_bss(ic, wh->i_addr2)) == NULL)
+ return ieee80211_ref_node(ic->ic_bss);
+
+ IEEE80211_ADDR_COPY(ni->ni_bssid, (bssid != NULL) ? bssid : zero);
+
+ ni->ni_rates = ic->ic_bss->ni_rates;
+ if (ic->ic_newassoc)
+ (*ic->ic_newassoc)(ic, ni, 1);
+
+ IEEE80211_DPRINTF(("%s: faked-up node %p for %s\n", __func__, ni,
+ ether_sprintf(wh->i_addr2)));
+
+ return ieee80211_ref_node(ni);
}
/*
* Like find but search based on the channel too.
+ *
+ * Note that ieee80211_find_node_for_beacon does not increase the
+ * reference count before returning the node, because drivers are not
+ * expected to call it.
*/
struct ieee80211_node *
-ieee80211_lookup_node(struct ieee80211com *ic,
- u_int8_t *macaddr, struct ieee80211_channel *chan)
+ieee80211_find_node_for_beacon(struct ieee80211com *ic, u_int8_t *macaddr,
+ struct ieee80211_channel *chan, char *ssid)
{
- struct ieee80211_node *ni;
- int hash;
- ieee80211_node_critsec_decl(s);
+ struct ieee80211_node *ni, *best;
+ int hash, best_score, score;
+
+ best = NULL;
+ best_score = -1;
hash = IEEE80211_NODE_HASH(macaddr);
- ieee80211_node_critsec_begin(ic, s);
+ IEEE80211_NODE_LOCK(ic);
LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
- if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) &&
- ni->ni_chan == chan) {
- ieee80211_node_incref(ni);/* mark referenced */
- break;
+ if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr))
+ continue;
+
+ score = (ni->ni_chan == chan) ? 1 : 0;
+
+ if (ssid[1] == 0 || ni->ni_esslen == 0)
+ score++;
+ else if (ssid[1] != ni->ni_esslen ||
+ memcmp(ssid + 2, ni->ni_essid, ssid[1]) != 0)
+ continue;
+
+ if (score > best_score) {
+ best = ni;
+ best_score = score;
}
}
- ieee80211_node_critsec_end(ic, s);
- return ni;
+ IEEE80211_NODE_UNLOCK(ic);
+ return best;
+}
+
+struct ieee80211_node *
+ieee80211_lookup_node(struct ieee80211com *ic,
+ u_int8_t *macaddr, struct ieee80211_channel *chan)
+{
+ char ssid[2] = { 0, 0 };
+ return ieee80211_find_node_for_beacon(ic, macaddr, chan, ssid);
}
static void
-_ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
+ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
{
IASSERT(ni != ic->ic_bss, ("freeing bss node"));
+ IEEE80211_DPRINTF(("%s %s\n", __func__, ether_sprintf(ni->ni_macaddr)));
IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
TAILQ_REMOVE(&ic->ic_node, ni, ni_list);
LIST_REMOVE(ni, ni_hash);
+ ic->ic_nnodes--;
if (!IF_IS_EMPTY(&ni->ni_savedq)) {
IF_PURGE(&ni->ni_savedq);
if (ic->ic_set_tim)
- ic->ic_set_tim(ic, ni->ni_associd, 0);
+ (*ic->ic_set_tim)(ic, ni->ni_associd, 0);
}
if (TAILQ_EMPTY(&ic->ic_node))
ic->ic_inact_timer = 0;
(*ic->ic_node_free)(ic, ni);
+ /* TBD indicate to drivers that a new node can be allocated */
}
void
-ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
+ieee80211_release_node(struct ieee80211com *ic, struct ieee80211_node *ni)
{
- ieee80211_node_critsec_decl(s);
-
- IASSERT(ni != ic->ic_bss, ("freeing ic_bss"));
-
- if (ieee80211_node_decref(ni) == 0) {
- ieee80211_node_critsec_begin(ic, s);
- _ieee80211_free_node(ic, ni);
- ieee80211_node_critsec_end(ic, s);
+ IEEE80211_DPRINTF(("%s %s refcnt %d\n", __func__,
+ ether_sprintf(ni->ni_macaddr), ni->ni_refcnt));
+ if (ieee80211_node_decref(ni) == 0 &&
+ ni->ni_state == IEEE80211_STA_COLLECT) {
+ IEEE80211_NODE_LOCK_BH(ic);
+ ieee80211_free_node(ic, ni);
+ IEEE80211_NODE_UNLOCK_BH(ic);
}
}
@@ -808,12 +876,15 @@ void
ieee80211_free_allnodes(struct ieee80211com *ic)
{
struct ieee80211_node *ni;
- ieee80211_node_critsec_decl(s);
- ieee80211_node_critsec_begin(ic, s);
+ IEEE80211_DPRINTF(("%s\n", __func__));
+ IEEE80211_NODE_LOCK_BH(ic);
while ((ni = TAILQ_FIRST(&ic->ic_node)) != NULL)
- _ieee80211_free_node(ic, ni);
- ieee80211_node_critsec_end(ic, s);
+ ieee80211_free_node(ic, ni);
+ IEEE80211_NODE_UNLOCK_BH(ic);
+
+ if (ic->ic_bss != NULL)
+ ieee80211_node_cleanup(ic, ic->ic_bss); /* for station mode */
}
/*
@@ -826,53 +897,112 @@ ieee80211_free_allnodes(struct ieee80211com *ic)
* process each node only once.
*/
void
-ieee80211_timeout_nodes(struct ieee80211com *ic)
+ieee80211_clean_nodes(struct ieee80211com *ic)
{
- struct ieee80211_node *ni;
- ieee80211_node_critsec_decl(s);
+ struct ieee80211_node *ni, *next_ni;
u_int gen = ic->ic_scangen++; /* NB: ok 'cuz single-threaded*/
-restart:
- ieee80211_node_critsec_begin(ic, s);
- TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
+ IEEE80211_NODE_LOCK(ic);
+ for (ni = TAILQ_FIRST(&ic->ic_node); ni != NULL; ni = next_ni) {
+ next_ni = TAILQ_NEXT(ni, ni_list);
+ if (ic->ic_nnodes <= ic->ic_max_nnodes)
+ break;
if (ni->ni_scangen == gen) /* previously handled */
continue;
ni->ni_scangen = gen;
- if (++ni->ni_inact > ieee80211_inact_max) {
- IEEE80211_DPRINTF(("station %s timed out "
- "due to inactivity (%u secs)\n",
- ether_sprintf(ni->ni_macaddr),
- ni->ni_inact));
- /*
- * Send a deauthenticate frame.
- *
- * Drop the node lock before sending the
- * deauthentication frame in case the driver takes
- * a lock, as this will result in a LOR between the
- * node lock and the driver lock.
- */
- ieee80211_node_critsec_end(ic, s);
+ if (ni->ni_refcnt > 0)
+ continue;
+ IEEE80211_DPRINTF(("station %s purged from LRU cache\n",
+ ether_sprintf(ni->ni_macaddr)));
+ /*
+ * Send a deauthenticate frame.
+ */
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ IEEE80211_NODE_UNLOCK(ic);
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_DEAUTH,
IEEE80211_REASON_AUTH_EXPIRE);
+ IEEE80211_NODE_LOCK(ic);
+ ieee80211_node_leave(ic, ni);
+ } else
ieee80211_free_node(ic, ni);
- ic->ic_stats.is_node_timeout++;
- goto restart;
- }
+ ic->ic_stats.is_node_timeout++;
}
- if (!TAILQ_EMPTY(&ic->ic_node))
- ic->ic_inact_timer = IEEE80211_INACT_WAIT;
- ieee80211_node_critsec_end(ic, s);
+ IEEE80211_NODE_UNLOCK(ic);
}
void
ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f, void *arg)
{
struct ieee80211_node *ni;
- ieee80211_node_critsec_decl(s);
- ieee80211_node_critsec_begin(ic, s);
+ IEEE80211_NODE_LOCK(ic);
TAILQ_FOREACH(ni, &ic->ic_node, ni_list)
(*f)(arg, ni);
- ieee80211_node_critsec_end(ic, s);
+ IEEE80211_NODE_UNLOCK(ic);
+}
+
+void
+ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni,
+ int resp)
+{
+ int newassoc;
+
+ if (ni->ni_associd == 0) {
+ u_int16_t aid;
+
+ /*
+ * It would be clever to search the bitmap
+ * more efficiently, but this will do for now.
+ */
+ for (aid = 1; aid < ic->ic_max_aid; aid++) {
+ if (!IEEE80211_AID_ISSET(aid,
+ ic->ic_aid_bitmap))
+ break;
+ }
+ if (aid >= ic->ic_max_aid) {
+ IEEE80211_SEND_MGMT(ic, ni, resp,
+ IEEE80211_REASON_ASSOC_TOOMANY);
+ ieee80211_node_leave(ic, ni);
+ return;
+ }
+ ni->ni_associd = aid | 0xc000;
+ IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap);
+ newassoc = 1;
+ /* XXX for 11g must turn off short slot time if long
+ slot time sta associates */
+ } else
+ newassoc = 0;
+
+ IEEE80211_DPRINTF(("station %s %s associated at aid %d\n",
+ ether_sprintf(ni->ni_macaddr),
+ (newassoc ? "newly" : "already"),
+ ni->ni_associd & ~0xc000));
+
+ /* give driver a chance to setup state like ni_txrate */
+ if (ic->ic_newassoc)
+ (*ic->ic_newassoc)(ic, ni, newassoc);
+ IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
+ ieee80211_node_newstate(ni, IEEE80211_STA_ASSOC);
+}
+
+/*
+ * Handle bookkeeping for station deauthentication/disassociation
+ * when operating as an ap.
+ */
+void
+ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+
+ IASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP,
+ ("not in ap mode, mode %u", ic->ic_opmode));
+ /*
+ * If node wasn't previously associated all
+ * we need to do is reclaim the reference.
+ */
+ if (ni->ni_associd == 0)
+ return;
+ IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
+ ni->ni_associd = 0;
+ ieee80211_node_newstate(ni, IEEE80211_STA_COLLECT);
}
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index 208d171fe4d..153527353f0 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_node.h,v 1.2 2004/11/02 02:15:49 reyk Exp $ */
+/* $OpenBSD: ieee80211_node.h,v 1.3 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */
/*-
@@ -41,6 +41,7 @@
#define IEEE80211_TRANS_WAIT 5 /* transition wait */
#define IEEE80211_INACT_WAIT 5 /* inactivity timer interval */
#define IEEE80211_INACT_MAX (300/IEEE80211_INACT_WAIT)
+#define IEEE80211_CACHE_SIZE 100
#define IEEE80211_NODE_HASHSIZE 32
/* simple hash is enough for variation of macaddr */
@@ -176,6 +177,8 @@ ieee80211_unref_node(struct ieee80211_node **ni)
*ni = NULL; /* guard against use */
}
+#ifdef __FreeBSD__
+typedef struct mtx ieee80211_node_lock_t;
#define IEEE80211_NODE_LOCK_INIT(_ic, _name) \
mtx_init(&(_ic)->ic_nodelock, _name, "802.11 node table", MTX_DEF)
#define IEEE80211_NODE_LOCK_DESTROY(_ic) mtx_destroy(&(_ic)->ic_nodelock)
@@ -183,6 +186,16 @@ ieee80211_unref_node(struct ieee80211_node **ni)
#define IEEE80211_NODE_UNLOCK(_ic) mtx_unlock(&(_ic)->ic_nodelock)
#define IEEE80211_NODE_LOCK_ASSERT(_ic) \
mtx_assert(&(_ic)->ic_nodelock, MA_OWNED)
+#else
+typedef int ieee80211_node_lock_t;
+#define IEEE80211_NODE_LOCK_INIT(_ic, _name)
+#define IEEE80211_NODE_LOCK_DESTROY(_ic)
+#define IEEE80211_NODE_LOCK(_ic) (_ic)->ic_nodelock = splnet()
+#define IEEE80211_NODE_UNLOCK(_ic) splx((_ic)->ic_nodelock)
+#define IEEE80211_NODE_LOCK_ASSERT(_ic)
+#endif
+#define IEEE80211_NODE_LOCK_BH IEEE80211_NODE_LOCK
+#define IEEE80211_NODE_UNLOCK_BH IEEE80211_NODE_UNLOCK
struct ieee80211com;
@@ -207,15 +220,23 @@ extern struct ieee80211_node *ieee80211_find_rxnode(struct ieee80211com *,
struct ieee80211_frame *);
extern struct ieee80211_node *ieee80211_find_txnode(struct ieee80211com *,
u_int8_t *);
+extern struct ieee80211_node *ieee80211_find_node_for_beacon(
+ struct ieee80211com *, u_int8_t *macaddr,
+ struct ieee80211_channel *, char *ssid);
extern struct ieee80211_node * ieee80211_lookup_node(struct ieee80211com *,
u_int8_t *macaddr, struct ieee80211_channel *);
-extern void ieee80211_free_node(struct ieee80211com *,
+extern void ieee80211_release_node(struct ieee80211com *,
struct ieee80211_node *);
extern void ieee80211_free_allnodes(struct ieee80211com *);
typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
extern void ieee80211_iterate_nodes(struct ieee80211com *ic,
ieee80211_iter_func *, void *);
-extern void ieee80211_timeout_nodes(struct ieee80211com *);
+extern void ieee80211_clean_nodes(struct ieee80211com *);
+
+extern void ieee80211_node_join(struct ieee80211com *,
+ struct ieee80211_node *, int);
+extern void ieee80211_node_leave(struct ieee80211com *,
+ struct ieee80211_node *);
extern int ieee80211_match_bss(struct ieee80211com *,
struct ieee80211_node *);
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 567669e3f1a..d8ccc745ec1 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_output.c,v 1.4 2004/12/28 23:07:32 jsg Exp $ */
+/* $OpenBSD: ieee80211_output.c,v 1.5 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
/*-
@@ -198,7 +198,7 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
ni = ieee80211_find_txnode(ic, eh.ether_dhost);
if (ni == NULL) {
IEEE80211_DPRINTF(("%s: no node for dst %s, discard frame\n",
- __func__, ether_sprintf(eh.ether_dhost)));
+ __func__, ether_sprintf(eh.ether_dhost)));
ic->ic_stats.is_tx_nonode++;
goto bad;
}
@@ -235,7 +235,7 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
- IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
+ IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid);
break;
case IEEE80211_M_HOSTAP:
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
@@ -253,8 +253,7 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
bad:
if (m != NULL)
m_freem(m);
- if (ni && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
*pni = NULL;
return NULL;
}
@@ -390,7 +389,7 @@ ieee80211_compute_duration(struct ieee80211_frame *wh, int len,
else if (lastlen0 != 0) { /* a short "tail" fragment */
lastlen = lastlen0 + overlen;
npkt++;
- } else
+ } else /* full-length "tail" fragment */
lastlen = fraglen + overlen;
if (npktp != NULL)
@@ -515,8 +514,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
* the xmit is complete all the way in the driver. On error we
* will remove our reference.
*/
- if (ni != ic->ic_bss)
- ieee80211_ref_node(ni);
+ ieee80211_ref_node(ni);
timer = 0;
switch (type) {
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
@@ -789,7 +787,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
default:
IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n",
- __func__, type));
+ __func__, type));
senderr(EINVAL, is_tx_unknownmgt);
/* NOTREACHED */
}
@@ -800,8 +798,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
ic->ic_mgt_timer = timer;
} else {
bad:
- if (ni != ic->ic_bss) /* remove ref we added */
- ieee80211_free_node(ic, ni);
+ ieee80211_release_node(ic, ni);
}
return ret;
#undef senderr
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index b086211ac46..708e9c89a4b 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.c,v 1.2 2004/07/04 22:34:14 naddy Exp $ */
+/* $OpenBSD: ieee80211_proto.c,v 1.3 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */
/*-
@@ -463,10 +463,8 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt
case IEEE80211_S_ASSOC:
/* timeout restart scan */
ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr);
- if (ni != NULL) {
+ if (ni != NULL)
ni->ni_fails++;
- ieee80211_unref_node(&ni);
- }
ieee80211_begin_scan(ifp);
break;
}
diff --git a/sys/net80211/ieee80211_regdomain.c b/sys/net80211/ieee80211_regdomain.c
index c30c62e7e0e..fa0722f7be4 100644
--- a/sys/net80211/ieee80211_regdomain.c
+++ b/sys/net80211/ieee80211_regdomain.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_regdomain.c,v 1.2 2004/11/06 18:31:41 reyk Exp $ */
+/* $OpenBSD: ieee80211_regdomain.c,v 1.3 2005/02/17 18:28:05 reyk Exp $ */
/*
* Copyright (c) 2004 Reyk Floeter <reyk@vantronix.net>.
@@ -179,3 +179,15 @@ ieee80211_regdomain2flag(u_int16_t regdomain, u_int16_t mhz)
return((u_int32_t)DMN_DEBUG);
}
+u_int32_t
+ieee80211_countrycode2regdomain(u_int16_t code)
+{
+ int i;
+
+ for (i = 0;
+ i < (sizeof(ieee80211_r_ctry) / sizeof(ieee80211_r_ctry[0])); i++)
+ if (ieee80211_r_ctry[i].cn_code == code)
+ return (ieee80211_r_ctry[i].cn_domain);
+
+ return((u_int32_t)DMN_DEFAULT);
+}
diff --git a/sys/net80211/ieee80211_regdomain.h b/sys/net80211/ieee80211_regdomain.h
index 2f6e9260021..3372b32ac54 100644
--- a/sys/net80211/ieee80211_regdomain.h
+++ b/sys/net80211/ieee80211_regdomain.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_regdomain.h,v 1.4 2004/12/30 23:35:35 reyk Exp $ */
+/* $OpenBSD: ieee80211_regdomain.h,v 1.5 2005/02/17 18:28:05 reyk Exp $ */
/*
* Copyright (c) 2004 Reyk Floeter <reyk@vantronix.net>.
@@ -479,6 +479,18 @@ struct ieee80211_countryname {
{ CTRY_DEBUG, "zz", DMN_DEBUG } \
}
+enum ieee80211_ctl {
+ CTL_11A = 0x00,
+ CTL_11B = 0x01,
+ CTL_11G = 0x02,
+ CTL_TURBO = 0x03,
+ CTL_TURBO_G = 0x04,
+ CTL_FCC = 0x10,
+ CTL_ETSI = 0x30,
+ CTL_MKK = 0x40,
+ CTL_NONE = 0xff
+};
+
struct ieee80211_regchannel {
u_int16_t rc_channel;
u_int32_t rc_mode;
@@ -810,6 +822,7 @@ extern u_int32_t ieee80211_name2regdomain(const char *);
extern const char *ieee80211_countrycode2name(u_int16_t);
extern const char *ieee80211_regdomain2name(u_int32_t);
extern u_int32_t ieee80211_regdomain2flag(u_int16_t, u_int16_t);
+extern u_int32_t ieee80211_countrycode2regdomain(u_int16_t);
__END_DECLS
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 26fd666bbd4..11aa668fa88 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_var.h,v 1.5 2005/02/15 19:44:15 reyk Exp $ */
+/* $OpenBSD: ieee80211_var.h,v 1.6 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */
/*-
@@ -110,6 +110,7 @@ struct ieee80211_channel {
#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+#define IEEE80211_CHAN_XR 0x1000 /* Extended range OFDM channel */
/*
* Useful combinations of channel characteristics.
@@ -126,6 +127,8 @@ struct ieee80211_channel {
(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
#define IEEE80211_CHAN_T \
(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
+#define IEEE80211_CHAN_TG \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
#define IEEE80211_IS_CHAN_FHSS(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
@@ -139,6 +142,8 @@ struct ieee80211_channel {
(((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
#define IEEE80211_IS_CHAN_T(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_T) == IEEE80211_CHAN_T)
+#define IEEE80211_IS_CHAN_TG(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_TG) == IEEE80211_CHAN_TG)
#define IEEE80211_IS_CHAN_2GHZ(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0)
@@ -150,6 +155,8 @@ struct ieee80211_channel {
(((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0)
#define IEEE80211_IS_CHAN_GFSK(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0)
+#define IEEE80211_IS_CHAN_XR(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_XR) != 0)
/* ni_chan encoding for FH phy */
#define IEEE80211_FH_CHANMOD 80
@@ -167,6 +174,7 @@ struct ieee80211com {
#else
struct arpcom ic_ac;
#endif
+ LIST_ENTRY(ieee80211com) ic_list; /* chain of all ieee80211com */
void (*ic_recv_mgmt)(struct ieee80211com *,
struct mbuf *, struct ieee80211_node *,
int, int, u_int32_t);
@@ -192,7 +200,7 @@ struct ieee80211com {
enum ieee80211_phytype ic_phytype; /* XXX wrong for multi-mode */
enum ieee80211_opmode ic_opmode; /* operation mode */
enum ieee80211_state ic_state; /* 802.11 state */
- u_int32_t ic_aid_bitmap[IEEE80211_MAX_AID / 32 + 1];
+ u_int32_t *ic_aid_bitmap;
u_int16_t ic_max_aid;
enum ieee80211_protmode ic_protmode; /* 802.11g protection mode */
struct ifmedia ic_media; /* interface media config */
@@ -206,9 +214,7 @@ struct ieee80211com {
int ic_fixed_rate; /* index to ic_sup_rates[] */
u_int16_t ic_rtsthreshold;
u_int16_t ic_fragthreshold;
-#ifdef __FreeBSD__
- struct mtx ic_nodelock; /* on node table */
-#endif
+ ieee80211_node_lock_t ic_nodelock; /* on node table */
u_int ic_scangen; /* gen# for timeout scan */
struct ieee80211_node *(*ic_node_alloc)(struct ieee80211com *);
void (*ic_node_free)(struct ieee80211com *,
@@ -218,7 +224,11 @@ struct ieee80211com {
const struct ieee80211_node *);
u_int8_t (*ic_node_getrssi)(struct ieee80211com *,
struct ieee80211_node *);
- TAILQ_HEAD(, ieee80211_node) ic_node; /* information of all nodes */
+ TAILQ_HEAD(, ieee80211_node) ic_node; /* information of all nodes
+ * LRU at tail
+ */
+ int ic_nnodes; /* length of ic_nnodes */
+ int ic_max_nnodes; /* max length of ic_nnodes */
LIST_HEAD(, ieee80211_node) ic_hash[IEEE80211_NODE_HASHSIZE];
u_int16_t ic_lintval; /* listen interval */
u_int16_t ic_holdover; /* PM hold over duration */
@@ -249,6 +259,9 @@ struct ieee80211com {
#endif
#define ic_softc ic_if.if_softc
+LIST_HEAD(ieee80211com_head, ieee80211com);
+extern struct ieee80211com_head ieee80211com_head;
+
#define IEEE80211_ADDR_EQ(a1,a2) (memcmp(a1,a2,IEEE80211_ADDR_LEN) == 0)
#define IEEE80211_ADDR_COPY(dst,src) memcpy(dst,src,IEEE80211_ADDR_LEN)
@@ -320,6 +333,6 @@ extern int ieee80211_debug;
#define IEEE80211_DPRINTF2(X)
#endif
-extern int ieee80211_inact_max;
+extern int ieee80211_cache_size;
#endif /* _NET80211_IEEE80211_VAR_H_ */