Sync ndis(4) and tools with FreeBSD and hook it all back into the build.
authorSascha Wildner <saw@online.de>
Wed, 7 Sep 2011 20:28:06 +0000 (22:28 +0200)
committerSascha Wildner <saw@online.de>
Wed, 7 Sep 2011 20:28:06 +0000 (22:28 +0200)
It supports NDIS 5.x drivers, that means Windows XP and Server 2003.
The latter is an educated guess by me. No testing has actually been
done using Windows Server 2003 drivers.

It is tested on i386 with the following PCI adapters:

* D-Link DWL-G520+ (Texas Instruments ACX111 chip), aka acx(4).

* Linksys WMP600N (Ralink RT2860 chip).

* Planex GW-DS54GR (Realtek RTL8185 chip) which was kindly donated by
  sephe.

Thanks to Max Herrgard <herrgard@gmail.com> for testing it on x86_64
with a CNet CWP-854 (Ralink RT2561T chip), aka ral(4).

Note that this port has the following caveats:

* PCI adapters need hw.ioapic_enable=0 in /boot/loader.conf but worked
  great then. Without it, the box will completely freeze after a while.
  This has been observed on both my own testing box as well as on a
  different box by Max Herrgard. The cause is yet unknown. :-(

* PC Card adapters are untested (they might just work).

* USB adapters are not yet stable at all. Panics might ensue.

Taken-from: FreeBSD

58 files changed:
Makefile_upgrade.inc
etc/mtree/BSD.root.dist
share/man/man4/Makefile
share/man/man4/man4.i386/Makefile
share/man/man4/ndis.4 [moved from share/man/man4/man4.i386/ndis.4 with 88% similarity]
share/man/man4/usb.4
share/man/man4/wlan.4
share/man/man9/ieee80211.9
sys/config/LINT
sys/config/LINT64
sys/cpu/i386/include/segments.h
sys/dev/netif/Makefile
sys/dev/netif/ndis/Makefile
sys/dev/netif/ndis/README [deleted file]
sys/dev/netif/ndis/if_ndis.c
sys/dev/netif/ndis/if_ndis_pccard.c
sys/dev/netif/ndis/if_ndis_pci.c
sys/dev/netif/ndis/if_ndis_usb.c [new file with mode: 0644]
sys/dev/netif/ndis/if_ndisvar.h
sys/emulation/Makefile
sys/emulation/ndis/Makefile
sys/emulation/ndis/cfg_var.h
sys/emulation/ndis/hal_var.h
sys/emulation/ndis/kern_ndis.c
sys/emulation/ndis/kern_windrv.c [new file with mode: 0644]
sys/emulation/ndis/ndis_var.h
sys/emulation/ndis/ntoskrnl_var.h
sys/emulation/ndis/pe_var.h
sys/emulation/ndis/regcall.h [deleted file]
sys/emulation/ndis/resource_var.h
sys/emulation/ndis/subr_hal.c
sys/emulation/ndis/subr_ndis.c
sys/emulation/ndis/subr_ntoskrnl.c
sys/emulation/ndis/subr_pe.c
sys/emulation/ndis/subr_usbd.c [new file with mode: 0644]
sys/emulation/ndis/usbd_var.h [new file with mode: 0644]
sys/emulation/ndis/winx32_wrap.S [new file with mode: 0644]
sys/emulation/ndis/winx64_wrap.S [new file with mode: 0644]
sys/platform/pc32/conf/files
sys/platform/pc32/conf/options
sys/platform/pc32/i386/machdep.c
sys/platform/pc64/conf/files
sys/platform/pc64/conf/options
usr.sbin/802_11/Makefile
usr.sbin/802_11/ndis_events/Makefile [new file with mode: 0644]
usr.sbin/802_11/ndis_events/ndis_events.8 [new file with mode: 0644]
usr.sbin/802_11/ndis_events/ndis_events.c [new file with mode: 0644]
usr.sbin/Makefile
usr.sbin/ndiscvt/Makefile
usr.sbin/ndiscvt/inf-parse.y
usr.sbin/ndiscvt/inf-token.l
usr.sbin/ndiscvt/inf.c
usr.sbin/ndiscvt/inf.h
usr.sbin/ndiscvt/ndiscvt.8
usr.sbin/ndiscvt/ndiscvt.c
usr.sbin/ndiscvt/ndisgen.8 [new file with mode: 0644]
usr.sbin/ndiscvt/ndisgen.sh [new file with mode: 0644]
usr.sbin/ndiscvt/windrv_stub.c [new file with mode: 0644]

index 6deb8c8..d43f64f 100644 (file)
@@ -1733,6 +1733,8 @@ TO_REMOVE+=/usr/share/man/man8/xten.8.gz
 TO_REMOVE+=/usr/bin/gprof4
 TO_REMOVE+=/usr/share/misc/gprof.callg
 TO_REMOVE+=/usr/share/misc/gprof.flat
+TO_REMOVE+=/usr/share/man/cat4/i386/ndis.4.gz
+TO_REMOVE+=/usr/share/man/man4/i386/ndis.4.gz
 
 .if ${MACHINE_ARCH} == "x86_64"
 TO_REMOVE+=/usr/libdata/stallion/2681.sys
@@ -1775,9 +1777,3 @@ TO_REMOVE+=/usr/share/man/man4/rum.4.gz
 TO_REMOVE+=/boot/modules/if_ural.ko
 TO_REMOVE+=/usr/share/man/cat4/ural.4.gz
 TO_REMOVE+=/usr/share/man/man4/ural.4.gz
-TO_REMOVE+=/boot/modules/ndis.ko
-TO_REMOVE+=/usr/share/man/cat4/i386/ndis.4.gz
-TO_REMOVE+=/usr/share/man/man4/i386/ndis.4.gz
-TO_REMOVE+=/usr/sbin/ndiscvt
-TO_REMOVE+=/usr/share/man/cat8/ndiscvt.8.gz
-TO_REMOVE+=/usr/share/man/man8/ndiscvt.8.gz
index 6f9aabe..d5fd23f 100644 (file)
@@ -1,5 +1,4 @@
 # $FreeBSD: src/etc/mtree/BSD.root.dist,v 1.45.2.4 2002/06/10 15:33:27 obrien Exp $
-# $DragonFly: src/etc/mtree/BSD.root.dist,v 1.12 2008/09/01 19:39:49 dillon Exp $
 #
 # Please see the file src/etc/mtree/README before making changes to this file.
 #
         defaults
         ..
     ..
+    compat
+        ndis
+        ..
+    ..
     dev
     ..
     etc
index 38e3551..d52b317 100644 (file)
@@ -171,6 +171,7 @@ MAN=        aac.4 \
        natm.4 \
        ncr.4 \
        ncv.4 \
+       ndis.4 \
        netgraph.4 \
        netintro.4 \
        nfe.4 \
index b107620..a69c2ca 100644 (file)
@@ -10,9 +10,6 @@ MAN=  aic.4 apm.4 ar.4 asr.4 \
        spkr.4 sr.4 stl.4 \
        tx.4 viapm.4 vx.4
 
-# XXX re-add when adjusted to the new 802.11 framework
-#MAN+= ndis.4 \
-
 MLINKS=        spkr.4 speaker.4 \
        stl.4 stli.4
 
similarity index 88%
rename from share/man/man4/man4.i386/ndis.4
rename to share/man/man4/ndis.4
index 316ca46..d1874e5 100644 (file)
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/share/man/man4/man4.i386/ndis.4,v 1.9 2004/12/21 01:09:34 brueffer Exp $
-.\" $DragonFly: src/share/man/man4/man4.i386/ndis.4,v 1.6 2008/07/26 16:25:41 swildner Exp $
+.\" $FreeBSD: src/share/man/man4/ndis.4,v 1.5 2010/03/14 15:49:04 gavin Exp $
 .\"
-.Dd December 10, 2003
-.Dt NDIS 4 i386
+.Dd May 10, 2011
+.Dt NDIS 4
 .Os
 .Sh NAME
 .Nm ndis
 .Nd NDIS miniport driver wrapper
 .Sh SYNOPSIS
-.\".Cd "options NDISAPI"
+.Cd "options NDISAPI"
 .Cd "device ndis"
 .Cd "device wlan"
 .Sh DESCRIPTION
@@ -90,10 +89,8 @@ file, which contains the
 definitions for driver-specific registry keys and other installation
 data such as device identifiers.
 These two files can be converted
-into a
-.Pa ndis_driver_data.h
-file using the
-.Xr ndiscvt 8
+into a kernel module file using the
+.Xr ndisgen 8
 utility.
 This file contains a binary image of the driver plus
 registry key data.
@@ -108,7 +105,7 @@ file.
 The
 .Nm
 driver is designed to support mainly Ethernet and wireless
-network devices with PCI and PCMCIA bus attachments.
+network devices with PCI, PCMCIA and USB bus attachments.
 (Cardbus
 devices are also supported as a subset of PCI.)
 It can
@@ -123,11 +120,11 @@ driver-specific registry keys to control the media setting
 which can be configured via the
 .Xr sysctl 8
 command.
-.Sh EXAMPLES
-Refer to the
-.Sx EXAMPLES
-section of
-.Xr wlan 4 .
+.\".Sh EXAMPLES
+.\"Refer to the
+.\".Sx EXAMPLES
+.\"section of
+.\".Xr wlan 4 .
 .Sh DIAGNOSTICS
 .Bl -diag
 .It "ndis%d: watchdog timeout"
@@ -136,13 +133,17 @@ issued, however the device failed to acknowledge the transmission
 before a timeout expired.
 .El
 .Sh SEE ALSO
+.Xr altq 4 ,
 .Xr arp 4 ,
 .Xr ifmedia 4 ,
 .Xr netintro 4 ,
 .Xr ng_ether 4 ,
 .Xr wlan 4 ,
 .Xr ifconfig 8 ,
-.Xr ndiscvt 8
+.Xr ndis_events 8 ,
+.Xr ndiscvt 8 ,
+.Xr ndisgen 8 ,
+.Xr wpa_supplicant 8
 .Rs
 .%T "NDIS 5.1 specification"
 .%O http://www.microsoft.com
@@ -151,16 +152,9 @@ before a timeout expired.
 The
 .Nm
 device driver first appeared in
-.Fx 5.3
-and was imported into
-.Dx 1.0 .
+.Fx 5.3 .
 .Sh AUTHORS
-.An -nosplit
 The
 .Nm
 driver was written by
 .An Bill Paul Aq wpaul@windriver.com .
-Porting to
-.Dx
-was done by
-.An Matthew Dillon .
index efa6fbe..98ae90f 100644 (file)
@@ -88,6 +88,8 @@ RealTek RTL8150 Ethernet driver
 .El
 .Ss Wireless network interfaces
 .Bl -tag -width ".Xr snd_uaudio 4" -offset indent -compact
+.It Xr ndis 4
+NDIS miniport driver wrapper
 .\".It Xr rum 4
 .\"Ralink Technology RT2501USB/RT2601USB IEEE 802.11 driver
 .It Xr ubt 4
index b1d5a48..3e1a0ad 100644 (file)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD: src/share/man/man4/wlan.4,v 1.23 2010/01/14 09:38:23 roam Exp $
 .\"
-.Dd April 14, 2010
+.Dd May 10, 2011
 .Dt WLAN 4
 .Os
 .Sh NAME
@@ -41,10 +41,9 @@ Where a device does not directly support 802.11 functionality
 this layer fills in.
 The
 .Nm
-module is required by all native 802.11 drivers.
-.\" as well as the
-.\".Xr ndis 4
-.\"support.
+module is required by all native 802.11 drivers as well as the
+.Xr ndis 4
+support.
 .Pp
 .Nm
 supports multi-mode devices capable of
index beec0bb..2fddb74 100644 (file)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD: src/share/man/man9/ieee80211.9,v 1.7 2010/03/29 17:39:38 trasz Exp $
 .\"
-.Dd April 28, 2010
+.Dd May 10, 2011
 .Dt IEEE80211 9
 .Os
 .Sh NAME
@@ -550,7 +550,7 @@ Device supports Reduced Inter Frame Spacing (RIFS).
 .El
 .Sh SEE ALSO
 .Xr ioctl 2 ,
-.\".Xr ndis 4 ,
+.Xr ndis 4 ,
 .\".Xr ieee80211_amrr 9 ,
 .Xr ieee80211_beacon 9 ,
 .Xr ieee80211_bmiss 9 ,
index f1e4adf..6c55022 100644 (file)
@@ -296,6 +296,10 @@ options    COMPAT_43
 #
 options                COMPAT_DF12             #Compatible with DragonFly 1.2 and earlier
 
+# Enable NDIS binary driver support
+options        NDISAPI
+device         ndis
+
 #
 # These three options provide support for System V Interface
 # Definition-style interprocess communication, in the form of shared
index e47227a..7575450 100644 (file)
@@ -160,6 +160,10 @@ options            CPU_ENABLE_EST
 #
 options        COMPAT_43
 
+# Enable NDIS binary driver support
+options        NDISAPI
+device         ndis
+
 #
 # These three options provide support for System V Interface
 # Definition-style interprocess communication, in the form of shared
index adfe648..3d1427f 100644 (file)
@@ -228,12 +228,13 @@ struct region_descriptor {
 #define GBIOSARGS_SEL  14      /* BIOS interface (Arguments) */
 #define        GTLS_START      15      /* Thread TLS Descriptor */
 #define        GTLS_END        17      /* Thread TLS Descriptor */
+#define        GNDIS_SEL       18      /* For the NDIS layer */
 
 #define NGTLS          (GTLS_END - GTLS_START + 1)
 #ifdef BDE_DEBUGGER
 #define        NGDT            21      /* some of 11-17 are reserved for debugger */
 #else
-#define NGDT           18
+#define NGDT           19
 #endif
 
 /*
index 2774de2..13a8064 100644 (file)
@@ -1,6 +1,7 @@
 SUBDIR= an age alc ale ar ath aue axe bce bfe bge \
-       cue dc ed em ep et e1000 fwe \
-       fxp ic iwi iwn jme kue lge lgue lnc mii_layer my msk mxge nfe nge pcn \
+       cue dc ed em ep et e1000 \
+       fwe fxp ic iwi iwn jme kue lge lgue lnc \
+       mii_layer my msk mxge ndis nfe nge pcn \
        ral re rl rue sbni sbsh sf sis sk sln sr ste stge ti tl tx txp \
        vge vr vx wb wi wpi xe xl ig_hal emx ae
 
index 0891d18..3493815 100644 (file)
@@ -1,8 +1,8 @@
-#
-# $DragonFly: src/sys/dev/netif/ndis/Makefile,v 1.1 2004/07/29 20:51:36 dillon Exp $
+# $FreeBSD: src/sys/modules/if_ndis/Makefile,v 1.6 2005/09/27 18:10:35 mlaier Exp $
 
 KMOD=  if_ndis
-SRCS=  if_ndis.c if_ndis_pccard.c if_ndis_pci.c \
-       card_if.h device_if.h bus_if.h pci_if.h
+SRCS=  if_ndis.c if_ndis_pci.c if_ndis_pccard.c if_ndis_usb.c
+SRCS+= device_if.h bus_if.h pci_if.h card_if.h
+SRCS+= opt_usb.h
 
 .include <bsd.kmod.mk>
diff --git a/sys/dev/netif/ndis/README b/sys/dev/netif/ndis/README
deleted file mode 100644 (file)
index d230bc4..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-$DragonFly: src/sys/dev/netif/ndis/README,v 1.2 2008/02/01 08:39:58 hasso Exp $
-                       USING IF_NDIS WITH WINDOWS DEVICE DRIVERS
-
-(1) Locate the .INF and .SYS file for the windows driver.  I have no idea
-    where the official location for these things are but I found the one
-    for the Centrino 2200 chipset (for my Sony TR3A) here:
-
-    http://news.gw.com/freebsd.hardware/4894
-    http://www.powernotebooks.com/Support/intel_2200_wlan.zip
-
-    My MD5 (intel_2200_wlan.zip) = 281812933642f3f2fd54710ee7bba2d4
-    This is unofficial.
-
-(2) Unpack the files into a temporary directory, then copy the appropriate
-    .INF and .SYS file to /usr/local/modules/if_ndis.
-
-    mkdir -p /usr/local/modules/if_ndis
-    cp .... 
-
-(3) Generate a driver module header file using ndiscvt then build and
-    install the module.  The object directory in which you store the
-    header file should match what make obj creates.  If your DFly sources
-    are in /usr/src then the example below will work.
-
-    # cd /usr/src/sys/dev/netif/ndis
-    # make obj
-    # make clean
-    # ndiscvt -i /usr/local/modules/if_ndis/w22n51.INF -s /usr/local/modules/if_ndis/w22n51.sys -o /usr/obj/usr/src/sys/dev/netif/ndis/ndis_driver_data.h
-    # make
-    # make install
-
-(4) Load all required modules into the running kernel:
-
-    # kldload /modules/wlan.ko
-    # kldload /modules/ndis.ko
-    # kldload /modules/if_ndis.ko
-
-    You should get something similar to the following system console
-    messages:
-
-    ndis0: NDIS API version: 5.1
-    ndis0: MAC address: 00:0e:35:15:ee:72
-    ndis0: 11b rates: 1Mbps 2Mbps 5.5Mbps 11Mbps 5.5Mbps 11Mbps
-    ndis0: 11g rates: 6Mbps 9Mbps 12Mbps 18Mbps 24Mbps 36Mbps 48Mbps 54Mbps
-
-(5) Bring the interface up and associate the SSID.  If you aren't sure
-    what your basestation id is you can use 'ifconfig -v ndis0 list scan' to
-    list available ssid's.
-
-    # ifconfig ndis0 up
-    # ifconfig -v ndis0 list scan
-    # ifconfig ssid "your_basestation_id"
-
-(6) Ifconfig should show the interface up and associated.  Run dhclient
-    or ifconfig your IP address. 
-
-    # ifconfig ndis0
-    [should show the interface up and associated]
-    # dhclient ndis0
-
index a367764..0d2f22a 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2003
  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
  *
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/if_ndis/if_ndis.c,v 1.65 2004/07/07 17:46:30 wpaul Exp $
- * $DragonFly: src/sys/dev/netif/ndis/if_ndis.c,v 1.23 2008/08/17 04:32:34 sephe Exp $
+ * $FreeBSD: src/sys/dev/if_ndis/if_ndis.c,v 1.178 2011/01/07 18:41:59 bschmidt Exp $
+ *
+ * WPA support originally contributed by Arvind Srinivasan <arvind@celar.us>
+ * then hacked upon mercilessly by me.
  */
 
 #include <sys/param.h>
 #include <sys/sockio.h>
 #include <sys/mbuf.h>
 #include <sys/malloc.h>
+#include <sys/endian.h>
+#include <sys/priv.h>
 #include <sys/kernel.h>
 #include <sys/socket.h>
 #include <sys/queue.h>
+#include <sys/module.h>
 #include <sys/proc.h>
-#include <sys/priv.h>
 #include <sys/sysctl.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
-#include <sys/serialize.h>
-#include <sys/thread2.h>
+#include <sys/kthread.h>
 
 #include <net/if.h>
-#include <net/ifq_var.h>
 #include <net/if_arp.h>
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
+#include <net/if_types.h>
 #include <net/route.h>
 
 #include <net/bpf.h>
+#include <net/ifq_var.h>
+
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/mplock2.h>
 
 #include <netproto/802_11/ieee80211_var.h>
 #include <netproto/802_11/ieee80211_ioctl.h>
-
-#include <netproto/802_11/if_wavelan_ieee.h>
+#include <netproto/802_11/ieee80211_regdomain.h>
 
 #include <bus/pci/pcireg.h>
 #include <bus/pci/pcivar.h>
+#include <bus/usb/usb.h>
+#include <bus/usb/usbdi.h>
 
-#include <emulation/ndis/regcall.h>
 #include <emulation/ndis/pe_var.h>
+#include <emulation/ndis/cfg_var.h>
 #include <emulation/ndis/resource_var.h>
 #include <emulation/ndis/ntoskrnl_var.h>
 #include <emulation/ndis/hal_var.h>
 #include <emulation/ndis/ndis_var.h>
-#include <emulation/ndis/cfg_var.h>
-#include "if_ndisvar.h"
+#include <emulation/ndis/usbd_var.h>
+#include <dev/netif/ndis/if_ndisvar.h>
+
+#define NDIS_DEBUG
+#ifdef NDIS_DEBUG
+#define DPRINTF(x)     do { if (ndis_debug > 0) kprintf x; } while (0)
+int ndis_debug = 0;
+SYSCTL_INT(_debug, OID_AUTO, ndis, CTLFLAG_RW, &ndis_debug, 0,
+    "if_ndis debug level");
+#else
+#define DPRINTF(x)
+#endif
 
-#define NDIS_IMAGE
-#define NDIS_REGVALS
+SYSCTL_DECL(_hw_ndisusb);
+int ndisusb_halt = 1;
+SYSCTL_INT(_hw_ndisusb, OID_AUTO, halt, CTLFLAG_RW, &ndisusb_halt, 0,
+    "Halt NDIS USB driver when it's attached");
 
-#include "ndis_driver_data.h"
+/* 0 - 30 dBm to mW conversion table */
+static const uint16_t dBm2mW[] = {
+       1, 1, 1, 1, 2, 2, 2, 2, 3, 3,
+       3, 4, 4, 4, 5, 6, 6, 7, 8, 9,
+       10, 11, 13, 14, 16, 18, 20, 22, 25, 28,
+       32, 35, 40, 45, 50, 56, 63, 71, 79, 89,
+       100, 112, 126, 141, 158, 178, 200, 224, 251, 282,
+       316, 355, 398, 447, 501, 562, 631, 708, 794, 891,
+       1000
+};
+
+MODULE_DEPEND(if_ndis, ether, 1, 1, 1);
+MODULE_DEPEND(if_ndis, wlan, 1, 1, 1);
+MODULE_DEPEND(if_ndis, ndis, 1, 1, 1);
+
+MODULE_VERSION(if_ndis, 1);
 
 int ndis_attach                        (device_t);
 int ndis_detach                        (device_t);
@@ -87,39 +121,155 @@ int ndis_suspend          (device_t);
 int ndis_resume                        (device_t);
 void ndis_shutdown             (device_t);
 
-static __stdcall void ndis_txeof       (ndis_handle,
-       ndis_packet *, ndis_status);
-static __stdcall void ndis_rxeof       (ndis_handle,
-       ndis_packet **, uint32_t);
-static __stdcall void ndis_linksts     (ndis_handle,
-       ndis_status, void *, uint32_t);
-static __stdcall void ndis_linksts_done        (ndis_handle);
-
-static void ndis_intr          (void *);
-static void ndis_intrtask      (void *);
+int ndisdrv_modevent           (module_t, int, void *);
+
+static void ndis_txeof         (ndis_handle, ndis_packet *, ndis_status);
+static void ndis_rxeof         (ndis_handle, ndis_packet **, uint32_t);
+static void ndis_rxeof_eth     (ndis_handle, ndis_handle, char *, void *,
+                                uint32_t, void *, uint32_t, uint32_t);
+static void ndis_rxeof_done    (ndis_handle);
+static void ndis_rxeof_xfr     (kdpc *, ndis_handle, void *, void *);
+static void ndis_rxeof_xfr_done        (ndis_handle, ndis_packet *,
+                                uint32_t, uint32_t);
+static void ndis_linksts       (ndis_handle, ndis_status, void *, uint32_t);
+static void ndis_linksts_done  (ndis_handle);
+
+/* We need to wrap these functions for amd64. */
+static funcptr ndis_txeof_wrap;
+static funcptr ndis_rxeof_wrap;
+static funcptr ndis_rxeof_eth_wrap;
+static funcptr ndis_rxeof_done_wrap;
+static funcptr ndis_rxeof_xfr_wrap;
+static funcptr ndis_rxeof_xfr_done_wrap;
+static funcptr ndis_linksts_wrap;
+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 struct  ieee80211vap *ndis_vap_create(struct ieee80211com *,
+                   const char name[IFNAMSIZ], int unit, int opmode,
+                   int flags, const uint8_t bssid[IEEE80211_ADDR_LEN],
+                   const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void ndis_vap_delete    (struct ieee80211vap *);
 static void ndis_tick          (void *);
-static void ndis_ticktask      (void *);
+static void ndis_ticktask      (device_object *, void *);
+static int ndis_raw_xmit       (struct ieee80211_node *, struct mbuf *,
+       const struct ieee80211_bpf_params *);
+static void ndis_update_mcast  (struct ifnet *ifp);
+static void ndis_update_promisc        (struct ifnet *ifp);
 static void ndis_start         (struct ifnet *);
-static void ndis_starttask     (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, struct ucred *);
-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 int ndis_ioctl_80211    (struct ifnet *, u_long, caddr_t, struct ucred *);
+static int ndis_newstate       (struct ieee80211vap *, enum ieee80211_state,
+       int);
+static int ndis_nettype_chan   (uint32_t);
+static int ndis_nettype_mode   (uint32_t);
+static void ndis_scan          (void *);
+static void ndis_scan_results  (struct ndis_softc *);
+static void ndis_scan_start    (struct ieee80211com *);
+static void ndis_scan_end      (struct ieee80211com *);
+static void ndis_set_channel   (struct ieee80211com *);
+static void ndis_scan_curchan  (struct ieee80211_scan_state *, unsigned long);
+static void ndis_scan_mindwell (struct ieee80211_scan_state *);
 static void ndis_init          (void *);
 static void ndis_stop          (struct ndis_softc *);
-static void ndis_watchdog      (struct ifnet *);
 static int ndis_ifmedia_upd    (struct ifnet *);
 static void ndis_ifmedia_sts   (struct ifnet *, struct ifmediareq *);
+static int ndis_get_bssid_list (struct ndis_softc *,
+                                       ndis_80211_bssid_list_ex **);
 static int ndis_get_assoc      (struct ndis_softc *, ndis_wlan_bssid_ex **);
 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 void ndis_auth_and_assoc        (struct ndis_softc *, struct ieee80211vap *);
 static void ndis_media_status  (struct ifnet *, struct ifmediareq *);
+static int ndis_set_cipher     (struct ndis_softc *, int);
+static int ndis_set_wpa                (struct ndis_softc *, void *, int);
+static int ndis_add_key                (struct ieee80211vap *,
+       const struct ieee80211_key *, const u_int8_t []);
+static int ndis_del_key                (struct ieee80211vap *,
+       const struct ieee80211_key *);
 
 static void ndis_setmulti      (struct ndis_softc *);
 static void ndis_map_sclist    (void *, bus_dma_segment_t *,
        int, bus_size_t, int);
 
+static int ndisdrv_loaded = 0;
+
+/*
+ * This routine should call windrv_load() once for each driver
+ * image. This will do the relocation and dynalinking for the
+ * image, and create a Windows driver object which will be
+ * saved in our driver database.
+ */
+int
+ndisdrv_modevent(module_t mod, int cmd, void *arg)
+{
+       int                     error = 0;
+
+       switch (cmd) {
+       case MOD_LOAD:
+               ndisdrv_loaded++;
+                if (ndisdrv_loaded > 1)
+                       break;
+               windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap,
+                   3, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_rxeof_eth, &ndis_rxeof_eth_wrap,
+                   8, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_rxeof_done, &ndis_rxeof_done_wrap,
+                   1, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_rxeof_xfr, &ndis_rxeof_xfr_wrap,
+                   4, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_rxeof_xfr_done,
+                   &ndis_rxeof_xfr_done_wrap, 4, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap,
+                   3, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap,
+                   4, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_linksts_done,
+                   &ndis_linksts_done_wrap, 1, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_ticktask, &ndis_ticktask_wrap,
+                   2, WINDRV_WRAP_STDCALL);
+               windrv_wrap((funcptr)ndis_starttask, &ndis_starttask_wrap,
+                   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--;
+               if (ndisdrv_loaded > 0)
+                       break;
+               /* fallthrough */
+       case MOD_SHUTDOWN:
+               windrv_unwrap(ndis_rxeof_wrap);
+               windrv_unwrap(ndis_rxeof_eth_wrap);
+               windrv_unwrap(ndis_rxeof_done_wrap);
+               windrv_unwrap(ndis_rxeof_xfr_wrap);
+               windrv_unwrap(ndis_rxeof_xfr_done_wrap);
+               windrv_unwrap(ndis_txeof_wrap);
+               windrv_unwrap(ndis_linksts_wrap);
+               windrv_unwrap(ndis_linksts_done_wrap);
+               windrv_unwrap(ndis_ticktask_wrap);
+               windrv_unwrap(ndis_starttask_wrap);
+               windrv_unwrap(ndis_resettask_wrap);
+               windrv_unwrap(ndis_inputtask_wrap);
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+
+       return (error);
+}
+
 /*
  * Program the 64-bit multicast hash filter.
  */
@@ -131,7 +281,7 @@ ndis_setmulti(struct ndis_softc *sc)
        int                     len, mclistsz, error;
        uint8_t                 *mclist;
 
-       ifp = &sc->arpcom.ac_if;
+       ifp = sc->ifp;
 
        if (!NDIS_INITIALIZED(sc))
                return;
@@ -142,12 +292,12 @@ ndis_setmulti(struct ndis_softc *sc)
                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 allmulti failed: %d\n", error);
                return;
        }
 
-       if (LIST_EMPTY(&ifp->if_multiaddrs))
+       if (TAILQ_EMPTY(&ifp->if_multiaddrs))
                return;
 
        len = sizeof(mclistsz);
@@ -163,23 +313,32 @@ ndis_setmulti(struct ndis_softc *sc)
        sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST;
 
        len = 0;
-       LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#if 0 /* XXX swildner */
+       if_maddr_rlock(ifp);
+#endif
+       TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
                if (ifma->ifma_addr->sa_family != AF_LINK)
                        continue;
                bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
                    mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN);
                len++;
                if (len > mclistsz) {
+#if 0 /* XXX swildner */
+                       if_maddr_runlock(ifp);
+#endif
                        sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
                        sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
                        goto out;
                }
        }
+#if 0 /* XXX swildner */
+       if_maddr_runlock(ifp);
+#endif
 
        len = len * ETHER_ADDR_LEN;
        error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len);
        if (error) {
-               device_printf (sc->ndis_dev, "set mclist failed: %d\n", error);
+               device_printf(sc->ndis_dev, "set mclist failed: %d\n", error);
                sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
                sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
        }
