diff options
Diffstat (limited to 'sys/dev/usb/if_rum.c')
-rw-r--r-- | sys/dev/usb/if_rum.c | 978 |
1 files changed, 465 insertions, 513 deletions
diff --git a/sys/dev/usb/if_rum.c b/sys/dev/usb/if_rum.c index 7657d10..ec46c84 100644 --- a/sys/dev/usb/if_rum.c +++ b/sys/dev/usb/if_rum.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_phy.h> #include <net80211/ieee80211_radiotap.h> #include <net80211/ieee80211_regdomain.h> @@ -128,23 +129,23 @@ MODULE_DEPEND(rum, wlan, 1, 1, 1); MODULE_DEPEND(rum, wlan_amrr, 1, 1, 1); MODULE_DEPEND(rum, usb, 1, 1, 1); +static struct ieee80211vap *rum_vap_create(struct ieee80211com *, + const char name[IFNAMSIZ], int unit, int opmode, + int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void rum_vap_delete(struct ieee80211vap *); static int rum_alloc_tx_list(struct rum_softc *); static void rum_free_tx_list(struct rum_softc *); static int rum_alloc_rx_list(struct rum_softc *); static void rum_free_rx_list(struct rum_softc *); -static int rum_media_change(struct ifnet *); static void rum_task(void *); static void rum_scantask(void *); -static int rum_newstate(struct ieee80211com *, +static int rum_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void rum_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status); static void rum_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status); -static int rum_rxrate(struct rum_rx_desc *); -static int rum_ack_rate(struct ieee80211com *, int); -static uint16_t rum_txtime(int, int, uint32_t); -static uint8_t rum_plcp_signal(int); static void rum_setup_tx_desc(struct rum_softc *, struct rum_tx_desc *, uint32_t, uint16_t, int, int); @@ -185,13 +186,17 @@ static void rum_update_promisc(struct rum_softc *); static const char *rum_get_rf(int); static void rum_read_eeprom(struct rum_softc *); static int rum_bbp_init(struct rum_softc *); +static void rum_init_locked(struct rum_softc *); static void rum_init(void *); static void rum_stop(void *); static int rum_load_microcode(struct rum_softc *, const u_char *, size_t); -static int rum_prepare_beacon(struct rum_softc *); +static int rum_prepare_beacon(struct rum_softc *, + struct ieee80211vap *); static int rum_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); +static struct ieee80211_node *rum_node_alloc(struct ieee80211_node_table *); +static void rum_newassoc(struct ieee80211_node *, int); static void rum_scan_start(struct ieee80211com *); static void rum_scan_end(struct ieee80211com *); static void rum_set_channel(struct ieee80211com *); @@ -378,21 +383,21 @@ rum_attach(device_t self) { struct rum_softc *sc = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; struct ifnet *ifp; const uint8_t *ucode = NULL; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; usbd_status error; - int i, ntries, size, bands; + int i, ntries, size; + uint8_t bands; uint32_t tmp; sc->sc_udev = uaa->device; sc->sc_dev = self; if (usbd_set_config_no(sc->sc_udev, RT2573_CONFIG_NO, 0) != 0) { - printf("%s: could not set configuration no\n", - device_get_nameunit(sc->sc_dev)); + device_printf(self, "could not set configuration no\n"); return ENXIO; } @@ -400,8 +405,7 @@ rum_attach(device_t self) error = usbd_device2interface_handle(sc->sc_udev, RT2573_IFACE_INDEX, &sc->sc_iface); if (error != 0) { - printf("%s: could not get interface handle\n", - device_get_nameunit(sc->sc_dev)); + device_printf(self, "could not get interface handle\n"); return ENXIO; } @@ -414,8 +418,8 @@ rum_attach(device_t self) for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); if (ed == NULL) { - printf("%s: no endpoint descriptor for iface %d\n", - device_get_nameunit(sc->sc_dev), i); + device_printf(self, + "no endpoint descriptor for iface %d\n", i); return ENXIO; } @@ -427,18 +431,23 @@ rum_attach(device_t self) sc->sc_tx_no = ed->bEndpointAddress; } if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) { - printf("%s: missing endpoint\n", - device_get_nameunit(sc->sc_dev)); + device_printf(self, "missing endpoint\n"); return ENXIO; } + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(self, "can not if_alloc()\n"); + return ENXIO; + } + ic = ifp->if_l2com; + mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); usb_init_task(&sc->sc_task, rum_task, sc); usb_init_task(&sc->sc_scantask, rum_scantask, sc); callout_init(&sc->watchdog_ch, 0); - callout_init(&sc->amrr_ch, 0); /* retrieve RT2573 rev. no */ for (ntries = 0; ntries < 1000; ntries++) { @@ -447,32 +456,22 @@ rum_attach(device_t self) DELAY(1000); } if (ntries == 1000) { - printf("%s: timeout waiting for chip to settle\n", - device_get_nameunit(sc->sc_dev)); - return ENXIO; + device_printf(self, "timeout waiting for chip to settle\n"); + goto bad; } /* retrieve MAC address and various other things from EEPROM */ rum_read_eeprom(sc); - printf("%s: MAC/BBP RT2573 (rev 0x%05x), RF %s\n", - device_get_nameunit(sc->sc_dev), tmp, rum_get_rf(sc->rf_rev)); + device_printf(self, "MAC/BBP RT2573 (rev 0x%05x), RF %s\n", + tmp, rum_get_rf(sc->rf_rev)); ucode = rt2573_ucode; size = sizeof rt2573_ucode; error = rum_load_microcode(sc, ucode, size); if (error != 0) { - device_printf(sc->sc_dev, "could not load 8051 microcode\n"); - mtx_destroy(&sc->sc_mtx); - return ENXIO; - } - - ifp = sc->sc_ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) { - printf("%s: can not if_alloc()\n", - device_get_nameunit(sc->sc_dev)); - mtx_destroy(&sc->sc_mtx); - return ENXIO; + device_printf(self, "could not load 8051 microcode\n"); + goto bad; } ifp->if_softc = sc; @@ -488,82 +487,47 @@ rum_attach(device_t self) ic->ic_ifp = ifp; ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ - ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ - ic->ic_state = IEEE80211_S_INIT; /* set device capabilities */ ic->ic_caps = - IEEE80211_C_IBSS | /* IBSS mode supported */ - IEEE80211_C_MONITOR | /* monitor mode supported */ - IEEE80211_C_HOSTAP | /* HostAp mode supported */ - IEEE80211_C_TXPMGT | /* tx power management */ - IEEE80211_C_SHPREAMBLE | /* short preamble supported */ - IEEE80211_C_SHSLOT | /* short slot time supported */ - IEEE80211_C_BGSCAN | /* bg scanning supported */ - IEEE80211_C_WPA; /* 802.11i */ + IEEE80211_C_IBSS /* IBSS mode supported */ + | IEEE80211_C_MONITOR /* monitor mode supported */ + | IEEE80211_C_HOSTAP /* HostAp mode supported */ + | IEEE80211_C_TXPMGT /* tx power management */ + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ + | IEEE80211_C_SHSLOT /* short slot time supported */ + | IEEE80211_C_BGSCAN /* bg scanning supported */ + | IEEE80211_C_WPA /* 802.11i */ + ; bands = 0; setbit(&bands, IEEE80211_MODE_11B); setbit(&bands, IEEE80211_MODE_11G); - ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1); - - if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) { - struct ieee80211_channel *c; - - /* set supported .11a channels */ - for (i = 34; i <= 46; i += 4) { - c = &ic->ic_channels[ic->ic_nchans++]; - c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A; - c->ic_ieee = i; - } - for (i = 36; i <= 64; i += 4) { - c = &ic->ic_channels[ic->ic_nchans++]; - c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A; - c->ic_ieee = i; - } - for (i = 100; i <= 140; i += 4) { - c = &ic->ic_channels[ic->ic_nchans++]; - c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A; - c->ic_ieee = i; - } - for (i = 149; i <= 165; i += 4) { - c = &ic->ic_channels[ic->ic_nchans++]; - c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A; - c->ic_ieee = i; - } - } + if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) + setbit(&bands, IEEE80211_MODE_11A); + ieee80211_init_channels(ic, NULL, &bands); ieee80211_ifattach(ic); + ic->ic_newassoc = rum_newassoc; + ic->ic_raw_xmit = rum_raw_xmit; + ic->ic_node_alloc = rum_node_alloc; ic->ic_scan_start = rum_scan_start; ic->ic_scan_end = rum_scan_end; ic->ic_set_channel = rum_set_channel; - /* enable s/w bmiss handling in sta mode */ - ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; + ic->ic_vap_create = rum_vap_create; + ic->ic_vap_delete = rum_vap_delete; - /* override state transition machine */ - sc->sc_newstate = ic->ic_newstate; - ic->ic_newstate = rum_newstate; - ic->ic_raw_xmit = rum_raw_xmit; - ieee80211_media_init(ic, rum_media_change, ieee80211_media_status); - - ieee80211_amrr_init(&sc->amrr, ic, - IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, - IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD); + sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); - bpfattach2(ifp, DLT_IEEE802_11_RADIO, - sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, - &sc->sc_drvbpf); + bpfattach(ifp, DLT_IEEE802_11_RADIO, + sizeof (struct ieee80211_frame) + sizeof(sc->sc_txtap)); - sc->sc_rxtap_len = sizeof sc->sc_rxtapu; + sc->sc_rxtap_len = sizeof sc->sc_rxtap; sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2573_RX_RADIOTAP_PRESENT); - sc->sc_txtap_len = sizeof sc->sc_txtapu; + sc->sc_txtap_len = sizeof sc->sc_txtap; sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); sc->sc_txtap.wt_ihdr.it_present = htole32(RT2573_TX_RADIOTAP_PRESENT); @@ -571,20 +535,26 @@ rum_attach(device_t self) ieee80211_announce(ic); return 0; +bad: + mtx_destroy(&sc->sc_mtx); + if_free(ifp); + return ENXIO; } static int rum_detach(device_t self) { struct rum_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; rum_stop(sc); + bpfdetach(ifp); + ieee80211_ifdetach(ic); + usb_rem_task(sc->sc_udev, &sc->sc_task); usb_rem_task(sc->sc_udev, &sc->sc_scantask); callout_stop(&sc->watchdog_ch); - callout_stop(&sc->amrr_ch); if (sc->amrr_xfer != NULL) { usbd_free_xfer(sc->amrr_xfer); @@ -603,22 +573,66 @@ rum_detach(device_t self) rum_free_rx_list(sc); rum_free_tx_list(sc); - bpfdetach(ifp); - ieee80211_ifdetach(ic); if_free(ifp); - mtx_destroy(&sc->sc_mtx); return 0; } +static struct ieee80211vap * +rum_vap_create(struct ieee80211com *ic, + const char name[IFNAMSIZ], int unit, int opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct rum_vap *rvp; + struct ieee80211vap *vap; + + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + return NULL; + rvp = (struct rum_vap *) malloc(sizeof(struct rum_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (rvp == NULL) + return NULL; + vap = &rvp->vap; + /* enable s/w bmiss handling for sta mode */ + ieee80211_vap_setup(ic, vap, name, unit, opmode, + flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); + + /* override state transition machine */ + rvp->newstate = vap->iv_newstate; + vap->iv_newstate = rum_newstate; + + callout_init(&rvp->amrr_ch, 0); + ieee80211_amrr_init(&rvp->amrr, vap, + IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, + IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, + 1000 /* 1 sec */); + + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); + ic->ic_opmode = opmode; + return vap; +} + +static void +rum_vap_delete(struct ieee80211vap *vap) +{ + struct rum_vap *rvp = RUM_VAP(vap); + + callout_stop(&rvp->amrr_ch); + ieee80211_amrr_cleanup(&rvp->amrr); + ieee80211_vap_detach(vap); + free(rvp, M_80211_VAP); +} + static int rum_alloc_tx_list(struct rum_softc *sc) { struct rum_tx_data *data; int i, error; - sc->tx_queued = 0; + sc->tx_queued = sc->tx_cur = 0; for (i = 0; i < RUM_TX_LIST_COUNT; i++) { data = &sc->tx_data[i]; @@ -627,16 +641,16 @@ rum_alloc_tx_list(struct rum_softc *sc) data->xfer = usbd_alloc_xfer(sc->sc_udev); if (data->xfer == NULL) { - printf("%s: could not allocate tx xfer\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, + "could not allocate tx xfer\n"); error = ENOMEM; goto fail; } data->buf = usbd_alloc_buffer(data->xfer, RT2573_TX_DESC_SIZE + MCLBYTES); if (data->buf == NULL) { - printf("%s: could not allocate tx buffer\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, + "could not allocate tx buffer\n"); error = ENOMEM; goto fail; } @@ -684,22 +698,22 @@ rum_alloc_rx_list(struct rum_softc *sc) data->xfer = usbd_alloc_xfer(sc->sc_udev); if (data->xfer == NULL) { - printf("%s: could not allocate rx xfer\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, + "could not allocate rx xfer\n"); error = ENOMEM; goto fail; } if (usbd_alloc_buffer(data->xfer, MCLBYTES) == NULL) { - printf("%s: could not allocate rx buffer\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, + "could not allocate rx buffer\n"); error = ENOMEM; goto fail; } data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); if (data->m == NULL) { - printf("%s: could not allocate rx mbuf\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, + "could not allocate rx mbuf\n"); error = ENOMEM; goto fail; } @@ -733,39 +747,20 @@ rum_free_rx_list(struct rum_softc *sc) } } -static int -rum_media_change(struct ifnet *ifp) -{ - struct rum_softc *sc = ifp->if_softc; - int error; - - RUM_LOCK(sc); - - error = ieee80211_media_change(ifp); - if (error != ENETRESET) { - RUM_UNLOCK(sc); - return error; - } - - if ((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & IFF_DRV_RUNNING)) - rum_init(sc); - - RUM_UNLOCK(sc); - - return 0; -} - static void rum_task(void *arg) { struct rum_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct rum_vap *rvp = RUM_VAP(vap); + const struct ieee80211_txparam *tp; enum ieee80211_state ostate; struct ieee80211_node *ni; uint32_t tmp; - ostate = ic->ic_state; + ostate = vap->iv_state; RUM_LOCK(sc); @@ -779,9 +774,9 @@ rum_task(void *arg) break; case IEEE80211_S_RUN: - ni = ic->ic_bss; + ni = vap->iv_bss; - if (ic->ic_opmode != IEEE80211_M_MONITOR) { + if (vap->iv_opmode != IEEE80211_M_MONITOR) { rum_update_slot(ic->ic_ifp); rum_enable_mrr(sc); rum_set_txpreamble(sc); @@ -789,16 +784,16 @@ rum_task(void *arg) rum_set_bssid(sc, ni->ni_bssid); } - if (ic->ic_opmode == IEEE80211_M_HOSTAP || - ic->ic_opmode == IEEE80211_M_IBSS) - rum_prepare_beacon(sc); + if (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS) + rum_prepare_beacon(sc, vap); - if (ic->ic_opmode != IEEE80211_M_MONITOR) + if (vap->iv_opmode != IEEE80211_M_MONITOR) rum_enable_tsf_sync(sc); - /* enable automatic rate adaptation in STA mode */ - if (ic->ic_opmode == IEEE80211_M_STA && - ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) + /* enable automatic rate adaptation */ + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; + if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) rum_amrr_start(sc, ni); break; default: @@ -807,40 +802,42 @@ rum_task(void *arg) RUM_UNLOCK(sc); - sc->sc_newstate(ic, sc->sc_state, sc->sc_arg); + IEEE80211_LOCK(ic); + rvp->newstate(vap, sc->sc_state, sc->sc_arg); + if (vap->iv_newstate_cb != NULL) + vap->iv_newstate_cb(vap, sc->sc_state, sc->sc_arg); + IEEE80211_UNLOCK(ic); } static int -rum_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) +rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { + struct rum_vap *rvp = RUM_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; struct rum_softc *sc = ic->ic_ifp->if_softc; - callout_stop(&sc->amrr_ch); + callout_stop(&rvp->amrr_ch); /* do it in a process context */ sc->sc_state = nstate; sc->sc_arg = arg; usb_rem_task(sc->sc_udev, &sc->sc_task); - if (nstate == IEEE80211_S_INIT) - sc->sc_newstate(ic, nstate, arg); - else + if (nstate == IEEE80211_S_INIT) { + rvp->newstate(vap, nstate, arg); + return 0; + } else { usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER); - return 0; + return EINPROGRESS; + } } -/* quickly determine if a given rate is CCK or OFDM */ -#define RUM_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) - -#define RUM_ACK_SIZE 14 /* 10 + 4(FCS) */ -#define RUM_CTS_SIZE 14 /* 10 + 4(FCS) */ - static void rum_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct rum_tx_data *data = priv; struct rum_softc *sc = data->sc; - struct ifnet *ifp = sc->sc_ic.ic_ifp; + struct ifnet *ifp = sc->sc_ifp; if (data->m != NULL && data->m->m_flags & M_TXCB) ieee80211_process_callback(data->ni, data->m, 0/*XXX*/); @@ -849,8 +846,8 @@ rum_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; - printf("%s: could not transmit buffer: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(status)); + device_printf(sc->sc_dev, "could not transmit buffer: %s\n", + usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh); @@ -879,10 +876,9 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct rum_rx_data *data = priv; struct rum_softc *sc = data->sc; - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rum_rx_desc *desc; - struct ieee80211_frame *wh; struct ieee80211_node *ni; struct mbuf *mnew, *m; int len, rssi; @@ -934,31 +930,29 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) rssi = rum_get_rssi(sc, desc->rssi); - wh = mtod(m, struct ieee80211_frame *); - ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); - - /* Error happened during RSSI conversion. */ - if (rssi < 0) - rssi = ni->ni_rssi; - - if (bpf_peers_present(sc->sc_drvbpf)) { + if (bpf_peers_present(ifp->if_bpf)) { struct rum_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = IEEE80211_RADIOTAP_F_FCS; - tap->wr_rate = rum_rxrate(desc); + tap->wr_rate = ieee80211_plcp2rate(desc->rate, + le32toh(desc->flags) & RT2573_RX_OFDM); tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); tap->wr_antenna = sc->rx_ant; tap->wr_antsignal = rssi; - bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); + bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); } - /* send the frame to the 802.11 layer */ - ieee80211_input(ic, m, ni, rssi, RT2573_NOISE_FLOOR, 0); - - /* node is no longer needed */ - ieee80211_free_node(ni); + ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); + if (ni != NULL) { + /* Error happened during RSSI conversion. */ + if (rssi < 0) + rssi = -30; /* XXX ignored by net80211 */ + (void) ieee80211_input(ni, m, rssi, RT2573_NOISE_FLOOR, 0); + ieee80211_free_node(ni); + } else + (void) ieee80211_input_all(ic, m, rssi, RT2573_NOISE_FLOOR, 0); DPRINTFN(15, ("rx done\n")); @@ -968,125 +962,12 @@ skip: /* setup a new transfer */ usbd_transfer(xfer); } -/* - * This function is only used by the Rx radiotap code. - */ -static int -rum_rxrate(struct rum_rx_desc *desc) -{ - if (le32toh(desc->flags) & RT2573_RX_OFDM) { - /* reverse function of rum_plcp_signal */ - switch (desc->rate) { - case 0xb: return 12; - case 0xf: return 18; - case 0xa: return 24; - case 0xe: return 36; - case 0x9: return 48; - case 0xd: return 72; - case 0x8: return 96; - case 0xc: return 108; - } - } else { - if (desc->rate == 10) - return 2; - if (desc->rate == 20) - return 4; - if (desc->rate == 55) - return 11; - if (desc->rate == 110) - return 22; - } - return 2; /* should not get there */ -} - -/* - * Return the expected ack rate for a frame transmitted at rate `rate'. - */ -static int -rum_ack_rate(struct ieee80211com *ic, int rate) -{ - switch (rate) { - /* CCK rates */ - case 2: - return 2; - case 4: - case 11: - case 22: - return (ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate; - - /* OFDM rates */ - case 12: - case 18: - return 12; - case 24: - case 36: - return 24; - case 48: - case 72: - case 96: - case 108: - return 48; - } - - /* default to 1Mbps */ - return 2; -} - -/* - * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'. - * The function automatically determines the operating mode depending on the - * given rate. `flags' indicates whether short preamble is in use or not. - */ -static uint16_t -rum_txtime(int len, int rate, uint32_t flags) -{ - uint16_t txtime; - - if (RUM_RATE_IS_OFDM(rate)) { - /* IEEE Std 802.11a-1999, pp. 37 */ - txtime = (8 + 4 * len + 3 + rate - 1) / rate; - txtime = 16 + 4 + 4 * txtime + 6; - } else { - /* IEEE Std 802.11b-1999, pp. 28 */ - txtime = (16 * len + rate - 1) / rate; - if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE)) - txtime += 72 + 24; - else - txtime += 144 + 48; - } - return txtime; -} - -static uint8_t -rum_plcp_signal(int rate) -{ - switch (rate) { - /* CCK rates (returned values are device-dependent) */ - case 2: return 0x0; - case 4: return 0x1; - case 11: return 0x2; - case 22: return 0x3; - - /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ - case 12: return 0xb; - case 18: return 0xf; - case 24: return 0xa; - case 36: return 0xe; - case 48: return 0x9; - case 72: return 0xd; - case 96: return 0x8; - case 108: return 0xc; - - /* unsupported rates (should not get there) */ - default: return 0xff; - } -} - static void rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, uint32_t flags, uint16_t xflags, int len, int rate) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t plcp_length; int remainder; @@ -1100,11 +981,11 @@ rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, RT2573_LOGCWMIN(4) | RT2573_LOGCWMAX(10)); /* setup PLCP fields */ - desc->plcp_signal = rum_plcp_signal(rate); + desc->plcp_signal = ieee80211_rate2plcp(rate); desc->plcp_service = 4; len += IEEE80211_CRC_LEN; - if (RUM_RATE_IS_OFDM(rate)) { + if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) { desc->flags |= htole32(RT2573_TX_OFDM); plcp_length = len & 0xfff; @@ -1128,43 +1009,108 @@ rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, #define RUM_TX_TIMEOUT 5000 static int +rum_sendprot(struct rum_softc *sc, + const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) +{ + struct ieee80211com *ic = ni->ni_ic; + const struct ieee80211_frame *wh; + struct rum_tx_desc *desc; + struct rum_tx_data *data; + struct mbuf *mprot; + int protrate, ackrate, pktlen, flags, isshort; + uint16_t dur; + usbd_status error; + + KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, + ("protection %d", prot)); + + wh = mtod(m, const struct ieee80211_frame *); + pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; + + protrate = ieee80211_ctl_rate(sc->sc_rates, rate); + ackrate = ieee80211_ack_rate(sc->sc_rates, rate); + + isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; + dur = ieee80211_compute_duration(sc->sc_rates, pktlen, rate, isshort); + + ieee80211_ack_duration(sc->sc_rates, rate, isshort); + flags = RT2573_TX_MORE_FRAG; + if (prot == IEEE80211_PROT_RTSCTS) { + /* NB: CTS is the same size as an ACK */ + dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort); + flags |= RT2573_TX_NEED_ACK; + mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); + } else { + mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); + } + if (mprot == NULL) { + /* XXX stat + msg */ + return ENOBUFS; + } + data = &sc->tx_data[sc->tx_cur]; + desc = (struct rum_tx_desc *)data->buf; + + data->m = mprot; + 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, flags, 0, mprot->m_pkthdr.len, protrate); + + usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, + /* NB: no roundup necessary */ + RT2573_TX_DESC_SIZE + mprot->m_pkthdr.len, + 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) { + data->m = NULL; + data->ni = NULL; + return error; + } + + sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RUM_TX_LIST_COUNT; + + return 0; +} + +static int rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rum_tx_desc *desc; struct rum_tx_data *data; struct ieee80211_frame *wh; + const struct ieee80211_txparam *tp; struct ieee80211_key *k; uint32_t flags = 0; uint16_t dur; usbd_status error; - int xferlen, rate; - - data = &sc->tx_data[0]; - desc = (struct rum_tx_desc *)data->buf; - - rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; + int xferlen; + data = &sc->tx_data[sc->tx_cur]; data->m = m0; data->ni = ni; + desc = (struct rum_tx_desc *)data->buf; wh = mtod(m0, struct ieee80211_frame *); - if (wh->i_fc[1] & IEEE80211_FC1_WEP) { - k = ieee80211_crypto_encap(ic, ni, m0); + k = ieee80211_crypto_encap(ni, m0); if (k == NULL) { m_freem(m0); return ENOBUFS; } + wh = mtod(m0, struct ieee80211_frame *); } - wh = mtod(m0, struct ieee80211_frame *); + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RT2573_TX_NEED_ACK; - dur = rum_txtime(RUM_ACK_SIZE, rum_ack_rate(ic, rate), - ic->ic_flags) + sc->sifs; + dur = ieee80211_ack_duration(sc->sc_rates, tp->mgmtrate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); *(uint16_t *)wh->i_dur = htole16(dur); /* tell hardware to add timestamp for probe responses */ @@ -1174,20 +1120,20 @@ rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) flags |= RT2573_TX_TIMESTAMP; } - if (bpf_peers_present(sc->sc_drvbpf)) { + if (bpf_peers_present(ifp->if_bpf)) { struct rum_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = tp->mgmtrate; tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); tap->wt_antenna = sc->tx_ant; - bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); } m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RT2573_TX_DESC_SIZE); - rum_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate); + rum_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, tp->mgmtrate); /* align end on a 4-bytes boundary */ xferlen = (RT2573_TX_DESC_SIZE + m0->m_pkthdr.len + 3) & ~3; @@ -1200,7 +1146,7 @@ rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) xferlen += 4; DPRINTFN(10, ("sending mgt frame len=%d rate=%d xfer len=%d\n", - m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, rate, xferlen)); + m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, tp->mgmtrate, xferlen)); 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); @@ -1214,6 +1160,7 @@ rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) } sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RUM_TX_LIST_COUNT; return 0; } @@ -1222,14 +1169,17 @@ static int rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rum_tx_desc *desc; struct rum_tx_data *data; uint32_t flags; usbd_status error; int xferlen, rate; - data = &sc->tx_data[0]; + KASSERT(params != NULL, ("no raw xmit params")); + + data = &sc->tx_data[sc->tx_cur]; desc = (struct rum_tx_desc *)data->buf; rate = params->ibp_rate0 & IEEE80211_RATE_VAL; @@ -1238,8 +1188,22 @@ rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, m_freem(m0); return EINVAL; } + flags = 0; + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) + flags |= RT2573_TX_NEED_ACK; + if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { + error = rum_sendprot(sc, m0, ni, + params->ibp_flags & IEEE80211_BPF_RTS ? + IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, + rate); + if (error) { + m_freem(m0); + return error; + } + flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; + } - if (bpf_peers_present(sc->sc_drvbpf)) { + if (bpf_peers_present(ifp->if_bpf)) { struct rum_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; @@ -1248,16 +1212,12 @@ rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); tap->wt_antenna = sc->tx_ant; - bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); } data->m = m0; data->ni = ni; - flags = 0; - if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) - flags |= RT2573_TX_NEED_ACK; - m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RT2573_TX_DESC_SIZE); /* XXX need to setup descriptor ourself */ rum_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate); @@ -1284,6 +1244,7 @@ rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, return error; sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RUM_TX_LIST_COUNT; return 0; } @@ -1291,10 +1252,13 @@ rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, static int rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rum_tx_desc *desc; struct rum_tx_data *data; struct ieee80211_frame *wh; + const struct ieee80211_txparam *tp; struct ieee80211_key *k; uint32_t flags = 0; uint16_t dur; @@ -1303,15 +1267,18 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) wh = mtod(m0, struct ieee80211_frame *); - if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) - rate = ic->ic_fixed_rate; - else - rate = ni->ni_rates.rs_rates[ni->ni_txrate]; - - rate &= IEEE80211_RATE_VAL; + tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + rate = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + rate = tp->ucastrate; + else { + (void) ieee80211_amrr_choose(ni, &RUM_NODE(ni)->amn); + rate = ni->ni_txrate; + } if (wh->i_fc[1] & IEEE80211_FC1_WEP) { - k = ieee80211_crypto_encap(ic, ni, m0); + k = ieee80211_crypto_encap(ni, m0); if (k == NULL) { m_freem(m0); return ENOBUFS; @@ -1321,7 +1288,24 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) wh = mtod(m0, struct ieee80211_frame *); } - data = &sc->tx_data[0]; + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + int prot = IEEE80211_PROT_NONE; + if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) + prot = IEEE80211_PROT_RTSCTS; + else if ((ic->ic_flags & IEEE80211_F_USEPROT) && + ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) + prot = ic->ic_protmode; + if (prot != IEEE80211_PROT_NONE) { + error = rum_sendprot(sc, m0, ni, prot, rate); + if (error) { + m_freem(m0); + return error; + } + 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; @@ -1331,12 +1315,12 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) flags |= RT2573_TX_NEED_ACK; flags |= RT2573_TX_MORE_FRAG; - dur = rum_txtime(RUM_ACK_SIZE, rum_ack_rate(ic, rate), - ic->ic_flags) + sc->sifs; + dur = ieee80211_ack_duration(sc->sc_rates, rate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); *(uint16_t *)wh->i_dur = htole16(dur); } - if (bpf_peers_present(sc->sc_drvbpf)) { + if (bpf_peers_present(ifp->if_bpf)) { struct rum_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; @@ -1345,7 +1329,7 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); tap->wt_antenna = sc->tx_ant; - bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); } m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RT2573_TX_DESC_SIZE); @@ -1376,6 +1360,7 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) } sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RUM_TX_LIST_COUNT; return 0; } @@ -1384,77 +1369,30 @@ static void rum_start(struct ifnet *ifp) { struct rum_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; - struct mbuf *m0; - struct ether_header *eh; + struct mbuf *m; for (;;) { - IF_POLL(&ic->ic_mgtq, m0); - if (m0 != NULL) { - if (sc->tx_queued >= RUM_TX_LIST_COUNT) { - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - break; - } - IF_DEQUEUE(&ic->ic_mgtq, m0); - - ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif; - m0->m_pkthdr.rcvif = NULL; - - if (bpf_peers_present(ic->ic_rawbpf)) - bpf_mtap(ic->ic_rawbpf, m0); - - if (rum_tx_mgt(sc, m0, ni) != 0) { - ieee80211_free_node(ni); - break; - } - } else { - if (ic->ic_state != IEEE80211_S_RUN) - break; - IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); - if (m0 == NULL) - break; - if (sc->tx_queued >= RUM_TX_LIST_COUNT) { - IFQ_DRV_PREPEND(&ifp->if_snd, m0); - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - break; - } - /* - * Cancel any background scan. - */ - if (ic->ic_flags & IEEE80211_F_SCAN) - ieee80211_cancel_scan(ic); - - if (m0->m_len < sizeof (struct ether_header) && - !(m0 = m_pullup(m0, sizeof (struct ether_header)))) - continue; - - eh = mtod(m0, struct ether_header *); - ni = ieee80211_find_txnode(ic, eh->ether_dhost); - if (ni == NULL) { - m_freem(m0); - continue; - } - BPF_MTAP(ifp, m0); - - m0 = ieee80211_encap(ic, m0, ni); - if (m0 == NULL) { - ieee80211_free_node(ni); - continue; - } - - if (bpf_peers_present(ic->ic_rawbpf)) - bpf_mtap(ic->ic_rawbpf, m0); - - if (rum_tx_data(sc, m0, ni) != 0) { - ieee80211_free_node(ni); - ifp->if_oerrors++; - break; - } + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->tx_queued >= RUM_TX_LIST_COUNT-1) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; + m = ieee80211_encap(ni, m); + if (m == NULL) { + ieee80211_free_node(ni); + continue; + } + if (rum_tx_data(sc, m, ni) != 0) { + ieee80211_free_node(ni); + ifp->if_oerrors++; + break; } - sc->sc_tx_timer = 5; - ic->ic_lastdata = ticks; callout_reset(&sc->watchdog_ch, hz, rum_watchdog, sc); } } @@ -1484,37 +1422,35 @@ static int rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct rum_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; - int error = 0; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; RUM_LOCK(sc); - switch (cmd) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - rum_update_promisc(sc); - else + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { rum_init(sc); + startall = 1; + } else + rum_update_promisc(sc); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) rum_stop(sc); } break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; default: - error = ieee80211_ioctl(ic, cmd, data); - } - - if (error == ENETRESET) { - if ((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & IFF_DRV_RUNNING) && - (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)) - rum_init(sc); - error = 0; + error = ether_ioctl(ifp, cmd, data); } - RUM_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); return error; } @@ -1532,8 +1468,8 @@ rum_eeprom_read(struct rum_softc *sc, uint16_t addr, void *buf, int len) error = usbd_do_request(sc->sc_udev, &req, buf); if (error != 0) { - printf("%s: could not read EEPROM: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not read EEPROM: %s\n", + usbd_errstr(error)); } } @@ -1561,8 +1497,9 @@ rum_read_multi(struct rum_softc *sc, uint16_t reg, void *buf, int len) error = usbd_do_request(sc->sc_udev, &req, buf); if (error != 0) { - printf("%s: could not multi read MAC register: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, + "could not multi read MAC register: %s\n", + usbd_errstr(error)); } } @@ -1588,8 +1525,9 @@ rum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len) error = usbd_do_request(sc->sc_udev, &req, buf); if (error != 0) { - printf("%s: could not multi write MAC register: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, + "could not multi write MAC register: %s\n", + usbd_errstr(error)); } } @@ -1604,8 +1542,7 @@ rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) break; } if (ntries == 5) { - printf("%s: could not write to BBP\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, "could not write to BBP\n"); return; } @@ -1624,8 +1561,7 @@ rum_bbp_read(struct rum_softc *sc, uint8_t reg) break; } if (ntries == 5) { - printf("%s: could not read BBP\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, "could not read BBP\n"); return 0; } @@ -1639,7 +1575,7 @@ rum_bbp_read(struct rum_softc *sc, uint8_t reg) DELAY(1); } - printf("%s: could not read BBP\n", device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, "could not read BBP\n"); return 0; } @@ -1654,8 +1590,7 @@ rum_rf_write(struct rum_softc *sc, uint8_t reg, uint32_t val) break; } if (ntries == 5) { - printf("%s: could not write to RF\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, "could not write to RF\n"); return; } @@ -1697,13 +1632,14 @@ rum_select_antenna(struct rum_softc *sc) static void rum_enable_mrr(struct rum_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; tmp = rum_read(sc, RT2573_TXRX_CSR4); tmp &= ~RT2573_MRR_CCK_FALLBACK; - if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) + if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) tmp |= RT2573_MRR_CCK_FALLBACK; tmp |= RT2573_MRR_ENABLED; @@ -1713,12 +1649,14 @@ rum_enable_mrr(struct rum_softc *sc) static void rum_set_txpreamble(struct rum_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; tmp = rum_read(sc, RT2573_TXRX_CSR4); tmp &= ~RT2573_SHORT_PREAMBLE; - if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE) + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) tmp |= RT2573_SHORT_PREAMBLE; rum_write(sc, RT2573_TXRX_CSR4, tmp); @@ -1727,13 +1665,14 @@ rum_set_txpreamble(struct rum_softc *sc) static void rum_set_basicrates(struct rum_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; /* update basic rate set */ 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 (IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) { /* 11a basic rates: 6, 12, 24Mbps */ rum_write(sc, RT2573_TXRX_CSR5, 0x150); } else { @@ -1787,15 +1726,13 @@ rum_select_band(struct rum_softc *sc, struct ieee80211_channel *c) else tmp |= RT2573_PA_PE_5GHZ; rum_write(sc, RT2573_PHY_CSR0, tmp); - - /* 802.11a uses a 16 microseconds short interframe space */ - sc->sifs = IEEE80211_IS_CHAN_5GHZ(c) ? 16 : 10; } static void rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct rfprog *rfprog; uint8_t bbp3, bbp94 = RT2573_BBPR94_DEFAULT; int8_t power; @@ -1868,10 +1805,12 @@ rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) static void rum_enable_tsf_sync(struct rum_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t tmp; - if (ic->ic_opmode != IEEE80211_M_STA) { + if (vap->iv_opmode != IEEE80211_M_STA) { /* * Change default 16ms TBTT adjustment to 8ms. * Must be done before enabling beacon generation. @@ -1882,10 +1821,10 @@ rum_enable_tsf_sync(struct rum_softc *sc) tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000; /* set beacon interval (in 1/16ms unit) */ - tmp |= ic->ic_bss->ni_intval * 16; + tmp |= vap->iv_bss->ni_intval * 16; tmp |= RT2573_TSF_TICKING | RT2573_ENABLE_TBTT; - if (ic->ic_opmode == IEEE80211_M_STA) + if (vap->iv_opmode == IEEE80211_M_STA) tmp |= RT2573_TSF_MODE(1); else tmp |= RT2573_TSF_MODE(2) | RT2573_GENERATE_BEACON; @@ -1897,7 +1836,7 @@ static void rum_update_slot(struct ifnet *ifp) { struct rum_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = ifp->if_l2com; uint8_t slottime; uint32_t tmp; @@ -1937,7 +1876,7 @@ rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr) static void rum_update_promisc(struct rum_softc *sc) { - struct ifnet *ifp = sc->sc_ic.ic_ifp; + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; tmp = rum_read(sc, RT2573_TXRX_CSR0); @@ -1967,7 +1906,8 @@ rum_get_rf(int rev) static void rum_read_eeprom(struct rum_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t val; #ifdef RUM_DEBUG int i; @@ -2082,12 +2022,11 @@ rum_bbp_init(struct rum_softc *sc) } static void -rum_init(void *priv) +rum_init_locked(struct rum_softc *sc) { #define N(a) (sizeof (a) / sizeof ((a)[0])) - struct rum_softc *sc = priv; - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct rum_rx_data *data; uint32_t tmp; usbd_status error; @@ -2111,8 +2050,8 @@ rum_init(void *priv) DELAY(1000); } if (ntries == 1000) { - printf("%s: timeout waiting for BBP/RF to wakeup\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, + "timeout waiting for BBP/RF to wakeup\n"); goto fail; } @@ -2138,8 +2077,7 @@ rum_init(void *priv) */ sc->amrr_xfer = usbd_alloc_xfer(sc->sc_udev); if (sc->amrr_xfer == NULL) { - printf("%s: could not allocate AMRR xfer\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, "could not allocate AMRR xfer\n"); goto fail; } @@ -2149,15 +2087,15 @@ rum_init(void *priv) error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE, &sc->sc_tx_pipeh); if (error != 0) { - printf("%s: could not open Tx pipe: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not open Tx pipe: %s\n", + 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) { - printf("%s: could not open Rx pipe: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not open Rx pipe: %s\n", + usbd_errstr(error)); goto fail; } @@ -2166,14 +2104,12 @@ rum_init(void *priv) */ error = rum_alloc_tx_list(sc); if (error != 0) { - printf("%s: could not allocate Tx list\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, "could not allocate Tx list\n"); goto fail; } error = rum_alloc_rx_list(sc); if (error != 0) { - printf("%s: could not allocate Rx list\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, "could not allocate Rx list\n"); goto fail; } @@ -2204,13 +2140,6 @@ rum_init(void *priv) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; - - if (ic->ic_opmode != IEEE80211_M_MONITOR) { - if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) - ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); - } else - ieee80211_new_state(ic, IEEE80211_S_RUN, -1); - return; fail: rum_stop(sc); @@ -2218,18 +2147,30 @@ fail: rum_stop(sc); } static void +rum_init(void *priv) +{ + struct rum_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + RUM_LOCK(sc); + rum_init_locked(sc); + RUM_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void rum_stop(void *priv) { struct rum_softc *sc = priv; - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; sc->sc_tx_timer = 0; ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - ieee80211_new_state(ic, IEEE80211_S_INIT, -1); - /* disable Rx */ tmp = rum_read(sc, RT2573_TXRX_CSR0); rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); @@ -2277,30 +2218,28 @@ rum_load_microcode(struct rum_softc *sc, const u_char *ucode, size_t size) error = usbd_do_request(sc->sc_udev, &req, NULL); if (error != 0) { - printf("%s: could not run firmware: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not run firmware: %s\n", + usbd_errstr(error)); } return error; } static int -rum_prepare_beacon(struct rum_softc *sc) +rum_prepare_beacon(struct rum_softc *sc, struct ieee80211vap *vap) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = vap->iv_ic; + const struct ieee80211_txparam *tp; struct rum_tx_desc desc; struct mbuf *m0; - int rate; - m0 = ieee80211_beacon_alloc(ic->ic_bss, &sc->sc_bo); + m0 = ieee80211_beacon_alloc(vap->iv_bss, &RUM_VAP(vap)->bo); if (m0 == NULL) { return ENOBUFS; } - /* send beacons at the lowest available rate */ - rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; - + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; rum_setup_tx_desc(sc, &desc, RT2573_TX_TIMESTAMP, RT2573_TX_HWSEQ, - m0->m_pkthdr.len, rate); + m0->m_pkthdr.len, tp->mgmtrate); /* copy the first 24 bytes of Tx descriptor into NIC memory */ rum_write_multi(sc, RT2573_HW_BEACON_BASE0, (uint8_t *)&desc, 24); @@ -2318,8 +2257,7 @@ static int rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { - struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = ni->ni_ic->ic_ifp; struct rum_softc *sc = ifp->if_softc; /* prevent management frames from being sent if we're not ready */ @@ -2328,16 +2266,13 @@ rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, ieee80211_free_node(ni); return ENETDOWN; } - if (sc->tx_queued >= RUM_TX_LIST_COUNT) { + if (sc->tx_queued >= RUM_TX_LIST_COUNT-1) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; m_freem(m); ieee80211_free_node(ni); return EIO; } - if (bpf_peers_present(ic->ic_rawbpf)) - bpf_mtap(ic->ic_rawbpf, m); - ifp->if_opackets++; if (params == NULL) { @@ -2368,26 +2303,22 @@ bad: static void rum_amrr_start(struct rum_softc *sc, struct ieee80211_node *ni) { - int i; + struct ieee80211vap *vap = ni->ni_vap; + struct rum_vap *rvp = RUM_VAP(vap); /* clear statistic registers (STA_CSR0 to STA_CSR5) */ rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta); - ieee80211_amrr_node_init(&sc->amrr, &sc->amn); - - /* set rate to some reasonable initial value */ - for (i = ni->ni_rates.rs_nrates - 1; - i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72; - i--); - ni->ni_txrate = i; + ieee80211_amrr_node_init(&rvp->amrr, &RUM_NODE(ni)->amn, ni); - callout_reset(&sc->amrr_ch, hz, rum_amrr_timeout, sc); + callout_reset(&rvp->amrr_ch, hz, rum_amrr_timeout, vap); } static void rum_amrr_timeout(void *arg) { - struct rum_softc *sc = (struct rum_softc *)arg; + struct ieee80211vap *vap = arg; + struct rum_softc *sc = vap->iv_ic->ic_ifp->if_softc; usb_device_request_t req; /* @@ -2399,7 +2330,7 @@ rum_amrr_timeout(void *arg) USETW(req.wIndex, RT2573_STA_CSR0); USETW(req.wLength, sizeof sc->sta); - usbd_setup_default_xfer(sc->amrr_xfer, sc->sc_udev, sc, + usbd_setup_default_xfer(sc->amrr_xfer, sc->sc_udev, vap, USBD_DEFAULT_TIMEOUT, &req, sc->sta, sizeof sc->sta, 0, rum_amrr_update); (void)usbd_transfer(sc->amrr_xfer); @@ -2409,8 +2340,11 @@ static void rum_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { - struct rum_softc *sc = (struct rum_softc *)priv; - struct ifnet *ifp = sc->sc_ic.ic_ifp; + struct ieee80211vap *vap = priv; + struct rum_vap *rvp = RUM_VAP(vap); + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct rum_softc *sc = ifp->if_softc; + int ok, fail; if (status != USBD_NORMAL_COMPLETION) { device_printf(sc->sc_dev, "could not retrieve Tx statistics - " @@ -2418,21 +2352,34 @@ rum_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv, return; } - /* count TX retry-fail as Tx errors */ - ifp->if_oerrors += le32toh(sc->sta[5]) >> 16; + ok = (le32toh(sc->sta[4]) >> 16) + /* TX ok w/o retry */ + (le32toh(sc->sta[5]) & 0xffff); /* TX ok w/ retry */ + fail = (le32toh(sc->sta[5]) >> 16); /* TX retry-fail count */ + + ieee80211_amrr_tx_update(&RUM_NODE(vap->iv_bss)->amn, + ok+fail, ok, (le32toh(sc->sta[5]) & 0xffff) + fail); + + ifp->if_oerrors += fail; /* count TX retry-fail as Tx errors */ - sc->amn.amn_retrycnt = - (le32toh(sc->sta[4]) >> 16) + /* TX one-retry ok count */ - (le32toh(sc->sta[5]) & 0xffff) + /* TX more-retry ok count */ - (le32toh(sc->sta[5]) >> 16); /* TX retry-fail count */ + callout_reset(&rvp->amrr_ch, hz, rum_amrr_timeout, vap); +} - sc->amn.amn_txcnt = - sc->amn.amn_retrycnt + - (le32toh(sc->sta[4]) & 0xffff); /* TX no-retry ok count */ +/* ARGUSED */ +static struct ieee80211_node * +rum_node_alloc(struct ieee80211_node_table *nt __unused) +{ + struct rum_node *rn; - ieee80211_amrr_choose(&sc->amrr, sc->sc_ic.ic_bss, &sc->amn); + rn = malloc(sizeof(struct rum_node), M_80211_NODE, M_NOWAIT | M_ZERO); + return rn != NULL ? &rn->ni : NULL; +} - callout_reset(&sc->amrr_ch, hz, rum_amrr_timeout, sc); +static void +rum_newassoc(struct ieee80211_node *ni, int isnew) +{ + struct ieee80211vap *vap = ni->ni_vap; + + ieee80211_amrr_node_init(&RUM_VAP(vap)->amrr, &RUM_NODE(ni)->amn, ni); } static void @@ -2469,14 +2416,17 @@ rum_set_channel(struct ieee80211com *ic) /* do it in a process context */ sc->sc_scan_action = RUM_SET_CHANNEL; usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER); + + sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); } static void rum_scantask(void *arg) { struct rum_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t tmp; RUM_LOCK(sc); @@ -2492,7 +2442,7 @@ rum_scantask(void *arg) case RUM_SCAN_END: rum_enable_tsf_sync(sc); /* XXX keep local copy */ - rum_set_bssid(sc, ic->ic_bss->ni_bssid); + rum_set_bssid(sc, vap->iv_bss->ni_bssid); break; case RUM_SET_CHANNEL: @@ -2513,6 +2463,8 @@ rum_scantask(void *arg) static int rum_get_rssi(struct rum_softc *sc, uint8_t raw) { + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; int lna, agc, rssi; lna = (raw >> 5) & 0x3; @@ -2530,7 +2482,7 @@ rum_get_rssi(struct rum_softc *sc, uint8_t raw) rssi = (2 * agc) - RT2573_NOISE_FLOOR; - if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_curchan)) { + if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { rssi += sc->rssi_2ghz_corr; if (lna == 1) |