diff options
author | glebius <glebius@FreeBSD.org> | 2015-08-07 11:43:14 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2015-08-07 11:43:14 +0000 |
commit | eb8a90b8596b58df12c5e12dd059fe3c40dad08e (patch) | |
tree | 6454e7be9c51af111875a842eec79f4a2ddb1d23 /sys/dev/wi/if_wi.c | |
parent | 94936bfa1d0fc354e859129a11266bc6dac1f589 (diff) | |
download | FreeBSD-src-eb8a90b8596b58df12c5e12dd059fe3c40dad08e.zip FreeBSD-src-eb8a90b8596b58df12c5e12dd059fe3c40dad08e.tar.gz |
Change KPI of how device drivers that provide wireless connectivity interact
with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to Olivier Cochard, gjb@, mmoll@,
op@ and lev@, who also participated in testing. Details here:
https://wiki.freebsd.org/projects/ifnet/net80211
Still, drivers: ndis, wtap, mwl, ipw, bwn, wi, upgt, uath were not
tested. Changes to mwl, ipw, bwn, wi, upgt are trivial and chances
of problems are low. The wtap wasn't compilable even before this change.
But the ndis driver is complex, and it is likely to be broken with this
commit. Help with testing and debugging it is appreciated.
Differential Revision: D2655, D2740
Sponsored by: Nginx, Inc.
Sponsored by: Netflix
Diffstat (limited to 'sys/dev/wi/if_wi.c')
-rw-r--r-- | sys/dev/wi/if_wi.c | 382 |
1 files changed, 146 insertions, 236 deletions
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index b316d46..f8af231 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -116,11 +116,9 @@ static struct ieee80211vap *wi_vap_create(struct ieee80211com *, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void wi_vap_delete(struct ieee80211vap *vap); -static void wi_stop_locked(struct wi_softc *sc, int disable); -static void wi_start_locked(struct ifnet *); -static void wi_start(struct ifnet *); -static int wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr, - struct mbuf *m0); +static int wi_transmit(struct ieee80211com *, struct mbuf *); +static void wi_start(struct wi_softc *); +static int wi_start_tx(struct wi_softc *, struct wi_frame *, struct mbuf *); static int wi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static int wi_newstate_sta(struct ieee80211vap *, enum ieee80211_state, int); @@ -131,10 +129,8 @@ static void wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf); static int wi_reset(struct wi_softc *); static void wi_watchdog(void *); -static int wi_ioctl(struct ifnet *, u_long, caddr_t); +static void wi_parent(struct ieee80211com *); static void wi_media_status(struct ifnet *, struct ifmediareq *); -static uint64_t wi_get_counter(struct ifnet *, ift_counter); - static void wi_rx_intr(struct wi_softc *); static void wi_tx_intr(struct wi_softc *); static void wi_tx_ex_intr(struct wi_softc *); @@ -153,10 +149,10 @@ static int wi_write_ssid(struct wi_softc *, int, u_int8_t *, int); static int wi_cmd(struct wi_softc *, int, int, int, int); static int wi_seek_bap(struct wi_softc *, int, int); static int wi_read_bap(struct wi_softc *, int, int, void *, int); -static int wi_write_bap(struct wi_softc *, int, int, void *, int); +static int wi_write_bap(struct wi_softc *, int, int, const void *, int); static int wi_mwrite_bap(struct wi_softc *, int, int, struct mbuf *, int); static int wi_read_rid(struct wi_softc *, int, void *, int *); -static int wi_write_rid(struct wi_softc *, int, void *, int); +static int wi_write_rid(struct wi_softc *, int, const void *, int); static int wi_write_appie(struct wi_softc *, int, const struct ieee80211_appie *); static void wi_scan_start(struct ieee80211com *); @@ -237,8 +233,7 @@ int wi_attach(device_t dev) { struct wi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic; - struct ifnet *ifp; + struct ieee80211com *ic = &sc->sc_ic; int i, nrates, buflen; u_int16_t val; u_int8_t ratebuf[2 + IEEE80211_RATE_SIZE]; @@ -249,15 +244,6 @@ wi_attach(device_t dev) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int error; - uint8_t macaddr[IEEE80211_ADDR_LEN]; - - ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); - if (ifp == NULL) { - device_printf(dev, "can not if_alloc\n"); - wi_free(dev); - return ENOSPC; - } - ic = ifp->if_l2com; sc->sc_firmware_type = WI_NOTYPE; sc->wi_cmd_count = 500; @@ -309,6 +295,7 @@ wi_attach(device_t dev) mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); + mbufq_init(&sc->sc_snd, ifqmaxlen); /* * Read the station address. @@ -317,12 +304,13 @@ wi_attach(device_t dev) * the probe to fail. */ buflen = IEEE80211_ADDR_LEN; - error = wi_read_rid(sc, WI_RID_MAC_NODE, macaddr, &buflen); + error = wi_read_rid(sc, WI_RID_MAC_NODE, &ic->ic_macaddr, &buflen); if (error != 0) { buflen = IEEE80211_ADDR_LEN; - error = wi_read_rid(sc, WI_RID_MAC_NODE, macaddr, &buflen); + error = wi_read_rid(sc, WI_RID_MAC_NODE, &ic->ic_macaddr, + &buflen); } - if (error || IEEE80211_ADDR_EQ(macaddr, empty_macaddr)) { + if (error || IEEE80211_ADDR_EQ(&ic->ic_macaddr, empty_macaddr)) { if (error != 0) device_printf(dev, "mac read failed %d\n", error); else { @@ -333,18 +321,6 @@ wi_attach(device_t dev) return (error); } - ifp->if_softc = sc; - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = wi_ioctl; - ifp->if_start = wi_start; - ifp->if_init = wi_init; - ifp->if_get_counter = wi_get_counter; - IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); - ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; - IFQ_SET_READY(&ifp->if_snd); - - ic->ic_ifp = ifp; ic->ic_softc = sc; ic->ic_name = device_get_nameunit(dev); ic->ic_phytype = IEEE80211_T_DS; @@ -458,16 +434,17 @@ wi_attach(device_t dev) sc->sc_portnum = WI_DEFAULT_PORT; - ieee80211_ifattach(ic, macaddr); + ieee80211_ifattach(ic); ic->ic_raw_xmit = wi_raw_xmit; ic->ic_scan_start = wi_scan_start; ic->ic_scan_end = wi_scan_end; ic->ic_set_channel = wi_set_channel; - ic->ic_vap_create = wi_vap_create; ic->ic_vap_delete = wi_vap_delete; ic->ic_update_mcast = wi_update_mcast; ic->ic_update_promisc = wi_update_promisc; + ic->ic_transmit = wi_transmit; + ic->ic_parent = wi_parent; ieee80211_radiotap_attach(ic, &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), @@ -483,7 +460,6 @@ wi_attach(device_t dev) if (error) { device_printf(dev, "bus_setup_intr() failed! (%d)\n", error); ieee80211_ifdetach(ic); - if_free(sc->sc_ifp); wi_free(dev); return error; } @@ -495,21 +471,20 @@ int wi_detach(device_t dev) { struct wi_softc *sc = device_get_softc(dev); - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211com *ic = &sc->sc_ic; WI_LOCK(sc); /* check if device was removed */ sc->wi_gone |= !bus_child_present(dev); - wi_stop_locked(sc, 0); + wi_stop(sc, 0); WI_UNLOCK(sc); ieee80211_ifdetach(ic); bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); - if_free(sc->sc_ifp); wi_free(dev); + mbufq_drain(&sc->sc_snd); mtx_destroy(&sc->sc_mtx); return (0); } @@ -520,19 +495,16 @@ wi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct wi_softc *sc = ic->ic_ifp->if_softc; + struct wi_softc *sc = ic->ic_softc; struct wi_vap *wvp; struct ieee80211vap *vap; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - wvp = (struct wi_vap *) malloc(sizeof(struct wi_vap), - M_80211_VAP, M_NOWAIT | M_ZERO); - if (wvp == NULL) - return NULL; + wvp = malloc(sizeof(struct wi_vap), M_80211_VAP, M_WAITOK | M_ZERO); vap = &wvp->wv_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); vap->iv_max_aid = WI_MAX_AID; @@ -566,7 +538,7 @@ wi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, } /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, wi_media_status); + ieee80211_vap_attach(vap, ieee80211_media_change, wi_media_status, mac); ic->ic_opmode = opmode; return vap; } @@ -585,7 +557,9 @@ wi_shutdown(device_t dev) { struct wi_softc *sc = device_get_softc(dev); + WI_LOCK(sc); wi_stop(sc, 1); + WI_UNLOCK(sc); return (0); } @@ -593,12 +567,12 @@ void wi_intr(void *arg) { struct wi_softc *sc = arg; - struct ifnet *ifp = sc->sc_ifp; u_int16_t status; WI_LOCK(sc); - if (sc->wi_gone || !sc->sc_enabled || (ifp->if_flags & IFF_UP) == 0) { + if (sc->wi_gone || !sc->sc_enabled || + (sc->sc_flags & WI_FLAGS_RUNNING) == 0) { CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); WI_UNLOCK(sc); @@ -617,9 +591,8 @@ wi_intr(void *arg) wi_tx_ex_intr(sc); if (status & WI_EV_INFO) wi_info_intr(sc); - if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - wi_start_locked(ifp); + if (mbufq_first(&sc->sc_snd) != NULL) + wi_start(sc); /* Re-enable interrupts. */ CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); @@ -642,7 +615,7 @@ wi_enable(struct wi_softc *sc) static int wi_setup_locked(struct wi_softc *sc, int porttype, int mode, - uint8_t mac[IEEE80211_ADDR_LEN]) + const uint8_t mac[IEEE80211_ADDR_LEN]) { int i; @@ -676,26 +649,25 @@ wi_setup_locked(struct wi_softc *sc, int porttype, int mode, return 0; } -static void -wi_init_locked(struct wi_softc *sc) +void +wi_init(struct wi_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; int wasenabled; WI_LOCK_ASSERT(sc); wasenabled = sc->sc_enabled; if (wasenabled) - wi_stop_locked(sc, 1); + wi_stop(sc, 1); - if (wi_setup_locked(sc, sc->sc_porttype, 3, IF_LLADDR(ifp)) != 0) { - if_printf(ifp, "interface not running\n"); - wi_stop_locked(sc, 1); + if (wi_setup_locked(sc, sc->sc_porttype, 3, + sc->sc_ic.ic_macaddr) != 0) { + device_printf(sc->sc_dev, "interface not running\n"); + wi_stop(sc, 1); return; } - ifp->if_drv_flags |= IFF_DRV_RUNNING; - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + sc->sc_flags |= WI_FLAGS_RUNNING; callout_reset(&sc->sc_watchdog, hz, wi_watchdog, sc); @@ -703,24 +675,8 @@ wi_init_locked(struct wi_softc *sc) } void -wi_init(void *arg) -{ - struct wi_softc *sc = arg; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - - WI_LOCK(sc); - wi_init_locked(sc); - WI_UNLOCK(sc); - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ieee80211_start_all(ic); /* start all vap's */ -} - -static void -wi_stop_locked(struct wi_softc *sc, int disable) +wi_stop(struct wi_softc *sc, int disable) { - struct ifnet *ifp = sc->sc_ifp; WI_LOCK_ASSERT(sc); @@ -736,22 +692,13 @@ wi_stop_locked(struct wi_softc *sc, int disable) sc->sc_tx_timer = 0; sc->sc_false_syns = 0; - ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING); -} - -void -wi_stop(struct wi_softc *sc, int disable) -{ - WI_LOCK(sc); - wi_stop_locked(sc, disable); - WI_UNLOCK(sc); + sc->sc_flags &= ~WI_FLAGS_RUNNING; } static void wi_set_channel(struct ieee80211com *ic) { - struct ifnet *ifp = ic->ic_ifp; - struct wi_softc *sc = ifp->if_softc; + struct wi_softc *sc = ic->ic_softc; DPRINTF(("%s: channel %d, %sscanning\n", __func__, ieee80211_chan2ieee(ic, ic->ic_curchan), @@ -766,8 +713,7 @@ wi_set_channel(struct ieee80211com *ic) static void wi_scan_start(struct ieee80211com *ic) { - struct ifnet *ifp = ic->ic_ifp; - struct wi_softc *sc = ifp->if_softc; + struct wi_softc *sc = ic->ic_softc; struct ieee80211_scan_state *ss = ic->ic_scan; DPRINTF(("%s\n", __func__)); @@ -790,8 +736,7 @@ wi_scan_start(struct ieee80211com *ic) static void wi_scan_end(struct ieee80211com *ic) { - struct ifnet *ifp = ic->ic_ifp; - struct wi_softc *sc = ifp->if_softc; + struct wi_softc *sc = ic->ic_softc; DPRINTF(("%s: restore port type %d\n", __func__, sc->sc_porttype)); @@ -824,9 +769,8 @@ static int wi_newstate_sta(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; - struct ifnet *ifp = ic->ic_ifp; struct ieee80211_node *bss; - struct wi_softc *sc = ifp->if_softc; + struct wi_softc *sc = ic->ic_softc; DPRINTF(("%s: %s -> %s\n", __func__, ieee80211_state_name[vap->iv_state], @@ -894,9 +838,8 @@ static int wi_newstate_hostap(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; - struct ifnet *ifp = ic->ic_ifp; struct ieee80211_node *bss; - struct wi_softc *sc = ifp->if_softc; + struct wi_softc *sc = ic->ic_softc; int error; DPRINTF(("%s: %s -> %s\n", __func__, @@ -953,10 +896,30 @@ wi_newstate_hostap(struct ieee80211vap *vap, enum ieee80211_state nstate, int ar return error; } +static int +wi_transmit(struct ieee80211com *ic, struct mbuf *m) +{ + struct wi_softc *sc = ic->ic_softc; + int error; + + WI_LOCK(sc); + if ((sc->sc_flags & WI_FLAGS_RUNNING) == 0) { + WI_UNLOCK(sc); + return (ENXIO); + } + error = mbufq_enqueue(&sc->sc_snd, m); + if (error) { + WI_UNLOCK(sc); + return (error); + } + wi_start(sc); + WI_UNLOCK(sc); + return (0); +} + static void -wi_start_locked(struct ifnet *ifp) +wi_start(struct wi_softc *sc) { - struct wi_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct ieee80211_frame *wh; struct mbuf *m0; @@ -972,15 +935,8 @@ wi_start_locked(struct ifnet *ifp) memset(&frmhdr, 0, sizeof(frmhdr)); cur = sc->sc_txnext; - for (;;) { - IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); - if (m0 == NULL) - break; - if (sc->sc_txd[cur].d_len != 0) { - IFQ_DRV_PREPEND(&ifp->if_snd, m0); - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - break; - } + while (sc->sc_txd[cur].d_len == 0 && + (m0 = mbufq_dequeue(&sc->sc_snd)) != NULL) { ni = (struct ieee80211_node *) m0->m_pkthdr.rcvif; /* reconstruct 802.3 header */ @@ -1029,28 +985,16 @@ wi_start_locked(struct ifnet *ifp) m_adj(m0, sizeof(struct ieee80211_frame)); frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len); ieee80211_free_node(ni); - if (wi_start_tx(ifp, &frmhdr, m0)) + if (wi_start_tx(sc, &frmhdr, m0)) continue; sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf; - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } } -static void -wi_start(struct ifnet *ifp) -{ - struct wi_softc *sc = ifp->if_softc; - - WI_LOCK(sc); - wi_start_locked(ifp); - WI_UNLOCK(sc); -} - static int -wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr, struct mbuf *m0) +wi_start_tx(struct wi_softc *sc, struct wi_frame *frmhdr, struct mbuf *m0) { - struct wi_softc *sc = ifp->if_softc; int cur = sc->sc_txnext; int fid, off, error; @@ -1060,13 +1004,13 @@ wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr, struct mbuf *m0) || wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0; m_freem(m0); if (error) { - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + counter_u64_add(sc->sc_ic.ic_oerrors, 1); return -1; } sc->sc_txd[cur].d_len = off; if (sc->sc_txcur == cur) { if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) { - if_printf(ifp, "xmit failed\n"); + device_printf(sc->sc_dev, "xmit failed\n"); sc->sc_txd[cur].d_len = 0; return -1; } @@ -1080,9 +1024,8 @@ wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = ic->ic_ifp; struct ieee80211vap *vap = ni->ni_vap; - struct wi_softc *sc = ifp->if_softc; + struct wi_softc *sc = ic->ic_softc; struct ieee80211_key *k; struct ieee80211_frame *wh; struct wi_frame frmhdr; @@ -1098,7 +1041,6 @@ wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0, memset(&frmhdr, 0, sizeof(frmhdr)); cur = sc->sc_txnext; if (sc->sc_txd[cur].d_len != 0) { - ifp->if_drv_flags |= IFF_DRV_OACTIVE; rc = ENOBUFS; goto out; } @@ -1129,7 +1071,7 @@ wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0, (caddr_t)&frmhdr.wi_whdr); m_adj(m0, sizeof(struct ieee80211_frame)); frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len); - if (wi_start_tx(ifp, &frmhdr, m0) < 0) { + if (wi_start_tx(sc, &frmhdr, m0) < 0) { m0 = NULL; rc = EIO; goto out; @@ -1160,7 +1102,7 @@ wi_reset(struct wi_softc *sc) } sc->sc_reset = 1; if (i == WI_INIT_TRIES) { - if_printf(sc->sc_ifp, "reset failed\n"); + device_printf(sc->sc_dev, "reset failed\n"); return error; } @@ -1178,7 +1120,6 @@ static void wi_watchdog(void *arg) { struct wi_softc *sc = arg; - struct ifnet *ifp = sc->sc_ifp; WI_LOCK_ASSERT(sc); @@ -1186,65 +1127,52 @@ wi_watchdog(void *arg) return; if (sc->sc_tx_timer && --sc->sc_tx_timer == 0) { - if_printf(ifp, "device timeout\n"); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - wi_init_locked(ifp->if_softc); + device_printf(sc->sc_dev, "device timeout\n"); + counter_u64_add(sc->sc_ic.ic_oerrors, 1); + wi_init(sc); return; } callout_reset(&sc->sc_watchdog, hz, wi_watchdog, sc); } -static int -wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +static void +wi_parent(struct ieee80211com *ic) { - struct wi_softc *sc = ifp->if_softc; - struct ieee80211com *ic = ifp->if_l2com; - struct ifreq *ifr = (struct ifreq *) data; - int error = 0, startall = 0; + struct wi_softc *sc = ic->ic_softc; + int startall = 0; - switch (cmd) { - case SIOCSIFFLAGS: - WI_LOCK(sc); - /* - * Can't do promisc and hostap at the same time. If all that's - * changing is the promisc flag, try to short-circuit a call to - * wi_init() by just setting PROMISC in the hardware. - */ - if (ifp->if_flags & IFF_UP) { - if (ic->ic_opmode != IEEE80211_M_HOSTAP && - ifp->if_drv_flags & IFF_DRV_RUNNING) { - if ((ifp->if_flags ^ sc->sc_if_flags) & IFF_PROMISC) { - wi_write_val(sc, WI_RID_PROMISC, - (ifp->if_flags & IFF_PROMISC) != 0); - } else { - wi_init_locked(sc); - startall = 1; - } + WI_LOCK(sc); + /* + * Can't do promisc and hostap at the same time. If all that's + * changing is the promisc flag, try to short-circuit a call to + * wi_init() by just setting PROMISC in the hardware. + */ + if (ic->ic_nrunning > 0) { + if (ic->ic_opmode != IEEE80211_M_HOSTAP && + sc->sc_flags & WI_FLAGS_RUNNING) { + if (ic->ic_promisc > 0 && + (sc->sc_flags & WI_FLAGS_PROMISC) == 0) { + wi_write_val(sc, WI_RID_PROMISC, 1); + sc->sc_flags |= WI_FLAGS_PROMISC; + } else if (ic->ic_promisc == 0 && + (sc->sc_flags & WI_FLAGS_PROMISC) != 0) { + wi_write_val(sc, WI_RID_PROMISC, 0); + sc->sc_flags &= ~WI_FLAGS_PROMISC; } else { - wi_init_locked(sc); + wi_init(sc); startall = 1; } } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - wi_stop_locked(sc, 1); - sc->wi_gone = 0; + wi_init(sc); + startall = 1; } - sc->sc_if_flags = ifp->if_flags; - WI_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); - break; - case SIOCGIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); - break; - case SIOCGIFADDR: - error = ether_ioctl(ifp, cmd, data); - break; - default: - error = EINVAL; - break; + } else if (sc->sc_flags & WI_FLAGS_RUNNING) { + wi_stop(sc, 1); + sc->wi_gone = 0; } - return error; + WI_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); } static void @@ -1252,7 +1180,7 @@ wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; - struct wi_softc *sc = ic->ic_ifp->if_softc; + struct wi_softc *sc = ic->ic_softc; u_int16_t val; int rate, len; @@ -1280,8 +1208,7 @@ wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) static void wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_node *ni = vap->iv_bss; @@ -1295,7 +1222,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) * indicator of the firmware's BSSID. Damp spurious * change-of-BSSID indications. */ - if ((ifp->if_flags & IFF_PROMISC) != 0 && + if (ic->ic_promisc > 0 && !ppsratecheck(&sc->sc_last_syn, &sc->sc_false_syns, WI_MAX_FALSE_SYNS)) return; @@ -1316,8 +1243,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) static __noinline void wi_rx_intr(struct wi_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211com *ic = &sc->sc_ic; struct wi_frame frmhdr; struct mbuf *m; struct ieee80211_frame *wh; @@ -1332,7 +1258,7 @@ wi_rx_intr(struct wi_softc *sc) /* First read in the frame header */ if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + counter_u64_add(ic->ic_ierrors, 1); DPRINTF(("wi_rx_intr: read fid %x failed\n", fid)); return; } @@ -1343,7 +1269,7 @@ wi_rx_intr(struct wi_softc *sc) status = le16toh(frmhdr.wi_status); if (status & WI_STAT_ERRSTAT) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + counter_u64_add(ic->ic_ierrors, 1); DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status)); return; } @@ -1358,7 +1284,7 @@ wi_rx_intr(struct wi_softc *sc) if (off + len > MCLBYTES) { if (ic->ic_opmode != IEEE80211_M_MONITOR) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + counter_u64_add(ic->ic_ierrors, 1); DPRINTF(("wi_rx_intr: oversized packet\n")); return; } else @@ -1371,7 +1297,7 @@ wi_rx_intr(struct wi_softc *sc) m = m_gethdr(M_NOWAIT, MT_DATA); if (m == NULL) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + counter_u64_add(ic->ic_ierrors, 1); DPRINTF(("wi_rx_intr: MGET failed\n")); return; } @@ -1380,7 +1306,6 @@ wi_rx_intr(struct wi_softc *sc) wi_read_bap(sc, fid, sizeof(frmhdr), m->m_data + sizeof(struct ieee80211_frame), len); m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len; - m->m_pkthdr.rcvif = ifp; CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); @@ -1425,7 +1350,6 @@ wi_rx_intr(struct wi_softc *sc) static __noinline void wi_tx_ex_intr(struct wi_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; struct wi_frame frmhdr; int fid; @@ -1440,7 +1364,7 @@ wi_tx_ex_intr(struct wi_softc *sc) */ if ((status & WI_TXSTAT_DISCONNECT) == 0) { if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) { - if_printf(ifp, "tx failed"); + device_printf(sc->sc_dev, "tx failed"); if (status & WI_TXSTAT_RET_ERR) printf(", retry limit exceeded"); if (status & WI_TXSTAT_AGED_ERR) @@ -1455,7 +1379,7 @@ wi_tx_ex_intr(struct wi_softc *sc) printf(", status=0x%x", status); printf("\n"); } - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + counter_u64_add(sc->sc_ic.ic_oerrors, 1); } else DPRINTF(("port disconnected\n")); } else @@ -1466,7 +1390,6 @@ wi_tx_ex_intr(struct wi_softc *sc) static __noinline void wi_tx_intr(struct wi_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; int fid, cur; if (sc->wi_gone) @@ -1477,19 +1400,17 @@ wi_tx_intr(struct wi_softc *sc) cur = sc->sc_txcur; if (sc->sc_txd[cur].d_fid != fid) { - if_printf(ifp, "bad alloc %x != %x, cur %d nxt %d\n", + device_printf(sc->sc_dev, "bad alloc %x != %x, cur %d nxt %d\n", fid, sc->sc_txd[cur].d_fid, cur, sc->sc_txnext); return; } sc->sc_tx_timer = 0; sc->sc_txd[cur].d_len = 0; sc->sc_txcur = cur = (cur + 1) % sc->sc_ntxbuf; - if (sc->sc_txd[cur].d_len == 0) - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - else { + if (sc->sc_txd[cur].d_len != 0) { if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid, 0, 0)) { - if_printf(ifp, "xmit failed\n"); + device_printf(sc->sc_dev, "xmit failed\n"); sc->sc_txd[cur].d_len = 0; } else { sc->sc_tx_timer = 5; @@ -1500,7 +1421,7 @@ wi_tx_intr(struct wi_softc *sc) static __noinline void wi_info_intr(struct wi_softc *sc) { - struct ieee80211com *ic = sc->sc_ifp->if_l2com; + struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); int i, fid, len, off; u_int16_t ltbuf[2]; @@ -1574,32 +1495,15 @@ finish: CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); } -static uint64_t -wi_get_counter(struct ifnet *ifp, ift_counter cnt) -{ - struct wi_softc *sc; - - sc = if_getsoftc(ifp); - - switch (cnt) { - case IFCOUNTER_COLLISIONS: - return (sc->sc_stats.wi_tx_single_retries + - sc->sc_stats.wi_tx_multi_retries + - sc->sc_stats.wi_tx_retry_limit); - default: - return (if_get_counter_default(ifp, cnt)); - } -} - static int wi_write_multi(struct wi_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; - int n; - struct ifmultiaddr *ifma; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap; struct wi_mcast mlist; + int n; - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { + if (ic->ic_allmulti > 0 || ic->ic_promisc > 0) { allmulti: memset(&mlist, 0, sizeof(mlist)); return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, @@ -1607,17 +1511,23 @@ allmulti: } n = 0; - if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (n >= 16) - goto allmulti; - IEEE80211_ADDR_COPY(&mlist.wi_mcast[n], - (LLADDR((struct sockaddr_dl *)ifma->ifma_addr))); - n++; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct ifnet *ifp; + struct ifmultiaddr *ifma; + + ifp = vap->iv_ifp; + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (n >= 16) + goto allmulti; + IEEE80211_ADDR_COPY(&mlist.wi_mcast[n], + (LLADDR((struct sockaddr_dl *)ifma->ifma_addr))); + n++; + } + if_maddr_runlock(ifp); } - if_maddr_runlock(ifp); return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, IEEE80211_ADDR_LEN * n); } @@ -1638,7 +1548,7 @@ wi_update_promisc(struct ieee80211com *ic) /* XXX handle WEP special case handling? */ wi_write_val(sc, WI_RID_PROMISC, (ic->ic_opmode == IEEE80211_M_MONITOR || - (ic->ic_ifp->if_flags & IFF_PROMISC))); + (ic->ic_promisc > 0))); WI_UNLOCK(sc); } @@ -1937,7 +1847,7 @@ wi_read_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen) } static int -wi_write_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen) +wi_write_bap(struct wi_softc *sc, int id, int off, const void *buf, int buflen) { int error, cnt; @@ -1949,7 +1859,7 @@ wi_write_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen) return error; } cnt = (buflen + 1) / 2; - CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, (u_int16_t *)buf, cnt); + CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, (const uint16_t *)buf, cnt); sc->sc_bap_off += cnt * 2; return 0; @@ -2039,7 +1949,7 @@ wi_read_rid(struct wi_softc *sc, int rid, void *buf, int *buflenp) } static int -wi_write_rid(struct wi_softc *sc, int rid, void *buf, int buflen) +wi_write_rid(struct wi_softc *sc, int rid, const void *buf, int buflen) { int error; u_int16_t ltbuf[2]; |