diff options
author | 2006-11-13 20:06:38 +0000 | |
---|---|---|
committer | 2006-11-13 20:06:38 +0000 | |
commit | bc303e9b522b31d160be11e50e51d35b0965c2e6 (patch) | |
tree | e02040d4abfa68bc890072a690e07f020457b71f /sys/dev/usb/if_rum.c | |
parent | fix macro abuse leading to stray numbers in the vm display. (diff) | |
download | wireguard-openbsd-bc303e9b522b31d160be11e50e51d35b0965c2e6.tar.xz wireguard-openbsd-bc303e9b522b31d160be11e50e51d35b0965c2e6.zip |
first round of commits for proper 11b/g protection support:
- use the newly introduced ieee80211_get_rts() and
ieee80211_get_cts_to_self() functions.
- use CTS-to-self instead of RTS/CTS to protect OFDM frames in
a mixed 11b/g BSS.
- make sure multicast frames are sent using CCK modulation.
remove support for 5GHz radios in ral(4) RT2560 and ural(4).
i'm not aware of any such adapters on the market and 11a code
is known to be broken.
some cleanup while i'm here.
Diffstat (limited to 'sys/dev/usb/if_rum.c')
-rw-r--r-- | sys/dev/usb/if_rum.c | 207 |
1 files changed, 131 insertions, 76 deletions
diff --git a/sys/dev/usb/if_rum.c b/sys/dev/usb/if_rum.c index b2e294ab8a9..b480ef90dd8 100644 --- a/sys/dev/usb/if_rum.c +++ b/sys/dev/usb/if_rum.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_rum.c,v 1.42 2006/10/22 12:27:56 damien Exp $ */ +/* $OpenBSD: if_rum.c,v 1.43 2006/11/13 20:06:38 damien Exp $ */ /*- * Copyright (c) 2005, 2006 Damien Bergamini <damien.bergamini@free.fr> @@ -124,7 +124,7 @@ Static void rum_txeof(usbd_xfer_handle, usbd_private_handle, Static void rum_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status); #if NBPFILTER > 0 -Static uint8_t rum_rxrate(struct rum_rx_desc *); +Static uint8_t rum_rxrate(const struct rum_rx_desc *); #endif Static int rum_ack_rate(struct ieee80211com *, int); Static uint16_t rum_txtime(int, int, uint32_t); @@ -309,11 +309,11 @@ USB_ATTACH(rum) } usb_init_task(&sc->sc_task, rum_task, sc); - timeout_set(&sc->scan_ch, rum_next_scan, sc); + timeout_set(&sc->scan_to, rum_next_scan, sc); sc->amrr.amrr_min_success_threshold = 1; sc->amrr.amrr_max_success_threshold = 10; - timeout_set(&sc->amrr_ch, rum_amrr_timeout, sc); + timeout_set(&sc->amrr_to, rum_amrr_timeout, sc); /* retrieve RT2573 rev. no */ for (ntries = 0; ntries < 1000; ntries++) { @@ -442,19 +442,17 @@ USB_DETACH(rum) if_detach(ifp); usb_rem_task(sc->sc_udev, &sc->sc_task); - timeout_del(&sc->scan_ch); - timeout_del(&sc->amrr_ch); + timeout_del(&sc->scan_to); + timeout_del(&sc->amrr_to); if (sc->amrr_xfer != NULL) { usbd_free_xfer(sc->amrr_xfer); sc->amrr_xfer = NULL; } - if (sc->sc_rx_pipeh != NULL) { usbd_abort_pipe(sc->sc_rx_pipeh); usbd_close_pipe(sc->sc_rx_pipeh); } - if (sc->sc_tx_pipeh != NULL) { usbd_abort_pipe(sc->sc_tx_pipeh); usbd_close_pipe(sc->sc_tx_pipeh); @@ -474,13 +472,12 @@ USB_DETACH(rum) Static int rum_alloc_tx_list(struct rum_softc *sc) { - struct rum_tx_data *data; int i, error; - sc->tx_queued = 0; + sc->tx_cur = sc->tx_queued = 0; - for (i = 0; i < RT2573_TX_LIST_COUNT; i++) { - data = &sc->tx_data[i]; + for (i = 0; i < RUM_TX_LIST_COUNT; i++) { + struct rum_tx_data *data = &sc->tx_data[i]; data->sc = sc; @@ -491,7 +488,6 @@ rum_alloc_tx_list(struct rum_softc *sc) error = ENOMEM; goto fail; } - data->buf = usbd_alloc_buffer(data->xfer, RT2573_TX_DESC_SIZE + IEEE80211_MAX_LEN); if (data->buf == NULL) { @@ -500,7 +496,6 @@ rum_alloc_tx_list(struct rum_softc *sc) error = ENOMEM; goto fail; } - /* clean Tx descriptor */ bzero(data->buf, RT2573_TX_DESC_SIZE); } @@ -514,17 +509,15 @@ fail: rum_free_tx_list(sc); Static void rum_free_tx_list(struct rum_softc *sc) { - struct rum_tx_data *data; int i; - for (i = 0; i < RT2573_TX_LIST_COUNT; i++) { - data = &sc->tx_data[i]; + for (i = 0; i < RUM_TX_LIST_COUNT; i++) { + struct rum_tx_data *data = &sc->tx_data[i]; if (data->xfer != NULL) { usbd_free_xfer(data->xfer); data->xfer = NULL; } - /* * The node has already been freed at that point so don't call * ieee80211_release_node() here. @@ -536,11 +529,10 @@ rum_free_tx_list(struct rum_softc *sc) Static int rum_alloc_rx_list(struct rum_softc *sc) { - struct rum_rx_data *data; int i, error; - for (i = 0; i < RT2573_RX_LIST_COUNT; i++) { - data = &sc->rx_data[i]; + for (i = 0; i < RUM_RX_LIST_COUNT; i++) { + struct rum_rx_data *data = &sc->rx_data[i]; data->sc = sc; @@ -551,7 +543,6 @@ rum_alloc_rx_list(struct rum_softc *sc) error = ENOMEM; goto fail; } - if (usbd_alloc_buffer(data->xfer, MCLBYTES) == NULL) { printf("%s: could not allocate rx buffer\n", USBDEVNAME(sc->sc_dev)); @@ -566,7 +557,6 @@ rum_alloc_rx_list(struct rum_softc *sc) error = ENOMEM; goto fail; } - MCLGET(data->m, M_DONTWAIT); if (!(data->m->m_flags & M_EXT)) { printf("%s: could not allocate rx mbuf cluster\n", @@ -574,7 +564,6 @@ rum_alloc_rx_list(struct rum_softc *sc) error = ENOMEM; goto fail; } - data->buf = mtod(data->m, uint8_t *); } @@ -587,17 +576,15 @@ fail: rum_free_tx_list(sc); Static void rum_free_rx_list(struct rum_softc *sc) { - struct rum_rx_data *data; int i; - for (i = 0; i < RT2573_RX_LIST_COUNT; i++) { - data = &sc->rx_data[i]; + for (i = 0; i < RUM_RX_LIST_COUNT; i++) { + struct rum_rx_data *data = &sc->rx_data[i]; if (data->xfer != NULL) { usbd_free_xfer(data->xfer); data->xfer = NULL; } - if (data->m != NULL) { m_freem(data->m); data->m = NULL; @@ -657,7 +644,7 @@ rum_task(void *arg) case IEEE80211_S_SCAN: rum_set_chan(sc, ic->ic_bss->ni_chan); - timeout_add(&sc->scan_ch, hz / 5); + timeout_add(&sc->scan_to, hz / 5); break; case IEEE80211_S_AUTH: @@ -708,8 +695,8 @@ rum_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) struct rum_softc *sc = ic->ic_if.if_softc; usb_rem_task(sc->sc_udev, &sc->sc_task); - timeout_del(&sc->scan_ch); - timeout_del(&sc->amrr_ch); + timeout_del(&sc->scan_to); + timeout_del(&sc->amrr_to); /* do it in a process context */ sc->sc_state = nstate; @@ -750,8 +737,6 @@ rum_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) s = splnet(); - m_freem(data->m); - data->m = NULL; ieee80211_release_node(ic, data->ni); data->ni = NULL; @@ -774,7 +759,7 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) struct rum_softc *sc = data->sc; struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; - struct rum_rx_desc *desc; + const struct rum_rx_desc *desc; struct ieee80211_frame *wh; struct ieee80211_node *ni; struct mbuf *mnew, *m; @@ -798,7 +783,7 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) goto skip; } - desc = (struct rum_rx_desc *)data->buf; + desc = (const struct rum_rx_desc *)data->buf; if (letoh32(desc->flags) & RT2573_RX_CRC_ERROR) { /* @@ -817,7 +802,6 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) ifp->if_ierrors++; goto skip; } - MCLGET(mnew, M_DONTWAIT); if (!(mnew->m_flags & M_EXT)) { printf("%s: could not allocate rx mbuf cluster\n", @@ -826,7 +810,6 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) ifp->if_ierrors++; goto skip; } - m = data->m; data->m = mnew; data->buf = mtod(data->m, uint8_t *); @@ -882,7 +865,7 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) skip: /* setup a new transfer */ usbd_setup_xfer(xfer, sc->sc_rx_pipeh, data, data->buf, MCLBYTES, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, rum_rxeof); - usbd_transfer(xfer); + (void)usbd_transfer(xfer); } /* @@ -891,7 +874,7 @@ skip: /* setup a new transfer */ */ #if NBPFILTER > 0 Static uint8_t -rum_rxrate(struct rum_rx_desc *desc) +rum_rxrate(const struct rum_rx_desc *desc) { if (letoh32(desc->flags) & RT2573_RX_OFDM) { /* reverse function of rum_plcp_signal */ @@ -921,7 +904,6 @@ rum_rxrate(struct rum_rx_desc *desc) /* * Return the expected ack rate for a frame transmitted at rate `rate'. - * XXX: this should depend on the destination node basic rate set. */ Static int rum_ack_rate(struct ieee80211com *ic, int rate) @@ -1062,7 +1044,7 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) uint32_t flags = 0; uint16_t dur; usbd_status error; - int xferlen, rate; + int rate, xferlen, pktlen, needrts = 0, needcts = 0; wh = mtod(m0, struct ieee80211_frame *); @@ -1075,30 +1057,102 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) wh = mtod(m0, struct ieee80211_frame *); } + /* compute actual packet length (including CRC and crypto overhead) */ + pktlen = m0->m_pkthdr.len + IEEE80211_CRC_LEN; + /* pickup a rate */ - if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == - IEEE80211_FC0_TYPE_MGT) { - /* mgmt frames are sent at the lowest available bit-rate */ + if (IEEE80211_IS_MULTICAST(wh->i_addr1) || + ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_MGT)) { + /* mgmt/multicast frames are sent at the lowest avail. rate */ rate = ni->ni_rates.rs_rates[0]; - } else { - if (ic->ic_fixed_rate != -1) { - rate = ic->ic_sup_rates[ic->ic_curmode]. - rs_rates[ic->ic_fixed_rate]; - } else - rate = ni->ni_rates.rs_rates[ni->ni_txrate]; - } + } else if (ic->ic_fixed_rate != -1) { + rate = ic->ic_sup_rates[ic->ic_curmode]. + rs_rates[ic->ic_fixed_rate]; + } else + rate = ni->ni_rates.rs_rates[ni->ni_txrate]; rate &= IEEE80211_RATE_VAL; - if (rate == 0) - rate = 2; /* fallback to 1Mbps; should not happen */ - data = &sc->tx_data[0]; + /* check if RTS/CTS or CTS-to-self protection must be used */ + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + /* multicast frames are not sent at OFDM rates in 802.11b/g */ + if (pktlen > ic->ic_rtsthreshold) { + needrts = 1; /* RTS/CTS based on frame length */ + } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && + RUM_RATE_IS_OFDM(rate)) { + if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) + needcts = 1; /* CTS-to-self */ + else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) + needrts = 1; /* RTS/CTS */ + } + } + if (needrts || needcts) { + struct mbuf *mprot; + int protrate, ackrate; + uint16_t dur; + + protrate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2; + ackrate = rum_ack_rate(ic, rate); + + dur = rum_txtime(pktlen, rate, ic->ic_flags) + + rum_txtime(RUM_ACK_SIZE, ackrate, ic->ic_flags) + + 2 * sc->sifs; + if (needrts) { + dur += rum_txtime(RUM_CTS_SIZE, rum_ack_rate(ic, + protrate), ic->ic_flags) + sc->sifs; + mprot = ieee80211_get_rts(ic, wh, dur); + } else { + mprot = ieee80211_get_cts_to_self(ic, dur); + } + if (mprot == NULL) { + printf("%s: could not allocate protection frame\n", + sc->sc_dev.dv_xname); + m_freem(m0); + return ENOBUFS; + } + + data = &sc->tx_data[sc->tx_cur]; + desc = (struct rum_tx_desc *)data->buf; + + /* avoid multiple free() of the same node for each fragment */ + data->ni = ieee80211_ref_node(ni); + + m_copydata(mprot, 0, mprot->m_pkthdr.len, + data->buf + RT2573_TX_DESC_SIZE); + rum_setup_tx_desc(sc, desc, + (needrts ? RT2573_TX_NEED_ACK : 0) | RT2573_TX_MORE_FRAG, + 0, mprot->m_pkthdr.len, protrate); + + /* no roundup necessary here */ + xferlen = RT2573_TX_DESC_SIZE + mprot->m_pkthdr.len; + + /* XXX may want to pass the protection frame to BPF */ + + /* mbuf is no longer needed */ + m_freem(mprot); + + usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, + xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, + RUM_TX_TIMEOUT, rum_txeof); + error = usbd_transfer(data->xfer); + if (error != 0 && error != USBD_IN_PROGRESS) { + m_freem(m0); + return error; + } + + sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RUM_TX_LIST_COUNT; + + flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; + } + + data = &sc->tx_data[sc->tx_cur]; desc = (struct rum_tx_desc *)data->buf; - data->m = m0; data->ni = ni; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - flags |= RT2573_TX_ACK; + flags |= RT2573_TX_NEED_ACK; dur = rum_txtime(RUM_ACK_SIZE, rum_ack_rate(ic, rate), ic->ic_flags) + sc->sifs; @@ -1147,16 +1201,17 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) DPRINTFN(10, ("sending frame len=%u rate=%u xfer len=%u\n", m0->m_pkthdr.len + RT2573_TX_DESC_SIZE, rate, xferlen)); + /* mbuf is no longer needed */ + m_freem(m0); + usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RUM_TX_TIMEOUT, rum_txeof); - error = usbd_transfer(data->xfer); - if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) { - m_freem(m0); + if (error != 0 && error != USBD_IN_PROGRESS) return error; - } sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RUM_TX_LIST_COUNT; return 0; } @@ -1179,7 +1234,7 @@ rum_start(struct ifnet *ifp) for (;;) { IF_POLL(&ic->ic_mgtq, m0); if (m0 != NULL) { - if (sc->tx_queued >= RT2573_TX_LIST_COUNT) { + if (sc->tx_queued >= RUM_TX_LIST_COUNT - 1) { ifp->if_flags |= IFF_OACTIVE; break; } @@ -1200,7 +1255,7 @@ rum_start(struct ifnet *ifp) IFQ_POLL(&ifp->if_snd, m0); if (m0 == NULL) break; - if (sc->tx_queued >= RT2573_TX_LIST_COUNT) { + if (sc->tx_queued >= RUM_TX_LIST_COUNT - 1) { ifp->if_flags |= IFF_OACTIVE; break; } @@ -1534,12 +1589,12 @@ rum_set_basicrates(struct rum_softc *sc) if (ic->ic_curmode == IEEE80211_MODE_11B) { /* 11b basic rates: 1, 2Mbps */ rum_write(sc, RT2573_TXRX_CSR5, 0x3); - } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) { + } else if (ic->ic_curmode == IEEE80211_MODE_11A) { /* 11a basic rates: 6, 12, 24Mbps */ rum_write(sc, RT2573_TXRX_CSR5, 0x150); } else { - /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ - rum_write(sc, RT2573_TXRX_CSR5, 0x15f); + /* 11b/g basic rates: 1, 2, 5.5, 11Mbps */ + rum_write(sc, RT2573_TXRX_CSR5, 0xf); } } @@ -1844,11 +1899,10 @@ rum_bbp_init(struct rum_softc *sc) { #define N(a) (sizeof (a) / sizeof ((a)[0])) int i, ntries; - uint8_t val; /* wait for BBP to be ready */ for (ntries = 0; ntries < 100; ntries++) { - val = rum_bbp_read(sc, 0); + const uint8_t val = rum_bbp_read(sc, 0); if (val != 0 && val != 0xff) break; DELAY(1000); @@ -1880,7 +1934,6 @@ rum_init(struct ifnet *ifp) #define N(a) (sizeof (a) / sizeof ((a)[0])) struct rum_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; - struct rum_rx_data *data; uint32_t tmp; usbd_status error; int i, ntries; @@ -1946,7 +1999,6 @@ rum_init(struct ifnet *ifp) USBDEVNAME(sc->sc_dev), usbd_errstr(error)); goto fail; } - error = usbd_open_pipe(sc->sc_iface, sc->sc_rx_no, USBD_EXCLUSIVE_USE, &sc->sc_rx_pipeh); if (error != 0) { @@ -1964,7 +2016,6 @@ rum_init(struct ifnet *ifp) USBDEVNAME(sc->sc_dev)); goto fail; } - error = rum_alloc_rx_list(sc); if (error != 0) { printf("%s: could not allocate Rx list\n", @@ -1975,12 +2026,17 @@ rum_init(struct ifnet *ifp) /* * Start up the receive pipe. */ - for (i = 0; i < RT2573_RX_LIST_COUNT; i++) { - data = &sc->rx_data[i]; + for (i = 0; i < RUM_RX_LIST_COUNT; i++) { + struct rum_rx_data *data = &sc->rx_data[i]; usbd_setup_xfer(data->xfer, sc->sc_rx_pipeh, data, data->buf, MCLBYTES, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, rum_rxeof); - usbd_transfer(data->xfer); + error = usbd_transfer(data->xfer); + if (error != 0 && error != USBD_IN_PROGRESS) { + printf("%s: could not queue Rx transfer\n", + USBDEVNAME(sc->sc_dev)); + goto fail; + } } /* update Rx filter */ @@ -2038,7 +2094,6 @@ rum_stop(struct ifnet *ifp, int disable) usbd_close_pipe(sc->sc_rx_pipeh); sc->sc_rx_pipeh = NULL; } - if (sc->sc_tx_pipeh != NULL) { usbd_abort_pipe(sc->sc_tx_pipeh); usbd_close_pipe(sc->sc_tx_pipeh); @@ -2130,7 +2185,7 @@ rum_amrr_start(struct rum_softc *sc, struct ieee80211_node *ni) i--); ni->ni_txrate = i; - timeout_add(&sc->amrr_ch, hz); + timeout_add(&sc->amrr_to, hz); } Static void @@ -2181,7 +2236,7 @@ rum_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv, ieee80211_amrr_choose(&sc->amrr, sc->sc_ic.ic_bss, &sc->amn); - timeout_add(&sc->amrr_ch, hz); + timeout_add(&sc->amrr_to, hz); } int |