@@ -191,7 +350,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);
 }
 
 static int
@@ -203,19 +362,19 @@ ndis_set_offload(struct ndis_softc *sc)
        struct ifnet            *ifp;
        int                     len, error;
 
-       ifp = &sc->arpcom.ac_if;
+       ifp = sc->ifp;
 
        if (!NDIS_INITIALIZED(sc))
-               return(EINVAL);
+               return (EINVAL);
 
        /* See if there's anything to set. */
 
        error = ndis_probe_offload(sc);
        if (error)
-               return(error);
-               
+               return (error);
+
        if (sc->ndis_hwassist == 0 && ifp->if_capabilities == 0)
-               return(0);
+               return (0);
 
        len = sizeof(ndis_task_offload_hdr) + sizeof(ndis_task_offload) +
            sizeof(ndis_task_tcpip_csum);
@@ -223,7 +382,7 @@ ndis_set_offload(struct ndis_softc *sc)
        ntoh = kmalloc(len, M_TEMP, M_NOWAIT|M_ZERO);
 
        if (ntoh == NULL)
-               return(ENOMEM);
+               return (ENOMEM);
 
        ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
        ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
@@ -252,7 +411,7 @@ ndis_set_offload(struct ndis_softc *sc)
        error = ndis_set_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
        kfree(ntoh, M_TEMP);
 
-       return(error);
+       return (error);
 }
 
 static int
@@ -264,18 +423,18 @@ ndis_probe_offload(struct ndis_softc *sc)
        struct ifnet            *ifp;
        int                     len, error, dummy;
 
-       ifp = &sc->arpcom.ac_if;
+       ifp = sc->ifp;
 
        len = sizeof(dummy);
        error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, &dummy, &len);
 
        if (error != ENOSPC)
-               return(error);
+               return (error);
 
        ntoh = kmalloc(len, M_TEMP, M_NOWAIT|M_ZERO);
 
        if (ntoh == NULL)
-               return(ENOMEM);
+               return (ENOMEM);
 
        ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
        ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
@@ -287,12 +446,12 @@ ndis_probe_offload(struct ndis_softc *sc)
 
        if (error) {
                kfree(ntoh, M_TEMP);
-               return(error);
+               return (error);
        }
 
        if (ntoh->ntoh_vers != NDIS_TASK_OFFLOAD_VERSION) {
                kfree(ntoh, M_TEMP);
-               return(EINVAL);
+               return (EINVAL);
        }
 
        nto = (ndis_task_offload *)((char *)ntoh +
@@ -317,7 +476,7 @@ ndis_probe_offload(struct ndis_softc *sc)
 
        if (nttc == NULL) {
                kfree(ntoh, M_TEMP);
-               return(ENOENT);
+               return (ENOENT);
        }
 
        sc->ndis_v4tx = nttc->nttc_v4tx;
@@ -341,7 +500,33 @@ ndis_probe_offload(struct ndis_softc *sc)
                ifp->if_capabilities |= IFCAP_RXCSUM;
 
        kfree(ntoh, M_TEMP);
-       return(0);
+       return (0);
+}
+
+static int
+ndis_nettype_chan(uint32_t type)
+{
+       switch (type) {
+       case NDIS_80211_NETTYPE_11FH:           return (IEEE80211_CHAN_FHSS);
+       case NDIS_80211_NETTYPE_11DS:           return (IEEE80211_CHAN_B);
+       case NDIS_80211_NETTYPE_11OFDM5:        return (IEEE80211_CHAN_A);
+       case NDIS_80211_NETTYPE_11OFDM24:       return (IEEE80211_CHAN_G);
+       }
+       DPRINTF(("unknown channel nettype %d\n", type));
+       return (IEEE80211_CHAN_B);      /* Default to 11B chan */
+}
+
+static int
+ndis_nettype_mode(uint32_t type)
+{
+       switch (type) {
+       case NDIS_80211_NETTYPE_11FH:           return (IEEE80211_MODE_FH);
+       case NDIS_80211_NETTYPE_11DS:           return (IEEE80211_MODE_11B);
+       case NDIS_80211_NETTYPE_11OFDM5:        return (IEEE80211_MODE_11A);
+       case NDIS_80211_NETTYPE_11OFDM24:       return (IEEE80211_MODE_11G);
+       }
+       DPRINTF(("unknown mode nettype %d\n", type));
+       return (IEEE80211_MODE_AUTO);
 }
 
 /*
@@ -353,43 +538,89 @@ ndis_attach(device_t dev)
 {
        u_char                  eaddr[ETHER_ADDR_LEN];
        struct ndis_softc       *sc;
-       struct ifnet            *ifp;
-       void                    *img;
-       int                     error = 0, len;
+       driver_object           *pdrv;
+       device_object           *pdo;
+       struct ifnet            *ifp = NULL;
+       int                     error = 0, len, mode;
+       uint8_t                 bands = 0;
        int                     i;
 
        sc = device_get_softc(dev);
 
-       callout_init(&sc->ndis_stat_timer);
-
-       sc->ndis_regvals = ndis_regvals;
+       lockinit(&sc->ndis_lock, "network driver", 0, LK_CANRECURSE);
+       KeInitializeSpinLock(&sc->ndis_rxlock);
+       KeInitializeSpinLock(&sc->ndisusb_xferlock);
+       InitializeListHead(&sc->ndis_shlist);
+       InitializeListHead(&sc->ndisusb_xferlist);
+       callout_init(&sc->ndis_stat_callout);
 
-#if __FreeBSD_version < 502113
-       sysctl_ctx_init(&sc->ndis_ctx);
+       if (sc->ndis_iftype == PCMCIABus) {
+               error = ndis_alloc_amem(sc);
+               if (error) {
+                       device_printf(dev, "failed to allocate "
+                           "attribute memory\n");
+                       goto fail;
+               }
+       }
 
-#endif
        /* Create sysctl registry nodes */
        ndis_create_sysctls(sc);
 
-       /* Set up driver image in memory. */
-       img = drv_data;
-       ndis_load_driver((vm_offset_t)img, sc);
+       /* Find the PDO for this device instance. */
+
+       if (sc->ndis_iftype == PCIBus)
+               pdrv = windrv_lookup(0, "PCI Bus");
+       else if (sc->ndis_iftype == PCMCIABus)
+               pdrv = windrv_lookup(0, "PCCARD Bus");
+       else
+               pdrv = windrv_lookup(0, "USB Bus");
+       pdo = windrv_find_pdo(pdrv, dev);
+
+       /*
+        * Create a new functional device object for this
+        * device. This is what creates the miniport block
+        * for this device instance.
+        */
+
+       if (NdisAddDevice(sc->ndis_dobj, pdo) != STATUS_SUCCESS) {
+               device_printf(dev, "failed to create FDO!\n");
+               error = ENXIO;
+               goto fail;
+       }
 
        /* Tell the user what version of the API the driver is using. */
        device_printf(dev, "NDIS API version: %d.%d\n",
-           sc->ndis_chars.nmc_version_major,
-           sc->ndis_chars.nmc_version_minor);
+           sc->ndis_chars->nmc_version_major,
+           sc->ndis_chars->nmc_version_minor);
 
        /* Do resource conversion. */
-       ndis_convert_res(sc);
+       if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus)
+               ndis_convert_res(sc);
+       else
+               sc->ndis_block->nmb_rlist = NULL;
 
        /* Install our RX and TX interrupt handlers. */
-       sc->ndis_block.nmb_senddone_func = ndis_txeof;
-       sc->ndis_block.nmb_pktind_func = ndis_rxeof;
+       sc->ndis_block->nmb_senddone_func = ndis_txeof_wrap;
+       sc->ndis_block->nmb_pktind_func = ndis_rxeof_wrap;
+       sc->ndis_block->nmb_ethrxindicate_func = ndis_rxeof_eth_wrap;
+       sc->ndis_block->nmb_ethrxdone_func = ndis_rxeof_done_wrap;
+       sc->ndis_block->nmb_tdcond_func = ndis_rxeof_xfr_done_wrap;
+
+       /* Override the status handler so we can detect link changes. */
+       sc->ndis_block->nmb_status_func = ndis_linksts_wrap;
+       sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap;
+
+       /* Set up work item handlers. */
+       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);
+       sc->ndisusb_xferitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
+       KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block);
 
        /* Call driver's init routine. */
        if (ndis_init_nic(sc)) {
-               device_printf (dev, "init handler failed\n");
+               device_printf(dev, "init handler failed\n");
                error = ENXIO;
                goto fail;
        }
@@ -400,25 +631,45 @@ ndis_attach(device_t dev)
        len = sizeof(eaddr);
        ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len);
 
-       bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
-
        /*
-        * Figure out of 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 = kmalloc(sizeof(ndis_packet *) *
            sc->ndis_maxpkts, M_DEVBUF, M_WAITOK|M_ZERO);
 
+       /* Allocate a pool of ndis_packets for TX encapsulation. */
+
+       NdisAllocatePacketPool(&i, &sc->ndis_txpool,
+           sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET);
+
+       if (i != NDIS_STATUS_SUCCESS) {
+               sc->ndis_txpool = NULL;
+               device_printf(dev, "failed to allocate TX packet pool");
+               error = ENOMEM;
+               goto fail;
+       }
+
        sc->ndis_txpending = sc->ndis_maxpkts;
 
        sc->ndis_oidcnt = 0;
@@ -434,50 +685,68 @@ ndis_attach(device_t dev)
         * supported by this driver. If it is, then this an 802.11
         * wireless driver, and we should set up media for wireless.
         */
-       for (i = 0; i < sc->ndis_oidcnt; i++) {
+       for (i = 0; i < sc->ndis_oidcnt; i++)
                if (sc->ndis_oids[i] == OID_802_11_CONFIGURATION) {
                        sc->ndis_80211++;
                        break;
                }
+
+       if (sc->ndis_80211)
+               ifp = if_alloc(IFT_IEEE80211);
+       else
+               ifp = if_alloc(IFT_ETHER);
+       if (ifp == NULL) {
+               error = ENOSPC;
+               goto fail;
        }
+       sc->ifp = ifp;
+       ifp->if_softc = sc;
 
        /* Check for task offload support. */
        ndis_probe_offload(sc);
 
-       ifp = &sc->arpcom.ac_if;
-       ifp->if_softc = sc;
        if_initname(ifp, device_get_name(dev), device_get_unit(dev));
        ifp->if_mtu = ETHERMTU;
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#if 0
+       if (sc->ndis_iftype == PNPBus)
+               ifp->if_flags |= IFF_NEEDSGIANT;
+#endif
        ifp->if_ioctl = ndis_ioctl;
        ifp->if_start = ndis_start;
-       ifp->if_watchdog = ndis_watchdog;
        ifp->if_init = ndis_init;
        ifp->if_baudrate = 10000000;
        ifq_set_maxlen(&ifp->if_snd, 50);
+#if 0 /* XXX swildner */
+       ifp->if_snd.ifq_drv_maxlen = 25;
+#endif
        ifq_set_ready(&ifp->if_snd);
        ifp->if_capenable = ifp->if_capabilities;
        ifp->if_hwassist = sc->ndis_hwassist;
 
        /* Do media setup */
        if (sc->ndis_80211) {
-               struct ieee80211com     *ic = (void *)ifp;
+               struct ieee80211com     *ic = ifp->if_l2com;
                ndis_80211_rates_ex     rates;
                struct ndis_80211_nettype_list *ntl;
                uint32_t                arg;
                int                     r;
 
-               ic->ic_phytype = IEEE80211_T_DS;
+               callout_init(&sc->ndis_scan_callout);
+
+               ifp->if_ioctl = ndis_ioctl_80211;
+               ic->ic_ifp = ifp;
                ic->ic_opmode = IEEE80211_M_STA;
-               ic->ic_caps = IEEE80211_C_IBSS;
-               ic->ic_state = IEEE80211_S_ASSOC;
-               ic->ic_modecaps = (1<<IEEE80211_MODE_AUTO);
+               ic->ic_phytype = IEEE80211_T_DS;
+               ic->ic_caps = IEEE80211_C_8023ENCAP |
+                       IEEE80211_C_STA | IEEE80211_C_IBSS;
+               setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO);
                len = 0;
                r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
                    NULL, &len);
                if (r != ENOSPC)
                        goto nonettypes;
-               ntl = kmalloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
+               ntl = kmalloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
                r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
                    ntl, &len);
                if (r != 0) {
@@ -486,29 +755,27 @@ ndis_attach(device_t dev)
                }
 
                for (i = 0; i < ntl->ntl_items; i++) {
-                       switch (ntl->ntl_type[i]) {
-                       case NDIS_80211_NETTYPE_11FH:
-                       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;
-                       }
+                       mode = ndis_nettype_mode(ntl->ntl_type[i]);
+                       if (mode) {
+                               setbit(ic->ic_modecaps, mode);
+                               setbit(&bands, mode);
+                       } else
+                               device_printf(dev, "Unknown nettype %d\n",
+                                   ntl->ntl_type[i]);
                }
                kfree(ntl, M_DEVBUF);
 nonettypes:
+               /* Default to 11b channels if the card did not supply any */
+               if (bands == 0) {
+                       setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
+                       setbit(&bands, IEEE80211_MODE_11B);
+               }
                len = sizeof(rates);
                bzero((char *)&rates, len);
                r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES,
                    (void *)rates, &len);
                if (r)
-                       device_printf (dev, "get rates failed: 0x%x\n", r);
+                       device_printf(dev, "get rates failed: 0x%x\n", r);
                /*
                 * 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
@@ -534,11 +801,11 @@ nonettypes:
        ic->ic_sup_rates[x].rs_nrates++
 
                ic->ic_curmode = IEEE80211_MODE_AUTO;
-               if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A))
+               if (isset(ic->ic_modecaps, IEEE80211_MODE_11A))
                        ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0;
-               if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B))
+               if (isset(ic->ic_modecaps, IEEE80211_MODE_11B))
                        ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0;
-               if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G))
+               if (isset(ic->ic_modecaps, 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) {
@@ -547,11 +814,10 @@ nonettypes:
                        case 11:
                        case 10:
                        case 22:
-                               if (!(ic->ic_modecaps &
-                                   (1<<IEEE80211_MODE_11B))) {
+                               if (isclr(ic->ic_modecaps, IEEE80211_MODE_11B)) {
                                        /* Lazy-init 802.11b. */
-                                       ic->ic_modecaps |=
-                                           (1<<IEEE80211_MODE_11B);
+                                       setbit(ic->ic_modecaps,
+                                           IEEE80211_MODE_11B);
                                        ic->ic_sup_rates[IEEE80211_MODE_11B].
                                            rs_nrates = 0;
                                }
@@ -559,11 +825,11 @@ nonettypes:
                                INCRATE(IEEE80211_MODE_11B);
                                break;
                        default:
-                               if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
+                               if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) {
                                        SETRATE(IEEE80211_MODE_11A, rates[i]);
                                        INCRATE(IEEE80211_MODE_11A);
                                }
-                               if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
+                               if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) {
                                        SETRATE(IEEE80211_MODE_11G, rates[i]);
                                        INCRATE(IEEE80211_MODE_11G);
                                }
@@ -578,7 +844,7 @@ nonettypes:
                 * just cheat here.  Just how in the heck do
                 * we detect turbo modes, though?
                 */
-               if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
+               if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) {
                        TESTSETRATE(IEEE80211_MODE_11B,
                            IEEE80211_RATE_BASIC|2);
                        TESTSETRATE(IEEE80211_MODE_11B,
@@ -588,54 +854,92 @@ nonettypes:
                        TESTSETRATE(IEEE80211_MODE_11B,
                            IEEE80211_RATE_BASIC|22);
                }
-               if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
-                       TESTSETRATE(IEEE80211_MODE_11G, 47);
+               if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) {
+                       TESTSETRATE(IEEE80211_MODE_11G, 48);
                        TESTSETRATE(IEEE80211_MODE_11G, 72);
                        TESTSETRATE(IEEE80211_MODE_11G, 96);
                        TESTSETRATE(IEEE80211_MODE_11G, 108);
                }
-               if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
-                       TESTSETRATE(IEEE80211_MODE_11A, 47);
+               if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) {
+                       TESTSETRATE(IEEE80211_MODE_11A, 48);
                        TESTSETRATE(IEEE80211_MODE_11A, 72);
                        TESTSETRATE(IEEE80211_MODE_11A, 96);
                        TESTSETRATE(IEEE80211_MODE_11A, 108);
                }
 #undef SETRATE
 #undef INCRATE
+               ieee80211_init_channels(ic, NULL, &bands);
+
                /*
-                * Taking yet more guesses here.
+                * To test for WPA support, we need to see if we can
+                * set AUTHENTICATION_MODE to WPA and read it back
+                * successfully.
                 */
-               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 (ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates &&
-                           i > 14)
-                               chanflag = IEEE80211_CHAN_A;
-                       if (chanflag == 0)
-                               break;
-                       ic->ic_channels[i].ic_freq =
-                           ieee80211_ieee2mhz(i, chanflag);
-                       ic->ic_channels[i].ic_flags = chanflag;
+               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)
-                       ic->ic_caps |= IEEE80211_C_WEP;
+               arg = NDIS_80211_WEPSTAT_ENC3ENABLED;
+               r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
+               if (r == 0) {
+                       ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP
+                                         |  IEEE80211_CRYPTO_TKIP
+                                         |  IEEE80211_CRYPTO_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_cryptocaps |= IEEE80211_CRYPTO_WEP
+                                         |  IEEE80211_CRYPTO_TKIP;
+                       goto got_crypto;
+               }
+               arg = NDIS_80211_WEPSTAT_ENC1ENABLED;
+               r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
+               if (r == 0)
+                       ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP;
+got_crypto:
                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));
-               ieee80211_ifattach(ic);
-               ieee80211_media_init(ic, ieee80211_media_change,
-                   ndis_media_status);
-               ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
-               ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+
+               r = ndis_get_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &i);
+               if (r == 0)
+                       ic->ic_caps |= IEEE80211_C_TXPMGT;
+
+               ieee80211_ifattach(ic, eaddr);
+               ic->ic_raw_xmit = ndis_raw_xmit;
+               ic->ic_scan_start = ndis_scan_start;
+               ic->ic_scan_end = ndis_scan_end;
+               ic->ic_set_channel = ndis_set_channel;
+               ic->ic_scan_curchan = ndis_scan_curchan;
+               ic->ic_scan_mindwell = ndis_scan_mindwell;
+               ic->ic_bsschan = IEEE80211_CHAN_ANYC;
+               //ic->ic_bss->ni_chan = ic->ic_bsschan;
+               ic->ic_vap_create = ndis_vap_create;
+               ic->ic_vap_delete = ndis_vap_delete;
+               ic->ic_update_mcast = ndis_update_mcast;
+               ic->ic_update_promisc = ndis_update_promisc;
+
+               if (bootverbose)
+                       ieee80211_announce(ic);
+
        } else {
                ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd,
                    ndis_ifmedia_sts);
@@ -649,29 +953,65 @@ nonettypes:
                ether_ifattach(ifp, eaddr, NULL);
        }
 
-       if (error == 0) {
-               error = bus_setup_intr(dev, sc->ndis_irq, INTR_MPSAFE,
-                                      ndis_intr, sc,
-                                      &sc->ndis_intrhand, 
-                                      ifp->if_serializer);
-               if (error) {
-                       device_printf(dev, "couldn't set up irq\n");
-                       goto fail;
-               }
+fail:
+       if (error) {
+               ndis_detach(dev);
+               return (error);
        }
 
+       if (sc->ndis_iftype == PNPBus && ndisusb_halt == 0)
+               return (error);
 
-       /* Override the status handler so we can detect link changes. */
-       sc->ndis_block.nmb_status_func = ndis_linksts;
-       sc->ndis_block.nmb_statusdone_func = ndis_linksts_done;
-fail:
-       if (error)
-               ndis_detach(dev);
-       else
-               /* We're done talking to the NIC for now; halt it. */
-               ndis_halt_nic(sc);
+       DPRINTF(("attach done.\n"));
+       /* We're done talking to the NIC for now; halt it. */
+       ndis_halt_nic(sc);
+       DPRINTF(("halting done.\n"));
 
-       return(error);
+       return (error);
+}
+
+static struct ieee80211vap *
+ndis_vap_create(struct ieee80211com *ic,
+       const char name[IFNAMSIZ], int unit, int opmode, int flags,
+       const uint8_t bssid[IEEE80211_ADDR_LEN],
+       const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+       struct ndis_vap *nvp;
+       struct ieee80211vap *vap;
+
+       if (!TAILQ_EMPTY(&ic->ic_vaps))         /* only one at a time */
+               return NULL;
+       nvp = (struct ndis_vap *) kmalloc(sizeof(struct ndis_vap),
+           M_80211_VAP, M_NOWAIT | M_ZERO);
+       if (nvp == NULL)
+               return NULL;
+       vap = &nvp->vap;
+       ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
+       /* override with driver methods */
+       nvp->newstate = vap->iv_newstate;
+       vap->iv_newstate = ndis_newstate;
+
+       /* complete setup */
+       ieee80211_vap_attach(vap, ieee80211_media_change, ndis_media_status);
+       ic->ic_opmode = opmode;
+       /* install key handing routines */
+       vap->iv_key_set = ndis_add_key;
+       vap->iv_key_delete = ndis_del_key;
+       return vap;
+}
+
+static void
+ndis_vap_delete(struct ieee80211vap *vap)
+{
+       struct ndis_vap *nvp = NDIS_VAP(vap);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ifnet *ifp = ic->ic_ifp;
+       struct ndis_softc *sc = ifp->if_softc;
+
+       ndis_stop(sc);
+       callout_stop(&sc->ndis_scan_callout); /* XXX swildner callout_drain() */
+       ieee80211_vap_detach(vap);
+       kfree(nvp, M_80211_VAP);
 }
 
 /*
@@ -686,24 +1026,36 @@ ndis_detach(device_t dev)
 {
        struct ndis_softc       *sc;
        struct ifnet            *ifp;
+       driver_object           *drv;
 
        sc = device_get_softc(dev);
-       ifp = &sc->arpcom.ac_if;
-
-       ifp->if_flags &= ~IFF_UP;
+       ifp = sc->ifp;
+       if (ifp != NULL)
+               ifp->if_flags &= ~IFF_UP;
 
        if (device_is_attached(dev)) {
-               lwkt_serialize_enter(ifp->if_serializer);
                ndis_stop(sc);
-               bus_teardown_intr(dev, sc->ndis_irq, sc->ndis_intrhand);
-               lwkt_serialize_exit(ifp->if_serializer);
-
-               if (sc->ndis_80211)
-                       ieee80211_ifdetach(&sc->ic);
-               else
-                       ether_ifdetach(ifp);
+               if (ifp != NULL) {
+                       if (sc->ndis_80211)
+                               ieee80211_ifdetach(ifp->if_l2com);
+                       else
+                               ether_ifdetach(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);
+       if (sc->ndisusb_xferitem != NULL)
+               IoFreeWorkItem(sc->ndisusb_xferitem);
+
        bus_generic_detach(dev);
+       ndis_unload_driver(sc);
 
        if (sc->ndis_irq)
                bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq);
@@ -717,18 +1069,40 @@ ndis_detach(device_t dev)
                bus_release_resource(dev, SYS_RES_MEMORY,
                    sc->ndis_altmem_rid, sc->ndis_res_altmem);
 
+       if (ifp != NULL)
+               if_free(ifp);
+
+       if (sc->ndis_iftype == PCMCIABus)
+               ndis_free_amem(sc);
+
        if (sc->ndis_sc)
                ndis_destroy_dma(sc);
 
-       ndis_unload_driver((void *)ifp);
+       if (sc->ndis_txarray)
+               kfree(sc->ndis_txarray, M_DEVBUF);
+
+       if (!sc->ndis_80211)
+               ifmedia_removeall(&sc->ifmedia);
+
+       if (sc->ndis_txpool != NULL)
+               NdisFreePacketPool(sc->ndis_txpool);
+
+       /* Destroy the PDO for this device. */
+
+       if (sc->ndis_iftype == PCIBus)
+               drv = windrv_lookup(0, "PCI Bus");
+       else if (sc->ndis_iftype == PCMCIABus)
+               drv = windrv_lookup(0, "PCCARD Bus");
+       else
+               drv = windrv_lookup(0, "USB Bus");
+       if (drv == NULL)
+               panic("couldn't find driver object");
+       windrv_destroy_pdo(drv, dev);
 
        if (sc->ndis_iftype == PCIBus)
                bus_dma_tag_destroy(sc->ndis_parent_tag);
 
-#if __FreeBSD_version < 502113
-       sysctl_ctx_free(&sc->ndis_ctx);
-#endif
-       return(0);
+       return (0);
 }
 
 int
@@ -737,16 +1111,17 @@ ndis_suspend(device_t dev)
        struct ndis_softc       *sc;
        struct ifnet            *ifp;
 
+       wlan_serialize_enter();
        sc = device_get_softc(dev);
-       ifp = &sc->arpcom.ac_if;
-       lwkt_serialize_enter(ifp->if_serializer);
+       ifp = sc->ifp;
 
 #ifdef notdef
        if (NDIS_INITIALIZED(sc))
-               ndis_stop(sc);
+               ndis_stop(sc);
 #endif
-       lwkt_serialize_exit(ifp->if_serializer);
-       return(0);
+
+       wlan_serialize_exit();
+       return (0);
 }
 
 int
@@ -755,114 +1130,376 @@ ndis_resume(device_t dev)
        struct ndis_softc       *sc;
        struct ifnet            *ifp;
 
+       wlan_serialize_enter();
        sc = device_get_softc(dev);
-       ifp = &sc->arpcom.ac_if;
+       ifp = sc->ifp;
 
-       lwkt_serialize_enter(ifp->if_serializer);
        if (NDIS_INITIALIZED(sc))
-               ndis_init(sc);
-       lwkt_serialize_exit(ifp->if_serializer);
+               ndis_init(sc);
 
-       return(0);
+       wlan_serialize_exit();
+       return (0);
 }
 
 /*
- * A frame has been uploaded: pass the resulting mbuf chain up to
- * the higher level protocols.
- *
- * When handling received NDIS packets, the 'status' field in the
- * out-of-band portion of the ndis_packet has special meaning. In the
- * most common case, the underlying NDIS driver will set this field
- * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
- * take posession of it. We then change the status field to
- * NDIS_STATUS_PENDING to tell the driver that we now own the packet,
- * and that we will return it at some point in the future via the
- * return packet handler.
- *
- * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
- * this means the driver is running out of packet/buffer resources and
- * wants to maintain ownership of the packet. In this case, we have to
- * copy the packet data into local storage and let the driver keep the
- * packet.
+ * 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.
  */
-__stdcall static void
-ndis_rxeof(ndis_handle adapter, ndis_packet **packets, uint32_t pktcnt)
+static void
+ndis_rxeof_eth(ndis_handle adapter, ndis_handle ctx, char *addr, void *hdr,
+    uint32_t hdrlen, void *lookahead, uint32_t lookaheadlen, uint32_t pktlen)
 {
-       struct ndis_softc       *sc;
        ndis_miniport_block     *block;
+       uint8_t                 irql = 0;
+       uint32_t                status;
+       ndis_buffer             *b;
        ndis_packet             *p;
-       uint32_t                s;
-       ndis_tcpip_csum         *csum;
-       struct ifnet            *ifp;
-       struct mbuf             *m0, *m;
-       int                     i;
+       struct mbuf             *m;
+       ndis_ethpriv            *priv;
 
-       block = (ndis_miniport_block *)adapter;
-       sc = (struct ndis_softc *)(block->nmb_ifp);
-       ifp = block->nmb_ifp;
+       block = adapter;
 
-       for (i = 0; i < pktcnt; i++) {
-               p = packets[i];
-               /* Stash the softc here so ptom can use it. */
-               p->np_softc = sc;
-               if (ndis_ptom(&m0, p)) {
-                       device_printf (sc->ndis_dev, "ptom failed\n");
-                       if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
-                               ndis_return_packet(sc, p);
-               } else {
-                       if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
-                               m = m_dup(m0, MB_DONTWAIT);
-                               /*
-                                * NOTE: we want to destroy the mbuf here, but
-                                * we don't actually want to return it to the
-                                * driver via the return packet handler. By
-                                * bumping np_refcnt, we can prevent the
-                                * ndis_return_packet() routine from actually
-                                * doing anything.
-                                */
-                               p->np_refcnt++;
-                               m_freem(m0);
-                               if (m == NULL)
-                                       ifp->if_ierrors++;
-                               else
-                                       m0 = m;
-                       } else
-                               p->np_oob.npo_status = NDIS_STATUS_PENDING;
-                       m0->m_pkthdr.rcvif = ifp;
-                       ifp->if_ipackets++;
+       m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
+       if (m == NULL)
+               return;
 
-                       /* Deal with checksum offload. */
+       /* Save the data provided to us so far. */
 
-                       if (ifp->if_capenable & IFCAP_RXCSUM &&
-                           p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) {
-                               s = (uintptr_t)
-                                   p->np_ext.npe_info[ndis_tcpipcsum_info];
-                               csum = (ndis_tcpip_csum *)&s;
-                               if (csum->u.ntc_rxflags &
-                                   NDIS_RXCSUM_IP_PASSED)
-                                       m0->m_pkthdr.csum_flags |=
-                                           CSUM_IP_CHECKED|CSUM_IP_VALID;
-                               if (csum->u.ntc_rxflags &
-                                   (NDIS_RXCSUM_TCP_PASSED |
-                                   NDIS_RXCSUM_UDP_PASSED)) {
-                                       m0->m_pkthdr.csum_flags |=
-                                           CSUM_DATA_VALID|CSUM_PSEUDO_HDR|
-                                           CSUM_FRAG_NOT_CHECKED;
-                                       m0->m_pkthdr.csum_data = 0xFFFF;
-                               }
-                       }
+       m->m_len = lookaheadlen + hdrlen;
+       m->m_pkthdr.len = pktlen + hdrlen;
+       m->m_next = NULL;
+       m_copyback(m, 0, hdrlen, hdr);
+       m_copyback(m, hdrlen, lookaheadlen, lookahead);
 
-                       ifp->if_input(ifp, m0);
-               }
+       /* Now create a fake NDIS_PACKET to hold the data */
+
+       NdisAllocatePacket(&status, &p, block->nmb_rxpool);
+
+       if (status != NDIS_STATUS_SUCCESS) {
+               m_freem(m);
+               return;
+       }
+
+       p->np_m0 = m;
+
+       b = IoAllocateMdl(m->m_data, m->m_pkthdr.len, FALSE, FALSE, NULL);
+
+       if (b == NULL) {
+               NdisFreePacket(p);
+               m_freem(m);
+               return;
        }
+
+       p->np_private.npp_head = p->np_private.npp_tail = b;
+       p->np_private.npp_totlen = m->m_pkthdr.len;
+
+       /* Save the packet RX context somewhere. */
+       priv = (ndis_ethpriv *)&p->np_protocolreserved;
+       priv->nep_ctx = ctx;
+
+       if (!NDIS_SERIALIZED(block))
+               KeAcquireSpinLock(&block->nmb_lock, &irql);
+
+       InsertTailList((&block->nmb_packetlist), (&p->np_list));
+
+       if (!NDIS_SERIALIZED(block))
+               KeReleaseSpinLock(&block->nmb_lock, irql);
 }
 
 /*
- * A frame was downloaded to the chip. It's safe for us to clean up
- * the list buffers.
+ * NdisMEthIndicateReceiveComplete() handler, runs at DISPATCH_LEVEL
+ * for serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
+ * miniports.
  */
