diff options
-rw-r--r-- | share/man/man4/acx.4 | 18 | ||||
-rw-r--r-- | sys/dev/ic/acx.c | 127 |
2 files changed, 92 insertions, 53 deletions
diff --git a/share/man/man4/acx.4 b/share/man/man4/acx.4 index d8ea85390e1..f7f1f2457bf 100644 --- a/share/man/man4/acx.4 +++ b/share/man/man4/acx.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: acx.4,v 1.24 2006/12/19 09:08:18 kettenis Exp $ +.\" $OpenBSD: acx.4,v 1.25 2007/05/03 21:24:56 mglocker Exp $ .\" .\" Copyright (c) 2006 Theo de Raadt. .\" Copyright (c) 2006 The DragonFly Project. All rights reserved. @@ -72,12 +72,12 @@ However, actual connections between stations are peer-to-peer. .It Host AP In this mode the driver acts as an access point (base station) for other cards. -.\" .It monitor mode -.\" In this mode the driver is able to receive packets without -.\" associating with an access point. -.\" This disables the internal receive filter and enables the card to -.\" capture packets from networks which it wouldn't normally have access to, -.\" or to scan for access points. +.It monitor mode +In this mode the driver is able to receive packets without +associating with an access point. +This disables the internal receive filter and enables the card to +capture packets from networks which it wouldn't normally have access to, +or to scan for access points. .El .Pp .Nm @@ -161,8 +161,8 @@ driver supports the following media options: Select Host AP operation. .It Cm ibss Select IBSS operation. -.\".It Cm monitor -.\"Select monitor mode. +.It Cm monitor +Select monitor mode. .El .It Fl mediaopt Ar opts Disable the specified media options on the driver and return it to the diff --git a/sys/dev/ic/acx.c b/sys/dev/ic/acx.c index b3244bca3bd..0298dc3c96c 100644 --- a/sys/dev/ic/acx.c +++ b/sys/dev/ic/acx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acx.c,v 1.73 2007/04/11 21:38:50 mglocker Exp $ */ +/* $OpenBSD: acx.c,v 1.74 2007/05/03 21:24:56 mglocker Exp $ */ /* * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> @@ -146,6 +146,7 @@ void acx_init_info_reg(struct acx_softc *); int acx_config(struct acx_softc *); int acx_read_config(struct acx_softc *, struct acx_config *); int acx_write_config(struct acx_softc *, struct acx_config *); +int acx_rx_config(struct acx_softc *); int acx_set_crypt_keys(struct acx_softc *); void acx_next_scan(void *); @@ -193,8 +194,7 @@ int acx_newstate(struct ieee80211com *, enum ieee80211_state, int); void acx_init_cmd_reg(struct acx_softc *); int acx_join_bss(struct acx_softc *, uint8_t, struct ieee80211_node *); -int acx_enable_txchan(struct acx_softc *, uint8_t); -int acx_enable_rxchan(struct acx_softc *, uint8_t); +int acx_set_channel(struct acx_softc *, uint8_t); int acx_init_radio(struct acx_softc *, uint32_t, uint32_t); void acx_iter_func(void *, struct ieee80211_node *); @@ -304,8 +304,10 @@ acx_attach(struct acx_softc *sc) /* * NOTE: Don't overwrite ic_caps set by chip specific code */ - ic->ic_caps |= IEEE80211_C_WEP | /* WEP */ - IEEE80211_C_IBSS | /* IBSS modes */ + ic->ic_caps = + IEEE80211_C_WEP | /* WEP */ + IEEE80211_C_IBSS | /* IBSS mode */ + IEEE80211_C_MONITOR | /* Monitor mode */ IEEE80211_C_HOSTAP | /* Access Point */ IEEE80211_C_SHPREAMBLE; /* Short preamble */ @@ -379,6 +381,7 @@ int acx_init(struct ifnet *ifp) { struct acx_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; char fname[] = "tiacx111c16"; int error, combined = 0; @@ -465,8 +468,12 @@ acx_init(struct ifnet *ifp) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - /* Begin background scanning */ - ieee80211_new_state(&sc->sc_ic, IEEE80211_S_SCAN, -1); + if (ic->ic_opmode != IEEE80211_M_MONITOR) + /* start background scanning */ + ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); + else + /* in monitor mode change directly into run state */ + ieee80211_new_state(ic, IEEE80211_S_RUN, -1); back: if (error) @@ -616,6 +623,10 @@ acx_config(struct acx_softc *sc) if (error) return (error); + error = acx_rx_config(sc); + if (error) + return (error); + if (acx_set_probe_req_tmplt(sc, "", 0) != 0) { printf("%s: can't set probe req template " "(empty ssid)\n", sc->sc_dev.dv_xname); @@ -717,7 +728,6 @@ acx_write_config(struct acx_softc *sc, struct acx_config *conf) struct acx_conf_rate_fallback rate_fb; struct acx_conf_antenna ant; struct acx_conf_regdom reg_dom; - struct acx_conf_rxopt rx_opt; struct ifnet *ifp = &sc->sc_ic.ic_if; int error; @@ -772,15 +782,39 @@ acx_write_config(struct acx_softc *sc, struct acx_config *conf) return (error); } - /* What we want to receive and how to receive */ - /* XXX may not belong here, acx_init() */ - rx_opt.opt1 = htole16(RXOPT1_FILT_FDEST | RXOPT1_INCL_RXBUF_HDR); - rx_opt.opt2 = htole16(RXOPT2_RECV_ASSOC_REQ | RXOPT2_RECV_AUTH | - RXOPT2_RECV_BEACON | RXOPT2_RECV_CF | RXOPT2_RECV_CTRL | - RXOPT2_RECV_DATA | RXOPT2_RECV_MGMT | RXOPT2_RECV_PROBE_REQ | - RXOPT2_RECV_PROBE_RESP | RXOPT2_RECV_OTHER); + return (0); +} + +int +acx_rx_config(struct acx_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct acx_conf_rxopt rx_opt; + + /* tell the RX receiver what frames we want to have */ + rx_opt.opt1 = htole16(RXOPT1_INCL_RXBUF_HDR); + rx_opt.opt2 = htole16( + RXOPT2_RECV_ASSOC_REQ | + RXOPT2_RECV_AUTH | + RXOPT2_RECV_BEACON | + RXOPT2_RECV_CF | + RXOPT2_RECV_CTRL | + RXOPT2_RECV_DATA | + RXOPT2_RECV_MGMT | + RXOPT2_RECV_PROBE_REQ | + RXOPT2_RECV_PROBE_RESP | + RXOPT2_RECV_OTHER); + + /* in monitor mode go promiscuous */ + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + rx_opt.opt1 |= RXOPT1_PROMISC; + rx_opt.opt2 |= RXOPT2_RECV_BROKEN | RXOPT2_RECV_ACK; + } else + rx_opt.opt1 |= RXOPT1_FILT_FDEST; + + /* finally set the RX options */ if (acx_set_conf(sc, ACX_CONF_RXOPT, &rx_opt, sizeof(rx_opt)) != 0) { - printf("%s: can't set RX option\n", ifp->if_xname); + printf("%s: can not set RX options!\n", sc->sc_dev.dv_xname); return (ENXIO); } @@ -795,6 +829,7 @@ acx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct ifaddr *ifa; struct ifreq *ifr; int s, error = 0; + uint8_t chan; s = splnet(); @@ -826,6 +861,21 @@ acx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (error == ENETRESET) error = 0; break; + case SIOCS80211CHANNEL: + /* allow fast channel switching in monitor mode */ + error = ieee80211_ioctl(ifp, cmd, data); + if (error == ENETRESET && + ic->ic_opmode == IEEE80211_M_MONITOR) { + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == + (IFF_UP | IFF_RUNNING)) { + ic->ic_bss->ni_chan = ic->ic_ibss_chan; + chan = ieee80211_chan2ieee(ic, + ic->ic_bss->ni_chan); + (void)acx_set_channel(sc, chan); + } + error = 0; + } + break; default: error = ieee80211_ioctl(ifp, cmd, data); break; @@ -1683,15 +1733,7 @@ acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) uint8_t chan; chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); - - if (acx_enable_txchan(sc, chan) != 0) { - DPRINTF(("%s: enable TX on channel %d failed\n", - ifp->if_xname, chan)); - } - if (acx_enable_rxchan(sc, chan) != 0) { - DPRINTF(("%s: enable RX on channel %d failed\n", - ifp->if_xname, chan)); - } + (void)acx_set_channel(sc, chan); timeout_add(&sc->sc_chanscan_timer, hz / acx_chanscan_rate); @@ -1739,17 +1781,8 @@ acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) error = 1; - if (acx_enable_txchan(sc, chan) != 0) { - printf("%s: enable TX on channel %d failed\n", - ifp->if_xname, chan); + if (acx_set_channel(sc, chan) != 0) goto back; - } - - if (acx_enable_rxchan(sc, chan) != 0) { - printf("%s: enable RX on channel %d failed\n", - ifp->if_xname, chan); - goto back; - } if (acx_set_beacon_tmplt(sc, ni) != 0) { printf("%s: set beacon template failed\n", @@ -2465,17 +2498,23 @@ acx_join_bss(struct acx_softc *sc, uint8_t mode, struct ieee80211_node *node) } int -acx_enable_txchan(struct acx_softc *sc, uint8_t chan) +acx_set_channel(struct acx_softc *sc, uint8_t chan) { - return (acx_exec_command(sc, ACXCMD_ENABLE_TXCHAN, &chan, sizeof(chan), - NULL, 0)); -} + if (acx_exec_command(sc, ACXCMD_ENABLE_TXCHAN, &chan, sizeof(chan), + NULL, 0) != 0) { + DPRINTF(("%s: setting TX channel %d failed\n", + sc->sc_dev.dv_xname, chan)); + return (ENXIO); + } -int -acx_enable_rxchan(struct acx_softc *sc, uint8_t chan) -{ - return (acx_exec_command(sc, ACXCMD_ENABLE_RXCHAN, &chan, sizeof(chan), - NULL, 0)); + if (acx_exec_command(sc, ACXCMD_ENABLE_RXCHAN, &chan, sizeof(chan), + NULL, 0) != 0) { + DPRINTF(("%s: setting RX channel %d failed\n", + sc->sc_dev.dv_xname, chan)); + return (ENXIO); + } + + return (0); } int |