summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2005-10-10 16:46:39 +0000
committerwpaul <wpaul@FreeBSD.org>2005-10-10 16:46:39 +0000
commitef07dbe57fe381dac96f0b1470d99bd3a2ccd3aa (patch)
tree899e14a42961670f9a34b64d8df4d8a3abe94542 /sys
parent01a20da53d2f99b5654208b24ad8d6ebfe324da9 (diff)
downloadFreeBSD-src-ef07dbe57fe381dac96f0b1470d99bd3a2ccd3aa.zip
FreeBSD-src-ef07dbe57fe381dac96f0b1470d99bd3a2ccd3aa.tar.gz
This commit makes a big round of updates and fixes many, many things.
First and most importantly, I threw out the thread priority-twiddling implementation of KeRaiseIrql()/KeLowerIrq()/KeGetCurrentIrql() in favor of a new scheme that uses sleep mutexes. The old scheme was really very naughty and sought to provide the same behavior as Windows spinlocks (i.e. blocking pre-emption) but in a way that wouldn't raise the ire of WITNESS. The new scheme represents 'DISPATCH_LEVEL' as the acquisition of a per-cpu sleep mutex. If a thread on cpu0 acquires the 'dispatcher mutex,' it will block any other thread on the same processor that tries to acquire it, in effect only allowing one thread on the processor to be at 'DISPATCH_LEVEL' at any given time. It can then do the 'atomic sit and spin' routine on the spinlock variable itself. If a thread on cpu1 wants to acquire the same spinlock, it acquires the 'dispatcher mutex' for cpu1 and then it too does an atomic sit and spin to try acquiring the spinlock. Unlike real spinlocks, this does not disable pre-emption of all threads on the CPU, but it does put any threads involved with the NDISulator to sleep, which is just as good for our purposes. This means I can now play nice with WITNESS, and I can safely do things like call malloc() when I'm at 'DISPATCH_LEVEL,' which you're allowed to do in Windows. Next, I completely re-wrote most of the event/timer/mutex handling and wait code. KeWaitForSingleObject() and KeWaitForMultipleObjects() have been re-written to use condition variables instead of msleep(). This allows us to use the Windows convention whereby thread A can tell thread B "wake up with a boosted priority." (With msleep(), you instead have thread B saying "when I get woken up, I'll use this priority here," and thread A can't tell it to do otherwise.) The new KeWaitForMultipleObjects() has been better tested and better duplicates the semantics of its Windows counterpart. I also overhauled the IoQueueWorkItem() API and underlying code. Like KeInsertQueueDpc(), IoQueueWorkItem() must insure that the same work item isn't put on the queue twice. ExQueueWorkItem(), which in my implementation is built on top of IoQueueWorkItem(), was also modified to perform a similar test. I renamed the doubly-linked list macros to give them the same names as their Windows counterparts and fixed RemoveListTail() and RemoveListHead() so they properly return the removed item. I also corrected the list handling code in ntoskrnl_dpc_thread() and ntoskrnl_workitem_thread(). I realized that the original logic did not correctly handle the case where a DPC callout tries to queue up another DPC. It works correctly now. I implemented IoConnectInterrupt() and IoDisconnectInterrupt() and modified NdisMRegisterInterrupt() and NdisMDisconnectInterrupt() to use them. I also tried to duplicate the interrupt handling scheme used in Windows. The interrupt handling is now internal to ndis.ko, and the ndis_intr() function has been removed from if_ndis.c. (In the USB case, interrupt handling isn't needed in if_ndis.c anyway.) NdisMSleep() has been rewritten to use a KeWaitForSingleObject() and a KeTimer, which is how it works in Windows. (This is mainly to insure that the NDISulator uses the KeTimer API so I can spot any problems with it that may arise.) KeCancelTimer() has been changed so that it only cancels timers, and does not attempt to cancel a DPC if the timer managed to fire and queue one up before KeCancelTimer() was called. The Windows DDK documentation seems to imply that KeCantelTimer() will also call KeRemoveQueueDpc() if necessary, but it really doesn't. The KeTimer implementation has been rewritten to use the callout API directly instead of timeout()/untimeout(). I still cheat a little in that I have to manage my own small callout timer wheel, but the timer code works more smoothly now. I discovered a race condition using timeout()/untimeout() with periodic timers where untimeout() fails to actually cancel a timer. I don't quite understand where the race is, using callout_init()/callout_reset()/callout_stop() directly seems to fix it. I also discovered and fixed a bug in winx32_wrap.S related to translating _stdcall calls. There are a couple of routines (i.e. the 64-bit arithmetic intrinsics in subr_ntoskrnl) that return 64-bit quantities. On the x86 arch, 64-bit values are returned in the %eax and %edx registers. However, it happens that the ctxsw_utow() routine uses %edx as a scratch register, and x86_stdcall_wrap() and x86_stdcall_call() were only preserving %eax before branching to ctxsw_utow(). This means %edx was getting clobbered in some cases. Curiously, the most noticeable effect of this bug is that the driver for the TI AXC110 chipset would constantly drop and reacquire its link for no apparent reason. Both %eax and %edx are preserved on the stack now. The _fastcall and _regparm wrappers already handled everything correctly. I changed if_ndis to use IoAllocateWorkItem() and IoQueueWorkItem() instead of the NdisScheduleWorkItem() API. This is to avoid possible deadlocks with any drivers that use NdisScheduleWorkItem() themselves. The unicode/ansi conversion handling code has been cleaned up. The internal routines have been moved to subr_ntoskrnl and the RtlXXX routines have been exported so that subr_ndis can call them. This removes the incestuous relationship between the two modules regarding this code and fixes the implementation so that it honors the 'maxlen' fields correctly. (Previously it was possible for NdisUnicodeStringToAnsiString() to possibly clobber memory it didn't own, which was causing many mysterious crashes in the Marvell 8335 driver.) The registry handling code (NdisOpen/Close/ReadConfiguration()) has been fixed to allocate memory for all the parameters it hands out to callers and delete whem when NdisCloseConfiguration() is called. (Previously, it would secretly use a single static buffer.) I also substantially updated if_ndis so that the source can now be built on FreeBSD 7, 6 and 5 without any changes. On FreeBSD 5, only WEP support is enabled. On FreeBSD 6 and 7, WPA-PSK support is enabled. The original WPA code has been updated to fit in more cleanly with the net80211 API, and to eleminate the use of magic numbers. The ndis_80211_setstate() routine now sets a default authmode of OPEN and initializes the RTS threshold and fragmentation threshold. The WPA routines were changed so that the authentication mode is always set first, followed by the cipher. Some drivers depend on the operations being performed in this order. I also added passthrough ioctls that allow application code to directly call the MiniportSetInformation()/MiniportQueryInformation() methods via ndis_set_info() and ndis_get_info(). The ndis_linksts() routine also caches the last 4 events signalled by the driver via NdisMIndicateStatus(), and they can be queried by an application via a separate ioctl. This is done to allow wpa_supplicant to directly program the various crypto and key management options in the driver, allowing things like WPA2 support to work. Whew.
Diffstat (limited to 'sys')
-rw-r--r--sys/compat/ndis/kern_ndis.c142
-rw-r--r--sys/compat/ndis/kern_windrv.c56
-rw-r--r--sys/compat/ndis/ndis_var.h119
-rw-r--r--sys/compat/ndis/ntoskrnl_var.h142
-rw-r--r--sys/compat/ndis/subr_hal.c108
-rw-r--r--sys/compat/ndis/subr_ndis.c555
-rw-r--r--sys/compat/ndis/subr_ntoskrnl.c1286
-rw-r--r--sys/compat/ndis/winx32_wrap.S24
-rw-r--r--sys/dev/if_ndis/if_ndis.c1244
-rw-r--r--sys/dev/if_ndis/if_ndisvar.h88
10 files changed, 2537 insertions, 1227 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
index 573d78f..97f63f7 100644
--- a/sys/compat/ndis/kern_ndis.c
+++ b/sys/compat/ndis/kern_ndis.c
@@ -82,7 +82,7 @@ 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_intrhand(kdpc *, device_object *,
+static void ndis_intrsetup(kdpc *, device_object *,
irp *, struct ndis_softc *);
static void ndis_return(kdpc *, void *, void *, void *);
@@ -93,7 +93,7 @@ static image_patch_table kernndis_functbl[] = {
IMPORT_SFUNC(ndis_getdone_func, 2),
IMPORT_SFUNC(ndis_resetdone_func, 3),
IMPORT_SFUNC(ndis_sendrsrcavail_func, 1),
- IMPORT_SFUNC(ndis_intrhand, 4),
+ IMPORT_SFUNC(ndis_intrsetup, 4),
IMPORT_SFUNC(ndis_return, 1),
{ NULL, NULL, NULL }
@@ -183,34 +183,6 @@ ndis_modevent(module_t mod, int cmd, void *arg)
DEV_MODULE(ndisapi, ndis_modevent, NULL);
MODULE_VERSION(ndisapi, 1);
-int
-ndis_thsuspend(p, m, timo)
- struct proc *p;
- struct mtx *m;
- int timo;
-{
- int error;
-
- if (m != NULL) {
- error = msleep(&p->p_siglist, m,
- curthread->td_priority, "ndissp", timo);
- } else {
- PROC_LOCK(p);
- error = msleep(&p->p_siglist, &p->p_mtx,
- curthread->td_priority|PDROP, "ndissp", timo);
- }
-
- return(error);
-}
-
-void
-ndis_thresume(p)
- struct proc *p;
-{
- wakeup(&p->p_siglist);
- return;
-}
-
static void
ndis_sendrsrcavail_func(adapter)
ndis_handle adapter;
@@ -328,7 +300,6 @@ ndis_create_sysctls(arg)
#endif
/* Add the driver-specific registry keys. */
- vals = sc->ndis_regvals;
while(1) {
if (vals->nc_cfgkey == NULL)
break;
@@ -358,17 +329,8 @@ ndis_create_sysctls(arg)
continue;
}
-#if __FreeBSD_version < 502113
- SYSCTL_ADD_STRING(&sc->ndis_ctx,
- SYSCTL_CHILDREN(sc->ndis_tree),
-#else
- SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
-#endif
- OID_AUTO, vals->nc_cfgkey,
- CTLFLAG_RW, vals->nc_val,
- sizeof(vals->nc_val),
- vals->nc_cfgdesc);
+ ndis_add_sysctl(sc, vals->nc_cfgkey, vals->nc_cfgdesc,
+ vals->nc_val, CTLFLAG_RW);
vals++;
}
@@ -420,8 +382,10 @@ ndis_add_sysctl(arg, key, desc, val, flag)
cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
- if (cfg == NULL)
+ if (cfg == NULL) {
+ printf("failed for %s\n", key);
return(ENOMEM);
+ }
cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
if (desc == NULL) {
@@ -433,6 +397,7 @@ ndis_add_sysctl(arg, key, desc, val, flag)
TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
+ cfg->ndis_oid =
#if __FreeBSD_version < 502113
SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
#else
@@ -446,18 +411,34 @@ ndis_add_sysctl(arg, key, desc, val, flag)
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(arg)
void *arg;
{
struct ndis_softc *sc;
struct ndis_cfglist *cfg;
+ struct sysctl_ctx_list *clist;
sc = arg;
+#if __FreeBSD_version < 502113
+ clist = &sc->ndis_ctx;
+#else
+ clist = device_get_sysctl_ctx(sc->ndis_dev);
+#endif
+
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);
free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
free(cfg, M_DEVBUF);
@@ -488,9 +469,11 @@ ndis_return(dpc, arg, sysarg1, sysarg2)
returnfunc = sc->ndis_chars->nmc_return_packet_func;
- KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+ if (NDIS_SERIALIZED(sc->ndis_block))
+ KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
MSCALL2(returnfunc, adapter, p);
- KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+ if (NDIS_SERIALIZED(sc->ndis_block))
+ KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
return;
}
@@ -691,10 +674,13 @@ ndis_ptom(m0, p)
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);
@@ -718,6 +704,7 @@ ndis_ptom(m0, p)
MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
p, 0, EXT_NDIS);
p->np_refcnt++;
+
totlen += m->m_len;
if (m->m_flags & M_PKTHDR)
*m0 = m;
@@ -726,6 +713,24 @@ ndis_ptom(m0, 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);
@@ -770,6 +775,7 @@ ndis_mtop(m0, p)
*p = NULL;
return(ENOMEM);
}
+ MmBuildMdlForNonPagedPool(buf);
if (priv->npp_head == NULL)
priv->npp_head = buf;
@@ -875,7 +881,6 @@ ndis_set_info(arg, oid, buf, buflen)
rval = sc->ndis_block->nmb_setstat;
}
-
if (byteswritten)
*buflen = byteswritten;
if (bytesneeded)
@@ -1080,7 +1085,7 @@ ndis_reset_nic(arg)
return(0);
}
-#define NDIS_REAP_TIMERS
+#undef NDIS_REAP_TIMERS
int
ndis_halt_nic(arg)
@@ -1112,9 +1117,9 @@ ndis_halt_nic(arg)
n->nmt_nexttimer = NULL;
}
sc->ndis_block->nmb_timerlist = NULL;
+#endif
if (!cold)
KeFlushQueuedDpcs();
-#endif
NDIS_LOCK(sc);
adapter = sc->ndis_block->nmb_miniportadapterctx;
@@ -1123,7 +1128,6 @@ ndis_halt_nic(arg)
return(EIO);
}
- sc->ndis_block->nmb_miniportadapterctx = NULL;
sc->ndis_block->nmb_devicectx = NULL;
/*
@@ -1137,6 +1141,10 @@ ndis_halt_nic(arg)
MSCALL1(haltfunc, adapter);
+ NDIS_LOCK(sc);
+ sc->ndis_block->nmb_miniportadapterctx = NULL;
+ NDIS_UNLOCK(sc);
+
return(0);
}
@@ -1216,7 +1224,7 @@ ndis_init_nic(arg)
* expects them to fire before the halt is called.
*/
- ndis_thsuspend(curthread->td_proc, NULL, hz);
+ tsleep(curthread->td_proc, PWAIT, "ndwait", hz);
NDIS_LOCK(sc);
sc->ndis_block->nmb_devicectx = sc;
@@ -1292,33 +1300,26 @@ ndis_isr(arg, ourintr, callhandler)
}
static void
-ndis_intrhand(dpc, dobj, ip, sc)
+ndis_intrsetup(dpc, dobj, ip, sc)
kdpc *dpc;
device_object *dobj;
irp *ip;
struct ndis_softc *sc;
{
- ndis_handle adapter;
- ndis_interrupt_handler intrfunc;
- uint8_t irql;
-
- adapter = sc->ndis_block->nmb_miniportadapterctx;
- intrfunc = sc->ndis_chars->nmc_interrupt_func;
-
- if (adapter == NULL || intrfunc == NULL)
- return;
-
- if (NDIS_SERIALIZED(sc->ndis_block))
- KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+ ndis_miniport_interrupt *intr;
- MSCALL1(intrfunc, adapter);
+ intr = sc->ndis_block->nmb_interrupt;
- /* If there's a MiniportEnableInterrupt() routine, call it. */
+ /* Sanity check. */
- ndis_enable_intr(sc);
+ if (intr == NULL)
+ return;
- if (NDIS_SERIALIZED(sc->ndis_block))
- KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+ KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
+ KeResetEvent(&intr->ni_dpcevt);
+ if (KeInsertQueueDpc(&intr->ni_dpc, NULL, NULL) == TRUE)
+ intr->ni_dpccnt++;
+ KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
return;
}
@@ -1424,6 +1425,7 @@ NdisAddDevice(drv, pdo)
block->nmb_physdeviceobj = pdo;
block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo);
KeInitializeSpinLock(&block->nmb_lock);
+ InitializeListHead(&block->nmb_parmlist);
/*
* Stash pointers to the miniport block and miniport
@@ -1447,7 +1449,7 @@ NdisAddDevice(drv, pdo)
IoDeleteDevice(fdo);
return(status);
}
- INIT_LIST_HEAD((&block->nmb_packetlist));
+ InitializeListHead((&block->nmb_packetlist));
}
/* Give interrupt handling priority over timers. */
diff --git a/sys/compat/ndis/kern_windrv.c b/sys/compat/ndis/kern_windrv.c
index 90c977b..9202911 100644
--- a/sys/compat/ndis/kern_windrv.c
+++ b/sys/compat/ndis/kern_windrv.c
@@ -137,8 +137,8 @@ windrv_libfini(void)
}
mtx_unlock(&drvdb_mtx);
- free(fake_pci_driver.dro_drivername.us_buf, M_DEVBUF);
- free(fake_pccard_driver.dro_drivername.us_buf, M_DEVBUF);
+ RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
+ RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
mtx_destroy(&drvdb_mtx);
@@ -161,16 +161,16 @@ windrv_lookup(img, name)
{
struct drvdb_ent *d;
unicode_string us;
+ ansi_string as;
bzero((char *)&us, sizeof(us));
/* Damn unicode. */
if (name != NULL) {
- us.us_len = strlen(name) * 2;
- us.us_maxlen = strlen(name) * 2;
- us.us_buf = NULL;
- ndis_ascii_to_unicode(name, &us.us_buf);
+ RtlInitAnsiString(&as, name);
+ if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
+ return(NULL);
}
mtx_lock(&drvdb_mtx);
@@ -187,7 +187,7 @@ windrv_lookup(img, name)
mtx_unlock(&drvdb_mtx);
if (name != NULL)
- ExFreePool(us.us_buf);
+ RtlFreeUnicodeString(&us);
return(NULL);
}
@@ -230,7 +230,7 @@ windrv_unload(mod, img, len)
driver_object *drv;
device_object *d, *pdo;
device_t dev;
- list_entry *e, *c;
+ list_entry *e;
drv = windrv_lookup(img, NULL);
@@ -267,7 +267,7 @@ windrv_unload(mod, img, len)
mtx_lock(&drvdb_mtx);
}
}
-
+
STAILQ_FOREACH(db, &drvdb_head, link) {
if (db->windrv_object->dro_driverstart == (void *)img) {
r = db;
@@ -280,23 +280,23 @@ windrv_unload(mod, img, len)
if (r == NULL)
return (ENOENT);
+ if (drv == NULL)
+ return(ENOENT);
+
/*
* Destroy any custom extensions that may have been added.
*/
drv = r->windrv_object;
- e = drv->dro_driverext->dre_usrext.nle_flink;
- while (e != &drv->dro_driverext->dre_usrext) {
- c = e->nle_flink;
- REMOVE_LIST_ENTRY(e);
+ while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
+ e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
ExFreePool(e);
- e = c;
}
/* Free the driver extension */
free(drv->dro_driverext, M_DEVBUF);
/* Free the driver name */
- free(drv->dro_drivername.us_buf, M_DEVBUF);
+ RtlFreeUnicodeString(&drv->dro_drivername);
/* Free driver object */
free(drv, M_DEVBUF);
@@ -330,6 +330,7 @@ windrv_load(mod, img, len, bustype, devlist, regvals)
struct driver_object *drv;
int status;
uint32_t *ptr;
+ ansi_string as;
/*
* First step: try to relocate and dynalink the executable
@@ -396,16 +397,17 @@ skipreloc:
return(ENOMEM);
}
- INIT_LIST_HEAD((&drv->dro_driverext->dre_usrext));
+ InitializeListHead((&drv->dro_driverext->dre_usrext));
drv->dro_driverstart = (void *)img;
drv->dro_driversize = len;
- drv->dro_drivername.us_len = strlen(DUMMY_REGISTRY_PATH) * 2;
- drv->dro_drivername.us_maxlen = strlen(DUMMY_REGISTRY_PATH) * 2;
- drv->dro_drivername.us_buf = NULL;
- ndis_ascii_to_unicode(DUMMY_REGISTRY_PATH,
- &drv->dro_drivername.us_buf);
+ RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
+ if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
+ free(new, M_DEVBUF);
+ free(drv, M_DEVBUF);
+ return(ENOMEM);
+ }
new->windrv_object = drv;
new->windrv_regvals = regvals;
@@ -417,7 +419,7 @@ skipreloc:
status = MSCALL2(entry, drv, &drv->dro_drivername);
if (status != STATUS_SUCCESS) {
- free(drv->dro_drivername.us_buf, M_DEVBUF);
+ RtlFreeUnicodeString(&drv->dro_drivername);
free(drv, M_DEVBUF);
free(new, M_DEVBUF);
return(ENODEV);
@@ -517,15 +519,15 @@ windrv_bus_attach(drv, name)
char *name;
{
struct drvdb_ent *new;
+ ansi_string as;
new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
if (new == NULL)
return (ENOMEM);
- drv->dro_drivername.us_len = strlen(name) * 2;
- drv->dro_drivername.us_maxlen = strlen(name) * 2;
- drv->dro_drivername.us_buf = NULL;
- ndis_ascii_to_unicode(name, &drv->dro_drivername.us_buf);
+ RtlInitAnsiString(&as, name);
+ if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
+ return(ENOMEM);
/*
* Set up a fake image pointer to avoid false matches
@@ -674,7 +676,7 @@ ctxsw_utow(void)
* hasn't, we need to do it right now or else things will
* explode.
*/
-
+
if (t->tid_self != t)
x86_newldt(NULL);
diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h
index 742fae2..4fd7106 100644
--- a/sys/compat/ndis/ndis_var.h
+++ b/sys/compat/ndis/ndis_var.h
@@ -268,6 +268,31 @@ typedef uint8_t ndis_kirql;
#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105
#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
+/*
+ * These are the possible power states for
+ * OID_PNP_SET_POWER and OID_PNP_QUERY_POWER.
+ */
+#define NDIS_POWERSTATE_UNSPEC 0
+#define NDIS_POWERSTATE_D0 1
+#define NDIS_POWERSTATE_D1 2
+#define NDIS_POWERSTATE_D2 3
+#define NDIS_POWERSTATE_D3 4
+
+/*
+ * These are used with the MiniportPnpEventNotify() method.
+ */
+
+#define NDIS_POWERPROFILE_BATTERY 0
+#define NDIS_POWERPROFILE_ACONLINE 1
+
+#define NDIS_PNP_EVENT_QUERY_REMOVED 0
+#define NDIS_PNP_EVENT_REMOVED 1
+#define NDIS_PNP_EVENT_SURPRISE_REMOVED 2
+#define NDIS_PNP_EVENT_QUERY_STOPPED 3
+#define NDIS_PNP_EVENT_STOPPED 4
+#define NDIS_PNP_EVENT_PROFILECHANGED 5
+
+
/* PnP/PM Statistics (Optional). */
#define OID_PNP_WAKE_UP_OK 0xFD020200
#define OID_PNP_WAKE_UP_ERROR 0xFD020201
@@ -310,6 +335,8 @@ typedef uint8_t ndis_kirql;
#define OID_802_11_REMOVE_KEY 0x0D01011E
#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F
#define OID_802_11_TEST 0x0D010120
+#define OID_802_11_CAPABILITY 0x0D010122
+#define OID_802_11_PMKID 0x0D010123
/* structures/definitions for 802.11 */
#define NDIS_80211_NETTYPE_11FH 0x00000000
@@ -390,6 +417,8 @@ typedef struct ndis_80211_wep ndis_80211_wep;
#define NDIS_80211_AUTHMODE_WPA 0x00000003
#define NDIS_80211_AUTHMODE_WPAPSK 0x00000004
#define NDIS_80211_AUTHMODE_WPANONE 0x00000005
+#define NDIS_80211_AUTHMODE_WPA2 0x00000006
+#define NDIS_80211_AUTHMODE_WPA2PSK 0x00000007
typedef uint8_t ndis_80211_rates[8];
typedef uint8_t ndis_80211_rates_ex[16];
@@ -483,6 +512,7 @@ typedef uint32_t ndis_80211_antenna;
#define NDIS_80211_RELOADDEFAULT_WEP 0x00000000
#define NDIS_80211_STATUSTYPE_AUTH 0x00000000
+#define NDIS_80211_STATUSTYPE_PMKIDLIST 0x00000001
struct ndis_80211_status_indication {
uint32_t nsi_type;
@@ -490,6 +520,11 @@ struct ndis_80211_status_indication {
typedef struct ndis_80211_status_indication ndis_80211_status_indication;
+#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
+
struct ndis_80211_auth_request {
uint32_t nar_len;
ndis_80211_macaddr nar_bssid;
@@ -503,8 +538,9 @@ struct ndis_80211_key {
uint32_t nk_keyidx;
uint32_t nk_keylen;
ndis_80211_macaddr nk_bssid;
+ uint8_t nk_pad[6];
uint64_t nk_keyrsc;
- uint8_t nk_keydata[256];
+ uint8_t nk_keydata[32];
};
typedef struct ndis_80211_key ndis_80211_key;
@@ -573,6 +609,61 @@ struct ndis_80211_test {
typedef struct ndis_80211_test ndis_80211_test;
+struct ndis_80211_auth_encrypt {
+ uint32_t ne_authmode;
+ uint32_t ne_cryptstat;
+};
+
+typedef struct ndis_80211_auth_encrypt ndis_80211_auth_encrypt;
+
+struct ndis_80211_caps {
+ uint32_t nc_len;
+ uint32_t nc_ver;
+ uint32_t nc_numpmkids;
+ ndis_80211_auth_encrypt nc_authencs[1];
+};
+
+typedef struct ndis_80211_caps ndis_80211_caps;
+
+struct ndis_80211_bssidinfo {
+ ndis_80211_macaddr nb_bssid;
+ uint8_t nb_pmkid[16];
+};
+
+typedef struct ndis_80211_bssidinfo ndis_80211_bssidinfo;
+
+struct ndis_80211_pmkid {
+ uint32_t np_len;
+ uint32_t np_bssidcnt;
+ ndis_80211_bssidinfo np_bssidinfo[1];
+};
+
+typedef struct ndis_80211_pmkid ndis_80211_pmkid;
+
+struct ndis_80211_pmkid_cand {
+ ndis_80211_macaddr npc_bssid;
+ uint32_t npc_flags;
+};
+
+typedef struct ndis_80211_pmkid_cand ndis_80211_pmkid_cand;
+
+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED (0x01)
+
+struct ndis_80211_pmkid_candidate_list {
+ uint32_t npcl_version;
+ uint32_t npcl_numcandidates;
+ ndis_80211_pmkid_cand npcl_candidatelist[1];
+};
+
+typedef struct ndis_80211_pmkid_candidate_list ndis_80211_pmkid_candidate_list;
+
+struct ndis_80211_enc_indication {
+ uint32_t nei_statustype;
+ ndis_80211_pmkid_candidate_list nei_pmkidlist;
+};
+
+typedef struct ndis_80211_enc_indication ndis_80211_enc_indication;
+
/* TCP OIDs. */
#define OID_TCP_TASK_OFFLOAD 0xFC010201
@@ -682,6 +773,7 @@ typedef struct ndis_task_ipsec ndis_task_ipsec;
* all attributes.
*/
+#define NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT 0x00000001
#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002
#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004
#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008
@@ -805,8 +897,20 @@ struct ndis_config_parm {
} ncp_parmdata;
};
+/*
+ * Not part of Windows NDIS spec; we uses this to keep a
+ * list of ndis_config_parm structures that we've allocated.
+ */
+
typedef struct ndis_config_parm ndis_config_parm;
+struct ndis_parmlist_entry {
+ list_entry np_list;
+ ndis_config_parm np_parm;
+};
+
+typedef struct ndis_parmlist_entry ndis_parmlist_entry;
+
#ifdef notdef
struct ndis_list_entry {
struct ndis_list_entry *nle_flink;
@@ -952,16 +1056,16 @@ typedef struct ndis_request ndis_request;
* Filler, not used.
*/
struct ndis_miniport_interrupt {
- void *ni_introbj;
+ kinterrupt *ni_introbj;
ndis_kspin_lock ni_dpccountlock;
void *ni_rsvd;
void *ni_isrfunc;
void *ni_dpcfunc;
- struct ndis_kdpc ni_dpc;
+ kdpc ni_dpc;
ndis_miniport_block *ni_block;
uint8_t ni_dpccnt;
uint8_t ni_filler1;
- struct ndis_kevent ni_dpcsdoneevent;
+ struct nt_kevent ni_dpcevt;
uint8_t ni_shared;
uint8_t ni_isrreq;
};
@@ -1506,8 +1610,7 @@ struct ndis_miniport_block {
* End of windows-specific portion of miniport block. Everything
* below is BSD-specific.
*/
- uint8_t nmb_dummybuf[128];
- ndis_config_parm nmb_replyparm;
+ list_entry nmb_parmlist;
ndis_resource_list *nmb_rlist;
ndis_status nmb_getstat;
ndis_status nmb_setstat;
@@ -1600,8 +1703,6 @@ extern image_patch_table ndis_functbl[];
__BEGIN_DECLS
extern int ndis_libinit(void);
extern int ndis_libfini(void);
-extern int ndis_ascii_to_unicode(char *, uint16_t **);
-extern int ndis_unicode_to_ascii(uint16_t *, int, char **);
extern int ndis_load_driver(vm_offset_t, void *);
extern int ndis_unload_driver(void *);
extern int ndis_mtop(struct mbuf *, ndis_packet **);
@@ -1629,8 +1730,6 @@ extern int ndis_destroy_dma(void *);
extern int ndis_create_sysctls(void *);
extern int ndis_add_sysctl(void *, char *, char *, char *, int);
extern int ndis_flush_sysctls(void *);
-extern int ndis_thsuspend(struct proc *, struct mtx *, int);
-extern void ndis_thresume(struct proc *);
extern int ndis_strcasecmp(const char *, const char *);
extern int ndis_strncasecmp(const char *, const char *, size_t);
diff --git a/sys/compat/ndis/ntoskrnl_var.h b/sys/compat/ndis/ntoskrnl_var.h
index 622a387..7a1f3af 100644
--- a/sys/compat/ndis/ntoskrnl_var.h
+++ b/sys/compat/ndis/ntoskrnl_var.h
@@ -48,6 +48,14 @@ struct unicode_string {
typedef struct unicode_string unicode_string;
+struct ansi_string {
+ uint16_t as_len;
+ uint16_t as_maxlen;
+ char *as_buf;
+};
+
+typedef struct ansi_string ansi_string;
+
/*
* Windows memory descriptor list. In Windows, it's possible for
* buffers to be passed between user and kernel contexts without
@@ -197,43 +205,54 @@ struct list_entry {
typedef struct list_entry list_entry;
-#define INIT_LIST_HEAD(l) \
+#define InitializeListHead(l) \
(l)->nle_flink = (l)->nle_blink = (l)
-#define REMOVE_LIST_ENTRY(e) \
+#define IsListEmpty(h) \
+ ((h)->nle_flink == (h))
+
+#define RemoveEntryList(e) \
do { \
list_entry *b; \
list_entry *f; \
\
- f = e->nle_flink; \
- b = e->nle_blink; \
+ f = (e)->nle_flink; \
+ b = (e)->nle_blink; \
b->nle_flink = f; \
f->nle_blink = b; \
} while (0)
-#define REMOVE_LIST_HEAD(l) \
- do { \
- list_entry *f; \
- list_entry *e; \
- \
- e = l->nle_flink; \
- f = e->nle_flink; \
- l->nle_flink = f; \
- f->nle_blink = l; \
- } while (0)
+/* These two have to be inlined since they return things. */
-#define REMOVE_LIST_TAIL(l) \
- do { \
- list_entry *b; \
- list_entry *e; \
- \
- e = l->nle_blink; \
- b = e->nle_blink; \
- l->nle_blink = b; \
- b->nle_flink = l; \
- } while (0)
+static __inline__ list_entry *
+RemoveHeadList(list_entry *l)
+{
+ list_entry *f;
+ list_entry *e;
+
+ e = l->nle_flink;
+ f = e->nle_flink;
+ l->nle_flink = f;
+ f->nle_blink = l;
+
+ return (e);
+}
+
+static __inline__ list_entry *
+RemoveTailList(list_entry *l)
+{
+ list_entry *b;
+ list_entry *e;
+
+ e = l->nle_blink;
+ b = e->nle_blink;
+ l->nle_blink = b;
+ b->nle_flink = l;
-#define INSERT_LIST_TAIL(l, e) \
+ return (e);
+}
+
+#define InsertTailList(l, e) \
do { \
list_entry *b; \
\
@@ -244,7 +263,7 @@ typedef struct list_entry list_entry;
l->nle_blink = (e); \
} while (0)
-#define INSERT_LIST_HEAD(l, e) \
+#define InsertHeadList(l, e) \
do { \
list_entry *f; \
\
@@ -263,12 +282,24 @@ struct nt_dispatch_header {
uint8_t dh_abs;
uint8_t dh_size;
uint8_t dh_inserted;
- uint32_t dh_sigstate;
+ int32_t dh_sigstate;
list_entry dh_waitlisthead;
};
typedef struct nt_dispatch_header nt_dispatch_header;
+/* Dispatcher object types */
+
+#define DISP_TYPE_NOTIFICATION_EVENT 0 /* KEVENT */
+#define DISP_TYPE_SYNCHRONIZATION_EVENT 1 /* KEVENT */
+#define DISP_TYPE_MUTANT 2 /* KMUTANT/KMUTEX */
+#define DISP_TYPE_PROCESS 3 /* KPROCESS */
+#define DISP_TYPE_QUEUE 4 /* KQUEUE */
+#define DISP_TYPE_SEMAPHORE 5 /* KSEMAPHORE */
+#define DISP_TYPE_THREAD 6 /* KTHREAD */
+#define DISP_TYPE_NOTIFICATION_TIMER 8 /* KTIMER */
+#define DISP_TYPE_SYNCHRONIZATION_TIMER 9 /* KTIMER */
+
#define OTYPE_EVENT 0
#define OTYPE_MUTEX 1
#define OTYPE_THREAD 2
@@ -334,14 +365,14 @@ struct ktimer {
uint64_t k_duetime;
union {
list_entry k_timerlistentry;
- struct callout_handle k_handle;
+ struct callout *k_callout;
} u;
void *k_dpc;
uint32_t k_period;
};
#define k_timerlistentry u.k_timerlistentry
-#define k_handle u.k_handle
+#define k_callout u.k_callout
typedef struct ktimer ktimer;
@@ -389,18 +420,12 @@ typedef struct kdpc kdpc;
*/
struct kmutant {
nt_dispatch_header km_header;
- union {
- list_entry km_listentry;
- uint32_t km_acquirecnt;
- } u;
+ list_entry km_listentry;
void *km_ownerthread;
uint8_t km_abandoned;
uint8_t km_apcdisable;
};
-#define km_listentry u.km_listentry
-#define km_acquirecnt u.km_acquirecnt
-
typedef struct kmutant kmutant;
#define LOOKASIDE_DEPTH 256
@@ -485,18 +510,28 @@ struct wait_block {
void *wb_kthread;
nt_dispatch_header *wb_object;
struct wait_block *wb_next;
+#ifdef notdef
uint16_t wb_waitkey;
uint16_t wb_waittype;
+#endif
+ uint8_t wb_waitkey;
+ uint8_t wb_waittype;
+ uint8_t wb_awakened;
+ uint8_t wb_oldpri;
};
typedef struct wait_block wait_block;
+#define wb_ext wb_kthread
+
#define THREAD_WAIT_OBJECTS 3
#define MAX_WAIT_OBJECTS 64
#define WAITTYPE_ALL 0
#define WAITTYPE_ANY 1
+#define WAITKEY_VALID 0x8000
+
struct thread_context {
void *tc_thrctx;
void *tc_thrfunc;
@@ -533,6 +568,23 @@ struct custom_extension {
typedef struct custom_extension custom_extension;
/*
+ * The KINTERRUPT structure in Windows is opaque to drivers.
+ * We define our own custom version with things we need.
+ */
+
+struct kinterrupt {
+ device_t ki_dev;
+ void *ki_cookie;
+ struct resource *ki_irq;
+ kspin_lock ki_lock_priv;
+ kspin_lock *ki_lock;
+ void *ki_svcfunc;
+ void *ki_svcctx;
+};
+
+typedef struct kinterrupt kinterrupt;
+
+/*
* In Windows, there are Physical Device Objects (PDOs) and
* Functional Device Objects (FDOs). Physical Device Objects are
* created and maintained by bus drivers. For example, the PCI
@@ -1199,7 +1251,7 @@ typedef struct work_queue_item work_queue_item;
do { \
(w)->wqi_func = (func); \
(w)->wqi_ctx = (ctx); \
- INIT_LIST_HEAD(&((w)->wqi_entry)); \
+ InitializeListHead(&((w)->wqi_entry)); \
} while (0); \
@@ -1251,6 +1303,16 @@ extern void ctxsw_wtou(void);
extern int ntoskrnl_libinit(void);
extern int ntoskrnl_libfini(void);
+
+extern uint32_t RtlUnicodeStringToAnsiString(ansi_string *,
+ unicode_string *, uint8_t);
+extern uint32_t RtlAnsiStringToUnicodeString(unicode_string *,
+ ansi_string *, uint8_t);
+extern void RtlInitAnsiString(ansi_string *, char *);
+extern void RtlInitUnicodeString(unicode_string *,
+ uint16_t *);
+extern void RtlFreeUnicodeString(unicode_string *);
+extern void RtlFreeAnsiString(ansi_string *);
extern void KeInitializeDpc(kdpc *, void *, void *);
extern uint8_t KeInsertQueueDpc(kdpc *, void *, void *);
extern uint8_t KeRemoveQueueDpc(kdpc *);
@@ -1280,10 +1342,16 @@ extern void KeAcquireSpinLockAtDpcLevel(kspin_lock *);
extern void KeReleaseSpinLockFromDpcLevel(kspin_lock *);
#endif
extern void KeInitializeSpinLock(kspin_lock *);
+extern uint8_t KeSynchronizeExecution(kinterrupt *, void *, void *);
extern uintptr_t InterlockedExchange(volatile uint32_t *,
uintptr_t);
extern void *ExAllocatePoolWithTag(uint32_t, size_t, uint32_t);
extern void ExFreePool(void *);
+extern uint32_t IoConnectInterrupt(kinterrupt **, void *, void *,
+ kspin_lock *, uint32_t, uint8_t, uint8_t, uint8_t, uint8_t,
+ uint32_t, uint8_t);
+extern void MmBuildMdlForNonPagedPool(mdl *);
+extern void IoDisconnectInterrupt(kinterrupt *);
extern uint32_t IoAllocateDriverObjectExtension(driver_object *,
void *, uint32_t, void **);
extern void *IoGetDriverObjectExtension(driver_object *, void *);
diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c
index ca8f009..fa376bf 100644
--- a/sys/compat/ndis/subr_hal.c
+++ b/sys/compat/ndis/subr_hal.c
@@ -80,12 +80,18 @@ static void READ_PORT_BUFFER_UCHAR(uint8_t *,
static uint64_t KeQueryPerformanceCounter(uint64_t *);
static void dummy (void);
-extern struct mtx_pool *ndis_mtxpool;
+#define NDIS_MAXCPUS 64
+static struct mtx disp_lock[NDIS_MAXCPUS];
int
hal_libinit()
{
image_patch_table *patch;
+ int i;
+
+ for (i = 0; i < NDIS_MAXCPUS; i++)
+ mtx_init(&disp_lock[i], "HAL preemption lock",
+ "HAL lock", MTX_RECURSE|MTX_DEF);
patch = hal_functbl;
while (patch->ipt_func != NULL) {
@@ -95,6 +101,7 @@ hal_libinit()
patch++;
}
+
return(0);
}
@@ -102,6 +109,10 @@ int
hal_libfini()
{
image_patch_table *patch;
+ int i;
+
+ for (i = 0; i < NDIS_MAXCPUS; i++)
+ mtx_destroy(&disp_lock[i]);
patch = hal_functbl;
while (patch->ipt_func != NULL) {
@@ -285,6 +296,72 @@ READ_PORT_BUFFER_UCHAR(port, val, cnt)
* KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If
* we detect someone trying to acquire a spinlock from DEVICE_LEVEL
* or HIGH_LEVEL, we panic.
+ *
+ * Alternate sleep-lock-based spinlock implementation
+ * --------------------------------------------------
+ *
+ * The earlier spinlock implementation was arguably a bit of a hack
+ * and presented several problems. It was basically designed to provide
+ * the functionality of spinlocks without incurring the wrath of
+ * WITNESS. We could get away with using both our spinlock implementation
+ * and FreeBSD sleep locks at the same time, but if WITNESS knew what
+ * we were really up to, it would have spanked us rather severely.
+ *
+ * There's another method we can use based entirely on sleep locks.
+ * First, it's important to realize that everything we're locking
+ * resides inside Project Evil itself: any critical data being locked
+ * by drivers belongs to the drivers, and should not be referenced
+ * by any other OS code outside of the NDISulator. The priority-based
+ * locking scheme has system-wide effects, just like real spinlocks
+ * (blocking preemption affects the whole CPU), but since we keep all
+ * our critical data private, we can use a simpler mechanism that
+ * affects only code/threads directly related to Project Evil.
+ *
+ * The idea is to create a sleep lock mutex for each CPU in the system.
+ * When a CPU running in the NDISulator wants to acquire a spinlock, it
+ * does the following:
+ * - Pin ourselves to the current CPU
+ * - Acquire the mutex for the current CPU
+ * - Spin on the spinlock variable using atomic test and set, just like
+ * a real spinlock.
+ * - Once we have the lock, we execute our critical code
+ *
+ * To give up the lock, we do:
+ * - Clear the spinlock variable with an atomic op
+ * - Release the per-CPU mutex
+ * - Unpin ourselves from the current CPU.
+ *
+ * On a uniprocessor system, this means all threads that access protected
+ * data are serialized through the per-CPU mutex. After one thread
+ * acquires the 'spinlock,' any other thread that uses a spinlock on the
+ * current CPU will block on the per-CPU mutex, which has the same general
+ * effect of blocking pre-emption, but _only_ for those threads that are
+ * running NDISulator code.
+ *
+ * On a multiprocessor system, threads on different CPUs all block on
+ * their respective per-CPU mutex, and the atomic test/set operation
+ * on the spinlock variable provides inter-CPU synchronization, though
+ * only for threads running NDISulator code.
+ *
+ * This method solves an important problem. In Windows, you're allowed
+ * to do an ExAllocatePoolWithTag() with a spinlock held, provided you
+ * allocate from NonPagedPool. This implies an atomic heap allocation
+ * that will not cause the current thread to sleep. (You can't sleep
+ * while holding real spinlock: clowns will eat you.) But in FreeBSD,
+ * malloc(9) _always_ triggers the acquisition of a sleep lock, even
+ * when you use M_NOWAIT. This is not a problem for FreeBSD native
+ * code: you're allowed to sleep in things like interrupt threads. But
+ * it is a problem with the old priority-based spinlock implementation:
+ * even though we get away with it most of the time, we really can't
+ * do a malloc(9) after doing a KeAcquireSpinLock() or KeRaiseIrql().
+ * With the new implementation, it's not a problem: you're allowed to
+ * acquire more than one sleep lock (as long as you avoid lock order
+ * reversals).
+ *
+ * The one drawback to this approach is that now we have a lot of
+ * contention on one per-CPU mutex within the NDISulator code. Whether
+ * or not this is preferable to the expected Windows spinlock behavior
+ * of blocking pre-emption is debatable.
*/
uint8_t
@@ -314,10 +391,10 @@ KfReleaseSpinLock(lock, newirql)
return;
}
- uint8_t
+uint8_t
KeGetCurrentIrql()
{
- if (AT_DISPATCH_LEVEL(curthread))
+ if (mtx_owned(&disp_lock[curthread->td_oncpu]))
return(DISPATCH_LEVEL);
return(PASSIVE_LEVEL);
}
@@ -338,19 +415,14 @@ KfRaiseIrql(irql)
{
uint8_t oldirql;
- if (irql < KeGetCurrentIrql())
+ oldirql = KeGetCurrentIrql();
+ if (irql < oldirql)
panic("IRQL_NOT_LESS_THAN");
- if (KeGetCurrentIrql() == DISPATCH_LEVEL)
- return(DISPATCH_LEVEL);
-
- mtx_lock_spin(&sched_lock);
- oldirql = curthread->td_base_pri;
- sched_prio(curthread, PI_REALTIME);
-#if __FreeBSD_version < 600000
- curthread->td_base_pri = PI_REALTIME;
-#endif
- mtx_unlock_spin(&sched_lock);
+ if (oldirql != DISPATCH_LEVEL) {
+ sched_pin();
+ mtx_lock(&disp_lock[curthread->td_oncpu]);
+ }
return(oldirql);
}
@@ -365,12 +437,8 @@ KfLowerIrql(oldirql)
if (KeGetCurrentIrql() != DISPATCH_LEVEL)
panic("IRQL_NOT_GREATER_THAN");
- mtx_lock_spin(&sched_lock);
-#if __FreeBSD_version < 600000
- curthread->td_base_pri = oldirql;
-#endif
- sched_prio(curthread, oldirql);
- mtx_unlock_spin(&sched_lock);
+ mtx_unlock(&disp_lock[curthread->td_oncpu]);
+ sched_unpin();
return;
}
diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c
index 5dfe8e5..7813515 100644
--- a/sys/compat/ndis/subr_ndis.c
+++ b/sys/compat/ndis/subr_ndis.c
@@ -104,6 +104,13 @@ __FBSDID("$FreeBSD$");
#include <compat/ndis/ndis_var.h>
#include <dev/if_ndis/if_ndisvar.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/uma.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+
static char ndis_filepath[MAXPATHLEN];
extern struct nd_head ndis_devhead;
@@ -124,17 +131,17 @@ static ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle,
static void NdisOpenConfiguration(ndis_status *,
ndis_handle *, ndis_handle);
static void NdisOpenConfigurationKeyByIndex(ndis_status *,
- ndis_handle, uint32_t, ndis_unicode_string *, ndis_handle *);
+ ndis_handle, uint32_t, unicode_string *, ndis_handle *);
static void NdisOpenConfigurationKeyByName(ndis_status *,
- ndis_handle, ndis_unicode_string *, ndis_handle *);
+ ndis_handle, unicode_string *, ndis_handle *);
static ndis_status ndis_encode_parm(ndis_miniport_block *,
struct sysctl_oid *, ndis_parm_type, ndis_config_parm **);
static ndis_status ndis_decode_parm(ndis_miniport_block *,
ndis_config_parm *, char *);
static void NdisReadConfiguration(ndis_status *, ndis_config_parm **,
- ndis_handle, ndis_unicode_string *, ndis_parm_type);
+ ndis_handle, unicode_string *, ndis_parm_type);
static void NdisWriteConfiguration(ndis_status *, ndis_handle,
- ndis_unicode_string *, ndis_config_parm *);
+ unicode_string *, ndis_config_parm *);
static void NdisCloseConfiguration(ndis_handle);
static void NdisAllocateSpinLock(ndis_spin_lock *);
static void NdisFreeSpinLock(ndis_spin_lock *);
@@ -213,11 +220,10 @@ static void NdisInitializeEvent(ndis_event *);
static void NdisSetEvent(ndis_event *);
static void NdisResetEvent(ndis_event *);
static uint8_t NdisWaitEvent(ndis_event *, uint32_t);
-static ndis_status NdisUnicodeStringToAnsiString(ndis_ansi_string *,
- ndis_unicode_string *);
+static ndis_status NdisUnicodeStringToAnsiString(ansi_string *,
+ unicode_string *);
static ndis_status
- NdisAnsiStringToUnicodeString(ndis_unicode_string *,
- ndis_ansi_string *);
+ NdisAnsiStringToUnicodeString(unicode_string *, ansi_string *);
static ndis_status NdisMPciAssignResources(ndis_handle,
uint32_t, ndis_resource_list **);
static ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *,
@@ -248,11 +254,10 @@ static uint8_t
void *, void *);
static void NdisGetCurrentSystemTime(uint64_t *);
static void NdisGetSystemUpTime(uint32_t *);
-static void NdisInitializeString(ndis_unicode_string *, char *);
-static void NdisInitAnsiString(ndis_ansi_string *, char *);
-static void NdisInitUnicodeString(ndis_unicode_string *,
- uint16_t *);
-static void NdisFreeString(ndis_unicode_string *);
+static void NdisInitializeString(unicode_string *, char *);
+static void NdisInitAnsiString(ansi_string *, char *);
+static void NdisInitUnicodeString(unicode_string *, uint16_t *);
+static void NdisFreeString(unicode_string *);
static ndis_status NdisMRemoveMiniport(ndis_handle *);
static void NdisTerminateWrapper(ndis_handle, void *);
static void NdisMGetDeviceProperty(ndis_handle, device_object **,
@@ -264,7 +269,7 @@ static void NdisGetFirstBufferFromPacketSafe(ndis_packet *,
ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t);
static int ndis_find_sym(linker_file_t, char *, char *, caddr_t *);
static void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *,
- ndis_unicode_string *, ndis_physaddr);
+ unicode_string *, ndis_physaddr);
static void NdisMapFile(ndis_status *, void **, ndis_handle);
static void NdisUnmapFile(ndis_handle);
static void NdisCloseFile(ndis_handle);
@@ -272,18 +277,19 @@ static uint8_t NdisSystemProcessorCount(void);
static void NdisMIndicateStatusComplete(ndis_handle);
static void NdisMIndicateStatus(ndis_handle, ndis_status,
void *, uint32_t);
+static void ndis_intr(void *);
+static void ndis_intrhand(kdpc *, ndis_miniport_interrupt *, void *, void *);
static funcptr ndis_findwrap(funcptr);
static void NdisCopyFromPacketToPacket(ndis_packet *,
uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *);
static void NdisCopyFromPacketToPacketSafe(ndis_packet *,
uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t);
static ndis_status NdisMRegisterDevice(ndis_handle,
- ndis_unicode_string *, ndis_unicode_string *, driver_dispatch **,
+ unicode_string *, unicode_string *, driver_dispatch **,
void **, ndis_handle *);
static ndis_status NdisMDeregisterDevice(ndis_handle);
static ndis_status
- NdisMQueryAdapterInstanceName(ndis_unicode_string *,
- ndis_handle);
+ NdisMQueryAdapterInstanceName(unicode_string *, ndis_handle);
static void NdisMRegisterUnloadHandler(ndis_handle, void *);
static void dummy(void);
@@ -346,57 +352,6 @@ ndis_findwrap(func)
}
/*
- * NDIS deals with strings in unicode format, so we have
- * do deal with them that way too. For now, we only handle
- * conversion between unicode and ASCII since that's all
- * that device drivers care about.
- */
-
-int
-ndis_ascii_to_unicode(ascii, unicode)
- char *ascii;
- uint16_t **unicode;
-{
- uint16_t *ustr;
- int i;
-
- if (*unicode == NULL)
- *unicode = malloc(strlen(ascii) * 2, M_DEVBUF, M_NOWAIT);
-
- if (*unicode == NULL)
- return(ENOMEM);
- ustr = *unicode;
- for (i = 0; i < strlen(ascii); i++) {
- *ustr = (uint16_t)ascii[i];
- ustr++;
- }
-
- return(0);
-}
-
-int
-ndis_unicode_to_ascii(unicode, ulen, ascii)
- uint16_t *unicode;
- int ulen;
- char **ascii;
-{
- uint8_t *astr;
- int i;
-
- if (*ascii == NULL)
- *ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_NOWAIT|M_ZERO);
- if (*ascii == NULL)
- return(ENOMEM);
- astr = *ascii;
- for (i = 0; i < ulen / 2; i++) {
- *astr = (uint8_t)unicode[i];
- astr++;
- }
-
- return(0);
-}
-
-/*
* This routine does the messy Windows Driver Model device attachment
* stuff on behalf of NDIS drivers. We register our own AddDevice
* routine here
@@ -465,8 +420,10 @@ NdisMRegisterMiniport(handle, characteristics, len)
if (IoAllocateDriverObjectExtension(drv, (void *)1,
sizeof(ndis_miniport_characteristics), (void **)&ch) !=
- STATUS_SUCCESS)
+ STATUS_SUCCESS) {
+ printf("register error\n");
return(NDIS_STATUS_RESOURCES);
+ }
bzero((char *)ch, sizeof(ndis_miniport_characteristics));
@@ -489,10 +446,10 @@ NdisAllocateMemoryWithTag(vaddr, len, tag)
{
void *mem;
-
mem = ExAllocatePoolWithTag(NonPagedPool, len, tag);
- if (mem == NULL)
+ if (mem == NULL) {
return(NDIS_STATUS_RESOURCES);
+ }
*vaddr = mem;
return(NDIS_STATUS_SUCCESS);
@@ -568,7 +525,7 @@ static void
NdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle)
ndis_status *status;
ndis_handle cfg;
- ndis_unicode_string *subkey;
+ unicode_string *subkey;
ndis_handle *subhandle;
{
*subhandle = cfg;
@@ -582,7 +539,7 @@ NdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle)
ndis_status *status;
ndis_handle cfg;
uint32_t idx;
- ndis_unicode_string *subkey;
+ unicode_string *subkey;
ndis_handle *subhandle;
{
*status = NDIS_STATUS_FAILURE;
@@ -597,36 +554,58 @@ ndis_encode_parm(block, oid, type, parm)
ndis_parm_type type;
ndis_config_parm **parm;
{
- uint16_t *unicode;
- ndis_unicode_string *ustr;
+ ndis_config_parm *p;
+ ndis_parmlist_entry *np;
+ unicode_string *us;
+ ansi_string as;
int base = 0;
+ uint32_t val;
+ char tmp[32];
- unicode = (uint16_t *)&block->nmb_dummybuf;
+ np = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(ndis_parmlist_entry), 0);
+ if (np == NULL)
+ return(NDIS_STATUS_RESOURCES);
+ InsertHeadList((&block->nmb_parmlist), (&np->np_list));
+ *parm = p = &np->np_parm;
switch(type) {
case ndis_parm_string:
- ndis_ascii_to_unicode((char *)oid->oid_arg1, &unicode);
- (*parm)->ncp_type = ndis_parm_string;
- ustr = &(*parm)->ncp_parmdata.ncp_stringdata;
- ustr->us_len = strlen((char *)oid->oid_arg1) * 2;
- ustr->us_buf = unicode;
+ /* See if this might be a number. */
+ val = strtoul((char *)oid->oid_arg1, NULL, 10);
+ us = &p->ncp_parmdata.ncp_stringdata;
+ p->ncp_type = ndis_parm_string;
+ if (val) {
+ snprintf(tmp, 32, "%x", val);
+ RtlInitAnsiString(&as, tmp);
+ } else {
+ RtlInitAnsiString(&as, (char *)oid->oid_arg1);
+ }
+
+ if (RtlAnsiStringToUnicodeString(us, &as, TRUE)) {
+ ExFreePool(np);
+ return(NDIS_STATUS_RESOURCES);
+ }
break;
case ndis_parm_int:
if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
base = 16;
else
base = 10;
- (*parm)->ncp_type = ndis_parm_int;
- (*parm)->ncp_parmdata.ncp_intdata =
+ p->ncp_type = ndis_parm_int;
+ p->ncp_parmdata.ncp_intdata =
strtol((char *)oid->oid_arg1, NULL, base);
break;
case ndis_parm_hexint:
+#ifdef notdef
if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
base = 16;
else
base = 10;
- (*parm)->ncp_type = ndis_parm_hexint;
- (*parm)->ncp_parmdata.ncp_intdata =
+#endif
+ base = 16;
+ p->ncp_type = ndis_parm_hexint;
+ p->ncp_parmdata.ncp_intdata =
strtoul((char *)oid->oid_arg1, NULL, base);
break;
default:
@@ -689,15 +668,15 @@ NdisReadConfiguration(status, parm, cfg, key, type)
ndis_status *status;
ndis_config_parm **parm;
ndis_handle cfg;
- ndis_unicode_string *key;
+ unicode_string *key;
ndis_parm_type type;
{
char *keystr = NULL;
- uint16_t *unicode;
ndis_miniport_block *block;
struct ndis_softc *sc;
struct sysctl_oid *oidp;
struct sysctl_ctx_entry *e;
+ ansi_string as;
block = (ndis_miniport_block *)cfg;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
@@ -707,10 +686,12 @@ NdisReadConfiguration(status, parm, cfg, key, type)
return;
}
- ndis_unicode_to_ascii(key->us_buf, key->us_len, &keystr);
- *parm = &block->nmb_replyparm;
- bzero((char *)&block->nmb_replyparm, sizeof(ndis_config_parm));
- unicode = (uint16_t *)&block->nmb_dummybuf;
+ if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
+ *status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ keystr = as.as_buf;
/*
* See if registry key is already in a list of known keys
@@ -724,12 +705,13 @@ NdisReadConfiguration(status, parm, cfg, key, type)
oidp = e->entry;
if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) {
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
*status = NDIS_STATUS_FAILURE;
return;
}
+
*status = ndis_encode_parm(block, oidp, type, parm);
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
return;
}
}
@@ -753,7 +735,7 @@ NdisReadConfiguration(status, parm, cfg, key, type)
ndis_add_sysctl(sc, keystr, "(dynamic string key)",
"UNSET", CTLFLAG_RW);
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
*status = NDIS_STATUS_FAILURE;
return;
@@ -765,15 +747,16 @@ ndis_decode_parm(block, parm, val)
ndis_config_parm *parm;
char *val;
{
- ndis_unicode_string *ustr;
- char *astr = NULL;
+ unicode_string *ustr;
+ ansi_string as;
switch(parm->ncp_type) {
case ndis_parm_string:
ustr = &parm->ncp_parmdata.ncp_stringdata;
- ndis_unicode_to_ascii(ustr->us_buf, ustr->us_len, &astr);
- bcopy(astr, val, 254);
- free(astr, M_DEVBUF);
+ if (RtlUnicodeStringToAnsiString(&as, ustr, TRUE))
+ return(NDIS_STATUS_RESOURCES);
+ bcopy(as.as_buf, val, as.as_len);
+ RtlFreeAnsiString(&as);
break;
case ndis_parm_int:
sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata);
@@ -792,9 +775,10 @@ static void
NdisWriteConfiguration(status, cfg, key, parm)
ndis_status *status;
ndis_handle cfg;
- ndis_unicode_string *key;
+ unicode_string *key;
ndis_config_parm *parm;
{
+ ansi_string as;
char *keystr = NULL;
ndis_miniport_block *block;
struct ndis_softc *sc;
@@ -805,13 +789,18 @@ NdisWriteConfiguration(status, cfg, key, parm)
block = (ndis_miniport_block *)cfg;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
- ndis_unicode_to_ascii(key->us_buf, key->us_len, &keystr);
+ if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
+ *status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ keystr = as.as_buf;
/* Decode the parameter into a string. */
bzero(val, sizeof(val));
*status = ndis_decode_parm(block, parm, val);
if (*status != NDIS_STATUS_SUCCESS) {
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
return;
}
@@ -826,7 +815,7 @@ NdisWriteConfiguration(status, cfg, key, parm)
if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
/* Found it, set the value. */
strcpy((char *)oidp->oid_arg1, val);
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
return;
}
}
@@ -835,7 +824,7 @@ NdisWriteConfiguration(status, cfg, key, parm)
ndis_add_sysctl(sc, keystr, "(dynamically set key)",
val, CTLFLAG_RW);
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
*status = NDIS_STATUS_SUCCESS;
return;
}
@@ -844,6 +833,22 @@ static void
NdisCloseConfiguration(cfg)
ndis_handle cfg;
{
+ list_entry *e;
+ ndis_parmlist_entry *pe;
+ ndis_miniport_block *block;
+ ndis_config_parm *p;
+
+ block = (ndis_miniport_block *)cfg;
+
+ while (!IsListEmpty(&block->nmb_parmlist)) {
+ e = RemoveHeadList(&block->nmb_parmlist);
+ pe = CONTAINING_RECORD(e, ndis_parmlist_entry, np_list);
+ p = &pe->np_parm;
+ if (p->ncp_type == ndis_parm_string)
+ RtlFreeUnicodeString(&p->ncp_parmdata.ncp_stringdata);
+ ExFreePool(e);
+ }
+
return;
}
@@ -1038,6 +1043,7 @@ NdisWritePciSlotInformation(adapter, slot, offset, buf, len)
* The errorlog routine uses a variable argument list, so we
* have to declare it this way.
*/
+
#define ERRMSGLEN 512
static void
NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
@@ -1046,13 +1052,15 @@ NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
ndis_miniport_block *block;
va_list ap;
int i, error;
- char *str = NULL, *ustr = NULL;
+ char *str = NULL;
uint16_t flags;
char msgbuf[ERRMSGLEN];
device_t dev;
driver_object *drv;
struct ndis_softc *sc;
struct ifnet *ifp;
+ unicode_string us;
+ ansi_string as;
block = (ndis_miniport_block *)adapter;
dev = block->nmb_physdeviceobj->do_devext;
@@ -1064,10 +1072,10 @@ NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
code, &str, &i, &flags);
if (error == 0 && flags & MESSAGE_RESOURCE_UNICODE &&
ifp->if_flags & IFF_DEBUG) {
- ustr = msgbuf;
- ndis_unicode_to_ascii((uint16_t *)str,
- ((i / 2)) > (ERRMSGLEN - 1) ? ERRMSGLEN : i, &ustr);
- str = ustr;
+ RtlInitUnicodeString(&us, (uint16_t *)msgbuf);
+ if (RtlUnicodeStringToAnsiString(&as, &us, TRUE))
+ return;
+ str = as.as_buf;
}
device_printf (dev, "NDIS ERROR: %x (%s)\n", code,
@@ -1082,6 +1090,9 @@ NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
va_end(ap);
}
+ if (str != NULL)
+ RtlFreeAnsiString(&as);
+
return;
}
@@ -1404,10 +1415,18 @@ NdisReadNetworkAddress(status, addr, addrlen, adapter)
block = (ndis_miniport_block *)adapter;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+#ifdef IFP2ENADDR
if (bcmp(IFP2ENADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0)
+#else
+ if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0)
+#endif
*status = NDIS_STATUS_FAILURE;
else {
+#ifdef IFP2ENADDR
*addr = IFP2ENADDR(sc->ifp);
+#else
+ *addr = sc->arpcom.ac_enaddr;
+#endif
*addrlen = ETHER_ADDR_LEN;
*status = NDIS_STATUS_SUCCESS;
}
@@ -1530,6 +1549,8 @@ NdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr)
if (sh == NULL)
return;
+ InitializeListHead(&sh->ndis_list);
+
/*
* When performing shared memory allocations, create a tag
* with a lowaddr limit that restricts physical memory mappings
@@ -1582,10 +1603,11 @@ NdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr)
* searching based on the virtual address fails.
*/
+ NDIS_LOCK(sc);
sh->ndis_paddr.np_quad = paddr->np_quad;
sh->ndis_saddr = *vaddr;
- sh->ndis_next = sc->ndis_shlist;
- sc->ndis_shlist = sh;
+ InsertHeadList((&sc->ndis_shlist), (&sh->ndis_list));
+ NDIS_UNLOCK(sc);
return;
}
@@ -1674,21 +1696,24 @@ NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr)
{
ndis_miniport_block *block;
struct ndis_softc *sc;
- struct ndis_shmem *sh, *prev;
+ struct ndis_shmem *sh = NULL;
+ list_entry *l;
if (vaddr == NULL || adapter == NULL)
return;
block = (ndis_miniport_block *)adapter;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
- sh = prev = sc->ndis_shlist;
/* Sanity check: is list empty? */
- if (sh == NULL)
+ if (IsListEmpty(&sc->ndis_shlist))
return;
- while (sh) {
+ NDIS_LOCK(sc);
+ l = sc->ndis_shlist.nle_flink;
+ while (l != &sc->ndis_shlist) {
+ sh = CONTAINING_RECORD(l, struct ndis_shmem, ndis_list);
if (sh->ndis_saddr == vaddr)
break;
/*
@@ -1697,26 +1722,25 @@ NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr)
*/
if (sh->ndis_paddr.np_quad == paddr.np_quad)
break;
- prev = sh;
- sh = sh->ndis_next;
+ l = l->nle_flink;
}
if (sh == NULL) {
+ NDIS_UNLOCK(sc);
printf("NDIS: buggy driver tried to free "
"invalid shared memory: vaddr: %p paddr: 0x%jx\n",
vaddr, (uintmax_t)paddr.np_quad);
return;
}
+ RemoveEntryList(&sh->ndis_list);
+
+ NDIS_UNLOCK(sc);
+
bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap);
bus_dma_tag_destroy(sh->ndis_stag);
- if (sh == sc->ndis_shlist)
- sc->ndis_shlist = sh->ndis_next;
- else
- prev->ndis_next = sh->ndis_next;
-
free(sh, M_DEVBUF);
return;
@@ -2077,6 +2101,7 @@ NdisAllocateBufferPool(status, pool, descnum)
ndis_handle *pool;
uint32_t descnum;
{
+
/*
* The only thing we can really do here is verify that descnum
* is a reasonable value, but I really don't know what to check
@@ -2111,6 +2136,8 @@ NdisAllocateBuffer(status, buffer, pool, vaddr, len)
return;
}
+ MmBuildMdlForNonPagedPool(buf);
+
*buffer = buf;
*status = NDIS_STATUS_SUCCESS;
@@ -2260,37 +2287,35 @@ NdisWaitEvent(event, msecs)
static ndis_status
NdisUnicodeStringToAnsiString(dstr, sstr)
- ndis_ansi_string *dstr;
- ndis_unicode_string *sstr;
+ ansi_string *dstr;
+ unicode_string *sstr;
{
- if (dstr == NULL || sstr == NULL)
- return(NDIS_STATUS_FAILURE);
- if (ndis_unicode_to_ascii(sstr->us_buf,
- sstr->us_len, &dstr->nas_buf))
+ uint32_t rval;
+
+ rval = RtlUnicodeStringToAnsiString(dstr, sstr, FALSE);
+
+ if (rval == STATUS_INSUFFICIENT_RESOURCES)
+ return(NDIS_STATUS_RESOURCES);
+ if (rval)
return(NDIS_STATUS_FAILURE);
- dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf);
+
return (NDIS_STATUS_SUCCESS);
}
static ndis_status
NdisAnsiStringToUnicodeString(dstr, sstr)
- ndis_unicode_string *dstr;
- ndis_ansi_string *sstr;
+ unicode_string *dstr;
+ ansi_string *sstr;
{
- char *str;
- if (dstr == NULL || sstr == NULL)
- return(NDIS_STATUS_FAILURE);
- str = malloc(sstr->nas_len + 1, M_DEVBUF, M_NOWAIT);
- if (str == NULL)
- return(NDIS_STATUS_FAILURE);
- strncpy(str, sstr->nas_buf, sstr->nas_len);
- *(str + sstr->nas_len) = '\0';
- if (ndis_ascii_to_unicode(str, &dstr->us_buf)) {
- free(str, M_DEVBUF);
+ uint32_t rval;
+
+ rval = RtlAnsiStringToUnicodeString(dstr, sstr, FALSE);
+
+ if (rval == STATUS_INSUFFICIENT_RESOURCES)
+ return(NDIS_STATUS_RESOURCES);
+ if (rval)
return(NDIS_STATUS_FAILURE);
- }
- dstr->us_len = dstr->us_maxlen = sstr->nas_len * 2;
- free(str, M_DEVBUF);
+
return (NDIS_STATUS_SUCCESS);
}
@@ -2311,6 +2336,77 @@ NdisMPciAssignResources(adapter, slot, list)
return (NDIS_STATUS_SUCCESS);
}
+static void
+ndis_intr(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ struct ifnet *ifp;
+ int is_our_intr = 0;
+ int call_isr = 0;
+ ndis_miniport_interrupt *intr;
+
+ sc = arg;
+ ifp = sc->ifp;
+ intr = sc->ndis_block->nmb_interrupt;
+
+ if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL)
+ return;
+
+ 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 ((is_our_intr || call_isr))
+ IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
+
+ return;
+}
+
+static void
+ndis_intrhand(dpc, intr, sysarg1, sysarg2)
+ kdpc *dpc;
+ ndis_miniport_interrupt *intr;
+ void *sysarg1;
+ void *sysarg2;
+{
+ struct ndis_softc *sc;
+ ndis_miniport_block *block;
+ ndis_handle adapter;
+
+ block = intr->ni_block;
+ adapter = block->nmb_miniportadapterctx;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+
+ if (NDIS_SERIALIZED(sc->ndis_block))
+ KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
+
+ MSCALL1(intr->ni_isrfunc, adapter);
+
+ /* If there's a MiniportEnableInterrupt() routine, call it. */
+
+ ndis_enable_intr(sc);
+
+ if (NDIS_SERIALIZED(sc->ndis_block))
+ KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
+
+ /*
+ * Set the completion event if we've drained all
+ * pending interrupts.
+ */
+
+ KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
+ intr->ni_dpccnt--;
+ if (intr->ni_dpccnt == 0)
+ KeSetEvent(&intr->ni_dpcevt, IO_NO_INCREMENT, FALSE);
+ KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
+
+ return;
+}
+
static ndis_status
NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode)
ndis_miniport_interrupt *intr;
@@ -2322,15 +2418,40 @@ NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode)
ndis_interrupt_mode imode;
{
ndis_miniport_block *block;
+ ndis_miniport_characteristics *ch;
+ struct ndis_softc *sc;
+ int error;
block = adapter;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+ ch = IoGetDriverObjectExtension(block->nmb_deviceobj->do_drvobj,
+ (void *)1);
+
+ intr->ni_rsvd = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct mtx), 0);
+ if (intr->ni_rsvd == NULL)
+ return(NDIS_STATUS_RESOURCES);
intr->ni_block = adapter;
intr->ni_isrreq = reqisr;
intr->ni_shared = shared;
- block->nmb_interrupt = intr;
+ intr->ni_dpccnt = 0;
+ intr->ni_isrfunc = ch->nmc_interrupt_func;
+ intr->ni_dpcfunc = ch->nmc_isr_func;
+
+ KeInitializeEvent(&intr->ni_dpcevt, EVENT_TYPE_NOTIFY, TRUE);
+ KeInitializeDpc(&intr->ni_dpc,
+ ndis_findwrap((funcptr)ndis_intrhand), intr);
+ KeSetImportanceDpc(&intr->ni_dpc, KDPC_IMPORTANCE_LOW);
- KeInitializeSpinLock(&intr->ni_dpccountlock);
+ error = IoConnectInterrupt(&intr->ni_introbj,
+ ndis_findwrap((funcptr)ndis_intr), sc, NULL,
+ ivec, ilevel, 0, imode, shared, 0, FALSE);
+
+ if (error != STATUS_SUCCESS)
+ return(NDIS_STATUS_FAILURE);
+
+ block->nmb_interrupt = intr;
return(NDIS_STATUS_SUCCESS);
}
@@ -2339,6 +2460,29 @@ static void
NdisMDeregisterInterrupt(intr)
ndis_miniport_interrupt *intr;
{
+ ndis_miniport_block *block;
+ struct ndis_softc *sc;
+ uint8_t irql;
+
+ block = intr->ni_block;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+
+ /* Should really be KeSynchronizeExecution() */
+
+ KeAcquireSpinLock(intr->ni_introbj->ki_lock, &irql);
+ block->nmb_interrupt = NULL;
+ KeReleaseSpinLock(intr->ni_introbj->ki_lock, irql);
+/*
+ KeFlushQueuedDpcs();
+*/
+ /* Disconnect our ISR */
+
+ IoDisconnectInterrupt(intr->ni_introbj);
+
+ KeWaitForSingleObject((nt_dispatch_header *)&intr->ni_dpcevt,
+ 0, 0, FALSE, NULL);
+ KeResetEvent(&intr->ni_dpcevt);
+
return;
}
@@ -2429,23 +2573,22 @@ static void
NdisMSleep(usecs)
uint32_t usecs;
{
- struct timeval tv;
+ ktimer timer;
/*
* During system bootstrap, (i.e. cold == 1), we aren't
- * allowed to msleep(), so calling ndis_thsuspend() here
- * will return 0, and we won't actually have delayed. This
- * is a problem because some drivers expect NdisMSleep()
- * to always wait, and might fail if the expected delay
- * period does not in fact elapse. As a workaround, if the
- * attempt to sleep delay fails, we do a hard DELAY() instead.
+ * allowed to sleep, so we have to do a hard DELAY()
+ * instead.
*/
- tv.tv_sec = 0;
- tv.tv_usec = usecs;
- if (ndis_thsuspend(curthread->td_proc, NULL, tvtohz(&tv)) == 0)
+ if (cold)
DELAY(usecs);
-
+ else {
+ KeInitializeTimer(&timer);
+ KeSetTimer(&timer, ((int64_t)usecs * -10), NULL);
+ KeWaitForSingleObject((nt_dispatch_header *)&timer,
+ 0, 0, FALSE, NULL);
+ }
return;
}
@@ -2571,19 +2714,7 @@ NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx)
void *syncfunc;
void *syncctx;
{
- uint8_t (*sync)(void *);
- uint8_t rval;
- uint8_t irql;
-
- if (syncfunc == NULL || syncctx == NULL)
- return(0);
-
- sync = syncfunc;
- KeAcquireSpinLock(&intr->ni_dpccountlock, &irql);
- rval = MSCALL1(sync, syncctx);
- KeReleaseSpinLock(&intr->ni_dpccountlock, irql);
-
- return(rval);
+ return(KeSynchronizeExecution(intr->ni_introbj, syncfunc, syncctx));
}
/*
@@ -2620,28 +2751,20 @@ NdisGetSystemUpTime(tval)
static void
NdisInitializeString(dst, src)
- ndis_unicode_string *dst;
+ unicode_string *dst;
char *src;
{
- ndis_unicode_string *u;
-
- u = dst;
- u->us_buf = NULL;
- if (ndis_ascii_to_unicode(src, &u->us_buf))
- return;
- u->us_len = u->us_maxlen = strlen(src) * 2;
+ ansi_string as;
+ RtlInitAnsiString(&as, src);
+ RtlAnsiStringToUnicodeString(dst, &as, TRUE);
return;
}
static void
NdisFreeString(str)
- ndis_unicode_string *str;
+ unicode_string *str;
{
- if (str == NULL)
- return;
- if (str->us_buf != NULL)
- free(str->us_buf, M_DEVBUF);
- free(str, M_DEVBUF);
+ RtlFreeUnicodeString(str);
return;
}
@@ -2654,47 +2777,19 @@ NdisMRemoveMiniport(adapter)
static void
NdisInitAnsiString(dst, src)
- ndis_ansi_string *dst;
+ ansi_string *dst;
char *src;
{
- ndis_ansi_string *a;
-
- a = dst;
- if (a == NULL)
- return;
- if (src == NULL) {
- a->nas_len = a->nas_maxlen = 0;
- a->nas_buf = NULL;
- } else {
- a->nas_buf = src;
- a->nas_len = a->nas_maxlen = strlen(src);
- }
-
+ RtlInitAnsiString(dst, src);
return;
}
static void
NdisInitUnicodeString(dst, src)
- ndis_unicode_string *dst;
+ unicode_string *dst;
uint16_t *src;
{
- ndis_unicode_string *u;
- int i;
-
- u = dst;
- if (u == NULL)
- return;
- if (src == NULL) {
- u->us_len = u->us_maxlen = 0;
- u->us_buf = NULL;
- } else {
- i = 0;
- while(src[i] != 0)
- i++;
- u->us_buf = src;
- u->us_len = u->us_maxlen = i * 2;
- }
-
+ RtlInitUnicodeString(dst, src);
return;
}
@@ -2806,9 +2901,10 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr)
ndis_status *status;
ndis_handle *filehandle;
uint32_t *filelength;
- ndis_unicode_string *filename;
+ unicode_string *filename;
ndis_physaddr highestaddr;
{
+ ansi_string as;
char *afilename = NULL;
struct thread *td = curthread;
struct nameidata nd;
@@ -2820,8 +2916,13 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr)
linker_file_t head, lf;
caddr_t kldstart, kldend;
- ndis_unicode_to_ascii(filename->us_buf,
- filename->us_len, &afilename);
+ if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) {
+ *status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ afilename = strdup(as.as_buf, M_DEVBUF);
+ RtlFreeAnsiString(&as);
fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0);
if (fh == NULL) {
@@ -3120,6 +3221,7 @@ NdisScheduleWorkItem(work)
ExInitializeWorkItem(wqi,
(work_item_func)work->nwi_func, work->nwi_ctx);
ExQueueWorkItem(wqi, WORKQUEUE_DELAYED);
+
return(NDIS_STATUS_SUCCESS);
}
@@ -3230,8 +3332,8 @@ NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio)
static ndis_status
NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle)
ndis_handle handle;
- ndis_unicode_string *devname;
- ndis_unicode_string *symname;
+ unicode_string *devname;
+ unicode_string *symname;
driver_dispatch *majorfuncs[];
void **devobj;
ndis_handle *devhandle;
@@ -3260,18 +3362,19 @@ NdisMDeregisterDevice(handle)
static ndis_status
NdisMQueryAdapterInstanceName(name, handle)
- ndis_unicode_string *name;
+ unicode_string *name;
ndis_handle handle;
{
ndis_miniport_block *block;
device_t dev;
+ ansi_string as;
block = (ndis_miniport_block *)handle;
dev = block->nmb_physdeviceobj->do_devext;
- ndis_ascii_to_unicode(__DECONST(char *,
- device_get_nameunit(dev)), &name->us_buf);
- name->us_len = strlen(device_get_nameunit(dev)) * 2;
+ RtlInitAnsiString(&as, __DECONST(char *, device_get_nameunit(dev)));
+ if (RtlAnsiStringToUnicodeString(name, &as, TRUE))
+ return(NDIS_STATUS_RESOURCES);
return(NDIS_STATUS_SUCCESS);
}
@@ -3422,6 +3525,8 @@ image_patch_table ndis_functbl[] = {
IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2),
IMPORT_SFUNC(ndis_timercall, 4),
IMPORT_SFUNC(ndis_asyncmem_complete, 2),
+ IMPORT_SFUNC(ndis_intr, 1),
+ IMPORT_SFUNC(ndis_intrhand, 4),
/*
* This last entry is a catch-all for any function we haven't
diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c
index 6ff0689..fd3955c 100644
--- a/sys/compat/ndis/subr_ntoskrnl.c
+++ b/sys/compat/ndis/subr_ntoskrnl.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <sys/kernel.h>
#include <sys/proc.h>
+#include <sys/condvar.h>
#include <sys/kthread.h>
#include <sys/module.h>
#include <sys/smp.h>
@@ -58,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <machine/clock.h>
#include <machine/bus.h>
#include <machine/stdarg.h>
+#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
@@ -77,11 +79,8 @@ __FBSDID("$FreeBSD$");
#include <compat/ndis/ndis_var.h>
struct kdpc_queue {
- list_entry kq_high;
- list_entry kq_low;
- list_entry kq_med;
+ list_entry kq_disp;
struct thread *kq_td;
- int kq_state;
int kq_cpu;
int kq_exit;
struct mtx kq_lock;
@@ -92,14 +91,22 @@ struct kdpc_queue {
typedef struct kdpc_queue kdpc_queue;
-static uint8_t RtlEqualUnicodeString(ndis_unicode_string *,
- ndis_unicode_string *, uint8_t);
-static void RtlCopyUnicodeString(ndis_unicode_string *,
- ndis_unicode_string *);
-static ndis_status RtlUnicodeStringToAnsiString(ndis_ansi_string *,
- ndis_unicode_string *, uint8_t);
-static ndis_status RtlAnsiStringToUnicodeString(ndis_unicode_string *,
- ndis_ansi_string *, uint8_t);
+struct wb_ext {
+ struct cv we_cv;
+ struct thread *we_td;
+};
+
+typedef struct wb_ext wb_ext;
+
+#define NTOSKRNL_TIMEOUTS 256
+struct callout ntoskrnl_callout[NTOSKRNL_TIMEOUTS];
+int ntoskrnl_callidx;
+#define CALLOUT_INC(i) (i) = ((i) + 1) % NTOSKRNL_TIMEOUTS
+
+static uint8_t RtlEqualUnicodeString(unicode_string *,
+ unicode_string *, uint8_t);
+static void RtlCopyUnicodeString(unicode_string *,
+ unicode_string *);
static irp *IoBuildSynchronousFsdRequest(uint32_t, device_object *,
void *, uint32_t, uint64_t *, nt_kevent *, io_status_block *);
static irp *IoBuildAsynchronousFsdRequest(uint32_t,
@@ -115,7 +122,10 @@ static irp *IoMakeAssociatedIrp(irp *, uint8_t);
static uint32_t KeWaitForMultipleObjects(uint32_t,
nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t,
int64_t *, wait_block *);
-static void ntoskrnl_wakeup(void *);
+static void ntoskrnl_waittest(nt_dispatch_header *, uint32_t);
+static void ntoskrnl_satisfy_wait(nt_dispatch_header *, struct thread *);
+static void ntoskrnl_satisfy_multiple_waits(wait_block *);
+static int ntoskrnl_is_signalled(nt_dispatch_header *, struct thread *);
static void ntoskrnl_timercall(void *);
static void ntoskrnl_run_dpc(void *);
static void ntoskrnl_dpc_thread(void *);
@@ -123,7 +133,12 @@ static void ntoskrnl_destroy_dpc_threads(void);
static void ntoskrnl_destroy_workitem_threads(void);
static void ntoskrnl_workitem_thread(void *);
static void ntoskrnl_workitem(device_object *, void *);
+static void ntoskrnl_unicode_to_ascii(uint16_t *, char *, int);
+static void ntoskrnl_ascii_to_unicode(char *, uint16_t *, int);
static uint8_t ntoskrnl_insert_dpc(list_entry *, kdpc *);
+static device_t ntoskrnl_finddev(device_t, uint32_t,
+ uint8_t, uint8_t, struct resource **);
+static void ntoskrnl_intr(void *);
static void WRITE_REGISTER_USHORT(uint16_t *, uint16_t);
static uint16_t READ_REGISTER_USHORT(uint16_t *);
static void WRITE_REGISTER_ULONG(uint32_t *, uint32_t);
@@ -163,19 +178,13 @@ static uint32_t InterlockedIncrement(volatile uint32_t *);
static uint32_t InterlockedDecrement(volatile uint32_t *);
static void ExInterlockedAddLargeStatistic(uint64_t *, uint32_t);
static uint32_t MmSizeOfMdl(void *, size_t);
-static void MmBuildMdlForNonPagedPool(mdl *);
static void *MmMapLockedPages(mdl *, uint8_t);
static void *MmMapLockedPagesSpecifyCache(mdl *,
uint8_t, uint32_t, void *, uint32_t, uint32_t);
static void MmUnmapLockedPages(void *, mdl *);
static uint8_t MmIsAddressValid(void *);
static size_t RtlCompareMemory(const void *, const void *, size_t);
-static void RtlInitAnsiString(ndis_ansi_string *, char *);
-static void RtlInitUnicodeString(ndis_unicode_string *,
- uint16_t *);
-static void RtlFreeUnicodeString(ndis_unicode_string *);
-static void RtlFreeAnsiString(ndis_ansi_string *);
-static ndis_status RtlUnicodeStringToInteger(ndis_unicode_string *,
+static ndis_status RtlUnicodeStringToInteger(unicode_string *,
uint32_t, uint32_t *);
static int atoi (const char *);
static long atol (const char *);
@@ -198,6 +207,8 @@ static void ObfDereferenceObject(void *);
static uint32_t ZwClose(ndis_handle);
static void *ntoskrnl_memset(void *, int, size_t);
static char *ntoskrnl_strstr(char *, char *);
+static int ntoskrnl_toupper(int);
+static int ntoskrnl_tolower(int);
static funcptr ntoskrnl_findwrap(funcptr);
static uint32_t DbgPrint(char *, ...);
static void DbgBreakPoint(void);
@@ -280,6 +291,9 @@ ntoskrnl_libinit()
patch++;
}
+ for (i = 0; i < NTOSKRNL_TIMEOUTS; i++)
+ callout_init(&ntoskrnl_callout[i], CALLOUT_MPSAFE);
+
/*
* MDLs are supposed to be variable size (they describe
* buffers containing some number of pages, but we don't
@@ -313,10 +327,10 @@ ntoskrnl_libfini()
patch++;
}
- /* Stop the DPC queues. */
- ntoskrnl_destroy_dpc_threads();
/* Stop the workitem queues. */
ntoskrnl_destroy_workitem_threads();
+ /* Stop the DPC queues. */
+ ntoskrnl_destroy_dpc_threads();
ExFreePool(kq_queues);
ExFreePool(wq_queues);
@@ -362,11 +376,24 @@ ntoskrnl_strstr(s, find)
return ((char *)s);
}
+static int
+ntoskrnl_toupper(c)
+ int c;
+{
+ return(toupper(c));
+}
+
+static int
+ntoskrnl_tolower(c)
+ int c;
+{
+ return(tolower(c));
+}
static uint8_t
RtlEqualUnicodeString(str1, str2, caseinsensitive)
- ndis_unicode_string *str1;
- ndis_unicode_string *str2;
+ unicode_string *str1;
+ unicode_string *str2;
uint8_t caseinsensitive;
{
int i;
@@ -390,8 +417,8 @@ RtlEqualUnicodeString(str1, str2, caseinsensitive)
static void
RtlCopyUnicodeString(dest, src)
- ndis_unicode_string *dest;
- ndis_unicode_string *src;
+ unicode_string *dest;
+ unicode_string *src;
{
if (dest->us_maxlen >= src->us_len)
@@ -402,55 +429,99 @@ RtlCopyUnicodeString(dest, src)
return;
}
-static ndis_status
+static void
+ntoskrnl_ascii_to_unicode(ascii, unicode, len)
+ char *ascii;
+ uint16_t *unicode;
+ int len;
+{
+ int i;
+ uint16_t *ustr;
+
+ ustr = unicode;
+ for (i = 0; i < len; i++) {
+ *ustr = (uint16_t)ascii[i];
+ ustr++;
+ }
+
+ return;
+}
+
+static void
+ntoskrnl_unicode_to_ascii(unicode, ascii, len)
+ uint16_t *unicode;
+ char *ascii;
+ int len;
+{
+ int i;
+ uint8_t *astr;
+
+ astr = ascii;
+ for (i = 0; i < len / 2; i++) {
+ *astr = (uint8_t)unicode[i];
+ astr++;
+ }
+
+ return;
+}
+
+uint32_t
RtlUnicodeStringToAnsiString(dest, src, allocate)
- ndis_ansi_string *dest;
- ndis_unicode_string *src;
+ ansi_string *dest;
+ unicode_string *src;
uint8_t allocate;
{
- char *astr = NULL;
-
if (dest == NULL || src == NULL)
return(NDIS_STATUS_FAILURE);
+
+ dest->as_len = src->us_len / 2;
+ if (dest->as_maxlen < dest->as_len)
+ dest->as_len = dest->as_maxlen;
+
if (allocate == TRUE) {
- if (ndis_unicode_to_ascii(src->us_buf, src->us_len, &astr))
- return(NDIS_STATUS_FAILURE);
- dest->nas_buf = astr;
- dest->nas_len = dest->nas_maxlen = strlen(astr);
+ dest->as_buf = ExAllocatePoolWithTag(NonPagedPool,
+ (src->us_len / 2) + 1, 0);
+ if (dest->as_buf == NULL)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ dest->as_len = dest->as_maxlen = src->us_len / 2;
} else {
- dest->nas_len = src->us_len / 2; /* XXX */
- if (dest->nas_maxlen < dest->nas_len)
- dest->nas_len = dest->nas_maxlen;
- ndis_unicode_to_ascii(src->us_buf, dest->nas_len * 2,
- &dest->nas_buf);
+ dest->as_len = src->us_len / 2; /* XXX */
+ if (dest->as_maxlen < dest->as_len)
+ dest->as_len = dest->as_maxlen;
}
- return (NDIS_STATUS_SUCCESS);
+
+ ntoskrnl_unicode_to_ascii(src->us_buf, dest->as_buf,
+ dest->as_len * 2);
+
+ return (STATUS_SUCCESS);
}
-static ndis_status
+uint32_t
RtlAnsiStringToUnicodeString(dest, src, allocate)
- ndis_unicode_string *dest;
- ndis_ansi_string *src;
+ unicode_string *dest;
+ ansi_string *src;
uint8_t allocate;
{
- uint16_t *ustr = NULL;
-
if (dest == NULL || src == NULL)
return(NDIS_STATUS_FAILURE);
if (allocate == TRUE) {
- if (ndis_ascii_to_unicode(src->nas_buf, &ustr))
- return(NDIS_STATUS_FAILURE);
- dest->us_buf = ustr;
- dest->us_len = dest->us_maxlen = strlen(src->nas_buf) * 2;
+ dest->us_buf = ExAllocatePoolWithTag(NonPagedPool,
+ src->as_len * 2, 0);
+ if (dest->us_buf == NULL)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ dest->us_len = dest->us_maxlen = strlen(src->as_buf) * 2;
} else {
- dest->us_len = src->nas_len * 2; /* XXX */
+ dest->us_len = src->as_len * 2; /* XXX */
if (dest->us_maxlen < dest->us_len)
dest->us_len = dest->us_maxlen;
- ndis_ascii_to_unicode(src->nas_buf, &dest->us_buf);
}
- return (NDIS_STATUS_SUCCESS);
+
+ ntoskrnl_ascii_to_unicode(src->as_buf, dest->us_buf,
+ dest->us_len / 2);
+
+ return (STATUS_SUCCESS);
}
void *
@@ -461,9 +532,10 @@ ExAllocatePoolWithTag(pooltype, len, tag)
{
void *buf;
- buf = malloc(len, M_DEVBUF, M_NOWAIT);
+ buf = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
if (buf == NULL)
return(NULL);
+
return(buf);
}
@@ -491,7 +563,7 @@ IoAllocateDriverObjectExtension(drv, clid, extlen, ext)
return(STATUS_INSUFFICIENT_RESOURCES);
ce->ce_clid = clid;
- INSERT_LIST_TAIL((&drv->dro_driverext->dre_usrext), (&ce->ce_list));
+ InsertTailList((&drv->dro_driverext->dre_usrext), (&ce->ce_list));
*ext = (void *)(ce + 1);
@@ -902,7 +974,7 @@ IoInitializeIrp(io, psize, ssize)
io->irp_size = psize;
io->irp_stackcnt = ssize;
io->irp_currentstackloc = ssize;
- INIT_LIST_HEAD(&io->irp_thlist);
+ InitializeListHead(&io->irp_thlist);
io->irp_tail.irp_overlay.irp_csl =
(io_stack_location *)(io + 1) + ssize;
@@ -1060,6 +1132,202 @@ IofCompleteRequest(ip, prioboost)
return;
}
+static device_t
+ntoskrnl_finddev(dev, vector, irql, shared, res)
+ device_t dev;
+ uint32_t vector;
+ uint8_t irql;
+ uint8_t shared;
+ struct resource **res;
+{
+ device_t *children;
+ device_t matching_dev;
+ int childcnt;
+ struct resource *r;
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+ uint32_t flags;
+ int i;
+
+ /* We only want devices that have been successfully probed. */
+
+ if (device_is_alive(dev) == FALSE)
+ return(NULL);
+
+ device_get_children(dev, &children, &childcnt);
+
+ /*
+ * If this device has no children, it's a leaf: we can
+ * examine its resources. If the interrupt resource we
+ * want isn't here, we return NULL, otherwise we return
+ * the device to terminate the recursive search.
+ */
+
+ if (childcnt == 0) {
+ rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
+ if (rl == NULL)
+ return(NULL);
+#if __FreeBSD_version < 600022
+ SLIST_FOREACH(rle, rl, link) {
+#else
+ STAILQ_FOREACH(rle, rl, link) {
+#endif
+ r = rle->res;
+
+ if (r == NULL)
+ continue;
+
+ flags = rman_get_flags(r);
+
+ if (!(flags & RF_ACTIVE))
+ continue;
+
+ if (shared == TRUE && !(flags & RF_SHAREABLE))
+ continue;
+
+ if (rle->type == SYS_RES_IRQ &&
+ rman_get_start(r) == irql) {
+ *res = r;
+ return(dev);
+ }
+ }
+ /* No match. */
+ return (NULL);
+ }
+
+ /*
+ * If this device has children, do another
+ * level of recursion to inspect them.
+ */
+
+ for (i = 0; i < childcnt; i++) {
+ matching_dev = ntoskrnl_finddev(children[i],
+ vector, irql, shared, res);
+ if (matching_dev != NULL) {
+ free(children, M_TEMP);
+ return(matching_dev);
+ }
+ }
+
+ free(children, M_TEMP);
+ return(NULL);
+}
+
+static void
+ntoskrnl_intr(arg)
+ void *arg;
+{
+ kinterrupt *iobj;
+ uint8_t irql;
+
+ iobj = arg;
+
+ KeAcquireSpinLock(iobj->ki_lock, &irql);
+ MSCALL1(iobj->ki_svcfunc, iobj->ki_svcctx);
+ KeReleaseSpinLock(iobj->ki_lock, irql);
+
+ return;
+}
+
+uint8_t
+KeSynchronizeExecution(iobj, syncfunc, syncctx)
+ kinterrupt *iobj;
+ void *syncfunc;
+ void *syncctx;
+{
+ uint8_t irql;
+
+ KeAcquireSpinLock(iobj->ki_lock, &irql);
+ MSCALL1(syncfunc, syncctx);
+ KeReleaseSpinLock(iobj->ki_lock, irql);
+
+ return(TRUE);
+}
+
+/*
+ * This routine is a pain because the only thing we get passed
+ * here is the interrupt request level and vector, but bus_setup_intr()
+ * needs the device too. We can hack around this for now, but it's
+ * awkward.
+ */
+
+uint32_t
+IoConnectInterrupt(iobj, svcfunc, svcctx, lock, vector, irql,
+ syncirql, imode, shared, affinity, savefloat)
+ kinterrupt **iobj;
+ void *svcfunc;
+ void *svcctx;
+ uint32_t vector;
+ kspin_lock *lock;
+ uint8_t irql;
+ uint8_t syncirql;
+ uint8_t imode;
+ uint8_t shared;
+ uint32_t affinity;
+ uint8_t savefloat;
+{
+ devclass_t nexus_class;
+ device_t *nexus_devs, devp;
+ int nexus_count = 0;
+ device_t matching_dev = NULL;
+ struct resource *res;
+ int i, error;
+
+ nexus_class = devclass_find("nexus");
+ devclass_get_devices(nexus_class, &nexus_devs, &nexus_count);
+
+ for (i = 0; i < nexus_count; i++) {
+ devp = nexus_devs[i];
+ matching_dev = ntoskrnl_finddev(devp, vector,
+ irql, shared, &res);
+ if (matching_dev)
+ break;
+ }
+
+ free(nexus_devs, M_TEMP);
+
+ if (matching_dev == NULL)
+ return(STATUS_INVALID_PARAMETER);
+
+ *iobj = ExAllocatePoolWithTag(NonPagedPool, sizeof(kinterrupt), 0);
+ if (*iobj == NULL)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ (*iobj)->ki_dev = matching_dev;
+ (*iobj)->ki_irq = res;
+ (*iobj)->ki_svcfunc = svcfunc;
+ (*iobj)->ki_svcctx = svcctx;
+
+ if (lock == NULL) {
+ KeInitializeSpinLock(&(*iobj)->ki_lock_priv);
+ (*iobj)->ki_lock = &(*iobj)->ki_lock_priv;
+ } else
+ (*iobj)->ki_lock = lock;
+
+ error = bus_setup_intr(matching_dev, res, INTR_TYPE_NET | INTR_MPSAFE,
+ ntoskrnl_intr, *iobj, &(*iobj)->ki_cookie);
+
+ if (error) {
+ ExFreePool(iobj);
+ return (STATUS_INVALID_PARAMETER);
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+void
+IoDisconnectInterrupt(iobj)
+ kinterrupt *iobj;
+{
+ if (iobj == NULL)
+ return;
+
+ bus_teardown_intr(iobj->ki_dev, iobj->ki_irq, iobj->ki_cookie);
+ ExFreePool(iobj);
+
+ return;
+}
+
device_object *
IoAttachDeviceToDeviceStack(src, dst)
device_object *src;
@@ -1094,7 +1362,7 @@ IoDetachDevice(topdev)
topdev->do_attacheddev = tail->do_attacheddev;
topdev->do_refcnt--;
- /* Now reduce the stacksize count for the tail objects. */
+ /* Now reduce the stacksize count for the takm_il objects. */
tail = topdev->do_attacheddev;
while (tail != NULL) {
@@ -1107,48 +1375,168 @@ IoDetachDevice(topdev)
return;
}
-/* Always called with dispatcher lock held. */
-static void
-ntoskrnl_wakeup(arg)
- void *arg;
+/*
+ * For the most part, an object is considered signalled if
+ * dh_sigstate == TRUE. The exception is for mutant objects
+ * (mutexes), where the logic works like this:
+ *
+ * - If the thread already owns the object and sigstate is
+ * less than or equal to 0, then the object is considered
+ * signalled (recursive acquisition).
+ * - If dh_sigstate == 1, the object is also considered
+ * signalled.
+ */
+
+static int
+ntoskrnl_is_signalled(obj, td)
+ nt_dispatch_header *obj;
+ struct thread *td;
{
+ kmutant *km;
+
+ if (obj->dh_type == DISP_TYPE_MUTANT) {
+ km = (kmutant *)obj;
+ if ((obj->dh_sigstate <= 0 && km->km_ownerthread == td) ||
+ obj->dh_sigstate == 1)
+ return(TRUE);
+ return(FALSE);
+ }
+
+ if (obj->dh_sigstate > 0)
+ return(TRUE);
+ return(FALSE);
+}
+
+static void
+ntoskrnl_satisfy_wait(obj, td)
nt_dispatch_header *obj;
- wait_block *w;
- list_entry *e;
struct thread *td;
+{
+ kmutant *km;
- obj = arg;
+ switch (obj->dh_type) {
+ case DISP_TYPE_MUTANT:
+ km = (struct kmutant *)obj;
+ obj->dh_sigstate--;
+ /*
+ * If sigstate reaches 0, the mutex is now
+ * non-signalled (the new thread owns it).
+ */
+ if (obj->dh_sigstate == 0) {
+ km->km_ownerthread = td;
+ if (km->km_abandoned == TRUE)
+ km->km_abandoned = FALSE;
+ }
+ break;
+ /* Synchronization objects get reset to unsignalled. */
+ case DISP_TYPE_SYNCHRONIZATION_EVENT:
+ case DISP_TYPE_SYNCHRONIZATION_TIMER:
+ obj->dh_sigstate = 0;
+ break;
+ case DISP_TYPE_SEMAPHORE:
+ obj->dh_sigstate--;
+ break;
+ default:
+ break;
+ }
- e = obj->dh_waitlisthead.nle_flink;
+ return;
+}
+
+static void
+ntoskrnl_satisfy_multiple_waits(wb)
+ wait_block *wb;
+{
+ wait_block *cur;
+ struct thread *td;
+
+ cur = wb;
+ td = wb->wb_kthread;
- obj->dh_sigstate = TRUE;
+ do {
+ ntoskrnl_satisfy_wait(wb->wb_object, td);
+ cur->wb_awakened = TRUE;
+ cur = cur->wb_next;
+ } while (cur != wb);
+
+ return;
+}
+
+/* Always called with dispatcher lock held. */
+static void
+ntoskrnl_waittest(obj, increment)
+ nt_dispatch_header *obj;
+ uint32_t increment;
+{
+ wait_block *w, *next;
+ list_entry *e;
+ struct thread *td;
+ wb_ext *we;
+ int satisfied;
/*
- * What happens if someone tells us to wake up
- * threads waiting on an object, but nobody's
- * waiting on it at the moment? For sync events,
- * the signal state is supposed to be automatically
- * reset, but this only happens in the KeWaitXXX()
- * functions. If nobody is waiting, the state never
- * gets cleared.
+ * Once an object has been signalled, we walk its list of
+ * wait blocks. If a wait block can be awakened, then satisfy
+ * waits as necessary and wake the thread.
+ *
+ * The rules work like this:
+ *
+ * If a wait block is marked as WAITTYPE_ANY, then
+ * we can satisfy the wait conditions on the current
+ * object and wake the thread right away. Satisfying
+ * the wait also has the effect of breaking us out
+ * of the search loop.
+ *
+ * If the object is marked as WAITTYLE_ALL, then the
+ * wait block will be part of a circularly linked
+ * list of wait blocks belonging to a waiting thread
+ * that's sleeping in KeWaitForMultipleObjects(). In
+ * order to wake the thread, all the objects in the
+ * wait list must be in the signalled state. If they
+ * are, we then satisfy all of them and wake the
+ * thread.
+ *
*/
- if (e == &obj->dh_waitlisthead) {
- if (obj->dh_type == EVENT_TYPE_SYNC)
- obj->dh_sigstate = FALSE;
- return;
- }
+ e = obj->dh_waitlisthead.nle_flink;
- while (e != &obj->dh_waitlisthead) {
- w = (wait_block *)e;
- td = w->wb_kthread;
- ndis_thresume(td->td_proc);
- /*
- * For synchronization objects, only wake up
- * the first waiter.
- */
- if (obj->dh_type == EVENT_TYPE_SYNC)
- break;
+ while (e != &obj->dh_waitlisthead && obj->dh_sigstate > 0) {
+ w = CONTAINING_RECORD(e, wait_block, wb_waitlist);
+ we = w->wb_ext;
+ td = we->we_td;
+ satisfied = FALSE;
+ if (w->wb_waittype == WAITTYPE_ANY) {
+ /*
+ * Thread can be awakened if
+ * any wait is satisfied.
+ */
+ ntoskrnl_satisfy_wait(obj, td);
+ satisfied = TRUE;
+ w->wb_awakened = TRUE;
+ } else {
+ /*
+ * Thread can only be woken up
+ * if all waits are satisfied.
+ * If the thread is waiting on multiple
+ * objects, they should all be linked
+ * through the wb_next pointers in the
+ * wait blocks.
+ */
+ satisfied = TRUE;
+ next = w->wb_next;
+ while (next != w) {
+ if (ntoskrnl_is_signalled(obj, td) == FALSE) {
+ satisfied = FALSE;
+ break;
+ }
+ next = next->wb_next;
+ }
+ ntoskrnl_satisfy_multiple_waits(w);
+ }
+
+ if (satisfied == TRUE)
+ cv_broadcastpri(&we->we_cv, w->wb_oldpri -
+ (increment * 4));
e = e->nle_flink;
}
@@ -1206,7 +1594,7 @@ ntoskrnl_time(tval)
*
* - For mutexes, we try to acquire the mutex and if we can't, we wait
* on the mutex until it's available and then grab it. When a mutex is
- * released, it enters the signaled state, which wakes up one of the
+ * released, it enters the signalled state, which wakes up one of the
* threads waiting to acquire it. Mutexes are always synchronization
* events.
*
@@ -1228,49 +1616,54 @@ KeWaitForSingleObject(obj, reason, mode, alertable, duetime)
uint8_t alertable;
int64_t *duetime;
{
- struct thread *td = curthread;
- kmutant *km;
wait_block w;
+ struct thread *td = curthread;
struct timeval tv;
int error = 0;
uint64_t curtime;
+ wb_ext we;
if (obj == NULL)
return(STATUS_INVALID_PARAMETER);
mtx_lock(&ntoskrnl_dispatchlock);
+ cv_init(&we.we_cv, "KeWFS");
+ we.we_td = td;
+
/*
- * See if the object is a mutex. If so, and we already own
- * it, then just increment the acquisition count and return.
- *
- * For any other kind of object, see if it's already in the
- * signalled state, and if it is, just return. If the object
- * is marked as a synchronization event, reset the state to
- * unsignalled.
+ * Check to see if this object is already signalled,
+ * and just return without waiting if it is.
*/
-
- if (obj->dh_size == OTYPE_MUTEX) {
- km = (kmutant *)obj;
- if (km->km_ownerthread == NULL ||
- km->km_ownerthread == curthread->td_proc) {
- obj->dh_sigstate = FALSE;
- km->km_acquirecnt++;
- km->km_ownerthread = curthread->td_proc;
+ if (ntoskrnl_is_signalled(obj, td) == TRUE) {
+ /* Sanity check the signal state value. */
+ if (obj->dh_sigstate != INT32_MIN) {
+ ntoskrnl_satisfy_wait(obj, curthread);
mtx_unlock(&ntoskrnl_dispatchlock);
return (STATUS_SUCCESS);
+ } else {
+ /*
+ * There's a limit to how many times we can
+ * recursively acquire a mutant. If we hit
+ * the limit, something is very wrong.
+ */
+ if (obj->dh_type == DISP_TYPE_MUTANT) {
+ mtx_unlock(&ntoskrnl_dispatchlock);
+ panic("mutant limit exceeded");
+ }
}
- } else if (obj->dh_sigstate == TRUE) {
- if (obj->dh_type == EVENT_TYPE_SYNC)
- obj->dh_sigstate = FALSE;
- mtx_unlock(&ntoskrnl_dispatchlock);
- return (STATUS_SUCCESS);
}
+ bzero((char *)&w, sizeof(wait_block));
w.wb_object = obj;
- w.wb_kthread = td;
+ w.wb_ext = &we;
+ w.wb_waittype = WAITTYPE_ANY;
+ w.wb_next = &w;
+ w.wb_waitkey = 0;
+ w.wb_awakened = FALSE;
+ w.wb_oldpri = td->td_priority;
- INSERT_LIST_TAIL((&obj->dh_waitlisthead), (&w.wb_waitlist));
+ InsertTailList((&obj->dh_waitlisthead), (&w.wb_waitlist));
/*
* The timeout value is specified in 100 nanosecond units
@@ -1298,41 +1691,30 @@ KeWaitForSingleObject(obj, reason, mode, alertable, duetime)
}
}
- error = ndis_thsuspend(td->td_proc, &ntoskrnl_dispatchlock,
- duetime == NULL ? 0 : tvtohz(&tv));
+ if (duetime == NULL)
+ cv_wait(&we.we_cv, &ntoskrnl_dispatchlock);
+ else
+ error = cv_timedwait(&we.we_cv,
+ &ntoskrnl_dispatchlock, tvtohz(&tv));
+
+ RemoveEntryList(&w.wb_waitlist);
+
+ cv_destroy(&we.we_cv);
/* We timed out. Leave the object alone and return status. */
if (error == EWOULDBLOCK) {
- REMOVE_LIST_ENTRY((&w.wb_waitlist));
- INIT_LIST_HEAD((&w.wb_waitlist));
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_TIMEOUT);
}
- /*
- * Mutexes are always synchronization objects, which means
- * if several threads are waiting to acquire it, only one will
- * be woken up. If that one is us, and the mutex is up for grabs,
- * grab it.
- */
-
- if (obj->dh_size == OTYPE_MUTEX) {
- km = (kmutant *)obj;
- if (km->km_ownerthread == NULL) {
- km->km_ownerthread = curthread->td_proc;
- km->km_acquirecnt++;
- }
- }
-
- if (obj->dh_type == EVENT_TYPE_SYNC)
- obj->dh_sigstate = FALSE;
- REMOVE_LIST_ENTRY((&w.wb_waitlist));
- INIT_LIST_HEAD((&w.wb_waitlist));
-
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_SUCCESS);
+/*
+ return(KeWaitForMultipleObjects(1, &obj, WAITTYPE_ALL, reason,
+ mode, alertable, duetime, &w));
+*/
}
static uint32_t
@@ -1348,13 +1730,15 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode,
wait_block *wb_array;
{
struct thread *td = curthread;
- kmutant *km;
- wait_block _wb_array[THREAD_WAIT_OBJECTS];
- wait_block *w;
+ wait_block *whead, *w;
+ wait_block _wb_array[MAX_WAIT_OBJECTS];
+ nt_dispatch_header *cur;
struct timeval tv;
- int i, wcnt = 0, widx = 0, error = 0;
+ int i, wcnt = 0, error = 0;
uint64_t curtime;
struct timespec t1, t2;
+ uint32_t status = STATUS_SUCCESS;
+ wb_ext we;
if (cnt > MAX_WAIT_OBJECTS)
return(STATUS_INVALID_PARAMETER);
@@ -1363,51 +1747,88 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode,
mtx_lock(&ntoskrnl_dispatchlock);
+ cv_init(&we.we_cv, "KeWFM");
+ we.we_td = td;
+
if (wb_array == NULL)
- w = &_wb_array[0];
+ whead = _wb_array;
else
- w = wb_array;
+ whead = wb_array;
+
+ bzero((char *)whead, sizeof(wait_block) * cnt);
/* First pass: see if we can satisfy any waits immediately. */
+ wcnt = 0;
+ w = whead;
+
for (i = 0; i < cnt; i++) {
- if (obj[i]->dh_size == OTYPE_MUTEX) {
- km = (kmutant *)obj[i];
- if (km->km_ownerthread == NULL ||
- km->km_ownerthread == curthread->td_proc) {
- obj[i]->dh_sigstate = FALSE;
- km->km_acquirecnt++;
- km->km_ownerthread = curthread->td_proc;
- if (wtype == WAITTYPE_ANY) {
- mtx_unlock(&ntoskrnl_dispatchlock);
- return (STATUS_WAIT_0 + i);
- }
+ InsertTailList((&obj[i]->dh_waitlisthead),
+ (&w->wb_waitlist));
+ w->wb_ext = &we;
+ w->wb_object = obj[i];
+ w->wb_waittype = wtype;
+ w->wb_waitkey = i;
+ w->wb_awakened = FALSE;
+ w->wb_oldpri = td->td_priority;
+ w->wb_next = w + 1;
+ w++;
+ wcnt++;
+ if (ntoskrnl_is_signalled(obj[i], td)) {
+ /*
+ * There's a limit to how many times
+ * we can recursively acquire a mutant.
+ * If we hit the limit, something
+ * is very wrong.
+ */
+ if (obj[i]->dh_sigstate == INT32_MIN &&
+ obj[i]->dh_type == DISP_TYPE_MUTANT) {
+ mtx_unlock(&ntoskrnl_dispatchlock);
+ panic("mutant limit exceeded");
}
- } else if (obj[i]->dh_sigstate == TRUE) {
- if (obj[i]->dh_type == EVENT_TYPE_SYNC)
- obj[i]->dh_sigstate = FALSE;
+
+ /*
+ * If this is a WAITTYPE_ANY wait, then
+ * satisfy the waited object and exit
+ * right now.
+ */
+
if (wtype == WAITTYPE_ANY) {
- mtx_unlock(&ntoskrnl_dispatchlock);
- return (STATUS_WAIT_0 + i);
+ ntoskrnl_satisfy_wait(obj[i], td);
+ status = STATUS_WAIT_0 + i;
+ goto wait_done;
+ } else {
+ w--;
+ wcnt--;
+ w->wb_object = NULL;
+ RemoveEntryList(&w->wb_waitlist);
}
}
}
/*
- * Second pass: set up wait for anything we can't
- * satisfy immediately.
+ * If this is a WAITTYPE_ALL wait and all objects are
+ * already signalled, satisfy the waits and exit now.
*/
- for (i = 0; i < cnt; i++) {
- if (obj[i]->dh_sigstate == TRUE)
- continue;
- INSERT_LIST_TAIL((&obj[i]->dh_waitlisthead),
- (&w[i].wb_waitlist));
- w[i].wb_kthread = td;
- w[i].wb_object = obj[i];
- wcnt++;
+ if (wtype == WAITTYPE_ALL && wcnt == 0) {
+ for (i = 0; i < cnt; i++)
+ ntoskrnl_satisfy_wait(obj[i], td);
+ status = STATUS_SUCCESS;
+ goto wait_done;
}
+ /*
+ * Create a circular waitblock list. The waitcount
+ * must always be non-zero when we get here.
+ */
+
+ (w - 1)->wb_next = whead;
+
+ /* Wait on any objects that aren't yet signalled. */
+
+ /* Calculate timeout, if any. */
+
if (duetime != NULL) {
if (*duetime < 0) {
tv.tv_sec = - (*duetime) / 10000000;
@@ -1428,32 +1849,62 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode,
while (wcnt) {
nanotime(&t1);
- error = ndis_thsuspend(td->td_proc, &ntoskrnl_dispatchlock,
- duetime == NULL ? 0 : tvtohz(&tv));
+ if (duetime == NULL)
+ cv_wait(&we.we_cv, &ntoskrnl_dispatchlock);
+ else
+ error = cv_timedwait(&we.we_cv,
+ &ntoskrnl_dispatchlock, tvtohz(&tv));
+
+ /* Wait with timeout expired. */
+
+ if (error) {
+ status = STATUS_TIMEOUT;
+ goto wait_done;
+ }
nanotime(&t2);
- for (i = 0; i < cnt; i++) {
- if (obj[i]->dh_size == OTYPE_MUTEX) {
- km = (kmutant *)obj;
- if (km->km_ownerthread == NULL) {
- km->km_ownerthread =
- curthread->td_proc;
- km->km_acquirecnt++;
+ /* See what's been signalled. */
+
+ w = whead;
+ do {
+ cur = w->wb_object;
+ if (ntoskrnl_is_signalled(cur, td) == TRUE ||
+ w->wb_awakened == TRUE) {
+ /* Sanity check the signal state value. */
+ if (cur->dh_sigstate == INT32_MIN &&
+ cur->dh_type == DISP_TYPE_MUTANT) {
+ mtx_unlock(&ntoskrnl_dispatchlock);
+ panic("mutant limit exceeded");
}
- }
- if (obj[i]->dh_sigstate == TRUE) {
- widx = i;
- if (obj[i]->dh_type == EVENT_TYPE_SYNC)
- obj[i]->dh_sigstate = FALSE;
- REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
- INIT_LIST_HEAD((&w[i].wb_waitlist));
wcnt--;
+ if (wtype == WAITTYPE_ANY) {
+ status = w->wb_waitkey &
+ STATUS_WAIT_0;
+ goto wait_done;
+ }
}
+ w = w->wb_next;
+ } while (w != whead);
+
+ /*
+ * If all objects have been signalled, or if this
+ * is a WAITTYPE_ANY wait and we were woke up by
+ * someone, we can bail.
+ */
+
+ if (wcnt == 0) {
+ status = STATUS_SUCCESS;
+ goto wait_done;
}
- if (error || wtype == WAITTYPE_ANY)
- break;
+ /*
+ * If this is WAITTYPE_ALL wait, and there's still
+ * objects that haven't been signalled, deduct the
+ * time that's elapsed so far from the timeout and
+ * wait again (or continue waiting indefinitely if
+ * there's no timeout).
+ */
if (duetime != NULL) {
tv.tv_sec -= (t2.tv_sec - t1.tv_sec);
@@ -1461,26 +1912,19 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode,
}
}
- if (wcnt) {
- for (i = 0; i < cnt; i++) {
- REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
- INIT_LIST_HEAD((&w[i].wb_waitlist));
- }
- }
- if (error == EWOULDBLOCK) {
- mtx_unlock(&ntoskrnl_dispatchlock);
- return(STATUS_TIMEOUT);
- }
+wait_done:
- if (wtype == WAITTYPE_ANY && wcnt) {
- mtx_unlock(&ntoskrnl_dispatchlock);
- return(STATUS_WAIT_0 + widx);
- }
+ cv_destroy(&we.we_cv);
+ for (i = 0; i < cnt; i++) {
+ if (whead[i].wb_object != NULL)
+ RemoveEntryList(&whead[i].wb_waitlist);
+
+ }
mtx_unlock(&ntoskrnl_dispatchlock);
- return(STATUS_SUCCESS);
+ return(status);
}
static void
@@ -2047,7 +2491,7 @@ MmSizeOfMdl(vaddr, len)
* Instead, we just fill in the page array with the kernel virtual
* addresses of the buffers.
*/
-static void
+void
MmBuildMdlForNonPagedPool(m)
mdl *m;
{
@@ -2135,16 +2579,14 @@ ntoskrnl_workitem_thread(arg)
kq = arg;
- INIT_LIST_HEAD(&kq->kq_med);
+ InitializeListHead(&kq->kq_disp);
kq->kq_td = curthread;
kq->kq_exit = 0;
- kq->kq_state = NDIS_PSTATE_SLEEPING;
mtx_init(&kq->kq_lock, "NDIS thread lock", NULL, MTX_SPIN);
KeInitializeEvent(&kq->kq_proc, EVENT_TYPE_SYNC, FALSE);
KeInitializeEvent(&kq->kq_dead, EVENT_TYPE_SYNC, FALSE);
while (1) {
-
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_proc,
0, 0, TRUE, NULL);
@@ -2152,34 +2594,27 @@ ntoskrnl_workitem_thread(arg)
if (kq->kq_exit) {
mtx_unlock_spin(&kq->kq_lock);
- KeSetEvent(&kq->kq_dead, 0, FALSE);
+ KeSetEvent(&kq->kq_dead, IO_NO_INCREMENT, FALSE);
break;
}
- kq->kq_state = NDIS_PSTATE_RUNNING;
-
- l = kq->kq_med.nle_flink;
- while (l != & kq->kq_med) {
+ while (!IsListEmpty(&kq->kq_disp)) {
+ l = RemoveHeadList(&kq->kq_disp);
iw = CONTAINING_RECORD(l,
io_workitem, iw_listentry);
- REMOVE_LIST_HEAD((&kq->kq_med));
- INIT_LIST_HEAD(l);
- if (iw->iw_func == NULL) {
- l = kq->kq_med.nle_flink;
+ InitializeListHead((&iw->iw_listentry));
+ if (iw->iw_func == NULL)
continue;
- }
mtx_unlock_spin(&kq->kq_lock);
MSCALL2(iw->iw_func, iw->iw_dobj, iw->iw_ctx);
mtx_lock_spin(&kq->kq_lock);
- l = kq->kq_med.nle_flink;
}
- kq->kq_state = NDIS_PSTATE_SLEEPING;
-
mtx_unlock_spin(&kq->kq_lock);
}
mtx_destroy(&kq->kq_lock);
+
#if __FreeBSD_version < 502113
mtx_lock(&Giant);
#endif
@@ -2195,9 +2630,8 @@ ntoskrnl_destroy_workitem_threads(void)
for (i = 0; i < WORKITEM_THREADS; i++) {
kq = wq_queues + i;
-
kq->kq_exit = 1;
- KeSetEvent(&kq->kq_proc, 0, FALSE);
+ KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_dead,
0, 0, TRUE, NULL);
}
@@ -2215,7 +2649,7 @@ IoAllocateWorkItem(dobj)
if (iw == NULL)
return(NULL);
- INIT_LIST_HEAD(&iw->iw_listentry);
+ InitializeListHead(&iw->iw_listentry);
iw->iw_dobj = dobj;
mtx_lock(&ntoskrnl_dispatchlock);
@@ -2241,21 +2675,38 @@ IoQueueWorkItem(iw, iw_func, qtype, ctx)
uint32_t qtype;
void *ctx;
{
- int state;
kdpc_queue *kq;
+ list_entry *l;
+ io_workitem *cur;
iw->iw_func = iw_func;
iw->iw_ctx = ctx;
-
kq = wq_queues + iw->iw_idx;
mtx_lock_spin(&kq->kq_lock);
- INSERT_LIST_TAIL((&kq->kq_med), (&iw->iw_listentry));
- state = kq->kq_state;
+
+ /*
+ * Traverse the list and make sure this workitem hasn't
+ * already been inserted. Queuing the same workitem
+ * twice will hose the list but good.
+ */
+
+ l = kq->kq_disp.nle_flink;
+ while (l != &kq->kq_disp) {
+ cur = CONTAINING_RECORD(l, io_workitem, iw_listentry);
+ if (cur == iw) {
+ /* Already queued -- do nothing. */
+ mtx_unlock_spin(&kq->kq_lock);
+ return;
+ }
+ l = l->nle_flink;
+ }
+
+ InsertTailList((&kq->kq_disp), (&iw->iw_listentry));
mtx_unlock_spin(&kq->kq_lock);
- if (state == NDIS_PSTATE_SLEEPING)
- KeSetEvent(&kq->kq_proc, 0, FALSE);
+
+ KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
return;
}
@@ -2278,6 +2729,31 @@ ntoskrnl_workitem(dobj, arg)
return;
}
+/*
+ * The ExQueueWorkItem() API is deprecated in Windows XP. Microsoft
+ * warns that it's unsafe and to use IoQueueWorkItem() instead. The
+ * problem with ExQueueWorkItem() is that it can't guard against
+ * the condition where a driver submits a job to the work queue and
+ * is then unloaded before the job is able to run. IoQueueWorkItem()
+ * acquires a reference to the device's device_object via the
+ * object manager and retains it until after the job has completed,
+ * which prevents the driver from being unloaded before the job
+ * runs. (We don't currently support this behavior, though hopefully
+ * that will change once the object manager API is fleshed out a bit.)
+ *
+ * Having said all that, the ExQueueWorkItem() API remains, because
+ * there are still other parts of Windows that use it, including
+ * NDIS itself: NdisScheduleWorkItem() calls ExQueueWorkItem().
+ * We fake up the ExQueueWorkItem() API on top of our implementation
+ * of IoQueueWorkItem(). Workitem thread #3 is reserved exclusively
+ * for ExQueueWorkItem() jobs, and we pass a pointer to the work
+ * queue item (provided by the caller) in to IoAllocateWorkItem()
+ * instead of the device_object. We need to save this pointer so
+ * we can apply a sanity check: as with the DPC queue and other
+ * workitem queues, we can't allow the same work queue item to
+ * be queued twice. If it's already pending, we silently return
+ */
+
void
ExQueueWorkItem(w, qtype)
work_queue_item *w;
@@ -2285,6 +2761,33 @@ ExQueueWorkItem(w, qtype)
{
io_workitem *iw;
io_workitem_func iwf;
+ kdpc_queue *kq;
+ list_entry *l;
+ io_workitem *cur;
+
+
+ /*
+ * We need to do a special sanity test to make sure
+ * the ExQueueWorkItem() API isn't used to queue
+ * the same workitem twice. Rather than checking the
+ * io_workitem pointer itself, we test the attached
+ * device object, which is really a pointer to the
+ * legacy work queue item structure.
+ */
+
+ kq = wq_queues + WORKITEM_LEGACY_THREAD;
+ mtx_lock_spin(&kq->kq_lock);
+ l = kq->kq_disp.nle_flink;
+ while (l != &kq->kq_disp) {
+ cur = CONTAINING_RECORD(l, io_workitem, iw_listentry);
+ if (cur->iw_dobj == (device_object *)w) {
+ /* Already queued -- do nothing. */
+ mtx_unlock_spin(&kq->kq_lock);
+ return;
+ }
+ l = l->nle_flink;
+ }
+ mtx_unlock_spin(&kq->kq_lock);
iw = IoAllocateWorkItem((device_object *)w);
if (iw == NULL)
@@ -2316,33 +2819,33 @@ RtlCompareMemory(s1, s2, len)
return(total);
}
-static void
+void
RtlInitAnsiString(dst, src)
- ndis_ansi_string *dst;
+ ansi_string *dst;
char *src;
{
- ndis_ansi_string *a;
+ ansi_string *a;
a = dst;
if (a == NULL)
return;
if (src == NULL) {
- a->nas_len = a->nas_maxlen = 0;
- a->nas_buf = NULL;
+ a->as_len = a->as_maxlen = 0;
+ a->as_buf = NULL;
} else {
- a->nas_buf = src;
- a->nas_len = a->nas_maxlen = strlen(src);
+ a->as_buf = src;
+ a->as_len = a->as_maxlen = strlen(src);
}
return;
}
-static void
+void
RtlInitUnicodeString(dst, src)
- ndis_unicode_string *dst;
+ unicode_string *dst;
uint16_t *src;
{
- ndis_unicode_string *u;
+ unicode_string *u;
int i;
u = dst;
@@ -2364,7 +2867,7 @@ RtlInitUnicodeString(dst, src)
ndis_status
RtlUnicodeStringToInteger(ustr, base, val)
- ndis_unicode_string *ustr;
+ unicode_string *ustr;
uint32_t base;
uint32_t *val;
{
@@ -2410,31 +2913,31 @@ RtlUnicodeStringToInteger(ustr, base, val)
astr++;
}
- ndis_unicode_to_ascii(uchr, len, &astr);
+ ntoskrnl_unicode_to_ascii(uchr, astr, len);
*val = strtoul(abuf, NULL, base);
return(NDIS_STATUS_SUCCESS);
}
-static void
+void
RtlFreeUnicodeString(ustr)
- ndis_unicode_string *ustr;
+ unicode_string *ustr;
{
if (ustr->us_buf == NULL)
return;
- free(ustr->us_buf, M_DEVBUF);
+ ExFreePool(ustr->us_buf);
ustr->us_buf = NULL;
return;
}
-static void
+void
RtlFreeAnsiString(astr)
- ndis_ansi_string *astr;
+ ansi_string *astr;
{
- if (astr->nas_buf == NULL)
+ if (astr->as_buf == NULL)
return;
- free(astr->nas_buf, M_DEVBUF);
- astr->nas_buf = NULL;
+ ExFreePool(astr->as_buf);
+ astr->as_buf = NULL;
return;
}
@@ -2512,13 +3015,12 @@ KeInitializeMutex(kmutex, level)
kmutant *kmutex;
uint32_t level;
{
- INIT_LIST_HEAD((&kmutex->km_header.dh_waitlisthead));
+ InitializeListHead((&kmutex->km_header.dh_waitlisthead));
kmutex->km_abandoned = FALSE;
kmutex->km_apcdisable = 1;
- kmutex->km_header.dh_sigstate = TRUE;
- kmutex->km_header.dh_type = EVENT_TYPE_SYNC;
- kmutex->km_header.dh_size = OTYPE_MUTEX;
- kmutex->km_acquirecnt = 0;
+ kmutex->km_header.dh_sigstate = 1;
+ kmutex->km_header.dh_type = DISP_TYPE_MUTANT;
+ kmutex->km_header.dh_size = sizeof(kmutant) / sizeof(uint32_t);
kmutex->km_ownerthread = NULL;
return;
}
@@ -2528,19 +3030,26 @@ KeReleaseMutex(kmutex, kwait)
kmutant *kmutex;
uint8_t kwait;
{
+ uint32_t prevstate;
+
mtx_lock(&ntoskrnl_dispatchlock);
- if (kmutex->km_ownerthread != curthread->td_proc) {
+ prevstate = kmutex->km_header.dh_sigstate;
+ if (kmutex->km_ownerthread != curthread) {
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_MUTANT_NOT_OWNED);
}
- kmutex->km_acquirecnt--;
- if (kmutex->km_acquirecnt == 0) {
+
+ kmutex->km_header.dh_sigstate++;
+ kmutex->km_abandoned = FALSE;
+
+ if (kmutex->km_header.dh_sigstate == 1) {
kmutex->km_ownerthread = NULL;
- ntoskrnl_wakeup(&kmutex->km_header);
+ ntoskrnl_waittest(&kmutex->km_header, IO_NO_INCREMENT);
}
+
mtx_unlock(&ntoskrnl_dispatchlock);
- return(kmutex->km_acquirecnt);
+ return(prevstate);
}
static uint32_t
@@ -2556,10 +3065,13 @@ KeInitializeEvent(kevent, type, state)
uint32_t type;
uint8_t state;
{
- INIT_LIST_HEAD((&kevent->k_header.dh_waitlisthead));
+ InitializeListHead((&kevent->k_header.dh_waitlisthead));
kevent->k_header.dh_sigstate = state;
- kevent->k_header.dh_type = type;
- kevent->k_header.dh_size = OTYPE_EVENT;
+ if (type == EVENT_TYPE_NOTIFY)
+ kevent->k_header.dh_type = DISP_TYPE_NOTIFICATION_EVENT;
+ else
+ kevent->k_header.dh_type = DISP_TYPE_SYNCHRONIZATION_EVENT;
+ kevent->k_header.dh_size = sizeof(nt_kevent) / sizeof(uint32_t);
return;
}
@@ -2584,10 +3096,49 @@ KeSetEvent(kevent, increment, kwait)
uint8_t kwait;
{
uint32_t prevstate;
+ wait_block *w;
+ nt_dispatch_header *dh;
+ struct thread *td;
+ wb_ext *we;
mtx_lock(&ntoskrnl_dispatchlock);
prevstate = kevent->k_header.dh_sigstate;
- ntoskrnl_wakeup(&kevent->k_header);
+ dh = &kevent->k_header;
+
+ if (IsListEmpty(&dh->dh_waitlisthead))
+ /*
+ * If there's nobody in the waitlist, just set
+ * the state to signalled.
+ */
+ dh->dh_sigstate = 1;
+ else {
+ /*
+ * Get the first waiter. If this is a synchronization
+ * event, just wake up that one thread (don't bother
+ * setting the state to signalled since we're supposed
+ * to automatically clear synchronization events anyway).
+ *
+ * If it's a notification event, or the the first
+ * waiter is doing a WAITTYPE_ALL wait, go through
+ * the full wait satisfaction process.
+ */
+ w = CONTAINING_RECORD(dh->dh_waitlisthead.nle_flink,
+ wait_block, wb_waitlist);
+ we = w->wb_ext;
+ td = we->we_td;
+ if (kevent->k_header.dh_type == DISP_TYPE_NOTIFICATION_EVENT ||
+ w->wb_waittype == WAITTYPE_ALL) {
+ if (prevstate == 0) {
+ dh->dh_sigstate = 1;
+ ntoskrnl_waittest(dh, increment);
+ }
+ } else {
+ w->wb_awakened |= TRUE;
+ cv_broadcastpri(&we->we_cv, w->wb_oldpri -
+ (increment * 4));
+ }
+ }
+
mtx_unlock(&ntoskrnl_dispatchlock);
return(prevstate);
@@ -2608,6 +3159,40 @@ KeReadStateEvent(kevent)
return(kevent->k_header.dh_sigstate);
}
+/*
+ * The object manager in Windows is responsible for managing
+ * references and access to various types of objects, including
+ * device_objects, events, threads, timers and so on. However,
+ * there's a difference in the way objects are handled in user
+ * mode versus kernel mode.
+ *
+ * In user mode (i.e. Win32 applications), all objects are
+ * managed by the object manager. For example, when you create
+ * a timer or event object, you actually end up with an
+ * object_header (for the object manager's bookkeeping
+ * purposes) and an object body (which contains the actual object
+ * structure, e.g. ktimer, kevent, etc...). This allows Windows
+ * to manage resource quotas and to enforce access restrictions
+ * on basically every kind of system object handled by the kernel.
+ *
+ * However, in kernel mode, you only end up using the object
+ * manager some of the time. For example, in a driver, you create
+ * a timer object by simply allocating the memory for a ktimer
+ * structure and initializing it with KeInitializeTimer(). Hence,
+ * the timer has no object_header and no reference counting or
+ * security/resource checks are done on it. The assumption in
+ * this case is that if you're running in kernel mode, you know
+ * what you're doing, and you're already at an elevated privilege
+ * anyway.
+ *
+ * There are some exceptions to this. The two most important ones
+ * for our purposes are device_objects and threads. We need to use
+ * the object manager to do reference counting on device_objects,
+ * and for threads, you can only get a pointer to a thread's
+ * dispatch header by using ObReferenceObjectByHandle() on the
+ * handle returned by PsCreateSystemThread().
+ */
+
static ndis_status
ObReferenceObjectByHandle(handle, reqaccess, otype,
accessmode, object, handleinfo)
@@ -2624,9 +3209,12 @@ ObReferenceObjectByHandle(handle, reqaccess, otype,
if (nr == NULL)
return(NDIS_STATUS_FAILURE);
- INIT_LIST_HEAD((&nr->no_dh.dh_waitlisthead));
+ InitializeListHead((&nr->no_dh.dh_waitlisthead));
nr->no_obj = handle;
- nr->no_dh.dh_size = OTYPE_THREAD;
+ nr->no_dh.dh_type = DISP_TYPE_THREAD;
+ nr->no_dh.dh_sigstate = 0;
+ nr->no_dh.dh_size = (uint8_t)(sizeof(struct thread) /
+ sizeof(uint32_t));
TAILQ_INSERT_TAIL(&ntoskrnl_reflist, nr, link);
*object = nr;
@@ -2728,7 +3316,8 @@ PsTerminateSystemThread(status)
TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) {
if (nr->no_obj != curthread->td_proc)
continue;
- ntoskrnl_wakeup(&nr->no_dh);
+ nr->no_dh.dh_sigstate = 1;
+ ntoskrnl_waittest(&nr->no_dh, IO_NO_INCREMENT);
break;
}
mtx_unlock(&ntoskrnl_dispatchlock);
@@ -2773,14 +3362,21 @@ ntoskrnl_timercall(arg)
ktimer *timer;
struct timeval tv;
- mtx_unlock(&Giant);
-
mtx_lock(&ntoskrnl_dispatchlock);
timer = arg;
+ callout_init(timer->k_callout, CALLOUT_MPSAFE);
+
+ /* Mark the timer as no longer being on the timer queue. */
+
timer->k_header.dh_inserted = FALSE;
+ /* Now signal the object and satisfy any waits on it. */
+
+ timer->k_header.dh_sigstate = 1;
+ ntoskrnl_waittest(&timer->k_header, IO_NO_INCREMENT);
+
/*
* If this is a periodic timer, re-arm it
* so it will fire again. We do this before
@@ -2794,18 +3390,19 @@ ntoskrnl_timercall(arg)
tv.tv_sec = 0;
tv.tv_usec = timer->k_period * 1000;
timer->k_header.dh_inserted = TRUE;
- timer->k_handle = timeout(ntoskrnl_timercall,
- timer, tvtohz(&tv));
+ timer->k_callout = &ntoskrnl_callout[ntoskrnl_callidx];
+ CALLOUT_INC(ntoskrnl_callidx);
+ callout_reset(timer->k_callout, tvtohz(&tv),
+ ntoskrnl_timercall, timer);
}
+ /* If there's a DPC associated with the timer, queue it up. */
+
if (timer->k_dpc != NULL)
KeInsertQueueDpc(timer->k_dpc, NULL, NULL);
- ntoskrnl_wakeup(&timer->k_header);
mtx_unlock(&ntoskrnl_dispatchlock);
- mtx_lock(&Giant);
-
return;
}
@@ -2830,12 +3427,14 @@ KeInitializeTimerEx(timer, type)
return;
bzero((char *)timer, sizeof(ktimer));
- INIT_LIST_HEAD((&timer->k_header.dh_waitlisthead));
+ InitializeListHead((&timer->k_header.dh_waitlisthead));
timer->k_header.dh_sigstate = FALSE;
timer->k_header.dh_inserted = FALSE;
- timer->k_header.dh_type = type;
- timer->k_header.dh_size = OTYPE_TIMER;
- callout_handle_init(&timer->k_handle);
+ if (type == EVENT_TYPE_NOTIFY)
+ timer->k_header.dh_type = DISP_TYPE_NOTIFICATION_TIMER;
+ else
+ timer->k_header.dh_type = DISP_TYPE_SYNCHRONIZATION_TIMER;
+ timer->k_header.dh_size = sizeof(ktimer) / sizeof(uint32_t);
return;
}
@@ -2868,18 +3467,27 @@ ntoskrnl_dpc_thread(arg)
kq = arg;
- INIT_LIST_HEAD(&kq->kq_high);
- INIT_LIST_HEAD(&kq->kq_low);
- INIT_LIST_HEAD(&kq->kq_med);
+ InitializeListHead(&kq->kq_disp);
kq->kq_td = curthread;
kq->kq_exit = 0;
- kq->kq_state = NDIS_PSTATE_SLEEPING;
mtx_init(&kq->kq_lock, "NDIS thread lock", NULL, MTX_SPIN);
KeInitializeEvent(&kq->kq_proc, EVENT_TYPE_SYNC, FALSE);
KeInitializeEvent(&kq->kq_done, EVENT_TYPE_SYNC, FALSE);
KeInitializeEvent(&kq->kq_dead, EVENT_TYPE_SYNC, FALSE);
+ /*
+ * Elevate our priority. DPCs are used to run interrupt
+ * handlers, and they should trigger as soon as possible
+ * once scheduled by an ISR.
+ */
+
+ mtx_lock_spin(&sched_lock);
sched_pin();
+ sched_prio(curthread, PRI_MIN_KERN);
+#if __FreeBSD_version < 600000
+ curthread->td_base_pri = PRI_MIN_KERN;
+#endif
+ mtx_unlock_spin(&sched_lock);
while (1) {
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_proc,
@@ -2889,59 +3497,23 @@ ntoskrnl_dpc_thread(arg)
if (kq->kq_exit) {
mtx_unlock_spin(&kq->kq_lock);
- KeSetEvent(&kq->kq_dead, 0, FALSE);
+ KeSetEvent(&kq->kq_dead, IO_NO_INCREMENT, FALSE);
break;
}
- kq->kq_state = NDIS_PSTATE_RUNNING;
-
- /* Process high importance list first. */
-
- l = kq->kq_high.nle_flink;
- while (l != &kq->kq_high) {
- d = CONTAINING_RECORD(l, kdpc, k_dpclistentry);
- REMOVE_LIST_ENTRY((&d->k_dpclistentry));
- INIT_LIST_HEAD((&d->k_dpclistentry));
- d->k_lock = NULL;
- mtx_unlock_spin(&kq->kq_lock);
- ntoskrnl_run_dpc(d);
- mtx_lock_spin(&kq->kq_lock);
- l = kq->kq_high.nle_flink;
- }
-
- /* Now the medium importance list. */
-
- l = kq->kq_med.nle_flink;
- while (l != &kq->kq_med) {
- d = CONTAINING_RECORD(l, kdpc, k_dpclistentry);
- REMOVE_LIST_ENTRY((&d->k_dpclistentry));
- INIT_LIST_HEAD((&d->k_dpclistentry));
- d->k_lock = NULL;
- mtx_unlock_spin(&kq->kq_lock);
- ntoskrnl_run_dpc(d);
- mtx_lock_spin(&kq->kq_lock);
- l = kq->kq_med.nle_flink;
- }
-
- /* And finally the low importance list. */
-
- l = kq->kq_low.nle_flink;
- while (l != &kq->kq_low) {
+ while (!IsListEmpty(&kq->kq_disp)) {
+ l = RemoveHeadList((&kq->kq_disp));
d = CONTAINING_RECORD(l, kdpc, k_dpclistentry);
- REMOVE_LIST_ENTRY((&d->k_dpclistentry));
- INIT_LIST_HEAD((&d->k_dpclistentry));
+ InitializeListHead((&d->k_dpclistentry));
d->k_lock = NULL;
mtx_unlock_spin(&kq->kq_lock);
ntoskrnl_run_dpc(d);
mtx_lock_spin(&kq->kq_lock);
- l = kq->kq_low.nle_flink;
}
- kq->kq_state = NDIS_PSTATE_SLEEPING;
-
mtx_unlock_spin(&kq->kq_lock);
- KeSetEvent(&kq->kq_done, 0, FALSE);
+ KeSetEvent(&kq->kq_done, IO_NO_INCREMENT, FALSE);
}
@@ -2995,7 +3567,6 @@ ntoskrnl_destroy_dpc_threads(void)
KeInitializeDpc(&dpc, NULL, NULL);
KeSetTargetProcessorDpc(&dpc, i);
KeInsertQueueDpc(&dpc, NULL, NULL);
-
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_dead,
0, 0, TRUE, NULL);
}
@@ -3019,7 +3590,11 @@ ntoskrnl_insert_dpc(head, dpc)
l = l->nle_flink;
}
- INSERT_LIST_TAIL((head), (&dpc->k_dpclistentry));
+ if (dpc->k_importance == KDPC_IMPORTANCE_HIGH)
+ InsertHeadList((head), (&dpc->k_dpclistentry));
+ else
+ InsertTailList((head), (&dpc->k_dpclistentry));
+
return (TRUE);
}
@@ -3037,13 +3612,12 @@ KeInitializeDpc(dpc, dpcfunc, dpcctx)
dpc->k_deferredctx = dpcctx;
dpc->k_num = KDPC_CPU_DEFAULT;
dpc->k_importance = KDPC_IMPORTANCE_MEDIUM;
- dpc->k_num = KeGetCurrentProcessorNumber();
/*
* In case someone tries to dequeue a DPC that
* hasn't been queued yet.
*/
- dpc->k_lock = NULL /*&ntoskrnl_dispatchlock*/;
- INIT_LIST_HEAD((&dpc->k_dpclistentry));
+ dpc->k_lock = NULL;
+ InitializeListHead((&dpc->k_dpclistentry));
return;
}
@@ -3056,7 +3630,6 @@ KeInsertQueueDpc(dpc, sysarg1, sysarg2)
{
kdpc_queue *kq;
uint8_t r;
- int state;
if (dpc == NULL)
return(FALSE);
@@ -3081,21 +3654,15 @@ KeInsertQueueDpc(dpc, sysarg1, sysarg2)
*/
mtx_lock_spin(&kq->kq_lock);
- if (dpc->k_importance == KDPC_IMPORTANCE_HIGH)
- r = ntoskrnl_insert_dpc(&kq->kq_high, dpc);
- else if (dpc->k_importance == KDPC_IMPORTANCE_LOW)
- r = ntoskrnl_insert_dpc(&kq->kq_low, dpc);
- else
- r = ntoskrnl_insert_dpc(&kq->kq_med, dpc);
+ r = ntoskrnl_insert_dpc(&kq->kq_disp, dpc);
if (r == TRUE)
dpc->k_lock = &kq->kq_lock;
- state = kq->kq_state;
mtx_unlock_spin(&kq->kq_lock);
+
if (r == FALSE)
return(r);
- if (state == NDIS_PSTATE_SLEEPING)
- KeSetEvent(&kq->kq_proc, 0, FALSE);
+ KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
return(r);
}
@@ -3104,21 +3671,26 @@ uint8_t
KeRemoveQueueDpc(dpc)
kdpc *dpc;
{
+ struct mtx *lock;
+
if (dpc == NULL)
return(FALSE);
- if (dpc->k_lock == NULL)
+ lock = dpc->k_lock;
+
+ if (lock == NULL)
return(FALSE);
- mtx_lock_spin((struct mtx*)(dpc->k_lock));
+ mtx_lock_spin(lock);
+ dpc->k_lock = NULL;
if (dpc->k_dpclistentry.nle_flink == &dpc->k_dpclistentry) {
- mtx_unlock_spin((struct mtx*)(dpc->k_lock));
+ mtx_unlock_spin(lock);
return(FALSE);
}
- REMOVE_LIST_ENTRY((&dpc->k_dpclistentry));
- INIT_LIST_HEAD((&dpc->k_dpclistentry));
- mtx_unlock_spin((struct mtx*)(dpc->k_lock));
+ RemoveEntryList((&dpc->k_dpclistentry));
+ InitializeListHead((&dpc->k_dpclistentry));
+ mtx_unlock_spin(lock);
return(TRUE);
}
@@ -3162,7 +3734,7 @@ KeFlushQueuedDpcs(void)
for (i = 0; i < mp_ncpus; i++) {
kq = kq_queues + i;
- KeSetEvent(&kq->kq_proc, 0, FALSE);
+ KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_done,
0, 0, TRUE, NULL);
}
@@ -3193,7 +3765,7 @@ KeSetTimerEx(timer, duetime, period, dpc)
mtx_lock(&ntoskrnl_dispatchlock);
if (timer->k_header.dh_inserted == TRUE) {
- untimeout(ntoskrnl_timercall, timer, timer->k_handle);
+ callout_stop(timer->k_callout);
timer->k_header.dh_inserted = FALSE;
pending = TRUE;
} else
@@ -3220,7 +3792,10 @@ KeSetTimerEx(timer, duetime, period, dpc)
}
timer->k_header.dh_inserted = TRUE;
- timer->k_handle = timeout(ntoskrnl_timercall, timer, tvtohz(&tv));
+ timer->k_callout = &ntoskrnl_callout[ntoskrnl_callidx];
+ CALLOUT_INC(ntoskrnl_callidx);
+ callout_reset(timer->k_callout, tvtohz(&tv),
+ ntoskrnl_timercall, timer);
mtx_unlock(&ntoskrnl_dispatchlock);
@@ -3236,6 +3811,12 @@ KeSetTimer(timer, duetime, dpc)
return (KeSetTimerEx(timer, duetime, 0, dpc));
}
+/*
+ * The Windows DDK documentation seems to say that cancelling
+ * a timer that has a DPC will result in the DPC also being
+ * cancelled, but this isn't really the case.
+ */
+
uint8_t
KeCancelTimer(timer)
ktimer *timer;
@@ -3247,14 +3828,12 @@ KeCancelTimer(timer)
mtx_lock(&ntoskrnl_dispatchlock);
+ pending = timer->k_header.dh_inserted;
+
if (timer->k_header.dh_inserted == TRUE) {
- untimeout(ntoskrnl_timercall, timer, timer->k_handle);
- if (timer->k_dpc != NULL)
- KeRemoveQueueDpc(timer->k_dpc);
timer->k_header.dh_inserted = FALSE;
- pending = TRUE;
- } else
- pending = KeRemoveQueueDpc(timer->k_dpc);
+ callout_stop(timer->k_callout);
+ }
mtx_unlock(&ntoskrnl_dispatchlock);
@@ -3299,6 +3878,8 @@ image_patch_table ntoskrnl_functbl[] = {
IMPORT_CFUNC(strncpy, 0),
IMPORT_CFUNC(strcpy, 0),
IMPORT_CFUNC(strlen, 0),
+ IMPORT_CFUNC_MAP(toupper, ntoskrnl_toupper, 0),
+ IMPORT_CFUNC_MAP(tolower, ntoskrnl_tolower, 0),
IMPORT_CFUNC_MAP(strstr, ntoskrnl_strstr, 0),
IMPORT_CFUNC_MAP(strchr, index, 0),
IMPORT_CFUNC(memcpy, 0),
@@ -3311,6 +3892,8 @@ image_patch_table ntoskrnl_functbl[] = {
IMPORT_SFUNC(IoAcquireCancelSpinLock, 1),
IMPORT_SFUNC(IoReleaseCancelSpinLock, 1),
IMPORT_SFUNC(IoCancelIrp, 1),
+ IMPORT_SFUNC(IoConnectInterrupt, 11),
+ IMPORT_SFUNC(IoDisconnectInterrupt, 1),
IMPORT_SFUNC(IoCreateDevice, 7),
IMPORT_SFUNC(IoDeleteDevice, 1),
IMPORT_SFUNC(IoGetAttachedDevice, 1),
@@ -3324,6 +3907,7 @@ image_patch_table ntoskrnl_functbl[] = {
IMPORT_SFUNC(IoMakeAssociatedIrp, 2),
IMPORT_SFUNC(IoFreeIrp, 1),
IMPORT_SFUNC(IoInitializeIrp, 3),
+ IMPORT_SFUNC(KeSynchronizeExecution, 3),
IMPORT_SFUNC(KeWaitForSingleObject, 5),
IMPORT_SFUNC(KeWaitForMultipleObjects, 8),
IMPORT_SFUNC(_allmul, 4),
diff --git a/sys/compat/ndis/winx32_wrap.S b/sys/compat/ndis/winx32_wrap.S
index 4fadfb5..f5d24ba 100644
--- a/sys/compat/ndis/winx32_wrap.S
+++ b/sys/compat/ndis/winx32_wrap.S
@@ -82,6 +82,13 @@
* we only know the absolute addresses of the thunk and unthunk
* routines. So we need to make sure the templates have enough
* room in them for the full address.
+ *
+ * Also note that when we call the a thunk/unthunk routine after
+ * invoking a wrapped function, we have to make sure to preserve
+ * the value returned from that function. Most functions return
+ * a 32-bit value in %eax, however some routines return 64-bit
+ * values, which span both %eax and %edx. Consequently, we have
+ * to preserve both registers.
*/
/*
@@ -114,13 +121,16 @@ ENTRY(x86_stdcall_wrap)
x86_stdcall_wrap_call:
movl $0,%eax
call *%eax # jump to routine
- mov %eax,%esi # preserve return val
+ push %eax # preserve return val
+ push %edx
movl $ctxsw_utow, %eax
call *%eax # thunk
+ pop %edx
+ pop %eax # restore return val
+
add $64,%esp # clean the stack
- mov %esi,%eax # restore return val
pop %edi
pop %esi
x86_stdcall_wrap_arg:
@@ -151,12 +161,14 @@ ENTRY(x86_stdcall_call)
call ctxsw_utow # thunk
call *12(%edi) # branch to stdcall routine
- mov %eax,%esi # preserve return val
+ push %eax # preserve return val
+ push %edx
call ctxsw_wtou # unthunk
+ pop %edx
+ pop %eax # restore return val
mov %edi,%esp # restore stack
- mov %esi,%eax # restore return val
pop %edi # restore %edi
pop %esi # and %esi
ret
@@ -188,10 +200,12 @@ x86_fastcall_wrap_call:
mov $0,%eax
call *%eax # branch to fastcall routine
push %eax # preserve return val
+ push %edx
movl $ctxsw_utow, %eax
call *%eax # thunk
+ pop %edx
pop %eax # restore return val
add $12,%esp # clean the stack
x86_fastcall_wrap_arg:
@@ -215,9 +229,11 @@ ENTRY(x86_fastcall_call)
mov 16(%esp),%edx
call *8(%esp) # branch to fastcall routine
push %eax # preserve return val
+ push %edx
call ctxsw_wtou # unthunk
+ pop %edx
pop %eax # restore return val
add $4,%esp # clean the stack
ret
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c
index 02a3dd6..3e67c52 100644
--- a/sys/dev/if_ndis/if_ndis.c
+++ b/sys/dev/if_ndis/if_ndis.c
@@ -29,7 +29,8 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * WPA support added by Arvind Srinivasan <arvind@celar.us>
+ * WPA support originally contributed by Arvind Srinivasan <arvind@celar.us>
+ * then hacked upon mercilessly by my.
*/
#include <sys/cdefs.h>
@@ -49,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#endif
+
#include <net/if.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
@@ -119,12 +121,11 @@ static funcptr ndis_ticktask_wrap;
static funcptr ndis_starttask_wrap;
static funcptr ndis_resettask_wrap;
-static void ndis_intr (void *);
static void ndis_tick (void *);
-static void ndis_ticktask (ndis_work_item *, void *);
+static void ndis_ticktask (device_object *, void *);
static void ndis_start (struct ifnet *);
-static void ndis_starttask (ndis_work_item *, void *);
-static void ndis_resettask (ndis_work_item *, void *);
+static void ndis_starttask (device_object *, void *);
+static void ndis_resettask (device_object *, void *);
static int ndis_ioctl (struct ifnet *, u_long, caddr_t);
static int ndis_wi_ioctl_get (struct ifnet *, u_long, caddr_t);
static int ndis_wi_ioctl_set (struct ifnet *, u_long, caddr_t);
@@ -140,8 +141,14 @@ static int ndis_probe_offload (struct ndis_softc *);
static int ndis_set_offload (struct ndis_softc *);
static void ndis_getstate_80211 (struct ndis_softc *);
static void ndis_setstate_80211 (struct ndis_softc *);
-static int ndis_add_key (struct ndis_softc *,
- struct ieee80211req_key *, int16_t);
+#ifdef IEEE80211_F_WPA
+static int ndis_set_cipher (struct ndis_softc *, int);
+static int ndis_set_wpa (struct ndis_softc *);
+static int ndis_add_key (struct ieee80211com *,
+ const struct ieee80211_key *, const u_int8_t []);
+static int ndis_del_key (struct ieee80211com *,
+ const struct ieee80211_key *);
+#endif
static void ndis_media_status (struct ifnet *, struct ifmediareq *);
static void ndis_setmulti (struct ndis_softc *);
@@ -243,7 +250,7 @@ ndis_setmulti(sc)
&sc->ndis_filter, &len);
if (error)
device_printf (sc->ndis_dev,
- "set filter failed: %d\n", error);
+ "set allmulti failed: %d\n", error);
return;
}
@@ -294,7 +301,7 @@ out:
error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
&sc->ndis_filter, &len);
if (error)
- device_printf (sc->ndis_dev, "set filter failed: %d\n", error);
+ device_printf (sc->ndis_dev, "set multi failed: %d\n", error);
return;
}
@@ -468,33 +475,20 @@ ndis_attach(dev)
int i;
sc = device_get_softc(dev);
+#if __FreeBSD_version < 600000
+ sc->ifp = &sc->arpcom.ac_if;
+ ifp = sc->ifp;
+#else
ifp = sc->ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
error = ENOSPC;
goto fail;
}
+#endif
ifp->if_softc = sc;
- mtx_init(&sc->ndis_mtx, "ndis softc lock",
- MTX_NETWORK_LOCK, MTX_DEF);
-
- /*
- * Hook interrupt early, since calling the driver's
- * init routine may trigger an interrupt. Note that
- * we don't need to do any explicit interrupt setup
- * for USB.
- */
-
- if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) {
- error = bus_setup_intr(dev, sc->ndis_irq,
- INTR_TYPE_NET | INTR_MPSAFE,
- ndis_intr, sc, &sc->ndis_intrhand);
-
- if (error) {
- device_printf(dev, "couldn't set up irq\n");
- goto fail;
- }
- }
+ KeInitializeSpinLock(&sc->ndis_spinlock);
+ InitializeListHead(&sc->ndis_shlist);
if (sc->ndis_iftype == PCMCIABus) {
error = ndis_alloc_amem(sc);
@@ -566,19 +560,22 @@ ndis_attach(dev)
ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len);
/*
- * Figure out if we're allowed to use multipacket sends
- * with this driver, and if so, how many.
+ * Figure out how big to make the TX buffer pool.
*/
- if (sc->ndis_chars->nmc_sendsingle_func &&
- sc->ndis_chars->nmc_sendmulti_func == NULL) {
- sc->ndis_maxpkts = 1;
- } else {
- len = sizeof(sc->ndis_maxpkts);
- ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS,
- &sc->ndis_maxpkts, &len);
+ len = sizeof(sc->ndis_maxpkts);
+ if (ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS,
+ &sc->ndis_maxpkts, &len)) {
+ device_printf (dev, "failed to get max TX packets\n");
+ error = ENXIO;
+ goto fail;
}
+ /* Enforce some sanity, just in case. */
+
+ if (sc->ndis_maxpkts == 0)
+ sc->ndis_maxpkts = 10;
+
sc->ndis_txarray = malloc(sizeof(ndis_packet *) *
sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT|M_ZERO);
@@ -645,7 +642,9 @@ ndis_attach(dev)
uint32_t arg;
int r;
+#if __FreeBSD_version >= 600000
ic->ic_ifp = ifp;
+#endif
ic->ic_phytype = IEEE80211_T_DS;
ic->ic_opmode = IEEE80211_M_STA;
ic->ic_caps = IEEE80211_C_IBSS;
@@ -656,7 +655,7 @@ ndis_attach(dev)
NULL, &len);
if (r != ENOSPC)
goto nonettypes;
- ntl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
+ ntl = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
ntl, &len);
if (r != 0) {
@@ -801,20 +800,73 @@ nonettypes:
ic->ic_channels[i].ic_flags = chanflag;
}
+ /*
+ * To test for WPA support, we need to see if we can
+ * set AUTHENTICATION_MODE to WPA and read it back
+ * successfully.
+ */
+#ifdef IEEE80211_F_WPA
+ i = sizeof(arg);
+ arg = NDIS_80211_AUTHMODE_WPA;
+ r = ndis_set_info(sc,
+ OID_802_11_AUTHENTICATION_MODE, &arg, &i);
+ if (r == 0) {
+ r = ndis_get_info(sc,
+ OID_802_11_AUTHENTICATION_MODE, &arg, &i);
+ if (r == 0 && arg == NDIS_80211_AUTHMODE_WPA)
+ ic->ic_caps |= IEEE80211_C_WPA;
+ }
+
+ /*
+ * To test for supported ciphers, we set each
+ * available encryption type in descending order.
+ * If ENC3 works, then we have WEP, TKIP and AES.
+ * If only ENC2 works, then we have WEP and TKIP.
+ * If only ENC1 works, then we have just WEP.
+ */
i = sizeof(arg);
- r = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &i);
- if (arg != NDIS_80211_WEPSTAT_NOTSUPPORTED)
+ arg = NDIS_80211_WEPSTAT_ENC3ENABLED;
+ r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
+ if (r == 0) {
+ ic->ic_caps |= IEEE80211_C_WEP|IEEE80211_C_TKIP|
+ IEEE80211_C_AES_CCM;
+ goto got_crypto;
+ }
+ arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
+ r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
+ if (r == 0) {
+ ic->ic_caps |= IEEE80211_C_WEP|IEEE80211_C_TKIP;
+ goto got_crypto;
+ }
+#endif
+ arg = NDIS_80211_WEPSTAT_ENC1ENABLED;
+ r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
+ if (r == 0)
ic->ic_caps |= IEEE80211_C_WEP;
+#ifdef IEEE80211_F_WPA
+got_crypto:
+#endif
i = sizeof(arg);
r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i);
if (r == 0)
ic->ic_caps |= IEEE80211_C_PMGT;
bcopy(eaddr, &ic->ic_myaddr, sizeof(eaddr));
+#if __FreeBSD_version < 600000
+ ieee80211_ifattach(ifp);
+ ieee80211_media_init(ifp, ieee80211_media_change,
+ ndis_media_status);
+#else
ieee80211_ifattach(ic);
ieee80211_media_init(ic, ieee80211_media_change,
ndis_media_status);
+#endif
ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+#ifdef IEEE80211_F_WPA
+ /* install key handing routines */
+ ic->ic_crypto.cs_key_set = ndis_add_key;
+ ic->ic_crypto.cs_key_delete = ndis_del_key;
+#endif
} else {
ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd,
ndis_ifmedia_sts);
@@ -833,12 +885,9 @@ nonettypes:
sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap;
/* Set up work item handlers. */
- NdisInitializeWorkItem(&sc->ndis_tickitem,
- (ndis_proc)ndis_ticktask_wrap, sc);
- NdisInitializeWorkItem(&sc->ndis_startitem,
- (ndis_proc)ndis_starttask_wrap, ifp);
- NdisInitializeWorkItem(&sc->ndis_resetitem,
- (ndis_proc)ndis_resettask_wrap, sc);
+ sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
+ sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
+ sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block);
@@ -878,16 +927,25 @@ ndis_detach(dev)
NDIS_UNLOCK(sc);
ndis_stop(sc);
if (sc->ndis_80211)
+#if __FreeBSD_version < 600000
+ ieee80211_ifdetach(ifp);
+#else
ieee80211_ifdetach(&sc->ic);
+#endif
else
ether_ifdetach(ifp);
} else
NDIS_UNLOCK(sc);
+ 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);
+
bus_generic_detach(dev);
- if (sc->ndis_intrhand)
- bus_teardown_intr(dev, sc->ndis_irq, sc->ndis_intrhand);
if (sc->ndis_irq)
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq);
if (sc->ndis_res_io)
@@ -900,8 +958,10 @@ ndis_detach(dev)
bus_release_resource(dev, SYS_RES_MEMORY,
sc->ndis_altmem_rid, sc->ndis_res_altmem);
+#if __FreeBSD_version >= 600000
if (ifp != NULL)
if_free(ifp);
+#endif
if (sc->ndis_iftype == PCMCIABus)
ndis_free_amem(sc);
@@ -939,8 +999,6 @@ ndis_detach(dev)
sysctl_ctx_free(&sc->ndis_ctx);
#endif
- mtx_destroy(&sc->ndis_mtx);
-
return(0);
}
@@ -1047,7 +1105,7 @@ ndis_rxeof_eth(adapter, ctx, addr, hdr, hdrlen, lookahead, lookaheadlen, pktlen)
KeAcquireSpinLock(&block->nmb_lock, &irql);
- INSERT_LIST_TAIL((&block->nmb_packetlist),
+ InsertTailList((&block->nmb_packetlist),
((list_entry *)&p->u.np_clrsvd.np_miniport_rsvd));
KeReleaseSpinLock(&block->nmb_lock, irql);
@@ -1099,8 +1157,8 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
l = block->nmb_packetlist.nle_flink;
- while(l != &block->nmb_packetlist) {
- REMOVE_LIST_HEAD((&block->nmb_packetlist));
+ while(!IsListEmpty(&block->nmb_packetlist)) {
+ l = RemoveHeadList((&block->nmb_packetlist));
p = CONTAINING_RECORD(l, ndis_packet,
u.np_clrsvd.np_miniport_rsvd);
@@ -1223,6 +1281,7 @@ ndis_rxeof(adapter, packets, pktcnt)
if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
ndis_return_packet(sc, p);
} else {
+#ifdef notdef
if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
m = m_dup(m0, M_DONTWAIT);
/*
@@ -1241,6 +1300,18 @@ ndis_rxeof(adapter, packets, pktcnt)
m0 = m;
} else
p->np_oob.npo_status = NDIS_STATUS_PENDING;
+#endif
+ m = m_dup(m0, M_DONTWAIT);
+ if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES)
+ p->np_refcnt++;
+ else
+ p->np_oob.npo_status = NDIS_STATUS_PENDING;
+ m_freem(m0);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ continue;
+ }
+ m0 = m;
m0->m_pkthdr.rcvif = ifp;
ifp->if_ipackets++;
@@ -1308,12 +1379,15 @@ ndis_txeof(adapter, packet, status)
ifp->if_opackets++;
else
ifp->if_oerrors++;
+
ifp->if_timer = 0;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
NDIS_UNLOCK(sc);
- NdisScheduleWorkItem(&sc->ndis_startitem);
+ IoQueueWorkItem(sc->ndis_startitem,
+ (io_workitem_func)ndis_starttask_wrap,
+ WORKQUEUE_CRITICAL, ifp);
return;
}
@@ -1330,8 +1404,32 @@ ndis_linksts(adapter, status, sbuf, slen)
block = adapter;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+ sc->ndis_sts = status;
+
+ /* Event list is all full up, drop this one. */
- block->nmb_getstat = status;
+ NDIS_LOCK(sc);
+ if (sc->ndis_evt[sc->ndis_evtpidx].ne_sts) {
+ NDIS_UNLOCK(sc);
+ return;
+ }
+
+ /* Cache the event. */
+
+ if (slen) {
+ sc->ndis_evt[sc->ndis_evtpidx].ne_buf = malloc(slen,
+ M_TEMP, M_NOWAIT);
+ if (sc->ndis_evt[sc->ndis_evtpidx].ne_buf == NULL) {
+ NDIS_UNLOCK(sc);
+ return;
+ }
+ bcopy((char *)sbuf,
+ sc->ndis_evt[sc->ndis_evtpidx].ne_buf, slen);
+ }
+ sc->ndis_evt[sc->ndis_evtpidx].ne_sts = status;
+ sc->ndis_evt[sc->ndis_evtpidx].ne_len = slen;
+ NDIS_EVTINC(sc->ndis_evtpidx);
+ NDIS_UNLOCK(sc);
return;
}
@@ -1351,51 +1449,28 @@ ndis_linksts_done(adapter)
if (!NDIS_INITIALIZED(sc))
return;
- switch (block->nmb_getstat) {
+ switch (sc->ndis_sts) {
case NDIS_STATUS_MEDIA_CONNECT:
- NdisScheduleWorkItem(&sc->ndis_tickitem);
- NdisScheduleWorkItem(&sc->ndis_startitem);
+ IoQueueWorkItem(sc->ndis_tickitem,
+ (io_workitem_func)ndis_ticktask_wrap,
+ WORKQUEUE_CRITICAL, sc);
+ IoQueueWorkItem(sc->ndis_startitem,
+ (io_workitem_func)ndis_starttask_wrap,
+ WORKQUEUE_CRITICAL, ifp);
break;
case NDIS_STATUS_MEDIA_DISCONNECT:
if (sc->ndis_link)
- NdisScheduleWorkItem(&sc->ndis_tickitem);
+ IoQueueWorkItem(sc->ndis_tickitem,
+ (io_workitem_func)ndis_ticktask_wrap,
+ WORKQUEUE_CRITICAL, sc);
break;
default:
break;
}
- return;
-}
-
-static void
-ndis_intr(arg)
- void *arg;
-{
- struct ndis_softc *sc;
- struct ifnet *ifp;
- int is_our_intr = 0;
- int call_isr = 0;
- uint8_t irql;
- ndis_miniport_interrupt *intr;
-
- sc = arg;
- ifp = sc->ifp;
- intr = sc->ndis_block->nmb_interrupt;
+ /* Notify possible listners of interface change. */
- if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL)
- return;
-
- KeAcquireSpinLock(&intr->ni_dpccountlock, &irql);
- if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
- ndis_isr(sc, &is_our_intr, &call_isr);
- else {
- ndis_disable_intr(sc);
- call_isr = 1;
- }
- KeReleaseSpinLock(&intr->ni_dpccountlock, irql);
-
- if ((is_our_intr || call_isr))
- IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
+ rt_ifmsg(ifp);
return;
}
@@ -1410,7 +1485,9 @@ ndis_tick(xsc)
sc = xsc;
- NdisScheduleWorkItem(&sc->ndis_tickitem);
+ IoQueueWorkItem(sc->ndis_tickitem,
+ (io_workitem_func)ndis_ticktask_wrap,
+ WORKQUEUE_CRITICAL, sc);
sc->ndis_stat_ch = timeout(ndis_tick, sc, hz *
sc->ndis_block->nmb_checkforhangsecs);
@@ -1420,17 +1497,17 @@ ndis_tick(xsc)
}
static void
-ndis_ticktask(w, xsc)
- ndis_work_item *w;
+ndis_ticktask(d, xsc)
+ device_object *d;
void *xsc;
{
struct ndis_softc *sc;
+ struct ieee80211com *ic;
ndis_checkforhang_handler hangfunc;
uint8_t rval;
- ndis_media_state linkstate;
- int error, len;
sc = xsc;
+ ic = &sc->ic;
hangfunc = sc->ndis_chars->nmc_checkhang_func;
@@ -1443,31 +1520,28 @@ ndis_ticktask(w, xsc)
}
}
- len = sizeof(linkstate);
- error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
- (void *)&linkstate, &len);
-
NDIS_LOCK(sc);
-
- if (sc->ndis_link == 0 && linkstate == nmc_connected) {
- device_printf(sc->ndis_dev, "link up\n");
+ if (sc->ndis_link == 0 &&
+ sc->ndis_sts == NDIS_STATUS_MEDIA_CONNECT) {
sc->ndis_link = 1;
NDIS_UNLOCK(sc);
- if (sc->ndis_80211)
+ if (sc->ndis_80211) {
ndis_getstate_80211(sc);
+ ic->ic_state = IEEE80211_S_RUN;
+ }
NDIS_LOCK(sc);
#ifdef LINK_STATE_UP
- sc->ifp->if_link_state = LINK_STATE_UP;
- rt_ifmsg(sc->ifp);
+ if_link_state_change(sc->ifp, LINK_STATE_UP);
#endif /* LINK_STATE_UP */
}
- if (sc->ndis_link == 1 && linkstate == nmc_disconnected) {
- device_printf(sc->ndis_dev, "link down\n");
+ if (sc->ndis_link == 1 &&
+ sc->ndis_sts == NDIS_STATUS_MEDIA_DISCONNECT) {
sc->ndis_link = 0;
+ if (sc->ndis_80211)
+ ic->ic_state = IEEE80211_S_ASSOC;
#ifdef LINK_STATE_DOWN
- sc->ifp->if_link_state = LINK_STATE_DOWN;
- rt_ifmsg(sc->ifp);
+ if_link_state_change(sc->ifp, LINK_STATE_DOWN);
#endif /* LINK_STATE_DOWN */
}
@@ -1504,8 +1578,8 @@ ndis_map_sclist(arg, segs, nseg, mapsize, error)
}
static void
-ndis_starttask(w, arg)
- ndis_work_item *w;
+ndis_starttask(d, arg)
+ device_object *d;
void *arg;
{
struct ifnet *ifp;
@@ -1659,10 +1733,17 @@ ndis_start(ifp)
NDIS_UNLOCK(sc);
- if (sc->ndis_maxpkts == 1)
- ndis_send_packet(sc, p);
- else
+ /*
+ * According to NDIS documentation, if a driver exports
+ * a MiniportSendPackets() routine, we prefer that over
+ * a MiniportSend() routine (which sends just a single
+ * packet).
+ */
+
+ if (sc->ndis_chars->nmc_sendmulti_func != NULL)
ndis_send_packets(sc, p0, pcnt);
+ else
+ ndis_send_packet(sc, p);
return;
}
@@ -1673,7 +1754,7 @@ ndis_init(xsc)
{
struct ndis_softc *sc = xsc;
struct ifnet *ifp = sc->ifp;
- int i, error;
+ int i, len, error;
/*
* Avoid reintializing the link unnecessarily.
@@ -1688,6 +1769,7 @@ ndis_init(xsc)
* Cancel pending I/O and free all RX/TX buffers.
*/
ndis_stop(sc);
+
if (ndis_init_nic(sc))
return;
@@ -1703,15 +1785,23 @@ ndis_init(xsc)
if (ifp->if_flags & IFF_PROMISC)
sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS;
- i = sizeof(sc->ndis_filter);
+ len = sizeof(sc->ndis_filter);
error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
- &sc->ndis_filter, &i);
+ &sc->ndis_filter, &len);
if (error)
device_printf (sc->ndis_dev, "set filter failed: %d\n", error);
/*
+ * Set lookahead.
+ */
+
+ i = ifp->if_mtu;
+ len = sizeof(i);
+ ndis_set_info(sc, OID_GEN_CURRENT_LOOKAHEAD, &i, &len);
+
+ /*
* Program the multicast filter, if necessary.
*/
ndis_setmulti(sc);
@@ -1731,6 +1821,10 @@ ndis_init(xsc)
sc->ndis_txpending = sc->ndis_maxpkts;
sc->ndis_link = 0;
+#ifdef LINK_STATE_UNKNOWN
+ if_link_state_change(sc->ifp, LINK_STATE_UNKNOWN);
+#endif /* LINK_STATE_UNKNOWN */
+
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
@@ -1818,12 +1912,148 @@ ndis_ifmedia_sts(ifp, ifmr)
return;
}
+#ifdef IEEE80211_F_WPA
+static int
+ndis_set_cipher(sc, cipher)
+ struct ndis_softc *sc;
+ int cipher;
+{
+ struct ieee80211com *ic;
+ int rval = 0, len;
+ uint32_t arg, save;
+
+ ic = &sc->ic;
+
+ len = sizeof(arg);
+
+ if (cipher == WPA_CSE_WEP40 || WPA_CSE_WEP104) {
+ if (!(ic->ic_caps & IEEE80211_C_WEP))
+ return(ENOTSUP);
+ arg = NDIS_80211_WEPSTAT_ENC1ENABLED;
+ }
+
+ if (cipher == WPA_CSE_TKIP) {
+ if (!(ic->ic_caps & IEEE80211_C_TKIP))
+ return(ENOTSUP);
+ arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
+ }
+
+ if (cipher == WPA_CSE_CCMP) {
+ if (!(ic->ic_caps & IEEE80211_C_AES_CCM))
+ return(ENOTSUP);
+ arg = NDIS_80211_WEPSTAT_ENC3ENABLED;
+ }
+
+ save = arg;
+ rval = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
+
+ if (rval)
+ return(rval);
+
+ /* Check that the cipher was set correctly. */
+
+ len = sizeof(save);
+ rval = ndis_get_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
+
+ if (rval != 0 || arg != save)
+ return(ENODEV);
+
+ return(0);
+}
+
+/*
+ * WPA is hairy to set up. Do the work in a separate routine
+ * so we don't clutter the setstate function too much.
+ * Important yet undocumented fact: first we have to set the
+ * authentication mode, _then_ we enable the ciphers. If one
+ * of the WPA authentication modes isn't enabled, the driver
+ * might not permit the TKIP or AES ciphers to be selected.
+ */
+
+static int
+ndis_set_wpa(sc)
+ struct ndis_softc *sc;
+{
+ struct ieee80211com *ic;
+ struct ieee80211_ie_wpa *w;
+ struct ndis_ie *n;
+ char *pos;
+ uint32_t arg;
+ int i;
+
+ ic = &sc->ic;
+
+ /*
+ * Apparently, the only way for us to know what ciphers
+ * and key management/authentication mode to use is for
+ * us to inspect the optional information element (IE)
+ * stored in the 802.11 state machine. This IE should be
+ * supplied by the WPA supplicant.
+ */
+
+ w = (struct ieee80211_ie_wpa *)ic->ic_opt_ie;
+
+ /* Check for the right kind of IE. */
+ if (w->wpa_id != IEEE80211_ELEMID_VENDOR)
+ return(EINVAL);
+
+ /* Skip over the ucast cipher OIDs. */
+ pos = (char *)&w->wpa_uciphers[0];
+ pos += w->wpa_uciphercnt * sizeof(struct ndis_ie);
+
+ /* Skip over the authmode count. */
+ pos += sizeof(u_int16_t);
+
+ /*
+ * Check for the authentication modes. I'm
+ * pretty sure there's only supposed to be one.
+ */
+
+ n = (struct ndis_ie *)pos;
+ if (n->ni_val == WPA_ASE_NONE)
+ arg = NDIS_80211_AUTHMODE_WPANONE;
+
+ if (n->ni_val == WPA_ASE_8021X_UNSPEC)
+ arg = NDIS_80211_AUTHMODE_WPA;
+
+ if (n->ni_val == WPA_ASE_8021X_PSK)
+ arg = NDIS_80211_AUTHMODE_WPAPSK;
+
+ i = sizeof(arg);
+ if (ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i))
+ return(ENOTSUP);
+ i = sizeof(arg);
+ ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i);
+
+ /* Now configure the desired ciphers. */
+
+ /* First, set up the multicast group cipher. */
+ n = (struct ndis_ie *)&w->wpa_mcipher[0];
+
+ if (ndis_set_cipher(sc, n->ni_val))
+ return(ENOTSUP);
+
+ /* Now start looking around for the unicast ciphers. */
+ pos = (char *)&w->wpa_uciphers[0];
+ n = (struct ndis_ie *)pos;
+
+ for (i = 0; i < w->wpa_uciphercnt; i++) {
+ if (ndis_set_cipher(sc, n->ni_val))
+ return(ENOTSUP);
+ n++;
+ }
+
+ return(0);
+}
+#endif
+
static void
ndis_setstate_80211(sc)
struct ndis_softc *sc;
{
struct ieee80211com *ic;
ndis_80211_ssid ssid;
+ ndis_80211_macaddr bssid;
ndis_80211_config config;
ndis_80211_wep wep;
int i, rval = 0, len;
@@ -1836,6 +2066,12 @@ ndis_setstate_80211(sc)
if (!NDIS_INITIALIZED(sc))
return;
+ /* Disassociate and turn off radio. */
+
+ len = sizeof(arg);
+ arg = 1;
+ ndis_set_info(sc, OID_802_11_DISASSOCIATE, &arg, &len);
+
/* Set network infrastructure mode. */
len = sizeof(arg);
@@ -1849,25 +2085,83 @@ ndis_setstate_80211(sc)
if (rval)
device_printf (sc->ndis_dev, "set infra failed: %d\n", rval);
+ /* Set RTS threshold */
+
+ len = sizeof(arg);
+ arg = ic->ic_rtsthreshold;
+ ndis_set_info(sc, OID_802_11_RTS_THRESHOLD, &arg, &len);
+
+ /* Set fragmentation threshold */
+
+ len = sizeof(arg);
+ arg = ic->ic_fragthreshold;
+ ndis_set_info(sc, OID_802_11_FRAGMENTATION_THRESHOLD, &arg, &len);
+
+ /* Set power management */
+
+ len = sizeof(arg);
+ if (ic->ic_flags & IEEE80211_F_PMGTON)
+ arg = NDIS_80211_POWERMODE_FAST_PSP;
+ else
+ arg = NDIS_80211_POWERMODE_CAM;
+ ndis_set_info(sc, OID_802_11_POWER_MODE, &arg, &len);
+
+ /*
+ * Default encryption mode to off, authentication
+ * to open and privacy to 'accept everything.'
+ */
+
+ len = sizeof(arg);
+ arg = NDIS_80211_WEPSTAT_DISABLED;
+ ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
+
+ len = sizeof(arg);
+ arg = NDIS_80211_AUTHMODE_OPEN;
+ ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
+
+ /*
+ * Note that OID_80211_PRIVACY_FILTER is optional:
+ * not all drivers implement it.
+ */
+ len = sizeof(arg);
+ arg = NDIS_80211_PRIVFILT_8021XWEP;
+ ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len);
+
/* Set WEP */
-#ifdef IEEE80211_F_PRIVACY
- if (ic->ic_flags & IEEE80211_F_PRIVACY) {
+#if __FreeBSD_version < 600000
+ if (ic->ic_flags & IEEE80211_F_WEPON) {
#else
- if (ic->ic_wep_mode >= IEEE80211_WEP_ON) {
+ if (ic->ic_flags & IEEE80211_F_PRIVACY &&
+ !(ic->ic_flags & IEEE80211_F_WPA)) {
#endif
+ int keys_set = 0;
+
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
if (ic->ic_nw_keys[i].wk_keylen) {
+#if __FreeBSD_version >= 600000
+ if (ic->ic_nw_keys[i].wk_cipher->ic_cipher !=
+ IEEE80211_CIPHER_WEP)
+ continue;
+#endif
bzero((char *)&wep, sizeof(wep));
wep.nw_keylen = ic->ic_nw_keys[i].wk_keylen;
-#ifdef notdef
- /* 5 and 13 are the only valid key lengths */
+
+ /*
+ * 5, 13 and 16 are the only valid
+ * only valid key lengths. Anything
+ * in between will be zero padded out to
+ * the next highest boundary.
+ */
if (ic->ic_nw_keys[i].wk_keylen < 5)
wep.nw_keylen = 5;
else if (ic->ic_nw_keys[i].wk_keylen > 5 &&
ic->ic_nw_keys[i].wk_keylen < 13)
wep.nw_keylen = 13;
-#endif
+ else if (ic->ic_nw_keys[i].wk_keylen > 13 &&
+ ic->ic_nw_keys[i].wk_keylen < 16)
+ wep.nw_keylen = 16;
+
wep.nw_keyidx = i;
wep.nw_length = (sizeof(uint32_t) * 3)
+ wep.nw_keylen;
@@ -1881,48 +2175,37 @@ ndis_setstate_80211(sc)
if (rval)
device_printf(sc->ndis_dev,
"set wepkey failed: %d\n", rval);
+ keys_set++;
}
}
- arg = NDIS_80211_WEPSTAT_ENABLED;
- len = sizeof(arg);
- rval = ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
- if (rval)
- device_printf(sc->ndis_dev,
- "enable WEP failed: %d\n", rval);
-#ifndef IEEE80211_F_WEPON
-#if 0
- if (ic->ic_wep_mode != IEEE80211_WEP_8021X &&
- ic->ic_wep_mode != IEEE80211_WEP_ON)
- arg = NDIS_80211_PRIVFILT_ACCEPTALL;
- else
-#endif
-#endif
- arg = NDIS_80211_PRIVFILT_8021XWEP;
- len = sizeof(arg);
- rval = ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len);
-#ifdef IEEE80211_WEP_8021X /*IEEE80211_F_WEPON*/
- /* Accept that we only have "shared" and 802.1x modes. */
- if (rval == 0) {
- if (arg == NDIS_80211_PRIVFILT_ACCEPTALL)
- ic->ic_wep_mode = IEEE80211_WEP_MIXED;
+ if (keys_set) {
+ arg = NDIS_80211_WEPSTAT_ENABLED;
+ len = sizeof(arg);
+ rval = ndis_set_info(sc,
+ OID_802_11_WEP_STATUS, &arg, &len);
+ if (rval)
+ device_printf(sc->ndis_dev,
+ "enable WEP failed: %d\n", rval);
+#ifdef IEEE80211_F_DROPUNENC
+ if (ic->ic_flags & IEEE80211_F_DROPUNENC)
+ arg = NDIS_80211_PRIVFILT_8021XWEP;
else
- ic->ic_wep_mode = IEEE80211_WEP_8021X;
- }
+ arg = NDIS_80211_PRIVFILT_ACCEPTALL;
+
+ len = sizeof(arg);
+ ndis_set_info(sc,
+ OID_802_11_PRIVACY_FILTER, &arg, &len);
#endif
- arg = NDIS_80211_AUTHMODE_OPEN;
- } else {
- arg = NDIS_80211_WEPSTAT_DISABLED;
- len = sizeof(arg);
- ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
- arg = NDIS_80211_AUTHMODE_OPEN;
- }
+ }
+ }
- len = sizeof(arg);
- rval = ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
+#ifdef IEEE80211_F_WPA
+ /* Set up WPA. */
-#ifdef notyet
- if (rval)
- device_printf (sc->ndis_dev, "set auth failed: %d\n", rval);
+ if (ic->ic_flags & IEEE80211_F_WPA1 && ic->ic_opt_ie_len &&
+ ic->ic_caps & IEEE80211_C_WPA)
+ if (ndis_set_wpa(sc))
+ device_printf(sc->ndis_dev, "WPA setup failed\n");
#endif
#ifdef notyet
@@ -1965,13 +2248,13 @@ ndis_setstate_80211(sc)
* Some drivers expect us to initialize these values, so
* provide some defaults.
*/
+
if (config.nc_beaconperiod == 0)
config.nc_beaconperiod = 100;
if (config.nc_atimwin == 0)
config.nc_atimwin = 100;
if (config.nc_fhconfig.ncf_dwelltime == 0)
config.nc_fhconfig.ncf_dwelltime = 200;
-
if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) {
int chan, chanflag;
@@ -1997,6 +2280,32 @@ ndis_setstate_80211(sc)
device_printf(sc->ndis_dev, "couldn't retrieve "
"channel info: %d\n", rval);
+ /*
+ * If the user selected a specific BSSID, try
+ * to use that one. This is useful in the case where
+ * there are several APs in range with the same network
+ * name. To delete the BSSID, we use the broadcast
+ * address as the BSSID.
+ * Note that some drivers seem to allow setting a BSSID
+ * in ad-hoc mode, which has the effect of forcing the
+ * NIC to create an ad-hoc cell with a specific BSSID,
+ * instead of a randomly chosen one. However, the net80211
+ * code makes the assumtion that the BSSID setting is invalid
+ * when you're in ad-hoc mode, so we don't allow that here.
+ */
+
+ len = IEEE80211_ADDR_LEN;
+ if (ic->ic_flags & IEEE80211_F_DESBSSID &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ bcopy(ic->ic_des_bssid, bssid, len);
+ else
+ bcopy(ifp->if_broadcastaddr, bssid, len);
+
+ rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len);
+ if (rval)
+ device_printf(sc->ndis_dev,
+ "setting BSSID failed: %d\n", rval);
+
/* Set SSID -- always do this last. */
len = sizeof(ssid);
@@ -2006,11 +2315,14 @@ ndis_setstate_80211(sc)
ssid.ns_ssidlen = 1;
} else
bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen);
+
rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
if (rval)
device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval);
+ ic->ic_state = IEEE80211_S_ASSOC;
+
return;
}
@@ -2059,9 +2371,11 @@ ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
case IEEE80211_MODE_11G:
imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G);
break;
+#ifdef IEEE80211_MODE_TURBO_A
case IEEE80211_MODE_TURBO_A:
imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
| IFM_IEEE80211_TURBO;
+#endif
break;
}
}
@@ -2266,6 +2580,9 @@ ndis_ioctl(ifp, command, data)
{
struct ndis_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *) data;
+ struct ndis_oid_data oid;
+ struct ndis_evt evt;
+ void *oidbuf;
int i, error = 0;
/*NDIS_LOCK(sc);*/
@@ -2308,7 +2625,11 @@ ndis_ioctl(ifp, command, data)
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
if (sc->ndis_80211) {
+#if __FreeBSD_version < 600000
+ error = ieee80211_ioctl(ifp, command, data);
+#else
error = ieee80211_ioctl(&sc->ic, command, data);
+#endif
if (error == ENETRESET) {
ndis_setstate_80211(sc);
/*ndis_init(sc);*/
@@ -2341,6 +2662,101 @@ ndis_ioctl(ifp, command, data)
else
error = ENOTTY;
break;
+ case SIOCGDRVSPEC:
+ if ((error = suser(curthread)))
+ break;
+ error = copyin(ifr->ifr_data, &oid, sizeof(oid));
+ if (error)
+ break;
+ oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO);
+ if (oidbuf == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len);
+ if (error) {
+ free(oidbuf, M_TEMP);
+ break;
+ }
+ error = ndis_get_info(sc, oid.oid, oidbuf, &oid.len);
+ if (error) {
+ free(oidbuf, M_TEMP);
+ break;
+ }
+ error = copyout(&oid, ifr->ifr_data, sizeof(oid));
+ if (error) {
+ free(oidbuf, M_TEMP);
+ break;
+ }
+ error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len);
+ free(oidbuf, M_TEMP);
+ break;
+ case SIOCSDRVSPEC:
+ if ((error = suser(curthread)))
+ break;
+ error = copyin(ifr->ifr_data, &oid, sizeof(oid));
+ if (error)
+ break;
+ oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO);
+ if (oidbuf == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len);
+ if (error) {
+ free(oidbuf, M_TEMP);
+ break;
+ }
+ error = ndis_set_info(sc, oid.oid, oidbuf, &oid.len);
+ if (error) {
+ free(oidbuf, M_TEMP);
+ break;
+ }
+ error = copyout(&oid, ifr->ifr_data, sizeof(oid));
+ if (error) {
+ free(oidbuf, M_TEMP);
+ break;
+ }
+ error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len);
+ free(oidbuf, M_TEMP);
+ break;
+ case SIOCGPRIVATE_0:
+ if ((error = suser(curthread)))
+ break;
+ NDIS_LOCK(sc);
+ if (sc->ndis_evt[sc->ndis_evtcidx].ne_sts == 0) {
+ error = ENOENT;
+ NDIS_UNLOCK(sc);
+ break;
+ }
+ error = copyin(ifr->ifr_data, &evt, sizeof(evt));
+ if (error)
+ break;
+ if (evt.ne_len < sc->ndis_evt[sc->ndis_evtcidx].ne_len) {
+ error = ENOSPC;
+ NDIS_UNLOCK(sc);
+ break;
+ }
+ error = copyout(&sc->ndis_evt[sc->ndis_evtcidx],
+ ifr->ifr_data, sizeof(uint32_t) * 2);
+ if (error) {
+ NDIS_UNLOCK(sc);
+ break;
+ }
+ if (sc->ndis_evt[sc->ndis_evtcidx].ne_len) {
+ error = copyout(sc->ndis_evt[sc->ndis_evtcidx].ne_buf,
+ ifr->ifr_data + (sizeof(uint32_t) * 2),
+ sc->ndis_evt[sc->ndis_evtcidx].ne_len);
+ if (error)
+ break;
+ free(sc->ndis_evt[sc->ndis_evtcidx].ne_buf, M_TEMP);
+ sc->ndis_evt[sc->ndis_evtcidx].ne_buf = NULL;
+ }
+ sc->ndis_evt[sc->ndis_evtcidx].ne_len = 0;
+ sc->ndis_evt[sc->ndis_evtcidx].ne_sts = 0;
+ NDIS_EVTINC(sc->ndis_evtcidx);
+ NDIS_UNLOCK(sc);
+ break;
case SIOCGIFGENERIC:
case SIOCSIFGENERIC:
if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) {
@@ -2356,7 +2772,11 @@ ndis_ioctl(ifp, command, data)
do_80211:
sc->ndis_skip = 1;
if (sc->ndis_80211) {
+#if __FreeBSD_version < 600000
+ error = ieee80211_ioctl(ifp, command, data);
+#else
error = ieee80211_ioctl(&sc->ic, command, data);
+#endif
if (error == ENETRESET) {
ndis_setstate_80211(sc);
error = 0;
@@ -2403,7 +2823,7 @@ ndis_wi_ioctl_get(ifp, command, data)
error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
if (error != ENOSPC)
break;
- bl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
+ bl = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
if (error) {
free(bl, M_DEVBUF);
@@ -2495,68 +2915,61 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data)
{
struct ndis_softc *sc;
struct ieee80211req *ireq;
+#ifdef RTM_IEEE80211_SCAN
ndis_80211_bssid_list_ex *bl;
- ndis_80211_ssid ssid;
- ndis_80211_macaddr bssid;
ndis_wlan_bssid_ex *wb;
struct ieee80211req_scan_result *sr, *bsr;
- int error, len, i, j;
+ int i, j;
char *cp;
- uint8_t nodename[IEEE80211_NWID_LEN];
+#endif
+ int error, len;
uint16_t nodename_u[IEEE80211_NWID_LEN + 1];
- char *acode;
+ unicode_string us;
+ ansi_string as;
sc = ifp->if_softc;
ireq = (struct ieee80211req *) data;
-
+
switch (ireq->i_type) {
+#ifdef IEEE80211_IOC_MLME
case IEEE80211_IOC_MLME:
error = 0;
break;
- case IEEE80211_IOC_BSSID:
- len = sizeof(bssid);
- bzero((char*)&bssid, len);
- error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len);
- if (error) {
- device_printf(sc->ndis_dev, "failed to get bssid\n");
- return(error);
- }
- ireq->i_len = len;
- error = copyout(&bssid, ireq->i_data, len);
- break;
- case IEEE80211_IOC_SSID:
- len = sizeof(ssid);
- bzero((char*)&ssid, len);
- error = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len);
- if (error) {
- device_printf(sc->ndis_dev, "failed to get ssid: %d\n", error);
- return(error);
- }
- ireq->i_len = ssid.ns_ssidlen;
- error = copyout(&ssid.ns_ssid, ireq->i_data, ssid.ns_ssidlen);
- break;
+#endif
+#ifdef RTM_IEEE80211_SCAN
case IEEE80211_IOC_SCAN_RESULTS:
len = 0;
error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
if (error != ENOSPC)
break;
- bl = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
+ bl = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
if (error) {
free(bl, M_DEVBUF);
break;
}
- sr = bsr = malloc(ireq->i_len, M_DEVBUF, M_WAITOK | M_ZERO);
- wb = bl->nblx_bssid;
+ sr = bsr = malloc(ireq->i_len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ wb = &bl->nblx_bssid[0];
len = 0;
for (i = 0; i < bl->nblx_items; i++) {
/*
- * Check if we have enough space left for this ap
+ * Check if we have enough space left for this ap.
+ * Note that the size of the SSID list structure
+ * can vary: the extended structure with info
+ * elements is only supported by NDIS 5.1 drivers.
*/
- j = roundup(sizeof(*sr) + wb->nwbx_ssid.ns_ssidlen
- + wb->nwbx_ielen -
- sizeof(struct ndis_80211_fixed_ies),
- sizeof(uint32_t));
+ if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
+ j = roundup(sizeof(*sr) +
+ wb->nwbx_ssid.ns_ssidlen +
+ wb->nwbx_ielen -
+ sizeof(struct ndis_80211_fixed_ies),
+ sizeof(uint32_t));
+ } else {
+ j = roundup(sizeof(*sr) +
+ wb->nwbx_ssid.ns_ssidlen +
+ sizeof(struct ndis_80211_fixed_ies),
+ sizeof(uint32_t));
+ }
if (len + j > ireq->i_len)
break;
bcopy(&wb->nwbx_macaddr, &sr->isr_bssid,
@@ -2586,11 +2999,13 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data)
cp = (char *)sr + sizeof(*sr);
bcopy(&wb->nwbx_ssid.ns_ssid, cp, sr->isr_ssid_len);
cp += sr->isr_ssid_len;
- sr->isr_ie_len = wb->nwbx_ielen
- - sizeof(struct ndis_80211_fixed_ies);
- bcopy((char *)wb->nwbx_ies +
- sizeof(struct ndis_80211_fixed_ies),
- cp, sr->isr_ie_len);
+ if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
+ sr->isr_ie_len = wb->nwbx_ielen
+ - sizeof(struct ndis_80211_fixed_ies);
+ bcopy((char *)wb->nwbx_ies +
+ sizeof(struct ndis_80211_fixed_ies),
+ cp, sr->isr_ie_len);
+ }
sr->isr_len = roundup(sizeof(*sr) + sr->isr_ssid_len
+ sr->isr_ie_len, sizeof(uint32_t));
len += sr->isr_len;
@@ -2603,318 +3018,172 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data)
free(bl, M_DEVBUF);
free(bsr, M_DEVBUF);
break;
+#endif
case IEEE80211_IOC_STATIONNAME:
error = ndis_get_info(sc, OID_GEN_MACHINE_NAME,
&nodename_u, &len);
if (error)
break;
- acode = nodename;
- bzero((char *)nodename, IEEE80211_NWID_LEN);
- ndis_unicode_to_ascii(nodename_u, len, &acode);
- ireq->i_len = len / 2 + 1;
- error = copyout(acode, ireq->i_data, ireq->i_len);
+ us.us_len = us.us_maxlen = len;
+ us.us_buf = nodename_u;
+ if (RtlUnicodeStringToAnsiString(&as, &us, TRUE)) {
+ error = ENOMEM;
+ break;
+ }
+ ireq->i_len = as.as_len;
+ error = copyout(as.as_buf, ireq->i_data, ireq->i_len);
+ RtlFreeAnsiString(&as);
break;
default:
+#if __FreeBSD_version < 600000
+ error = ieee80211_ioctl(ifp, command, data);
+#else
error = ieee80211_ioctl(&sc->ic, command, data);
+#endif
+ break;
}
return(error);
}
-static int
-ndis_add_key(sc, wk, i_len)
- struct ndis_softc *sc;
- struct ieee80211req_key *wk;
- int16_t i_len;
+#ifdef IEEE80211_F_WPA
+int
+ndis_del_key(ic, key)
+ struct ieee80211com *ic;
+ const struct ieee80211_key *key;
{
- ndis_80211_key *rkey;
- ndis_80211_wep *wep;
- int len, error;
- uint32_t arg;
+ struct ndis_softc *sc;
+ ndis_80211_key rkey;
+ int len, error = 0;
- /* infrastructure mode only supported for now */
- len = sizeof(arg);
- arg = NDIS_80211_NET_INFRA_BSS;
- error = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
- if (error) {
- device_printf(sc->ndis_dev,
- "setting infrastructure mode failed\n");
- return(error);
- }
+ sc = ic->ic_ifp->if_softc;
- switch(wk->ik_type) {
- case IEEE80211_CIPHER_WEP:
- len = 12 + wk->ik_keylen;
- wep = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
- if(!wep)
- return(ENOSPC);
- wep->nw_length = len;
- wep->nw_keyidx = wk->ik_keyix;
- wep->nw_keylen = wk->ik_keylen;
- if(wk->ik_flags & IEEE80211_KEY_XMIT)
- wep->nw_keyidx |= 1 << 31;
- device_printf(sc->ndis_dev, "setting wep key\n");
- error = copyin(wk->ik_keydata, wep->nw_keydata, wk->ik_keylen);
- if(error) {
- device_printf(sc->ndis_dev,
- "copyin of wep key to kernel space failed\n");
- free(wep, M_TEMP);
- break;
- }
- error = ndis_set_info(sc, OID_802_11_ADD_WEP, wep, &len);
- if(error) {
- device_printf(sc->ndis_dev,
- "setting wep key failed\n");
- break;
- }
- free(wep, M_TEMP);
+ bzero((char *)&rkey, sizeof(rkey));
+ len = sizeof(rkey);
- /* set the authentication mode */
+ rkey.nk_len = len;
+ rkey.nk_keyidx = key->wk_keyix;
- arg = NDIS_80211_AUTHMODE_OPEN;
- error = ndis_set_info(sc,
- OID_802_11_AUTHENTICATION_MODE, &arg, &len);
- if(error) {
- device_printf(sc->ndis_dev,
- "setting authentication mode failed\n");
- }
+ bcopy(ic->ic_ifp->if_broadcastaddr,
+ rkey.nk_bssid, IEEE80211_ADDR_LEN);
- /* set the encryption */
+ error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len);
- len = sizeof(arg);
- arg = NDIS_80211_WEPSTAT_ENABLED;
- error = ndis_set_info(sc,
- OID_802_11_ENCRYPTION_STATUS, &arg, &len);
- if(error) {
- device_printf(sc->ndis_dev,
- "setting encryption status failed\n");
- return(error);
- }
- break;
+ if (error)
+ return(0);
+
+ return(1);
+}
+
+/*
+ * In theory this could be called for any key, but we'll
+ * only use it for WPA TKIP or AES keys. These need to be
+ * set after initial authentication with the AP.
+ */
+
+static int
+ndis_add_key(ic, key, mac)
+ struct ieee80211com *ic;
+ const struct ieee80211_key *key;
+ const uint8_t mac[IEEE80211_ADDR_LEN];
+{
+ struct ndis_softc *sc;
+ ndis_80211_key rkey;
+ int len, error = 0;
+
+ sc = ic->ic_ifp->if_softc;
+
+ switch (key->wk_cipher->ic_cipher) {
case IEEE80211_CIPHER_TKIP:
- len = 12 + 6 + 6 + 8 + wk->ik_keylen;
- rkey = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
- if(!rkey)
- return(ENOSPC);
- rkey->nk_len = len;
- error = copyin(wk->ik_macaddr,
- rkey->nk_bssid, IEEE80211_ADDR_LEN);
- if(error) {
- device_printf(sc->ndis_dev,
- "copyin of bssid to kernel space failed\n");
- free(rkey, M_TEMP);
- break;
- }
- /* keyrsc needs to be fixed: need to do some shifting */
- error = copyin(&(wk->ik_keyrsc),
- &(rkey->nk_keyrsc), sizeof(rkey->nk_keyrsc));
- if(error) {
- device_printf(sc->ndis_dev,
- "copyin of keyrsc to kernel space failed\n");
- free(rkey, M_TEMP);
- break;
- }
+ len = sizeof(ndis_80211_key);
+ bzero((char *)&rkey, sizeof(rkey));
+
+ rkey.nk_len = len;
+ rkey.nk_keylen = key->wk_keylen;
+
+ if (key->wk_flags & IEEE80211_KEY_SWMIC)
+ rkey.nk_keylen += 16;
/* key index - gets weird in NDIS */
- rkey->nk_keyidx = wk->ik_keyix;
- if(wk->ik_flags & IEEE80211_KEY_XMIT)
- rkey->nk_keyidx |= 1 << 31;
- if((bcmp(rkey->nk_bssid, "\xff\xff\xff\xff\xff\xff",
- IEEE80211_ADDR_LEN) == 0) ||
- (bcmp(rkey->nk_bssid, "\x0\x0\x0\x0\x0\x0",
- IEEE80211_ADDR_LEN) == 0)) {
- /* group key - nothing to do in ndis */
+ if (key->wk_keyix != IEEE80211_KEYIX_NONE)
+ rkey.nk_keyidx = key->wk_keyix;
+ else
+ rkey.nk_keyidx = 0;
+
+ if (key->wk_flags & IEEE80211_KEY_XMIT)
+ rkey.nk_keyidx |= 1 << 31;
+
+ if (key->wk_flags & IEEE80211_KEY_GROUP) {
+ bcopy(ic->ic_ifp->if_broadcastaddr,
+ rkey.nk_bssid, IEEE80211_ADDR_LEN);
} else {
+ bcopy(ic->ic_bss->ni_bssid,
+ rkey.nk_bssid, IEEE80211_ADDR_LEN);
/* pairwise key */
- rkey->nk_keyidx |= 1 << 30;
+ rkey.nk_keyidx |= 1 << 30;
}
/* need to set bit 29 based on keyrsc */
+ rkey.nk_keyrsc = key->wk_keyrsc;
- rkey->nk_keylen = wk->ik_keylen;
- if (wk->ik_type == IEEE80211_CIPHER_TKIP &&
- wk->ik_keylen == 32) {
- /*
- * key data needs to be offset by 4 due
- * to mismatch between NDIS spec and BSD??
- */
- error = copyin(wk->ik_keydata,
- rkey->nk_keydata + 4, 16);
- if(error) {
- device_printf(sc->ndis_dev, "copyin of "
- "keydata(0) to kernel space failed\n");
- free(rkey, M_TEMP);
- break;
- }
- error = copyin(wk->ik_keydata + 24,
- rkey->nk_keydata + 20, 8);
- if(error) {
- device_printf(sc->ndis_dev, "copyin of "
- "keydata(1) to kernel space failed\n");
- free(rkey, M_TEMP);
- break;
- }
- error = copyin(wk->ik_keydata + 16,
- rkey->nk_keydata + 28, 8);
- if(error) {
- device_printf(sc->ndis_dev, "copyin of "
- "keydata(2) to kernel space failed\n");
- free(rkey, M_TEMP);
- break;
- }
- } else {
- error = copyin(wk->ik_keydata,
- rkey->nk_keydata + 4, wk->ik_keylen);
- if(error) {
- device_printf(sc->ndis_dev, "copyin of "
- "keydata(CCMP) to kernel space failed\n");
- free(rkey, M_TEMP);
- break;
- }
- }
- error = ndis_set_info(sc, OID_802_11_ADD_KEY, rkey, &len);
+ if (rkey.nk_keyrsc)
+ rkey.nk_keyidx |= 1 << 29;
+
+ if (key->wk_flags & IEEE80211_KEY_SWMIC) {
+ bcopy(key->wk_key, rkey.nk_keydata, 16);
+ bcopy(key->wk_key + 24, rkey.nk_keydata + 16, 8);
+ bcopy(key->wk_key + 16, rkey.nk_keydata + 24, 8);
+ } else
+ bcopy(key->wk_key, rkey.nk_keydata, key->wk_keylen);
+
+ error = ndis_set_info(sc, OID_802_11_ADD_KEY, &rkey, &len);
+ break;
+ case IEEE80211_CIPHER_WEP:
+ error = 0;
break;
+ /*
+ * I don't know how to set up keys for the AES
+ * cipher yet. Is it the same as TKIP?
+ */
case IEEE80211_CIPHER_AES_CCM:
- return(ENOTTY);
default:
- return(ENOTTY);
+ error = ENOTTY;
+ break;
}
- return(error);
+
+ /* We need to return 1 for success, 0 for failure. */
+
+ if (error)
+ return(0);
+
+ return (1);
}
+#endif
static int
ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data)
{
struct ndis_softc *sc;
struct ieee80211req *ireq;
- int error, len, arg, ucnt;
- uint8_t nodename[IEEE80211_NWID_LEN];
- uint16_t nodename_u[IEEE80211_NWID_LEN + 1];
- uint16_t *ucode;
- struct ieee80211req_del_key *rk;
- struct ieee80211req_key *wk;
- unsigned char *wpa_ie;
- ndis_80211_ssid ssid;
- ndis_80211_remove_key rkey;
+ int error = EINVAL, len;
+ ansi_string as;
+ unicode_string us;
sc = ifp->if_softc;
ireq = (struct ieee80211req *) data;
-
+
switch (ireq->i_type) {
+#ifdef IEEE80211_IOC_MLME
case IEEE80211_IOC_MLME:
case IEEE80211_IOC_ROAMING:
case IEEE80211_IOC_COUNTERMEASURES:
case IEEE80211_IOC_DROPUNENCRYPTED:
error = 0;
break;
- case IEEE80211_IOC_PRIVACY:
- len = sizeof(arg);
- arg = NDIS_80211_PRIVFILT_8021XWEP;
- error = ndis_set_info(sc,
- OID_802_11_PRIVACY_FILTER, &arg, &len);
- if (error) {
- device_printf(sc->ndis_dev,
- "setting wep privacy filter failed\n");
- error = 0;
- }
- break;
- case IEEE80211_IOC_WPA:
- /* nothing to do */
- error = 0;
- break;
- case IEEE80211_IOC_OPTIE:
- wpa_ie = (char*)ireq->i_data;
- if (ireq->i_len < 14 || !wpa_ie) {
- /* cannot figure out anything */
- arg = NDIS_80211_AUTHMODE_OPEN;
- error = ndis_set_info(sc,
- OID_802_11_AUTHENTICATION_MODE, &arg, &len);
- return(error);
- }
- if (wpa_ie[0] == IEEE80211_ELEMID_RSN) {
- error = ENOTTY;
- break;
- } else if (wpa_ie[0] == IEEE80211_ELEMID_VENDOR) {
-
- /* set the encryption based on multicast cipher */
-
- if (!memcmp(wpa_ie + 8, "\x00\x50\xf2\x02", 4)) {
- len = sizeof(arg);
- arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
- error = ndis_set_info(sc,
- OID_802_11_ENCRYPTION_STATUS, &arg, &len);
- if (error) {
- device_printf(sc->ndis_dev, "setting "
- "encryption status to "
- "ENC2 failed\n");
- /* continue anyway */
- }
- }
- }
-
- /* set the authentication mode */
-
- ucnt = wpa_ie[12] + 256* wpa_ie[13];
-
- /* 4 bytes per unicast cipher */
-
- ucnt = 14 + 4*ucnt + 2; /* account for number of authsels */
-
- if (ireq->i_len < ucnt) {
- arg = NDIS_80211_AUTHMODE_WPANONE;
- } else {
- if (!memcmp((void*)(&wpa_ie[ucnt]),
- "\x00\x50\xf2\x02", 4)) {
- arg = NDIS_80211_AUTHMODE_WPAPSK;
- } else if (!memcmp((void*)(&wpa_ie[ucnt]),
- "\x00\x50\xf2\x01", 4)) {
- arg = NDIS_80211_AUTHMODE_WPA;
- } else {
- arg = NDIS_80211_AUTHMODE_WPANONE;
- }
- }
- len = sizeof(arg);
- error = ndis_set_info(sc,
- OID_802_11_AUTHENTICATION_MODE, &arg, &len);
- if (error) {
- device_printf(sc->ndis_dev,
- "setting authentication mode to WPA-PSK failed\n");
- break;
- }
- break;
- case IEEE80211_IOC_SSID:
- len = sizeof(ssid);
- bzero((char*)&ssid, len);
- ssid.ns_ssidlen = ireq->i_len;
- error = copyin(ireq->i_data, &(ssid.ns_ssid), ireq->i_len);
- if (error)
- break;
- error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
- if (error) {
- device_printf(sc->ndis_dev,
- "setting SSID to %s\n", ssid.ns_ssid);
- }
- break;
- case IEEE80211_IOC_DELKEY:
- len = sizeof(rkey);
- bzero((char*)&rkey, len);
- rk = (struct ieee80211req_del_key*)ireq->i_data;
- rkey.nk_len = len;
- rkey.nk_keyidx = rk->idk_keyix;
- error = copyin(rk->idk_macaddr,
- &(rkey.nk_bssid), sizeof(ndis_80211_macaddr));
- if (error)
- break;
- error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len);
- if (error)
- device_printf(sc->ndis_dev, "deleting key\n");
- break;
- case IEEE80211_IOC_WPAKEY:
- wk = (struct ieee80211req_key*)ireq->i_data;
- error = ndis_add_key(sc, wk, ireq->i_len);
- break;
+#endif
+#ifdef RTM_IEEE80211_SCAN
case IEEE80211_IOC_SCAN_REQ:
len = 0;
error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN,
@@ -2922,6 +3191,7 @@ ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data)
tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2);
rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
break;
+#endif
case IEEE80211_IOC_STATIONNAME:
error = suser(curthread);
if (error)
@@ -2931,18 +3201,23 @@ ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data)
error = EINVAL;
break;
}
- bzero((char *)nodename, IEEE80211_NWID_LEN);
- error = copyin(ireq->i_data, nodename, ireq->i_len);
- if (error)
+ as.as_len = as.as_maxlen = ireq->i_len;
+ as.as_buf = ireq->i_data;
+ if (RtlAnsiStringToUnicodeString(&us, &as, TRUE)) {
+ error = ENOMEM;
break;
- ucode = nodename_u;
- ndis_ascii_to_unicode((char *)nodename, &ucode);
- len = ireq->i_len * 2;
+ }
+ len = us.us_len;
error = ndis_set_info(sc, OID_GEN_MACHINE_NAME,
- &nodename_u, &len);
+ us.us_buf, &len);
+ RtlFreeUnicodeString(&us);
break;
default:
+#if __FreeBSD_version < 600000
+ error = ieee80211_ioctl(ifp, command, data);
+#else
error = ieee80211_ioctl(&sc->ic, command, data);
+#endif
if (error == ENETRESET) {
ndis_setstate_80211(sc);
error = 0;
@@ -2953,8 +3228,8 @@ ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data)
}
static void
-ndis_resettask(w, arg)
- ndis_work_item *w;
+ndis_resettask(d, arg)
+ device_object *d;
void *arg;
{
struct ndis_softc *sc;
@@ -2977,8 +3252,12 @@ ndis_watchdog(ifp)
device_printf(sc->ndis_dev, "watchdog timeout\n");
NDIS_UNLOCK(sc);
- NdisScheduleWorkItem(&sc->ndis_resetitem);
- NdisScheduleWorkItem(&sc->ndis_startitem);
+ IoQueueWorkItem(sc->ndis_resetitem,
+ (io_workitem_func)ndis_resettask_wrap,
+ WORKQUEUE_CRITICAL, sc);
+ IoQueueWorkItem(sc->ndis_startitem,
+ (io_workitem_func)ndis_starttask_wrap,
+ WORKQUEUE_CRITICAL, ifp);
return;
}
@@ -2992,6 +3271,12 @@ ndis_stop(sc)
struct ndis_softc *sc;
{
struct ifnet *ifp;
+ struct ieee80211com *ic;
+ int i;
+
+ ic = &sc->ic;
+ if (sc->ndis_80211)
+ ic->ic_state = IEEE80211_S_INIT;
ifp = sc->ifp;
untimeout(ndis_tick, sc, sc->ndis_stat_ch);
@@ -3004,6 +3289,17 @@ ndis_stop(sc)
ndis_halt_nic(sc);
+ NDIS_LOCK(sc);
+ for (i = 0; i < NDIS_EVENTS; i++) {
+ if (sc->ndis_evt[i].ne_sts && sc->ndis_evt[i].ne_buf != NULL)
+ free(sc->ndis_evt[i].ne_buf, M_TEMP);
+ sc->ndis_evt[i].ne_sts = 0;
+ sc->ndis_evt[i].ne_len = 0;
+ }
+ sc->ndis_evtcidx = 0;
+ sc->ndis_evtpidx = 0;
+ NDIS_UNLOCK(sc);
+
return;
}
diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h
index 5e28b7d..b595dd7 100644
--- a/sys/dev/if_ndis/if_ndisvar.h
+++ b/sys/dev/if_ndis/if_ndisvar.h
@@ -35,6 +35,16 @@
#define NDIS_DEFAULT_NODENAME "FreeBSD NDIS node"
#define NDIS_NODENAME_LEN 32
+/* For setting/getting OIDs from userspace. */
+
+struct ndis_oid_data {
+ uint32_t oid;
+ uint32_t len;
+#ifdef notdef
+ uint8_t data[1];
+#endif
+};
+
struct ndis_pci_type {
uint16_t ndis_vid;
uint16_t ndis_did;
@@ -49,28 +59,51 @@ struct ndis_pccard_type {
};
struct ndis_shmem {
+ list_entry ndis_list;
bus_dma_tag_t ndis_stag;
bus_dmamap_t ndis_smap;
void *ndis_saddr;
ndis_physaddr ndis_paddr;
- struct ndis_shmem *ndis_next;
};
struct ndis_cfglist {
ndis_cfg ndis_cfg;
+ struct sysctl_oid *ndis_oid;
TAILQ_ENTRY(ndis_cfglist) link;
};
+/*
+ * Helper struct to make parsing information
+ * elements easier.
+ */
+struct ndis_ie {
+ uint8_t ni_oui[3];
+ uint8_t ni_val;
+};
+
TAILQ_HEAD(nch, ndis_cfglist);
-#define NDIS_INITIALIZED(sc) (sc->ndis_block->nmb_miniportadapterctx != NULL)
+#define NDIS_INITIALIZED(sc) (sc->ndis_block->nmb_devicectx != NULL)
#define NDIS_INC(x) \
(x)->ndis_txidx = ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts
+#if __FreeBSD_version < 600000
+#define arpcom ic.ic_ac
+#endif
+
+#define NDIS_EVENTS 4
+#define NDIS_EVTINC(x) (x) = ((x) + 1) % NDIS_EVENTS
+
+struct ndis_evt {
+ uint32_t ne_sts;
+ uint32_t ne_len;
+ char *ne_buf;
+};
+
struct ndis_softc {
- struct ifnet *ifp;
struct ieee80211com ic; /* interface info */
+ struct ifnet *ifp;
struct ifmedia ifmedia; /* media info */
u_long ndis_hwassist;
uint32_t ndis_v4tx;
@@ -91,7 +124,8 @@ struct ndis_softc {
struct resource *ndis_res_cm; /* common mem (pccard) */
struct resource_list ndis_rl;
int ndis_rescnt;
- struct mtx ndis_mtx;
+ kspin_lock ndis_spinlock;
+ uint8_t ndis_irql;
device_t ndis_dev;
int ndis_unit;
ndis_miniport_block *ndis_block;
@@ -110,6 +144,7 @@ struct ndis_softc {
struct nch ndis_cfglist_head;
int ndis_80211;
int ndis_link;
+ uint32_t ndis_sts;
uint32_t ndis_filter;
int ndis_if_flags;
int ndis_skip;
@@ -121,18 +156,53 @@ struct ndis_softc {
int ndis_devidx;
interface_type ndis_iftype;
driver_object *ndis_dobj;
- ndis_work_item ndis_tickitem;
- ndis_work_item ndis_startitem;
- ndis_work_item ndis_resetitem;
+ io_workitem *ndis_tickitem;
+ io_workitem *ndis_startitem;
+ io_workitem *ndis_resetitem;
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;
};
-#define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx)
-#define NDIS_UNLOCK(_sc) mtx_unlock(&(_sc)->ndis_mtx)
+#define NDIS_LOCK(_sc) KeAcquireSpinLock(&(_sc)->ndis_spinlock, \
+ &(_sc)->ndis_irql);
+#define NDIS_UNLOCK(_sc) KeReleaseSpinLock(&(_sc)->ndis_spinlock, \
+ (_sc)->ndis_irql);
+
+/*
+ * Backwards compatibility defines.
+ */
+
+#ifndef IF_ADDR_LOCK
+#define IF_ADDR_LOCK(x)
+#define IF_ADDR_UNLOCK(x)
+#endif
+
+#ifndef IFF_DRV_OACTIVE
+#define IFF_DRV_OACTIVE IFF_OACTIVE
+#define IFF_DRV_RUNNING IFF_RUNNING
+#define if_drv_flags if_flags
+#endif
+
+#ifndef ic_def_txkey
+#define ic_def_txkey ic_wep_txkey
+#define wk_keylen wk_len
+#endif
+
+#ifndef SIOCGDRVSPEC
+#define SIOCSDRVSPEC _IOW('i', 123, struct ifreq) /* set driver-specific
+ parameters */
+#define SIOCGDRVSPEC _IOWR('i', 123, struct ifreq) /* get driver-specific
+ parameters */
+#endif
OpenPOWER on IntegriCloud