-__stdcall static void
-ndis_txeof(ndis_handle adapter, ndis_packet *packet, ndis_status status)
+static void
+ndis_rxeof_done(ndis_handle adapter)
+{
+       struct ndis_softc       *sc;
+       ndis_miniport_block     *block;
+
+       block = adapter;
+
+       /* Schedule transfer/RX of queued packets. */
+
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+
+       KeInsertQueueDpc(&sc->ndis_rxdpc, NULL, NULL);
+}
+
+/*
+ * MiniportTransferData() handler, runs at DISPATCH_LEVEL.
+ */
+static void
+ndis_rxeof_xfr(kdpc *dpc, ndis_handle adapter, void *sysarg1, void *sysarg2)
+{
+       ndis_miniport_block     *block;
+       struct ndis_softc       *sc;
+       ndis_packet             *p;
+       list_entry              *l;
+       uint32_t                status;
+       ndis_ethpriv            *priv;
+       struct ifnet            *ifp;
+       struct mbuf             *m;
+
+       block = adapter;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       ifp = sc->ifp;
+
+       KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
+
+       l = block->nmb_packetlist.nle_flink;
+       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;
+               p->np_softc = sc;
+               p->np_m0 = NULL;
+
+               KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
+
+               status = MSCALL6(sc->ndis_chars->nmc_transferdata_func,
+                   p, &p->np_private.npp_totlen, block, priv->nep_ctx,
+                   m->m_len, m->m_pkthdr.len - m->m_len);
+
+               KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
+
+               /*
+                * If status is NDIS_STATUS_PENDING, do nothing and
+                * wait for a callback to the ndis_rxeof_xfr_done()
+                * handler.
+                */
+
+               m->m_len = m->m_pkthdr.len;
+               m->m_pkthdr.rcvif = ifp;
+
+               if (status == NDIS_STATUS_SUCCESS) {
+                       IoFreeMdl(p->np_private.npp_head);
+                       NdisFreePacket(p);
+                       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)
+                       m_freem(m);
+
+               /* Advance to next packet */
+               l = block->nmb_packetlist.nle_flink;
+       }
+
+       KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
+}
+
+/*
+ * NdisMTransferDataComplete() handler, runs at DISPATCH_LEVEL.
+ */
+static void
+ndis_rxeof_xfr_done(ndis_handle adapter, ndis_packet *packet, uint32_t status,
+    uint32_t len)
+{
+       ndis_miniport_block     *block;
+       struct ndis_softc       *sc;
+       struct ifnet            *ifp;
+       struct mbuf             *m;
+
+       block = adapter;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       ifp = sc->ifp;
+
+       m = packet->np_m0;
+       IoFreeMdl(packet->np_private.npp_head);
+       NdisFreePacket(packet);
+
+       if (status != NDIS_STATUS_SUCCESS) {
+               m_freem(m);
+               return;
+       }
+
+       m->m_len = m->m_pkthdr.len;
+       m->m_pkthdr.rcvif = ifp;
+       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);
+}
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ *
+ * When handling received NDIS packets, the 'status' field in the
+ * out-of-band portion of the ndis_packet has special meaning. In the
+ * most common case, the underlying NDIS driver will set this field
+ * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
+ * take posession of it. We then change the status field to
+ * NDIS_STATUS_PENDING to tell the driver that we now own the packet,
+ * and that we will return it at some point in the future via the
+ * return packet handler.
+ *
+ * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
+ * this means the driver is running out of packet/buffer resources and
+ * wants to maintain ownership of the packet. In this case, we have to
+ * copy the packet data into local storage and let the driver keep the
+ * packet.
+ */
+static void
+ndis_rxeof(ndis_handle adapter, ndis_packet **packets, uint32_t pktcnt)
+{
+       struct ndis_softc       *sc;
+       ndis_miniport_block     *block;
+       ndis_packet             *p;
+       uint32_t                s;
+       ndis_tcpip_csum         *csum;
+       struct ifnet            *ifp;
+       struct mbuf             *m0, *m;
+       int                     i;
+
+       block = (ndis_miniport_block *)adapter;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       ifp = sc->ifp;
+
+       /*
+        * There's a slim chance the driver may indicate some packets
+        * before we're completely ready to handle them. If we detect this,
+        * we need to return them to the miniport and ignore them.
+        */
+        if (!(ifp->if_flags & IFF_RUNNING)) {
+               for (i = 0; i < pktcnt; i++) {
+                       p = packets[i];
+                       if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) {
+                               p->np_refcnt++;
+                               ndis_return_packet(p);
+                       }
+               }
+               return;
+        }
+
+       for (i = 0; i < pktcnt; i++) {
+               p = packets[i];
+               /* Stash the softc here so ptom can use it. */
+               p->np_softc = sc;
+               if (ndis_ptom(&m0, p)) {
+                       device_printf(sc->ndis_dev, "ptom failed\n");
+                       if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
+                               ndis_return_packet(p);
+               } else {
+#ifdef notdef
+                       if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
+                               m = m_dup(m0, MB_DONTWAIT);
+                               /*
+                                * NOTE: we want to destroy the mbuf here, but
+                                * we don't actually want to return it to the
+                                * driver via the return packet handler. By
+                                * bumping np_refcnt, we can prevent the
+                                * ndis_return_packet() routine from actually
+                                * doing anything.
+                                */
+                               p->np_refcnt++;
+                               m_freem(m0);
+                               if (m == NULL)
+                                       ifp->if_ierrors++;
+                               else
+                                       m0 = m;
+                       } else
+                               p->np_oob.npo_status = NDIS_STATUS_PENDING;
+#endif
+                       m = m_dup(m0, MB_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;
+
+                       /* Deal with checksum offload. */
+
+                       if (ifp->if_capenable & IFCAP_RXCSUM &&
+                           p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) {
+                               s = (uintptr_t)
+                                   p->np_ext.npe_info[ndis_tcpipcsum_info];
+                               csum = (ndis_tcpip_csum *)&s;
+                               if (csum->u.ntc_rxflags &
+                                   NDIS_RXCSUM_IP_PASSED)
+                                       m0->m_pkthdr.csum_flags |=
+                                           CSUM_IP_CHECKED|CSUM_IP_VALID;
+                               if (csum->u.ntc_rxflags &
+                                   (NDIS_RXCSUM_TCP_PASSED |
+                                   NDIS_RXCSUM_UDP_PASSED)) {
+                                       m0->m_pkthdr.csum_flags |=
+                                           CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
+                                       m0->m_pkthdr.csum_data = 0xFFFF;
+                               }
+                       }
+
+                       KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
+                       IF_ENQUEUE(&sc->ndis_rxqueue, m0);
+                       KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
+                       IoQueueWorkItem(sc->ndis_inputitem,
+                           (io_workitem_func)ndis_inputtask_wrap,
+                           WORKQUEUE_CRITICAL, ifp);
+               }
+       }
+}
+
+/*
+ * 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(device_object *dobj, void *arg)
+{
+       ndis_miniport_block     *block;
+       struct ifnet            *ifp;
+       struct ndis_softc       *sc;
+       struct mbuf             *m;
+       struct ieee80211com     *ic;
+       struct ieee80211vap     *vap;
+       uint8_t                 irql;
+
+       ifp = arg;
+       sc = ifp->if_softc;
+       ic = ifp->if_l2com;
+       vap = TAILQ_FIRST(&ic->ic_vaps);
+       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);
+               if ((sc->ndis_80211 != 0) && (vap != NULL))
+                       vap->iv_deliver_data(vap, vap->iv_bss, m);
+               else
+                       (*ifp->if_input)(ifp, m);
+               KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
+       }
+       KeReleaseSpinLock(&sc->ndis_rxlock, irql);
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+static void
+ndis_txeof(ndis_handle adapter, ndis_packet *packet, ndis_status status)
 {
        struct ndis_softc       *sc;
        ndis_miniport_block     *block;
@@ -871,8 +1508,8 @@ ndis_txeof(ndis_handle adapter, ndis_packet *packet, ndis_status status)
        struct mbuf             *m;
 
        block = (ndis_miniport_block *)adapter;
-       sc = (struct ndis_softc *)block->nmb_ifp;
-       ifp = block->nmb_ifp;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       ifp = sc->ifp;
 
        m = packet->np_m0;
        idx = packet->np_txidx;
@@ -882,6 +1519,7 @@ ndis_txeof(ndis_handle adapter, ndis_packet *packet, ndis_status status)
        ndis_free_packet(packet);
        m_freem(m);
 
+       NDISMTX_LOCK(sc);
        sc->ndis_txarray[idx] = NULL;
        sc->ndis_txpending++;
 
@@ -889,22 +1527,55 @@ ndis_txeof(ndis_handle adapter, ndis_packet *packet, ndis_status status)
                ifp->if_opackets++;
        else
                ifp->if_oerrors++;
-       ifp->if_timer = 0;
+
+       sc->ndis_tx_timer = 0;
        ifp->if_flags &= ~IFF_OACTIVE;
 
-       ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
+       NDISMTX_UNLOCK(sc);
+
+       IoQueueWorkItem(sc->ndis_startitem,
+           (io_workitem_func)ndis_starttask_wrap,
+           WORKQUEUE_CRITICAL, ifp);
 }
 
-__stdcall static void
-ndis_linksts(ndis_handle adapter, ndis_status status, void *sbuf, uint32_t slen)
+static void
+ndis_linksts(ndis_handle adapter, ndis_status status, void *sbuf,
+    uint32_t slen)
 {
        ndis_miniport_block     *block;
+       struct ndis_softc       *sc;
 
        block = adapter;
-       block->nmb_getstat = status;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       sc->ndis_sts = status;
+
+       /* Event list is all full up, drop this one. */
+
+       NDISMTX_LOCK(sc);
+       if (sc->ndis_evt[sc->ndis_evtpidx].ne_sts) {
+               NDISMTX_UNLOCK(sc);
+               return;
+       }
+
+       /* Cache the event. */
+
+       if (slen) {
+               sc->ndis_evt[sc->ndis_evtpidx].ne_buf = kmalloc(slen,
+                   M_TEMP, M_NOWAIT);
+               if (sc->ndis_evt[sc->ndis_evtpidx].ne_buf == NULL) {
+                       NDISMTX_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);
+       NDISMTX_UNLOCK(sc);
 }
 
-__stdcall static void
+static void
 ndis_linksts_done(ndis_handle adapter)
 {
        ndis_miniport_block     *block;
@@ -912,20 +1583,26 @@ ndis_linksts_done(ndis_handle adapter)
        struct ifnet            *ifp;
 
        block = adapter;
-       ifp = block->nmb_ifp;
-       sc = ifp->if_softc;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       ifp = sc->ifp;
 
        if (!NDIS_INITIALIZED(sc))
                return;
 
-       switch (block->nmb_getstat) {
+       switch (sc->ndis_sts) {
        case NDIS_STATUS_MEDIA_CONNECT:
-               ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
-               ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
+               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)
-                       ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
+                       IoQueueWorkItem(sc->ndis_tickitem,
+                           (io_workitem_func)ndis_ticktask_wrap,
+                           WORKQUEUE_CRITICAL, sc);
                break;
        default:
                break;
@@ -933,115 +1610,96 @@ ndis_linksts_done(ndis_handle adapter)
 }
 
 static void
-ndis_intrtask(void *arg)
-{
-       struct ndis_softc       *sc;
-       struct ifnet            *ifp;
-       uint8_t                 irql;
-
-       sc = arg;
-       ifp = &sc->arpcom.ac_if;
-
-       lwkt_serialize_enter(ifp->if_serializer);
-       irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
-       ndis_intrhand(sc);
-       FASTCALL1(hal_lower_irql, irql);
-       ndis_enable_intr(sc);
-       lwkt_serialize_exit(ifp->if_serializer);
-}
-
-static void
-ndis_intr(void *arg)
+ndis_tick(void *xsc)
 {
        struct ndis_softc       *sc;
-       struct ifnet            *ifp;
-       int                     is_our_intr = 0;
-       int                     call_isr = 0;
-
-       sc = arg;
-       ifp = &sc->arpcom.ac_if;
 
-       if (sc->ndis_block.nmb_miniportadapterctx == NULL)
-               return;
+       sc = xsc;
 
-       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;
+       if (sc->ndis_hang_timer && --sc->ndis_hang_timer == 0) {
+               IoQueueWorkItem(sc->ndis_tickitem,
+                   (io_workitem_func)ndis_ticktask_wrap,
+                   WORKQUEUE_CRITICAL, sc);
+               sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs;
        }
 
-       if ((is_our_intr || call_isr))
-               ndis_sched(ndis_intrtask, ifp, NDIS_SWI);
-}
-
-static void
-ndis_tick(void *xsc)
-{
-       struct ndis_softc       *sc;
+       if (sc->ndis_tx_timer && --sc->ndis_tx_timer == 0) {
+               sc->ifp->if_oerrors++;
+               device_printf(sc->ndis_dev, "watchdog timeout\n");
 
-       sc = xsc;
+               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, sc->ifp);
+       }
 
-       ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
-       callout_reset(&sc->ndis_stat_timer,
-                     hz *sc->ndis_block.nmb_checkforhangsecs, ndis_tick, sc);
+       callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc);
 }
 
 static void
-ndis_ticktask(void *xsc)
+ndis_ticktask(device_object *d, void *xsc)
 {
        struct ndis_softc       *sc;
-       struct ifnet            *ifp;
-       __stdcall ndis_checkforhang_handler hangfunc;
+       struct ieee80211com     *ic;
+       struct ieee80211vap     *vap;
+       ndis_checkforhang_handler hangfunc;
        uint8_t                 rval;
-       ndis_media_state        linkstate;
-       int                     error, len;
 
        sc = xsc;
-       ifp = &sc->arpcom.ac_if;
+       ic = sc->ifp->if_l2com;
+       vap = TAILQ_FIRST(&ic->ic_vaps);
+
+       NDIS_LOCK(sc);
+       if (!NDIS_INITIALIZED(sc)) {
+               NDIS_UNLOCK(sc);
+               return;
+       }
+       NDIS_UNLOCK(sc);
 
-       lwkt_serialize_enter(ifp->if_serializer);
-       hangfunc = sc->ndis_chars.nmc_checkhang_func;
+       hangfunc = sc->ndis_chars->nmc_checkhang_func;
 
        if (hangfunc != NULL) {
-               rval = hangfunc(sc->ndis_block.nmb_miniportadapterctx);
+               rval = MSCALL1(hangfunc,
+                   sc->ndis_block->nmb_miniportadapterctx);
                if (rval == TRUE) {
                        ndis_reset_nic(sc);
-                       lwkt_serialize_exit(ifp->if_serializer);
                        return;
                }
        }
 
-       len = sizeof(linkstate);
-       error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
-           (void *)&linkstate, &len);
-
-       if (sc->ndis_link == 0 && linkstate == nmc_connected) {
-               device_printf(sc->ndis_dev, "link up\n");
+       NDIS_LOCK(sc);
+       if (sc->ndis_link == 0 &&
+           sc->ndis_sts == NDIS_STATUS_MEDIA_CONNECT) {
                sc->ndis_link = 1;
-               if (sc->ndis_80211)
+               NDIS_UNLOCK(sc);
+               if ((sc->ndis_80211 != 0) && (vap != NULL)) {
                        ndis_getstate_80211(sc);
-#ifdef LINK_STATE_UP
-               sc->arpcom.ac_if.if_link_state = LINK_STATE_UP;
-               rt_ifmsg(&(sc->arpcom.ac_if));
-#endif /* LINK_STATE_UP */
+                       ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
+               }
+               NDIS_LOCK(sc);
+               sc->ifp->if_link_state = LINK_STATE_UP;
+               if_link_state_change(sc->ifp);
        }
 
-       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;
-#ifdef LINK_STATE_DOWN
-               sc->arpcom.ac_if.if_link_state = LINK_STATE_DOWN;
-               rt_ifmsg(&(sc->arpcom.ac_if));
-#endif /* LINK_STATE_DOWN */
+               NDIS_UNLOCK(sc);
+               if ((sc->ndis_80211 != 0) && (vap != NULL))
+                       ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
+               NDIS_LOCK(sc);
+               sc->ifp->if_link_state = LINK_STATE_DOWN;
+               if_link_state_change(sc->ifp);
        }
 
-       lwkt_serialize_exit(ifp->if_serializer);
+       NDIS_UNLOCK(sc);
 }
 
 static void
 ndis_map_sclist(void *arg, bus_dma_segment_t *segs, int nseg,
-               bus_size_t mapsize, int error)
+    bus_size_t mapsize, int error)
 {
        struct ndis_sc_list     *sclist;
        int                     i;
@@ -1059,14 +1717,39 @@ ndis_map_sclist(void *arg, bus_dma_segment_t *segs, int nseg,
        }
 }
 
+static int
+ndis_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+       const struct ieee80211_bpf_params *params)
+{
+       /* no support; just discard */
+       m_freem(m);
+       ieee80211_free_node(ni);
+       return (0);
+}
+
+static void
+ndis_update_mcast(struct ifnet *ifp)
+{
+       struct ndis_softc       *sc = ifp->if_softc;
+
+       ndis_setmulti(sc);
+}
+
+static void
+ndis_update_promisc(struct ifnet *ifp)
+{
+       /* not supported */
+}
+
 static void
-ndis_starttask(void *arg)
+ndis_starttask(device_object *d, void *arg)
 {
        struct ifnet            *ifp;
 
        ifp = arg;
+
        if (!ifq_is_empty(&ifp->if_snd))
-               if_devstart(ifp);
+               ndis_start(ifp);
 }
 
 /*
@@ -1081,7 +1764,6 @@ ndis_starttask(void *arg)
  * we need to perform busdma work here. Those that use map registers
  * will do the mapping themselves on a buffer by buffer basis.
  */
-
 static void
 ndis_start(struct ifnet *ifp)
 {
@@ -1089,11 +1771,13 @@ ndis_start(struct ifnet *ifp)
        struct mbuf             *m = NULL;
        ndis_packet             **p0 = NULL, *p = NULL;
        ndis_tcpip_csum         *csum;
-       int                     pcnt = 0;
+       int                     pcnt = 0, status;
 
        sc = ifp->if_softc;
 
+       NDIS_LOCK(sc);
        if (!sc->ndis_link || ifp->if_flags & IFF_OACTIVE) {
+               NDIS_UNLOCK(sc);
                return;
        }
 
@@ -1104,10 +1788,15 @@ ndis_start(struct ifnet *ifp)
                if (m == NULL)
                        break;
 
-               sc->ndis_txarray[sc->ndis_txidx] = NULL;
+               NdisAllocatePacket(&status,
+                   &sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool);
+
+               if (status != NDIS_STATUS_SUCCESS)
+                       break;
 
                if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
-                       m_freem(m);
+                       ifq_prepend(&ifp->if_snd, m);
+                       NDIS_UNLOCK(sc);
                        return;
                }
 
@@ -1159,8 +1848,8 @@ ndis_start(struct ifnet *ifp)
                 * If there's a BPF listener, bounce a copy of this frame
                 * to him.
                 */
-
-               BPF_MTAP(ifp, m);
+               if (!sc->ndis_80211)    /* XXX handle 80211 */
+                       BPF_MTAP(ifp, m);
 
                /*
                 * The array that p0 points to must appear contiguous,
@@ -1169,12 +1858,12 @@ ndis_start(struct ifnet *ifp)
                 * so the this batch of packets can be transmitted, then
                 * wait for txeof to ask us to send the rest.
                 */
-
                if (sc->ndis_txidx == 0)
                        break;
        }
 
        if (pcnt == 0) {
+               NDIS_UNLOCK(sc);
                return;
        }
 
@@ -1184,20 +1873,31 @@ ndis_start(struct ifnet *ifp)
        /*
         * Set a timeout in case the chip goes out to lunch.
         */
-       ifp->if_timer = 5;
+       sc->ndis_tx_timer = 5;
 
-       if (sc->ndis_maxpkts == 1)
-               ndis_send_packet(sc, p);
-       else
-               ndis_send_packets(sc, p0, pcnt);
-}
+       NDIS_UNLOCK(sc);
 
-static void
-ndis_init(void *xsc)
+       /*
+        * 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;
+}
+
+static void
+ndis_init(void *xsc)
 {
        struct ndis_softc       *sc = xsc;
-       struct ifnet            *ifp = &sc->arpcom.ac_if;
-       int                     i, error;
+       struct ifnet            *ifp = sc->ifp;
+       struct ieee80211com     *ic = ifp->if_l2com;
+       int                     i, len, error;
 
        /*
         * Avoid reintializing the link unnecessarily.
@@ -1205,15 +1905,22 @@ ndis_init(void *xsc)
         * fixing the upper layer modules so they don't
         * call ifp->if_init() quite as often.
         */
-       if (sc->ndis_link && sc->ndis_skip)
+       if (sc->ndis_link)
                return;
 
        /*
         * Cancel pending I/O and free all RX/TX buffers.
         */
        ndis_stop(sc);
-       if (ndis_init_nic(sc))
-               return;
+
+       if (!(sc->ndis_iftype == PNPBus && ndisusb_halt == 0)) {
+               error = ndis_init_nic(sc);
+               if (error != 0) {
+                       device_printf(sc->ndis_dev,
+                           "failed to initialize the device: %d\n", error);
+                       return;
+               }
+       }
 
        /* Init our MAC address */
 
@@ -1227,13 +1934,20 @@ ndis_init(void *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);
+               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.
@@ -1243,18 +1957,18 @@ ndis_init(void *xsc)
        /* Setup task offload. */
        ndis_set_offload(sc);
 
-       /* Enable interrupts. */
-       ndis_enable_intr(sc);
-
-       if (sc->ndis_80211)
-               ndis_setstate_80211(sc);
+       NDIS_LOCK(sc);
 
        sc->ndis_txidx = 0;
        sc->ndis_txpending = sc->ndis_maxpkts;
        sc->ndis_link = 0;
 
+       sc->ifp->if_link_state = LINK_STATE_UNKNOWN;
+       if_link_state_change(sc->ifp);
+
        ifp->if_flags |= IFF_RUNNING;
        ifp->if_flags &= ~IFF_OACTIVE;
+       sc->ndis_tx_timer = 0;
 
        /*
         * Some drivers don't set this value. The NDIS spec says
@@ -1262,12 +1976,16 @@ ndis_init(void *xsc)
         * seconds." We use 3 seconds, because it seems for some
         * drivers, exactly 2 seconds is too fast.
         */
+       if (sc->ndis_block->nmb_checkforhangsecs == 0)
+               sc->ndis_block->nmb_checkforhangsecs = 3;
 
-       if (sc->ndis_block.nmb_checkforhangsecs == 0)
-               sc->ndis_block.nmb_checkforhangsecs = 3;
+       sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs;
+       callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc);
+       NDIS_UNLOCK(sc);
 
