summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Glocker <mglocker@cvs.openbsd.org>2007-05-03 21:24:57 +0000
committerMarcus Glocker <mglocker@cvs.openbsd.org>2007-05-03 21:24:57 +0000
commitbc942897e2ccde50d855a9f425c48522fd86b3c1 (patch)
tree96581e5b33e040488df9597c4d7257d766ccafc3
parent2a1dbae779144e573ece4e58b7b150553c6fba43 (diff)
Add monitor mode. Add fast channel switching. Do some simplifications
while there. Comments, tested, and OK claudio@
-rw-r--r--share/man/man4/acx.418
-rw-r--r--sys/dev/ic/acx.c127
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