diff options
Diffstat (limited to 'sys/dev/usb/if_ural.c')
-rw-r--r-- | sys/dev/usb/if_ural.c | 949 |
1 files changed, 453 insertions, 496 deletions
diff --git a/sys/dev/usb/if_ural.c b/sys/dev/usb/if_ural.c index c2b063f..40a225b 100644 --- a/sys/dev/usb/if_ural.c +++ b/sys/dev/usb/if_ural.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> @@ -115,23 +116,23 @@ MODULE_DEPEND(ural, wlan, 1, 1, 1); MODULE_DEPEND(ural, wlan_amrr, 1, 1, 1); MODULE_DEPEND(ural, usb, 1, 1, 1); +static struct ieee80211vap *ural_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 ural_vap_delete(struct ieee80211vap *); static int ural_alloc_tx_list(struct ural_softc *); static void ural_free_tx_list(struct ural_softc *); static int ural_alloc_rx_list(struct ural_softc *); static void ural_free_rx_list(struct ural_softc *); -static int ural_media_change(struct ifnet *); static void ural_task(void *); static void ural_scantask(void *); -static int ural_newstate(struct ieee80211com *, +static int ural_newstate(struct ieee80211vap *, enum ieee80211_state, int); -static int ural_rxrate(struct ural_rx_desc *); static void ural_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status); static void ural_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status); -static int ural_ack_rate(struct ieee80211com *, int); -static uint16_t ural_txtime(int, int, uint32_t); -static uint8_t ural_plcp_signal(int); static void ural_setup_tx_desc(struct ural_softc *, struct ural_tx_desc *, uint32_t, int, int); static int ural_tx_bcn(struct ural_softc *, struct mbuf *, @@ -142,7 +143,6 @@ static int ural_tx_data(struct ural_softc *, struct mbuf *, struct ieee80211_node *); static void ural_start(struct ifnet *); static void ural_watchdog(void *); -static int ural_reset(struct ifnet *); static int ural_ioctl(struct ifnet *, u_long, caddr_t); static void ural_set_testmode(struct ural_softc *); static void ural_eeprom_read(struct ural_softc *, uint16_t, void *, @@ -156,6 +156,8 @@ static void ural_write_multi(struct ural_softc *, uint16_t, void *, static void ural_bbp_write(struct ural_softc *, uint8_t, uint8_t); static uint8_t ural_bbp_read(struct ural_softc *, uint8_t); static void ural_rf_write(struct ural_softc *, uint8_t, uint32_t); +static struct ieee80211_node *ural_node_alloc(struct ieee80211_node_table *); +static void ural_newassoc(struct ieee80211_node *, int); static void ural_scan_start(struct ieee80211com *); static void ural_scan_end(struct ieee80211com *); static void ural_set_channel(struct ieee80211com *); @@ -165,7 +167,8 @@ static void ural_disable_rf_tune(struct ural_softc *); static void ural_enable_tsf_sync(struct ural_softc *); static void ural_update_slot(struct ifnet *); static void ural_set_txpreamble(struct ural_softc *); -static void ural_set_basicrates(struct ural_softc *); +static void ural_set_basicrates(struct ural_softc *, + const struct ieee80211_channel *); static void ural_set_bssid(struct ural_softc *, const uint8_t *); static void ural_set_macaddr(struct ural_softc *, uint8_t *); static void ural_update_promisc(struct ural_softc *); @@ -174,6 +177,7 @@ static void ural_read_eeprom(struct ural_softc *); static int ural_bbp_init(struct ural_softc *); static void ural_set_txantenna(struct ural_softc *, int); static void ural_set_rxantenna(struct ural_softc *, int); +static void ural_init_locked(struct ural_softc *); static void ural_init(void *); static void ural_stop(void *); static int ural_raw_xmit(struct ieee80211_node *, struct mbuf *, @@ -387,18 +391,18 @@ ural_attach(device_t self) struct ural_softc *sc = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); struct ifnet *ifp; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; usbd_status error; - int i, bands; + int i; + uint8_t bands; sc->sc_udev = uaa->device; sc->sc_dev = self; if (usbd_set_config_no(sc->sc_udev, RAL_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; } @@ -406,8 +410,7 @@ ural_attach(device_t self) error = usbd_device2interface_handle(sc->sc_udev, RAL_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; } @@ -420,8 +423,8 @@ ural_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 %d\n", - device_get_nameunit(sc->sc_dev), i); + device_printf(self, "no endpoint descriptor for %d\n", + i); return ENXIO; } @@ -433,10 +436,16 @@ ural_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(sc->sc_dev, "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); @@ -444,7 +453,6 @@ ural_attach(device_t self) usb_init_task(&sc->sc_task, ural_task, sc); usb_init_task(&sc->sc_scantask, ural_scantask, sc); callout_init(&sc->watchdog_ch, 0); - callout_init(&sc->amrr_ch, 0); /* retrieve RT2570 rev. no */ sc->asic_rev = ural_read(sc, RAL_MAC_CSR0); @@ -452,16 +460,8 @@ ural_attach(device_t self) /* retrieve MAC address and various other things from EEPROM */ ural_read_eeprom(sc); - printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s\n", - device_get_nameunit(sc->sc_dev), sc->asic_rev, - ural_get_rf(sc->rf_rev)); - - ifp = sc->sc_ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) { - printf("%s: can not if_alloc()\n", - device_get_nameunit(sc->sc_dev)); - return ENXIO; - } + device_printf(sc->sc_dev, "MAC/BBP RT2570 (rev 0x%02x), RF %s\n", + sc->asic_rev, ural_get_rf(sc->rf_rev)); ifp->if_softc = sc; if_initname(ifp, "ural", device_get_unit(sc->sc_dev)); @@ -476,8 +476,6 @@ ural_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 = @@ -496,34 +494,29 @@ ural_attach(device_t self) setbit(&bands, IEEE80211_MODE_11G); if (sc->rf_rev == RAL_RF_5222) setbit(&bands, IEEE80211_MODE_11A); - ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1); + ieee80211_init_channels(ic, NULL, &bands); ieee80211_ifattach(ic); - ic->ic_reset = ural_reset; - /* enable s/w bmiss handling in sta mode */ - ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; + ic->ic_newassoc = ural_newassoc; + ic->ic_raw_xmit = ural_raw_xmit; + ic->ic_node_alloc = ural_node_alloc; ic->ic_scan_start = ural_scan_start; ic->ic_scan_end = ural_scan_end; ic->ic_set_channel = ural_set_channel; - /* override state transition machine */ - sc->sc_newstate = ic->ic_newstate; - ic->ic_newstate = ural_newstate; - ic->ic_raw_xmit = ural_raw_xmit; - ieee80211_media_init(ic, ural_media_change, ieee80211_media_status); + ic->ic_vap_create = ural_vap_create; + ic->ic_vap_delete = ural_vap_delete; - 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) + 64, &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(RAL_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(RAL_TX_RADIOTAP_PRESENT); @@ -537,13 +530,16 @@ static int ural_detach(device_t self) { struct ural_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; ural_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); @@ -563,22 +559,66 @@ ural_detach(device_t self) ural_free_rx_list(sc); ural_free_tx_list(sc); - bpfdetach(ifp); - ieee80211_ifdetach(ic); if_free(ifp); - mtx_destroy(&sc->sc_mtx); return 0; } +static struct ieee80211vap * +ural_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 ural_vap *uvp; + struct ieee80211vap *vap; + + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + return NULL; + uvp = (struct ural_vap *) malloc(sizeof(struct ural_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (uvp == NULL) + return NULL; + vap = &uvp->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 */ + uvp->newstate = vap->iv_newstate; + vap->iv_newstate = ural_newstate; + + callout_init(&uvp->amrr_ch, 0); + ieee80211_amrr_init(&uvp->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 +ural_vap_delete(struct ieee80211vap *vap) +{ + struct ural_vap *uvp = URAL_VAP(vap); + + callout_stop(&uvp->amrr_ch); + ieee80211_amrr_cleanup(&uvp->amrr); + ieee80211_vap_detach(vap); + free(uvp, M_80211_VAP); +} + static int ural_alloc_tx_list(struct ural_softc *sc) { struct ural_tx_data *data; int i, error; - sc->tx_queued = 0; + sc->tx_queued = sc->tx_cur = 0; for (i = 0; i < RAL_TX_LIST_COUNT; i++) { data = &sc->tx_data[i]; @@ -587,8 +627,8 @@ ural_alloc_tx_list(struct ural_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; } @@ -596,8 +636,8 @@ ural_alloc_tx_list(struct ural_softc *sc) data->buf = usbd_alloc_buffer(data->xfer, RAL_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; } @@ -643,23 +683,23 @@ ural_alloc_rx_list(struct ural_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; } @@ -694,39 +734,20 @@ ural_free_rx_list(struct ural_softc *sc) } } -static int -ural_media_change(struct ifnet *ifp) -{ - struct ural_softc *sc = ifp->if_softc; - int error; - - RAL_LOCK(sc); - - error = ieee80211_media_change(ifp); - if (error != ENETRESET) { - RAL_UNLOCK(sc); - return error; - } - - if ((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & IFF_DRV_RUNNING)) - ural_init(sc); - - RAL_UNLOCK(sc); - - return 0; -} - static void ural_task(void *xarg) { struct ural_softc *sc = xarg; - 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 ural_vap *uvp = URAL_VAP(vap); + const struct ieee80211_txparam *tp; enum ieee80211_state ostate; struct ieee80211_node *ni; struct mbuf *m; - ostate = ic->ic_state; + ostate = vap->iv_state; RAL_LOCK(sc); switch (sc->sc_state) { @@ -741,27 +762,27 @@ ural_task(void *xarg) 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) { ural_update_slot(ic->ic_ifp); ural_set_txpreamble(sc); - ural_set_basicrates(sc); + ural_set_basicrates(sc, ic->ic_bsschan); ural_set_bssid(sc, ni->ni_bssid); } - if (ic->ic_opmode == IEEE80211_M_HOSTAP || - ic->ic_opmode == IEEE80211_M_IBSS) { - m = ieee80211_beacon_alloc(ni, &sc->sc_bo); + if (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS) { + m = ieee80211_beacon_alloc(ni, &uvp->bo); if (m == NULL) { - printf("%s: could not allocate beacon\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, + "could not allocate beacon\n"); return; } if (ural_tx_bcn(sc, m, ni) != 0) { - printf("%s: could not send beacon\n", - device_get_nameunit(sc->sc_dev)); + device_printf(sc->sc_dev, + "could not send beacon\n"); return; } } @@ -769,12 +790,12 @@ ural_task(void *xarg) /* make tx led blink on tx (controlled by ASIC) */ ural_write(sc, RAL_MAC_CSR20, 1); - if (ic->ic_opmode != IEEE80211_M_MONITOR) + if (vap->iv_opmode != IEEE80211_M_MONITOR) ural_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) ural_amrr_start(sc, ni); break; @@ -784,15 +805,21 @@ ural_task(void *xarg) } RAL_UNLOCK(sc); - sc->sc_newstate(ic, sc->sc_state, sc->sc_arg); + + IEEE80211_LOCK(ic); + uvp->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 void ural_scantask(void *arg) { struct ural_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); RAL_LOCK(sc); if (sc->sc_scan_action == URAL_SCAN_START) { @@ -806,77 +833,42 @@ ural_scantask(void *arg) } else { ural_enable_tsf_sync(sc); /* XXX keep local copy */ - ural_set_bssid(sc, ic->ic_bss->ni_bssid); + ural_set_bssid(sc, vap->iv_bss->ni_bssid); } RAL_UNLOCK(sc); } static int -ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) +ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { + struct ural_vap *uvp = URAL_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; struct ural_softc *sc = ic->ic_ifp->if_softc; - callout_stop(&sc->amrr_ch); + callout_stop(&uvp->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) { + uvp->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 RAL_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) - -#define RAL_ACK_SIZE 14 /* 10 + 4(FCS) */ -#define RAL_CTS_SIZE 14 /* 10 + 4(FCS) */ - -#define RAL_SIFS 10 /* us */ - #define RAL_RXTX_TURNAROUND 5 /* us */ -/* - * This function is only used by the Rx radiotap code. - */ -static int -ural_rxrate(struct ural_rx_desc *desc) -{ - if (le32toh(desc->flags) & RAL_RX_OFDM) { - /* reverse function of ural_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 */ -} - static void ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct ural_tx_data *data = priv; struct ural_softc *sc = data->sc; - struct ifnet *ifp = sc->sc_ic.ic_ifp; + struct ifnet *ifp = sc->sc_ifp; if (data->m->m_flags & M_TXCB) ieee80211_process_callback(data->ni, data->m, @@ -885,8 +877,8 @@ ural_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_rx_pipeh); @@ -916,13 +908,12 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct ural_rx_data *data = priv; struct ural_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 ural_rx_desc *desc; - struct ieee80211_frame *wh; struct ieee80211_node *ni; struct mbuf *mnew, *m; - int len; + int len, rssi; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) @@ -970,30 +961,30 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff; - if (bpf_peers_present(sc->sc_drvbpf)) { + if (bpf_peers_present(ifp->if_bpf)) { struct ural_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = IEEE80211_RADIOTAP_F_FCS; - tap->wr_rate = ural_rxrate(desc); + tap->wr_rate = ieee80211_plcp2rate(desc->rate, + le32toh(desc->flags) & RAL_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 = URAL_RSSI(desc->rssi); - bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); + bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); } /* Strip trailing 802.11 MAC FCS. */ m_adj(m, -IEEE80211_CRC_LEN); - wh = mtod(m, struct ieee80211_frame *); - ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); - - /* send the frame to the 802.11 layer */ - ieee80211_input(ic, m, ni, URAL_RSSI(desc->rssi), RAL_NOISE_FLOOR, 0); - - /* node is no longer needed */ - ieee80211_free_node(ni); + rssi = URAL_RSSI(desc->rssi); + ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); + if (ni != NULL) { + (void) ieee80211_input(ni, m, rssi, RAL_NOISE_FLOOR, 0); + ieee80211_free_node(ni); + } else + (void) ieee80211_input_all(ic, m, rssi, RAL_NOISE_FLOOR, 0); DPRINTFN(15, ("rx done\n")); @@ -1003,95 +994,12 @@ skip: /* setup a new transfer */ usbd_transfer(xfer); } -/* - * 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 -ural_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 -ural_txtime(int len, int rate, uint32_t flags) -{ - uint16_t txtime; - - if (RAL_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 -ural_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 ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc, uint32_t flags, 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; @@ -1103,11 +1011,11 @@ ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc, desc->wme |= htole16(RAL_IVOFFSET(sizeof (struct ieee80211_frame))); /* setup PLCP fields */ - desc->plcp_signal = ural_plcp_signal(rate); + desc->plcp_signal = ieee80211_rate2plcp(rate); desc->plcp_service = 4; len += IEEE80211_CRC_LEN; - if (RAL_RATE_IS_OFDM(rate)) { + if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) { desc->flags |= htole32(RAL_TX_OFDM); plcp_length = len & 0xfff; @@ -1136,14 +1044,17 @@ ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc, static int ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + const struct ieee80211_txparam *tp; struct ural_tx_desc *desc; usbd_xfer_handle xfer; - uint8_t cmd = 0; + uint8_t cmd; usbd_status error; uint8_t *buf; - int xferlen, rate; + int xferlen; - rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2; + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; xfer = usbd_alloc_xfer(sc->sc_udev); if (xfer == NULL) @@ -1158,6 +1069,7 @@ ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) return ENOMEM; } + cmd = 0; usbd_setup_xfer(xfer, sc->sc_tx_pipeh, NULL, &cmd, sizeof cmd, USBD_FORCE_SHORT_XFER, RAL_TX_TIMEOUT, NULL); @@ -1171,10 +1083,10 @@ ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) m_copydata(m0, 0, m0->m_pkthdr.len, buf + RAL_TX_DESC_SIZE); ural_setup_tx_desc(sc, desc, RAL_TX_IFS_NEWBACKOFF | RAL_TX_TIMESTAMP, - m0->m_pkthdr.len, rate); + m0->m_pkthdr.len, tp->mgmtrate); DPRINTFN(10, ("sending beacon frame len=%u rate=%u xfer len=%u\n", - m0->m_pkthdr.len, rate, xferlen)); + m0->m_pkthdr.len, tp->mgmtrate, xferlen)); usbd_setup_xfer(xfer, sc->sc_tx_pipeh, NULL, buf, xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT, NULL); @@ -1188,40 +1100,43 @@ ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) static int ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = sc->sc_ifp; + const struct ieee80211_txparam *tp; struct ural_tx_desc *desc; struct ural_tx_data *data; struct ieee80211_frame *wh; struct ieee80211_key *k; - uint32_t flags = 0; + uint32_t flags; uint16_t dur; usbd_status error; - int xferlen, rate; + int xferlen; - data = &sc->tx_data[0]; + data = &sc->tx_data[sc->tx_cur]; desc = (struct ural_tx_desc *)data->buf; - rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 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 *); } data->m = m0; data->ni = ni; - wh = mtod(m0, struct ieee80211_frame *); - + flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RAL_TX_ACK; - dur = ural_txtime(RAL_ACK_SIZE, rate, ic->ic_flags) + RAL_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 */ @@ -1232,20 +1147,20 @@ ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) flags |= RAL_TX_TIMESTAMP; } - if (bpf_peers_present(sc->sc_drvbpf)) { + if (bpf_peers_present(ifp->if_bpf)) { struct ural_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 + RAL_TX_DESC_SIZE); - ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate); + ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, tp->mgmtrate); /* align end on a 2-bytes boundary */ xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1; @@ -1258,7 +1173,7 @@ ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) xferlen += 2; DPRINTFN(10, ("sending mgt frame len=%u rate=%u xfer len=%u\n", - m0->m_pkthdr.len, rate, xferlen)); + m0->m_pkthdr.len, tp->mgmtrate, xferlen)); usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT, @@ -1273,6 +1188,71 @@ ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) } sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RAL_TX_LIST_COUNT; + + return 0; +} + +static int +ural_sendprot(struct ural_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 ural_tx_desc *desc; + struct ural_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 = RAL_TX_RETRY(7); + if (prot == IEEE80211_PROT_RTSCTS) { + /* NB: CTS is the same size as an ACK */ + dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort); + flags |= RAL_TX_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 ural_tx_desc *)data->buf; + + data->m = mprot; + data->ni = ieee80211_ref_node(ni); + m_copydata(mprot, 0, mprot->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE); + ural_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate); + + usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, + /* NB: no roundup necessary */ + RAL_TX_DESC_SIZE + mprot->m_pkthdr.len, + USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT, ural_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) % RAL_TX_LIST_COUNT; return 0; } @@ -1281,14 +1261,17 @@ static int ural_tx_raw(struct ural_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 ural_tx_desc *desc; struct ural_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 ural_tx_desc *)data->buf; rate = params->ibp_rate0 & IEEE80211_RATE_VAL; @@ -1297,8 +1280,22 @@ ural_tx_raw(struct ural_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 |= RAL_TX_ACK; + if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { + error = ural_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 |= RAL_TX_IFS_SIFS; + } - if (bpf_peers_present(sc->sc_drvbpf)) { + if (bpf_peers_present(ifp->if_bpf)) { struct ural_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; @@ -1307,16 +1304,12 @@ ural_tx_raw(struct ural_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 |= RAL_TX_ACK; - m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE); /* XXX need to setup descriptor ourself */ ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate); @@ -1347,6 +1340,7 @@ ural_tx_raw(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, } sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RAL_TX_LIST_COUNT; return 0; } @@ -1354,10 +1348,13 @@ ural_tx_raw(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, static int ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = sc->sc_ifp; struct ural_tx_desc *desc; struct ural_tx_data *data; struct ieee80211_frame *wh; + const struct ieee80211_txparam *tp; struct ieee80211_key *k; uint32_t flags = 0; uint16_t dur; @@ -1366,25 +1363,42 @@ ural_tx_data(struct ural_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; + 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 - rate = ni->ni_rates.rs_rates[ni->ni_txrate]; - - rate &= IEEE80211_RATE_VAL; + 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; } - /* packet header may have moved, reset our local pointer */ 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 = ural_sendprot(sc, m0, ni, prot, rate); + if (error) { + m_freem(m0); + return error; + } + flags |= RAL_TX_IFS_SIFS; + } + } + + data = &sc->tx_data[sc->tx_cur]; desc = (struct ural_tx_desc *)data->buf; data->m = m0; @@ -1394,12 +1408,12 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) flags |= RAL_TX_ACK; flags |= RAL_TX_RETRY(7); - dur = ural_txtime(RAL_ACK_SIZE, ural_ack_rate(ic, rate), - ic->ic_flags) + RAL_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 ural_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; @@ -1408,7 +1422,7 @@ ural_tx_data(struct ural_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 + RAL_TX_DESC_SIZE); @@ -1440,6 +1454,7 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) } sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % RAL_TX_LIST_COUNT; return 0; } @@ -1448,77 +1463,30 @@ static void ural_start(struct ifnet *ifp) { struct ural_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; - struct mbuf *m0; - struct ether_header *eh; struct ieee80211_node *ni; + struct mbuf *m; for (;;) { - IF_POLL(&ic->ic_mgtq, m0); - if (m0 != NULL) { - if (sc->tx_queued >= RAL_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 (ural_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 >= RAL_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 (ural_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 >= RAL_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 (ural_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, ural_watchdog, sc); } } @@ -1544,61 +1512,40 @@ ural_watchdog(void *arg) RAL_UNLOCK(sc); } -/* - * This function allows for fast channel switching in monitor mode (used by - * net-mgmt/kismet). In IBSS mode, we must explicitly reset the interface to - * generate a new beacon frame. - */ -static int -ural_reset(struct ifnet *ifp) -{ - struct ural_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; - - if (ic->ic_opmode != IEEE80211_M_MONITOR) - return ENETRESET; - - ural_set_chan(sc, ic->ic_curchan); - - return 0; -} - static int ural_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ural_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 = 1; RAL_LOCK(sc); - switch (cmd) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + ural_init_locked(sc); + startall = 1; + } else ural_update_promisc(sc); - else - ural_init(sc); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) ural_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)) - ural_init(sc); - error = 0; + error = ether_ioctl(ifp, cmd, data); + break; } - RAL_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); return error; } @@ -1616,8 +1563,8 @@ ural_set_testmode(struct ural_softc *sc) error = usbd_do_request(sc->sc_udev, &req, NULL); if (error != 0) { - printf("%s: could not set test mode: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not set test mode: %s\n", + usbd_errstr(error)); } } @@ -1635,8 +1582,8 @@ ural_eeprom_read(struct ural_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)); } } @@ -1655,8 +1602,8 @@ ural_read(struct ural_softc *sc, uint16_t reg) error = usbd_do_request(sc->sc_udev, &req, &val); if (error != 0) { - printf("%s: could not read MAC register: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not read MAC register: %s\n", + usbd_errstr(error)); return 0; } @@ -1677,8 +1624,8 @@ ural_read_multi(struct ural_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 read MAC register: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not read MAC register: %s\n", + usbd_errstr(error)); } } @@ -1696,8 +1643,8 @@ ural_write(struct ural_softc *sc, uint16_t reg, uint16_t val) error = usbd_do_request(sc->sc_udev, &req, NULL); if (error != 0) { - printf("%s: could not write MAC register: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not write MAC register: %s\n", + usbd_errstr(error)); } } @@ -1715,8 +1662,8 @@ ural_write_multi(struct ural_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 write MAC register: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(error)); + device_printf(sc->sc_dev, "could not write MAC register: %s\n", + usbd_errstr(error)); } } @@ -1731,7 +1678,7 @@ ural_bbp_write(struct ural_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; } @@ -1753,7 +1700,7 @@ ural_bbp_read(struct ural_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; } @@ -1771,7 +1718,7 @@ ural_rf_write(struct ural_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; } @@ -1785,6 +1732,24 @@ ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val) DPRINTFN(15, ("RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff)); } +/* ARGUSED */ +static struct ieee80211_node * +ural_node_alloc(struct ieee80211_node_table *nt __unused) +{ + struct ural_node *un; + + un = malloc(sizeof(struct ural_node), M_80211_NODE, M_NOWAIT | M_ZERO); + return un != NULL ? &un->ni : NULL; +} + +static void +ural_newassoc(struct ieee80211_node *ni, int isnew) +{ + struct ieee80211vap *vap = ni->ni_vap; + + ieee80211_amrr_node_init(&URAL_VAP(vap)->amrr, &URAL_NODE(ni)->amn, ni); +} + static void ural_scan_start(struct ieee80211com *ic) { @@ -1822,12 +1787,15 @@ ural_set_channel(struct ieee80211com *ic) /* do it in a process context */ sc->sc_scan_action = URAL_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 ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint8_t power, tmp; u_int i, chan; @@ -1924,17 +1892,9 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c) ural_disable_rf_tune(sc); } + /* XXX doesn't belong here */ /* update basic rate set */ - if (IEEE80211_IS_CHAN_B(c)) { - /* 11b basic rates: 1, 2Mbps */ - ural_write(sc, RAL_TXRX_CSR11, 0x3); - } else if (IEEE80211_IS_CHAN_A(c)) { - /* 11a basic rates: 6, 12, 24Mbps */ - ural_write(sc, RAL_TXRX_CSR11, 0x150); - } else { - /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ - ural_write(sc, RAL_TXRX_CSR11, 0x15f); - } + ural_set_basicrates(sc, c); } /* @@ -1963,13 +1923,15 @@ ural_disable_rf_tune(struct ural_softc *sc) static void ural_enable_tsf_sync(struct ural_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); uint16_t logcwmin, preload, tmp; /* first, disable TSF synchronization */ ural_write(sc, RAL_TXRX_CSR19, 0); - tmp = (16 * ic->ic_bss->ni_intval) << 4; + tmp = (16 * vap->iv_bss->ni_intval) << 4; ural_write(sc, RAL_TXRX_CSR18, tmp); logcwmin = (ic->ic_opmode == IEEE80211_M_IBSS) ? 2 : 0; @@ -1992,7 +1954,7 @@ static void ural_update_slot(struct ifnet *ifp) { struct ural_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = ifp->if_l2com; uint16_t slottime, sifs, eifs; slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; @@ -2017,32 +1979,33 @@ ural_update_slot(struct ifnet *ifp) static void ural_set_txpreamble(struct ural_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t tmp; tmp = ural_read(sc, RAL_TXRX_CSR10); tmp &= ~RAL_SHORT_PREAMBLE; - if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE) + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) tmp |= RAL_SHORT_PREAMBLE; ural_write(sc, RAL_TXRX_CSR10, tmp); } static void -ural_set_basicrates(struct ural_softc *sc) +ural_set_basicrates(struct ural_softc *sc, const struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; - + /* XXX wrong, take from rate set */ /* update basic rate set */ - if (ic->ic_curmode == IEEE80211_MODE_11B) { - /* 11b basic rates: 1, 2Mbps */ - ural_write(sc, RAL_TXRX_CSR11, 0x3); - } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) { + if (IEEE80211_IS_CHAN_5GHZ(c)) { /* 11a basic rates: 6, 12, 24Mbps */ ural_write(sc, RAL_TXRX_CSR11, 0x150); - } else { + } else if (IEEE80211_IS_CHAN_ANYG(c)) { /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ ural_write(sc, RAL_TXRX_CSR11, 0x15f); + } else { + /* 11b basic rates: 1, 2Mbps */ + ural_write(sc, RAL_TXRX_CSR11, 0x3); } } @@ -2083,7 +2046,7 @@ ural_set_macaddr(struct ural_softc *sc, uint8_t *addr) static void ural_update_promisc(struct ural_softc *sc) { - struct ifnet *ifp = sc->sc_ic.ic_ifp; + struct ifnet *ifp = sc->sc_ifp; uint32_t tmp; tmp = ural_read(sc, RAL_TXRX_CSR2); @@ -2116,7 +2079,8 @@ ural_get_rf(int rev) static void ural_read_eeprom(struct ural_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint16_t val; ural_eeprom_read(sc, RAL_EEPROM_CONFIG0, &val, 2); @@ -2222,12 +2186,11 @@ ural_set_rxantenna(struct ural_softc *sc, int antenna) } static void -ural_init(void *priv) +ural_init_locked(struct ural_softc *sc) { #define N(a) (sizeof (a) / sizeof ((a)[0])) - struct ural_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 ural_rx_data *data; uint16_t tmp; usbd_status error; @@ -2251,8 +2214,8 @@ ural_init(void *priv) DELAY(1000); } if (ntries == 100) { - 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; } @@ -2281,8 +2244,7 @@ ural_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; } @@ -2292,16 +2254,16 @@ ural_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; } @@ -2310,15 +2272,13 @@ ural_init(void *priv) */ error = ural_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 = ural_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; } @@ -2346,13 +2306,6 @@ ural_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: ural_stop(sc); @@ -2360,17 +2313,29 @@ fail: ural_stop(sc); } static void +ural_init(void *priv) +{ + struct ural_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + RAL_LOCK(sc); + ural_init_locked(sc); + RAL_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void ural_stop(void *priv) { struct ural_softc *sc = priv; - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = sc->sc_ifp; 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 */ ural_write(sc, RAL_TXRX_CSR2, RAL_DISABLE_RX); @@ -2420,9 +2385,6 @@ ural_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return EIO; } - if (bpf_peers_present(ic->ic_rawbpf)) - bpf_mtap(ic->ic_rawbpf, m); - ifp->if_opackets++; if (params == NULL) { @@ -2453,27 +2415,22 @@ bad: static void ural_amrr_start(struct ural_softc *sc, struct ieee80211_node *ni) { - int i; + struct ieee80211vap *vap = ni->ni_vap; + struct ural_vap *uvp = URAL_VAP(vap); /* clear statistic registers (STA_CSR0 to STA_CSR10) */ ural_read_multi(sc, RAL_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(&uvp->amrr, &URAL_NODE(ni)->amn, ni); - callout_reset(&sc->amrr_ch, hz, ural_amrr_timeout, sc); + callout_reset(&uvp->amrr_ch, hz, ural_amrr_timeout, vap); } static void ural_amrr_timeout(void *arg) { - struct ural_softc *sc = (struct ural_softc *)arg; + struct ieee80211vap *vap = arg; + struct ural_softc *sc = vap->iv_ic->ic_ifp->if_softc; usb_device_request_t req; /* @@ -2485,7 +2442,7 @@ ural_amrr_timeout(void *arg) USETW(req.wIndex, RAL_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, ural_amrr_update); (void)usbd_transfer(sc->amrr_xfer); @@ -2495,8 +2452,12 @@ static void ural_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { - struct ural_softc *sc = (struct ural_softc *)priv; - struct ifnet *ifp = sc->sc_ic.ic_ifp; + struct ieee80211vap *vap = priv; + struct ural_vap *uvp = URAL_VAP(vap); + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct ural_softc *sc = ifp->if_softc; + struct ieee80211_node *ni = vap->iv_bss; + int ok, fail; if (status != USBD_NORMAL_COMPLETION) { device_printf(sc->sc_dev, "could not retrieve Tx statistics - " @@ -2504,19 +2465,15 @@ ural_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv, return; } - /* count TX retry-fail as Tx errors */ - ifp->if_oerrors += sc->sta[9]; - - sc->amn.amn_retrycnt = - sc->sta[7] + /* TX one-retry ok count */ - sc->sta[8] + /* TX more-retry ok count */ - sc->sta[9]; /* TX retry-fail count */ + ok = sc->sta[7] + /* TX ok w/o retry */ + sc->sta[8]; /* TX ok w/ retry */ + fail = sc->sta[9]; /* TX retry-fail count */ - sc->amn.amn_txcnt = - sc->amn.amn_retrycnt + - sc->sta[6]; /* TX no-retry ok count */ + ieee80211_amrr_tx_update(&URAL_NODE(ni)->amn, + ok+fail, ok, sc->sta[8] + fail); + (void) ieee80211_amrr_choose(ni, &URAL_NODE(ni)->amn); - ieee80211_amrr_choose(&sc->amrr, sc->sc_ic.ic_bss, &sc->amn); + ifp->if_oerrors += fail; /* count TX retry-fail as Tx errors */ - callout_reset(&sc->amrr_ch, hz, ural_amrr_timeout, sc); + callout_reset(&uvp->amrr_ch, hz, ural_amrr_timeout, vap); } |