-       callout_reset(&sc->ndis_stat_timer,
-                     hz * sc->ndis_block.nmb_checkforhangsecs, ndis_tick, sc);
+       /* XXX force handling */
+       if (sc->ndis_80211)
+               ieee80211_start_all(ic);        /* start all vap's */
 }
 
 /*
@@ -1283,7 +2001,7 @@ ndis_ifmedia_upd(struct ifnet *ifp)
        if (NDIS_INITIALIZED(sc))
                ndis_init(sc);
 
-       return(0);
+       return (0);
 }
 
 /*
@@ -1295,7 +2013,7 @@ ndis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
        struct ndis_softc       *sc;
        uint32_t                media_info;
        ndis_media_state        linkstate;
-       int                     error, len;
+       int                     len;
 
        ifmr->ifm_status = IFM_AVALID;
        ifmr->ifm_active = IFM_ETHER;
@@ -1305,17 +2023,17 @@ ndis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
                return;
 
        len = sizeof(linkstate);
-       error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
+       ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
            (void *)&linkstate, &len);
 
        len = sizeof(media_info);
-       error = ndis_get_info(sc, OID_GEN_LINK_SPEED,
+       ndis_get_info(sc, OID_GEN_LINK_SPEED,
            (void *)&media_info, &len);
 
        if (linkstate == nmc_connected)
                ifmr->ifm_status |= IFM_ACTIVE;
 
-       switch(media_info) {
+       switch (media_info) {
        case 100000:
                ifmr->ifm_active |= IFM_10_T;
                break;
@@ -1331,22 +2049,177 @@ ndis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
        }
 }
 
+static int
+ndis_set_cipher(struct ndis_softc *sc, int cipher)
+{
+       struct ieee80211com     *ic;
+       int                     rval = 0, len;
+       uint32_t                arg, save;
+
+       ic = sc->ifp->if_l2com;
+
+       len = sizeof(arg);
+
+       if (cipher == WPA_CSE_WEP40 || cipher == WPA_CSE_WEP104) {
+               if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_WEP))
+                       return (ENOTSUP);
+               arg = NDIS_80211_WEPSTAT_ENC1ENABLED;
+       }
+
+       if (cipher == WPA_CSE_TKIP) {
+               if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIP))
+                       return (ENOTSUP);
+               arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
+       }
+
+       if (cipher == WPA_CSE_CCMP) {
+               if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_AES_CCM))
+                       return (ENOTSUP);
+               arg = NDIS_80211_WEPSTAT_ENC3ENABLED;
+       }
+
+       DPRINTF(("Setting cipher to %d\n", arg));
+       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(struct ndis_softc *sc, void *ie, int ielen)
+{
+       struct ieee80211_ie_wpa *w;
+       struct ndis_ie          *n;
+       char                    *pos;
+       uint32_t                arg;
+       int                     i;
+
+       /*
+        * 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 *)ie;
+
+       /* Check for the right kind of IE. */
+       if (w->wpa_id != IEEE80211_ELEMID_VENDOR) {
+               DPRINTF(("Incorrect IE type %d\n", w->wpa_id));
+               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;
+
+       DPRINTF(("Setting WPA auth mode to %d\n", arg));
+       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);
+}
+
+static void
+ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
+{
+       struct ieee80211vap *vap = ifp->if_softc;
+       struct ndis_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+       uint32_t txrate;
+       int len;
+
+       if (!NDIS_INITIALIZED(sc))
+               return;
+
+       len = sizeof(txrate);
+       if (ndis_get_info(sc, OID_GEN_LINK_SPEED, &txrate, &len) == 0)
+               vap->iv_bss->ni_txrate = txrate / 5000;
+       ieee80211_media_status(ifp, imr);
+}
+
 static void
 ndis_setstate_80211(struct ndis_softc *sc)
 {
        struct ieee80211com     *ic;
-       ndis_80211_ssid         ssid;
+       struct ieee80211vap     *vap;
+       ndis_80211_macaddr      bssid;
        ndis_80211_config       config;
-       ndis_80211_wep          wep;
-       int                     i, rval = 0, len;
+       int                     rval = 0, len;
        uint32_t                arg;
        struct ifnet            *ifp;
 
-       ic = &sc->ic;
-       ifp = &sc->ic.ic_ac.ac_if;
+       ifp = sc->ifp;
+       ic = ifp->if_l2com;
+       vap = TAILQ_FIRST(&ic->ic_vaps);
 
-       if (!NDIS_INITIALIZED(sc))
+       if (!NDIS_INITIALIZED(sc)) {
+               DPRINTF(("%s: NDIS not initialized\n", __func__));
                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. */
 
@@ -1361,86 +2234,231 @@ ndis_setstate_80211(struct ndis_softc *sc)
        if (rval)
                device_printf (sc->ndis_dev, "set infra failed: %d\n", rval);
 
+       /* Set power management */
+       len = sizeof(arg);
+       if (vap->iv_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);
+
+       /* Set TX power */
+       if ((ic->ic_caps & IEEE80211_C_TXPMGT) &&
+           ic->ic_txpowlimit < (sizeof(dBm2mW) / sizeof(dBm2mW[0]))) {
+               arg = dBm2mW[ic->ic_txpowlimit];
+               len = sizeof(arg);
+               ndis_set_info(sc, OID_802_11_TX_POWER_LEVEL, &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_802_11_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);
+
+       len = sizeof(config);
+       bzero((char *)&config, len);
+       config.nc_length = len;
+       config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
+       rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len);
+
+       /*
+        * 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_bsschan != IEEE80211_CHAN_ANYC) {
+               int chan, chanflag;
+
+               chan = ieee80211_chan2ieee(ic, ic->ic_bsschan);
+               chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
+                   IEEE80211_CHAN_5GHZ;
+               if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
+                       config.nc_dsconfig =
+                               ic->ic_bsschan->ic_freq * 1000;
+                       len = sizeof(config);
+                       config.nc_length = len;
+                       config.nc_fhconfig.ncf_length =
+                           sizeof(ndis_80211_config_fh);
+                       DPRINTF(("Setting channel to %ukHz\n", config.nc_dsconfig));
+                       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 if (rval)
+               device_printf(sc->ndis_dev, "couldn't retrieve "
+                   "channel info: %d\n", rval);
+
+       /* Set the BSSID to our value so the driver doesn't associate */
+       len = IEEE80211_ADDR_LEN;
+       bcopy(IF_LLADDR(ifp), bssid, len);
+       DPRINTF(("Setting BSSID to %6D\n", (uint8_t *)&bssid, ":"));
+       rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len);
+       if (rval)
+               device_printf(sc->ndis_dev,
+                   "setting BSSID failed: %d\n", rval);
+}
+
+static void
+ndis_auth_and_assoc(struct ndis_softc *sc, struct ieee80211vap *vap)
+{
+       struct ieee80211com     *ic;
+       struct ieee80211_node   *ni;
+       ndis_80211_ssid         ssid;
+       ndis_80211_macaddr      bssid;
+       ndis_80211_wep          wep;
+       int                     i, rval = 0, len, error;
+       uint32_t                arg;
+       struct ifnet            *ifp;
+
+       ifp = sc->ifp;
+       ic = ifp->if_l2com;
+       ni = vap->iv_bss;
+
+       if (!NDIS_INITIALIZED(sc)) {
+               DPRINTF(("%s: NDIS not initialized\n", __func__));
+               return;
+       }
+
+       /* Initial setup */
+       ndis_setstate_80211(sc);
+
+       /* Set network infrastructure mode. */
+
+       len = sizeof(arg);
+       if (vap->iv_opmode == IEEE80211_M_IBSS)
+               arg = NDIS_80211_NET_INFRA_IBSS;
+       else
+               arg = NDIS_80211_NET_INFRA_BSS;
+
+       rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
+
+       if (rval)
+               device_printf (sc->ndis_dev, "set infra failed: %d\n", rval);
+
+       /* Set RTS threshold */
+
+       len = sizeof(arg);
+       arg = vap->iv_rtsthreshold;
+       ndis_set_info(sc, OID_802_11_RTS_THRESHOLD, &arg, &len);
+
+       /* Set fragmentation threshold */
+
+       len = sizeof(arg);
+       arg = vap->iv_fragthreshold;
+       ndis_set_info(sc, OID_802_11_FRAGMENTATION_THRESHOLD, &arg, &len);
+
        /* Set WEP */
 
-#ifdef IEEE80211_F_PRIVACY
-       if (ic->ic_flags & IEEE80211_F_PRIVACY) {
-#else
-       if (ic->ic_wep_mode >= IEEE80211_WEP_ON) {
-#endif
+       if (vap->iv_flags & IEEE80211_F_PRIVACY &&
+           !(vap->iv_flags & IEEE80211_F_WPA)) {
+               int keys_set = 0;
+
+               if (ni->ni_authmode == IEEE80211_AUTH_SHARED) {
+                       len = sizeof(arg);
+                       arg = NDIS_80211_AUTHMODE_SHARED;
+                       DPRINTF(("Setting shared auth\n"));
+                       ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE,
+                           &arg, &len);
+               }
                for (i = 0; i < IEEE80211_WEP_NKID; i++) {
-                       if (ic->ic_nw_keys[i].wk_keylen) {
+                       if (vap->iv_nw_keys[i].wk_keylen) {
+                               if (vap->iv_nw_keys[i].wk_cipher->ic_cipher !=
+                                   IEEE80211_CIPHER_WEP)
+                                       continue;
                                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 */
-                               if (ic->ic_nw_keys[i].wk_len < 5)
+                               wep.nw_keylen = vap->iv_nw_keys[i].wk_keylen;
+
+                               /*
+                                * 5, 13 and 16 are the only valid
+                                * key lengths. Anything in between
+                                * will be zero padded out to the
+                                * next highest boundary.
+                                */
+                               if (vap->iv_nw_keys[i].wk_keylen < 5)
                                        wep.nw_keylen = 5;
-                               else if (ic->ic_nw_keys[i].wk_len > 5 &&
-                                    ic->ic_nw_keys[i].wk_len < 13)
+                               else if (vap->iv_nw_keys[i].wk_keylen > 5 &&
+                                    vap->iv_nw_keys[i].wk_keylen < 13)
                                        wep.nw_keylen = 13;
-#endif
+                               else if (vap->iv_nw_keys[i].wk_keylen > 13 &&
+                                    vap->iv_nw_keys[i].wk_keylen < 16)
+                                       wep.nw_keylen = 16;
+
                                wep.nw_keyidx = i;
                                wep.nw_length = (sizeof(uint32_t) * 3)
                                    + wep.nw_keylen;
-                               if (i == ic->ic_def_txkey)
+                               if (i == vap->iv_def_txkey)
                                        wep.nw_keyidx |= NDIS_80211_WEPKEY_TX;
-                               bcopy(ic->ic_nw_keys[i].wk_key,
+                               bcopy(vap->iv_nw_keys[i].wk_key,
                                    wep.nw_keydata, wep.nw_length);
                                len = sizeof(wep);
+                               DPRINTF(("Setting WEP key %d\n", i));
                                rval = ndis_set_info(sc,
                                    OID_802_11_ADD_WEP, &wep, &len);
                                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_PRIVACY
-               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;
+               if (keys_set) {
+                       DPRINTF(("Setting WEP on\n"));
+                       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);
+                       if (vap->iv_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 notyet
-       if (rval)
-               device_printf (sc->ndis_dev, "set auth failed: %d\n", rval);
-#endif
+       /* Set up WPA. */
+       if ((vap->iv_flags & IEEE80211_F_WPA) &&
+           vap->iv_appie_assocreq != NULL) {
+               struct ieee80211_appie *ie = vap->iv_appie_assocreq;
+               error = ndis_set_wpa(sc, ie->ie_data, ie->ie_len);
+               if (error != 0)
+                       device_printf(sc->ndis_dev, "WPA setup failed\n");
+       }
 
 #ifdef notyet
        /* Set network type. */
 
        arg = 0;
 
-       switch (ic->ic_curmode) {
+       switch (vap->iv_curmode) {
        case IEEE80211_MODE_11A:
                arg = NDIS_80211_NETTYPE_11OFDM5;
                break;
@@ -1452,161 +2470,129 @@ ndis_setstate_80211(struct ndis_softc *sc)
                break;
        default:
                device_printf(sc->ndis_dev, "unknown mode: %d\n",
-                   ic->ic_curmode);
+                   vap->iv_curmode);
        }
 
        if (arg) {
+               DPRINTF(("Setting network type to %d\n", arg));
                len = sizeof(arg);
                rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE,
                    &arg, &len);
                if (rval)
-                       device_printf (sc->ndis_dev,
+                       device_printf(sc->ndis_dev,
                            "set nettype failed: %d\n", rval);
        }
 #endif
 
-       len = sizeof(config);
-       bzero((char *)&config, len);
-       config.nc_length = len;
-       config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
-       rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); 
-
        /*
-        * Some drivers expect us to initialize these values, so
-        * provide some defaults.
+        * 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.
         */
-       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;
+       len = IEEE80211_ADDR_LEN;
+       if (vap->iv_flags & IEEE80211_F_DESBSSID &&
+           vap->iv_opmode != IEEE80211_M_IBSS)
+               bcopy(ni->ni_bssid, bssid, len);
+       else
+               bcopy(ifp->if_broadcastaddr, bssid, len);
 
-               chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
-               chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
-                   IEEE80211_CHAN_5GHZ;
-               if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
-                       config.nc_dsconfig =
-                           ic->ic_ibss_chan->ic_freq * 1000;
-                       ic->ic_bss->ni_chan = ic->ic_ibss_chan;
-                       len = sizeof(config);
-                       config.nc_length = len;
-                       config.nc_fhconfig.ncf_length =
-                           sizeof(ndis_80211_config_fh);
-                       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 if (rval)
-               device_printf(sc->ndis_dev, "couldn't retrieve "
-                   "channel info: %d\n", rval);
+       DPRINTF(("Setting BSSID to %6D\n", (uint8_t *)&bssid, ":"));
+       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. */
 
+#ifdef NDIS_DEBUG
+       if (ndis_debug > 0) {
+               kprintf("Setting ESSID to ");
+               ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
+               kprintf("\n");
+       }
+#endif
+
        len = sizeof(ssid);
        bzero((char *)&ssid, len);
-       ssid.ns_ssidlen = ic->ic_des_esslen;
+       ssid.ns_ssidlen = ni->ni_esslen;
        if (ssid.ns_ssidlen == 0) {
                ssid.ns_ssidlen = 1;
        } else
-               bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen);
+               bcopy(ni->ni_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);
-}
 
-static void
-ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
-{
-        struct ieee80211com *ic = (void *)ifp; /* XXX */
-        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_A:
-                imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
-                                |  IFM_IEEE80211_TURBO;
-                break;
-        }
+       return;
 }
 
 static int
-ndis_get_assoc(struct ndis_softc *sc, ndis_wlan_bssid_ex **assoc)
+ndis_get_bssid_list(struct ndis_softc *sc, ndis_80211_bssid_list_ex **bl)
 {
-       ndis_80211_bssid_list_ex        *bl;
+       int     len, error;
+
+       len = sizeof(uint32_t) + (sizeof(ndis_wlan_bssid_ex) * 16);
+       *bl = kmalloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (*bl == NULL)
+               return (ENOMEM);
+
+       error = ndis_get_info(sc, OID_802_11_BSSID_LIST, *bl, &len);
+       if (error == ENOSPC) {
+               kfree(*bl, M_DEVBUF);
+               *bl = kmalloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
+               if (*bl == NULL)
+                       return (ENOMEM);
+
+               error = ndis_get_info(sc, OID_802_11_BSSID_LIST, *bl, &len);
+       }
+       if (error) {
+               DPRINTF(("%s: failed to read\n", __func__));
+               kfree(*bl, M_DEVBUF);
+               return (error);
+       }
+
+       return (0);
+}
+
+static int
+ndis_get_assoc(struct ndis_softc *sc, ndis_wlan_bssid_ex **assoc)
+{
+       struct ifnet *ifp = sc->ifp;
+       struct ieee80211com *ic = ifp->if_l2com;
+       struct ieee80211vap     *vap;
+       struct ieee80211_node   *ni;
+       ndis_80211_bssid_list_ex        *bl;
        ndis_wlan_bssid_ex      *bs;
        ndis_80211_macaddr      bssid;
        int                     i, len, error;
 
        if (!sc->ndis_link)
-               return(ENOENT);
+               return (ENOENT);
 
        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\n");
-               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\n");
-               return (error);
+               return (ENOENT);
        }
 
-       bl = kmalloc(len, M_TEMP, M_NOWAIT|M_ZERO);
-       if (bl == NULL)
-               return (ENOMEM);
-       error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
-       if (error) {
-               kfree(bl, M_TEMP);
-               device_printf(sc->ndis_dev, "bssid_list failed\n");
+       vap = TAILQ_FIRST(&ic->ic_vaps);
+       ni = vap->iv_bss;
+
+       error = ndis_get_bssid_list(sc, &bl);
+       if (error)
                return (error);
-       }
 
        bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0];
        for (i = 0; i < bl->nblx_items; i++) {
@@ -1614,106 +2600,53 @@ ndis_get_assoc(struct ndis_softc *sc, ndis_wlan_bssid_ex **assoc)
                        *assoc = kmalloc(bs->nwbx_len, M_TEMP, M_NOWAIT);
                        if (*assoc == NULL) {
                                kfree(bl, M_TEMP);
-                               return(ENOMEM);
+                               return (ENOMEM);
                        }
                        bcopy((char *)bs, (char *)*assoc, bs->nwbx_len);
                        kfree(bl, M_TEMP);
-                       return(0);
-               }       
+                       if (ic->ic_opmode == IEEE80211_M_STA)
+                               ni->ni_associd = 1 | 0xc000; /* fake associd */
+                       return (0);
+               }
                bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len);
        }
 
        kfree(bl, M_TEMP);
-       return(ENOENT);
+       return (ENOENT);
 }
 
 static void
 ndis_getstate_80211(struct ndis_softc *sc)
 {
        struct ieee80211com     *ic;
-       ndis_80211_ssid         ssid;
-       ndis_80211_config       config;
+       struct ieee80211vap     *vap;
+       struct ieee80211_node   *ni;
        ndis_wlan_bssid_ex      *bs;
        int                     rval, len, i = 0;
+       int                     chanflag;
        uint32_t                arg;
        struct ifnet            *ifp;
 
-       ic = &sc->ic;
-       ifp = &sc->ic.ic_ac.ac_if;
+       ifp = sc->ifp;
+       ic = ifp->if_l2com;
+       vap = TAILQ_FIRST(&ic->ic_vaps);
+       ni = vap->iv_bss;
 
        if (!NDIS_INITIALIZED(sc))
                return;
 
-       if (sc->ndis_link)
-               ic->ic_state = IEEE80211_S_RUN;
-       else
-               ic->ic_state = IEEE80211_S_ASSOC;
-
-
-       /*
-        * If we're associated, retrieve info on the current bssid.
-        */
-       if ((rval = 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;
-               }
-               kfree(bs, M_TEMP);
-       } else {
+       if ((rval = ndis_get_assoc(sc, &bs)) != 0)
                return;
-       }
-
-       len = sizeof(ssid);
-       bzero((char *)&ssid, len);
-       rval = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len);
-
-       if (rval)
-               device_printf (sc->ndis_dev, "get ssid failed: %d\n", rval);
-       bcopy(ssid.ns_ssid, ic->ic_bss->ni_essid, ssid.ns_ssidlen);
-       ic->ic_bss->ni_esslen = ssid.ns_ssidlen;
 
-       len = sizeof(arg);
-       rval = ndis_get_info(sc, OID_GEN_LINK_SPEED, &arg, &len);
-       if (rval)
-               device_printf (sc->ndis_dev, "get link speed failed: %d\n",
-                   rval);
-
-       if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
-               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 / 5000)
-                               break;
-               }
-       }
-
-       if (i == ic->ic_bss->ni_rates.rs_nrates &&
-           ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
-               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 / 5000)
-                               break;
-               }
-       }
+       /* We're associated, retrieve info on the current bssid. */
+       ic->ic_curmode = ndis_nettype_mode(bs->nwbx_nettype);
+       chanflag = ndis_nettype_chan(bs->nwbx_nettype);
+       IEEE80211_ADDR_COPY(ni->ni_bssid, bs->nwbx_macaddr);
 
-       if (i == ic->ic_bss->ni_rates.rs_nrates)
-               device_printf(sc->ndis_dev, "no matching rate for: %d\n",
-                   arg / 5000);
-       else
-               ic->ic_bss->ni_txrate = i;
+       /* Get SSID from current association info. */
+       bcopy(bs->nwbx_ssid.ns_ssid, ni->ni_essid,
+           bs->nwbx_ssid.ns_ssidlen);
+       ni->ni_esslen = bs->nwbx_ssid.ns_ssidlen;
 
        if (ic->ic_caps & IEEE80211_C_PMGT) {
                len = sizeof(arg);
@@ -1723,45 +2656,82 @@ ndis_getstate_80211(struct ndis_softc *sc)
                        device_printf(sc->ndis_dev,
                            "get power mode failed: %d\n", rval);
                if (arg == NDIS_80211_POWERMODE_CAM)
-                       ic->ic_flags &= ~IEEE80211_F_PMGTON;
+                       vap->iv_flags &= ~IEEE80211_F_PMGTON;
                else
-                       ic->ic_flags |= IEEE80211_F_PMGTON;
+                       vap->iv_flags |= IEEE80211_F_PMGTON;
        }
 
-       len = sizeof(config);
-       bzero((char *)&config, len);
-       config.nc_length = len;
-       config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
-       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);
+       /* Get TX power */
+       if (ic->ic_caps & IEEE80211_C_TXPMGT) {
+               len = sizeof(arg);
+               ndis_get_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &len);
+               for (i = 0; i < (sizeof(dBm2mW) / sizeof(dBm2mW[0])); i++)
+                       if (dBm2mW[i] >= arg)
+                               break;
+               ic->ic_txpowlimit = i;
+       }
+
+       /*
+        * Use the current association information to reflect
+        * what channel we're on.
+        */
+       ic->ic_curchan = ieee80211_find_channel(ic,
+           bs->nwbx_config.nc_dsconfig / 1000, chanflag);
+       if (ic->ic_curchan == NULL)
+               ic->ic_curchan = &ic->ic_channels[0];
+       ni->ni_chan = ic->ic_curchan;
+       ic->ic_bsschan = ic->ic_curchan;
+
+       kfree(bs, M_TEMP);
+
+       /*
+        * Determine current authentication mode.
+        */
+       len = sizeof(arg);
+       rval = ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
+       if (rval)
+               device_printf(sc->ndis_dev,
+                   "get authmode status failed: %d\n", rval);
+       else {
+               vap->iv_flags &= ~IEEE80211_F_WPA;
+               switch (arg) {
+               case NDIS_80211_AUTHMODE_OPEN:
+                       ni->ni_authmode = IEEE80211_AUTH_OPEN;
+                       break;
+               case NDIS_80211_AUTHMODE_SHARED:
+                       ni->ni_authmode = IEEE80211_AUTH_SHARED;
+                       break;
+               case NDIS_80211_AUTHMODE_AUTO:
+                       ni->ni_authmode = IEEE80211_AUTH_AUTO;
+                       break;
+               case NDIS_80211_AUTHMODE_WPA:
+               case NDIS_80211_AUTHMODE_WPAPSK:
+               case NDIS_80211_AUTHMODE_WPANONE:
+                       ni->ni_authmode = IEEE80211_AUTH_WPA;
+                       vap->iv_flags |= IEEE80211_F_WPA1;
+                       break;
+               case NDIS_80211_AUTHMODE_WPA2:
+               case NDIS_80211_AUTHMODE_WPA2PSK:
+                       ni->ni_authmode = IEEE80211_AUTH_WPA;
+                       vap->iv_flags |= IEEE80211_F_WPA2;
+                       break;
+               default:
+                       ni->ni_authmode = IEEE80211_AUTH_NONE;
+                       break;
+               }
+       }
 
-/*
        len = sizeof(arg);
        rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
 
        if (rval)
-               device_printf (sc->ndis_dev,
+               device_printf(sc->ndis_dev,
                    "get wep status failed: %d\n", rval);
 
        if (arg == NDIS_80211_WEPSTAT_ENABLED)
-               ic->ic_flags |= IEEE80211_F_WEPON;
+               vap->iv_flags |= IEEE80211_F_PRIVACY|IEEE80211_F_DROPUNENC;
        else
-               ic->ic_flags &= ~IEEE80211_F_WEPON;
-*/
+               vap->iv_flags &= ~(IEEE80211_F_PRIVACY|IEEE80211_F_DROPUNENC);
 }
 
 static int
@@ -1771,7 +2741,9 @@ ndis_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
        struct ifreq            *ifr = (struct ifreq *) data;
        int                     i, error = 0;
 
-       switch(command) {
+       /*NDIS_LOCK(sc);*/
+
+       switch (command) {
        case SIOCSIFFLAGS:
                if (ifp->if_flags & IFF_UP) {
                        if (ifp->if_flags & IFF_RUNNING &&
@@ -1808,15 +2780,7 @@ ndis_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
                break;
        case SIOCGIFMEDIA:
        case SIOCSIFMEDIA:
-               if (sc->ndis_80211) {
-                       error = ieee80211_ioctl(&sc->ic, command, data, cr);
-                       if (error == ENETRESET) {
-                               ndis_setstate_80211(sc);
-                               /*ndis_init(sc);*/
-                               error = 0;
-                       }
-               } else
-                       error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
+               error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
                break;
        case SIOCSIFCAP:
                ifp->if_capenable = ifr->ifr_reqcap;
@@ -1826,157 +2790,272 @@ ndis_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
                        ifp->if_hwassist = 0;
                ndis_set_offload(sc);
                break;
-       case SIOCGIFGENERIC:
-       case SIOCSIFGENERIC:
-               if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) {
-                       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:
-               sc->ndis_skip = 1;
-               if (sc->ndis_80211) {
-                       error = ieee80211_ioctl(&sc->ic, command, data, cr);
-                       if (error == ENETRESET) {
-                               ndis_setstate_80211(sc);
-                               error = 0;
-                       }
-               } else
-                       error = ether_ioctl(ifp, command, data);
-               sc->ndis_skip = 0;
+               error = ether_ioctl(ifp, command, data);
                break;
        }
+
+       /*NDIS_UNLOCK(sc);*/
+
        return(error);
 }
 
 static int
-ndis_wi_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data)
+ndis_ioctl_80211(struct ifnet *ifp, u_long command, caddr_t data,
+    struct ucred *cr)
 {
-       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);
+       struct ndis_softc       *sc = ifp->if_softc;
+       struct ieee80211com     *ic = ifp->if_l2com;
+       struct ifreq            *ifr = (struct ifreq *) data;
+       struct ndis_oid_data    oid;
+       struct ndis_evt         evt;
+       void                    *oidbuf;
+       int                     error = 0;
 
-       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, PCATCH, "ssidscan", hz * 2);
-               len = 0;
-               error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
-               if (error != ENOSPC)
+       switch (command) {
+       case SIOCSIFFLAGS:
+               /*NDIS_LOCK(sc);*/
+               if (ifp->if_flags & IFF_UP) {
+                       if (!(ifp->if_flags & IFF_RUNNING))
+                               ndis_init(sc);
+               } else {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               ndis_stop(sc);
+               }
+               sc->ndis_if_flags = ifp->if_flags;
+               error = 0;
+               /*NDIS_UNLOCK(sc);*/
+               break;
+       case SIOCGDRVSPEC:
+               if ((error = priv_check(curthread, PRIV_DRIVER)))
+                       break;
+               error =  copyin(ifr->ifr_data, &oid, sizeof(oid));
+               if (error)
                        break;
-               bl = kmalloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
-               error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
+               oidbuf = kmalloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO);
+               if (oidbuf == NULL) {
+                       error = ENOMEM;
+                       break;
+               }
+               error =  copyin((caddr_t)ifr->ifr_data + sizeof(oid), oidbuf, oid.len);
                if (error) {
-                       kfree(bl, M_DEVBUF);
+                       kfree(oidbuf, M_TEMP);
                        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);
+               error = ndis_get_info(sc, oid.oid, oidbuf, &oid.len);
+               if (error) {
+                       kfree(oidbuf, M_TEMP);
+                       break;
+               }
+               error = copyout(&oid, ifr->ifr_data, sizeof(oid));
+               if (error) {
+                       kfree(oidbuf, M_TEMP);
+                       break;
+               }
+               error = copyout(oidbuf, (caddr_t)ifr->ifr_data + sizeof(oid), oid.len);
+               kfree(oidbuf, M_TEMP);
+               break;
+       case SIOCSDRVSPEC:
+               if ((error = priv_check(curthread, PRIV_DRIVER)))
+                       break;
+               error =  copyin(ifr->ifr_data, &oid, sizeof(oid));
+               if (error)
+                       break;
+               oidbuf = kmalloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO);
+               if (oidbuf == NULL) {
+                       error = ENOMEM;
+                       break;
+               }
+               error =  copyin((caddr_t)ifr->ifr_data + sizeof(oid), oidbuf, oid.len);
+               if (error) {
+                       kfree(oidbuf, M_TEMP);
+                       break;
+               }
+               error = ndis_set_info(sc, oid.oid, oidbuf, &oid.len);
+               if (error) {
+                       kfree(oidbuf, M_TEMP);
+                       break;
                }
-               kfree(bl, M_DEVBUF);
-               error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
+               error = copyout(&oid, ifr->ifr_data, sizeof(oid));
+               if (error) {
+                       kfree(oidbuf, M_TEMP);
+                       break;
+               }
+               error = copyout(oidbuf, (caddr_t)ifr->ifr_data + sizeof(oid), oid.len);
+               kfree(oidbuf, M_TEMP);
+               break;
+       case SIOCGPRIVATE_0:
+               if ((error = priv_check(curthread, PRIV_DRIVER)))
+                       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,
+                           (caddr_t)ifr->ifr_data + (sizeof(uint32_t) * 2),
+                           sc->ndis_evt[sc->ndis_evtcidx].ne_len);
+                       if (error) {
+                               NDIS_UNLOCK(sc);
+                               break;
+                       }
+                       kfree(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 SIOCGIFMEDIA:
+               error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, command);
+               break;
+       case SIOCGIFADDR:
+               error = ether_ioctl(ifp, command, data);
                break;
        default:
-               error = ENOTTY;
+               error = EINVAL;
                break;
        }
        return (error);
 }
 
-static int
-ndis_wi_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data)
+int
+ndis_del_key(struct ieee80211vap *vap, const struct ieee80211_key *key)
 {
-       struct wi_req           wreq;
-       struct ifreq            *ifr;
        struct ndis_softc       *sc;
-       uint32_t                foo;
-       int                     error, len;
+       ndis_80211_key          rkey;
+       int                     len, error = 0;
+
+       sc = vap->iv_ic->ic_ifp->if_softc;
+
+       bzero((char *)&rkey, sizeof(rkey));
+       len = sizeof(rkey);
+
+       rkey.nk_len = len;
+       rkey.nk_keyidx = key->wk_keyix;
+
+       bcopy(vap->iv_ifp->if_broadcastaddr,
+           rkey.nk_bssid, IEEE80211_ADDR_LEN);
+
+       error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len);
 
-       error = priv_check(curthread, PRIV_ROOT);
        if (error)
-               return (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(struct ieee80211vap *vap, const struct ieee80211_key *key,
+    const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+       struct ndis_softc       *sc;
+       struct ifnet            *ifp;
+       ndis_80211_key          rkey;
+       int                     len, error = 0;
+
+       ifp = vap->iv_ic->ic_ifp;
        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);
+       switch (key->wk_cipher->ic_cipher) {
+       case IEEE80211_CIPHER_TKIP:
+
+               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 */
+
+               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(ifp->if_broadcastaddr,
+                           rkey.nk_bssid, IEEE80211_ADDR_LEN);
+               } else {
+                       bcopy(vap->iv_bss->ni_bssid,
+                           rkey.nk_bssid, IEEE80211_ADDR_LEN);
+                       /* pairwise key */
+                       rkey.nk_keyidx |= 1 << 30;
+               }
+
+               /* need to set bit 29 based on keyrsc */
+               rkey.nk_keyrsc = key->wk_keyrsc[0];     /* XXX need tid */
+
+               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:
        default:
                error = ENOTTY;
                break;
        }
-       return (error);
+
+       /* We need to return 1 for success, 0 for failure. */
+
+       if (error)
+               return (0);
+
+       return (1);
 }
 
 static void
-ndis_watchdog(struct ifnet *ifp)
+ndis_resettask(device_object *d, void *arg)
 {
        struct ndis_softc               *sc;
 
-       sc = ifp->if_softc;
-
-       ifp->if_oerrors++;
-       device_printf(sc->ndis_dev, "watchdog timeout\n");
-
+       sc = arg;
        ndis_reset_nic(sc);
-       ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
 }
 
 /*
@@ -1987,15 +3066,35 @@ static void
 ndis_stop(struct ndis_softc *sc)
 {
        struct ifnet            *ifp;
+       int                     i;
 
-       ifp = &sc->arpcom.ac_if;
-       callout_stop(&sc->ndis_stat_timer);
-
-       ndis_halt_nic(sc);
+       ifp = sc->ifp;
+       callout_stop(&sc->ndis_stat_callout); /* XXX swildner callout_drain() */
 
-       ifp->if_timer = 0;
+       NDIS_LOCK(sc);
+       sc->ndis_tx_timer = 0;
        sc->ndis_link = 0;
        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+       NDIS_UNLOCK(sc);
