diff options
author | wpaul <wpaul@FreeBSD.org> | 2004-01-12 03:49:20 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2004-01-12 03:49:20 +0000 |
commit | fcdf650572f5a3a8136abc088d10d11b87cfee2b (patch) | |
tree | 847703543f24b8e7621f9bdd8cf9093494b1fdca | |
parent | 29386da0d731180d9c11f2a1d73c3dec930c14c6 (diff) | |
download | FreeBSD-src-fcdf650572f5a3a8136abc088d10d11b87cfee2b.zip FreeBSD-src-fcdf650572f5a3a8136abc088d10d11b87cfee2b.tar.gz |
Merge in some changes submitted by Brian Feldman. Among other things,
these add support for listing BSSIDs via wicontrol -l. I added code
to call OID_802_11_BSSID_LIST_SCAN to allow scanning for any nearby
wirelsss nets.
Convert from using individual mutexes to a mutex pool, created in
subr_ndis.c. This deals with the problem of drivers creating locks
in their DriverEntry() routines which might get trashed later.
Put some messages under IFF_DEBUG.
-rw-r--r-- | sys/compat/ndis/kern_ndis.c | 9 | ||||
-rw-r--r-- | sys/compat/ndis/ndis_var.h | 2 | ||||
-rw-r--r-- | sys/compat/ndis/subr_hal.c | 6 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ndis.c | 77 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ntoskrnl.c | 49 | ||||
-rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 621 | ||||
-rw-r--r-- | sys/dev/if_ndis/if_ndisvar.h | 8 |
7 files changed, 547 insertions, 225 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c index f138439..39a8be4 100644 --- a/sys/compat/ndis/kern_ndis.c +++ b/sys/compat/ndis/kern_ndis.c @@ -151,7 +151,8 @@ ndis_status_func(adapter, status, sbuf, slen) ndis_miniport_block *block; block = adapter; - device_printf (block->nmb_dev, "status: %x\n", status); + if (block->nmb_ifp->if_flags & IFF_DEBUG) + device_printf (block->nmb_dev, "status: %x\n", status); return; } @@ -162,7 +163,8 @@ ndis_statusdone_func(adapter) ndis_miniport_block *block; block = adapter; - device_printf (block->nmb_dev, "status complete\n"); + if (block->nmb_ifp->if_flags & IFF_DEBUG) + device_printf (block->nmb_dev, "status complete\n"); return; } @@ -201,7 +203,8 @@ ndis_resetdone_func(adapter, status, addressingreset) ndis_miniport_block *block; block = adapter; - device_printf (block->nmb_dev, "reset done...\n"); + if (block->nmb_ifp->if_flags & IFF_DEBUG) + device_printf (block->nmb_dev, "reset done...\n"); return; } diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h index a0bb5d0..48432c0 100644 --- a/sys/compat/ndis/ndis_var.h +++ b/sys/compat/ndis/ndis_var.h @@ -443,7 +443,7 @@ typedef struct ndis_wlan_bssid_ex ndis_wlan_bssid_ex; struct ndis_80211_bssid_list_ex { uint32_t nblx_items; - ndis_wlan_bssid nblx_bssid[1]; + ndis_wlan_bssid_ex nblx_bssid[1]; }; typedef struct ndis_80211_bssid_list_ex ndis_80211_bssid_list_ex; diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c index cc51c0a..6d9e0c0 100644 --- a/sys/compat/ndis/subr_hal.c +++ b/sys/compat/ndis/subr_hal.c @@ -82,6 +82,8 @@ __stdcall static void hal_unlock(/*kspin_lock *, uint8_t*/void); __stdcall static uint8_t hal_irql(void); __stdcall static void dummy (void); +extern struct mtx_pool *ndis_mtxpool; + __stdcall static void hal_stall_exec_cpu(usecs) uint32_t usecs; @@ -211,7 +213,7 @@ hal_lock(/*lock*/void) __asm__ __volatile__ ("" : "=c" (lock)); - mtx_lock((struct mtx *)*lock); + mtx_pool_lock(ndis_mtxpool, (struct mtx *)*lock); return(0); } @@ -223,7 +225,7 @@ hal_unlock(/*lock, newirql*/void) __asm__ __volatile__ ("" : "=c" (lock), "=d" (newiqrl)); - mtx_unlock((struct mtx *)*lock); + mtx_pool_unlock(ndis_mtxpool, (struct mtx *)*lock); return; } diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c index 4dca682..429be6f 100644 --- a/sys/compat/ndis/subr_ndis.c +++ b/sys/compat/ndis/subr_ndis.c @@ -103,8 +103,9 @@ __FBSDID("$FreeBSD$"); #define __stdcall __attribute__((__stdcall__)) #define FUNC void(*)(void) -static struct mtx ndis_interlock; +static struct mtx *ndis_interlock; static char ndis_filepath[MAXPATHLEN]; +struct mtx_pool *ndis_mtxpool; SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath, MAXPATHLEN, "Path used by NdisOpenFile() to search for files"); @@ -278,17 +279,17 @@ __stdcall static void dummy(void); int ndis_libinit() { - mtx_init(&ndis_interlock, "ndislock", MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE | MTX_DUPOK); strcpy(ndis_filepath, "/compat/ndis"); - + ndis_mtxpool = mtx_pool_create("ndis mutex pool", + 1024, MTX_DEF | MTX_RECURSE | MTX_DUPOK);; + ndis_interlock = mtx_pool_alloc(ndis_mtxpool); return(0); } int ndis_libfini() { - mtx_destroy(&ndis_interlock); + mtx_pool_destroy(&ndis_mtxpool); return(0); } @@ -678,15 +679,7 @@ __stdcall static void ndis_create_lock(lock) ndis_spin_lock *lock; { - struct mtx *mtx; - - mtx = malloc(sizeof(struct mtx), M_DEVBUF, M_NOWAIT|M_ZERO); - if (mtx == NULL) - return; - mtx_init(mtx, "ndislock", "ndis spin lock", - MTX_DEF | MTX_RECURSE | MTX_DUPOK); - lock->nsl_spinlock = (ndis_kspin_lock)mtx; - + lock->nsl_spinlock = (ndis_kspin_lock)mtx_pool_alloc(ndis_mtxpool); return; } @@ -694,13 +687,7 @@ __stdcall static void ndis_destroy_lock(lock) ndis_spin_lock *lock; { - struct mtx *ndis_mtx; - - ndis_mtx = (struct mtx *)lock->nsl_spinlock; - mtx_destroy(ndis_mtx); - free(ndis_mtx, M_DEVBUF); - lock->nsl_spinlock = 0xdeadf00d; /* XXX */ - + /* We use a mutex pool, so this is a no-op. */ return; } @@ -708,32 +695,7 @@ __stdcall static void ndis_lock(lock) ndis_spin_lock *lock; { - if (lock == NULL) - return; - /* - * Workaround for certain broken NDIS drivers. I have - * encountered one case where a driver creates a spinlock - * within its DriverEntry() routine, which is then destroyed - * in its MiniportHalt() routine. This is a bug, because - * MiniportHalt() is meant to only destroy what MiniportInit() - * creates. This leads to the following problem: - * DriverEntry() <- spinlock created - * MiniportInit() <- NIC initialized - * MiniportHalt() <- NIC halted, spinlock destroyed - * MiniportInit() <- NIC initialized, spinlock not recreated - * NdisAcquireSpinLock(boguslock) <- panic - * To work around this, we poison the spinlock on destroy, and - * if we try to re-acquire the poison pill^Wspinlock, we init - * it again so subsequent calls will work. - * - * Drivers that behave in this way are likely not officially - * certified by Microsoft, since their I would expect the - * Microsoft NDIS test tool to catch mistakes like this. - */ - if (lock->nsl_spinlock == 0xdeadf00d) - ndis_create_lock(lock); - mtx_lock((struct mtx *)lock->nsl_spinlock); - + mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); return; } @@ -741,10 +703,7 @@ __stdcall static void ndis_unlock(lock) ndis_spin_lock *lock; { - if (lock == NULL) - return; - mtx_unlock((struct mtx *)lock->nsl_spinlock); - + mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); return; } @@ -2102,13 +2061,13 @@ ndis_insert_head(head, entry, lock) { ndis_list_entry *flink; - mtx_lock((struct mtx *)lock->nsl_spinlock); + mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); flink = head->nle_flink; entry->nle_flink = flink; entry->nle_blink = head; flink->nle_blink = entry; head->nle_flink = entry; - mtx_unlock((struct mtx *)lock->nsl_spinlock); + mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); return(flink); } @@ -2121,12 +2080,12 @@ ndis_remove_head(head, lock) ndis_list_entry *flink; ndis_list_entry *entry; - mtx_lock((struct mtx *)lock->nsl_spinlock); + mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); entry = head->nle_flink; flink = entry->nle_flink; head->nle_flink = flink; flink->nle_blink = head; - mtx_unlock((struct mtx *)lock->nsl_spinlock); + mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); return(entry); } @@ -2139,13 +2098,13 @@ ndis_insert_tail(head, entry, lock) { ndis_list_entry *blink; - mtx_lock((struct mtx *)lock->nsl_spinlock); + mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); blink = head->nle_blink; entry->nle_flink = head; entry->nle_blink = blink; blink->nle_flink = entry; head->nle_blink = entry; - mtx_unlock((struct mtx *)lock->nsl_spinlock); + mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); return(blink); } @@ -2165,9 +2124,9 @@ ndis_sync_with_intr(intr, syncfunc, syncctx) sc = (struct ndis_softc *)intr->ni_block->nmb_ifp; sync = syncfunc; - mtx_lock(&sc->ndis_intrmtx); + mtx_pool_lock(ndis_mtxpool, sc->ndis_intrmtx); rval = sync(syncctx); - mtx_unlock(&sc->ndis_intrmtx); + mtx_pool_unlock(ndis_mtxpool, sc->ndis_intrmtx); return(rval); } diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c index 2c73d55..14a446b 100644 --- a/sys/compat/ndis/subr_ntoskrnl.c +++ b/sys/compat/ndis/subr_ntoskrnl.c @@ -122,22 +122,19 @@ __stdcall static void ntoskrnl_init_lock(kspin_lock *); __stdcall static void dummy(void); __stdcall static size_t ntoskrnl_memcmp(const void *, const void *, size_t); -static struct mtx ntoskrnl_interlock; +static struct mtx *ntoskrnl_interlock; +extern struct mtx_pool *ndis_mtxpool; int ntoskrnl_libinit() { - mtx_init(&ntoskrnl_interlock, "ntoskrnllock", "ntoskrnl interlock", - MTX_DEF | MTX_RECURSE); - + ntoskrnl_interlock = mtx_pool_alloc(ndis_mtxpool); return(0); } int ntoskrnl_libfini() { - mtx_destroy(&ntoskrnl_interlock); - return(0); } @@ -412,11 +409,7 @@ ntoskrnl_init_lookaside(lookaside, allocfunc, freefunc, else lookaside->nll_l.gl_freefunc = freefunc; - mtx = malloc(sizeof(struct mtx), M_DEVBUF, M_NOWAIT|M_ZERO); - if (mtx == NULL) - return; - mtx_init(mtx, "ndisnplook", "ndis lookaside lock", - MTX_DEF | MTX_RECURSE | MTX_DUPOK); + mtx = mtx_pool_alloc(ndis_mtxpool); lookaside->nll_obsoletelock = (kspin_lock)mtx; return; @@ -426,8 +419,6 @@ __stdcall static void ntoskrnl_delete_lookaside(lookaside) paged_lookaside_list *lookaside; { - mtx_destroy((struct mtx *)lookaside->nll_obsoletelock); - free((struct mtx *)lookaside->nll_obsoletelock, M_DEVBUF); return; } @@ -456,11 +447,7 @@ ntoskrnl_init_nplookaside(lookaside, allocfunc, freefunc, else lookaside->nll_l.gl_freefunc = freefunc; - mtx = malloc(sizeof(struct mtx), M_DEVBUF, M_NOWAIT|M_ZERO); - if (mtx == NULL) - return; - mtx_init(mtx, "ndisnplook", "ndis lookaside lock", - MTX_DEF | MTX_RECURSE | MTX_DUPOK); + mtx = mtx_pool_alloc(ndis_mtxpool); lookaside->nll_obsoletelock = (kspin_lock)mtx; return; @@ -470,8 +457,6 @@ __stdcall static void ntoskrnl_delete_nplookaside(lookaside) npaged_lookaside_list *lookaside; { - mtx_destroy((struct mtx *)lookaside->nll_obsoletelock); - free((struct mtx *)lookaside->nll_obsoletelock, M_DEVBUF); return; } @@ -492,11 +477,11 @@ ntoskrnl_push_slist(/*head, entry*/ void) __asm__ __volatile__ ("" : "=c" (head), "=d" (entry)); - mtx_lock(&ntoskrnl_interlock); + mtx_pool_lock(ndis_mtxpool, ntoskrnl_interlock); oldhead = head->slh_list.slh_next; entry->sl_next = head->slh_list.slh_next; head->slh_list.slh_next = entry; - mtx_unlock(&ntoskrnl_interlock); + mtx_pool_unlock(ndis_mtxpool, ntoskrnl_interlock); return(oldhead); } @@ -508,11 +493,11 @@ ntoskrnl_pop_slist(/*head*/ void) __asm__ __volatile__ ("" : "=c" (head)); - mtx_lock(&ntoskrnl_interlock); + mtx_pool_lock(ndis_mtxpool, ntoskrnl_interlock); first = head->slh_list.slh_next; if (first != NULL) head->slh_list.slh_next = first->sl_next; - mtx_unlock(&ntoskrnl_interlock); + mtx_pool_unlock(ndis_mtxpool, ntoskrnl_interlock); return(first); } @@ -526,11 +511,11 @@ ntoskrnl_push_slist_ex(/*head, entry,*/ lock) __asm__ __volatile__ ("" : "=c" (head), "=d" (entry)); - mtx_lock((struct mtx *)*lock); + mtx_pool_lock(ndis_mtxpool, (struct mtx *)*lock); oldhead = head->slh_list.slh_next; entry->sl_next = head->slh_list.slh_next; head->slh_list.slh_next = entry; - mtx_unlock((struct mtx *)*lock); + mtx_pool_unlock(ndis_mtxpool, (struct mtx *)*lock); return(oldhead); } @@ -543,11 +528,11 @@ ntoskrnl_pop_slist_ex(/*head, lock*/ void) __asm__ __volatile__ ("" : "=c" (head), "=d" (lock)); - mtx_lock((struct mtx *)*lock); + mtx_pool_lock(ndis_mtxpool, (struct mtx *)*lock); first = head->slh_list.slh_next; if (first != NULL) head->slh_list.slh_next = first->sl_next; - mtx_unlock((struct mtx *)*lock); + mtx_pool_unlock(ndis_mtxpool, (struct mtx *)*lock); return(first); } @@ -558,7 +543,8 @@ ntoskrnl_lock_dpc(/*lock*/ void) __asm__ __volatile__ ("" : "=c" (lock)); - mtx_lock((struct mtx *)*lock); + mtx_pool_lock(ndis_mtxpool, (struct mtx *)*lock); + return; } @@ -569,7 +555,8 @@ ntoskrnl_unlock_dpc(/*lock*/ void) __asm__ __volatile__ ("" : "=c" (lock)); - mtx_unlock((struct mtx *)*lock); + mtx_pool_unlock(ndis_mtxpool, (struct mtx *)*lock); + return; } @@ -635,7 +622,7 @@ __stdcall static void ntoskrnl_init_lock(lock) kspin_lock *lock; { - *lock = (kspin_lock)&ntoskrnl_interlock; + *lock = (kspin_lock)mtx_pool_alloc(ndis_mtxpool); return; } diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index 0d1a168..415e262 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -64,6 +64,8 @@ __FBSDID("$FreeBSD$"); #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_ioctl.h> +#include <dev/wi/if_wavelan_ieee.h> + #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> @@ -112,27 +114,25 @@ static void ndis_ticktask (void *, int); static void ndis_start (struct ifnet *); static void ndis_starttask (void *, int); 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); static void ndis_init (void *); static void ndis_stop (struct ndis_softc *); static void ndis_watchdog (struct ifnet *); static void ndis_shutdown (device_t); static int ndis_ifmedia_upd (struct ifnet *); static void ndis_ifmedia_sts (struct ifnet *, struct ifmediareq *); +static int ndis_get_assoc (struct ndis_softc *, ndis_wlan_bssid_ex *); static void ndis_getstate_80211 (struct ndis_softc *); static void ndis_setstate_80211 (struct ndis_softc *); +static void ndis_media_status (struct ifnet *, struct ifmediareq *); static void ndis_reset (struct ndis_softc *); static void ndis_setmulti (struct ndis_softc *); static void ndis_map_sclist (void *, bus_dma_segment_t *, int, bus_size_t, int); -#ifdef NDIS_USEIOSPACE -#define NDIS_RES SYS_RES_IOPORT -#define NDIS_RID NDIS_PCI_LOIO -#else -#define NDIS_RES SYS_RES_MEMORY -#define NDIS_RID NDIS_PCI_LOMEM -#endif +extern struct mtx_pool *ndis_mtxpool; static device_method_t ndis_methods[] = { /* Device interface */ @@ -239,12 +239,12 @@ ndis_attach(dev) unit = device_get_unit(dev); sc->ndis_dev = dev; - mtx_init(&sc->ndis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + sc->ndis_mtx = mtx_pool_alloc(ndis_mtxpool); /* * Map control/status registers. */ + pci_enable_busmaster(dev); rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); @@ -258,7 +258,7 @@ ndis_attach(dev) 0, ~0, 1, RF_ACTIVE); if (sc->ndis_res_io == NULL) { device_printf(dev, - "couldn't map iospace"); + "couldn't map iospace\n"); error = ENXIO; goto fail; } @@ -267,7 +267,7 @@ ndis_attach(dev) if (sc->ndis_res_altmem != NULL && sc->ndis_res_mem != NULL) { device_printf(dev, - "too many memory resources"); + "too many memory resources\n"); error = ENXIO; goto fail; } @@ -280,7 +280,8 @@ ndis_attach(dev) 0, ~0, 1, RF_ACTIVE); if (sc->ndis_res_altmem == NULL) { device_printf(dev, - "couldn't map alt memory"); + "couldn't map alt " + "memory\n"); error = ENXIO; goto fail; } @@ -293,7 +294,7 @@ ndis_attach(dev) 0, ~0, 1, RF_ACTIVE); if (sc->ndis_res_mem == NULL) { device_printf(dev, - "couldn't map memory"); + "couldn't map memory\n"); error = ENXIO; goto fail; } @@ -306,7 +307,7 @@ ndis_attach(dev) RF_SHAREABLE | RF_ACTIVE); if (sc->ndis_irq == NULL) { device_printf(dev, - "couldn't map interrupt"); + "couldn't map interrupt\n"); error = ENXIO; goto fail; } @@ -331,8 +332,7 @@ ndis_attach(dev) goto fail; } - mtx_init(&sc->ndis_intrmtx, device_get_nameunit(dev), "ndisisrlock", - MTX_DEF | MTX_RECURSE); + sc->ndis_intrmtx = mtx_pool_alloc(ndis_mtxpool); TASK_INIT(&sc->ndis_intrtask, 0, ndis_intrtask, sc); TASK_INIT(&sc->ndis_ticktask, 0, ndis_ticktask, sc); TASK_INIT(&sc->ndis_starttask, 0, ndis_starttask, sc); @@ -480,23 +480,53 @@ ndis_attach(dev) ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = 50; - /* - * Call MI attach routine. - */ - ether_ifattach(ifp, eaddr); - /* Do media setup */ if (sc->ndis_80211) { struct ieee80211com *ic = (void *)ifp; + ndis_80211_config config; ndis_80211_rates rates; + struct ndis_80211_nettype_list *ntl; uint32_t arg; int r; ic->ic_phytype = IEEE80211_T_DS; ic->ic_opmode = IEEE80211_M_STA; - ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_IBSS; - ic->ic_state = IEEE80211_S_RUN; + ic->ic_caps = IEEE80211_C_IBSS; + ic->ic_state = IEEE80211_S_ASSOC; ic->ic_modecaps = (1<<IEEE80211_MODE_AUTO); + len = 0; + r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, + NULL, &len); + if (r != ENOSPC) + goto nonettypes; + ntl = malloc(len, M_DEVBUF, M_WAITOK); + r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, + ntl, &len); + if (r != 0) { + free(ntl, M_DEVBUF); + goto nonettypes; + } + + for (i = 0; i < ntl->ntl_items; i++) { + switch (ntl->ntl_type[i]) { + case NDIS_80211_NETTYPE_11FH: + ic->ic_modecaps |= (1<<IEEE80211_MODE_11B); + break; + case NDIS_80211_NETTYPE_11DS: + ic->ic_modecaps |= (1<<IEEE80211_MODE_11B); + break; + case NDIS_80211_NETTYPE_11OFDM5: + ic->ic_modecaps |= (1<<IEEE80211_MODE_11A); + break; + case NDIS_80211_NETTYPE_11OFDM24: + ic->ic_modecaps |= (1<<IEEE80211_MODE_11G); + break; + default: + break; + } + } + free(ntl, M_DEVBUF); +nonettypes: len = sizeof(rates); bzero((char *)&rates, len); r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES, @@ -504,44 +534,61 @@ ndis_attach(dev) if (r) device_printf (dev, "get rates failed: 0x%x\n", r); /* - * We need a way to distinguish between 802.11b cards - * and 802.11g cards. Unfortunately, Microsoft doesn't - * really give us one, so we have to apply a bit of a - * heuristic here. If we ask for supported rates, and - * we get 8 of them, then we know this isn't just a - * plain 802.11b card, since those only support up to - * 4 rates. This doesn't help us distinguish 802.11g - * from 802.11a or turbo cards though. + * Since the supported rates only up to 8 can be supported, + * if this is not 802.11b we're just going to be faking it + * all up to heck. */ #define SETRATE(x, y) \ - ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y); + ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y) #define INCRATE(x) \ - ic->ic_sup_rates[x].rs_nrates++; + ic->ic_sup_rates[x].rs_nrates++ - if (rates[7]) { - ic->ic_curmode = IEEE80211_MODE_11G; - ic->ic_modecaps |= (1<<IEEE80211_MODE_11G)| - (1<<IEEE80211_MODE_11B); + ic->ic_curmode = IEEE80211_MODE_AUTO; + if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) + ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0; + if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0; + if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0; - for (i = 0; i < len; i++) { - switch(rates[i] & IEEE80211_RATE_VAL) { - case 2: - case 4: - case 11: - case 22: - SETRATE(IEEE80211_MODE_11B, rates[i]); - INCRATE(IEEE80211_MODE_11B); - break; - default: + for (i = 0; i < len; i++) { + switch (rates[i] & IEEE80211_RATE_VAL) { + case 2: + case 4: + case 11: + case 10: + case 22: + if (!(ic->ic_modecaps & + (1<<IEEE80211_MODE_11B))) { + /* Lazy-init 802.11b. */ + ic->ic_modecaps |= + (1<<IEEE80211_MODE_11B); + ic->ic_sup_rates[IEEE80211_MODE_11B]. + rs_nrates = 0; + } + SETRATE(IEEE80211_MODE_11B, rates[i]); + INCRATE(IEEE80211_MODE_11B); + break; + default: + if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) { + SETRATE(IEEE80211_MODE_11A, rates[i]); + INCRATE(IEEE80211_MODE_11A); + } + if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) { SETRATE(IEEE80211_MODE_11G, rates[i]); INCRATE(IEEE80211_MODE_11G); - break; } + break; } + } - /* Now cheat by filling in the 54Mbps rates. */ - + /* + * If the hardware supports 802.11g, it most + * likely supports 802.11b and all of the + * 802.11b and 802.11g speeds, so maybe we can + * just cheat here. Just how in the heck do + * we detect turbo modes, though? + */ + if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) { SETRATE(IEEE80211_MODE_11G, 47); INCRATE(IEEE80211_MODE_11G); SETRATE(IEEE80211_MODE_11G, 72); @@ -550,39 +597,63 @@ ndis_attach(dev) INCRATE(IEEE80211_MODE_11G); SETRATE(IEEE80211_MODE_11G, 108); INCRATE(IEEE80211_MODE_11G); - } else { - ic->ic_curmode = IEEE80211_MODE_11B; - ic->ic_modecaps |= (1<<IEEE80211_MODE_11B); - ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0; - for (i = 0; i < len; i++) { - if (!rates[i]) - break; - SETRATE(IEEE80211_MODE_11B, rates[i]); - INCRATE(IEEE80211_MODE_11B); - } + } + if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) { + SETRATE(IEEE80211_MODE_11A, 47); + INCRATE(IEEE80211_MODE_11A); + SETRATE(IEEE80211_MODE_11A, 72); + INCRATE(IEEE80211_MODE_11A); + SETRATE(IEEE80211_MODE_11A, 96); + INCRATE(IEEE80211_MODE_11A); + SETRATE(IEEE80211_MODE_11A, 108); + INCRATE(IEEE80211_MODE_11A); } #undef SETRATE #undef INCRATE /* - * The Microsoft API has no support for getting/setting - * channels, so we lie like a rug here. If you wan to - * select a channel, use the sysctl/registry interface. + * Taking yet more guesses here. */ - for (i = 1; i < 11; i++) { + for (i = 1; i < IEEE80211_CHAN_MAX; i++) { + int chanflag = 0; + + if (ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates) + chanflag |= IEEE80211_CHAN_G; + if (i <= 14) + chanflag |= IEEE80211_CHAN_B; + if (chanflag == 0) + break; ic->ic_channels[i].ic_freq = - ieee80211_ieee2mhz(i, IEEE80211_CHAN_B); - ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B; + ieee80211_ieee2mhz(i, chanflag); + ic->ic_channels[i].ic_flags = chanflag; } i = sizeof(arg); r = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &i); if (arg != NDIS_80211_WEPSTAT_NOTSUPPORTED) ic->ic_caps |= IEEE80211_C_WEP; - ieee80211_node_attach(ifp); + i = sizeof(arg); + r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i); + if (r == 0) + ic->ic_caps |= IEEE80211_C_PMGT; + i = sizeof(config); + r = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &i); + if (r == 0) { + int chan; + chan = ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0); + if (chan < 0 || chan >= IEEE80211_CHAN_MAX) { + ic->ic_ibss_chan = &ic->ic_channels[1]; + } else + ic->ic_ibss_chan = &ic->ic_channels[chan]; + } else { + device_printf(sc->ndis_dev, "couldn't retrieve " + "channel info: %d\n", r); + ic->ic_ibss_chan = &ic->ic_channels[1]; + } + bcopy(eaddr, &ic->ic_myaddr, sizeof(eaddr)); + ieee80211_ifattach(ifp); ieee80211_media_init(ifp, ieee80211_media_change, - ieee80211_media_status); - ic->ic_ibss_chan = &ic->ic_channels[1]; - ic->ic_bss->ni_chan = &ic->ic_channels[1]; + ndis_media_status); + ic->ic_bss->ni_chan = ic->ic_ibss_chan; } else { ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd, ndis_ifmedia_sts); @@ -593,6 +664,7 @@ ndis_attach(dev) IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO); + ether_ifattach(ifp, eaddr); } /* Override the status handler so we can detect link changes. */ @@ -632,13 +704,12 @@ ndis_detach(dev) ifp->if_flags &= ~IFF_UP; if (device_is_attached(dev)) { - if (sc->ndis_80211) { - ifmedia_removeall(&sc->ic.ic_media); - ieee80211_node_detach(ifp); - } NDIS_UNLOCK(sc); ndis_stop(sc); - ether_ifdetach(ifp); + if (sc->ndis_80211) + ieee80211_ifdetach(ifp); + else + ether_ifdetach(ifp); } else NDIS_UNLOCK(sc); @@ -667,9 +738,6 @@ ndis_detach(dev) sysctl_ctx_free(&sc->ndis_ctx); - mtx_destroy(&sc->ndis_intrmtx); - mtx_destroy(&sc->ndis_mtx); - return(0); } @@ -809,17 +877,13 @@ ndis_linksts_done(adapter) switch (block->nmb_getstat) { case NDIS_STATUS_MEDIA_CONNECT: - sc->ndis_link = 1; - device_printf(sc->ndis_dev, "link up\n"); - if (sc->ndis_80211) - ndis_getstate_80211(sc); + taskqueue_enqueue(taskqueue_swi, &sc->ndis_ticktask); taskqueue_enqueue(taskqueue_swi, &sc->ndis_starttask); break; case NDIS_STATUS_MEDIA_DISCONNECT: - device_printf(sc->ndis_dev, "link down\n"); if (sc->ndis_80211) ndis_getstate_80211(sc); - sc->ndis_link = 0; + taskqueue_enqueue(taskqueue_swi, &sc->ndis_ticktask); break; default: break; @@ -842,9 +906,9 @@ ndis_intrtask(arg, pending) NDIS_LOCK(sc); ndis_intrhand(sc); NDIS_UNLOCK(sc); - mtx_lock(&sc->ndis_intrmtx); + mtx_lock(sc->ndis_intrmtx); ndis_enable_intr(sc); - mtx_unlock(&sc->ndis_intrmtx); + mtx_unlock(sc->ndis_intrmtx); if (ifp->if_snd.ifq_head != NULL) ndis_start(ifp); @@ -867,14 +931,14 @@ ndis_intr(arg) if (!(ifp->if_flags & IFF_UP)) return; - mtx_lock(&sc->ndis_intrmtx); + mtx_lock(sc->ndis_intrmtx); 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; } - mtx_unlock(&sc->ndis_intrmtx); + mtx_unlock(sc->ndis_intrmtx); if (is_our_intr || call_isr) taskqueue_enqueue(taskqueue_swi, &sc->ndis_intrtask); @@ -889,6 +953,9 @@ ndis_tick(xsc) struct ndis_softc *sc; sc = xsc; taskqueue_enqueue(taskqueue_swi, &sc->ndis_ticktask); + sc->ndis_stat_ch = timeout(ndis_tick, sc, hz * + sc->ndis_block.nmb_checkforhangsecs); + } static void @@ -910,8 +977,19 @@ ndis_ticktask(xsc, pending) NDIS_LOCK(sc); - if (linkstate == nmc_connected) + if (sc->ndis_link == 0 && linkstate == nmc_connected) { + device_printf(sc->ndis_dev, "link up\n"); sc->ndis_link = 1; + if (sc->ndis_80211) + ndis_getstate_80211(sc); + } + + if (sc->ndis_link == 1 && linkstate == nmc_disconnected) { + device_printf(sc->ndis_dev, "link down\n"); + sc->ndis_link = 0; + } + + NDIS_UNLOCK(sc); hangfunc = sc->ndis_chars.nmc_checkhang_func; @@ -921,11 +999,6 @@ ndis_ticktask(xsc, pending) ndis_reset_nic(sc); } - sc->ndis_stat_ch = timeout(ndis_tick, sc, hz * - sc->ndis_block.nmb_checkforhangsecs); - - NDIS_UNLOCK(sc); - return; } @@ -1228,6 +1301,7 @@ ndis_setstate_80211(sc) { struct ieee80211com *ic; ndis_80211_ssid ssid; + ndis_80211_config config; ndis_80211_wep wep; int i, rval = 0, len; uint32_t arg; @@ -1261,7 +1335,11 @@ ndis_setstate_80211(sc) /* Set WEP */ +#ifdef IEEE80211_F_WEPON if (ic->ic_flags & IEEE80211_F_WEPON) { +#else + if (ic->ic_wep_mode >= IEEE80211_WEP_ON) { +#endif for (i = 0; i < IEEE80211_WEP_NKID; i++) { if (ic->ic_nw_keys[i].wk_len) { bzero((char *)&wep, sizeof(wep)); @@ -1295,13 +1373,30 @@ ndis_setstate_80211(sc) if (rval) device_printf(sc->ndis_dev, "enable WEP failed: %d\n", rval); +#ifndef IEEE80211_F_WEPON + if (ic->ic_wep_mode != IEEE80211_WEP_8021X && + ic->ic_wep_mode != IEEE80211_WEP_ON) + arg = NDIS_80211_PRIVFILT_ACCEPTALL; + else +#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; + else + ic->ic_wep_mode = IEEE80211_WEP_8021X; + } +#endif } else { arg = NDIS_80211_WEPSTAT_DISABLED; len = sizeof(arg); ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len); } - /* Set SSID. */ len = sizeof(ssid); @@ -1316,15 +1411,134 @@ ndis_setstate_80211(sc) if (rval) device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval); + len = sizeof(config); + rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); + if (rval == 0) { + int chan; + + chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); + if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) { + config.nc_dsconfig = + ic->ic_bss->ni_chan->ic_freq * 1000; + rval = ndis_set_info(sc, OID_802_11_CONFIGURATION, + &config, &len); + if (rval) + device_printf(sc->ndis_dev, "couldn't change " + "DS config to %ukHz: %d\n", + config.nc_dsconfig, rval); + } + } else + device_printf(sc->ndis_dev, "couldn't retrieve " + "channel info: %d\n", rval); + return; } static void +ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr) +{ + struct ieee80211com *ic = (void *)ifp; + struct ieee80211_node *ni = NULL; + + imr->ifm_status = IFM_AVALID; + imr->ifm_active = IFM_IEEE80211; + if (ic->ic_state == IEEE80211_S_RUN) + imr->ifm_status |= IFM_ACTIVE; + imr->ifm_active |= IFM_AUTO; + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + ni = ic->ic_bss; + /* calculate rate subtype */ + imr->ifm_active |= ieee80211_rate2media(ic, + ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode); + break; + case IEEE80211_M_IBSS: + ni = ic->ic_bss; + /* calculate rate subtype */ + imr->ifm_active |= ieee80211_rate2media(ic, + ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode); + imr->ifm_active |= IFM_IEEE80211_ADHOC; + break; + case IEEE80211_M_AHDEMO: + /* should not come here */ + break; + case IEEE80211_M_HOSTAP: + imr->ifm_active |= IFM_IEEE80211_HOSTAP; + break; + case IEEE80211_M_MONITOR: + imr->ifm_active |= IFM_IEEE80211_MONITOR; + break; + } + switch (ic->ic_curmode) { + case IEEE80211_MODE_11A: + imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A); + break; + case IEEE80211_MODE_11B: + imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B); + break; + case IEEE80211_MODE_11G: + imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G); + break; + case IEEE80211_MODE_TURBO: + imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A) + | IFM_IEEE80211_TURBO; + break; + } +} + +static int +ndis_get_assoc(sc, assoc) + struct ndis_softc *sc; + ndis_wlan_bssid_ex *assoc; +{ + ndis_80211_bssid_list_ex *bl; + ndis_wlan_bssid_ex *bs; + ndis_80211_macaddr bssid; + int i, len, error; + + len = sizeof(bssid); + error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len); + if (error) { + device_printf(sc->ndis_dev, "failed to get bssid"); + return(ENOENT); + } + len = 0; + error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len); + if (error != ENOSPC) { + device_printf(sc->ndis_dev, "bssid_list failed"); + return (error); + } + + bl = malloc(len, M_TEMP, M_NOWAIT); + error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len); + if (error) { + free(bl, M_TEMP); + device_printf(sc->ndis_dev, "bssid_list failed"); + return (error); + } + + bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0]; + for (i = 0; i < bl->nblx_items; i++) { + if (bcmp(bs->nwbx_macaddr, bssid, sizeof(bssid)) == 0) { + bcopy((char *)bs, (char *)assoc, bs->nwbx_len); + free(bl, M_TEMP); + return(0); + } + bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len); + } + + free(bl, M_TEMP); + return(ENOENT); +} + +static void ndis_getstate_80211(sc) struct ndis_softc *sc; { struct ieee80211com *ic; ndis_80211_ssid ssid; + ndis_80211_config config; + ndis_wlan_bssid_ex bs; int rval, len, i = 0; uint32_t arg; struct ifnet *ifp; @@ -1339,24 +1553,30 @@ ndis_getstate_80211(sc) ic->ic_state = IEEE80211_S_RUN; else ic->ic_state = IEEE80211_S_ASSOC; -/* - len = sizeof(arg); - rval = ndis_get_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len); - if (rval) - device_printf (sc->ndis_dev, "get infra failed: %d\n", rval); - switch(arg) { - case NDIS_80211_NET_INFRA_IBSS: - ic->ic_opmode = IEEE80211_M_IBSS; - break; - case NDIS_80211_NET_INFRA_BSS: - ic->ic_opmode = IEEE80211_M_STA; - break; - default: - break; + /* + * If we're associated, retrieve info on the current bssid. + */ + if (ndis_get_assoc(sc, &bs) == 0) { + switch(bs.nwbx_nettype) { + case NDIS_80211_NETTYPE_11FH: + case NDIS_80211_NETTYPE_11DS: + ic->ic_curmode = IEEE80211_MODE_11B; + break; + case NDIS_80211_NETTYPE_11OFDM5: + ic->ic_curmode = IEEE80211_MODE_11A; + break; + case NDIS_80211_NETTYPE_11OFDM24: + ic->ic_curmode = IEEE80211_MODE_11G; + break; + default: + device_printf(sc->ndis_dev, + "unknown nettype %d\n", arg); + break; + } } -*/ + len = sizeof(ssid); bzero((char *)&ssid, len); rval = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len); @@ -1373,7 +1593,7 @@ ndis_getstate_80211(sc) ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B]; for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) { if ((ic->ic_bss->ni_rates.rs_rates[i] & - IEEE80211_RATE_VAL) == (arg / 10000) * 2) + IEEE80211_RATE_VAL) == arg / 5000) break; } } @@ -1383,28 +1603,48 @@ ndis_getstate_80211(sc) ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11G]; for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) { if ((ic->ic_bss->ni_rates.rs_rates[i] & - IEEE80211_RATE_VAL) == (arg / 10000) * 2) + IEEE80211_RATE_VAL) == arg / 5000) break; } } if (i == ic->ic_bss->ni_rates.rs_nrates) - device_printf (sc->ndis_dev, "no matching rate for: %d\n", - (arg / 10000) * 2); + device_printf(sc->ndis_dev, "no matching rate for: %d\n", + arg / 5000); else ic->ic_bss->ni_txrate = i; - len = sizeof(arg); - rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len); + if (ic->ic_caps & IEEE80211_C_PMGT) { + len = sizeof(arg); + rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len); + + if (rval) + device_printf(sc->ndis_dev, + "get power mode failed: %d\n", rval); + if (arg == NDIS_80211_POWERMODE_CAM) + ic->ic_flags &= ~IEEE80211_F_PMGTON; + else + ic->ic_flags |= IEEE80211_F_PMGTON; + } + + len = sizeof(config); + rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); + if (rval == 0) { + int chan; + + chan = ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0); + if (chan < 0 || chan >= IEEE80211_CHAN_MAX) { + if (ifp->if_flags & IFF_DEBUG) + device_printf(sc->ndis_dev, "current channel " + "(%uMHz) out of bounds\n", + config.nc_dsconfig / 1000); + ic->ic_bss->ni_chan = &ic->ic_channels[1]; + } else + ic->ic_bss->ni_chan = &ic->ic_channels[chan]; + } else + device_printf(sc->ndis_dev, "couldn't retrieve " + "channel info: %d\n", rval); - if (rval) - device_printf (sc->ndis_dev, - "get power mode failed: %d\n", rval); - if (arg == NDIS_80211_POWERMODE_CAM) - ic->ic_flags &= ~IEEE80211_F_PMGTON; - else - ic->ic_flags |= IEEE80211_F_PMGTON; - /* len = sizeof(arg); rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len); @@ -1472,12 +1712,24 @@ ndis_ioctl(ifp, command, data) if (sc->ndis_80211) { error = ieee80211_ioctl(ifp, command, data); if (error == ENETRESET) { - ndis_setstate_80211(sc); + /*ndis_setstate_80211(sc);*/ + ndis_init(sc); error = 0; } } else error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); break; + case SIOCGIFGENERIC: + case SIOCSIFGENERIC: + if (sc->ndis_80211 && ifp->if_flags & IFF_UP) { + if (command == SIOCGIFGENERIC) + error = ndis_wi_ioctl_get(ifp, command, data); + else + error = ndis_wi_ioctl_set(ifp, command, data); + } else + error = ENOTTY; + if (error != ENOTTY) + break; default: if (sc->ndis_80211) { error = ieee80211_ioctl(ifp, command, data); @@ -1495,6 +1747,124 @@ ndis_ioctl(ifp, command, data) return(error); } +static int +ndis_wi_ioctl_get(ifp, command, data) + struct ifnet *ifp; + u_long command; + caddr_t data; +{ + struct wi_req wreq; + struct ifreq *ifr; + struct ndis_softc *sc; + ndis_80211_bssid_list_ex *bl; + ndis_wlan_bssid_ex *wb; + struct wi_apinfo *api; + int error, i, j, len, maxaps; + + sc = ifp->if_softc; + ifr = (struct ifreq *)data; + error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); + if (error) + return (error); + + switch (wreq.wi_type) { + case WI_RID_READ_APS: + len = 0; + error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, + NULL, &len); + if (error == 0) + tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2); + 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); + error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len); + if (error) { + free(bl, M_DEVBUF); + break; + } + maxaps = (2 * wreq.wi_len - sizeof(int)) / sizeof(*api); + maxaps = MIN(maxaps, bl->nblx_items); + wreq.wi_len = (maxaps * sizeof(*api) + sizeof(int)) / 2; + *(int *)&wreq.wi_val = maxaps; + api = (struct wi_apinfo *)&((int *)&wreq.wi_val)[1]; + wb = bl->nblx_bssid; + while (maxaps--) { + bzero(api, sizeof(*api)); + bcopy(&wb->nwbx_macaddr, &api->bssid, + sizeof(api->bssid)); + api->namelen = wb->nwbx_ssid.ns_ssidlen; + bcopy(&wb->nwbx_ssid.ns_ssid, &api->name, api->namelen); + if (wb->nwbx_privacy) + api->capinfo |= IEEE80211_CAPINFO_PRIVACY; + /* XXX Where can we get noise information? */ + api->signal = wb->nwbx_rssi + 149; /* XXX */ + api->quality = api->signal; + api->channel = + ieee80211_mhz2ieee(wb->nwbx_config.nc_dsconfig / + 1000, 0); + /* In "auto" infrastructure mode, this is useless. */ + if (wb->nwbx_netinfra == NDIS_80211_NET_INFRA_IBSS) + api->capinfo |= IEEE80211_CAPINFO_IBSS; + if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) { + j = sizeof(ndis_80211_rates_ex); + /* handle other extended things */ + } else + j = sizeof(ndis_80211_rates); + for (i = api->rate = 0; i < j; i++) + api->rate = MAX(api->rate, 5 * + (wb->nwbx_supportedrates[i] & 0x7f)); + api++; + wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len); + } + free(bl, M_DEVBUF); + error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); + break; + default: + error = ENOTTY; + break; + } + return (error); +} + +static int +ndis_wi_ioctl_set(ifp, command, data) + struct ifnet *ifp; + u_long command; + caddr_t data; +{ + struct wi_req wreq; + struct ifreq *ifr; + struct ndis_softc *sc; + uint32_t foo; + int error, len; + + error = suser(curthread); + if (error) + return (error); + + sc = ifp->if_softc; + ifr = (struct ifreq *)data; + error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); + if (error) + return (error); + + switch (wreq.wi_type) { + case WI_RID_SCAN_APS: + case WI_RID_SCAN_REQ: /* arguments ignored */ + len = sizeof(foo); + foo = 0; + error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, &foo, + &len); + break; + default: + error = ENOTTY; + break; + } + return (error); +} + static void ndis_watchdog(ifp) struct ifnet *ifp; @@ -1530,6 +1900,7 @@ ndis_stop(sc) ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; + sc->ndis_link = 0; untimeout(ndis_tick, sc, sc->ndis_stat_ch); ndis_halt_nic(sc); diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h index 2987aae..45736f0 100644 --- a/sys/dev/if_ndis/if_ndisvar.h +++ b/sys/dev/if_ndis/if_ndisvar.h @@ -90,8 +90,8 @@ struct ndis_softc { struct resource *ndis_res_am; /* attribute mem (pccard) */ struct resource *ndis_res_cm; /* common mem (pccard) */ int ndis_rescnt; - struct mtx ndis_mtx; - struct mtx ndis_intrmtx; + struct mtx *ndis_mtx; + struct mtx *ndis_intrmtx; struct task ndis_intrtask; struct task ndis_ticktask; struct task ndis_starttask; @@ -129,6 +129,6 @@ struct ndis_softc { int ndis_mmapcnt; }; -#define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx) -#define NDIS_UNLOCK(_sc) mtx_unlock(&(_sc)->ndis_mtx) +#define NDIS_LOCK(_sc) mtx_pool_lock(ndis_mtxpool, (_sc)->ndis_mtx) +#define NDIS_UNLOCK(_sc) mtx_pool_unlock(ndis_mtxpool, (_sc)->ndis_mtx) |