diff options
| author | Bill Paul <wpaul@FreeBSD.org> | 2005-10-27 17:08:57 +0000 |
|---|---|---|
| committer | Bill Paul <wpaul@FreeBSD.org> | 2005-10-27 17:08:57 +0000 |
| commit | 0dbb2e0f3424ca769df0bcb1afd129b20b394202 (patch) | |
| tree | 4b9437a3f49cf1f2030d1a1c6fb2e7dd2d7c3ecb /sys/dev | |
| parent | fd47f7362f0095f68af208c4107f59f365bc470c (diff) | |
Notes
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 1385 | ||||
| -rw-r--r-- | sys/dev/if_ndis/if_ndisvar.h | 93 |
2 files changed, 979 insertions, 499 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index 616887df0221..097221fac66c 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -29,14 +29,13 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * WPA support added by Arvind Srinivasan <arvind@celar.us> + * WPA support originally contributed by Arvind Srinivasan <arvind@celar.us> + * then hacked upon mercilessly by my. */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_bdg.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/sockio.h> @@ -51,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #endif + #include <net/if.h> #include <net/if_arp.h> #include <net/ethernet.h> @@ -120,13 +120,14 @@ static funcptr ndis_linksts_done_wrap; static funcptr ndis_ticktask_wrap; static funcptr ndis_starttask_wrap; static funcptr ndis_resettask_wrap; +static funcptr ndis_inputtask_wrap; -static void ndis_intr (void *); static void ndis_tick (void *); -static void ndis_ticktask (ndis_work_item *, void *); +static void ndis_ticktask (device_object *, void *); static void ndis_start (struct ifnet *); -static void ndis_starttask (ndis_work_item *, void *); -static void ndis_resettask (ndis_work_item *, void *); +static void ndis_starttask (device_object *, void *); +static void ndis_resettask (device_object *, void *); +static void ndis_inputtask (device_object *, void *); static int ndis_ioctl (struct ifnet *, u_long, caddr_t); static int ndis_wi_ioctl_get (struct ifnet *, u_long, caddr_t); static int ndis_wi_ioctl_set (struct ifnet *, u_long, caddr_t); @@ -142,8 +143,14 @@ static int ndis_probe_offload (struct ndis_softc *); static int ndis_set_offload (struct ndis_softc *); static void ndis_getstate_80211 (struct ndis_softc *); static void ndis_setstate_80211 (struct ndis_softc *); -static int ndis_add_key (struct ndis_softc *, - struct ieee80211req_key *, int16_t); +#ifdef IEEE80211_F_WPA +static int ndis_set_cipher (struct ndis_softc *, int); +static int ndis_set_wpa (struct ndis_softc *); +static int ndis_add_key (struct ieee80211com *, + const struct ieee80211_key *, const u_int8_t []); +static int ndis_del_key (struct ieee80211com *, + const struct ieee80211_key *); +#endif static void ndis_media_status (struct ifnet *, struct ifmediareq *); static void ndis_setmulti (struct ndis_softc *); @@ -194,6 +201,8 @@ ndisdrv_modevent(mod, cmd, arg) 2, WINDRV_WRAP_STDCALL); windrv_wrap((funcptr)ndis_resettask, &ndis_resettask_wrap, 2, WINDRV_WRAP_STDCALL); + windrv_wrap((funcptr)ndis_inputtask, &ndis_inputtask_wrap, + 2, WINDRV_WRAP_STDCALL); break; case MOD_UNLOAD: ndisdrv_loaded--; @@ -212,6 +221,7 @@ ndisdrv_modevent(mod, cmd, arg) windrv_unwrap(ndis_ticktask_wrap); windrv_unwrap(ndis_starttask_wrap); windrv_unwrap(ndis_resettask_wrap); + windrv_unwrap(ndis_inputtask_wrap); break; default: error = EINVAL; @@ -245,7 +255,7 @@ ndis_setmulti(sc) &sc->ndis_filter, &len); if (error) device_printf (sc->ndis_dev, - "set filter failed: %d\n", error); + "set allmulti failed: %d\n", error); return; } @@ -296,7 +306,7 @@ out: error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, &sc->ndis_filter, &len); if (error) - device_printf (sc->ndis_dev, "set filter failed: %d\n", error); + device_printf (sc->ndis_dev, "set multi failed: %d\n", error); return; } @@ -470,33 +480,21 @@ ndis_attach(dev) int i; sc = device_get_softc(dev); +#if __FreeBSD_version < 600031 + sc->ifp = &sc->arpcom.ac_if; + ifp = sc->ifp; +#else ifp = sc->ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { error = ENOSPC; goto fail; } +#endif ifp->if_softc = sc; - mtx_init(&sc->ndis_mtx, "ndis softc lock", - MTX_NETWORK_LOCK, MTX_DEF); - - /* - * Hook interrupt early, since calling the driver's - * init routine may trigger an interrupt. Note that - * we don't need to do any explicit interrupt setup - * for USB. - */ - - if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) { - error = bus_setup_intr(dev, sc->ndis_irq, - INTR_TYPE_NET | INTR_MPSAFE, - ndis_intr, sc, &sc->ndis_intrhand); - - if (error) { - device_printf(dev, "couldn't set up irq\n"); - goto fail; - } - } + KeInitializeSpinLock(&sc->ndis_spinlock); + KeInitializeSpinLock(&sc->ndis_rxlock); + InitializeListHead(&sc->ndis_shlist); if (sc->ndis_iftype == PCMCIABus) { error = ndis_alloc_amem(sc); @@ -568,26 +566,37 @@ ndis_attach(dev) ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len); /* - * Figure out if we're allowed to use multipacket sends - * with this driver, and if so, how many. + * Figure out how big to make the TX buffer pool. */ - if (sc->ndis_chars->nmc_sendsingle_func && - sc->ndis_chars->nmc_sendmulti_func == NULL) { - sc->ndis_maxpkts = 1; - } else { - len = sizeof(sc->ndis_maxpkts); - ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS, - &sc->ndis_maxpkts, &len); + len = sizeof(sc->ndis_maxpkts); + if (ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS, + &sc->ndis_maxpkts, &len)) { + device_printf (dev, "failed to get max TX packets\n"); + error = ENXIO; + goto fail; } + /* + * If this is a deserialized miniport, we don't have + * to honor the OID_GEN_MAXIMUM_SEND_PACKETS result. + */ + + if (!NDIS_SERIALIZED(sc->ndis_block)) + sc->ndis_maxpkts = NDIS_TXPKTS; + + /* Enforce some sanity, just in case. */ + + if (sc->ndis_maxpkts == 0) + sc->ndis_maxpkts = 10; + sc->ndis_txarray = malloc(sizeof(ndis_packet *) * - sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT|M_ZERO); + NDIS_TXPKTS, M_DEVBUF, M_NOWAIT|M_ZERO); /* Allocate a pool of ndis_packets for TX encapsulation. */ NdisAllocatePacketPool(&i, &sc->ndis_txpool, - sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET); + NDIS_TXPKTS, PROTOCOL_RESERVED_SIZE_IN_PACKET); if (i != NDIS_STATUS_SUCCESS) { sc->ndis_txpool = NULL; @@ -621,6 +630,14 @@ ndis_attach(dev) /* Check for task offload support. */ ndis_probe_offload(sc); +#if __FreeBSD_version < 502109 + /* + * An NDIS device was detected. Inform the world. + */ + device_printf(dev, "%s address: %6D\n", + sc->ndis_80211 ? "802.11" : "Ethernet", eaddr, ":"); +#endif + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; @@ -647,7 +664,9 @@ ndis_attach(dev) uint32_t arg; int r; +#if __FreeBSD_version >= 600007 ic->ic_ifp = ifp; +#endif ic->ic_phytype = IEEE80211_T_DS; ic->ic_opmode = IEEE80211_M_STA; ic->ic_caps = IEEE80211_C_IBSS; @@ -658,7 +677,7 @@ ndis_attach(dev) NULL, &len); if (r != ENOSPC) goto nonettypes; - ntl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO); + ntl = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO); r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, ntl, &len); if (r != 0) { @@ -803,20 +822,73 @@ nonettypes: ic->ic_channels[i].ic_flags = chanflag; } + /* + * To test for WPA support, we need to see if we can + * set AUTHENTICATION_MODE to WPA and read it back + * successfully. + */ +#ifdef IEEE80211_F_WPA + i = sizeof(arg); + arg = NDIS_80211_AUTHMODE_WPA; + r = ndis_set_info(sc, + OID_802_11_AUTHENTICATION_MODE, &arg, &i); + if (r == 0) { + r = ndis_get_info(sc, + OID_802_11_AUTHENTICATION_MODE, &arg, &i); + if (r == 0 && arg == NDIS_80211_AUTHMODE_WPA) + ic->ic_caps |= IEEE80211_C_WPA; + } + + /* + * To test for supported ciphers, we set each + * available encryption type in descending order. + * If ENC3 works, then we have WEP, TKIP and AES. + * If only ENC2 works, then we have WEP and TKIP. + * If only ENC1 works, then we have just WEP. + */ i = sizeof(arg); - r = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &i); - if (arg != NDIS_80211_WEPSTAT_NOTSUPPORTED) + arg = NDIS_80211_WEPSTAT_ENC3ENABLED; + r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); + if (r == 0) { + ic->ic_caps |= IEEE80211_C_WEP|IEEE80211_C_TKIP| + IEEE80211_C_AES_CCM; + goto got_crypto; + } + arg = NDIS_80211_WEPSTAT_ENC2ENABLED; + r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); + if (r == 0) { + ic->ic_caps |= IEEE80211_C_WEP|IEEE80211_C_TKIP; + goto got_crypto; + } +#endif + arg = NDIS_80211_WEPSTAT_ENC1ENABLED; + r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); + if (r == 0) ic->ic_caps |= IEEE80211_C_WEP; +#ifdef IEEE80211_F_WPA +got_crypto: +#endif i = sizeof(arg); r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i); if (r == 0) ic->ic_caps |= IEEE80211_C_PMGT; bcopy(eaddr, &ic->ic_myaddr, sizeof(eaddr)); +#if __FreeBSD_version < 600007 + ieee80211_ifattach(ifp); + ieee80211_media_init(ifp, ieee80211_media_change, + ndis_media_status); +#else ieee80211_ifattach(ic); ieee80211_media_init(ic, ieee80211_media_change, ndis_media_status); +#endif ic->ic_ibss_chan = IEEE80211_CHAN_ANYC; ic->ic_bss->ni_chan = ic->ic_ibss_chan; +#ifdef IEEE80211_F_WPA + /* install key handing routines */ + ic->ic_crypto.cs_key_set = ndis_add_key; + ic->ic_crypto.cs_key_delete = ndis_del_key; +#endif } else { ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd, ndis_ifmedia_sts); @@ -835,12 +907,10 @@ nonettypes: sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap; /* Set up work item handlers. */ - NdisInitializeWorkItem(&sc->ndis_tickitem, - (ndis_proc)ndis_ticktask_wrap, sc); - NdisInitializeWorkItem(&sc->ndis_startitem, - (ndis_proc)ndis_starttask_wrap, ifp); - NdisInitializeWorkItem(&sc->ndis_resetitem, - (ndis_proc)ndis_resettask_wrap, sc); + sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); + sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); + sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); + sc->ndis_inputitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block); @@ -870,8 +940,6 @@ ndis_detach(dev) driver_object *drv; sc = device_get_softc(dev); - KASSERT(mtx_initialized(&sc->ndis_mtx), - ("ndis mutex not initialized")); NDIS_LOCK(sc); ifp = sc->ifp; ifp->if_flags &= ~IFF_UP; @@ -880,18 +948,27 @@ ndis_detach(dev) NDIS_UNLOCK(sc); ndis_stop(sc); if (sc->ndis_80211) +#if __FreeBSD_version < 600007 + ieee80211_ifdetach(ifp); +#else ieee80211_ifdetach(&sc->ic); +#endif else ether_ifdetach(ifp); } else NDIS_UNLOCK(sc); - if (ifp != NULL) - if_free(ifp); + + if (sc->ndis_tickitem != NULL) + IoFreeWorkItem(sc->ndis_tickitem); + if (sc->ndis_startitem != NULL) + IoFreeWorkItem(sc->ndis_startitem); + if (sc->ndis_resetitem != NULL) + IoFreeWorkItem(sc->ndis_resetitem); + if (sc->ndis_inputitem != NULL) + IoFreeWorkItem(sc->ndis_inputitem); bus_generic_detach(dev); - if (sc->ndis_intrhand) - bus_teardown_intr(dev, sc->ndis_irq, sc->ndis_intrhand); if (sc->ndis_irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq); if (sc->ndis_res_io) @@ -904,6 +981,11 @@ ndis_detach(dev) bus_release_resource(dev, SYS_RES_MEMORY, sc->ndis_altmem_rid, sc->ndis_res_altmem); +#if __FreeBSD_version >= 600031 + if (ifp != NULL) + if_free(ifp); +#endif + if (sc->ndis_iftype == PCMCIABus) ndis_free_amem(sc); @@ -940,8 +1022,6 @@ ndis_detach(dev) sysctl_ctx_free(&sc->ndis_ctx); #endif - mtx_destroy(&sc->ndis_mtx); - return(0); } @@ -982,6 +1062,9 @@ ndis_resume(dev) /* * The following bunch of routines are here to support drivers that * use the NdisMEthIndicateReceive()/MiniportTransferData() mechanism. + * The NdisMEthIndicateReceive() handler runs at DISPATCH_LEVEL for + * serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized + * miniports. */ static void @@ -1048,14 +1131,19 @@ ndis_rxeof_eth(adapter, ctx, addr, hdr, hdrlen, lookahead, lookaheadlen, pktlen) KeAcquireSpinLock(&block->nmb_lock, &irql); - INSERT_LIST_TAIL((&block->nmb_packetlist), - ((list_entry *)&p->u.np_clrsvd.np_miniport_rsvd)); + InsertTailList((&block->nmb_packetlist), (&p->np_list)); KeReleaseSpinLock(&block->nmb_lock, irql); return; } +/* + * NdisMEthIndicateReceiveComplete() handler, runs at DISPATCH_LEVEL + * for serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized + * miniports. + */ + static void ndis_rxeof_done(adapter) ndis_handle adapter; @@ -1075,7 +1163,7 @@ ndis_rxeof_done(adapter) } /* - * Runs at DISPATCH_LEVEL. + * MiniportTransferData() handler, runs at DISPATCH_LEVEL. */ static void ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2) @@ -1100,10 +1188,10 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2) KeAcquireSpinLockAtDpcLevel(&block->nmb_lock); l = block->nmb_packetlist.nle_flink; - while(l != &block->nmb_packetlist) { - REMOVE_LIST_HEAD((&block->nmb_packetlist)); - p = CONTAINING_RECORD(l, ndis_packet, - u.np_clrsvd.np_miniport_rsvd); + while(!IsListEmpty(&block->nmb_packetlist)) { + l = RemoveHeadList((&block->nmb_packetlist)); + p = CONTAINING_RECORD(l, ndis_packet, np_list); + InitializeListHead((&p->np_list)); priv = (ndis_ethpriv *)&p->np_protocolreserved; m = p->np_m0; @@ -1130,8 +1218,12 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2) if (status == NDIS_STATUS_SUCCESS) { IoFreeMdl(p->np_private.npp_head); NdisFreePacket(p); - ifp->if_ipackets++; - (*ifp->if_input)(ifp, m); + KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); + _IF_ENQUEUE(&sc->ndis_rxqueue, m); + KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); + IoQueueWorkItem(sc->ndis_inputitem, + (io_workitem_func)ndis_inputtask_wrap, + WORKQUEUE_CRITICAL, ifp); } if (status == NDIS_STATUS_FAILURE) @@ -1146,6 +1238,9 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2) return; } +/* + * NdisMTransferDataComplete() handler, runs at DISPATCH_LEVEL. + */ static void ndis_rxeof_xfr_done(adapter, packet, status, len) ndis_handle adapter; @@ -1173,8 +1268,13 @@ ndis_rxeof_xfr_done(adapter, packet, status, len) m->m_len = m->m_pkthdr.len; m->m_pkthdr.rcvif = ifp; - ifp->if_ipackets++; - (*ifp->if_input)(ifp, m); + KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); + _IF_ENQUEUE(&sc->ndis_rxqueue, m); + KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); + IoQueueWorkItem(sc->ndis_inputitem, + (io_workitem_func)ndis_inputtask_wrap, + WORKQUEUE_CRITICAL, ifp); + return; } /* @@ -1224,6 +1324,7 @@ ndis_rxeof(adapter, packets, pktcnt) if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) ndis_return_packet(sc, p); } else { +#ifdef notdef if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) { m = m_dup(m0, M_DONTWAIT); /* @@ -1242,8 +1343,19 @@ ndis_rxeof(adapter, packets, pktcnt) m0 = m; } else p->np_oob.npo_status = NDIS_STATUS_PENDING; +#endif + m = m_dup(m0, M_DONTWAIT); + if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) + p->np_refcnt++; + else + p->np_oob.npo_status = NDIS_STATUS_PENDING; + m_freem(m0); + if (m == NULL) { + ifp->if_ierrors++; + continue; + } + m0 = m; m0->m_pkthdr.rcvif = ifp; - ifp->if_ipackets++; /* Deal with checksum offload. */ @@ -1265,7 +1377,12 @@ ndis_rxeof(adapter, packets, pktcnt) } } - (*ifp->if_input)(ifp, m0); + KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); + _IF_ENQUEUE(&sc->ndis_rxqueue, m); + KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); + IoQueueWorkItem(sc->ndis_inputitem, + (io_workitem_func)ndis_inputtask_wrap, + WORKQUEUE_CRITICAL, ifp); } } @@ -1273,6 +1390,43 @@ ndis_rxeof(adapter, packets, pktcnt) } /* + * This routine is run at PASSIVE_LEVEL. We use this routine to pass + * packets into the stack in order to avoid calling (*ifp->if_input)() + * with any locks held (at DISPATCH_LEVEL, we'll be holding the + * 'dispatch level' per-cpu sleep lock). + */ + +static void +ndis_inputtask(dobj, arg) + device_object *dobj; + void *arg; +{ + ndis_miniport_block *block; + struct ifnet *ifp; + struct ndis_softc *sc; + struct mbuf *m; + uint8_t irql; + + ifp = arg; + sc = ifp->if_softc; + block = dobj->do_devext; + + KeAcquireSpinLock(&sc->ndis_rxlock, &irql); + while(1) { + _IF_DEQUEUE(&sc->ndis_rxqueue, m); + if (m == NULL) + break; + KeReleaseSpinLock(&sc->ndis_rxlock, irql); + ifp->if_ipackets++; + (*ifp->if_input)(ifp, m); + KeAcquireSpinLock(&sc->ndis_rxlock, &irql); + } + KeReleaseSpinLock(&sc->ndis_rxlock, irql); + + return; +} + +/* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ @@ -1309,12 +1463,15 @@ ndis_txeof(adapter, packet, status) ifp->if_opackets++; else ifp->if_oerrors++; + ifp->if_timer = 0; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; NDIS_UNLOCK(sc); - NdisScheduleWorkItem(&sc->ndis_startitem); + IoQueueWorkItem(sc->ndis_startitem, + (io_workitem_func)ndis_starttask_wrap, + WORKQUEUE_CRITICAL, ifp); return; } @@ -1331,8 +1488,32 @@ ndis_linksts(adapter, status, sbuf, slen) block = adapter; sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + sc->ndis_sts = status; + + /* Event list is all full up, drop this one. */ + + NDIS_LOCK(sc); + if (sc->ndis_evt[sc->ndis_evtpidx].ne_sts) { + NDIS_UNLOCK(sc); + return; + } - block->nmb_getstat = status; + /* Cache the event. */ + + if (slen) { + sc->ndis_evt[sc->ndis_evtpidx].ne_buf = malloc(slen, + M_TEMP, M_NOWAIT); + if (sc->ndis_evt[sc->ndis_evtpidx].ne_buf == NULL) { + NDIS_UNLOCK(sc); + return; + } + bcopy((char *)sbuf, + sc->ndis_evt[sc->ndis_evtpidx].ne_buf, slen); + } + sc->ndis_evt[sc->ndis_evtpidx].ne_sts = status; + sc->ndis_evt[sc->ndis_evtpidx].ne_len = slen; + NDIS_EVTINC(sc->ndis_evtpidx); + NDIS_UNLOCK(sc); return; } @@ -1352,51 +1533,28 @@ ndis_linksts_done(adapter) if (!NDIS_INITIALIZED(sc)) return; - switch (block->nmb_getstat) { + switch (sc->ndis_sts) { case NDIS_STATUS_MEDIA_CONNECT: - NdisScheduleWorkItem(&sc->ndis_tickitem); - NdisScheduleWorkItem(&sc->ndis_startitem); + IoQueueWorkItem(sc->ndis_tickitem, + (io_workitem_func)ndis_ticktask_wrap, + WORKQUEUE_CRITICAL, sc); + IoQueueWorkItem(sc->ndis_startitem, + (io_workitem_func)ndis_starttask_wrap, + WORKQUEUE_CRITICAL, ifp); break; case NDIS_STATUS_MEDIA_DISCONNECT: if (sc->ndis_link) - NdisScheduleWorkItem(&sc->ndis_tickitem); + IoQueueWorkItem(sc->ndis_tickitem, + (io_workitem_func)ndis_ticktask_wrap, + WORKQUEUE_CRITICAL, sc); break; default: break; } - return; -} - -static void -ndis_intr(arg) - void *arg; -{ - struct ndis_softc *sc; - struct ifnet *ifp; - int is_our_intr = 0; - int call_isr = 0; - uint8_t irql; - ndis_miniport_interrupt *intr; - - sc = arg; - ifp = sc->ifp; - intr = sc->ndis_block->nmb_interrupt; - - if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL) - return; - - KeAcquireSpinLock(&intr->ni_dpccountlock, &irql); - if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE) - ndis_isr(sc, &is_our_intr, &call_isr); - else { - ndis_disable_intr(sc); - call_isr = 1; - } - KeReleaseSpinLock(&intr->ni_dpccountlock, irql); + /* Notify possible listners of interface change. */ - if ((is_our_intr || call_isr)) - IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc); + rt_ifmsg(ifp); return; } @@ -1411,7 +1569,9 @@ ndis_tick(xsc) sc = xsc; - NdisScheduleWorkItem(&sc->ndis_tickitem); + IoQueueWorkItem(sc->ndis_tickitem, + (io_workitem_func)ndis_ticktask_wrap, + WORKQUEUE_CRITICAL, sc); sc->ndis_stat_ch = timeout(ndis_tick, sc, hz * sc->ndis_block->nmb_checkforhangsecs); @@ -1421,17 +1581,24 @@ ndis_tick(xsc) } static void -ndis_ticktask(w, xsc) - ndis_work_item *w; +ndis_ticktask(d, xsc) + device_object *d; void *xsc; { struct ndis_softc *sc; + struct ieee80211com *ic; ndis_checkforhang_handler hangfunc; uint8_t rval; - ndis_media_state linkstate; - int error, len; sc = xsc; + ic = &sc->ic; + + NDIS_LOCK(sc); + if (!NDIS_INITIALIZED(sc)) { + NDIS_UNLOCK(sc); + return; + } + NDIS_UNLOCK(sc); hangfunc = sc->ndis_chars->nmc_checkhang_func; @@ -1444,31 +1611,42 @@ ndis_ticktask(w, xsc) } } - len = sizeof(linkstate); - error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS, - (void *)&linkstate, &len); - NDIS_LOCK(sc); - - if (sc->ndis_link == 0 && linkstate == nmc_connected) { - device_printf(sc->ndis_dev, "link up\n"); + if (sc->ndis_link == 0 && + sc->ndis_sts == NDIS_STATUS_MEDIA_CONNECT) { sc->ndis_link = 1; NDIS_UNLOCK(sc); - if (sc->ndis_80211) + if (sc->ndis_80211) { ndis_getstate_80211(sc); + ic->ic_state = IEEE80211_S_RUN; + } NDIS_LOCK(sc); #ifdef LINK_STATE_UP +#if __FreeBSD_version > 600006 + if_link_state_change(sc->ifp, LINK_STATE_UP); +#else sc->ifp->if_link_state = LINK_STATE_UP; rt_ifmsg(sc->ifp); +#endif +#else + device_printf(sc->ndis_dev, "link state changed to UP\n"); #endif /* LINK_STATE_UP */ } - if (sc->ndis_link == 1 && linkstate == nmc_disconnected) { - device_printf(sc->ndis_dev, "link down\n"); + if (sc->ndis_link == 1 && + sc->ndis_sts == NDIS_STATUS_MEDIA_DISCONNECT) { sc->ndis_link = 0; + if (sc->ndis_80211) + ic->ic_state = IEEE80211_S_ASSOC; #ifdef LINK_STATE_DOWN +#if __FreeBSD_version > 600006 + if_link_state_change(sc->ifp, LINK_STATE_DOWN); +#else sc->ifp->if_link_state = LINK_STATE_DOWN; rt_ifmsg(sc->ifp); +#endif +#else + device_printf(sc->ndis_dev, "link state changed to DOWN\n"); #endif /* LINK_STATE_DOWN */ } @@ -1505,8 +1683,8 @@ ndis_map_sclist(arg, segs, nseg, mapsize, error) } static void -ndis_starttask(w, arg) - ndis_work_item *w; +ndis_starttask(d, arg) + device_object *d; void *arg; { struct ifnet *ifp; @@ -1660,10 +1838,17 @@ ndis_start(ifp) NDIS_UNLOCK(sc); - if (sc->ndis_maxpkts == 1) - ndis_send_packet(sc, p); - else + /* + * According to NDIS documentation, if a driver exports + * a MiniportSendPackets() routine, we prefer that over + * a MiniportSend() routine (which sends just a single + * packet). + */ + + if (sc->ndis_chars->nmc_sendmulti_func != NULL) ndis_send_packets(sc, p0, pcnt); + else + ndis_send_packet(sc, p); return; } @@ -1674,7 +1859,7 @@ ndis_init(xsc) { struct ndis_softc *sc = xsc; struct ifnet *ifp = sc->ifp; - int i, error; + int i, len, error; /* * Avoid reintializing the link unnecessarily. @@ -1689,6 +1874,7 @@ ndis_init(xsc) * Cancel pending I/O and free all RX/TX buffers. */ ndis_stop(sc); + if (ndis_init_nic(sc)) return; @@ -1704,15 +1890,23 @@ ndis_init(xsc) if (ifp->if_flags & IFF_PROMISC) sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; - i = sizeof(sc->ndis_filter); + len = sizeof(sc->ndis_filter); error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, - &sc->ndis_filter, &i); + &sc->ndis_filter, &len); if (error) device_printf (sc->ndis_dev, "set filter failed: %d\n", error); /* + * Set lookahead. + */ + + i = ifp->if_mtu; + len = sizeof(i); + ndis_set_info(sc, OID_GEN_CURRENT_LOOKAHEAD, &i, &len); + + /* * Program the multicast filter, if necessary. */ ndis_setmulti(sc); @@ -1732,6 +1926,15 @@ ndis_init(xsc) sc->ndis_txpending = sc->ndis_maxpkts; sc->ndis_link = 0; +#ifdef LINK_STATE_UNKNOWN +#if __FreeBSD_version > 600006 + if_link_state_change(sc->ifp, LINK_STATE_UNKNOWN); +#else + sc->ifp->if_link_state = LINK_STATE_DOWN; + rt_ifmsg(sc->ifp); +#endif +#endif /* LINK_STATE_UNKNOWN */ + ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; @@ -1819,12 +2022,148 @@ ndis_ifmedia_sts(ifp, ifmr) return; } +#ifdef IEEE80211_F_WPA +static int +ndis_set_cipher(sc, cipher) + struct ndis_softc *sc; + int cipher; +{ + struct ieee80211com *ic; + int rval = 0, len; + uint32_t arg, save; + + ic = &sc->ic; + + len = sizeof(arg); + + if (cipher == WPA_CSE_WEP40 || WPA_CSE_WEP104) { + if (!(ic->ic_caps & IEEE80211_C_WEP)) + return(ENOTSUP); + arg = NDIS_80211_WEPSTAT_ENC1ENABLED; + } + + if (cipher == WPA_CSE_TKIP) { + if (!(ic->ic_caps & IEEE80211_C_TKIP)) + return(ENOTSUP); + arg = NDIS_80211_WEPSTAT_ENC2ENABLED; + } + + if (cipher == WPA_CSE_CCMP) { + if (!(ic->ic_caps & IEEE80211_C_AES_CCM)) + return(ENOTSUP); + arg = NDIS_80211_WEPSTAT_ENC3ENABLED; + } + + save = arg; + rval = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len); + + if (rval) + return(rval); + + /* Check that the cipher was set correctly. */ + + len = sizeof(save); + rval = ndis_get_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len); + + if (rval != 0 || arg != save) + return(ENODEV); + + return(0); +} + +/* + * WPA is hairy to set up. Do the work in a separate routine + * so we don't clutter the setstate function too much. + * Important yet undocumented fact: first we have to set the + * authentication mode, _then_ we enable the ciphers. If one + * of the WPA authentication modes isn't enabled, the driver + * might not permit the TKIP or AES ciphers to be selected. + */ + +static int +ndis_set_wpa(sc) + struct ndis_softc *sc; +{ + struct ieee80211com *ic; + struct ieee80211_ie_wpa *w; + struct ndis_ie *n; + char *pos; + uint32_t arg; + int i; + + ic = &sc->ic; + + /* + * Apparently, the only way for us to know what ciphers + * and key management/authentication mode to use is for + * us to inspect the optional information element (IE) + * stored in the 802.11 state machine. This IE should be + * supplied by the WPA supplicant. + */ + + w = (struct ieee80211_ie_wpa *)ic->ic_opt_ie; + + /* Check for the right kind of IE. */ + if (w->wpa_id != IEEE80211_ELEMID_VENDOR) + return(EINVAL); + + /* Skip over the ucast cipher OIDs. */ + pos = (char *)&w->wpa_uciphers[0]; + pos += w->wpa_uciphercnt * sizeof(struct ndis_ie); + + /* Skip over the authmode count. */ + pos += sizeof(u_int16_t); + + /* + * Check for the authentication modes. I'm + * pretty sure there's only supposed to be one. + */ + + n = (struct ndis_ie *)pos; + if (n->ni_val == WPA_ASE_NONE) + arg = NDIS_80211_AUTHMODE_WPANONE; + + if (n->ni_val == WPA_ASE_8021X_UNSPEC) + arg = NDIS_80211_AUTHMODE_WPA; + + if (n->ni_val == WPA_ASE_8021X_PSK) + arg = NDIS_80211_AUTHMODE_WPAPSK; + + i = sizeof(arg); + if (ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i)) + return(ENOTSUP); + i = sizeof(arg); + ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i); + + /* Now configure the desired ciphers. */ + + /* First, set up the multicast group cipher. */ + n = (struct ndis_ie *)&w->wpa_mcipher[0]; + + if (ndis_set_cipher(sc, n->ni_val)) + return(ENOTSUP); + + /* Now start looking around for the unicast ciphers. */ + pos = (char *)&w->wpa_uciphers[0]; + n = (struct ndis_ie *)pos; + + for (i = 0; i < w->wpa_uciphercnt; i++) { + if (ndis_set_cipher(sc, n->ni_val)) + return(ENOTSUP); + n++; + } + + return(0); +} +#endif + static void ndis_setstate_80211(sc) struct ndis_softc *sc; { struct ieee80211com *ic; ndis_80211_ssid ssid; + ndis_80211_macaddr bssid; ndis_80211_config config; ndis_80211_wep wep; int i, rval = 0, len; @@ -1837,6 +2176,12 @@ ndis_setstate_80211(sc) if (!NDIS_INITIALIZED(sc)) return; + /* Disassociate and turn off radio. */ + + len = sizeof(arg); + arg = 1; + ndis_set_info(sc, OID_802_11_DISASSOCIATE, &arg, &len); + /* Set network infrastructure mode. */ len = sizeof(arg); @@ -1850,25 +2195,83 @@ ndis_setstate_80211(sc) if (rval) device_printf (sc->ndis_dev, "set infra failed: %d\n", rval); + /* Set RTS threshold */ + + len = sizeof(arg); + arg = ic->ic_rtsthreshold; + ndis_set_info(sc, OID_802_11_RTS_THRESHOLD, &arg, &len); + + /* Set fragmentation threshold */ + + len = sizeof(arg); + arg = ic->ic_fragthreshold; + ndis_set_info(sc, OID_802_11_FRAGMENTATION_THRESHOLD, &arg, &len); + + /* Set power management */ + + len = sizeof(arg); + if (ic->ic_flags & IEEE80211_F_PMGTON) + arg = NDIS_80211_POWERMODE_FAST_PSP; + else + arg = NDIS_80211_POWERMODE_CAM; + ndis_set_info(sc, OID_802_11_POWER_MODE, &arg, &len); + + /* + * Default encryption mode to off, authentication + * to open and privacy to 'accept everything.' + */ + + len = sizeof(arg); + arg = NDIS_80211_WEPSTAT_DISABLED; + ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len); + + len = sizeof(arg); + arg = NDIS_80211_AUTHMODE_OPEN; + ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len); + + /* + * Note that OID_80211_PRIVACY_FILTER is optional: + * not all drivers implement it. + */ + len = sizeof(arg); + arg = NDIS_80211_PRIVFILT_8021XWEP; + ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len); + /* Set WEP */ -#ifdef IEEE80211_F_PRIVACY - if (ic->ic_flags & IEEE80211_F_PRIVACY) { +#if __FreeBSD_version < 600007 + if (ic->ic_flags & IEEE80211_F_WEPON) { #else - if (ic->ic_wep_mode >= IEEE80211_WEP_ON) { + if (ic->ic_flags & IEEE80211_F_PRIVACY && + !(ic->ic_flags & IEEE80211_F_WPA)) { #endif + int keys_set = 0; + for (i = 0; i < IEEE80211_WEP_NKID; i++) { if (ic->ic_nw_keys[i].wk_keylen) { +#if __FreeBSD_version >= 600007 + if (ic->ic_nw_keys[i].wk_cipher->ic_cipher != + IEEE80211_CIPHER_WEP) + continue; +#endif bzero((char *)&wep, sizeof(wep)); wep.nw_keylen = ic->ic_nw_keys[i].wk_keylen; -#ifdef notdef - /* 5 and 13 are the only valid key lengths */ + + /* + * 5, 13 and 16 are the only valid + * only valid key lengths. Anything + * in between will be zero padded out to + * the next highest boundary. + */ if (ic->ic_nw_keys[i].wk_keylen < 5) wep.nw_keylen = 5; else if (ic->ic_nw_keys[i].wk_keylen > 5 && ic->ic_nw_keys[i].wk_keylen < 13) wep.nw_keylen = 13; -#endif + else if (ic->ic_nw_keys[i].wk_keylen > 13 && + ic->ic_nw_keys[i].wk_keylen < 16) + wep.nw_keylen = 16; + wep.nw_keyidx = i; wep.nw_length = (sizeof(uint32_t) * 3) + wep.nw_keylen; @@ -1882,48 +2285,37 @@ ndis_setstate_80211(sc) if (rval) device_printf(sc->ndis_dev, "set wepkey failed: %d\n", rval); + keys_set++; } } - arg = NDIS_80211_WEPSTAT_ENABLED; - len = sizeof(arg); - rval = ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len); - if (rval) - device_printf(sc->ndis_dev, - "enable WEP failed: %d\n", rval); -#ifndef IEEE80211_F_WEPON -#if 0 - if (ic->ic_wep_mode != IEEE80211_WEP_8021X && - ic->ic_wep_mode != IEEE80211_WEP_ON) - arg = NDIS_80211_PRIVFILT_ACCEPTALL; - else -#endif -#endif - arg = NDIS_80211_PRIVFILT_8021XWEP; - len = sizeof(arg); - rval = ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len); -#ifdef IEEE80211_WEP_8021X /*IEEE80211_F_WEPON*/ - /* Accept that we only have "shared" and 802.1x modes. */ - if (rval == 0) { - if (arg == NDIS_80211_PRIVFILT_ACCEPTALL) - ic->ic_wep_mode = IEEE80211_WEP_MIXED; + if (keys_set) { + arg = NDIS_80211_WEPSTAT_ENABLED; + len = sizeof(arg); + rval = ndis_set_info(sc, + OID_802_11_WEP_STATUS, &arg, &len); + if (rval) + device_printf(sc->ndis_dev, + "enable WEP failed: %d\n", rval); +#ifdef IEEE80211_F_DROPUNENC + if (ic->ic_flags & IEEE80211_F_DROPUNENC) + arg = NDIS_80211_PRIVFILT_8021XWEP; else - ic->ic_wep_mode = IEEE80211_WEP_8021X; - } + arg = NDIS_80211_PRIVFILT_ACCEPTALL; + + len = sizeof(arg); + ndis_set_info(sc, + OID_802_11_PRIVACY_FILTER, &arg, &len); #endif - arg = NDIS_80211_AUTHMODE_OPEN; - } else { - arg = NDIS_80211_WEPSTAT_DISABLED; - len = sizeof(arg); - ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len); - arg = NDIS_80211_AUTHMODE_OPEN; - } + } + } - len = sizeof(arg); - rval = ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len); +#ifdef IEEE80211_F_WPA + /* Set up WPA. */ -#ifdef notyet - if (rval) - device_printf (sc->ndis_dev, "set auth failed: %d\n", rval); + if (ic->ic_flags & IEEE80211_F_WPA1 && ic->ic_opt_ie_len && + ic->ic_caps & IEEE80211_C_WPA) + if (ndis_set_wpa(sc)) + device_printf(sc->ndis_dev, "WPA setup failed\n"); #endif #ifdef notyet @@ -1966,13 +2358,13 @@ ndis_setstate_80211(sc) * Some drivers expect us to initialize these values, so * provide some defaults. */ + if (config.nc_beaconperiod == 0) config.nc_beaconperiod = 100; if (config.nc_atimwin == 0) config.nc_atimwin = 100; if (config.nc_fhconfig.ncf_dwelltime == 0) config.nc_fhconfig.ncf_dwelltime = 200; - if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) { int chan, chanflag; @@ -1998,6 +2390,32 @@ ndis_setstate_80211(sc) device_printf(sc->ndis_dev, "couldn't retrieve " "channel info: %d\n", rval); + /* + * If the user selected a specific BSSID, try + * to use that one. This is useful in the case where + * there are several APs in range with the same network + * name. To delete the BSSID, we use the broadcast + * address as the BSSID. + * Note that some drivers seem to allow setting a BSSID + * in ad-hoc mode, which has the effect of forcing the + * NIC to create an ad-hoc cell with a specific BSSID, + * instead of a randomly chosen one. However, the net80211 + * code makes the assumtion that the BSSID setting is invalid + * when you're in ad-hoc mode, so we don't allow that here. + */ + + len = IEEE80211_ADDR_LEN; + if (ic->ic_flags & IEEE80211_F_DESBSSID && + ic->ic_opmode != IEEE80211_M_IBSS) + bcopy(ic->ic_des_bssid, bssid, len); + else + bcopy(ifp->if_broadcastaddr, bssid, len); + + rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len); + if (rval) + device_printf(sc->ndis_dev, + "setting BSSID failed: %d\n", rval); + /* Set SSID -- always do this last. */ len = sizeof(ssid); @@ -2007,11 +2425,14 @@ ndis_setstate_80211(sc) ssid.ns_ssidlen = 1; } else bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen); + rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); if (rval) device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval); + ic->ic_state = IEEE80211_S_ASSOC; + return; } @@ -2060,9 +2481,11 @@ ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr) case IEEE80211_MODE_11G: imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G); break; +#ifdef IEEE80211_MODE_TURBO_A case IEEE80211_MODE_TURBO_A: imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A) | IFM_IEEE80211_TURBO; +#endif break; } } @@ -2267,6 +2690,9 @@ ndis_ioctl(ifp, command, data) { struct ndis_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; + struct ndis_oid_data oid; + struct ndis_evt evt; + void *oidbuf; int i, error = 0; /*NDIS_LOCK(sc);*/ @@ -2309,7 +2735,11 @@ ndis_ioctl(ifp, command, data) case SIOCGIFMEDIA: case SIOCSIFMEDIA: if (sc->ndis_80211) { +#if __FreeBSD_version < 600007 + error = ieee80211_ioctl(ifp, command, data); +#else error = ieee80211_ioctl(&sc->ic, command, data); +#endif if (error == ENETRESET) { ndis_setstate_80211(sc); /*ndis_init(sc);*/ @@ -2342,6 +2772,105 @@ ndis_ioctl(ifp, command, data) else error = ENOTTY; break; + case SIOCGDRVSPEC: + if ((error = suser(curthread))) + break; + error = copyin(ifr->ifr_data, &oid, sizeof(oid)); + if (error) + break; + oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO); + if (oidbuf == NULL) { + error = ENOMEM; + break; + } + error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = ndis_get_info(sc, oid.oid, oidbuf, &oid.len); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = copyout(&oid, ifr->ifr_data, sizeof(oid)); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len); + free(oidbuf, M_TEMP); + break; + case SIOCSDRVSPEC: + if ((error = suser(curthread))) + break; + error = copyin(ifr->ifr_data, &oid, sizeof(oid)); + if (error) + break; + oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO); + if (oidbuf == NULL) { + error = ENOMEM; + break; + } + error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = ndis_set_info(sc, oid.oid, oidbuf, &oid.len); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = copyout(&oid, ifr->ifr_data, sizeof(oid)); + if (error) { + free(oidbuf, M_TEMP); + break; + } + error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len); + free(oidbuf, M_TEMP); + break; + case SIOCGPRIVATE_0: + if ((error = suser(curthread))) + break; + NDIS_LOCK(sc); + if (sc->ndis_evt[sc->ndis_evtcidx].ne_sts == 0) { + error = ENOENT; + NDIS_UNLOCK(sc); + break; + } + error = copyin(ifr->ifr_data, &evt, sizeof(evt)); + if (error) { + NDIS_UNLOCK(sc); + break; + } + if (evt.ne_len < sc->ndis_evt[sc->ndis_evtcidx].ne_len) { + error = ENOSPC; + NDIS_UNLOCK(sc); + break; + } + error = copyout(&sc->ndis_evt[sc->ndis_evtcidx], + ifr->ifr_data, sizeof(uint32_t) * 2); + if (error) { + NDIS_UNLOCK(sc); + break; + } + if (sc->ndis_evt[sc->ndis_evtcidx].ne_len) { + error = copyout(sc->ndis_evt[sc->ndis_evtcidx].ne_buf, + ifr->ifr_data + (sizeof(uint32_t) * 2), + sc->ndis_evt[sc->ndis_evtcidx].ne_len); + if (error) { + NDIS_UNLOCK(sc); + break; + } + free(sc->ndis_evt[sc->ndis_evtcidx].ne_buf, M_TEMP); + sc->ndis_evt[sc->ndis_evtcidx].ne_buf = NULL; + } + sc->ndis_evt[sc->ndis_evtcidx].ne_len = 0; + sc->ndis_evt[sc->ndis_evtcidx].ne_sts = 0; + NDIS_EVTINC(sc->ndis_evtcidx); + NDIS_UNLOCK(sc); + break; case SIOCGIFGENERIC: case SIOCSIFGENERIC: if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) { @@ -2357,7 +2886,11 @@ ndis_ioctl(ifp, command, data) do_80211: sc->ndis_skip = 1; if (sc->ndis_80211) { +#if __FreeBSD_version < 600007 + error = ieee80211_ioctl(ifp, command, data); +#else error = ieee80211_ioctl(&sc->ic, command, data); +#endif if (error == ENETRESET) { ndis_setstate_80211(sc); error = 0; @@ -2404,7 +2937,7 @@ ndis_wi_ioctl_get(ifp, command, data) error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len); if (error != ENOSPC) break; - bl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO); + bl = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO); error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len); if (error) { free(bl, M_DEVBUF); @@ -2496,68 +3029,61 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data) { struct ndis_softc *sc; struct ieee80211req *ireq; +#ifdef RTM_IEEE80211_SCAN ndis_80211_bssid_list_ex *bl; - ndis_80211_ssid ssid; - ndis_80211_macaddr bssid; ndis_wlan_bssid_ex *wb; struct ieee80211req_scan_result *sr, *bsr; - int error, len, i, j; + int i, j; char *cp; - uint8_t nodename[IEEE80211_NWID_LEN]; +#endif + int error, len; uint16_t nodename_u[IEEE80211_NWID_LEN + 1]; - char *acode; + unicode_string us; + ansi_string as; sc = ifp->if_softc; ireq = (struct ieee80211req *) data; - + switch (ireq->i_type) { +#ifdef IEEE80211_IOC_MLME case IEEE80211_IOC_MLME: error = 0; break; - case IEEE80211_IOC_BSSID: - len = sizeof(bssid); - bzero((char*)&bssid, len); - error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len); - if (error) { - device_printf(sc->ndis_dev, "failed to get bssid\n"); - return(error); - } - ireq->i_len = len; - error = copyout(&bssid, ireq->i_data, len); - break; - case IEEE80211_IOC_SSID: - len = sizeof(ssid); - bzero((char*)&ssid, len); - error = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len); - if (error) { - device_printf(sc->ndis_dev, "failed to get ssid: %d\n", error); - return(error); - } - ireq->i_len = ssid.ns_ssidlen; - error = copyout(&ssid.ns_ssid, ireq->i_data, ssid.ns_ssidlen); - break; +#endif +#ifdef RTM_IEEE80211_SCAN case IEEE80211_IOC_SCAN_RESULTS: len = 0; error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len); if (error != ENOSPC) break; - bl = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); + bl = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len); if (error) { free(bl, M_DEVBUF); break; } - sr = bsr = malloc(ireq->i_len, M_DEVBUF, M_WAITOK | M_ZERO); - wb = bl->nblx_bssid; + sr = bsr = malloc(ireq->i_len, M_DEVBUF, M_NOWAIT | M_ZERO); + wb = &bl->nblx_bssid[0]; len = 0; for (i = 0; i < bl->nblx_items; i++) { /* - * Check if we have enough space left for this ap + * Check if we have enough space left for this ap. + * Note that the size of the SSID list structure + * can vary: the extended structure with info + * elements is only supported by NDIS 5.1 drivers. */ - j = roundup(sizeof(*sr) + wb->nwbx_ssid.ns_ssidlen - + wb->nwbx_ielen - - sizeof(struct ndis_80211_fixed_ies), - sizeof(uint32_t)); + if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) { + j = roundup(sizeof(*sr) + + wb->nwbx_ssid.ns_ssidlen + + wb->nwbx_ielen - + sizeof(struct ndis_80211_fixed_ies), + sizeof(uint32_t)); + } else { + j = roundup(sizeof(*sr) + + wb->nwbx_ssid.ns_ssidlen + + sizeof(struct ndis_80211_fixed_ies), + sizeof(uint32_t)); + } if (len + j > ireq->i_len) break; bcopy(&wb->nwbx_macaddr, &sr->isr_bssid, @@ -2587,11 +3113,13 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data) cp = (char *)sr + sizeof(*sr); bcopy(&wb->nwbx_ssid.ns_ssid, cp, sr->isr_ssid_len); cp += sr->isr_ssid_len; - sr->isr_ie_len = wb->nwbx_ielen - - sizeof(struct ndis_80211_fixed_ies); - bcopy((char *)wb->nwbx_ies + - sizeof(struct ndis_80211_fixed_ies), - cp, sr->isr_ie_len); + if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) { + sr->isr_ie_len = wb->nwbx_ielen + - sizeof(struct ndis_80211_fixed_ies); + bcopy((char *)wb->nwbx_ies + + sizeof(struct ndis_80211_fixed_ies), + cp, sr->isr_ie_len); + } sr->isr_len = roundup(sizeof(*sr) + sr->isr_ssid_len + sr->isr_ie_len, sizeof(uint32_t)); len += sr->isr_len; @@ -2604,318 +3132,172 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data) free(bl, M_DEVBUF); free(bsr, M_DEVBUF); break; +#endif case IEEE80211_IOC_STATIONNAME: error = ndis_get_info(sc, OID_GEN_MACHINE_NAME, &nodename_u, &len); if (error) break; - acode = nodename; - bzero((char *)nodename, IEEE80211_NWID_LEN); - ndis_unicode_to_ascii(nodename_u, len, &acode); - ireq->i_len = len / 2 + 1; - error = copyout(acode, ireq->i_data, ireq->i_len); + us.us_len = us.us_maxlen = len; + us.us_buf = nodename_u; + if (RtlUnicodeStringToAnsiString(&as, &us, TRUE)) { + error = ENOMEM; + break; + } + ireq->i_len = as.as_len; + error = copyout(as.as_buf, ireq->i_data, ireq->i_len); + RtlFreeAnsiString(&as); break; default: +#if __FreeBSD_version < 600007 + error = ieee80211_ioctl(ifp, command, data); +#else error = ieee80211_ioctl(&sc->ic, command, data); +#endif + break; } return(error); } -static int -ndis_add_key(sc, wk, i_len) - struct ndis_softc *sc; - struct ieee80211req_key *wk; - int16_t i_len; +#ifdef IEEE80211_F_WPA +int +ndis_del_key(ic, key) + struct ieee80211com *ic; + const struct ieee80211_key *key; { - ndis_80211_key *rkey; - ndis_80211_wep *wep; - int len, error; - uint32_t arg; + struct ndis_softc *sc; + ndis_80211_key rkey; + int len, error = 0; - /* infrastructure mode only supported for now */ - len = sizeof(arg); - arg = NDIS_80211_NET_INFRA_BSS; - error = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len); - if (error) { - device_printf(sc->ndis_dev, - "setting infrastructure mode failed\n"); - return(error); - } + sc = ic->ic_ifp->if_softc; - switch(wk->ik_type) { - case IEEE80211_CIPHER_WEP: - len = 12 + wk->ik_keylen; - wep = malloc(len, M_TEMP, M_WAITOK | M_ZERO); - if(!wep) - return(ENOSPC); - wep->nw_length = len; - wep->nw_keyidx = wk->ik_keyix; - wep->nw_keylen = wk->ik_keylen; - if(wk->ik_flags & IEEE80211_KEY_XMIT) - wep->nw_keyidx |= 1 << 31; - device_printf(sc->ndis_dev, "setting wep key\n"); - error = copyin(wk->ik_keydata, wep->nw_keydata, wk->ik_keylen); - if(error) { - device_printf(sc->ndis_dev, - "copyin of wep key to kernel space failed\n"); - free(wep, M_TEMP); - break; - } - error = ndis_set_info(sc, OID_802_11_ADD_WEP, wep, &len); - if(error) { - device_printf(sc->ndis_dev, - "setting wep key failed\n"); - break; - } - free(wep, M_TEMP); + bzero((char *)&rkey, sizeof(rkey)); + len = sizeof(rkey); - /* set the authentication mode */ + rkey.nk_len = len; + rkey.nk_keyidx = key->wk_keyix; - arg = NDIS_80211_AUTHMODE_OPEN; - error = ndis_set_info(sc, - OID_802_11_AUTHENTICATION_MODE, &arg, &len); - if(error) { - device_printf(sc->ndis_dev, - "setting authentication mode failed\n"); - } + bcopy(ic->ic_ifp->if_broadcastaddr, + rkey.nk_bssid, IEEE80211_ADDR_LEN); - /* set the encryption */ + error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len); - len = sizeof(arg); - arg = NDIS_80211_WEPSTAT_ENABLED; - error = ndis_set_info(sc, - OID_802_11_ENCRYPTION_STATUS, &arg, &len); - if(error) { - device_printf(sc->ndis_dev, - "setting encryption status failed\n"); - return(error); - } - break; + if (error) + return(0); + + return(1); +} + +/* + * In theory this could be called for any key, but we'll + * only use it for WPA TKIP or AES keys. These need to be + * set after initial authentication with the AP. + */ + +static int +ndis_add_key(ic, key, mac) + struct ieee80211com *ic; + const struct ieee80211_key *key; + const uint8_t mac[IEEE80211_ADDR_LEN]; +{ + struct ndis_softc *sc; + ndis_80211_key rkey; + int len, error = 0; + + sc = ic->ic_ifp->if_softc; + + switch (key->wk_cipher->ic_cipher) { case IEEE80211_CIPHER_TKIP: - len = 12 + 6 + 6 + 8 + wk->ik_keylen; - rkey = malloc(len, M_TEMP, M_WAITOK | M_ZERO); - if(!rkey) - return(ENOSPC); - rkey->nk_len = len; - error = copyin(wk->ik_macaddr, - rkey->nk_bssid, IEEE80211_ADDR_LEN); - if(error) { - device_printf(sc->ndis_dev, - "copyin of bssid to kernel space failed\n"); - free(rkey, M_TEMP); - break; - } - /* keyrsc needs to be fixed: need to do some shifting */ - error = copyin(&(wk->ik_keyrsc), - &(rkey->nk_keyrsc), sizeof(rkey->nk_keyrsc)); - if(error) { - device_printf(sc->ndis_dev, - "copyin of keyrsc to kernel space failed\n"); - free(rkey, M_TEMP); - break; - } + len = sizeof(ndis_80211_key); + bzero((char *)&rkey, sizeof(rkey)); + + rkey.nk_len = len; + rkey.nk_keylen = key->wk_keylen; + + if (key->wk_flags & IEEE80211_KEY_SWMIC) + rkey.nk_keylen += 16; /* key index - gets weird in NDIS */ - rkey->nk_keyidx = wk->ik_keyix; - if(wk->ik_flags & IEEE80211_KEY_XMIT) - rkey->nk_keyidx |= 1 << 31; - if((bcmp(rkey->nk_bssid, "\xff\xff\xff\xff\xff\xff", - IEEE80211_ADDR_LEN) == 0) || - (bcmp(rkey->nk_bssid, "\x0\x0\x0\x0\x0\x0", - IEEE80211_ADDR_LEN) == 0)) { - /* group key - nothing to do in ndis */ + if (key->wk_keyix != IEEE80211_KEYIX_NONE) + rkey.nk_keyidx = key->wk_keyix; + else + rkey.nk_keyidx = 0; + + if (key->wk_flags & IEEE80211_KEY_XMIT) + rkey.nk_keyidx |= 1 << 31; + + if (key->wk_flags & IEEE80211_KEY_GROUP) { + bcopy(ic->ic_ifp->if_broadcastaddr, + rkey.nk_bssid, IEEE80211_ADDR_LEN); } else { + bcopy(ic->ic_bss->ni_bssid, + rkey.nk_bssid, IEEE80211_ADDR_LEN); /* pairwise key */ - rkey->nk_keyidx |= 1 << 30; + rkey.nk_keyidx |= 1 << 30; } /* need to set bit 29 based on keyrsc */ + rkey.nk_keyrsc = key->wk_keyrsc; - rkey->nk_keylen = wk->ik_keylen; - if (wk->ik_type == IEEE80211_CIPHER_TKIP && - wk->ik_keylen == 32) { - /* - * key data needs to be offset by 4 due - * to mismatch between NDIS spec and BSD?? - */ - error = copyin(wk->ik_keydata, - rkey->nk_keydata + 4, 16); - if(error) { - device_printf(sc->ndis_dev, "copyin of " - "keydata(0) to kernel space failed\n"); - free(rkey, M_TEMP); - break; - } - error = copyin(wk->ik_keydata + 24, - rkey->nk_keydata + 20, 8); - if(error) { - device_printf(sc->ndis_dev, "copyin of " - "keydata(1) to kernel space failed\n"); - free(rkey, M_TEMP); - break; - } - error = copyin(wk->ik_keydata + 16, - rkey->nk_keydata + 28, 8); - if(error) { - device_printf(sc->ndis_dev, "copyin of " - "keydata(2) to kernel space failed\n"); - free(rkey, M_TEMP); - break; - } - } else { - error = copyin(wk->ik_keydata, - rkey->nk_keydata + 4, wk->ik_keylen); - if(error) { - device_printf(sc->ndis_dev, "copyin of " - "keydata(CCMP) to kernel space failed\n"); - free(rkey, M_TEMP); - break; - } - } - error = ndis_set_info(sc, OID_802_11_ADD_KEY, rkey, &len); + if (rkey.nk_keyrsc) + rkey.nk_keyidx |= 1 << 29; + + if (key->wk_flags & IEEE80211_KEY_SWMIC) { + bcopy(key->wk_key, rkey.nk_keydata, 16); + bcopy(key->wk_key + 24, rkey.nk_keydata + 16, 8); + bcopy(key->wk_key + 16, rkey.nk_keydata + 24, 8); + } else + bcopy(key->wk_key, rkey.nk_keydata, key->wk_keylen); + + error = ndis_set_info(sc, OID_802_11_ADD_KEY, &rkey, &len); + break; + case IEEE80211_CIPHER_WEP: + error = 0; break; + /* + * I don't know how to set up keys for the AES + * cipher yet. Is it the same as TKIP? + */ case IEEE80211_CIPHER_AES_CCM: - return(ENOTTY); default: - return(ENOTTY); + error = ENOTTY; + break; } - return(error); + + /* We need to return 1 for success, 0 for failure. */ + + if (error) + return(0); + + return (1); } +#endif static int ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data) { struct ndis_softc *sc; struct ieee80211req *ireq; - int error, len, arg, ucnt; - uint8_t nodename[IEEE80211_NWID_LEN]; - uint16_t nodename_u[IEEE80211_NWID_LEN + 1]; - uint16_t *ucode; - struct ieee80211req_del_key *rk; - struct ieee80211req_key *wk; - unsigned char *wpa_ie; - ndis_80211_ssid ssid; - ndis_80211_remove_key rkey; + int error = EINVAL, len; + ansi_string as; + unicode_string us; sc = ifp->if_softc; ireq = (struct ieee80211req *) data; - + switch (ireq->i_type) { +#ifdef IEEE80211_IOC_MLME case IEEE80211_IOC_MLME: case IEEE80211_IOC_ROAMING: case IEEE80211_IOC_COUNTERMEASURES: case IEEE80211_IOC_DROPUNENCRYPTED: error = 0; break; - case IEEE80211_IOC_PRIVACY: - len = sizeof(arg); - arg = NDIS_80211_PRIVFILT_8021XWEP; - error = ndis_set_info(sc, - OID_802_11_PRIVACY_FILTER, &arg, &len); - if (error) { - device_printf(sc->ndis_dev, - "setting wep privacy filter failed\n"); - error = 0; - } - break; - case IEEE80211_IOC_WPA: - /* nothing to do */ - error = 0; - break; - case IEEE80211_IOC_OPTIE: - wpa_ie = (char*)ireq->i_data; - if (ireq->i_len < 14 || !wpa_ie) { - /* cannot figure out anything */ - arg = NDIS_80211_AUTHMODE_OPEN; - error = ndis_set_info(sc, - OID_802_11_AUTHENTICATION_MODE, &arg, &len); - return(error); - } - if (wpa_ie[0] == IEEE80211_ELEMID_RSN) { - error = ENOTTY; - break; - } else if (wpa_ie[0] == IEEE80211_ELEMID_VENDOR) { - - /* set the encryption based on multicast cipher */ - - if (!memcmp(wpa_ie + 8, "\x00\x50\xf2\x02", 4)) { - len = sizeof(arg); - arg = NDIS_80211_WEPSTAT_ENC2ENABLED; - error = ndis_set_info(sc, - OID_802_11_ENCRYPTION_STATUS, &arg, &len); - if (error) { - device_printf(sc->ndis_dev, "setting " - "encryption status to " - "ENC2 failed\n"); - /* continue anyway */ - } - } - } - - /* set the authentication mode */ - - ucnt = wpa_ie[12] + 256* wpa_ie[13]; - - /* 4 bytes per unicast cipher */ - - ucnt = 14 + 4*ucnt + 2; /* account for number of authsels */ - - if (ireq->i_len < ucnt) { - arg = NDIS_80211_AUTHMODE_WPANONE; - } else { - if (!memcmp((void*)(&wpa_ie[ucnt]), - "\x00\x50\xf2\x02", 4)) { - arg = NDIS_80211_AUTHMODE_WPAPSK; - } else if (!memcmp((void*)(&wpa_ie[ucnt]), - "\x00\x50\xf2\x01", 4)) { - arg = NDIS_80211_AUTHMODE_WPA; - } else { - arg = NDIS_80211_AUTHMODE_WPANONE; - } - } - len = sizeof(arg); - error = ndis_set_info(sc, - OID_802_11_AUTHENTICATION_MODE, &arg, &len); - if (error) { - device_printf(sc->ndis_dev, - "setting authentication mode to WPA-PSK failed\n"); - break; - } - break; - case IEEE80211_IOC_SSID: - len = sizeof(ssid); - bzero((char*)&ssid, len); - ssid.ns_ssidlen = ireq->i_len; - error = copyin(ireq->i_data, &(ssid.ns_ssid), ireq->i_len); - if (error) - break; - error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); - if (error) { - device_printf(sc->ndis_dev, - "setting SSID to %s\n", ssid.ns_ssid); - } - break; - case IEEE80211_IOC_DELKEY: - len = sizeof(rkey); - bzero((char*)&rkey, len); - rk = (struct ieee80211req_del_key*)ireq->i_data; - rkey.nk_len = len; - rkey.nk_keyidx = rk->idk_keyix; - error = copyin(rk->idk_macaddr, - &(rkey.nk_bssid), sizeof(ndis_80211_macaddr)); - if (error) - break; - error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len); - if (error) - device_printf(sc->ndis_dev, "deleting key\n"); - break; - case IEEE80211_IOC_WPAKEY: - wk = (struct ieee80211req_key*)ireq->i_data; - error = ndis_add_key(sc, wk, ireq->i_len); - break; +#endif +#ifdef RTM_IEEE80211_SCAN case IEEE80211_IOC_SCAN_REQ: len = 0; error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, @@ -2923,6 +3305,7 @@ ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data) tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2); rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); break; +#endif case IEEE80211_IOC_STATIONNAME: error = suser(curthread); if (error) @@ -2932,18 +3315,23 @@ ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data) error = EINVAL; break; } - bzero((char *)nodename, IEEE80211_NWID_LEN); - error = copyin(ireq->i_data, nodename, ireq->i_len); - if (error) + as.as_len = as.as_maxlen = ireq->i_len; + as.as_buf = ireq->i_data; + if (RtlAnsiStringToUnicodeString(&us, &as, TRUE)) { + error = ENOMEM; break; - ucode = nodename_u; - ndis_ascii_to_unicode((char *)nodename, &ucode); - len = ireq->i_len * 2; + } + len = us.us_len; error = ndis_set_info(sc, OID_GEN_MACHINE_NAME, - &nodename_u, &len); + us.us_buf, &len); + RtlFreeUnicodeString(&us); break; default: +#if __FreeBSD_version < 600007 + error = ieee80211_ioctl(ifp, command, data); +#else error = ieee80211_ioctl(&sc->ic, command, data); +#endif if (error == ENETRESET) { ndis_setstate_80211(sc); error = 0; @@ -2954,8 +3342,8 @@ ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data) } static void -ndis_resettask(w, arg) - ndis_work_item *w; +ndis_resettask(d, arg) + device_object *d; void *arg; { struct ndis_softc *sc; @@ -2978,8 +3366,12 @@ ndis_watchdog(ifp) device_printf(sc->ndis_dev, "watchdog timeout\n"); NDIS_UNLOCK(sc); - NdisScheduleWorkItem(&sc->ndis_resetitem); - NdisScheduleWorkItem(&sc->ndis_startitem); + IoQueueWorkItem(sc->ndis_resetitem, + (io_workitem_func)ndis_resettask_wrap, + WORKQUEUE_CRITICAL, sc); + IoQueueWorkItem(sc->ndis_startitem, + (io_workitem_func)ndis_starttask_wrap, + WORKQUEUE_CRITICAL, ifp); return; } @@ -2993,6 +3385,12 @@ ndis_stop(sc) struct ndis_softc *sc; { struct ifnet *ifp; + struct ieee80211com *ic; + int i; + + ic = &sc->ic; + if (sc->ndis_80211) + ic->ic_state = IEEE80211_S_INIT; ifp = sc->ifp; untimeout(ndis_tick, sc, sc->ndis_stat_ch); @@ -3005,6 +3403,17 @@ ndis_stop(sc) ndis_halt_nic(sc); + NDIS_LOCK(sc); + for (i = 0; i < NDIS_EVENTS; i++) { + if (sc->ndis_evt[i].ne_sts && sc->ndis_evt[i].ne_buf != NULL) + free(sc->ndis_evt[i].ne_buf, M_TEMP); + sc->ndis_evt[i].ne_sts = 0; + sc->ndis_evt[i].ne_len = 0; + } + sc->ndis_evtcidx = 0; + sc->ndis_evtpidx = 0; + NDIS_UNLOCK(sc); + return; } diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h index 5e28b7d3979e..13d517cf3075 100644 --- a/sys/dev/if_ndis/if_ndisvar.h +++ b/sys/dev/if_ndis/if_ndisvar.h @@ -35,6 +35,16 @@ #define NDIS_DEFAULT_NODENAME "FreeBSD NDIS node" #define NDIS_NODENAME_LEN 32 +/* For setting/getting OIDs from userspace. */ + +struct ndis_oid_data { + uint32_t oid; + uint32_t len; +#ifdef notdef + uint8_t data[1]; +#endif +}; + struct ndis_pci_type { uint16_t ndis_vid; uint16_t ndis_did; @@ -49,28 +59,52 @@ struct ndis_pccard_type { }; struct ndis_shmem { + list_entry ndis_list; bus_dma_tag_t ndis_stag; bus_dmamap_t ndis_smap; void *ndis_saddr; ndis_physaddr ndis_paddr; - struct ndis_shmem *ndis_next; }; struct ndis_cfglist { ndis_cfg ndis_cfg; + struct sysctl_oid *ndis_oid; TAILQ_ENTRY(ndis_cfglist) link; }; +/* + * Helper struct to make parsing information + * elements easier. + */ +struct ndis_ie { + uint8_t ni_oui[3]; + uint8_t ni_val; +}; + TAILQ_HEAD(nch, ndis_cfglist); -#define NDIS_INITIALIZED(sc) (sc->ndis_block->nmb_miniportadapterctx != NULL) +#define NDIS_INITIALIZED(sc) (sc->ndis_block->nmb_devicectx != NULL) +#define NDIS_TXPKTS 64 #define NDIS_INC(x) \ - (x)->ndis_txidx = ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts + (x)->ndis_txidx = ((x)->ndis_txidx + 1) % NDIS_TXPKTS + +#if __FreeBSD_version < 600007 +#define arpcom ic.ic_ac +#endif + +#define NDIS_EVENTS 4 +#define NDIS_EVTINC(x) (x) = ((x) + 1) % NDIS_EVENTS + +struct ndis_evt { + uint32_t ne_sts; + uint32_t ne_len; + char *ne_buf; +}; struct ndis_softc { - struct ifnet *ifp; struct ieee80211com ic; /* interface info */ + struct ifnet *ifp; struct ifmedia ifmedia; /* media info */ u_long ndis_hwassist; uint32_t ndis_v4tx; @@ -91,7 +125,8 @@ struct ndis_softc { struct resource *ndis_res_cm; /* common mem (pccard) */ struct resource_list ndis_rl; int ndis_rescnt; - struct mtx ndis_mtx; + kspin_lock ndis_spinlock; + uint8_t ndis_irql; device_t ndis_dev; int ndis_unit; ndis_miniport_block *ndis_block; @@ -110,6 +145,7 @@ struct ndis_softc { struct nch ndis_cfglist_head; int ndis_80211; int ndis_link; + uint32_t ndis_sts; uint32_t ndis_filter; int ndis_if_flags; int ndis_skip; @@ -121,18 +157,53 @@ struct ndis_softc { int ndis_devidx; interface_type ndis_iftype; driver_object *ndis_dobj; - ndis_work_item ndis_tickitem; - ndis_work_item ndis_startitem; - ndis_work_item ndis_resetitem; + io_workitem *ndis_tickitem; + io_workitem *ndis_startitem; + io_workitem *ndis_resetitem; + io_workitem *ndis_inputitem; kdpc ndis_rxdpc; bus_dma_tag_t ndis_parent_tag; - struct ndis_shmem *ndis_shlist; + list_entry ndis_shlist; bus_dma_tag_t ndis_mtag; bus_dma_tag_t ndis_ttag; bus_dmamap_t *ndis_mmaps; bus_dmamap_t *ndis_tmaps; int ndis_mmapcnt; + struct ndis_evt ndis_evt[NDIS_EVENTS]; + int ndis_evtpidx; + int ndis_evtcidx; + struct ifqueue ndis_rxqueue; + kspin_lock ndis_rxlock; }; -#define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx) -#define NDIS_UNLOCK(_sc) mtx_unlock(&(_sc)->ndis_mtx) +#define NDIS_LOCK(_sc) KeAcquireSpinLock(&(_sc)->ndis_spinlock, \ + &(_sc)->ndis_irql); +#define NDIS_UNLOCK(_sc) KeReleaseSpinLock(&(_sc)->ndis_spinlock, \ + (_sc)->ndis_irql); + +/* + * Backwards compatibility defines. + */ + +#ifndef IF_ADDR_LOCK +#define IF_ADDR_LOCK(x) +#define IF_ADDR_UNLOCK(x) +#endif + +#ifndef IFF_DRV_OACTIVE +#define IFF_DRV_OACTIVE IFF_OACTIVE +#define IFF_DRV_RUNNING IFF_RUNNING +#define if_drv_flags if_flags +#endif + +#ifndef ic_def_txkey +#define ic_def_txkey ic_wep_txkey +#define wk_keylen wk_len +#endif + +#ifndef SIOCGDRVSPEC +#define SIOCSDRVSPEC _IOW('i', 123, struct ifreq) /* set driver-specific + parameters */ +#define SIOCGDRVSPEC _IOWR('i', 123, struct ifreq) /* get driver-specific + parameters */ +#endif |