+
+       if (sc->ndis_iftype != PNPBus ||
+           (sc->ndis_iftype == PNPBus &&
+            !(sc->ndisusb_status & NDISUSB_STATUS_DETACH) &&
+            ndisusb_halt != 0))
+               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) {
+                       kfree(sc->ndis_evt[i].ne_buf, M_TEMP);
+                       sc->ndis_evt[i].ne_buf = NULL;
+               }
+               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);
 }
 
 /*
@@ -2005,12 +3104,219 @@ ndis_stop(struct ndis_softc *sc)
 void
 ndis_shutdown(device_t dev)
 {
-       struct ndis_softc       *sc;
-       struct ifnet            *ifp;
+       struct ndis_softc               *sc;
 
+       wlan_serialize_enter();
        sc = device_get_softc(dev);
-       ifp = &sc->arpcom.ac_if;
-       lwkt_serialize_enter(ifp->if_serializer);
-       ndis_shutdown_nic(sc);
-       lwkt_serialize_exit(ifp->if_serializer);
+       ndis_stop(sc);
+       wlan_serialize_exit();
+}
+
+static int
+ndis_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+       struct ndis_vap *nvp = NDIS_VAP(vap);
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ifnet *ifp = ic->ic_ifp;
+       struct ndis_softc *sc = ifp->if_softc;
+       enum ieee80211_state ostate;
+
+       DPRINTF(("%s: %s -> %s\n", __func__,
+               ieee80211_state_name[vap->iv_state],
+               ieee80211_state_name[nstate]));
+
+       ostate = vap->iv_state;
+       vap->iv_state = nstate;
+
+       switch (nstate) {
+       /* pass on to net80211 */
+       case IEEE80211_S_INIT:
+       case IEEE80211_S_SCAN:
+               return nvp->newstate(vap, nstate, arg);
+       case IEEE80211_S_ASSOC:
+               if (ostate != IEEE80211_S_AUTH) {
+                       wlan_serialize_exit();
+                       ndis_auth_and_assoc(sc, vap);
+                       wlan_serialize_enter();
+               }
+               break;
+       case IEEE80211_S_AUTH:
+               wlan_serialize_exit();
+               ndis_auth_and_assoc(sc, vap);
+               if (vap->iv_state == IEEE80211_S_AUTH) /* XXX */
+                       ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
+               wlan_serialize_enter();
+               break;
+       default:
+               break;
+       }
+       return (0);
+}
+
+static void
+ndis_scan(void *arg)
+{
+       struct ieee80211vap *vap = arg;
+
+       ieee80211_scan_done(vap);
+}
+
+static void
+ndis_scan_results(struct ndis_softc *sc)
+{
+       struct ieee80211com *ic;
+       struct ieee80211vap *vap;
+       ndis_80211_bssid_list_ex *bl;
+       ndis_wlan_bssid_ex      *wb;
+       struct ieee80211_scanparams sp;
+       struct ieee80211_frame wh;
+       struct ieee80211_channel *saved_chan;
+       int i, j;
+       int rssi, noise, freq, chanflag;
+       uint8_t ssid[2+IEEE80211_NWID_LEN];
+       uint8_t rates[2+IEEE80211_RATE_MAXSIZE];
+       uint8_t *frm, *efrm;
+
+       ic = sc->ifp->if_l2com;
+       vap = TAILQ_FIRST(&ic->ic_vaps);
+       saved_chan = ic->ic_curchan;
+       noise = -96;
+
+       if (ndis_get_bssid_list(sc, &bl))
+               return;
+
+       DPRINTF(("%s: %d results\n", __func__, bl->nblx_items));
+       wb = &bl->nblx_bssid[0];
+       for (i = 0; i < bl->nblx_items; i++) {
+               memset(&sp, 0, sizeof(sp));
+
+               memcpy(wh.i_addr2, wb->nwbx_macaddr, sizeof(wh.i_addr2));
+               memcpy(wh.i_addr3, wb->nwbx_macaddr, sizeof(wh.i_addr3));
+               rssi = 100 * (wb->nwbx_rssi - noise) / (-32 - noise);
+               rssi = max(0, min(rssi, 100));  /* limit 0 <= rssi <= 100 */
+               if (wb->nwbx_privacy)
+                       sp.capinfo |= IEEE80211_CAPINFO_PRIVACY;
+               sp.bintval = wb->nwbx_config.nc_beaconperiod;
+               switch (wb->nwbx_netinfra) {
+                       case NDIS_80211_NET_INFRA_IBSS:
+                               sp.capinfo |= IEEE80211_CAPINFO_IBSS;
+                               break;
+                       case NDIS_80211_NET_INFRA_BSS:
+                               sp.capinfo |= IEEE80211_CAPINFO_ESS;
+                               break;
+               }
+               sp.rates = &rates[0];
+               for (j = 0; j < IEEE80211_RATE_MAXSIZE; j++) {
+                       /* XXX - check units */
+                       if (wb->nwbx_supportedrates[j] == 0)
+                               break;
+                       rates[2 + j] =
+                       wb->nwbx_supportedrates[j] & 0x7f;
+               }
+               rates[1] = j;
+               sp.ssid = (uint8_t *)&ssid[0];
+               memcpy(sp.ssid + 2, &wb->nwbx_ssid.ns_ssid,
+                   wb->nwbx_ssid.ns_ssidlen);
+               sp.ssid[1] = wb->nwbx_ssid.ns_ssidlen;
+
+               chanflag = ndis_nettype_chan(wb->nwbx_nettype);
+               freq = wb->nwbx_config.nc_dsconfig / 1000;
+               sp.chan = sp.bchan = ieee80211_mhz2ieee(freq, chanflag);
+               /* Hack ic->ic_curchan to be in sync with the scan result */
+               ic->ic_curchan = ieee80211_find_channel(ic, freq, chanflag);
+               if (ic->ic_curchan == NULL)
+                       ic->ic_curchan = &ic->ic_channels[0];
+
+               /* Process extended info from AP */
+               if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
+                       frm = (uint8_t *)&wb->nwbx_ies;
+                       efrm = frm + wb->nwbx_ielen;
+                       if (efrm - frm < 12)
+                               goto done;
+                       sp.tstamp = frm;                        frm += 8;
+                       sp.bintval = le16toh(*(uint16_t *)frm); frm += 2;
+                       sp.capinfo = le16toh(*(uint16_t *)frm); frm += 2;
+                       sp.ies = frm;
+                       sp.ies_len = efrm - frm;
+               }
+done:
+               DPRINTF(("scan: bssid %6D chan %dMHz (%d/%d) rssi %d\n",
+                   wb->nwbx_macaddr, ":", freq, sp.bchan, chanflag,
+                   rssi));
+               ieee80211_add_scan(vap, &sp, &wh, 0, rssi, noise);
+               wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
+       }
+       kfree(bl, M_DEVBUF);
+       /* Restore the channel after messing with it */
+       ic->ic_curchan = saved_chan;
+}
+
+static void
+ndis_scan_start(struct ieee80211com *ic)
+{
+       struct ifnet *ifp = ic->ic_ifp;
+       struct ndis_softc *sc = ifp->if_softc;
+       struct ieee80211vap *vap;
+       struct ieee80211_scan_state *ss;
+       ndis_80211_ssid ssid;
+       int error, len;
+
+       ss = ic->ic_scan;
+       vap = TAILQ_FIRST(&ic->ic_vaps);
+
+       if (!NDIS_INITIALIZED(sc)) {
+               DPRINTF(("%s: scan aborted\n", __func__));
+               ieee80211_cancel_scan(vap);
+               return;
+       }
+
+       len = sizeof(ssid);
+       bzero((char *)&ssid, len);
+       if (ss->ss_nssid == 0)
+               ssid.ns_ssidlen = 1;
+       else {
+               /* Perform a directed scan */
+               ssid.ns_ssidlen = ss->ss_ssid[0].len;
+               bcopy(ss->ss_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen);
+       }
+
+       error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
+       if (error)
+               DPRINTF(("%s: set ESSID failed\n", __func__));
+
+       len = 0;
+       error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, NULL, &len);
+       if (error) {
+               DPRINTF(("%s: scan command failed\n", __func__));
+               ieee80211_cancel_scan(vap);
+               return;
+       }
+       /* Set a timer to collect the results */
+       callout_reset(&sc->ndis_scan_callout, hz * 3, ndis_scan, vap);
+}
+
+static void
+ndis_set_channel(struct ieee80211com *ic)
+{
+       /* ignore */
+}
+
+static void
+ndis_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
+{
+       /* ignore */
+}
+
+static void
+ndis_scan_mindwell(struct ieee80211_scan_state *ss)
+{
+       /* NB: don't try to abort scan; wait for firmware to finish */
+}
+
+static void
+ndis_scan_end(struct ieee80211com *ic)
+{
+       struct ndis_softc *sc = ic->ic_ifp->if_softc;
+
+       ndis_scan_results(sc);
 }
index 89c76d2..4e7725c 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2003
  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
  *
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/if_ndis/if_ndis_pccard.c,v 1.6 2004/07/11 00:19:30 wpaul Exp $
+ * $FreeBSD: src/sys/dev/if_ndis/if_ndis_pccard.c,v 1.19 2010/12/16 15:19:32 jhb Exp $
  */
 
 #include <sys/ctype.h>
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/proc.h>
 #include <sys/module.h>
 #include <sys/socket.h>
 #include <sys/queue.h>
 #include <sys/sysctl.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
+#include <sys/lock.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/if_media.h>
 
+#include <sys/bus.h>
+#include <sys/rman.h>
+
 #include <netproto/802_11/ieee80211_var.h>
 
-#include <emulation/ndis/regcall.h>
+#include <bus/usb/usb.h>
+#include <bus/usb/usbdi.h>
+
 #include <emulation/ndis/pe_var.h>
+#include <emulation/ndis/cfg_var.h>
 #include <emulation/ndis/resource_var.h>
 #include <emulation/ndis/ntoskrnl_var.h>
 #include <emulation/ndis/ndis_var.h>
-#include <emulation/ndis/cfg_var.h>
-#include "if_ndisvar.h"
+#include <dev/netif/ndis/if_ndisvar.h>
 
 #include <bus/pccard/pccardvar.h>
 #include "card_if.h"
 
-#include "ndis_driver_data.h"
-
-#ifdef NDIS_PCMCIA_DEV_TABLE 
-
-MODULE_DEPEND(ndis, pccard, 1, 1, 1);
-MODULE_DEPEND(ndis, wlan, 1, 1, 1);
-MODULE_DEPEND(ndis, ndisapi, 1, 1, 1);
-
-/*
- * Various supported device vendors/types and their names.
- * These are defined in the ndis_driver_data.h file.
- */
-static struct ndis_pccard_type ndis_devs[] = {
-#ifdef NDIS_PCMCIA_DEV_TABLE
-       NDIS_PCMCIA_DEV_TABLE
-#endif
-       { NULL, NULL, NULL }
-};
+MODULE_DEPEND(if_ndis, pccard, 1, 1, 1);
 
 static int ndis_probe_pccard   (device_t);
 static int ndis_attach_pccard  (device_t);
+static int ndis_detach_pccard  (device_t);
 static struct resource_list *ndis_get_resource_list
                                (device_t, device_t);
+static int ndis_devcompare     (interface_type,
+                                struct ndis_pccard_type *, device_t);
+extern int ndisdrv_modevent    (module_t, int, void *);
 extern int ndis_attach         (device_t);
 extern int ndis_shutdown       (device_t);
 extern int ndis_detach         (device_t);
 extern int ndis_suspend                (device_t);
 extern int ndis_resume         (device_t);
 
+extern unsigned char drv_data[];
+
 static device_method_t ndis_methods[] = {
        /* Device interface */
        DEVMETHOD(device_probe,         ndis_probe_pccard),
        DEVMETHOD(device_attach,        ndis_attach_pccard),
-       DEVMETHOD(device_detach,        ndis_detach),
+       DEVMETHOD(device_detach,        ndis_detach_pccard),
        DEVMETHOD(device_shutdown,      ndis_shutdown),
        DEVMETHOD(device_suspend,       ndis_suspend),
        DEVMETHOD(device_resume,        ndis_resume),
@@ -112,50 +104,61 @@ static device_method_t ndis_methods[] = {
 };
 
 static driver_t ndis_driver = {
-#ifdef NDIS_DEVNAME
-       NDIS_DEVNAME,
-#else
        "ndis",
-#endif
        ndis_methods,
        sizeof(struct ndis_softc)
 };
 
 static devclass_t ndis_devclass;
 
-#ifdef NDIS_MODNAME
-#define NDIS_MODNAME_OVERRIDE_PCMCIA(x)                                        \
-       DRIVER_MODULE(x, pccard, ndis_driver, ndis_devclass, NULL, NULL)
-NDIS_MODNAME_OVERRIDE_PCMCIA(NDIS_MODNAME);
-#else
-DRIVER_MODULE(ndis, pccard, ndis_driver, ndis_devclass, NULL, NULL);
-#endif
+DRIVER_MODULE(if_ndis, pccard, ndis_driver, ndis_devclass, ndisdrv_modevent, NULL);
 
-/*
- * Probe for an NDIS device. Check the PCI vendor and device
- * IDs against our list and return a device name if we find a match.
- */
 static int
-ndis_probe_pccard(device_t dev)
+ndis_devcompare(interface_type bustype, struct ndis_pccard_type *t,
+    device_t dev)
 {
-       struct ndis_pccard_type *t;
        const char              *prodstr, *vendstr;
-       int                     error;
 
-       t = ndis_devs;
+       if (bustype != PCMCIABus)
+               return(FALSE);
 
        prodstr = pccard_get_product_str(dev);
        vendstr = pccard_get_vendor_str(dev);
 
        while(t->ndis_name != NULL) {
-               if (ndis_strcasecmp(vendstr, t->ndis_vid) == 0 &&
-                   ndis_strcasecmp(prodstr, t->ndis_did) == 0) {
+               if (strcasecmp(vendstr, t->ndis_vid) == 0 &&
+                   strcasecmp(prodstr, t->ndis_did) == 0) {
                        device_set_desc(dev, t->ndis_name);
-                       return(0);
+                       return(TRUE);
                }
                t++;
        }
 
+       return(FALSE);
+}
+
+/*
+ * Probe for an NDIS device. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+static int
+ndis_probe_pccard(device_t dev)
+{
+       driver_object           *drv;
+       struct drvdb_ent        *db;
+
+       drv = windrv_lookup(0, "PCCARD Bus");
+       if (drv == NULL)
+               return(ENXIO);
+
+       db = windrv_match((matchfuncptr)ndis_devcompare, dev);
+
+       if (db != NULL) {
+               /* Create PDO for this device instance */
+               windrv_create_pdo(drv, dev);
+               return(0);
+       }
+
        return(ENXIO);
 }
 
@@ -171,10 +174,20 @@ ndis_attach_pccard(device_t dev)
        struct ndis_pccard_type *t;
        int                     devidx = 0;
        const char              *prodstr, *vendstr;
+       struct drvdb_ent        *db;
 
+       wlan_serialize_enter();
        sc = device_get_softc(dev);
        unit = device_get_unit(dev);
        sc->ndis_dev = dev;
+
+       db = windrv_match((matchfuncptr)ndis_devcompare, dev);
+       if (db == NULL) {
+               wlan_serialize_exit();
+               return (ENXIO);
+       }
+       sc->ndis_dobj = db->windrv_object;
+       sc->ndis_regvals = db->windrv_regvals;
        resource_list_init(&sc->ndis_rl);
 
        sc->ndis_io_rid = 0;
@@ -208,18 +221,14 @@ ndis_attach_pccard(device_t dev)
 
        /* Figure out exactly which device we matched. */
 
-       t = ndis_devs;
+       t = db->windrv_devlist;
 
-       error = pccard_get_product_str(dev, &prodstr);
-       if (error)
-               return(error);
-       error = pccard_get_vendor_str(dev, &vendstr);
-       if (error)
-               return(error);
+       prodstr = pccard_get_product_str(dev);
+       vendstr = pccard_get_vendor_str(dev);
 
        while(t->ndis_name != NULL) {
-               if (ndis_strcasecmp(vendstr, t->ndis_vid) == 0 &&
-                   ndis_strcasecmp(prodstr, t->ndis_did) == 0)
+               if (strcasecmp(vendstr, t->ndis_vid) == 0 &&
+                   strcasecmp(prodstr, t->ndis_did) == 0)
                        break;
                t++;
                devidx++;
@@ -230,6 +239,18 @@ ndis_attach_pccard(device_t dev)
        error = ndis_attach(dev);
 
 fail:
+       wlan_serialize_exit();
+       return(error);
+}
+
+static int
+ndis_detach_pccard(device_t dev)
+{
+       int error = 0;
+
+       wlan_serialize_enter();
+       error = ndis_detach(dev);
+       wlan_serialize_exit();
        return(error);
 }
 
@@ -242,8 +263,6 @@ ndis_get_resource_list(device_t dev, device_t child)
        return (&sc->ndis_rl);
 }
 
-#endif /* NDIS_PCI_DEV_TABLE */
-
 #define NDIS_AM_RID 3
 
 int
index 9bc27cd..ea6f846 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2003
  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
  *
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/if_ndis/if_ndis_pci.c,v 1.7 2004/07/11 00:19:30 wpaul Exp $
+ * $FreeBSD: src/sys/dev/if_ndis/if_ndis_pci.c,v 1.26 2010/12/19 11:14:34 tijl Exp $
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/proc.h>
 #include <sys/module.h>
 #include <sys/socket.h>
 #include <sys/queue.h>
 #include <sys/sysctl.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
+#include <sys/lock.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/if_media.h>
 
+#include <sys/bus.h>
+#include <sys/rman.h>
+
 #include <netproto/802_11/ieee80211_var.h>
 
 #include <bus/pci/pcireg.h>
 #include <bus/pci/pcivar.h>
+#include <bus/usb/usb.h>
+#include <bus/usb/usbdi.h>
 
-#include <emulation/ndis/regcall.h>
 #include <emulation/ndis/pe_var.h>
+#include <emulation/ndis/cfg_var.h>
 #include <emulation/ndis/resource_var.h>
 #include <emulation/ndis/ntoskrnl_var.h>
 #include <emulation/ndis/ndis_var.h>
-#include <emulation/ndis/cfg_var.h>
-#include "if_ndisvar.h"
-
-#include "ndis_driver_data.h"
+#include <dev/netif/ndis/if_ndisvar.h>
 
-#ifdef NDIS_PCI_DEV_TABLE 
-
-MODULE_DEPEND(ndis, pci, 1, 1, 1);
-MODULE_DEPEND(ndis, wlan, 1, 1, 1);
-MODULE_DEPEND(ndis, ndisapi, 1, 1, 1);
-
-/*
- * Various supported device vendors/types and their names.
- * These are defined in the ndis_driver_data.h file.
- */
-static struct ndis_pci_type ndis_devs[] = {
-#ifdef NDIS_PCI_DEV_TABLE
-       NDIS_PCI_DEV_TABLE
-#endif
-       { 0, 0, 0, NULL }
-};
+MODULE_DEPEND(if_ndis, pci, 1, 1, 1);
 
 static int ndis_probe_pci      (device_t);
 static int ndis_attach_pci     (device_t);
+static int ndis_detach_pci     (device_t);
 static struct resource_list *ndis_get_resource_list
                                (device_t, device_t);
+static int ndis_devcompare     (interface_type,
+                                struct ndis_pci_type *, device_t);
+extern int ndisdrv_modevent    (module_t, int, void *);
 extern int ndis_attach         (device_t);
 extern int ndis_shutdown       (device_t);
 extern int ndis_detach         (device_t);
@@ -93,7 +82,7 @@ static device_method_t ndis_methods[] = {
        /* Device interface */
        DEVMETHOD(device_probe,         ndis_probe_pci),
        DEVMETHOD(device_attach,        ndis_attach_pci),
-       DEVMETHOD(device_detach,        ndis_detach),
+       DEVMETHOD(device_detach,        ndis_detach_pci),
        DEVMETHOD(device_shutdown,      ndis_shutdown),
        DEVMETHOD(device_suspend,       ndis_suspend),
        DEVMETHOD(device_resume,        ndis_resume),
@@ -105,28 +94,41 @@ static device_method_t ndis_methods[] = {
 };
 
 static driver_t ndis_driver = {
-#ifdef NDIS_DEVNAME
-       NDIS_DEVNAME,
-#else
        "ndis",
-#endif
        ndis_methods,
        sizeof(struct ndis_softc)
 };
 
 static devclass_t ndis_devclass;
 
-#ifdef NDIS_MODNAME
-#define NDIS_MODNAME_OVERRIDE_PCI(x)                                   \
-       DRIVER_MODULE(x, pci, ndis_driver, ndis_devclass, NULL, NULL)
-#define NDIS_MODNAME_OVERRIDE_CARDBUS(x)                               \
-       DRIVER_MODULE(x, cardbus, ndis_driver, ndis_devclass, NULL, NULL)
-NDIS_MODNAME_OVERRIDE_PCI(NDIS_MODNAME);
-NDIS_MODNAME_OVERRIDE_CARDBUS(NDIS_MODNAME);
-#else
-DRIVER_MODULE(ndis, pci, ndis_driver, ndis_devclass, NULL, NULL);
-DRIVER_MODULE(ndis, cardbus, ndis_driver, ndis_devclass, NULL, NULL);
-#endif
+DRIVER_MODULE(if_ndis, pci, ndis_driver, ndis_devclass, ndisdrv_modevent, NULL);
+DRIVER_MODULE(if_ndis, cardbus, ndis_driver, ndis_devclass, ndisdrv_modevent, NULL);
+
+static int
+ndis_devcompare(interface_type bustype, struct ndis_pci_type *t, device_t dev)
+{
+       uint16_t                vid, did;
+       uint32_t                subsys;
+
+       if (bustype != PCIBus)
+               return(FALSE);
+
+       vid = pci_get_vendor(dev);
+       did = pci_get_device(dev);
+       subsys = pci_get_subdevice(dev);
+       subsys = (subsys << 16) | pci_get_subvendor(dev);
+
+       while(t->ndis_name != NULL) {
+               if ((t->ndis_vid == vid) && (t->ndis_did == did) &&
+                   (t->ndis_subsys == subsys || t->ndis_subsys == 0)) {
+                       device_set_desc(dev, t->ndis_name);
+                       return(TRUE);
+               }
+               t++;
+       }
+
+       return(FALSE);
+}
 
 /*
  * Probe for an NDIS device. Check the PCI vendor and device
@@ -135,19 +137,20 @@ DRIVER_MODULE(ndis, cardbus, ndis_driver, ndis_devclass, NULL, NULL);
 static int
 ndis_probe_pci(device_t dev)
 {
-       struct ndis_pci_type    *t;
+       driver_object           *drv;
+       struct drvdb_ent        *db;
 
-       t = ndis_devs;
+       drv = windrv_lookup(0, "PCI Bus");
 
-       while(t->ndis_name != NULL) {
-               if ((pci_get_vendor(dev) == t->ndis_vid) &&
-                   (pci_get_device(dev) == t->ndis_did) &&
-                   ((pci_read_config(dev, PCIR_SUBVEND_0, 4) ==
-                   t->ndis_subsys) || t->ndis_subsys == 0)) {
-                       device_set_desc(dev, t->ndis_name);
-                       return(0);
-               }
-               t++;
+       if (drv == NULL)
+               return(ENXIO);
+
+       db = windrv_match((matchfuncptr)ndis_devcompare, dev);
+
+       if (db != NULL) {
+               /* Create PDO for this device instance */
+               windrv_create_pdo(drv, dev);
+               return(0);
        }
 
        return(ENXIO);
@@ -166,11 +169,24 @@ ndis_attach_pci(device_t dev)
        int                     devidx = 0, defidx = 0;
        struct resource_list    *rl;
        struct resource_list_entry      *rle;
+       struct drvdb_ent        *db;
+       uint16_t                vid, did;
+       uint32_t                subsys;
+
+       wlan_serialize_enter();
 
        sc = device_get_softc(dev);
        unit = device_get_unit(dev);
        sc->ndis_dev = dev;
 
+       db = windrv_match((matchfuncptr)ndis_devcompare, dev);
+       if (db == NULL) {
+               wlan_serialize_exit();
+               return (ENXIO);
+       }
+       sc->ndis_dobj = db->windrv_object;
+       sc->ndis_regvals = db->windrv_regvals;
+
        /*
         * Map control/status registers.
         */
@@ -201,7 +217,7 @@ ndis_attach_pci(device_t dev)
                                        error = ENXIO;
                                        goto fail;
                                }
-                               if (rle->rid == PCIR_BAR(2)) {
+                               if (sc->ndis_res_mem) {
                                        sc->ndis_altmem_rid = rle->rid;
                                        sc->ndis_res_altmem =
                                            bus_alloc_resource_any(dev,
@@ -290,24 +306,25 @@ ndis_attach_pci(device_t dev)
 
        /* Figure out exactly which device we matched. */
 
-       t = ndis_devs;
+       vid = pci_get_vendor(dev);
+       did = pci_get_device(dev);
+       subsys = pci_get_subdevice(dev);
+       subsys = (subsys << 16) | pci_get_subvendor(dev);
+
+       t = db->windrv_devlist;
 
        while(t->ndis_name != NULL) {
-               if ((pci_get_vendor(dev) == t->ndis_vid) &&
-                   (pci_get_device(dev) == t->ndis_did)) {
+               if (t->ndis_vid == vid && t->ndis_did == did) {
                        if (t->ndis_subsys == 0)
                                defidx = devidx;
-                       else {
-                               if (t->ndis_subsys ==
-                                   pci_read_config(dev, PCIR_SUBVEND_0, 4))
-                                       break;
-                       }
+                       else if (t->ndis_subsys == subsys)
+                               break;
                }
                t++;
                devidx++;
        }
 
-       if (ndis_devs[devidx].ndis_name == NULL)
+       if (t->ndis_name == NULL)
                sc->ndis_devidx = defidx;
        else
                sc->ndis_devidx = devidx;
@@ -315,6 +332,18 @@ ndis_attach_pci(device_t dev)
        error = ndis_attach(dev);
 
 fail:
+       wlan_serialize_exit();
+       return(error);
+}
+
+static int
+ndis_detach_pci(device_t dev)
+{
+       int error = 0;
+
+       wlan_serialize_enter();
+       error = ndis_detach(dev);
+       wlan_serialize_exit();
        return(error);
 }
 
@@ -326,5 +355,3 @@ ndis_get_resource_list(device_t dev, device_t child)
        sc = device_get_softc(dev);
        return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev));
 }
-
-#endif /* NDIS_PCI_DEV_TABLE */
diff --git a/sys/dev/netif/ndis/if_ndis_usb.c b/sys/dev/netif/ndis/if_ndis_usb.c
new file mode 100644 (file)
index 0000000..ed3f4e9
--- /dev/null
@@ -0,0 +1,262 @@
+/*-
+ * Copyright (c) 2005
+ *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/dev/if_ndis/if_ndis_usb.c,v 1.10 2008/12/27 08:03:32 weongyo Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/lock.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <sys/bus.h>
+#include <bus/usb/usb.h>
+#include <bus/usb/usbdi.h>
+#include <bus/usb/usbdi_util.h>
+#include <bus/usb/usbdivar.h>
+
+#include <netproto/802_11/ieee80211_var.h>
+
+#include <emulation/ndis/pe_var.h>
+#include <emulation/ndis/cfg_var.h>
+#include <emulation/ndis/resource_var.h>
+#include <emulation/ndis/ntoskrnl_var.h>
+#include <emulation/ndis/ndis_var.h>
+#include <emulation/ndis/usbd_var.h>
+#include <dev/netif/ndis/if_ndisvar.h>
+
+SYSCTL_NODE(_hw, OID_AUTO, ndisusb, CTLFLAG_RD, 0, "NDIS USB driver parameters");
+
+MODULE_DEPEND(if_ndis, usb, 1, 1, 1);
+
+static device_probe_t ndisusb_match;
+static device_attach_t ndisusb_attach;
+static device_detach_t ndisusb_detach;
+static bus_get_resource_list_t ndis_get_resource_list;
+
+extern int ndisdrv_modevent     (module_t, int, void *);
+extern int ndis_attach          (device_t);
+extern int ndis_shutdown        (device_t);
+extern int ndis_detach          (device_t);
+extern int ndis_suspend         (device_t);
+extern int ndis_resume          (device_t);
+
+extern unsigned char drv_data[];
+
+static device_method_t ndis_methods[] = {
+        /* Device interface */
+       DEVMETHOD(device_probe,         ndisusb_match),
+       DEVMETHOD(device_attach,        ndisusb_attach),
+       DEVMETHOD(device_detach,        ndisusb_detach),
+       DEVMETHOD(device_shutdown,      ndis_shutdown),
+
+        /* bus interface */
+       DEVMETHOD(bus_print_child,      bus_generic_print_child),
+       DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
+       DEVMETHOD(bus_get_resource_list, ndis_get_resource_list),
+
+       { 0, 0 }
+};
+
+static driver_t ndis_driver = {
+       "ndis",
+       ndis_methods,
+       sizeof(struct ndis_softc)
+};
+
+static devclass_t ndis_devclass;
+
+DRIVER_MODULE(if_ndis, uhub, ndis_driver, ndis_devclass, ndisdrv_modevent, 0);
+
+static int
+ndisusb_devcompare(interface_type bustype, struct ndis_usb_type *t, device_t dev)
+{
+       struct usb_attach_arg *uaa;
+
+       if (bustype != PNPBus)
+               return (FALSE);
+
+       uaa = device_get_ivars(dev);
+
+       while (t->ndis_name != NULL) {
+               if ((uaa->vendor == t->ndis_vid) &&
+                   (uaa->product == t->ndis_did)) {
+                       device_set_desc(dev, t->ndis_name);
+                       return (TRUE);
+               }
+               t++;
+       }
+
+       return (FALSE);
+}
+
+static int
+ndisusb_match(device_t self)
+{
+       struct drvdb_ent *db;
+       struct usb_attach_arg *uaa = device_get_ivars(self);
+
+       if (windrv_lookup(0, "USB Bus") == NULL)
+               return (UMATCH_NONE);
+
+       if (uaa->iface != NULL)
+               return (UMATCH_NONE);
+
+       db = windrv_match((matchfuncptr)ndisusb_devcompare, self);
+       if (db == NULL)
+               return (UMATCH_NONE);
+
+       return (UMATCH_VENDOR_PRODUCT);
+}
+
+static int
+ndisusb_attach(device_t self)
+{
+       struct drvdb_ent        *db;
+       struct ndisusb_softc *dummy = device_get_softc(self);
+       struct usb_attach_arg *uaa = device_get_ivars(self);
+       struct ndis_softc       *sc;
+       struct ndis_usb_type    *t;
+       driver_object           *drv;
+       int                     devidx = 0;
+       usbd_status             status;
+
+       wlan_serialize_enter();
+       sc = (struct ndis_softc *)dummy;
+
+       if (uaa->device == NULL) {
+               wlan_serialize_exit();
+               return ENXIO;
+       }
+
+       db = windrv_match((matchfuncptr)ndisusb_devcompare, self);
+       if (db == NULL) {
+               wlan_serialize_exit();
+               return (ENXIO);
+       }
+
+       sc->ndis_dev = self;
+       sc->ndis_dobj = db->windrv_object;
+       sc->ndis_regvals = db->windrv_regvals;
+       sc->ndis_iftype = PNPBus;
+
+       /* Create PDO for this device instance */
+
+       drv = windrv_lookup(0, "USB Bus");
+       windrv_create_pdo(drv, self);
+
+       status = usbd_set_config_no(uaa->device, NDISUSB_CONFIG_NO, 0);
+       if (status != USBD_NORMAL_COMPLETION) {
+               device_printf(self, "setting config no failed\n");
+               wlan_serialize_exit();
+               return (ENXIO);
+       }
+
+       /* Figure out exactly which device we matched. */
+
+       t = db->windrv_devlist;
+
+       while (t->ndis_name != NULL) {
+               if ((uaa->vendor == t->ndis_vid) &&
+                   (uaa->product == t->ndis_did)) {
+                       sc->ndis_devidx = devidx;
+                       break;
+               }
+               t++;
+               devidx++;
+       }
+
+       if (ndis_attach(self) != 0) {
+               wlan_serialize_exit();
+               return ENXIO;
+       }
+
+       usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, uaa->device, self);
+
+       wlan_serialize_exit();
+       return 0;
+}
+
+static int
+ndisusb_detach(device_t self)
+{
+       int i, error;
+       struct ndis_softc       *sc = device_get_softc(self);
+       struct usb_attach_arg *uaa = device_get_ivars(self);
+
+       wlan_serialize_enter();
+       sc->ndisusb_status |= NDISUSB_STATUS_DETACH;
+
+       for (i = 0; i < NDISUSB_ENDPT_MAX; i++) {
+               if (sc->ndisusb_ep[i] == NULL)
+                       continue;
+
+               usbd_abort_pipe(sc->ndisusb_ep[i]);
+               usbd_close_pipe(sc->ndisusb_ep[i]);
+               sc->ndisusb_ep[i] = NULL;
+       }
+
+       if (sc->ndisusb_iin_buf != NULL) {
+               kfree(sc->ndisusb_iin_buf, M_USBDEV);
+               sc->ndisusb_iin_buf = NULL;
+       }
+
+       ndis_pnpevent_nic(self, NDIS_PNP_EVENT_SURPRISE_REMOVED);
+
+       usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, uaa->device, self);
+
+       error = ndis_detach(self);
+
+       wlan_serialize_exit();
+       return error;
+}
+
+static struct resource_list *
+ndis_get_resource_list(device_t dev, device_t child)
+{
+       struct ndis_softc       *sc;
+
+       sc = device_get_softc(dev);
+       return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev));
+}
index 61746e5..e9f26e7 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2003
  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
  *
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/if_ndis/if_ndisvar.h,v 1.15 2004/07/11 00:19:30 wpaul Exp $
- * $DragonFly: src/sys/dev/netif/ndis/if_ndisvar.h,v 1.3 2005/12/31 19:39:14 dillon Exp $
+ * $FreeBSD: src/sys/dev/if_ndis/if_ndisvar.h,v 1.39 2009/05/02 15:14:18 thompsa Exp $
  */
 
 #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,32 +58,74 @@ struct ndis_pccard_type {
        char                    *ndis_name;
 };
 
