diff options
-rw-r--r-- | sys/dev/ic/ath.c | 18 | ||||
-rw-r--r-- | sys/dev/ic/atw.c | 13 | ||||
-rw-r--r-- | sys/dev/ic/ral.c | 24 | ||||
-rw-r--r-- | sys/dev/ic/rtw.c | 16 | ||||
-rw-r--r-- | sys/dev/pci/if_ipw.c | 15 | ||||
-rw-r--r-- | sys/dev/pci/if_iwi.c | 17 | ||||
-rw-r--r-- | sys/dev/usb/if_atu.c | 12 | ||||
-rw-r--r-- | sys/net80211/ieee80211.c | 254 | ||||
-rw-r--r-- | sys/net80211/ieee80211.h | 94 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 414 | ||||
-rw-r--r-- | sys/net80211/ieee80211_ioctl.c | 11 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 472 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 27 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 19 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.c | 6 | ||||
-rw-r--r-- | sys/net80211/ieee80211_regdomain.c | 14 | ||||
-rw-r--r-- | sys/net80211/ieee80211_regdomain.h | 15 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 27 |
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_ */ |