diff options
author | Marcus Glocker <mglocker@cvs.openbsd.org> | 2007-06-01 23:43:33 +0000 |
---|---|---|
committer | Marcus Glocker <mglocker@cvs.openbsd.org> | 2007-06-01 23:43:33 +0000 |
commit | 980158b9fd0f04fd96168924ec21adf0d6e00253 (patch) | |
tree | 80983985afef38d45979300c10709002b9bfd012 | |
parent | 1b739e73e223f9c851a42f8417dda3d6e71ed3ff (diff) |
Add RX path and enable monitor mode.
-rw-r--r-- | sys/dev/pcmcia/if_malo.c | 163 | ||||
-rw-r--r-- | sys/dev/pcmcia/if_maloreg.h | 14 | ||||
-rw-r--r-- | sys/dev/pcmcia/if_malovar.h | 21 |
3 files changed, 167 insertions, 31 deletions
diff --git a/sys/dev/pcmcia/if_malo.c b/sys/dev/pcmcia/if_malo.c index 3f1fb570c24..026a1516027 100644 --- a/sys/dev/pcmcia/if_malo.c +++ b/sys/dev/pcmcia/if_malo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_malo.c,v 1.8 2007/05/28 13:51:09 mglocker Exp $ */ +/* $OpenBSD: if_malo.c,v 1.9 2007/06/01 23:43:32 mglocker Exp $ */ /* * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org> @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "bpfilter.h" + #include <sys/param.h> #include <sys/proc.h> #include <sys/systm.h> @@ -26,6 +28,11 @@ #include <sys/tree.h> #include <sys/malloc.h> #include <sys/sockio.h> +#include <sys/mbuf.h> + +#if NBPFILTER > 0 +#include <net/bpf.h> +#endif #include <net/if.h> #include <net/if_media.h> @@ -68,9 +75,12 @@ int cmalo_fw_load_helper(struct malo_softc *); int cmalo_fw_load_main(struct malo_softc *); int cmalo_init(struct ifnet *); void cmalo_stop(struct malo_softc *); +int cmalo_media_change(struct ifnet *); +int cmalo_newstate(struct ieee80211com *, enum ieee80211_state, int); void cmalo_detach(void *); int cmalo_intr(void *); -void cmalo_intr_mask(struct malo_softc *sc, int); +void cmalo_intr_mask(struct malo_softc *, int); +void cmalo_rx(struct malo_softc *); void cmalo_hexdump(void *, int); int cmalo_cmd_get_hwspec(struct malo_softc *); @@ -246,12 +256,15 @@ cmalo_attach(void *arg) return; sc->sc_flags |= MALO_FW_LOADED; + /* allocate command buffer */ + sc->sc_cmd = malloc(MALO_CMD_BUFFER_SIZE, M_DEVBUF, M_NOWAIT); + + /* allocate data buffer */ + sc->sc_data = malloc(MCLBYTES, M_DEVBUF, M_NOWAIT); + /* enable interrupts */ cmalo_intr_mask(sc, 1); - /* allocate command buffer */ - sc->sc_cmd = malloc(MALO_CMD_BUFFER_SIZE, M_USBDEV, M_WAITOK); - /* get hardware specs */ cmalo_cmd_get_hwspec(sc); @@ -267,6 +280,7 @@ cmalo_attach(void *arg) ic->ic_opmode = IEEE80211_M_STA; ic->ic_state = IEEE80211_S_INIT; ic->ic_caps = + IEEE80211_C_MONITOR | IEEE80211_C_IBSS | IEEE80211_C_WEP; @@ -285,8 +299,9 @@ cmalo_attach(void *arg) if_attach(ifp); ieee80211_ifattach(ifp); - ieee80211_media_init(ifp, ieee80211_media_change, - ieee80211_media_status); + sc->sc_newstate = ic->ic_newstate; + ic->ic_newstate = cmalo_newstate; + ieee80211_media_init(ifp, cmalo_media_change, ieee80211_media_status); /* second attach line */ printf("%s: address %s\n", @@ -325,10 +340,17 @@ cmalo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } break; default: - error = EINVAL; + error = ieee80211_ioctl(ifp, cmd, data); break; } + if (error == ENETRESET) { + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == + (IFF_UP | IFF_RUNNING)) + cmalo_init(ifp); + error = 0; + } + splx(s); return (error); @@ -376,13 +398,14 @@ cmalo_fw_load_helper(struct malo_softc *sc) uc = (uint16_t *)(ucode + offset); for (i = 0; i < bsize / 2; i++) MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i])); - MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DNLD_OVER); - MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DNLD_OVER); + MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER); + MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, + MALO_VAL_CMD_DL_OVER); /* poll for an acknowledgement */ for (i = 0; i < 50; i++) { if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) == - MALO_VAL_DNLD_OVER) + MALO_VAL_CMD_DL_OVER) break; delay(1000); } @@ -397,8 +420,8 @@ cmalo_fw_load_helper(struct malo_softc *sc) /* helper firmware download done */ MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, 0); - MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DNLD_OVER); - MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DNLD_OVER); + MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER); + MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER); DPRINTF(1, "%s: helper FW downloaded\n", sc->sc_dev.dv_xname); return (0); @@ -462,13 +485,14 @@ cmalo_fw_load_main(struct malo_softc *sc) uc = (uint16_t *)(ucode + offset); for (i = 0; i < bsize / 2; i++) MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i])); - MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DNLD_OVER); - MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DNLD_OVER); + MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER); + MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, + MALO_VAL_CMD_DL_OVER); /* poll for an acknowledgement */ for (i = 0; i < 5000; i++) { if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) == - MALO_VAL_DNLD_OVER) + MALO_VAL_CMD_DL_OVER) break; } if (i == 5000) { @@ -521,7 +545,9 @@ cmalo_init(struct ifnet *ifp) } /* setup device */ - if (cmalo_cmd_set_channel(sc, 1) != 0) + if (cmalo_cmd_set_macctrl(sc) != 0) + return (EIO); + if (cmalo_cmd_set_txpower(sc, 15) != 0) return (EIO); if (cmalo_cmd_set_antenna(sc, 1) != 0) return (EIO); @@ -529,11 +555,7 @@ cmalo_init(struct ifnet *ifp) return (EIO); if (cmalo_cmd_set_radio(sc, 1) != 0) return (EIO); - if (cmalo_cmd_set_txpower(sc, 15) != 0) - return (EIO); - if (cmalo_cmd_set_macctrl(sc) != 0) - return (EIO); - if (cmalo_cmd_set_macaddr(sc) != 0) + if (cmalo_cmd_set_channel(sc, 1) != 0) return (EIO); /* device up */ @@ -558,6 +580,28 @@ cmalo_stop(struct malo_softc *sc) ifp->if_flags &= ~IFF_RUNNING; } +int +cmalo_media_change(struct ifnet *ifp) +{ + int error; + + if ((error = ieee80211_media_change(ifp) != ENETRESET)) + return (error); + + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) + cmalo_init(ifp); + + return (0); +} + +int +cmalo_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) +{ + struct malo_softc *sc = ic->ic_if.if_softc; + + return (sc->sc_newstate(ic, nstate, arg)); +} + void cmalo_detach(void *arg) { @@ -573,6 +617,10 @@ cmalo_detach(void *arg) if (sc->sc_cmd != NULL) free(sc->sc_cmd, M_DEVBUF); + /* free data buffer */ + if (sc->sc_data != NULL) + free(sc->sc_data, M_DEVBUF); + /* detach inferface */ ieee80211_ifdetach(ifp); if_detach(ifp); @@ -598,6 +646,9 @@ cmalo_intr(void *arg) DPRINTF(2, "%s: interrupt handler called (intr = 0x%04x)\n", sc->sc_dev.dv_xname, intr); + if (intr & MALO_VAL_HOST_INTR_RX) + /* RX frame received */ + cmalo_rx(sc); if (intr & MALO_VAL_HOST_INTR_CMD) /* command response */ sc->sc_cmd_running = 0; @@ -632,6 +683,65 @@ cmalo_intr_mask(struct malo_softc *sc, int enable) } void +cmalo_rx(struct malo_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + struct malo_rx_desc *rxdesc; + struct mbuf *m; + uint8_t *data; + uint16_t psize, *uc; + int i; + + /* read the whole RX packet */ + psize = MALO_READ_2(sc, MALO_REG_DATA_READ_LEN); + uc = (uint16_t *)sc->sc_data; + for (i = 0; i < psize / 2; i++) + uc[i] = htole16(MALO_READ_2(sc, MALO_REG_DATA_READ)); + if (psize & 0x0001) + uc[i] = MALO_READ_1(sc, MALO_REG_DATA_READ); + MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DATA_DL_OVER); + MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DATA_DL_OVER); + + rxdesc = (struct malo_rx_desc *)sc->sc_data; + + DPRINTF(2, "RX status=%d, pkglen=%d, pkgoffset=%d\n", + rxdesc->status, rxdesc->pkglen, rxdesc->pkgoffset); + + if (rxdesc->status != MALO_RX_STATUS_OK) + /* RX packet is not OK */ + return; + + /* prepare mbuf */ + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + ifp->if_ierrors++; + return; + } + MCLGET(m, M_DONTWAIT); + if (!(m->m_flags & M_EXT)) { + ifp->if_ierrors++; + m_freem(m); + return; + } + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = letoh16(rxdesc->pkglen); + data = mtod(m, uint8_t *); + bcopy(sc->sc_data + rxdesc->pkgoffset, data, m->m_pkthdr.len); + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); +#endif + + /* push the frame up to the network stack if not in monitor mode */ + if (ic->ic_opmode != IEEE80211_M_MONITOR) + ether_input_mbuf(ifp, m); + + m_freem(m); +} + +void cmalo_hexdump(void *buf, int len) { #ifdef CMALO_DEBUG @@ -868,7 +978,7 @@ cmalo_cmd_set_antenna(struct malo_softc *sc, uint16_t action) if (action == 1) /* set RX antenna */ - body->antenna_mode = htole16(0xffff); /* diversity */ + body->antenna_mode = htole16(0xffff); if (action == 2) /* set TX antenna */ body->antenna_mode = htole16(2); @@ -886,6 +996,7 @@ cmalo_cmd_set_antenna(struct malo_softc *sc, uint16_t action) int cmalo_cmd_set_macctrl(struct malo_softc *sc) { + struct ieee80211com *ic = &sc->sc_ic; struct malo_cmd_header *hdr = sc->sc_cmd; struct malo_cmd_body_macctrl *body; uint16_t psize; @@ -901,6 +1012,8 @@ cmalo_cmd_set_macctrl(struct malo_softc *sc) body->action = htole16(MALO_CMD_MACCTRL_RX_ON); body->action |= htole16(MALO_CMD_MACCTRL_TX_ON); + if (ic->ic_opmode == IEEE80211_M_MONITOR) + body->action |= htole16(MALO_CMD_MACCTRL_PROMISC_ON); /* process command request */ if (cmalo_cmd_request(sc, psize, 0) != 0) @@ -958,8 +1071,8 @@ cmalo_cmd_request(struct malo_softc *sc, uint16_t psize, int no_response) uc = (uint16_t *)sc->sc_cmd; for (i = 0; i < psize / 2; i++) MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i])); - MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_DNLD_OVER); - MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_DNLD_OVER); + MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER); + MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER); if (no_response) /* we don't expect a response */ diff --git a/sys/dev/pcmcia/if_maloreg.h b/sys/dev/pcmcia/if_maloreg.h index eac3cdfa99b..aa8563b990f 100644 --- a/sys/dev/pcmcia/if_maloreg.h +++ b/sys/dev/pcmcia/if_maloreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_maloreg.h,v 1.4 2007/05/28 13:51:09 mglocker Exp $ */ +/* $OpenBSD: if_maloreg.h,v 1.5 2007/06/01 23:43:32 mglocker Exp $ */ /* * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org> @@ -16,28 +16,31 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* I/O registers */ +/* registers */ #define MALO_REG_HOST_STATUS 0x00 #define MALO_REG_CARD_INTR_CAUSE 0x02 #define MALO_REG_HOST_INTR_MASK 0x04 +#define MALO_REG_DATA_READ 0x10 #define MALO_REG_CMD_READ 0x12 #define MALO_REG_CMD_WRITE_LEN 0x18 #define MALO_REG_CMD_WRITE 0x1a #define MALO_REG_CARD_STATUS 0x20 #define MALO_REG_HOST_INTR_CAUSE 0x22 +#define MALO_REG_DATA_READ_LEN 0x24 #define MALO_REG_RBAL 0x28 #define MALO_REG_CMD_READ_LEN 0x30 #define MALO_REG_SCRATCH 0x3f #define MALO_REG_CARD_INTR_MASK 0x44 -/* I/O register values */ +/* register values */ #define MALO_VAL_SCRATCH_READY 0x00 #define MALO_VAL_SCRATCH_FW_LOADED 0x5a #define MALO_VAL_HOST_INTR_MASK_ON 0x001f -#define MALO_VAL_DNLD_OVER (1 << 2) +#define MALO_VAL_DATA_DL_OVER 0x02 +#define MALO_VAL_CMD_DL_OVER 0x04 /* interrupt reasons */ -#define MALO_VAL_HOST_INTR_RX (1 << 0) +#define MALO_VAL_HOST_INTR_RX (1 << 1) #define MALO_VAL_HOST_INTR_CMD (1 << 3) /* FW commands */ @@ -60,3 +63,4 @@ #define MALO_CMD_RADIO_AUTO_P 0x0004 #define MALO_CMD_MACCTRL_RX_ON 0x0001 #define MALO_CMD_MACCTRL_TX_ON 0x0002 +#define MALO_CMD_MACCTRL_PROMISC_ON 0x0080 diff --git a/sys/dev/pcmcia/if_malovar.h b/sys/dev/pcmcia/if_malovar.h index 2235e3edec0..79740109658 100644 --- a/sys/dev/pcmcia/if_malovar.h +++ b/sys/dev/pcmcia/if_malovar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_malovar.h,v 1.5 2007/05/28 13:51:09 mglocker Exp $ */ +/* $OpenBSD: if_malovar.h,v 1.6 2007/06/01 23:43:32 mglocker Exp $ */ /* * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org> @@ -109,13 +109,32 @@ struct malo_cmd_body_macaddr { uint8_t macaddr[ETHER_ADDR_LEN]; } __packed; +/* RX descriptor */ +#define MALO_RX_STATUS_OK 0x0001 +struct malo_rx_desc { + uint16_t status; + uint8_t snr; + uint8_t control; + uint16_t pkglen; + uint8_t nf; + uint8_t rate; + uint32_t pkgoffset; + uint32_t reserved1; + uint8_t priority; + uint8_t reserved2[3]; +} __packed; + struct malo_softc { struct device sc_dev; struct ieee80211com sc_ic; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + int (*sc_newstate) + (struct ieee80211com *, enum ieee80211_state, + int); int sc_flags; void *sc_cmd; uint8_t sc_cmd_running; + void *sc_data; }; |