+struct ndis_usb_type {
+       uint16_t                ndis_vid;
+       uint16_t                ndis_did;
+       char                    *ndis_name;
+};
+
 struct ndis_shmem {
+       list_entry              ndis_list;
        bus_dma_tag_t           ndis_stag;
        bus_dmamap_t            ndis_smap;
        void                    *ndis_saddr;
-       struct ndis_shmem       *ndis_next;
+       ndis_physaddr           ndis_paddr;
 };
 
 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) % (x)->ndis_maxpkts
+
+
+#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_vap {
+       struct ieee80211vap     vap;
+
+       int                     (*newstate)(struct ieee80211vap *,
+                                   enum ieee80211_state, int);
+};
+#define        NDIS_VAP(vap)   ((struct ndis_vap *)(vap))
 
-#define arpcom ic.ic_ac
+#define        NDISUSB_CONFIG_NO                       1
+#define        NDISUSB_IFACE_INDEX                     0
+#define        NDISUSB_INTR_TIMEOUT                    1000
+#define        NDISUSB_TX_TIMEOUT                      10000
+struct ndisusb_xfer {
+       usbd_xfer_handle        nx_xfer;
+       usbd_private_handle     nx_priv;
+       usbd_status             nx_status;
+       list_entry              nx_xferlist;
+};
 
 struct ndis_softc {
-       struct ieee80211com     ic;             /* interface info */
-#ifdef notdef
-       struct ieee80211com     arpcom;         /* interface info */
-#endif
+       struct ifnet            *ifp;
        struct ifmedia          ifmedia;        /* media info */
        u_long                  ndis_hwassist;
        uint32_t                ndis_v4tx;
@@ -95,23 +146,28 @@ struct ndis_softc {
        struct resource         *ndis_res_cm;   /* common mem (pccard) */
        struct resource_list    ndis_rl;
        int                     ndis_rescnt;
+       struct lock             ndis_lock;
+       uint8_t                 ndis_irql;
        device_t                ndis_dev;
        int                     ndis_unit;
-       ndis_miniport_block     ndis_block;
-       ndis_miniport_characteristics   ndis_chars;
+       ndis_miniport_block     *ndis_block;
+       ndis_miniport_characteristics   *ndis_chars;
        interface_type          ndis_type;
-       struct callout          ndis_stat_timer;
+       struct callout          ndis_scan_callout;
+       struct callout          ndis_stat_callout;
        int                     ndis_maxpkts;
        ndis_oid                *ndis_oids;
        int                     ndis_oidcnt;
        int                     ndis_txidx;
        int                     ndis_txpending;
        ndis_packet             **ndis_txarray;
+       ndis_handle             ndis_txpool;
        int                     ndis_sc;
        ndis_cfg                *ndis_regvals;
        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;
@@ -122,13 +178,55 @@ struct ndis_softc {
 #endif
        int                     ndis_devidx;
        interface_type          ndis_iftype;
-
+       driver_object           *ndis_dobj;
+       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;
+
+       int                     (*ndis_newstate)(struct ieee80211com *,
+                                   enum ieee80211_state, int);
+       int                     ndis_tx_timer;
+       int                     ndis_hang_timer;
+
+       io_workitem             *ndisusb_xferitem;
+       list_entry              ndisusb_xferlist;
+       kspin_lock              ndisusb_xferlock;
+#define        NDISUSB_ENDPT_BOUT      0
+#define        NDISUSB_ENDPT_BIN       1
+#define        NDISUSB_ENDPT_IIN       2
+#define        NDISUSB_ENDPT_IOUT      3
+#define        NDISUSB_ENDPT_MAX       4
+       usbd_pipe_handle        ndisusb_ep[NDISUSB_ENDPT_MAX];
+       char                    *ndisusb_iin_buf;
+       int                     ndisusb_status;
+#define NDISUSB_STATUS_DETACH  0x1
 };
 
+#define        NDISMTX_LOCK(_sc)       lockmgr(&(_sc)->ndis_lock, LK_EXCLUSIVE)
+#define        NDISMTX_UNLOCK(_sc)     lockmgr(&(_sc)->ndis_lock, LK_RELEASE)
+#define        NDISUSB_LOCK(_sc)       get_mplock()
+#define        NDISUSB_UNLOCK(_sc)     rel_mplock()
+#define        NDIS_LOCK(_sc) do {                                             \
+       if ((_sc)->ndis_iftype == PNPBus)                               \
+               NDISUSB_LOCK(_sc);                                      \
+       NDISMTX_LOCK(_sc);                                              \
+} while (0)
+#define        NDIS_UNLOCK(_sc) do {                                           \
+       if ((_sc)->ndis_iftype == PNPBus)                               \
+               NDISUSB_UNLOCK(_sc);                                    \
+       NDISMTX_UNLOCK(_sc);                                            \
+} while (0)
index 1f83f33..e69e177 100644 (file)
@@ -1,15 +1,7 @@
-# $DragonFly: src/sys/emulation/Makefile,v 1.4 2008/07/23 16:39:34 dillon Exp $
-#
+SUBDIR= ndis
 
 .if ${MACHINE_ARCH} == i386
-SUBDIR=linux
-.elif ${MACHINE_ARCH} == x86_64
-SUBDIR=
-.else
-.error Unknown MACHINE_ARCH.
+SUBDIR+=linux
 .endif
 
-# needs to be ported to new net80211 stack
-# SUBDIR= ndis
-
 .include <bsd.subdir.mk>
index e0497bb..5b70ade 100644 (file)
@@ -1,9 +1,17 @@
-# $DragonFly: src/sys/emulation/ndis/Makefile,v 1.3 2006/06/25 11:02:39 corecode Exp $
-#
+# $FreeBSD: src/sys/modules/ndis/Makefile,v 1.14 2010/08/23 06:13:29 imp Exp $
 
 KMOD=  ndis
 SRCS=  subr_pe.c subr_ndis.c subr_hal.c subr_ntoskrnl.c kern_ndis.c
+SRCS+= kern_windrv.c subr_usbd.c
 SRCS+= device_if.h bus_if.h pci_if.h
+SRCS+= opt_usb.h
 
-.include <bsd.kmod.mk>
+.if ${MACHINE_ARCH} == "x86_64"
+SRCS+= winx64_wrap.S
+.endif
+
+.if ${MACHINE_ARCH} == "i386"
+SRCS+= winx32_wrap.S
+.endif
 
+.include <bsd.kmod.mk>
index 1da6d61..56a02a3 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2003
  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
  *
@@ -29,8 +29,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/compat/ndis/cfg_var.h,v 1.2 2003/12/18 03:51:21 wpaul Exp $
- * $DragonFly: src/sys/emulation/ndis/cfg_var.h,v 1.1 2004/07/29 20:51:33 dillon Exp $
+ * $FreeBSD: src/sys/compat/ndis/cfg_var.h,v 1.3 2005/01/05 22:34:36 imp Exp $
  */
 
 #ifndef _CFG_VAR_H_
index a2ed11c..a3580a1 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2003
  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
  *
@@ -29,8 +29,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/compat/ndis/hal_var.h,v 1.3 2004/04/14 07:48:02 wpaul Exp $
- * $DragonFly: src/sys/emulation/ndis/hal_var.h,v 1.1 2004/07/29 20:51:33 dillon Exp $
+ * $FreeBSD: src/sys/compat/ndis/hal_var.h,v 1.10 2009/03/12 02:51:55 weongyo Exp $
  */
 
 #ifndef _HAL_VAR_H_
 extern image_patch_table hal_functbl[];
 
 __BEGIN_DECLS
-__stdcall __regcall uint8_t hal_lock(REGARGS1(kspin_lock *lock));
-__stdcall __regcall void hal_unlock(REGARGS2(kspin_lock *lock, uint8_t newirql));
-__stdcall uint8_t hal_irql(void);
-__stdcall __regcall uint8_t hal_raise_irql(REGARGS1(uint8_t irql));
-__stdcall __regcall void hal_lower_irql(REGARGS1(uint8_t oldirql));
+extern int hal_libinit(void);
+extern int hal_libfini(void);
+extern uint8_t KfAcquireSpinLock(kspin_lock *);
+extern void KfReleaseSpinLock(kspin_lock *, uint8_t);
+extern uint8_t KfRaiseIrql(uint8_t);
+extern void KfLowerIrql(uint8_t);
+extern uint8_t KeGetCurrentIrql(void);
 __END_DECLS
 
 #endif /* _HAL_VAR_H_ */
-
-
index 84b77d7..2cae57d 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2003
  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
  *
@@ -29,8 +29,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.57 2004/07/11 00:19:30 wpaul Exp $
- * $DragonFly: src/sys/emulation/ndis/kern_ndis.c,v 1.14 2006/12/20 18:14:41 dillon Exp $
+ * $FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.111 2011/02/23 21:45:28 brucec Exp $
  */
 
 #include <sys/param.h>
@@ -45,6 +44,7 @@
 #include <sys/proc.h>
 #include <sys/malloc.h>
 #include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/conf.h>
 
 #include <sys/kernel.h>
@@ -52,7 +52,6 @@
 #include <sys/kthread.h>
 #include <sys/bus.h>
 #include <sys/rman.h>
-
 #include <sys/mplock2.h>
 
 #include <net/if.h>
 #include <netproto/802_11/ieee80211_var.h>
 #include <netproto/802_11/ieee80211_ioctl.h>
 
-#include "regcall.h"
-#include "pe_var.h"
-#include "resource_var.h"
-#include "ntoskrnl_var.h"
-#include "ndis_var.h"
-#include "hal_var.h"
-#include "cfg_var.h"
+#include <bus/usb/usb.h>
+#include <bus/usb/usbdi.h>
+
+#include <emulation/ndis/pe_var.h>
+#include <emulation/ndis/cfg_var.h>
+#include <emulation/ndis/resource_var.h>
+#include <emulation/ndis/ntoskrnl_var.h>
+#include <emulation/ndis/ndis_var.h>
+#include <emulation/ndis/hal_var.h>
+#include <emulation/ndis/usbd_var.h>
 #include <dev/netif/ndis/if_ndisvar.h>
 
 #define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
 
-__stdcall static void ndis_status_func(ndis_handle, ndis_status,
-       void *, uint32_t);
-__stdcall static void ndis_statusdone_func(ndis_handle);
-__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
-__stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
-__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
-__stdcall static void ndis_sendrsrcavail_func(ndis_handle);
-
-struct nd_head ndis_devhead;
-
-struct ndis_req {
-       void                    (*nr_func)(void *);
-       void                    *nr_arg;
-       int                     nr_exit;
-       STAILQ_ENTRY(ndis_req)  link;
+static void ndis_status_func(ndis_handle, ndis_status, void *, uint32_t);
+static void ndis_statusdone_func(ndis_handle);
+static void ndis_setdone_func(ndis_handle, ndis_status);
+static void ndis_getdone_func(ndis_handle, ndis_status);
+static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
+static void ndis_sendrsrcavail_func(ndis_handle);
+static void ndis_intrsetup(kdpc *, device_object *,
+       irp *, struct ndis_softc *);
+static void ndis_return(device_object *, void *);
+
+static image_patch_table kernndis_functbl[] = {
+       IMPORT_SFUNC(ndis_status_func, 4),
+       IMPORT_SFUNC(ndis_statusdone_func, 1),
+       IMPORT_SFUNC(ndis_setdone_func, 2),
+       IMPORT_SFUNC(ndis_getdone_func, 2),
+       IMPORT_SFUNC(ndis_resetdone_func, 3),
+       IMPORT_SFUNC(ndis_sendrsrcavail_func, 1),
+       IMPORT_SFUNC(ndis_intrsetup, 4),
+       IMPORT_SFUNC(ndis_return, 1),
+
+       { NULL, NULL, NULL }
 };
 
-struct ndisproc {
-       struct ndisqhead        *np_q;
-       struct thread           *np_td;
-       int                     np_state;
-};
-
-static void ndis_return(void *);
-static int ndis_create_kthreads(void);
-static void ndis_destroy_kthreads(void);
-static void ndis_stop_thread(int);
-static int ndis_enlarge_thrqueue(int);
-static int ndis_shrink_thrqueue(int);
-static void ndis_runq(void *);
-
-static MALLOC_DEFINE(M_NDIS_PACKET, "ndis_packet", "ndis packet slosh");
-static MALLOC_DEFINE(M_NDIS_BUFFER, "ndis_buffer", "ndis buffer slosh");
-struct lwkt_token ndis_thr_token;
-static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo;
-struct ndisqhead ndis_itodo;
-struct ndisqhead ndis_free;
-static int ndis_jobs = 32;
-
-static struct ndisproc ndis_tproc;
-static struct ndisproc ndis_iproc;
+static struct nd_head ndis_devhead;
 
 /*
  * This allows us to export our symbols to other modules.
  * Note that we call ourselves 'ndisapi' to avoid a namespace
  * collision with if_ndis.ko, which internally calls itself
  * 'ndis.'
+ *
+ * Note: some of the subsystems depend on each other, so the
+ * order in which they're started is important. The order of
+ * importance is:
+ *
+ * HAL - spinlocks and IRQL manipulation
+ * ntoskrnl - DPC and workitem threads, object waiting
+ * windrv - driver/device registration
+ *
+ * The HAL should also be the last thing shut down, since
+ * the ntoskrnl subsystem will use spinlocks right up until
+ * the DPC and workitem threads are terminated.
  */
+
 static int
 ndis_modevent(module_t mod, int cmd, void *arg)
 {
        int                     error = 0;
+       image_patch_table       *patch;
 
        switch (cmd) {
        case MOD_LOAD:
                /* Initialize subsystems */
-               ndis_libinit();
+               hal_libinit();
                ntoskrnl_libinit();
-
-               /* Initialize TX buffer UMA zone. */
-               ndis_create_kthreads();
+               windrv_libinit();
+               ndis_libinit();
+               usbd_libinit();
+
+               patch = kernndis_functbl;
+               while (patch->ipt_func != NULL) {
+                       windrv_wrap((funcptr)patch->ipt_func,
+                           (funcptr *)&patch->ipt_wrap,
+                           patch->ipt_argcnt, patch->ipt_ftype);
+                       patch++;
+               }
 
                TAILQ_INIT(&ndis_devhead);
-
                break;
        case MOD_SHUTDOWN:
-               /* stop kthreads */
-               ndis_destroy_kthreads();
                if (TAILQ_FIRST(&ndis_devhead) == NULL) {
                        /* Shut down subsystems */
                        ndis_libfini();
+                       usbd_libfini();
+                       windrv_libfini();
                        ntoskrnl_libfini();
+                       hal_libfini();
 
-                       /* Remove zones */
-#if 0  /* YYY */
-                       malloc_uninit(M_NDIS_PACKET);
-                       malloc_uninit(M_NDIS_BUFFER);
-#endif
+                       patch = kernndis_functbl;
+                       while (patch->ipt_func != NULL) {
+                               windrv_unwrap(patch->ipt_wrap);
+                               patch++;
+                       }
                }
                break;
        case MOD_UNLOAD:
-               /* stop kthreads */
-               ndis_destroy_kthreads();
-
                /* Shut down subsystems */
                ndis_libfini();
+               usbd_libfini();
+               windrv_libfini();
                ntoskrnl_libfini();
+               hal_libfini();
+
+               patch = kernndis_functbl;
+               while (patch->ipt_func != NULL) {
+                       windrv_unwrap(patch->ipt_wrap);
+                       patch++;
+               }
 
-               /* Remove zones */
-#if 0  /* YYY */
-               malloc_uninit(M_NDIS_PACKET);
-               malloc_uninit(M_NDIS_BUFFER);
-#endif
                break;
        default:
                error = EINVAL;
                break;
        }
 
-       return(error);
-}
-DEV_MODULE(ndisapi, ndis_modevent, NULL);
-MODULE_VERSION(ndisapi, 1);
-
-/*
- * We create two kthreads for the NDIS subsystem. One of them is a task
- * queue for performing various odd jobs. The other is an swi thread
- * reserved exclusively for running interrupt handlers. The reason we
- * have our own task queue is that there are some cases where we may
- * need to sleep for a significant amount of time, and if we were to
- * use one of the taskqueue threads, we might delay the processing
- * of other pending tasks which might need to run right away. We have
- * a separate swi thread because we don't want our interrupt handling
- * to be delayed either.
- *
- * By default there are 32 jobs available to start, and another 8
- * are added to the free list each time a new device is created.
- */
-
-static void
-ndis_runq(void *arg)
-{
-       struct ndis_req         *r = NULL, *die = NULL;
-       struct ndisproc         *p;
-
-       p = arg;
-       get_mplock();
-
-       while (1) {
-
-               /* Sleep, but preserve our original priority. */
-               ndis_thsuspend(p->np_td, 0);
-
-               /* Look for any jobs on the work queue. */
-
-               lwkt_gettoken(&ndis_thr_token);
-               p->np_state = NDIS_PSTATE_RUNNING;
-               while(STAILQ_FIRST(p->np_q) != NULL) {
-                       r = STAILQ_FIRST(p->np_q);
-                       STAILQ_REMOVE_HEAD(p->np_q, link);
-                       lwkt_reltoken(&ndis_thr_token);
-
-                       /* Do the work. */
-
-                       if (r->nr_func != NULL)
-                               (*r->nr_func)(r->nr_arg);
-
-                       lwkt_gettoken(&ndis_thr_token);
-                       STAILQ_INSERT_HEAD(&ndis_free, r, link);
-
-                       /* Check for a shutdown request */
-
-                       if (r->nr_exit == TRUE)
-                               die = r;
-               }
-               p->np_state = NDIS_PSTATE_SLEEPING;
-               lwkt_reltoken(&ndis_thr_token);
-
-               /* Bail if we were told to shut down. */
-
-               if (die != NULL)
-                       break;
-       }
-
-       wakeup(die);
-       rel_mplock();
-}
-
-static int
-ndis_create_kthreads(void)
-{
-       struct ndis_req         *r;
-       int                     i, error = 0;
-
-       lwkt_token_init(&ndis_thr_token, "ndis");
-
-       STAILQ_INIT(&ndis_ttodo);
-       STAILQ_INIT(&ndis_itodo);
-       STAILQ_INIT(&ndis_free);
-
-       for (i = 0; i < ndis_jobs; i++) {
-               r = kmalloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
-               STAILQ_INSERT_HEAD(&ndis_free, r, link);
-       }
-
-       if (error == 0) {
-               ndis_tproc.np_q = &ndis_ttodo;
-               ndis_tproc.np_state = NDIS_PSTATE_SLEEPING;
-               error = kthread_create_stk(ndis_runq, &ndis_tproc,
-                   &ndis_tproc.np_td, NDIS_KSTACK_PAGES * PAGE_SIZE,
-                   "ndis taskqueue");
-       }
-
-       if (error == 0) {
-               ndis_iproc.np_q = &ndis_itodo;
-               ndis_iproc.np_state = NDIS_PSTATE_SLEEPING;
-               error = kthread_create_stk(ndis_runq, &ndis_iproc,
-                   &ndis_iproc.np_td, NDIS_KSTACK_PAGES * PAGE_SIZE,
-                   "ndis swi");
-       }
-
-       if (error) {
-               while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
-                       STAILQ_REMOVE_HEAD(&ndis_free, link);
-                       kfree(r, M_DEVBUF);
-               }
-               return(error);
-       }
-
-       return(0);
-}
-
-static void
-ndis_destroy_kthreads(void)
-{
-       struct ndis_req         *r;
-
-       /* Stop the threads. */
-
-       ndis_stop_thread(NDIS_TASKQUEUE);
-       ndis_stop_thread(NDIS_SWI);
-
-       /* Destroy request structures. */
-
-       while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
-               STAILQ_REMOVE_HEAD(&ndis_free, link);
-               kfree(r, M_DEVBUF);
-       }
-
-       lwkt_token_uninit(&ndis_thr_token);
-
-       return;
+       return (error);
 }
+DEV_MODULE(ndis, ndis_modevent, NULL);
+MODULE_VERSION(ndis, 1);
 
 static void
-ndis_stop_thread(int t)
-{
-       struct ndis_req         *r;
-       struct ndisqhead        *q;
-       thread_t                td;
-
-       if (t == NDIS_TASKQUEUE) {
-               q = &ndis_ttodo;
-               td = ndis_tproc.np_td;
-       } else {
-               q = &ndis_itodo;
-               td = ndis_iproc.np_td;
-       }
-
-       /* Create and post a special 'exit' job. */
-
-       lwkt_gettoken(&ndis_thr_token);
-       r = STAILQ_FIRST(&ndis_free);
-       STAILQ_REMOVE_HEAD(&ndis_free, link);
-       r->nr_func = NULL;
-       r->nr_arg = NULL;
-       r->nr_exit = TRUE;
-       STAILQ_INSERT_TAIL(q, r, link);
-       lwkt_reltoken(&ndis_thr_token);
-
-       ndis_thresume(td);
-
-       /* wait for thread exit */
-
-       tsleep(r, PCATCH, "ndisthexit", hz * 60);
-
-       /* Now empty the job list. */
-
-       lwkt_gettoken(&ndis_thr_token);
-       while ((r = STAILQ_FIRST(q)) != NULL) {
-               STAILQ_REMOVE_HEAD(q, link);
-               STAILQ_INSERT_HEAD(&ndis_free, r, link);
-       }
-       lwkt_reltoken(&ndis_thr_token);
-}
-
-static int
-ndis_enlarge_thrqueue(int cnt)
-{
-       struct ndis_req         *r;
-       int                     i;
-
-       for (i = 0; i < cnt; i++) {
-               r = kmalloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
-               lwkt_gettoken(&ndis_thr_token);
-               STAILQ_INSERT_HEAD(&ndis_free, r, link);
-               ndis_jobs++;
-               lwkt_reltoken(&ndis_thr_token);
-       }
-
-       return(0);
-}
-
-static int
-ndis_shrink_thrqueue(int cnt)
-{
-       struct ndis_req         *r;
-       int                     i;
-
-       for (i = 0; i < cnt; i++) {
-               lwkt_gettoken(&ndis_thr_token);
-               r = STAILQ_FIRST(&ndis_free);
-               if (r == NULL) {
-                       lwkt_reltoken(&ndis_thr_token);
-                       return(ENOMEM);
-               }
-               STAILQ_REMOVE_HEAD(&ndis_free, link);
-               ndis_jobs--;
-               lwkt_reltoken(&ndis_thr_token);
-               kfree(r, M_DEVBUF);
-       }
-
-       return(0);
-}
-
-int
-ndis_unsched(void (*func)(void *), void *arg, int t)
-{
-       struct ndis_req         *r;
-       struct ndisqhead        *q;
-       thread_t                td;
-
-       if (t == NDIS_TASKQUEUE) {
-               q = &ndis_ttodo;
-               td = ndis_tproc.np_td;
-       } else {
-               q = &ndis_itodo;
-               td = ndis_iproc.np_td;
-       }
-
-       lwkt_gettoken(&ndis_thr_token);
-       STAILQ_FOREACH(r, q, link) {
-               if (r->nr_func == func && r->nr_arg == arg) {
-                       STAILQ_REMOVE(q, r, ndis_req, link);
-                       STAILQ_INSERT_HEAD(&ndis_free, r, link);
-                       lwkt_reltoken(&ndis_thr_token);
-                       return(0);
-               }
-       }
-
-       lwkt_reltoken(&ndis_thr_token);
-
-       return(ENOENT);
-}
-
-int
-ndis_sched(void (*func)(void *), void *arg, int t)
-{
-       struct ndis_req         *r;
-       struct ndisqhead        *q;
-       thread_t                td;
-       int                     s;
-
-       if (t == NDIS_TASKQUEUE) {
-               q = &ndis_ttodo;
-               td = ndis_tproc.np_td;
-       } else {
-               q = &ndis_itodo;
-               td = ndis_iproc.np_td;
-       }
-
-       lwkt_gettoken(&ndis_thr_token);
-       /*
-        * Check to see if an instance of this job is already
-        * pending. If so, don't bother queuing it again.
-        */
-       STAILQ_FOREACH(r, q, link) {
-               if (r->nr_func == func && r->nr_arg == arg) {
-                       lwkt_reltoken(&ndis_thr_token);
-                       return(0);
-               }
-       }
-       r = STAILQ_FIRST(&ndis_free);
-       if (r == NULL) {
-               lwkt_reltoken(&ndis_thr_token);
-               return(EAGAIN);
-       }
-       STAILQ_REMOVE_HEAD(&ndis_free, link);
-       r->nr_func = func;
-       r->nr_arg = arg;
-       r->nr_exit = FALSE;
-       STAILQ_INSERT_TAIL(q, r, link);
-       if (t == NDIS_TASKQUEUE)
-               s = ndis_tproc.np_state;
-       else
-               s = ndis_iproc.np_state;
-       lwkt_reltoken(&ndis_thr_token);
-
-       /*
-        * Post the job, but only if the thread is actually blocked
-        * on its own suspend call. If a driver queues up a job with
-        * NdisScheduleWorkItem() which happens to do a KeWaitForObject(),
-        * it may suspend there, and in that case we don't want to wake
-        * it up until KeWaitForObject() gets woken up on its own.
-        */
-       if (s == NDIS_PSTATE_SLEEPING)
-               ndis_thresume(td);
-
-       return(0);
-}
-
-int
-ndis_thsuspend(thread_t td, int timo)
-{
-       int                     error;
-
-       error = tsleep(td, 0, "ndissp", timo);
-       return(error);
-}
-
-void
-ndis_thresume(struct thread *td)
-{
-       wakeup(td);
-}
-
-__stdcall static void
 ndis_sendrsrcavail_func(ndis_handle adapter)
 {
-       return;
 }
 
-__stdcall static void
+static void
 ndis_status_func(ndis_handle adapter, ndis_status status, void *sbuf,
-                uint32_t slen)
+    uint32_t slen)
 {
        ndis_miniport_block     *block;
-       block = adapter;
+       struct ndis_softc       *sc;
+       struct ifnet            *ifp;
 
-       if (block->nmb_ifp->if_flags & IFF_DEBUG)
-               device_printf (block->nmb_dev, "status: %x\n", status);
-       return;
+       block = adapter;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       ifp = sc->ifp;
+       if (ifp->if_flags & IFF_DEBUG)
+               device_printf(sc->ndis_dev, "status: %x\n", status);
 }
 
-__stdcall static void
+static void
 ndis_statusdone_func(ndis_handle adapter)
 {
        ndis_miniport_block     *block;
+       struct ndis_softc       *sc;
+       struct ifnet            *ifp;
+
        block = adapter;
-       
-       if (block->nmb_ifp->if_flags & IFF_DEBUG)
-               device_printf (block->nmb_dev, "status complete\n");
-       return;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       ifp = sc->ifp;
+       if (ifp->if_flags & IFF_DEBUG)
+               device_printf(sc->ndis_dev, "status complete\n");
 }
 
-__stdcall static void
+static void
 ndis_setdone_func(ndis_handle adapter, ndis_status status)
 {
        ndis_miniport_block     *block;
        block = adapter;
 
        block->nmb_setstat = status;
-       wakeup(&block->nmb_wkupdpctimer);
-       return;
+       KeSetEvent(&block->nmb_setevent, IO_NO_INCREMENT, FALSE);
 }
 
-__stdcall static void
+static void
 ndis_getdone_func(ndis_handle adapter, ndis_status status)
 {
        ndis_miniport_block     *block;
        block = adapter;
 
        block->nmb_getstat = status;
-       wakeup(&block->nmb_wkupdpctimer);
-       return;
+       KeSetEvent(&block->nmb_getevent, IO_NO_INCREMENT, FALSE);
 }
 
-__stdcall static void
+static void
 ndis_resetdone_func(ndis_handle adapter, ndis_status status,
-                   uint8_t addressingreset)
+       uint8_t addressingreset)
 {
        ndis_miniport_block     *block;
+       struct ndis_softc       *sc;
+       struct ifnet            *ifp;
+
        block = adapter;
+       sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+       ifp = sc->ifp;
 
-       if (block->nmb_ifp->if_flags & IFF_DEBUG)
-               device_printf (block->nmb_dev, "reset done...\n");
-       wakeup(block->nmb_ifp);
-       return;
+       if (ifp->if_flags & IFF_DEBUG)
+               device_printf(sc->ndis_dev, "reset done...\n");
+       KeSetEvent(&block->nmb_resetevent, IO_NO_INCREMENT, FALSE);
 }
 
 int
@@ -561,16 +264,17 @@ ndis_create_sysctls(void *arg)
        struct ndis_softc       *sc;
        ndis_cfg                *vals;
        char                    buf[256];
+       struct sysctl_oid       *oidp;
+       struct sysctl_ctx_entry *e;
 
        if (arg == NULL)
-               return(EINVAL);
+               return (EINVAL);
 
        sc = arg;
        vals = sc->ndis_regvals;
 
        TAILQ_INIT(&sc->ndis_cfglist_head);
 
-#if __FreeBSD_version < 502113
        /* Create the sysctl tree. */
 
        sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
@@ -578,32 +282,34 @@ ndis_create_sysctls(void *arg)
            device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
            device_get_desc(sc->ndis_dev));
 
-#endif
        /* Add the driver-specific registry keys. */
 
-       vals = sc->ndis_regvals;
        while(1) {
                if (vals->nc_cfgkey == NULL)
                        break;
+
                if (vals->nc_idx != sc->ndis_devidx) {
                        vals++;
                        continue;
                }
-#if 1
-               SYSCTL_ADD_STRING(&sc->ndis_ctx,
-                   SYSCTL_CHILDREN(sc->ndis_tree),
-                   OID_AUTO, vals->nc_cfgkey,
-                   CTLFLAG_RW, vals->nc_val,
-                   sizeof(vals->nc_val),
-                   vals->nc_cfgdesc);
-#else
-               SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
-                   SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
-                   OID_AUTO, vals->nc_cfgkey,
-                   CTLFLAG_RW, vals->nc_val,
-                   sizeof(vals->nc_val),
-                   vals->nc_cfgdesc);
-#endif
+
+               /* See if we already have a sysctl with this name */
+
+               oidp = NULL;
+               TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
+                       oidp = e->entry;
+                       if (strcasecmp(oidp->oid_name, vals->nc_cfgkey) == 0)
+                               break;
+                       oidp = NULL;
+               }
+
+               if (oidp != NULL) {
+                       vals++;
+                       continue;
+               }
+
+               ndis_add_sysctl(sc, vals->nc_cfgkey, vals->nc_cfgdesc,
+                   vals->nc_val, CTLFLAG_RW);
                vals++;
        }
 
@@ -620,6 +326,16 @@ ndis_create_sysctls(void *arg)
        ndis_add_sysctl(sc, "NdisVersion",
            "NDIS API Version", "0x00050001", CTLFLAG_RD);
 
+       /*
+        * Some miniport drivers rely on the existence of the SlotNumber,
+        * NetCfgInstanceId and DriverDesc keys.
+        */
+       ndis_add_sysctl(sc, "SlotNumber", "Slot Numer", "01", CTLFLAG_RD);
+       ndis_add_sysctl(sc, "NetCfgInstanceId", "NetCfgInstanceId",
+           "{12345678-1234-5678-CAFE0-123456789ABC}", CTLFLAG_RD);
+       ndis_add_sysctl(sc, "DriverDesc", "Driver Description",
+           "NDIS Network Adapter", CTLFLAG_RD);
+
        /* Bus type (PCI, PCMCIA, etc...) */
        ksprintf(buf, "%d", (int)sc->ndis_iftype);
        ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
@@ -636,7 +352,7 @@ ndis_create_sysctls(void *arg)
                    "Interrupt Number", buf, CTLFLAG_RD);
        }
 
-       return(0);
+       return (0);
 }
 
 int
@@ -659,97 +375,130 @@ ndis_add_sysctl(void *arg, char *key, char *desc, char *val, int flag)
 
        TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
 
-#if 1
+       cfg->ndis_oid =
        SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
            OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
            cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
            cfg->ndis_cfg.nc_cfgdesc);
-#else
-       SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
-           SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
-           OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
-           cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
-           cfg->ndis_cfg.nc_cfgdesc);
-#endif
 
-       return(0);
+       return (0);
 }
 
+/*
+ * Somewhere, somebody decided "hey, let's automatically create
+ * a sysctl tree for each device instance as it's created -- it'll
+ * make life so much easier!" Lies. Why must they turn the kernel
+ * into a house of lies?
+ */
+
 int
 ndis_flush_sysctls(void *arg)
 {
        struct ndis_softc       *sc;
        struct ndis_cfglist     *cfg;
+       struct sysctl_ctx_list  *clist;
 
        sc = arg;
 
+       clist = &sc->ndis_ctx;
+
        while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
                cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
                TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
+               sysctl_ctx_entry_del(clist, cfg->ndis_oid);
+               sysctl_remove_oid(cfg->ndis_oid, 1, 0);
                kfree(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
                kfree(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
                kfree(cfg, M_DEVBUF);
        }
 
-       return(0);
+       return (0);
+}
+
+void *
+ndis_get_routine_address(struct image_patch_table *functbl, char *name)
+{
+       int                     i;
+
+       for (i = 0; functbl[i].ipt_name != NULL; i++)
+               if (strcmp(name, functbl[i].ipt_name) == 0)
+                       return (functbl[i].ipt_wrap);
+       return (NULL);
 }
 
 static void
-ndis_return(void *arg)
+ndis_return(device_object *dobj, void *arg)
 {
-       struct ndis_softc       *sc;
+       ndis_miniport_block     *block;
+       ndis_miniport_characteristics   *ch;
        ndis_return_handler     returnfunc;
        ndis_handle             adapter;
        ndis_packet             *p;
        uint8_t                 irql;
+       list_entry              *l;
+
+       block = arg;
+       ch = IoGetDriverObjectExtension(dobj->do_drvobj, (void *)1);
 
        p = arg;
-       sc = p->np_softc;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
+       adapter = block->nmb_miniportadapterctx;
 
        if (adapter == NULL)
                return;
 
-       returnfunc = sc->ndis_chars.nmc_return_packet_func;
-       irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
-       returnfunc(adapter, p);
-       FASTCALL1(hal_lower_irql, irql);
+       returnfunc = ch->nmc_return_packet_func;
 
-       return;
+       KeAcquireSpinLock(&block->nmb_returnlock, &irql);
+       while (!IsListEmpty(&block->nmb_returnlist)) {
+               l = RemoveHeadList((&block->nmb_returnlist));
+               p = CONTAINING_RECORD(l, ndis_packet, np_list);
+               InitializeListHead((&p->np_list));
+               KeReleaseSpinLock(&block->nmb_returnlock, irql);
+               MSCALL2(returnfunc, adapter, p);
+               KeAcquireSpinLock(&block->nmb_returnlock, &irql);
+       }
+       KeReleaseSpinLock(&block->nmb_returnlock, irql);
 }
 
 static void
-ndis_extref_packet(void *arg)
+ndis_reference_packet(void *arg)
 {
-       ndis_packet     *p = arg;
+       ndis_packet             *p;
+
+       if (arg == NULL)
+               return;
+
+       p = arg;
 
-       ++p->np_refcnt;
+       /* Increment refcount. */
+       atomic_add_int(&p->np_refcnt, 1);
 }
 
-static void
-ndis_extfree_packet(void *arg)
+void
+ndis_return_packet(void *arg)
 {
-       ndis_packet     *p = arg;
+       ndis_packet             *p;
+       ndis_miniport_block     *block;
 
-       if (p == NULL)
+       if (arg == NULL)
                return;
 
-       /* Decrement refcount. */
-       p->np_refcnt--;
+       p = arg;
 
        /* Release packet when refcount hits zero, otherwise return. */
-       if (p->np_refcnt)
+       if (atomic_fetchadd_int(&p->np_refcnt, -1) > 1)
                return;
 
-       ndis_sched(ndis_return, p, NDIS_SWI);
+       block = ((struct ndis_softc *)p->np_softc)->ndis_block;
 
-       return;
-}
+       KeAcquireSpinLockAtDpcLevel(&block->nmb_returnlock);
+       InitializeListHead((&p->np_list));
+       InsertHeadList((&block->nmb_returnlist), (&p->np_list));
+       KeReleaseSpinLockFromDpcLevel(&block->nmb_returnlock);
 
-void
-ndis_return_packet(struct ndis_softc *sc, ndis_packet *p)
-{
-       ndis_extfree_packet(p);
+       IoQueueWorkItem(block->nmb_returnitem,
+           (io_workitem_func)kernndis_functbl[7].ipt_wrap,
+           WORKQUEUE_CRITICAL, block);
 }
 
 void
@@ -761,12 +510,10 @@ ndis_free_bufs(ndis_buffer *b0)
                return;
 
        while(b0 != NULL) {
-               next = b0->nb_next;
-               kfree(b0, M_NDIS_BUFFER);
+               next = b0->mdl_next;
+               IoFreeMdl(b0);
                b0 = next;
        }
-
-       return;
 }
 
 void
@@ -776,9 +523,7 @@ ndis_free_packet(ndis_packet *p)
                return;
 
        ndis_free_bufs(p->np_private.npp_head);
-       kfree(p, M_NDIS_PACKET);
-
-       return;
+       NdisFreePacket(p);
 }
 
 int
@@ -790,12 +535,13 @@ ndis_convert_res(void *arg)
        ndis_miniport_block     *block;
        device_t                dev;
        struct resource_list    *brl;
+       struct resource_list_entry      *brle;
        struct resource_list    brl_rev;
-       struct resource_list_entry      *brle, *n;
-       int                     error = 0;
+       struct resource_list_entry      *n;
+       int                     error = 0;
 
        sc = arg;
-       block = &sc->ndis_block;
+       block = sc->ndis_block;
        dev = sc->ndis_dev;
 
        SLIST_INIT(&brl_rev);
@@ -805,7 +551,7 @@ ndis_convert_res(void *arg)
            M_DEVBUF, M_WAITOK|M_NULLOK|M_ZERO);
 
        if (rl == NULL)
-               return(ENOMEM);
+               return (ENOMEM);
 
        rl->cprl_version = 5;
        rl->cprl_version = 1;
@@ -829,6 +575,7 @@ ndis_convert_res(void *arg)
                 * in order to fix this, we have to create our own
                 * temporary list with the entries in reverse order.
                 */
+
                SLIST_FOREACH(brle, brl, link) {
                        n = kmalloc(sizeof(struct resource_list_entry),
                            M_TEMP, M_WAITOK|M_NULLOK);
@@ -858,15 +605,20 @@ ndis_convert_res(void *arg)
                                    CM_RESOURCE_MEMORY_READ_WRITE;
                                prd->cprd_sharedisp =
                                    CmResourceShareDeviceExclusive;
-                               prd->u.cprd_port.cprd_start.np_quad =
+                               prd->u.cprd_mem.cprd_start.np_quad =
                                    brle->start;
-                               prd->u.cprd_port.cprd_len = brle->count;
+                               prd->u.cprd_mem.cprd_len = brle->count;
                                break;
                        case SYS_RES_IRQ:
                                prd->cprd_type = CmResourceTypeInterrupt;
                                prd->cprd_flags = 0;
+                               /*
+                                * Always mark interrupt resources as
+                                * shared, since in our implementation,
+                                * they will be.
+                                */
                                prd->cprd_sharedisp =
-                                   CmResourceShareDeviceExclusive;
+                                   CmResourceShareShared;
                                prd->u.cprd_intr.cprd_level = brle->start;
                                prd->u.cprd_intr.cprd_vector = brle->start;
                                prd->u.cprd_intr.cprd_affinity = 0;
@@ -888,7 +640,7 @@ bad:
                kfree (n, M_TEMP);
        }
 
-       return(error);
+       return (error);
 }
 
 /*
@@ -900,48 +652,46 @@ bad:
  * the ndis_packet as external storage. In most cases, this will
  * point to a memory region allocated by the driver (either by
  * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
- * the driver to handle free()ing this region for is, so we set up
+ * the driver to handle kfree()ing this region for is, so we set up
  * a dummy no-op free handler for it.
- */ 
+ */
 
 int
 ndis_ptom(struct mbuf **m0, ndis_packet *p)
 {
-       struct mbuf             *m, *prev = NULL;
+       struct mbuf             *m = NULL, *prev = NULL;
        ndis_buffer             *buf;
        ndis_packet_private     *priv;
        uint32_t                totlen = 0;
+       struct ifnet            *ifp;
+       struct ether_header     *eh;
+       int                     diff;
 
        if (p == NULL || m0 == NULL)
-               return(EINVAL);
+               return (EINVAL);
 
        priv = &p->np_private;
        buf = priv->npp_head;
        p->np_refcnt = 0;
 
-       for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
-               if (buf == priv->npp_head)
-                       MGETHDR(m, MB_DONTWAIT, MT_HEADER);
-               else
+       for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) {
+               if (buf == priv->npp_head) {
+                       /* XXX swildner: why not MT_HEADER? (see FreeBSD) */
+                       MGETHDR(m, MB_DONTWAIT, MT_DATA);
+               } else {
                        MGET(m, MB_DONTWAIT, MT_DATA);
+               }
                if (m == NULL) {
                        m_freem(*m0);
                        *m0 = NULL;
-                       return(ENOBUFS);
+                       return (ENOBUFS);
                }
-               m->m_len = buf->nb_bytecount;
-               m->m_data = MDL_VA(buf);
-               m->m_ext.ext_free = ndis_extfree_packet;
-               m->m_ext.ext_ref = ndis_extref_packet;
-               m->m_ext.ext_arg = p;
-               m->m_ext.ext_buf = m->m_data;
-               m->m_ext.ext_size = m->m_len;
-               m->m_flags |= M_EXT;
-#if 0
-               MEXTADD(m, m->m_data, m->m_len, ndis_free_packet,
-                   p, 0, EXT_NDIS);
-#endif
-               p->np_refcnt++;
+               m->m_len = MmGetMdlByteCount(buf);
+               m->m_data = MmGetMdlVirtualAddress(buf);
+               m_extadd(m, m->m_data, m->m_len, ndis_reference_packet,
+                   ndis_return_packet, p);
+//             p->np_refcnt++;
+
                totlen += m->m_len;
                if (m->m_flags & M_PKTHDR)
                        *m0 = m;
@@ -950,13 +700,31 @@ ndis_ptom(struct mbuf **m0, ndis_packet *p)
                prev = m;
        }
 
+       /*
+        * This is a hack to deal with the Marvell 8335 driver
+        * which, when associated with an AP in WPA-PSK mode,
+        * seems to overpad its frames by 8 bytes. I don't know
+        * that the extra 8 bytes are for, and they're not there
+        * in open mode, so for now clamp the frame size at 1514
+        * until I can figure out how to deal with this properly,
+        * otherwise if_ethersubr() will spank us by discarding
+        * the 'oversize' frames.
+        */
+
+       eh = mtod((*m0), struct ether_header *);
+       ifp = ((struct ndis_softc *)p->np_softc)->ifp;
+       if (totlen > ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE)) {
+               diff = totlen - ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE);
+               totlen -= diff;
+               m->m_len -= diff;
+       }
        (*m0)->m_pkthdr.len = totlen;
 
-       return(0);
+       return (0);
 }
 
 /*
- * Create an mbuf chain from an NDIS packet chain.
+ * Create an NDIS packet from an mbuf chain.
  * This is used mainly when transmitting packets, where we need
  * to turn an mbuf off an interface's send queue and transform it
  * into an NDIS packet which will be fed into the NDIS driver's
@@ -977,43 +745,33 @@ ndis_mtop(struct mbuf *m0, ndis_packet **p)
        ndis_buffer             *buf = NULL, *prev = NULL;
        ndis_packet_private     *priv;
 
-       if (p == NULL || m0 == NULL)
-               return(EINVAL);
+       if (p == NULL || *p == NULL || m0 == NULL)
+               return (EINVAL);
 
-       /* If caller didn't supply a packet, make one. */
-       if (*p == NULL) {
-               *p = kmalloc(sizeof(ndis_packet), M_NDIS_PACKET, M_NOWAIT|M_ZERO);
-               if (*p == NULL)
-                       return(ENOMEM);
-       }
-       
        priv = &(*p)->np_private;
        priv->npp_totlen = m0->m_pkthdr.len;
-        priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
-       priv->npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
 
        for (m = m0; m != NULL; m = m->m_next) {
                if (m->m_len == 0)
                        continue;
-               buf = kmalloc(sizeof(ndis_buffer), M_NDIS_BUFFER, M_NOWAIT|M_ZERO);
+               buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL);
                if (buf == NULL) {
                        ndis_free_packet(*p);
                        *p = NULL;
-                       return(ENOMEM);
+                       return (ENOMEM);
                }
+               MmBuildMdlForNonPagedPool(buf);
 
-               MDL_INIT(buf, m->m_data, m->m_len);
                if (priv->npp_head == NULL)
                        priv->npp_head = buf;
                else
-                       prev->nb_next = buf;
+                       prev->mdl_next = buf;
                prev = buf;
        }
 
        priv->npp_tail = buf;
-       priv->npp_totlen = m0->m_pkthdr.len;
 
-       return(0);
+       return (0);
 }
 
 int
@@ -1023,7 +781,7 @@ ndis_get_supported_oids(void *arg, ndis_oid **oids, int *oidcnt)
        ndis_oid                *o;
 
        if (arg == NULL || oids == NULL || oidcnt == NULL)
-               return(EINVAL);
+               return (EINVAL);
        len = 0;
        ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
 
@@ -1033,13 +791,13 @@ ndis_get_supported_oids(void *arg, ndis_oid **oids, int *oidcnt)
 
        if (rval) {
                kfree(o, M_DEVBUF);
-               return(rval);
+               return (rval);
        }
 
        *oids = o;
        *oidcnt = len / 4;
 
-       return(0);
+       return (0);
 }
 
 int
@@ -1050,25 +808,51 @@ ndis_set_info(void *arg, ndis_oid oid, void *buf, int *buflen)
        ndis_handle             adapter;
        ndis_setinfo_handler    setfunc;
        uint32_t                byteswritten = 0, bytesneeded = 0;
-       int                     error;
        uint8_t                 irql;
+       uint64_t                duetime;
+
+       /*
+        * According to the NDIS spec, MiniportQueryInformation()
+        * and MiniportSetInformation() requests are handled serially:
+        * once one request has been issued, we must wait for it to
+        * finish before allowing another request to proceed.
+        */
 
        sc = arg;
-       setfunc = sc->ndis_chars.nmc_setinfo_func;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
 
-       if (adapter == NULL || setfunc == NULL)
-               return(ENXIO);
+       KeResetEvent(&sc->ndis_block->nmb_setevent);
+
+       KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+
+       if (sc->ndis_block->nmb_pendingreq != NULL) {
+               KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+               panic("ndis_set_info() called while other request pending");
+       } else
+               sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
+
+       setfunc = sc->ndis_chars->nmc_setinfo_func;
+       adapter = sc->ndis_block->nmb_miniportadapterctx;
+
+       if (adapter == NULL || setfunc == NULL ||
+           sc->ndis_block->nmb_devicectx == NULL) {
+               sc->ndis_block->nmb_pendingreq = NULL;
+               KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+               return (ENXIO);
+       }
 
-       irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
-       rval = setfunc(adapter, oid, buf, *buflen,
+       rval = MSCALL6(setfunc, adapter, oid, buf, *buflen,
            &byteswritten, &bytesneeded);
-       FASTCALL1(hal_lower_irql, irql);
+
+       sc->ndis_block->nmb_pendingreq = NULL;
+
+       KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 
        if (rval == NDIS_STATUS_PENDING) {
-               error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
-                   0, "ndisset", 5 * hz);
-               rval = sc->ndis_block.nmb_setstat;
+               /* Wait up to 5 seconds. */
+               duetime = (5 * 1000000) * -10;
+               KeWaitForSingleObject(&sc->ndis_block->nmb_setevent,
+                   0, 0, FALSE, &duetime);
+               rval = sc->ndis_block->nmb_setstat;
        }
 
        if (byteswritten)
@@ -1077,22 +861,22 @@ ndis_set_info(void *arg, ndis_oid oid, void *buf, int *buflen)
                *buflen = bytesneeded;
 
        if (rval == NDIS_STATUS_INVALID_LENGTH)
-               return(ENOSPC);
+               return (ENOSPC);
 
        if (rval == NDIS_STATUS_INVALID_OID)
-               return(EINVAL);
+               return (EINVAL);
 
        if (rval == NDIS_STATUS_NOT_SUPPORTED ||
            rval == NDIS_STATUS_NOT_ACCEPTED)
-               return(ENOTSUP);
+               return (ENOTSUP);
 
        if (rval != NDIS_STATUS_SUCCESS)
-               return(ENODEV);
+               return (ENODEV);
 
-       return(0);
+       return (0);
 }
 
-typedef __stdcall void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status);
+typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status);
 
 int
 ndis_send_packets(void *arg, ndis_packet **packets, int cnt)
@@ -1100,20 +884,22 @@ ndis_send_packets(void *arg, ndis_packet **packets, int cnt)
        struct ndis_softc       *sc;
        ndis_handle             adapter;
        ndis_sendmulti_handler  sendfunc;
-       ndis_senddone_func      senddonefunc;
+       ndis_senddone_func              senddonefunc;
        int                     i;
        ndis_packet             *p;
-       uint8_t                 irql;
+       uint8_t                 irql = 0;
 
        sc = arg;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
+       adapter = sc->ndis_block->nmb_miniportadapterctx;
        if (adapter == NULL)
-               return(ENXIO);
-       sendfunc = sc->ndis_chars.nmc_sendmulti_func;
-       senddonefunc = sc->ndis_block.nmb_senddone_func;
-       irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
-       sendfunc(adapter, packets, cnt);
-       FASTCALL1(hal_lower_irql, irql);
+               return (ENXIO);
+       sendfunc = sc->ndis_chars->nmc_sendmulti_func;
+       senddonefunc = sc->ndis_block->nmb_senddone_func;
+
+       if (NDIS_SERIALIZED(sc->ndis_block))
+               KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+
+       MSCALL3(sendfunc, adapter, packets, cnt);
 
        for (i = 0; i < cnt; i++) {
                p = packets[i];
@@ -1125,9 +911,12 @@ ndis_send_packets(void *arg, ndis_packet **packets, int cnt)
                 */
                if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
                        continue;
-               senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status);
+               MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status);
        }
 
+       if (NDIS_SERIALIZED(sc->ndis_block))
+               KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+
        return(0);
 }
 
@@ -1138,26 +927,33 @@ ndis_send_packet(void *arg, ndis_packet *packet)
        ndis_handle             adapter;
        ndis_status             status;
        ndis_sendsingle_handler sendfunc;
-       ndis_senddone_func      senddonefunc;
-       uint8_t                 irql;
+       ndis_senddone_func              senddonefunc;
+       uint8_t                 irql = 0;
 
        sc = arg;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
+       adapter = sc->ndis_block->nmb_miniportadapterctx;
        if (adapter == NULL)
-               return(ENXIO);
-       sendfunc = sc->ndis_chars.nmc_sendsingle_func;
-       senddonefunc = sc->ndis_block.nmb_senddone_func;
-
-       irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
-       status = sendfunc(adapter, packet, packet->np_private.npp_flags);
-       FASTCALL1(hal_lower_irql, irql);
+               return (ENXIO);
+       sendfunc = sc->ndis_chars->nmc_sendsingle_func;
+       senddonefunc = sc->ndis_block->nmb_senddone_func;
+
+       if (NDIS_SERIALIZED(sc->ndis_block))
+               KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+       status = MSCALL3(sendfunc, adapter, packet,
+           packet->np_private.npp_flags);
+
+       if (status == NDIS_STATUS_PENDING) {
+               if (NDIS_SERIALIZED(sc->ndis_block))
+                       KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+               return (0);
+       }
 
-       if (status == NDIS_STATUS_PENDING)
-               return(0);
+       MSCALL3(senddonefunc, sc->ndis_block, packet, status);
 
-       senddonefunc(&sc->ndis_block, packet, status);
+       if (NDIS_SERIALIZED(sc->ndis_block))
+               KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 
-       return(0);
+       return (0);
 }
 
 int
@@ -1176,11 +972,11 @@ ndis_init_dma(void *arg)
                    &sc->ndis_tmaps[i]);
                if (error) {
                        kfree(sc->ndis_tmaps, M_DEVBUF);
-                       return(ENODEV);
+                       return (ENODEV);
                }
        }
 
-       return(0);
+       return (0);
 }
 
 int
@@ -1203,11 +999,12 @@ ndis_destroy_dma(void *arg)
                }
                bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
        }
-       if (sc->ndis_tmaps)
-               kfree(sc->ndis_tmaps, M_DEVBUF);
+
+       kfree(sc->ndis_tmaps, M_DEVBUF);
+
        bus_dma_tag_destroy(sc->ndis_ttag);
 
-       return(0);
+       return (0);
 }
 
 int
@@ -1218,23 +1015,37 @@ ndis_reset_nic(void *arg)
        ndis_reset_handler      resetfunc;
        uint8_t                 addressing_reset;
        int                     rval;
-       uint8_t                 irql;
+       uint8_t                 irql = 0;
 
        sc = arg;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
-       resetfunc = sc->ndis_chars.nmc_reset_func;
-       if (adapter == NULL || resetfunc == NULL)
-               return(EIO);
 
-       irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
-       rval = resetfunc(&addressing_reset, adapter);
-       FASTCALL1(hal_lower_irql, irql);
+       NDIS_LOCK(sc);
+       adapter = sc->ndis_block->nmb_miniportadapterctx;
+       resetfunc = sc->ndis_chars->nmc_reset_func;
 
-       if (rval == NDIS_STATUS_PENDING) {
-               tsleep(sc, 0, "ndisrst", 0);
+       if (adapter == NULL || resetfunc == NULL ||
+           sc->ndis_block->nmb_devicectx == NULL) {
+               NDIS_UNLOCK(sc);
+               return(EIO);
        }
 
-       return(0);
+       NDIS_UNLOCK(sc);
+
+       KeResetEvent(&sc->ndis_block->nmb_resetevent);
+
+       if (NDIS_SERIALIZED(sc->ndis_block))
+               KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+
+       rval = MSCALL2(resetfunc, &addressing_reset, adapter);
+
+       if (NDIS_SERIALIZED(sc->ndis_block))
+               KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+
+       if (rval == NDIS_STATUS_PENDING)
+               KeWaitForSingleObject(&sc->ndis_block->nmb_resetevent,
+                   0, 0, FALSE, NULL);
+
+       return (0);
 }
 
 int
@@ -1243,27 +1054,54 @@ ndis_halt_nic(void *arg)
        struct ndis_softc       *sc;
        ndis_handle             adapter;
        ndis_halt_handler       haltfunc;
+       ndis_miniport_block     *block;
+       int                     empty = 0;
+       uint8_t                 irql;
 
        sc = arg;
+       block = sc->ndis_block;
 
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
+       if (!cold)
+               KeFlushQueuedDpcs();
+
+       /*
+        * Wait for all packets to be returned.
+        */
+
+       while (1) {
+               KeAcquireSpinLock(&block->nmb_returnlock, &irql);
+               empty = IsListEmpty(&block->nmb_returnlist);
+               KeReleaseSpinLock(&block->nmb_returnlock, irql);
+               if (empty)
+                       break;
+               NdisMSleep(1000);
+       }
+
+       NDIS_LOCK(sc);
+       adapter = sc->ndis_block->nmb_miniportadapterctx;
        if (adapter == NULL) {
-               return(EIO);
+               NDIS_UNLOCK(sc);
+               return (EIO);
        }
 
+       sc->ndis_block->nmb_devicectx = NULL;
+
        /*
         * The adapter context is only valid after the init
         * handler has been called, and is invalid once the
         * halt handler has been called.
         */
 
-       haltfunc = sc->ndis_chars.nmc_halt_func;
+       haltfunc = sc->ndis_chars->nmc_halt_func;
+       NDIS_UNLOCK(sc);
 
-       haltfunc(adapter);
+       MSCALL1(haltfunc, adapter);
 
-       sc->ndis_block.nmb_miniportadapterctx = NULL;
+       NDIS_LOCK(sc);
+       sc->ndis_block->nmb_miniportadapterctx = NULL;
+       NDIS_UNLOCK(sc);
 
-       return(0);
+       return (0);
 }
 
 int
@@ -1274,23 +1112,49 @@ ndis_shutdown_nic(void *arg)
        ndis_shutdown_handler   shutdownfunc;
 
        sc = arg;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
-       shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
+       NDIS_LOCK(sc);
+       adapter = sc->ndis_block->nmb_miniportadapterctx;
+       shutdownfunc = sc->ndis_chars->nmc_shutdown_handler;
+       NDIS_UNLOCK(sc);
        if (adapter == NULL || shutdownfunc == NULL)
-               return(EIO);
+               return (EIO);
 
-       if (sc->ndis_chars.nmc_rsvd0 == NULL)
-               shutdownfunc(adapter);
+       if (sc->ndis_chars->nmc_rsvd0 == NULL)
+               MSCALL1(shutdownfunc, adapter);
        else
-               shutdownfunc(sc->ndis_chars.nmc_rsvd0);
+               MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0);
 
-       ndis_shrink_thrqueue(8);
-       TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link);
+       TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
 
        return(0);
 }
 
 int
+ndis_pnpevent_nic(void *arg, int type)
+{
+       device_t                dev;
+       struct ndis_softc       *sc;
+       ndis_handle             adapter;
+       ndis_pnpevent_handler   pnpeventfunc;
+
+       dev = arg;
+       sc = device_get_softc(arg);
+       NDIS_LOCK(sc);
+       adapter = sc->ndis_block->nmb_miniportadapterctx;
+       pnpeventfunc = sc->ndis_chars->nmc_pnpevent_handler;
+       NDIS_UNLOCK(sc);
+       if (adapter == NULL || pnpeventfunc == NULL)
+               return (EIO);
+
+       if (sc->ndis_chars->nmc_rsvd0 == NULL)
+               MSCALL4(pnpeventfunc, adapter, type, NULL, 0);
+       else
+               MSCALL4(pnpeventfunc, sc->ndis_chars->nmc_rsvd0, type, NULL, 0);
+
+       return (0);
+}
+
+int
 ndis_init_nic(void *arg)
 {
        struct ndis_softc       *sc;
@@ -1301,18 +1165,20 @@ ndis_init_nic(void *arg)
        uint32_t                chosenmedium, i;
 
        if (arg == NULL)
-               return(EINVAL);
+               return (EINVAL);
 
        sc = arg;
-       block = &sc->ndis_block;
-       initfunc = sc->ndis_chars.nmc_init_func;
+       NDIS_LOCK(sc);
+       block = sc->ndis_block;
+       initfunc = sc->ndis_chars->nmc_init_func;
+       NDIS_UNLOCK(sc);
 
-       TAILQ_INIT(&block->nmb_timerlist);
+       sc->ndis_block->nmb_timerlist = NULL;
 
        for (i = 0; i < NdisMediumMax; i++)
                mediumarray[i] = i;
 
-        status = initfunc(&openstatus, &chosenmedium,
+        status = MSCALL6(initfunc, &openstatus, &chosenmedium,
             mediumarray, NdisMediumMax, block, block);
 
        /*
@@ -1321,90 +1187,48 @@ ndis_init_nic(void *arg)
         * If the init failed, none of these will work.
         */
        if (status != NDIS_STATUS_SUCCESS) {
-               sc->ndis_block.nmb_miniportadapterctx = NULL;
-               return(ENXIO);
+               NDIS_LOCK(sc);
+               sc->ndis_block->nmb_miniportadapterctx = NULL;
+               NDIS_UNLOCK(sc);
+               return (ENXIO);
        }
 
-       return(0);
-}
-
-void
-ndis_enable_intr(void *arg)
-{
-       struct ndis_softc       *sc;
-       ndis_handle             adapter;
-       ndis_enable_interrupts_handler  intrenbfunc;
-
-       sc = arg;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
-       intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
-       if (adapter == NULL || intrenbfunc == NULL)
-               return;
-       intrenbfunc(adapter);
-
-       return;
-}
-
-void
-ndis_disable_intr(void *arg)
-{
-       struct ndis_softc       *sc;
-       ndis_handle             adapter;
-       ndis_disable_interrupts_handler intrdisfunc;
-
-       sc = arg;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
-       intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
-       if (adapter == NULL || intrdisfunc == NULL)
-           return;
-       intrdisfunc(adapter);
-
-       return;
-}
-
-int
-ndis_isr(void *arg, int *ourintr, int *callhandler)
-{
-       struct ndis_softc       *sc;
-       ndis_handle             adapter;
-       ndis_isr_handler        isrfunc;
-       uint8_t                 accepted, queue;
-
-       if (arg == NULL || ourintr == NULL || callhandler == NULL)
-               return(EINVAL);
+       /*
+        * This may look really goofy, but apparently it is possible
+        * to halt a miniport too soon after it's been initialized.
+        * After MiniportInitialize() finishes, pause for 1 second
+        * to give the chip a chance to handle any short-lived timers
+        * that were set in motion. If we call MiniportHalt() too soon,
+        * some of the timers may not be cancelled, because the driver
+        * expects them to fire before the halt is called.
+        */
 
-       sc = arg;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
-       isrfunc = sc->ndis_chars.nmc_isr_func;
-       if (adapter == NULL || isrfunc == NULL)
-               return(ENXIO);
+       tsleep(arg, 0, "ndwait", hz);
 
-       isrfunc(&accepted, &queue, adapter);
-       *ourintr = accepted;
-       *callhandler = queue;
+       NDIS_LOCK(sc);
+       sc->ndis_block->nmb_devicectx = sc;
+       NDIS_UNLOCK(sc);
 
-       return(0);
+       return (0);
 }
 
-int
-ndis_intrhand(void *arg)
+static void
+ndis_intrsetup(kdpc *dpc, device_object *dobj, irp *ip, struct ndis_softc *sc)
 {
-       struct ndis_softc       *sc;
-       ndis_handle             adapter;
-       ndis_interrupt_handler  intrfunc;
+       ndis_miniport_interrupt *intr;
 
-       if (arg == NULL)
-               return(EINVAL);
+       intr = sc->ndis_block->nmb_interrupt;
 
-       sc = arg;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
-       intrfunc = sc->ndis_chars.nmc_interrupt_func;
-       if (adapter == NULL || intrfunc == NULL)
-               return(EINVAL);
+       /* Sanity check. */
 
-       intrfunc(adapter);
+       if (intr == NULL)
+               return;
 
-       return(0);
+       KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
+       KeResetEvent(&intr->ni_dpcevt);
+       if (KeInsertQueueDpc(&intr->ni_dpc, NULL, NULL) == TRUE)
+               intr->ni_dpccnt++;
+       KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
 }
 
 int
@@ -1415,27 +1239,46 @@ ndis_get_info(void *arg, ndis_oid oid, void *buf, int *buflen)
        ndis_handle             adapter;
        ndis_queryinfo_handler  queryfunc;
        uint32_t                byteswritten = 0, bytesneeded = 0;
-       int                     error;
        uint8_t                 irql;
+       uint64_t                duetime;
 
        sc = arg;
-       queryfunc = sc->ndis_chars.nmc_queryinfo_func;
-       adapter = sc->ndis_block.nmb_miniportadapterctx;
 
-       if (adapter == NULL || queryfunc == NULL)
-               return(ENXIO);
+       KeResetEvent(&sc->ndis_block->nmb_getevent);
+
+       KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+
+       if (sc->ndis_block->nmb_pendingreq != NULL) {
+               KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+               panic("ndis_get_info() called while other request pending");
+       } else
+               sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
+
+       queryfunc = sc->ndis_chars->nmc_queryinfo_func;
+       adapter = sc->ndis_block->nmb_miniportadapterctx;
+
+       if (adapter == NULL || queryfunc == NULL ||
+           sc->ndis_block->nmb_devicectx == NULL) {
+               sc->ndis_block->nmb_pendingreq = NULL;
+               KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+               return (ENXIO);
+       }
 
-       irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
-       rval = queryfunc(adapter, oid, buf, *buflen,
+       rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen,
            &byteswritten, &bytesneeded);
-       FASTCALL1(hal_lower_irql, irql);
+
+       sc->ndis_block->nmb_pendingreq = NULL;
+
+       KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 
        /* Wait for requests that block. */
 
        if (rval == NDIS_STATUS_PENDING) {
-               error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
-                   0, "ndisget", 5 * hz);
-               rval = sc->ndis_block.nmb_getstat;
+               /* Wait up to 5 seconds. */
+               duetime = (5 * 1000000) * -10;
+               KeWaitForSingleObject(&sc->ndis_block->nmb_getevent,
+                   0, 0, FALSE, &duetime);
+               rval = sc->ndis_block->nmb_getstat;
        }
 
        if (byteswritten)
@@ -1445,138 +1288,130 @@ ndis_get_info(void *arg, ndis_oid oid, void *buf, int *buflen)
 
        if (rval == NDIS_STATUS_INVALID_LENGTH ||
            rval == NDIS_STATUS_BUFFER_TOO_SHORT)
-               return(ENOSPC);
+               return (ENOSPC);
 
        if (rval == NDIS_STATUS_INVALID_OID)
-               return(EINVAL);
+               return (EINVAL);
 
        if (rval == NDIS_STATUS_NOT_SUPPORTED ||
            rval == NDIS_STATUS_NOT_ACCEPTED)
-               return(ENOTSUP);
+               return (ENOTSUP);
 
        if (rval != NDIS_STATUS_SUCCESS)
-               return(ENODEV);
+               return (ENODEV);
 
-       return(0);
+       return (0);
 }
 
-int
-ndis_unload_driver(void *arg)
+uint32_t
+NdisAddDevice(driver_object *drv, device_object *pdo)
 {
+       device_object           *fdo;
+       ndis_miniport_block     *block;
        struct ndis_softc       *sc;
+       uint32_t                status;
+       int                     error;
 
-       sc = arg;
+       sc = device_get_softc(pdo->do_devext);
 
-       kfree(sc->ndis_block.nmb_rlist, M_DEVBUF);
+        if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) {
+               error = bus_setup_intr(sc->ndis_dev, sc->ndis_irq,
+                   INTR_MPSAFE,
+                   ntoskrnl_intr, sc, &sc->ndis_intrhand, NULL);
+               if (error)
+                       return (NDIS_STATUS_FAILURE);
+       }
 
-       ndis_flush_sysctls(sc);
+       status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL,
+           FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
 
-       ndis_shrink_thrqueue(8);
-       TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link);
+       if (status != STATUS_SUCCESS)
+               return (status);
 
-       return(0);
-}
+       block = fdo->do_devext;
 
-#define NDIS_LOADED            htonl(0x42534F44)
+       block->nmb_filterdbs.nf_ethdb = block;
+       block->nmb_deviceobj = fdo;
+       block->nmb_physdeviceobj = pdo;
+       block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo);
+       KeInitializeSpinLock(&block->nmb_lock);
+       KeInitializeSpinLock(&block->nmb_returnlock);
+       KeInitializeEvent(&block->nmb_getevent, EVENT_TYPE_NOTIFY, TRUE);
+       KeInitializeEvent(&block->nmb_setevent, EVENT_TYPE_NOTIFY, TRUE);
+       KeInitializeEvent(&block->nmb_resetevent, EVENT_TYPE_NOTIFY, TRUE);
+       InitializeListHead(&block->nmb_parmlist);
+       InitializeListHead(&block->nmb_returnlist);
+       block->nmb_returnitem = IoAllocateWorkItem(fdo);
 
-int
-ndis_load_driver(vm_offset_t img, void *arg)
-{
-       driver_entry            entry;
-       image_optional_header   opt_hdr;
-       image_import_descriptor imp_desc;
-       ndis_unicode_string     dummystr;
-        ndis_miniport_block     *block;
-       ndis_status             status;
-       int                     idx;
-       uint32_t                *ptr;
-       struct ndis_softc       *sc;
-
-       sc = arg;
+       /*
+        * Stash pointers to the miniport block and miniport
+        * characteristics info in the if_ndis softc so the
+        * UNIX wrapper driver can get to them later.
+         */
+       sc->ndis_block = block;
+       sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1);
 
        /*
-        * Only perform the relocation/linking phase once
-        * since the binary image may be shared among multiple
-        * device instances.
+        * If the driver has a MiniportTransferData() function,
+        * we should allocate a private RX packet pool.
         */
 
-       ptr = (uint32_t *)(img + 8);
-       if (*ptr != NDIS_LOADED) {
-               /* Perform text relocation */
-               if (pe_relocate(img))
-                       return(ENOEXEC);
-
-               /* Dynamically link the NDIS.SYS routines -- required. */
-               if (pe_patch_imports(img, "NDIS", ndis_functbl))
-                       return(ENOEXEC);
-
-               /* Dynamically link the HAL.dll routines -- also required. */
-               if (pe_patch_imports(img, "HAL", hal_functbl))
-                       return(ENOEXEC);
-
-               /* Dynamically link ntoskrnl.exe -- optional. */
-               if (pe_get_import_descriptor(img,
-                   &imp_desc, "ntoskrnl") == 0) {
-                       if (pe_patch_imports(img,
-                           "ntoskrnl", ntoskrnl_functbl))
-                               return(ENOEXEC);
+       if (sc->ndis_chars->nmc_transferdata_func != NULL) {
+               NdisAllocatePacketPool(&status, &block->nmb_rxpool,
+                   32, PROTOCOL_RESERVED_SIZE_IN_PACKET);
+               if (status != NDIS_STATUS_SUCCESS) {
+                       IoDetachDevice(block->nmb_nextdeviceobj);
+                       IoDeleteDevice(fdo);
+                       return (status);
                }
-               *ptr = NDIS_LOADED;
+               InitializeListHead((&block->nmb_packetlist));
        }
 
-        /* Locate the driver entry point */
-       pe_get_optional_header(img, &opt_hdr);
-       entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
+       /* Give interrupt handling priority over timers. */
+       IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap);
+       KeSetImportanceDpc(&fdo->do_dpc, KDPC_IMPORTANCE_HIGH);
 
-       dummystr.nus_len = strlen(NDIS_DUMMY_PATH) * 2;
-       dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH) * 2;
-       dummystr.nus_buf = NULL;
-       ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
+       /* Finish up BSD-specific setup. */
 
-       /*
-        * Now that we have the miniport driver characteristics,
-        * create an NDIS block and call the init handler.
-        * This will cause the driver to try to probe for
-        * a device.
-        */
+       block->nmb_signature = (void *)0xcafebabe;
+       block->nmb_status_func = kernndis_functbl[0].ipt_wrap;
+       block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap;
+       block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap;
+       block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap;
+       block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap;
+       block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap;
+       block->nmb_pendingreq = NULL;
 
-       block = &sc->ndis_block;
+       TAILQ_INSERT_TAIL(&ndis_devhead, block, link);
 
-       ptr = (uint32_t *)block;
-       for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
-               *ptr = idx | 0xdead0000;
-               ptr++;
-       }
+       return (STATUS_SUCCESS);
+}
 
-       block->nmb_signature = (void *)0xcafebabe;
-       block->nmb_setdone_func = ndis_setdone_func;
-       block->nmb_querydone_func = ndis_getdone_func;
-       block->nmb_status_func = ndis_status_func;
-       block->nmb_statusdone_func = ndis_statusdone_func;
-       block->nmb_resetdone_func = ndis_resetdone_func;
-       block->nmb_sendrsrc_func = ndis_sendrsrcavail_func;
-
-       block->nmb_ifp = &sc->arpcom.ac_if;
-       block->nmb_dev = sc->ndis_dev;
-       block->nmb_img = img;
-       block->nmb_devobj.do_rsvd = block;
+int
+ndis_unload_driver(void *arg)
+{
+       struct ndis_softc       *sc;
+       device_object           *fdo;
 
-       /*
-        * Now call the DriverEntry() routine. This will cause
-        * a callout to the NdisInitializeWrapper() and
-        * NdisMRegisterMiniport() routines.
-        */
-       status = entry(&block->nmb_devobj, &dummystr);
+       sc = arg;
 
-       kfree (dummystr.nus_buf, M_DEVBUF);
+       if (sc->ndis_intrhand)
+               bus_teardown_intr(sc->ndis_dev,
+                   sc->ndis_irq, sc->ndis_intrhand);
 
-       if (status != NDIS_STATUS_SUCCESS)
-               return(ENODEV);
+       if (sc->ndis_block->nmb_rlist != NULL)
+               kfree(sc->ndis_block->nmb_rlist, M_DEVBUF);
 
-       ndis_enlarge_thrqueue(8);
+       ndis_flush_sysctls(sc);
 
-       TAILQ_INSERT_TAIL(&ndis_devhead, block, link);
+       TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
 
-       return(0);
-}
+       if (sc->ndis_chars->nmc_transferdata_func != NULL)
+               NdisFreePacketPool(sc->ndis_block->nmb_rxpool);
+       fdo = sc->ndis_block->nmb_deviceobj;
+       IoFreeWorkItem(sc->ndis_block->nmb_returnitem);
+       IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj);
+       IoDeleteDevice(fdo);
 
+       return (0);
+}
diff --git a/sys/emulation/ndis/kern_windrv.c b/sys/emulation/ndis/kern_windrv.c
new file mode 100644 (file)
index 0000000..ba2e5e5
--- /dev/null
@@ -0,0 +1,937 @@
+/*-
+ * Copyright (c) 2005
+ *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.21 2010/11/22 20:46:38 bschmidt Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/unistd.h>
+#include <sys/types.h>
+
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex2.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/mbuf.h>
+#include <sys/bus.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+
+#include <sys/queue.h>
+
+#ifdef __i386__
+#include <machine/segments.h>
+#endif
+
+#include <bus/usb/usb.h>
+#include <bus/usb/usbdi.h>
+
+#include <emulation/ndis/pe_var.h>
+#include <emulation/ndis/cfg_var.h>
+#include <emulation/ndis/resource_var.h>
+#include <emulation/ndis/ntoskrnl_var.h>
+#include <emulation/ndis/ndis_var.h>
+#include <emulation/ndis/hal_var.h>
+#include <emulation/ndis/usbd_var.h>
+
+static struct lock drvdb_lock;
+static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
+
+static driver_object   fake_pci_driver; /* serves both PCI and cardbus */
+static driver_object   fake_pccard_driver;
+
+#ifdef __i386__
+static void x86_oldldt(void *);
+static void x86_newldt(void *);
+
+struct tid {
+       void                    *tid_except_list;       /* 0x00 */
+       uint32_t                tid_oldfs;              /* 0x04 */
+       uint32_t                tid_selector;           /* 0x08 */
+       struct tid              *tid_self;              /* 0x0C */
+       int                     tid_cpu;                /* 0x10 */
+};
+
+static struct tid      *my_tids;
+#endif /* __i386__ */
+
+#define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
+
+int
+windrv_libinit(void)
+{
+       STAILQ_INIT(&drvdb_head);
+       lockinit(&drvdb_lock, "Windows driver DB lock", 0, LK_CANRECURSE);
+
+       /*
+        * PCI and pccard devices don't need to use IRPs to
+        * interact with their bus drivers (usually), so our
+        * emulated PCI and pccard drivers are just stubs.
+        * USB devices, on the other hand, do all their I/O
+        * by exchanging IRPs with the USB bus driver, so
+        * for that we need to provide emulator dispatcher
+        * routines, which are in a separate module.
+        */
+
+       windrv_bus_attach(&fake_pci_driver, "PCI Bus");
+       windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus");
+
+#ifdef __i386__
+
+       /*
+        * In order to properly support SMP machines, we have
+        * to modify the GDT on each CPU, since we never know
+        * on which one we'll end up running.
+        */
+
+       my_tids = ExAllocatePoolWithTag(NonPagedPool,
+           sizeof(struct tid) * ncpus, 0);
+       if (my_tids == NULL)
+               panic("failed to allocate thread info blocks");
+       lwkt_cpusync_simple(-1, x86_newldt, NULL);
+#endif
+       return (0);
+}
+
+int
+windrv_libfini(void)
+{
+       struct drvdb_ent        *d;
+
+       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+       while(STAILQ_FIRST(&drvdb_head) != NULL) {
+               d = STAILQ_FIRST(&drvdb_head);
+               STAILQ_REMOVE_HEAD(&drvdb_head, link);
+               kfree(d, M_DEVBUF);
+       }
+       lockmgr(&drvdb_lock, LK_RELEASE);
+
+       RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
+       RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
+
+       lockuninit(&drvdb_lock);
+
+#ifdef __i386__
+       lwkt_cpusync_simple(-1, x86_oldldt, NULL);
+       ExFreePool(my_tids);
+#endif
+       return (0);
+}
+
+/*
+ * Given the address of a driver image, find its corresponding
+ * driver_object.
+ */
+
+driver_object *
+windrv_lookup(vm_offset_t img, char *name)
+{
+       struct drvdb_ent        *d;
+       unicode_string          us;
+       ansi_string             as;
+
+       bzero((char *)&us, sizeof(us));
+
+       /* Damn unicode. */
+
+       if (name != NULL) {
+               RtlInitAnsiString(&as, name);
+               if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
+                       return (NULL);
+       }
+
+       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+       STAILQ_FOREACH(d, &drvdb_head, link) {
+               if (d->windrv_object->dro_driverstart == (void *)img ||
+                   (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
+                   (char *)us.us_buf, us.us_len) == 0 && us.us_len)) {
+                       lockmgr(&drvdb_lock, LK_RELEASE);
+                       if (name != NULL)
+                               ExFreePool(us.us_buf);
+                       return (d->windrv_object);
+               }
+       }
+       lockmgr(&drvdb_lock, LK_RELEASE);
+
+       if (name != NULL)
+               RtlFreeUnicodeString(&us);
+
+       return (NULL);
+}
+
+struct drvdb_ent *
+windrv_match(matchfuncptr matchfunc, void *ctx)
+{
+       struct drvdb_ent        *d;
+       int                     match;
+
+       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+       STAILQ_FOREACH(d, &drvdb_head, link) {
+               if (d->windrv_devlist == NULL)
+                       continue;
+               match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx);
+               if (match == TRUE) {
+                       lockmgr(&drvdb_lock, LK_RELEASE);
+                       return (d);
+               }
+       }
+       lockmgr(&drvdb_lock, LK_RELEASE);
+
+       return (NULL);
+}
+
+/*
+ * Remove a driver_object from our datatabase and destroy it. Throw
+ * away any custom driver extension info that may have been added.
+ */
+
+int
+windrv_unload(module_t mod, vm_offset_t img, int len)
+{
+       struct drvdb_ent        *db, *r = NULL;
+       driver_object           *drv;
+       device_object           *d, *pdo;
+       device_t                dev;
+       list_entry              *e;
+
+       drv = windrv_lookup(img, NULL);
+
+       /*
+        * When we unload a driver image, we need to force a
+        * detach of any devices that might be using it. We
+        * need the PDOs of all attached devices for this.
+        * Getting at them is a little hard. We basically
+        * have to walk the device lists of all our bus
+        * drivers.
+        */
+
+       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+       STAILQ_FOREACH(db, &drvdb_head, link) {
+               /*
+                * Fake bus drivers have no devlist info.
+                * If this driver has devlist info, it's
+                * a loaded Windows driver and has no PDOs,
+                * so skip it.
+                */
+               if (db->windrv_devlist != NULL)
+                       continue;
+               pdo = db->windrv_object->dro_devobj;
+               while (pdo != NULL) {
+                       d = pdo->do_attacheddev;
+                       if (d->do_drvobj != drv) {
+                               pdo = pdo->do_nextdev;
+                               continue;
+                       }
+                       dev = pdo->do_devext;
+                       pdo = pdo->do_nextdev;
+                       lockmgr(&drvdb_lock, LK_RELEASE);
+                       device_detach(dev);
+                       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+               }
+       }
+
+       STAILQ_FOREACH(db, &drvdb_head, link) {
+               if (db->windrv_object->dro_driverstart == (void *)img) {
+                       r = db;
+                       STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link);
+                       break;
+               }
+       }
+       lockmgr(&drvdb_lock, LK_RELEASE);
+
+       if (r == NULL)
+               return (ENOENT);
+
+       if (drv == NULL)
+               return (ENOENT);
+
+       /*
+        * Destroy any custom extensions that may have been added.
+        */
+       drv = r->windrv_object;
+       while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
+               e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
+               ExFreePool(e);
+       }
+
+       /* Free the driver extension */
+       kfree(drv->dro_driverext, M_DEVBUF);
+
+       /* Free the driver name */
+       RtlFreeUnicodeString(&drv->dro_drivername);
+
+       /* Free driver object */
+       kfree(drv, M_DEVBUF);
+
+       /* Free our DB handle */
+       kfree(r, M_DEVBUF);
+
+       return (0);
+}
+
+#define WINDRV_LOADED          htonl(0x42534F44)
+
+#ifdef __amd64__
+static void
+patch_user_shared_data_address(vm_offset_t img, size_t len)
+{
+       unsigned long i, n, max_addr, *addr;
+
+       n = len - sizeof(unsigned long);
+       max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data);
+       for (i = 0; i < n; i++) {
+               addr = (unsigned long *)(img + i);
+               if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) {
+                       *addr -= KI_USER_SHARED_DATA;
+                       *addr += (unsigned long)&kuser_shared_data;
+               }
+       }
+}
+#endif
+
+/*
+ * Loader routine for actual Windows driver modules, ultimately
+ * calls the driver's DriverEntry() routine.
+ */
+
+int
+windrv_load(module_t mod, vm_offset_t img, int len, interface_type bustype,
+    void *devlist, ndis_cfg *regvals)
+{
+       image_import_descriptor imp_desc;
+       image_optional_header   opt_hdr;
+       driver_entry            entry;
+       struct drvdb_ent        *new;
+       struct driver_object    *drv;
+       int                     status;
+       uint32_t                *ptr;
+       ansi_string             as;
+
+       /*
+        * First step: try to relocate and dynalink the executable
+        * driver image.
+        */
+
+       ptr = (uint32_t *)(img + 8);
+       if (*ptr == WINDRV_LOADED)
+               goto skipreloc;
+
+       /* Perform text relocation */
+       if (pe_relocate(img))
+               return (ENOEXEC);
+
+       /* Dynamically link the NDIS.SYS routines -- required. */
+       if (pe_patch_imports(img, "NDIS", ndis_functbl))
+               return (ENOEXEC);
+
+       /* Dynamically link the HAL.dll routines -- optional. */
+       if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
+               if (pe_patch_imports(img, "HAL", hal_functbl))
+                       return (ENOEXEC);
+       }
+
+       /* Dynamically link ntoskrnl.exe -- optional. */
+       if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
+               if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
+                       return (ENOEXEC);
+       }
+
+#ifdef __amd64__
+       patch_user_shared_data_address(img, len);
+#endif
+
+       /* Dynamically link USBD.SYS -- optional */
+       if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
+               if (pe_patch_imports(img, "USBD", usbd_functbl))
+                       return (ENOEXEC);
+       }
+
+       *ptr = WINDRV_LOADED;
+
+skipreloc:
+
+       /* Next step: find the driver entry point. */
+
+       pe_get_optional_header(img, &opt_hdr);
+       entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
+
+       /* Next step: allocate and store a driver object. */
+
+       new = kmalloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
+       if (new == NULL)
+               return (ENOMEM);
+
+       drv = kmalloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
+       if (drv == NULL) {
+               kfree (new, M_DEVBUF);
+               return (ENOMEM);
+       }
+
+       /* Allocate a driver extension structure too. */
+
+       drv->dro_driverext = kmalloc(sizeof(driver_extension),
+           M_DEVBUF, M_NOWAIT|M_ZERO);
+
+       if (drv->dro_driverext == NULL) {
+               kfree(new, M_DEVBUF);
+               kfree(drv, M_DEVBUF);
+               return (ENOMEM);
+       }
+
+       InitializeListHead((&drv->dro_driverext->dre_usrext));
+
+       drv->dro_driverstart = (void *)img;
+       drv->dro_driversize = len;
+
+       RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
+       if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
+               kfree(new, M_DEVBUF);
+               kfree(drv, M_DEVBUF);
+               return (ENOMEM);
+       }
+
+       new->windrv_object = drv;
+       new->windrv_regvals = regvals;
+       new->windrv_devlist = devlist;
+       new->windrv_bustype = bustype;
+
+       /* Now call the DriverEntry() function. */
+
+       status = MSCALL2(entry, drv, &drv->dro_drivername);
+
+       if (status != STATUS_SUCCESS) {
+               RtlFreeUnicodeString(&drv->dro_drivername);
+               kfree(drv, M_DEVBUF);
+               kfree(new, M_DEVBUF);
+               return (ENODEV);
+       }
+
+       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+       STAILQ_INSERT_HEAD(&drvdb_head, new, link);
+       lockmgr(&drvdb_lock, LK_RELEASE);
+
+       return (0);
+}
+
+/*
+ * Make a new Physical Device Object for a device that was
+ * detected/plugged in. For us, the PDO is just a way to
+ * get at the device_t.
+ */
+
+int
+windrv_create_pdo(driver_object *drv, device_t bsddev)
+{
+       device_object           *dev;
+
+       /*
+        * This is a new physical device object, which technically
+        * is the "top of the stack." Consequently, we don't do
+        * an IoAttachDeviceToDeviceStack() here.
+        */
+
+       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+       IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
+       lockmgr(&drvdb_lock, LK_RELEASE);
+
+       /* Stash pointer to our BSD device handle. */
+
+       dev->do_devext = bsddev;
+
+       return (STATUS_SUCCESS);
+}
+
+void
+windrv_destroy_pdo(driver_object *drv, device_t bsddev)
+{
+       device_object           *pdo;
+
+       pdo = windrv_find_pdo(drv, bsddev);
+
+       /* Remove reference to device_t */
+
+       pdo->do_devext = NULL;
+
+       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+       IoDeleteDevice(pdo);
+       lockmgr(&drvdb_lock, LK_RELEASE);
+}
+
+/*
+ * Given a device_t, find the corresponding PDO in a driver's
+ * device list.
+ */
+
+device_object *
+windrv_find_pdo(driver_object *drv, device_t bsddev)
+{
+       device_object           *pdo;
+
+       lockmgr(&drvdb_lock, LK_EXCLUSIVE);
+       pdo = drv->dro_devobj;
+       while (pdo != NULL) {
+               if (pdo->do_devext == bsddev) {
+                       lockmgr(&drvdb_lock, LK_RELEASE);
+                       return (pdo);
+               }
+               pdo = pdo->do_nextdev;
+       }
+       lockmgr(&drvdb_lock, LK_RELEASE);
+
+       return (NULL);
+}
+
+/*
+ * Add an internally emulated driver to the database. We need this
+ * to set up an emulated bus driver so that it can receive IRPs.
+ */
+
+int
+windrv_bus_attach(driver_object *drv, char *name)
+{
+       struct drvdb_ent        *new;
+       ansi_string             as;
+
+       new = kmalloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
+       if (new == NULL)
+               return (ENOMEM);
+
+       RtlInitAnsiString(&as, name);
+       if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
+       {
+               kfree(new, M_DEVBUF);
+               return (ENOMEM);
+       }
+
+       /*
+        * Set up a fake image pointer to avoid false matches
+        * in windrv_lookup().
+