From 3d0ceda3043d3d75e3188f3653157efb0123913d Mon Sep 17 00:00:00 2001 From: rittera Date: Thu, 30 Mar 2006 22:56:50 +0000 Subject: [PATCH] Added the original FreeBSD RELENG_54 files in sys/compat/ndis. --- sys/compat/ndis/cfg_var.h | 47 + sys/compat/ndis/hal_var.h | 58 + sys/compat/ndis/kern_ndis.c | 1764 +++++++++++++++++ sys/compat/ndis/kern_windrv.c | 485 +++++ sys/compat/ndis/ndis_var.h | 1609 +++++++++++++++ sys/compat/ndis/ntoskrnl_var.h | 1253 ++++++++++++ sys/compat/ndis/pe_var.h | 573 ++++++ sys/compat/ndis/resource_var.h | 199 ++ sys/compat/ndis/subr_hal.c | 412 ++++ sys/compat/ndis/subr_ndis.c | 3305 +++++++++++++++++++++++++++++++ sys/compat/ndis/subr_ntoskrnl.c | 2811 ++++++++++++++++++++++++++ sys/compat/ndis/subr_pe.c | 638 ++++++ sys/compat/ndis/subr_usbd.c | 156 ++ sys/compat/ndis/usbd_var.h | 56 + sys/compat/ndis/winx64_wrap.S | 177 ++ 15 files changed, 13543 insertions(+) create mode 100644 sys/compat/ndis/cfg_var.h create mode 100644 sys/compat/ndis/hal_var.h create mode 100644 sys/compat/ndis/kern_ndis.c create mode 100644 sys/compat/ndis/kern_windrv.c create mode 100644 sys/compat/ndis/ndis_var.h create mode 100644 sys/compat/ndis/ntoskrnl_var.h create mode 100644 sys/compat/ndis/pe_var.h create mode 100644 sys/compat/ndis/resource_var.h create mode 100644 sys/compat/ndis/subr_hal.c create mode 100644 sys/compat/ndis/subr_ndis.c create mode 100644 sys/compat/ndis/subr_ntoskrnl.c create mode 100644 sys/compat/ndis/subr_pe.c create mode 100644 sys/compat/ndis/subr_usbd.c create mode 100644 sys/compat/ndis/usbd_var.h create mode 100644 sys/compat/ndis/winx64_wrap.S diff --git a/sys/compat/ndis/cfg_var.h b/sys/compat/ndis/cfg_var.h new file mode 100644 index 000000000000..04002893274d --- /dev/null +++ b/sys/compat/ndis/cfg_var.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/compat/ndis/cfg_var.h,v 1.2.2.1 2005/01/30 00:59:19 imp Exp $ + */ + +#ifndef _CFG_VAR_H_ +#define _CFG_VAR_H_ + +struct ndis_cfg { + char *nc_cfgkey; + char *nc_cfgdesc; + char nc_val[256]; + int nc_idx; +}; + +typedef struct ndis_cfg ndis_cfg; + +#endif /* _CFG_VAR_H_ */ diff --git a/sys/compat/ndis/hal_var.h b/sys/compat/ndis/hal_var.h new file mode 100644 index 000000000000..e0a549c1fb65 --- /dev/null +++ b/sys/compat/ndis/hal_var.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/compat/ndis/hal_var.h,v 1.4.2.2 2005/02/18 16:30:09 wpaul Exp $ + */ + +#ifndef _HAL_VAR_H_ +#define _HAL_VAR_H_ + +#ifdef __amd64__ +#define NDIS_BUS_SPACE_IO AMD64_BUS_SPACE_IO +#define NDIS_BUS_SPACE_MEM AMD64_BUS_SPACE_MEM +#else +#define NDIS_BUS_SPACE_IO I386_BUS_SPACE_IO +#define NDIS_BUS_SPACE_MEM I386_BUS_SPACE_MEM +#endif + +extern image_patch_table hal_functbl[]; + +__BEGIN_DECLS +extern int hal_libinit(void); +extern int hal_libfini(void); +__fastcall extern uint8_t KfAcquireSpinLock(REGARGS1(kspin_lock *lock)); +__fastcall void KfReleaseSpinLock(REGARGS2(kspin_lock *lock, uint8_t newirql)); +__fastcall extern uint8_t KfRaiseIrql(REGARGS1(uint8_t irql)); +__fastcall extern void KfLowerIrql(REGARGS1(uint8_t oldirql)); +__stdcall extern uint8_t KeGetCurrentIrql(void); +__END_DECLS + +#endif /* _HAL_VAR_H_ */ diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c new file mode 100644 index 000000000000..dcbf64da1462 --- /dev/null +++ b/sys/compat/ndis/kern_ndis.c @@ -0,0 +1,1764 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.60.2.5 2005/04/01 17:14:20 wpaul Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" + +__stdcall static void ndis_status_func(ndis_handle, ndis_status, + void *, uint32_t); +__stdcall static void ndis_statusdone_func(ndis_handle); +__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); +__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); +__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); +__stdcall static void ndis_sendrsrcavail_func(ndis_handle); +__stdcall static void ndis_intrhand(kdpc *, device_object *, + irp *, struct ndis_softc *); + +static image_patch_table kernndis_functbl[] = { + IMPORT_FUNC(ndis_status_func), + IMPORT_FUNC(ndis_statusdone_func), + IMPORT_FUNC(ndis_setdone_func), + IMPORT_FUNC(ndis_getdone_func), + IMPORT_FUNC(ndis_resetdone_func), + IMPORT_FUNC(ndis_sendrsrcavail_func), + IMPORT_FUNC(ndis_intrhand), + + { NULL, NULL, NULL } +}; + +struct nd_head ndis_devhead; + +struct ndis_req { + void (*nr_func)(void *); + void *nr_arg; + int nr_exit; + STAILQ_ENTRY(ndis_req) link; +}; + +struct ndisproc { + struct ndisqhead *np_q; + struct proc *np_p; + int np_state; +}; + +static void ndis_return(void *); +static int ndis_create_kthreads(void); +static void ndis_destroy_kthreads(void); +static void ndis_stop_thread(int); +static int ndis_enlarge_thrqueue(int); +static int ndis_shrink_thrqueue(int); +static void ndis_runq(void *); + +static struct mtx ndis_thr_mtx; +static struct mtx ndis_req_mtx; +static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo; +static struct ndisqhead ndis_itodo; +static struct ndisqhead ndis_free; +static int ndis_jobs = 32; + +static struct ndisproc ndis_tproc; +static struct ndisproc ndis_iproc; + +/* + * This allows us to export our symbols to other modules. + * Note that we call ourselves 'ndisapi' to avoid a namespace + * collision with if_ndis.ko, which internally calls itself + * 'ndis.' + */ + +static int +ndis_modevent(module_t mod, int cmd, void *arg) +{ + int error = 0; + image_patch_table *patch; + + switch (cmd) { + case MOD_LOAD: + /* Initialize subsystems */ + windrv_libinit(); + hal_libinit(); + ndis_libinit(); + ntoskrnl_libinit(); + usbd_libinit(); + + patch = kernndis_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap); + patch++; + } + + ndis_create_kthreads(); + + TAILQ_INIT(&ndis_devhead); + + break; + case MOD_SHUTDOWN: + /* stop kthreads */ + ndis_destroy_kthreads(); + if (TAILQ_FIRST(&ndis_devhead) == NULL) { + /* Shut down subsystems */ + hal_libfini(); + ndis_libfini(); + ntoskrnl_libfini(); + usbd_libfini(); + windrv_libfini(); + + patch = kernndis_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + } + break; + case MOD_UNLOAD: + /* stop kthreads */ + ndis_destroy_kthreads(); + + /* Shut down subsystems */ + hal_libfini(); + ndis_libfini(); + ntoskrnl_libfini(); + usbd_libfini(); + windrv_libfini(); + + patch = kernndis_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + break; + default: + error = EINVAL; + break; + } + + return(error); +} +DEV_MODULE(ndisapi, ndis_modevent, NULL); +MODULE_VERSION(ndisapi, 1); + +/* + * We create two kthreads for the NDIS subsystem. One of them is a task + * queue for performing various odd jobs. The other is an swi thread + * reserved exclusively for running interrupt handlers. The reason we + * have our own task queue is that there are some cases where we may + * need to sleep for a significant amount of time, and if we were to + * use one of the taskqueue threads, we might delay the processing + * of other pending tasks which might need to run right away. We have + * a separate swi thread because we don't want our interrupt handling + * to be delayed either. + * + * By default there are 32 jobs available to start, and another 8 + * are added to the free list each time a new device is created. + */ + +static void +ndis_runq(arg) + void *arg; +{ + struct ndis_req *r = NULL, *die = NULL; + struct ndisproc *p; + + p = arg; + + while (1) { + + /* Sleep, but preserve our original priority. */ + ndis_thsuspend(p->np_p, NULL, 0); + + /* Look for any jobs on the work queue. */ + + mtx_lock_spin(&ndis_thr_mtx); + p->np_state = NDIS_PSTATE_RUNNING; + while(STAILQ_FIRST(p->np_q) != NULL) { + r = STAILQ_FIRST(p->np_q); + STAILQ_REMOVE_HEAD(p->np_q, link); + mtx_unlock_spin(&ndis_thr_mtx); + + /* Do the work. */ + + if (r->nr_func != NULL) + (*r->nr_func)(r->nr_arg); + + mtx_lock_spin(&ndis_thr_mtx); + STAILQ_INSERT_HEAD(&ndis_free, r, link); + + /* Check for a shutdown request */ + + if (r->nr_exit == TRUE) + die = r; + } + p->np_state = NDIS_PSTATE_SLEEPING; + mtx_unlock_spin(&ndis_thr_mtx); + + /* Bail if we were told to shut down. */ + + if (die != NULL) + break; + } + + wakeup(die); +#if __FreeBSD_version < 502113 + mtx_lock(&Giant); +#endif + kthread_exit(0); + return; /* notreached */ +} + +static int +ndis_create_kthreads() +{ + struct ndis_req *r; + int i, error = 0; + + mtx_init(&ndis_thr_mtx, "NDIS thread lock", NULL, MTX_SPIN); + mtx_init(&ndis_req_mtx, "NDIS request lock", MTX_NDIS_LOCK, MTX_DEF); + + STAILQ_INIT(&ndis_ttodo); + STAILQ_INIT(&ndis_itodo); + STAILQ_INIT(&ndis_free); + + for (i = 0; i < ndis_jobs; i++) { + r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); + if (r == NULL) { + error = ENOMEM; + break; + } + STAILQ_INSERT_HEAD(&ndis_free, r, link); + } + + if (error == 0) { + ndis_tproc.np_q = &ndis_ttodo; + ndis_tproc.np_state = NDIS_PSTATE_SLEEPING; + error = kthread_create(ndis_runq, &ndis_tproc, + &ndis_tproc.np_p, RFHIGHPID, + NDIS_KSTACK_PAGES, "ndis taskqueue"); + } + + if (error == 0) { + ndis_iproc.np_q = &ndis_itodo; + ndis_iproc.np_state = NDIS_PSTATE_SLEEPING; + error = kthread_create(ndis_runq, &ndis_iproc, + &ndis_iproc.np_p, RFHIGHPID, + NDIS_KSTACK_PAGES, "ndis swi"); + } + + if (error) { + while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { + STAILQ_REMOVE_HEAD(&ndis_free, link); + free(r, M_DEVBUF); + } + return(error); + } + + return(0); +} + +static void +ndis_destroy_kthreads() +{ + struct ndis_req *r; + + /* Stop the threads. */ + + ndis_stop_thread(NDIS_TASKQUEUE); + ndis_stop_thread(NDIS_SWI); + + /* Destroy request structures. */ + + while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { + STAILQ_REMOVE_HEAD(&ndis_free, link); + free(r, M_DEVBUF); + } + + mtx_destroy(&ndis_req_mtx); + mtx_destroy(&ndis_thr_mtx); + + return; +} + +static void +ndis_stop_thread(t) + int t; +{ + struct ndis_req *r; + struct ndisqhead *q; + struct proc *p; + + if (t == NDIS_TASKQUEUE) { + q = &ndis_ttodo; + p = ndis_tproc.np_p; + } else { + q = &ndis_itodo; + p = ndis_iproc.np_p; + } + + /* Create and post a special 'exit' job. */ + + mtx_lock_spin(&ndis_thr_mtx); + r = STAILQ_FIRST(&ndis_free); + STAILQ_REMOVE_HEAD(&ndis_free, link); + r->nr_func = NULL; + r->nr_arg = NULL; + r->nr_exit = TRUE; + STAILQ_INSERT_TAIL(q, r, link); + mtx_unlock_spin(&ndis_thr_mtx); + + ndis_thresume(p); + + /* wait for thread exit */ + + tsleep(r, curthread->td_priority|PCATCH, "ndisthexit", hz * 60); + + /* Now empty the job list. */ + + mtx_lock_spin(&ndis_thr_mtx); + while ((r = STAILQ_FIRST(q)) != NULL) { + STAILQ_REMOVE_HEAD(q, link); + STAILQ_INSERT_HEAD(&ndis_free, r, link); + } + mtx_unlock_spin(&ndis_thr_mtx); + + return; +} + +static int +ndis_enlarge_thrqueue(cnt) + int cnt; +{ + struct ndis_req *r; + int i; + + for (i = 0; i < cnt; i++) { + r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); + if (r == NULL) + return(ENOMEM); + mtx_lock_spin(&ndis_thr_mtx); + STAILQ_INSERT_HEAD(&ndis_free, r, link); + ndis_jobs++; + mtx_unlock_spin(&ndis_thr_mtx); + } + + return(0); +} + +static int +ndis_shrink_thrqueue(cnt) + int cnt; +{ + struct ndis_req *r; + int i; + + for (i = 0; i < cnt; i++) { + mtx_lock_spin(&ndis_thr_mtx); + r = STAILQ_FIRST(&ndis_free); + if (r == NULL) { + mtx_unlock_spin(&ndis_thr_mtx); + return(ENOMEM); + } + STAILQ_REMOVE_HEAD(&ndis_free, link); + ndis_jobs--; + mtx_unlock_spin(&ndis_thr_mtx); + free(r, M_DEVBUF); + } + + return(0); +} + +int +ndis_unsched(func, arg, t) + void (*func)(void *); + void *arg; + int t; +{ + struct ndis_req *r; + struct ndisqhead *q; + struct proc *p; + + if (t == NDIS_TASKQUEUE) { + q = &ndis_ttodo; + p = ndis_tproc.np_p; + } else { + q = &ndis_itodo; + p = ndis_iproc.np_p; + } + + mtx_lock_spin(&ndis_thr_mtx); + STAILQ_FOREACH(r, q, link) { + if (r->nr_func == func && r->nr_arg == arg) { + STAILQ_REMOVE(q, r, ndis_req, link); + STAILQ_INSERT_HEAD(&ndis_free, r, link); + mtx_unlock_spin(&ndis_thr_mtx); + return(0); + } + } + + mtx_unlock_spin(&ndis_thr_mtx); + + return(ENOENT); +} + +int +ndis_sched(func, arg, t) + void (*func)(void *); + void *arg; + int t; +{ + struct ndis_req *r; + struct ndisqhead *q; + struct proc *p; + int s; + + if (t == NDIS_TASKQUEUE) { + q = &ndis_ttodo; + p = ndis_tproc.np_p; + } else { + q = &ndis_itodo; + p = ndis_iproc.np_p; + } + + mtx_lock_spin(&ndis_thr_mtx); + /* + * Check to see if an instance of this job is already + * pending. If so, don't bother queuing it again. + */ + STAILQ_FOREACH(r, q, link) { + if (r->nr_func == func && r->nr_arg == arg) { + mtx_unlock_spin(&ndis_thr_mtx); + return(0); + } + } + r = STAILQ_FIRST(&ndis_free); + if (r == NULL) { + mtx_unlock_spin(&ndis_thr_mtx); + return(EAGAIN); + } + STAILQ_REMOVE_HEAD(&ndis_free, link); + r->nr_func = func; + r->nr_arg = arg; + r->nr_exit = FALSE; + STAILQ_INSERT_TAIL(q, r, link); + if (t == NDIS_TASKQUEUE) + s = ndis_tproc.np_state; + else + s = ndis_iproc.np_state; + mtx_unlock_spin(&ndis_thr_mtx); + + /* + * Post the job, but only if the thread is actually blocked + * on its own suspend call. If a driver queues up a job with + * NdisScheduleWorkItem() which happens to do a KeWaitForObject(), + * it may suspend there, and in that case we don't want to wake + * it up until KeWaitForObject() gets woken up on its own. + */ + if (s == NDIS_PSTATE_SLEEPING) + ndis_thresume(p); + + return(0); +} + +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; +} + +__stdcall static void +ndis_sendrsrcavail_func(adapter) + ndis_handle adapter; +{ + return; +} + +__stdcall static void +ndis_status_func(adapter, status, sbuf, slen) + ndis_handle adapter; + ndis_status status; + void *sbuf; + uint32_t slen; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ifnet *ifp; + + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = &sc->arpcom.ac_if; + if (ifp->if_flags & IFF_DEBUG) + device_printf (sc->ndis_dev, "status: %x\n", status); + return; +} + +__stdcall static void +ndis_statusdone_func(adapter) + ndis_handle adapter; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ifnet *ifp; + + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = &sc->arpcom.ac_if; + if (ifp->if_flags & IFF_DEBUG) + device_printf (sc->ndis_dev, "status complete\n"); + return; +} + +__stdcall static void +ndis_setdone_func(adapter, status) + ndis_handle adapter; + ndis_status status; +{ + ndis_miniport_block *block; + block = adapter; + + block->nmb_setstat = status; + wakeup(&block->nmb_setstat); + return; +} + +__stdcall static void +ndis_getdone_func(adapter, status) + ndis_handle adapter; + ndis_status status; +{ + ndis_miniport_block *block; + block = adapter; + + block->nmb_getstat = status; + wakeup(&block->nmb_getstat); + return; +} + +__stdcall static void +ndis_resetdone_func(adapter, status, addressingreset) + ndis_handle adapter; + ndis_status status; + uint8_t addressingreset; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ifnet *ifp; + + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = &sc->arpcom.ac_if; + + if (ifp->if_flags & IFF_DEBUG) + device_printf (sc->ndis_dev, "reset done...\n"); + wakeup(sc); + return; +} + +int +ndis_create_sysctls(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_cfg *vals; + char buf[256]; + struct sysctl_oid *oidp; + struct sysctl_ctx_entry *e; + + if (arg == NULL) + return(EINVAL); + + sc = arg; + vals = sc->ndis_regvals; + + TAILQ_INIT(&sc->ndis_cfglist_head); + +#if __FreeBSD_version < 502113 + /* Create the sysctl tree. */ + + sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, + SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, + device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, + device_get_desc(sc->ndis_dev)); + +#endif + /* Add the driver-specific registry keys. */ + + vals = sc->ndis_regvals; + while(1) { + if (vals->nc_cfgkey == NULL) + break; + if (vals->nc_idx != sc->ndis_devidx) { + vals++; + continue; + } + + /* See if we already have a sysctl with this name */ + + oidp = NULL; +#if __FreeBSD_version < 502113 + TAILQ_FOREACH(e, &sc->ndis_ctx, link) { +#else + TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { +#endif + oidp = e->entry; + if (ndis_strcasecmp(oidp->oid_name, + vals->nc_cfgkey) == 0) + break; + oidp = NULL; + } + + if (oidp != NULL) { + vals++; + 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); + vals++; + } + + /* Now add a couple of builtin keys. */ + + /* + * Environment can be either Windows (0) or WindowsNT (1). + * We qualify as the latter. + */ + ndis_add_sysctl(sc, "Environment", + "Windows environment", "1", CTLFLAG_RD); + + /* NDIS version should be 5.1. */ + ndis_add_sysctl(sc, "NdisVersion", + "NDIS API Version", "0x00050001", CTLFLAG_RD); + + /* Bus type (PCI, PCMCIA, etc...) */ + sprintf(buf, "%d", (int)sc->ndis_iftype); + ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); + + if (sc->ndis_res_io != NULL) { + sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); + ndis_add_sysctl(sc, "IOBaseAddress", + "Base I/O Address", buf, CTLFLAG_RD); + } + + if (sc->ndis_irq != NULL) { + sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); + ndis_add_sysctl(sc, "InterruptNumber", + "Interrupt Number", buf, CTLFLAG_RD); + } + + return(0); +} + +int +ndis_add_sysctl(arg, key, desc, val, flag) + void *arg; + char *key; + char *desc; + char *val; + int flag; +{ + struct ndis_softc *sc; + struct ndis_cfglist *cfg; + char descstr[256]; + + sc = arg; + + cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); + + if (cfg == NULL) + return(ENOMEM); + + cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); + if (desc == NULL) { + snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); + cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); + } else + cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); + strcpy(cfg->ndis_cfg.nc_val, val); + + TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); + +#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, cfg->ndis_cfg.nc_cfgkey, flag, + cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), + cfg->ndis_cfg.nc_cfgdesc); + + return(0); +} + +int +ndis_flush_sysctls(arg) + void *arg; +{ + struct ndis_softc *sc; + struct ndis_cfglist *cfg; + + sc = arg; + + while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { + cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); + TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); + free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); + free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); + free(cfg, M_DEVBUF); + } + + return(0); +} + +static void +ndis_return(arg) + void *arg; +{ + struct ndis_softc *sc; + __stdcall ndis_return_handler returnfunc; + ndis_handle adapter; + ndis_packet *p; + uint8_t irql; + + p = arg; + sc = p->np_softc; + adapter = sc->ndis_block->nmb_miniportadapterctx; + + if (adapter == NULL) + return; + + returnfunc = sc->ndis_chars->nmc_return_packet_func; + + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + MSCALL2(returnfunc, adapter, p); + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + return; +} + +void +ndis_return_packet(buf, arg) + void *buf; /* not used */ + void *arg; +{ + ndis_packet *p; + + if (arg == NULL) + return; + + p = arg; + + /* Decrement refcount. */ + p->np_refcnt--; + + /* Release packet when refcount hits zero, otherwise return. */ + if (p->np_refcnt) + return; + + ndis_sched(ndis_return, p, NDIS_TASKQUEUE); + + return; +} + +void +ndis_free_bufs(b0) + ndis_buffer *b0; +{ + ndis_buffer *next; + + if (b0 == NULL) + return; + + while(b0 != NULL) { + next = b0->mdl_next; + IoFreeMdl(b0); + b0 = next; + } + + return; +} +int in_reset = 0; +void +ndis_free_packet(p) + ndis_packet *p; +{ + if (p == NULL) + return; + + ndis_free_bufs(p->np_private.npp_head); + NdisFreePacket(p); + return; +} + +int +ndis_convert_res(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_resource_list *rl = NULL; + cm_partial_resource_desc *prd = NULL; + ndis_miniport_block *block; + device_t dev; + struct resource_list *brl; + struct resource_list_entry *brle; +#if __FreeBSD_version < 600022 + struct resource_list brl_rev; + struct resource_list_entry *n; +#endif + int error = 0; + + sc = arg; + block = sc->ndis_block; + dev = sc->ndis_dev; + +#if __FreeBSD_version < 600022 + SLIST_INIT(&brl_rev); +#endif + + rl = malloc(sizeof(ndis_resource_list) + + (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (rl == NULL) + return(ENOMEM); + + rl->cprl_version = 5; + rl->cprl_version = 1; + rl->cprl_count = sc->ndis_rescnt; + prd = rl->cprl_partial_descs; + + brl = BUS_GET_RESOURCE_LIST(dev, dev); + + if (brl != NULL) { + +#if __FreeBSD_version < 600022 + /* + * We have a small problem. Some PCI devices have + * multiple I/O ranges. Windows orders them starting + * from lowest numbered BAR to highest. We discover + * them in that order too, but insert them into a singly + * linked list head first, which means when time comes + * to traverse the list, we enumerate them in reverse + * order. This screws up some drivers which expect the + * BARs to be in ascending order so that they can choose + * the "first" one as their register space. Unfortunately, + * in order to fix this, we have to create our own + * temporary list with the entries in reverse order. + */ + SLIST_FOREACH(brle, brl, link) { + n = malloc(sizeof(struct resource_list_entry), + M_TEMP, M_NOWAIT); + if (n == NULL) { + error = ENOMEM; + goto bad; + } + bcopy((char *)brle, (char *)n, + sizeof(struct resource_list_entry)); + SLIST_INSERT_HEAD(&brl_rev, n, link); + } + + SLIST_FOREACH(brle, &brl_rev, link) { +#else + STAILQ_FOREACH(brle, brl, link) { +#endif + switch (brle->type) { + case SYS_RES_IOPORT: + prd->cprd_type = CmResourceTypePort; + prd->cprd_flags = CM_RESOURCE_PORT_IO; + prd->cprd_sharedisp = + CmResourceShareDeviceExclusive; + prd->u.cprd_port.cprd_start.np_quad = + brle->start; + prd->u.cprd_port.cprd_len = brle->count; + break; + case SYS_RES_MEMORY: + prd->cprd_type = CmResourceTypeMemory; + prd->cprd_flags = + CM_RESOURCE_MEMORY_READ_WRITE; + prd->cprd_sharedisp = + CmResourceShareDeviceExclusive; + prd->u.cprd_port.cprd_start.np_quad = + brle->start; + prd->u.cprd_port.cprd_len = brle->count; + break; + case SYS_RES_IRQ: + prd->cprd_type = CmResourceTypeInterrupt; + prd->cprd_flags = 0; + prd->cprd_sharedisp = + CmResourceShareDeviceExclusive; + prd->u.cprd_intr.cprd_level = brle->start; + prd->u.cprd_intr.cprd_vector = brle->start; + prd->u.cprd_intr.cprd_affinity = 0; + break; + default: + break; + } + prd++; + } + } + + block->nmb_rlist = rl; + +#if __FreeBSD_version < 600022 +bad: + + while (!SLIST_EMPTY(&brl_rev)) { + n = SLIST_FIRST(&brl_rev); + SLIST_REMOVE_HEAD(&brl_rev, link); + free (n, M_TEMP); + } +#endif + + return(error); +} + +/* + * Map an NDIS packet to an mbuf list. When an NDIS driver receives a + * packet, it will hand it to us in the form of an ndis_packet, + * which we need to convert to an mbuf that is then handed off + * to the stack. Note: we configure the mbuf list so that it uses + * the memory regions specified by the ndis_buffer structures in + * the ndis_packet as external storage. In most cases, this will + * point to a memory region allocated by the driver (either by + * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect + * the driver to handle free()ing this region for is, so we set up + * a dummy no-op free handler for it. + */ + +int +ndis_ptom(m0, p) + struct mbuf **m0; + ndis_packet *p; +{ + struct mbuf *m, *prev = NULL; + ndis_buffer *buf; + ndis_packet_private *priv; + uint32_t totlen = 0; + + if (p == NULL || m0 == NULL) + return(EINVAL); + + priv = &p->np_private; + buf = priv->npp_head; + p->np_refcnt = 0; + + for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { + if (buf == priv->npp_head) + MGETHDR(m, M_DONTWAIT, MT_HEADER); + else + MGET(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + m_freem(*m0); + *m0 = NULL; + return(ENOBUFS); + } + m->m_len = MmGetMdlByteCount(buf); + m->m_data = MmGetMdlVirtualAddress(buf); + 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 & MT_HEADER) + *m0 = m; + else + prev->m_next = m; + prev = m; + } + + (*m0)->m_pkthdr.len = totlen; + + return(0); +} + +/* + * Create an NDIS packet from an mbuf chain. + * This is used mainly when transmitting packets, where we need + * to turn an mbuf off an interface's send queue and transform it + * into an NDIS packet which will be fed into the NDIS driver's + * send routine. + * + * NDIS packets consist of two parts: an ndis_packet structure, + * which is vaguely analagous to the pkthdr portion of an mbuf, + * and one or more ndis_buffer structures, which define the + * actual memory segments in which the packet data resides. + * We need to allocate one ndis_buffer for each mbuf in a chain, + * plus one ndis_packet as the header. + */ + +int +ndis_mtop(m0, p) + struct mbuf *m0; + ndis_packet **p; +{ + struct mbuf *m; + ndis_buffer *buf = NULL, *prev = NULL; + ndis_packet_private *priv; + + if (p == NULL || *p == NULL || m0 == NULL) + return(EINVAL); + + priv = &(*p)->np_private; + priv->npp_totlen = m0->m_pkthdr.len; + + for (m = m0; m != NULL; m = m->m_next) { + if (m->m_len == 0) + continue; + buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); + if (buf == NULL) { + ndis_free_packet(*p); + *p = NULL; + return(ENOMEM); + } + + if (priv->npp_head == NULL) + priv->npp_head = buf; + else + prev->mdl_next = buf; + prev = buf; + } + + priv->npp_tail = buf; + + return(0); +} + +int +ndis_get_supported_oids(arg, oids, oidcnt) + void *arg; + ndis_oid **oids; + int *oidcnt; +{ + int len, rval; + ndis_oid *o; + + if (arg == NULL || oids == NULL || oidcnt == NULL) + return(EINVAL); + len = 0; + ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); + + o = malloc(len, M_DEVBUF, M_NOWAIT); + if (o == NULL) + return(ENOMEM); + + rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); + + if (rval) { + free(o, M_DEVBUF); + return(rval); + } + + *oids = o; + *oidcnt = len / 4; + + return(0); +} + +int +ndis_set_info(arg, oid, buf, buflen) + void *arg; + ndis_oid oid; + void *buf; + int *buflen; +{ + struct ndis_softc *sc; + ndis_status rval; + ndis_handle adapter; + __stdcall ndis_setinfo_handler setfunc; + uint32_t byteswritten = 0, bytesneeded = 0; + int error; + uint8_t irql; + + /* + * According to the NDIS spec, MiniportQueryInformation() + * and MiniportSetInformation() requests are handled serially: + * once one request has been issued, we must wait for it to + * finish before allowing another request to proceed. + */ + + sc = arg; + + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + if (sc->ndis_block->nmb_pendingreq != NULL) + panic("ndis_set_info() called while other request pending"); + else + sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; + + setfunc = sc->ndis_chars->nmc_setinfo_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; + + if (adapter == NULL || setfunc == NULL) { + sc->ndis_block->nmb_pendingreq = NULL; + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + return(ENXIO); + } + + rval = MSCALL6(setfunc, adapter, oid, buf, *buflen, + &byteswritten, &bytesneeded); + + sc->ndis_block->nmb_pendingreq = NULL; + + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + if (rval == NDIS_STATUS_PENDING) { + mtx_lock(&ndis_req_mtx); + error = msleep(&sc->ndis_block->nmb_setstat, + &ndis_req_mtx, + curthread->td_priority|PDROP, + "ndisset", 5 * hz); + rval = sc->ndis_block->nmb_setstat; + } + + + if (byteswritten) + *buflen = byteswritten; + if (bytesneeded) + *buflen = bytesneeded; + + if (rval == NDIS_STATUS_INVALID_LENGTH) + return(ENOSPC); + + if (rval == NDIS_STATUS_INVALID_OID) + return(EINVAL); + + if (rval == NDIS_STATUS_NOT_SUPPORTED || + rval == NDIS_STATUS_NOT_ACCEPTED) + return(ENOTSUP); + + if (rval != NDIS_STATUS_SUCCESS) + return(ENODEV); + + return(0); +} + +typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); + +int +ndis_send_packets(arg, packets, cnt) + void *arg; + ndis_packet **packets; + int cnt; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_sendmulti_handler sendfunc; + __stdcall ndis_senddone_func senddonefunc; + int i; + ndis_packet *p; + uint8_t irql; + + sc = arg; + adapter = sc->ndis_block->nmb_miniportadapterctx; + if (adapter == NULL) + return(ENXIO); + sendfunc = sc->ndis_chars->nmc_sendmulti_func; + senddonefunc = sc->ndis_block->nmb_senddone_func; + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + MSCALL3(sendfunc, adapter, packets, cnt); + + for (i = 0; i < cnt; i++) { + p = packets[i]; + /* + * Either the driver already handed the packet to + * ndis_txeof() due to a failure, or it wants to keep + * it and release it asynchronously later. Skip to the + * next one. + */ + if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) + continue; + MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status); + } + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + return(0); +} + +int +ndis_send_packet(arg, packet) + void *arg; + ndis_packet *packet; +{ + struct ndis_softc *sc; + ndis_handle adapter; + ndis_status status; + __stdcall ndis_sendsingle_handler sendfunc; + __stdcall ndis_senddone_func senddonefunc; + uint8_t irql; + + sc = arg; + adapter = sc->ndis_block->nmb_miniportadapterctx; + if (adapter == NULL) + return(ENXIO); + sendfunc = sc->ndis_chars->nmc_sendsingle_func; + senddonefunc = sc->ndis_block->nmb_senddone_func; + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + status = MSCALL3(sendfunc, adapter, packet, + packet->np_private.npp_flags); + + if (status == NDIS_STATUS_PENDING) { + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + return(0); + } + + MSCALL3(senddonefunc, sc->ndis_block, packet, status); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + return(0); +} + +int +ndis_init_dma(arg) + void *arg; +{ + struct ndis_softc *sc; + int i, error; + + sc = arg; + + sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (sc->ndis_tmaps == NULL) + return(ENOMEM); + + for (i = 0; i < sc->ndis_maxpkts; i++) { + error = bus_dmamap_create(sc->ndis_ttag, 0, + &sc->ndis_tmaps[i]); + if (error) { + free(sc->ndis_tmaps, M_DEVBUF); + return(ENODEV); + } + } + + return(0); +} + +int +ndis_destroy_dma(arg) + void *arg; +{ + struct ndis_softc *sc; + struct mbuf *m; + ndis_packet *p = NULL; + int i; + + sc = arg; + + for (i = 0; i < sc->ndis_maxpkts; i++) { + if (sc->ndis_txarray[i] != NULL) { + p = sc->ndis_txarray[i]; + m = (struct mbuf *)p->np_rsvd[1]; + if (m != NULL) + m_freem(m); + ndis_free_packet(sc->ndis_txarray[i]); + } + bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); + } + + free(sc->ndis_tmaps, M_DEVBUF); + + bus_dma_tag_destroy(sc->ndis_ttag); + + return(0); +} + +int +ndis_reset_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_reset_handler resetfunc; + uint8_t addressing_reset; + struct ifnet *ifp; + int rval; + uint8_t irql; + + sc = arg; + ifp = &sc->arpcom.ac_if; + + adapter = sc->ndis_block->nmb_miniportadapterctx; + resetfunc = sc->ndis_chars->nmc_reset_func; + + if (adapter == NULL || resetfunc == NULL) + return(EIO); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + rval = MSCALL2(resetfunc, &addressing_reset, adapter); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + if (rval == NDIS_STATUS_PENDING) { + mtx_lock(&ndis_req_mtx); + msleep(sc, &ndis_req_mtx, + curthread->td_priority|PDROP, "ndisrst", 0); + } + + return(0); +} + +int +ndis_halt_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_halt_handler haltfunc; + struct ifnet *ifp; + + sc = arg; + ifp = &sc->arpcom.ac_if; + + NDIS_LOCK(sc); + adapter = sc->ndis_block->nmb_miniportadapterctx; + if (adapter == NULL) { + NDIS_UNLOCK(sc); + return(EIO); + } + + /* + * The adapter context is only valid after the init + * handler has been called, and is invalid once the + * halt handler has been called. + */ + + haltfunc = sc->ndis_chars->nmc_halt_func; + NDIS_UNLOCK(sc); + + MSCALL1(haltfunc, adapter); + + NDIS_LOCK(sc); + sc->ndis_block->nmb_miniportadapterctx = NULL; + NDIS_UNLOCK(sc); + + return(0); +} + +int +ndis_shutdown_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_shutdown_handler shutdownfunc; + + sc = arg; + NDIS_LOCK(sc); + adapter = sc->ndis_block->nmb_miniportadapterctx; + shutdownfunc = sc->ndis_chars->nmc_shutdown_handler; + NDIS_UNLOCK(sc); + if (adapter == NULL || shutdownfunc == NULL) + return(EIO); + + if (sc->ndis_chars->nmc_rsvd0 == NULL) + MSCALL1(shutdownfunc, adapter); + else + MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0); + + ndis_shrink_thrqueue(8); + TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); + + return(0); +} + +int +ndis_init_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + __stdcall ndis_init_handler initfunc; + ndis_status status, openstatus = 0; + ndis_medium mediumarray[NdisMediumMax]; + uint32_t chosenmedium, i; + + if (arg == NULL) + return(EINVAL); + + sc = arg; + NDIS_LOCK(sc); + block = sc->ndis_block; + initfunc = sc->ndis_chars->nmc_init_func; + NDIS_UNLOCK(sc); + + for (i = 0; i < NdisMediumMax; i++) + mediumarray[i] = i; + + status = MSCALL6(initfunc, &openstatus, &chosenmedium, + mediumarray, NdisMediumMax, block, block); + + /* + * If the init fails, blow away the other exported routines + * we obtained from the driver so we can't call them later. + * If the init failed, none of these will work. + */ + if (status != NDIS_STATUS_SUCCESS) { + NDIS_LOCK(sc); + sc->ndis_block->nmb_miniportadapterctx = NULL; + NDIS_UNLOCK(sc); + return(ENXIO); + } + + return(0); +} + +void +ndis_enable_intr(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_enable_interrupts_handler intrenbfunc; + + sc = arg; + adapter = sc->ndis_block->nmb_miniportadapterctx; + intrenbfunc = sc->ndis_chars->nmc_enable_interrupts_func; + if (adapter == NULL || intrenbfunc == NULL) + return; + MSCALL1(intrenbfunc, adapter); + + return; +} + +void +ndis_disable_intr(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_disable_interrupts_handler intrdisfunc; + + sc = arg; + adapter = sc->ndis_block->nmb_miniportadapterctx; + intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func; + if (adapter == NULL || intrdisfunc == NULL) + return; + + MSCALL1(intrdisfunc, adapter); + + return; +} + +int +ndis_isr(arg, ourintr, callhandler) + void *arg; + int *ourintr; + int *callhandler; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_isr_handler isrfunc; + uint8_t accepted, queue; + + if (arg == NULL || ourintr == NULL || callhandler == NULL) + return(EINVAL); + + sc = arg; + adapter = sc->ndis_block->nmb_miniportadapterctx; + isrfunc = sc->ndis_chars->nmc_isr_func; + + if (adapter == NULL || isrfunc == NULL) + return(ENXIO); + + MSCALL3(isrfunc, &accepted, &queue, adapter); + + *ourintr = accepted; + *callhandler = queue; + + return(0); +} + +__stdcall static void +ndis_intrhand(dpc, dobj, ip, sc) + kdpc *dpc; + device_object *dobj; + irp *ip; + struct ndis_softc *sc; +{ + ndis_handle adapter; + __stdcall 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); + + MSCALL1(intrfunc, adapter); + + /* If there's a MiniportEnableInterrupt() routine, call it. */ + + ndis_enable_intr(sc); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + return; +} + +int +ndis_get_info(arg, oid, buf, buflen) + void *arg; + ndis_oid oid; + void *buf; + int *buflen; +{ + struct ndis_softc *sc; + ndis_status rval; + ndis_handle adapter; + __stdcall ndis_queryinfo_handler queryfunc; + uint32_t byteswritten = 0, bytesneeded = 0; + int error; + uint8_t irql; + + sc = arg; + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + if (sc->ndis_block->nmb_pendingreq != NULL) + panic("ndis_get_info() called while other request pending"); + else + sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; + + queryfunc = sc->ndis_chars->nmc_queryinfo_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; + + if (adapter == NULL || queryfunc == NULL) { + sc->ndis_block->nmb_pendingreq = NULL; + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + return(ENXIO); + } + + rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, + &byteswritten, &bytesneeded); + + sc->ndis_block->nmb_pendingreq = NULL; + + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + /* Wait for requests that block. */ + + if (rval == NDIS_STATUS_PENDING) { + mtx_lock(&ndis_req_mtx); + error = msleep(&sc->ndis_block->nmb_getstat, + &ndis_req_mtx, + curthread->td_priority|PDROP, + "ndisget", 5 * hz); + rval = sc->ndis_block->nmb_getstat; + } + + if (byteswritten) + *buflen = byteswritten; + if (bytesneeded) + *buflen = bytesneeded; + + if (rval == NDIS_STATUS_INVALID_LENGTH || + rval == NDIS_STATUS_BUFFER_TOO_SHORT) + return(ENOSPC); + + if (rval == NDIS_STATUS_INVALID_OID) + return(EINVAL); + + if (rval == NDIS_STATUS_NOT_SUPPORTED || + rval == NDIS_STATUS_NOT_ACCEPTED) + return(ENOTSUP); + + if (rval != NDIS_STATUS_SUCCESS) + return(ENODEV); + + return(0); +} + +__stdcall uint32_t +NdisAddDevice(drv, pdo) + driver_object *drv; + device_object *pdo; +{ + device_object *fdo; + ndis_miniport_block *block; + struct ndis_softc *sc; + uint32_t status; + + status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, + FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); + + if (status != STATUS_SUCCESS) + return(status); + + block = fdo->do_devext; + block->nmb_deviceobj = fdo; + block->nmb_physdeviceobj = pdo; + block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); + KeInitializeSpinLock(&block->nmb_lock); + + /* + * Stash pointers to the miniport block and miniport + * characteristics info in the if_ndis softc so the + * UNIX wrapper driver can get to them later. + */ + sc = device_get_softc(pdo->do_devext); + sc->ndis_block = block; + sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); + + IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap); + + /* Finish up BSD-specific setup. */ + + block->nmb_signature = (void *)0xcafebabe; + block->nmb_status_func = kernndis_functbl[0].ipt_wrap; + block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap; + block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap; + block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; + block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; + block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; + block->nmb_pendingreq = NULL; + + ndis_enlarge_thrqueue(8); + + TAILQ_INSERT_TAIL(&ndis_devhead, block, link); + + return (STATUS_SUCCESS); +} + +int +ndis_unload_driver(arg) + void *arg; +{ + struct ndis_softc *sc; + device_object *fdo; + + sc = arg; + + if (sc->ndis_block->nmb_rlist != NULL) + free(sc->ndis_block->nmb_rlist, M_DEVBUF); + + ndis_flush_sysctls(sc); + + ndis_shrink_thrqueue(8); + TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); + + fdo = sc->ndis_block->nmb_deviceobj; + IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); + IoDeleteDevice(fdo); + + return(0); +} diff --git a/sys/compat/ndis/kern_windrv.c b/sys/compat/ndis/kern_windrv.c new file mode 100644 index 000000000000..380ea102ab37 --- /dev/null +++ b/sys/compat/ndis/kern_windrv.c @@ -0,0 +1,485 @@ +/*- + * Copyright (c) 2005 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.3.2.2 2005/03/31 04:24:35 wpaul Exp $"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +struct windrv_type { + uint16_t windrv_vid; /* for PCI or USB */ + uint16_t windrv_did; /* for PCI or USB */ + uint32_t windrv_subsys; /* for PCI */ + char *windrv_vname; /* for pccard */ + char *windrv_dname; /* for pccard */ + char *windrv_name; /* for pccard, PCI or USB */ +}; + +struct drvdb_ent { + driver_object *windrv_object; + struct windrv_type *windrv_devlist; + ndis_cfg *windrv_regvals; + STAILQ_ENTRY(drvdb_ent) link; +}; + +struct mtx drvdb_mtx; +static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head; + +static driver_object fake_pci_driver; /* serves both PCI and cardbus */ +static driver_object fake_pccard_driver; + + +#define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path" + +int +windrv_libinit(void) +{ + STAILQ_INIT(&drvdb_head); + mtx_init(&drvdb_mtx, "Windows driver DB lock", + "Windows internal lock", MTX_DEF); + + /* + * PCI and pccard devices don't need to use IRPs to + * interact with their bus drivers (usually), so our + * emulated PCI and pccard drivers are just stubs. + * USB devices, on the other hand, do all their I/O + * by exchanging IRPs with the USB bus driver, so + * for that we need to provide emulator dispatcher + * routines, which are in a separate module. + */ + + windrv_bus_attach(&fake_pci_driver, "PCI Bus"); + windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus"); + + return(0); +} + +int +windrv_libfini(void) +{ + struct drvdb_ent *d; + + mtx_lock(&drvdb_mtx); + while(STAILQ_FIRST(&drvdb_head) != NULL) { + d = STAILQ_FIRST(&drvdb_head); + STAILQ_REMOVE_HEAD(&drvdb_head, link); + free(d, M_DEVBUF); + } + mtx_unlock(&drvdb_mtx); + + free(fake_pci_driver.dro_drivername.us_buf, M_DEVBUF); + free(fake_pccard_driver.dro_drivername.us_buf, M_DEVBUF); + + mtx_destroy(&drvdb_mtx); + return(0); +} + +/* + * Given the address of a driver image, find its corresponding + * driver_object. + */ + +driver_object * +windrv_lookup(img, name) + vm_offset_t img; + char *name; +{ + struct drvdb_ent *d; + unicode_string 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); + } + + mtx_lock(&drvdb_mtx); + STAILQ_FOREACH(d, &drvdb_head, link) { + if (d->windrv_object->dro_driverstart == (void *)img || + bcmp((char *)d->windrv_object->dro_drivername.us_buf, + (char *)us.us_buf, us.us_len) == 0) { + mtx_unlock(&drvdb_mtx); + return(d->windrv_object); + } + } + mtx_unlock(&drvdb_mtx); + + if (name != NULL) + ExFreePool(us.us_buf); + + return(NULL); +} + +/* + * Remove a driver_object from our datatabase and destroy it. Throw + * away any custom driver extension info that may have been added. + */ + +int +windrv_unload(mod, img, len) + module_t mod; + vm_offset_t img; + int len; +{ + struct drvdb_ent *d, *r = NULL; + driver_object *drv; + list_entry *e, *c; + + mtx_lock(&drvdb_mtx); + STAILQ_FOREACH(d, &drvdb_head, link) { + if (d->windrv_object->dro_driverstart == (void *)img) { + r = d; + STAILQ_REMOVE(&drvdb_head, d, drvdb_ent, link); + break; + } + } + mtx_unlock(&drvdb_mtx); + + if (r == 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); + 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); + + /* Free driver object */ + free(drv, M_DEVBUF); + + /* Free our DB handle */ + free(r, M_DEVBUF); + + return(0); +} + +/* + * Loader routine for actual Windows driver modules, ultimately + * calls the driver's DriverEntry() routine. + */ + +int +windrv_load(mod, img, len) + module_t mod; + vm_offset_t img; + int len; +{ + image_import_descriptor imp_desc; + image_optional_header opt_hdr; + driver_entry entry; + struct drvdb_ent *new; + struct driver_object *drv; + int status; + + /* + * First step: try to relocate and dynalink the executable + * driver image. + */ + + /* Perform text relocation */ + if (pe_relocate(img)) + return(ENOEXEC); + + /* Dynamically link the NDIS.SYS routines -- required. */ + if (pe_patch_imports(img, "NDIS", ndis_functbl)) + return(ENOEXEC); + + /* Dynamically link the HAL.dll routines -- also required. */ + if (pe_patch_imports(img, "HAL", hal_functbl)) + return(ENOEXEC); + + /* Dynamically link ntoskrnl.exe -- optional. */ + if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) { + if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl)) + return(ENOEXEC); + } + + /* Dynamically link USBD.SYS -- optional */ + if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) { + if (pe_patch_imports(img, "USBD", usbd_functbl)) + return(ENOEXEC); + } + + /* Next step: find the driver entry point. */ + + pe_get_optional_header(img, &opt_hdr); + entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); + + /* Next step: allocate and store a driver object. */ + + new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT); + if (new == NULL) + return (ENOMEM); + + drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO); + if (drv == NULL) { + free (new, M_DEVBUF); + return (ENOMEM); + } + + /* Allocate a driver extension structure too. */ + + drv->dro_driverext = malloc(sizeof(driver_extension), + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (drv->dro_driverext == NULL) { + free(new, M_DEVBUF); + free(drv, M_DEVBUF); + return(ENOMEM); + } + + INIT_LIST_HEAD((&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); + + new->windrv_object = drv; + + /* Now call the DriverEntry() function. */ + + status = MSCALL2(entry, drv, &drv->dro_drivername); + + if (status != STATUS_SUCCESS) { + free(drv->dro_drivername.us_buf, M_DEVBUF); + free(drv, M_DEVBUF); + free(new, M_DEVBUF); + return(ENODEV); + } + + mtx_lock(&drvdb_mtx); + STAILQ_INSERT_HEAD(&drvdb_head, new, link); + mtx_unlock(&drvdb_mtx); + + return (0); +} + +/* + * Make a new Physical Device Object for a device that was + * detected/plugged in. For us, the PDO is just a way to + * get at the device_t. + */ + +int +windrv_create_pdo(drv, bsddev) + driver_object *drv; + device_t bsddev; +{ + device_object *dev; + + /* + * This is a new physical device object, which technically + * is the "top of the stack." Consequently, we don't do + * an IoAttachDeviceToDeviceStack() here. + */ + + mtx_lock(&drvdb_mtx); + IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev); + mtx_unlock(&drvdb_mtx); + + /* Stash pointer to our BSD device handle. */ + + dev->do_devext = bsddev; + + return(STATUS_SUCCESS); +} + +void +windrv_destroy_pdo(drv, bsddev) + driver_object *drv; + device_t bsddev; +{ + device_object *pdo; + + pdo = windrv_find_pdo(drv, bsddev); + + /* Remove reference to device_t */ + + pdo->do_devext = NULL; + + mtx_lock(&drvdb_mtx); + IoDeleteDevice(pdo); + mtx_unlock(&drvdb_mtx); + + return; +} + +/* + * Given a device_t, find the corresponding PDO in a driver's + * device list. + */ + +device_object * +windrv_find_pdo(drv, bsddev) + driver_object *drv; + device_t bsddev; +{ + device_object *pdo; + + mtx_lock(&drvdb_mtx); + pdo = drv->dro_devobj; + if (pdo->do_devext != bsddev) { + mtx_unlock(&drvdb_mtx); + panic("PDO wasn't first device in list"); + } + mtx_unlock(&drvdb_mtx); + + return(pdo); +} + +/* + * Add an internally emulated driver to the database. We need this + * to set up an emulated bus driver so that it can receive IRPs. + */ + +int +windrv_bus_attach(drv, name) + driver_object *drv; + char *name; +{ + struct drvdb_ent *new; + + new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT); + 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); + + new->windrv_object = drv; + new->windrv_devlist = NULL; + new->windrv_regvals = NULL; + + mtx_lock(&drvdb_mtx); + STAILQ_INSERT_HEAD(&drvdb_head, new, link); + mtx_unlock(&drvdb_mtx); + + return(0); +} + +#ifdef __amd64__ + +extern void x86_64_wrap(void); +extern void x86_64_wrap_call(void); +extern void x86_64_wrap_end(void); + +#endif /* __amd64__ */ + +int +windrv_wrap(func, wrap) + funcptr func; + funcptr *wrap; +{ +#ifdef __amd64__ + funcptr p; + vm_offset_t *calladdr; + vm_offset_t wrapstart, wrapend, wrapcall; + + wrapstart = (vm_offset_t)&x86_64_wrap; + wrapend = (vm_offset_t)&x86_64_wrap_end; + wrapcall = (vm_offset_t)&x86_64_wrap_call; + + /* Allocate a new wrapper instance. */ + + p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); + if (p == NULL) + return(ENOMEM); + + /* Copy over the code. */ + + bcopy((char *)wrapstart, p, (wrapend - wrapstart)); + + /* Insert the function address into the new wrapper instance. */ + + calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2); + *calladdr = (vm_offset_t)func; + + *wrap = p; +#else /* __amd64__ */ + *wrap = func; +#endif /* __amd64__ */ + return(0); +} + +int +windrv_unwrap(func) + funcptr func; +{ +#ifdef __amd64__ + free(func, M_DEVBUF); +#endif /* __amd64__ */ + return(0); +} diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h new file mode 100644 index 000000000000..281e7a02dc62 --- /dev/null +++ b/sys/compat/ndis/ndis_var.h @@ -0,0 +1,1609 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/compat/ndis/ndis_var.h,v 1.29.2.3 2005/03/31 04:24:35 wpaul Exp $ + */ + +#ifndef _NDIS_VAR_H_ +#define _NDIS_VAR_H_ + +/* Forward declarations */ +struct ndis_miniport_block; +struct ndis_mdriver_block; +typedef struct ndis_miniport_block ndis_miniport_block; +typedef struct ndis_mdriver_block ndis_mdriver_block; + +/* Base types */ +typedef uint32_t ndis_status; +typedef void *ndis_handle; +typedef uint32_t ndis_oid; +typedef uint32_t ndis_error_code; +typedef register_t ndis_kspin_lock; +typedef uint8_t ndis_kirql; + +/* + * NDIS status codes (there are lots of them). The ones that + * don't seem to fit the pattern are actually mapped to generic + * NT status codes. + */ + +#define NDIS_STATUS_SUCCESS 0 +#define NDIS_STATUS_PENDING 0x00000103 +#define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 +#define NDIS_STATUS_NOT_COPIED 0x00010002 +#define NDIS_STATUS_NOT_ACCEPTED 0x00010003 +#define NDIS_STATUS_CALL_ACTIVE 0x00010007 +#define NDIS_STATUS_ONLINE 0x40010003 +#define NDIS_STATUS_RESET_START 0x40010004 +#define NDIS_STATUS_RESET_END 0x40010005 +#define NDIS_STATUS_RING_STATUS 0x40010006 +#define NDIS_STATUS_CLOSED 0x40010007 +#define NDIS_STATUS_WAN_LINE_UP 0x40010008 +#define NDIS_STATUS_WAN_LINE_DOWN 0x40010009 +#define NDIS_STATUS_WAN_FRAGMENT 0x4001000A +#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B +#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C +#define NDIS_STATUS_HARDWARE_LINE_UP 0x4001000D +#define NDIS_STATUS_HARDWARE_LINE_DOWN 0x4001000E +#define NDIS_STATUS_INTERFACE_UP 0x4001000F +#define NDIS_STATUS_INTERFACE_DOWN 0x40010010 +#define NDIS_STATUS_MEDIA_BUSY 0x40010011 +#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 +#define NDIS_STATUS_WW_INDICATION NDIS_STATUS_MEDIA_SPECIFIC_INDICATION +#define NDIS_STATUS_LINK_SPEED_CHANGE 0x40010013 +#define NDIS_STATUS_WAN_GET_STATS 0x40010014 +#define NDIS_STATUS_WAN_CO_FRAGMENT 0x40010015 +#define NDIS_STATUS_WAN_CO_LINKPARAMS 0x40010016 +#define NDIS_STATUS_NOT_RESETTABLE 0x80010001 +#define NDIS_STATUS_SOFT_ERRORS 0x80010003 +#define NDIS_STATUS_HARD_ERRORS 0x80010004 +#define NDIS_STATUS_BUFFER_OVERFLOW 0x80000005 +#define NDIS_STATUS_FAILURE 0xC0000001 +#define NDIS_STATUS_RESOURCES 0xC000009A +#define NDIS_STATUS_CLOSING 0xC0010002 +#define NDIS_STATUS_BAD_VERSION 0xC0010004 +#define NDIS_STATUS_BAD_CHARACTERISTICS 0xC0010005 +#define NDIS_STATUS_ADAPTER_NOT_FOUND 0xC0010006 +#define NDIS_STATUS_OPEN_FAILED 0xC0010007 +#define NDIS_STATUS_DEVICE_FAILED 0xC0010008 +#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 +#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A +#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B +#define NDIS_STATUS_REQUEST_ABORTED 0xC001000C +#define NDIS_STATUS_RESET_IN_PROGRESS 0xC001000D +#define NDIS_STATUS_CLOSING_INDICATING 0xC001000E +#define NDIS_STATUS_NOT_SUPPORTED 0xC00000BB +#define NDIS_STATUS_INVALID_PACKET 0xC001000F +#define NDIS_STATUS_OPEN_LIST_FULL 0xC0010010 +#define NDIS_STATUS_ADAPTER_NOT_READY 0xC0010011 +#define NDIS_STATUS_ADAPTER_NOT_OPEN 0xC0010012 +#define NDIS_STATUS_NOT_INDICATING 0xC0010013 +#define NDIS_STATUS_INVALID_LENGTH 0xC0010014 +#define NDIS_STATUS_INVALID_DATA 0xC0010015 +#define NDIS_STATUS_BUFFER_TOO_SHORT 0xC0010016 +#define NDIS_STATUS_INVALID_OID 0xC0010017 +#define NDIS_STATUS_ADAPTER_REMOVED 0xC0010018 +#define NDIS_STATUS_UNSUPPORTED_MEDIA 0xC0010019 +#define NDIS_STATUS_GROUP_ADDRESS_IN_USE 0xC001001A +#define NDIS_STATUS_FILE_NOT_FOUND 0xC001001B +#define NDIS_STATUS_ERROR_READING_FILE 0xC001001C +#define NDIS_STATUS_ALREADY_MAPPED 0xC001001D +#define NDIS_STATUS_RESOURCE_CONFLICT 0xC001001E +#define NDIS_STATUS_NO_CABLE 0xC001001F +#define NDIS_STATUS_INVALID_SAP 0xC0010020 +#define NDIS_STATUS_SAP_IN_USE 0xC0010021 +#define NDIS_STATUS_INVALID_ADDRESS 0xC0010022 +#define NDIS_STATUS_VC_NOT_ACTIVATED 0xC0010023 +#define NDIS_STATUS_DEST_OUT_OF_ORDER 0xC0010024 +#define NDIS_STATUS_VC_NOT_AVAILABLE 0xC0010025 +#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE 0xC0010026 +#define NDIS_STATUS_INCOMPATABLE_QOS 0xC0010027 +#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED 0xC0010028 +#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION 0xC0010029 +#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR 0xC0011000 +#define NDIS_STATUS_INVALID_DEVICE_REQUEST 0xC0000010 +#define NDIS_STATUS_NETWORK_UNREACHABLE 0xC000023C + +/* + * NDIS event codes. They are usually reported to NdisWriteErrorLogEntry(). + */ + +#define EVENT_NDIS_RESOURCE_CONFLICT 0xC0001388 +#define EVENT_NDIS_OUT_OF_RESOURCE 0xC0001389 +#define EVENT_NDIS_HARDWARE_FAILURE 0xC000138A +#define EVENT_NDIS_ADAPTER_NOT_FOUND 0xC000138B +#define EVENT_NDIS_INTERRUPT_CONNECT 0xC000138C +#define EVENT_NDIS_DRIVER_FAILURE 0xC000138D +#define EVENT_NDIS_BAD_VERSION 0xC000138E +#define EVENT_NDIS_TIMEOUT 0x8000138F +#define EVENT_NDIS_NETWORK_ADDRESS 0xC0001390 +#define EVENT_NDIS_UNSUPPORTED_CONFIGURATION 0xC0001391 +#define EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER 0xC0001392 +#define EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER 0xC0001393 +#define EVENT_NDIS_BAD_IO_BASE_ADDRESS 0xC0001394 +#define EVENT_NDIS_RECEIVE_SPACE_SMALL 0x40001395 +#define EVENT_NDIS_ADAPTER_DISABLED 0x80001396 +#define EVENT_NDIS_IO_PORT_CONFLICT 0x80001397 +#define EVENT_NDIS_PORT_OR_DMA_CONFLICT 0x80001398 +#define EVENT_NDIS_MEMORY_CONFLICT 0x80001399 +#define EVENT_NDIS_INTERRUPT_CONFLICT 0x8000139A +#define EVENT_NDIS_DMA_CONFLICT 0x8000139B +#define EVENT_NDIS_INVALID_DOWNLOAD_FILE_ERROR 0xC000139C +#define EVENT_NDIS_MAXRECEIVES_ERROR 0x8000139D +#define EVENT_NDIS_MAXTRANSMITS_ERROR 0x8000139E +#define EVENT_NDIS_MAXFRAMESIZE_ERROR 0x8000139F +#define EVENT_NDIS_MAXINTERNALBUFS_ERROR 0x800013A0 +#define EVENT_NDIS_MAXMULTICAST_ERROR 0x800013A1 +#define EVENT_NDIS_PRODUCTID_ERROR 0x800013A2 +#define EVENT_NDIS_LOBE_FAILUE_ERROR 0x800013A3 +#define EVENT_NDIS_SIGNAL_LOSS_ERROR 0x800013A4 +#define EVENT_NDIS_REMOVE_RECEIVED_ERROR 0x800013A5 +#define EVENT_NDIS_TOKEN_RING_CORRECTION 0x400013A6 +#define EVENT_NDIS_ADAPTER_CHECK_ERROR 0xC00013A7 +#define EVENT_NDIS_RESET_FAILURE_ERROR 0x800013A8 +#define EVENT_NDIS_CABLE_DISCONNECTED_ERROR 0x800013A9 +#define EVENT_NDIS_RESET_FAILURE_CORRECTION 0x800013AA + +/* + * NDIS OIDs used by the queryinfo/setinfo routines. + * Some are required by all NDIS drivers, some are specific to + * a particular type of device, and some are purely optional. + * Unfortunately, one of the purely optional OIDs is the one + * that lets us set the MAC address of the device. + */ + +/* Required OIDs */ +#define OID_GEN_SUPPORTED_LIST 0x00010101 +#define OID_GEN_HARDWARE_STATUS 0x00010102 +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_MEDIA_IN_USE 0x00010104 +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 +#define OID_GEN_LINK_SPEED 0x00010107 +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B +#define OID_GEN_VENDOR_ID 0x0001010C +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F +#define OID_GEN_DRIVER_VERSION 0x00010110 +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 +#define OID_GEN_MAC_OPTIONS 0x00010113 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 +#define OID_GEN_SUPPORTED_GUIDS 0x00010117 +#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 /* Set only */ +#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 /* Set only */ +#define OID_GEN_MACHINE_NAME 0x0001021A +#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B /* Set only */ +#define OID_GEN_VLAN_ID 0x0001021C + +/* Optional OIDs. */ +#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 +#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 + +/* Required statistics OIDs. */ +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 + +/* Optional OID statistics */ +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E +#define OID_GEN_GET_TIME_CAPS 0x0002020F +#define OID_GEN_GET_NETCARD_TIME 0x00020210 +#define OID_GEN_NETCARD_LOAD 0x00020211 +#define OID_GEN_DEVICE_PROFILE 0x00020212 + +/* 802.3 (ethernet) OIDs */ +#define OID_802_3_PERMANENT_ADDRESS 0x01010101 +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +#define OID_802_3_MULTICAST_LIST 0x01010103 +#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 +#define OID_802_3_MAC_OPTIONS 0x01010105 +#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 +#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 +#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 +#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 +#define OID_802_3_XMIT_DEFERRED 0x01020201 +#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 +#define OID_802_3_RCV_OVERRUN 0x01020203 +#define OID_802_3_XMIT_UNDERRUN 0x01020204 +#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 +#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 +#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 + +/* PnP and power management OIDs */ +#define OID_PNP_CAPABILITIES 0xFD010100 +#define OID_PNP_SET_POWER 0xFD010101 +#define OID_PNP_QUERY_POWER 0xFD010102 +#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 +#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 +#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105 +#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 + +/* PnP/PM Statistics (Optional). */ +#define OID_PNP_WAKE_UP_OK 0xFD020200 +#define OID_PNP_WAKE_UP_ERROR 0xFD020201 + +/* The following bits are defined for OID_PNP_ENABLE_WAKE_UP */ +#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 +#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 +#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 + +/* 802.11 OIDs */ +#define OID_802_11_BSSID 0x0D010101 +#define OID_802_11_SSID 0x0D010102 +#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0D010203 +#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 +#define OID_802_11_TX_POWER_LEVEL 0x0D010205 +#define OID_802_11_RSSI 0x0D010206 +#define OID_802_11_RSSI_TRIGGER 0x0D010207 +#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 +#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0D010209 +#define OID_802_11_RTS_THRESHOLD 0x0D01020A +#define OID_802_11_NUMBER_OF_ANTENNAS 0x0D01020B +#define OID_802_11_RX_ANTENNA_SELECTED 0x0D01020C +#define OID_802_11_TX_ANTENNA_SELECTED 0x0D01020D +#define OID_802_11_SUPPORTED_RATES 0x0D01020E +#define OID_802_11_DESIRED_RATES 0x0D010210 +#define OID_802_11_CONFIGURATION 0x0D010211 +#define OID_802_11_STATISTICS 0x0D020212 +#define OID_802_11_ADD_WEP 0x0D010113 +#define OID_802_11_REMOVE_WEP 0x0D010114 +#define OID_802_11_DISASSOCIATE 0x0D010115 +#define OID_802_11_POWER_MODE 0x0D010216 +#define OID_802_11_BSSID_LIST 0x0D010217 +#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 +#define OID_802_11_PRIVACY_FILTER 0x0D010119 +#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A +#define OID_802_11_WEP_STATUS 0x0D01011B +#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS +#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C +#define OID_802_11_ADD_KEY 0x0D01011D +#define OID_802_11_REMOVE_KEY 0x0D01011E +#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F +#define OID_802_11_TEST 0x0D010120 + +/* structures/definitions for 802.11 */ +#define NDIS_80211_NETTYPE_11FH 0x00000000 +#define NDIS_80211_NETTYPE_11DS 0x00000001 +#define NDIS_80211_NETTYPE_11OFDM5 0x00000002 +#define NDIS_80211_NETTYPE_11OFDM24 0x00000003 + +struct ndis_80211_nettype_list { + uint32_t ntl_items; + uint32_t ntl_type[1]; +}; + +#define NDIS_80211_POWERMODE_CAM 0x00000000 +#define NDIS_80211_POWERMODE_MAX_PSP 0x00000001 +#define NDIS_80211_POWERMODE_FAST_PSP 0x00000002 + +typedef uint32_t ndis_80211_power; /* Power in milliwatts */ +typedef uint32_t ndis_80211_rssi; /* Signal strength in dBm */ + +struct ndis_80211_config_fh { + uint32_t ncf_length; + uint32_t ncf_hoppatterh; + uint32_t ncf_hopset; + uint32_t ncf_dwelltime; +}; + +typedef struct ndis_80211_config_fh ndis_80211_config_fh; + +struct ndis_80211_config { + uint32_t nc_length; + uint32_t nc_beaconperiod; + uint32_t nc_atimwin; + uint32_t nc_dsconfig; + ndis_80211_config_fh nc_fhconfig; +}; + +typedef struct ndis_80211_config ndis_80211_config; + +struct ndis_80211_stats { + uint32_t ns_length; + uint64_t ns_txfragcnt; + uint64_t ns_txmcastcnt; + uint64_t ns_failedcnt; + uint64_t ns_retrycnt; + uint64_t ns_multiretrycnt; + uint64_t ns_rtssuccesscnt; + uint64_t ns_rtsfailcnt; + uint64_t ns_ackfailcnt; + uint64_t ns_dupeframecnt; + uint64_t ns_rxfragcnt; + uint64_t ns_rxmcastcnt; + uint64_t ns_fcserrcnt; +}; + +typedef struct ndis_80211_stats ndis_80211_stats; + +typedef uint32_t ndis_80211_key_idx; + +struct ndis_80211_wep { + uint32_t nw_length; + uint32_t nw_keyidx; + uint32_t nw_keylen; + uint8_t nw_keydata[256]; +}; + +typedef struct ndis_80211_wep ndis_80211_wep; + +#define NDIS_80211_WEPKEY_TX 0x80000000 +#define NDIS_80211_WEPKEY_PERCLIENT 0x40000000 + +#define NDIS_80211_NET_INFRA_IBSS 0x00000000 +#define NDIS_80211_NET_INFRA_BSS 0x00000001 +#define NDIS_80211_NET_INFRA_AUTO 0x00000002 + +#define NDIS_80211_AUTHMODE_OPEN 0x00000000 +#define NDIS_80211_AUTHMODE_SHARED 0x00000001 +#define NDIS_80211_AUTHMODE_AUTO 0x00000002 +#define NDIS_80211_AUTHMODE_WPA 0x00000003 +#define NDIS_80211_AUTHMODE_WPAPSK 0x00000004 +#define NDIS_80211_AUTHMODE_WPANONE 0x00000005 + +typedef uint8_t ndis_80211_rates[8]; +typedef uint8_t ndis_80211_rates_ex[16]; +typedef uint8_t ndis_80211_macaddr[6]; + +struct ndis_80211_ssid { + uint32_t ns_ssidlen; + uint8_t ns_ssid[32]; +}; + +typedef struct ndis_80211_ssid ndis_80211_ssid; + +struct ndis_wlan_bssid { + uint32_t nwb_length; + ndis_80211_macaddr nwb_macaddr; + uint8_t nwb_rsvd[2]; + ndis_80211_ssid nwb_ssid; + uint32_t nwb_privacy; + ndis_80211_rssi nwb_rssi; + uint32_t nwb_nettype; + ndis_80211_config nwb_config; + uint32_t nwb_netinfra; + ndis_80211_rates nwb_supportedrates; +}; + +typedef struct ndis_wlan_bssid ndis_wlan_bssid; + +struct ndis_80211_bssid_list { + uint32_t nbl_items; + ndis_wlan_bssid nbl_bssid[1]; +}; + +typedef struct ndis_80211_bssid_list ndis_80211_bssid_list; + +struct ndis_wlan_bssid_ex { + uint32_t nwbx_len; + ndis_80211_macaddr nwbx_macaddr; + uint8_t nwbx_rsvd[2]; + ndis_80211_ssid nwbx_ssid; + uint32_t nwbx_privacy; + ndis_80211_rssi nwbx_rssi; + uint32_t nwbx_nettype; + ndis_80211_config nwbx_config; + uint32_t nwbx_netinfra; + ndis_80211_rates_ex nwbx_supportedrates; + uint32_t nwbx_ielen; + uint32_t nwbx_ies[1]; +}; + +typedef struct ndis_wlan_bssid_ex ndis_wlan_bssid_ex; + +struct ndis_80211_bssid_list_ex { + uint32_t nblx_items; + ndis_wlan_bssid_ex nblx_bssid[1]; +}; + +typedef struct ndis_80211_bssid_list_ex ndis_80211_bssid_list_ex; + +struct ndis_80211_fixed_ies { + uint8_t nfi_tstamp[8]; + uint16_t nfi_beaconint; + uint16_t nfi_caps; +}; + +struct ndis_80211_variable_ies { + uint8_t nvi_elemid; + uint8_t nvi_len; + uint8_t nvi_data[1]; +}; + +typedef uint32_t ndis_80211_fragthresh; +typedef uint32_t ndis_80211_rtsthresh; +typedef uint32_t ndis_80211_antenna; + +#define NDIS_80211_PRIVFILT_ACCEPTALL 0x00000000 +#define NDIS_80211_PRIVFILT_8021XWEP 0x00000001 + +#define NDIS_80211_WEPSTAT_ENABLED 0x00000000 +#define NDIS_80211_WEPSTAT_ENC1ENABLED NDIS_80211_WEPSTAT_ENABLED +#define NDIS_80211_WEPSTAT_DISABLED 0x00000001 +#define NDIS_80211_WEPSTAT_ENCDISABLED NDIS_80211_WEPSTAT_DISABLED +#define NDIS_80211_WEPSTAT_KEYABSENT 0x00000002 +#define NDIS_80211_WEPSTAT_ENC1KEYABSENT NDIS_80211_WEPSTAT_KEYABSENT +#define NDIS_80211_WEPSTAT_NOTSUPPORTED 0x00000003 +#define NDIS_80211_WEPSTAT_ENCNOTSUPPORTED NDIS_80211_WEPSTAT_NOTSUPPORTED +#define NDIS_80211_WEPSTAT_ENC2ENABLED 0x00000004 +#define NDIS_80211_WEPSTAT_ENC2KEYABSENT 0x00000005 +#define NDIS_80211_WEPSTAT_ENC3ENABLED 0x00000006 +#define NDIS_80211_WEPSTAT_ENC3KEYABSENT 0x00000007 + +#define NDIS_80211_RELOADDEFAULT_WEP 0x00000000 + +#define NDIS_80211_STATUSTYPE_AUTH 0x00000000 + +struct ndis_80211_status_indication { + uint32_t nsi_type; +}; + +typedef struct ndis_80211_status_indication ndis_80211_status_indication; + +struct ndis_80211_auth_request { + uint32_t nar_len; + ndis_80211_macaddr nar_bssid; + uint32_t nar_flags; +}; + +typedef struct ndis_80211_auth_request ndis_80211_auth_request; + +struct ndis_80211_key { + uint32_t nk_len; + uint32_t nk_keyidx; + uint32_t nk_keylen; + ndis_80211_macaddr nk_bssid; + uint64_t nk_keyrsc; + uint8_t nk_keydata[256]; +}; + +typedef struct ndis_80211_key ndis_80211_key; + +struct ndis_80211_remove_key { + uint32_t nk_len; + uint32_t nk_keyidx; + ndis_80211_macaddr nk_bssid; +}; + +typedef struct ndis_80211_remove_key ndis_80211_remove_key; + +#define NDIS_80211_AI_REQFI_CAPABILITIES 0x00000001 +#define NDIS_80211_AI_REQFI_LISTENINTERVAL 0x00000002 +#define NDIS_80211_AI_REQFI_CURRENTAPADDRESS 0x00000004 + +#define NDIS_80211_AI_RESFI_CAPABILITIES 0x00000001 +#define NDIS_80211_AI_RESFI_STATUSCODE 0x00000002 +#define NDIS_80211_AI_RESFI_ASSOCIATIONID 0x00000004 + +struct ndis_80211_ai_reqfi { + uint16_t naq_caps; + uint16_t naq_listentint; + ndis_80211_macaddr naq_currentapaddr; +}; + +typedef struct ndis_80211_ai_reqfi ndis_80211_ai_reqfi; + +struct ndis_80211_ai_resfi { + uint16_t nas_caps; + uint16_t nas_statuscode; + uint16_t nas_associd; +}; + +typedef struct ndis_80211_ai_resfi ndis_80211_ai_resfi; + +struct ndis_80211_assoc_info { + uint32_t nai_len; + uint16_t nai_avail_req_fixed_ies; + ndis_80211_ai_reqfi nai_req_fixed_ies; + uint32_t nai_req_ielen; + uint32_t nai_offset_req_ies; + uint16_t nai_avail_resp_fixed_ies; + ndis_80211_ai_resfi nai_resp_fixed_iex; + uint32_t nai_resp_ielen; + uint32_t nai_offset_resp_ies; +}; + +typedef struct ndis_80211_assoc_info ndis_80211_assoc_info; + +struct ndis_80211_auth_event { + ndis_80211_status_indication nae_status; + ndis_80211_auth_request nae_request[1]; +}; + +typedef struct ndis_80211_auth_event ndis_80211_auth_event; + +struct ndis_80211_test { + uint32_t nt_len; + uint32_t nt_type; + union { + ndis_80211_auth_event nt_authevent; + uint32_t nt_rssitrigger; + } u; +}; + +typedef struct ndis_80211_test ndis_80211_test; + +/* TCP OIDs. */ + +#define OID_TCP_TASK_OFFLOAD 0xFC010201 +#define OID_TCP_TASK_IPSEC_ADD_SA 0xFC010202 +#define OID_TCP_TASK_IPSEC_DELETE_SA 0xFC010203 +#define OID_TCP_SAN_SUPPORT 0xFC010204 + + +#define NDIS_TASK_OFFLOAD_VERSION 1 + +#define NDIS_TASK_TCPIP_CSUM 0x00000000 +#define NDIS_TASK_IPSEC 0x00000001 +#define NDIS_TASK_TCP_LARGESEND 0x00000002 + +#define NDIS_ENCAP_UNSPEC 0x00000000 +#define NDIS_ENCAP_NULL 0x00000001 +#define NDIS_ENCAP_IEEE802_3 0x00000002 +#define NDIS_ENCAP_IEEE802_5 0x00000003 +#define NDIS_ENCAP_SNAP_ROUTED 0x00000004 +#define NDIS_ENCAP_SNAP_BRIDGED 0x00000005 + +#define NDIS_ENCAPFLAG_FIXEDHDRLEN 0x00000001 + +struct ndis_encap_fmt { + uint32_t nef_encap; + uint32_t nef_flags; + uint32_t nef_encaphdrlen; +}; + +typedef struct ndis_encap_fmt ndis_encap_fmt; + +struct ndis_task_offload_hdr { + uint32_t ntoh_vers; + uint32_t ntoh_len; + uint32_t ntoh_rsvd; + uint32_t ntoh_offset_firsttask; + ndis_encap_fmt ntoh_encapfmt; +}; + +typedef struct ndis_task_offload_hdr ndis_task_offload_hdr; + +struct ndis_task_offload { + uint32_t nto_vers; + uint32_t nto_len; + uint32_t nto_task; + uint32_t nto_offset_nexttask; + uint32_t nto_taskbuflen; + uint8_t nto_taskbuf[1]; +}; + +typedef struct ndis_task_offload ndis_task_offload; + +#define NDIS_TCPSUM_FLAGS_IP_OPTS 0x00000001 +#define NDIS_TCPSUM_FLAGS_TCP_OPTS 0x00000002 +#define NDIS_TCPSUM_FLAGS_TCP_CSUM 0x00000004 +#define NDIS_TCPSUM_FLAGS_UDP_CSUM 0x00000008 +#define NDIS_TCPSUM_FLAGS_IP_CSUM 0x00000010 + +struct ndis_task_tcpip_csum { + uint32_t nttc_v4tx; + uint32_t nttc_v4rx; + uint32_t nttc_v6tx; + uint32_t nttc_v6rx; +}; + +typedef struct ndis_task_tcpip_csum ndis_task_tcpip_csum; + +struct ndis_task_tcp_largesend { + uint32_t nttl_vers; + uint32_t nttl_maxofflen; + uint32_t nttl_minsegcnt; + uint8_t nttl_tcpopt; + uint8_t nttl_ipopt; +}; + +typedef struct ndis_task_tcp_largesend ndis_task_tcp_largesend; + +#define NDIS_IPSEC_AH_MD5 0x00000001 +#define NDIS_IPSEC_AH_SHA1 0x00000002 +#define NDIS_IPSEC_AH_TRANSPORT 0x00000004 +#define NDIS_IPSEC_AH_TUNNEL 0x00000008 +#define NDIS_IPSEC_AH_SEND 0x00000010 +#define NDIS_IPSEC_AH_RECEIVE 0x00000020 + +#define NDIS_IPSEC_ESP_DES 0x00000001 +#define NDIS_IPSEC_ESP_RSVD 0x00000002 +#define NDIS_IPSEC_ESP_3DES 0x00000004 +#define NDIS_IPSEC_ESP_NULL 0x00000008 +#define NDIS_IPSEC_ESP_TRANSPORT 0x00000010 +#define NDIS_IPSEC_ESP_TUNNEL 0x00000020 +#define NDIS_IPSEC_ESP_SEND 0x00000040 +#define NDIS_IPSEC_ESP_RECEIVE 0x00000080 + +struct ndis_task_ipsec { + uint32_t nti_ah_esp_combined; + uint32_t nti_ah_transport_tunnel_combined; + uint32_t nti_v4_options; + uint32_t nti_rsvd; + uint32_t nti_v4ah; + uint32_t nti_v4esp; +}; + +typedef struct ndis_task_ipsec ndis_task_ipsec; + +/* + * Attribures of NDIS drivers. Not all drivers support + * all attributes. + */ + +#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002 +#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004 +#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008 +#define NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER 0x00000010 +#define NDIS_ATTRIBUTE_DESERIALIZE 0x00000020 +#define NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND 0x00000040 +#define NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK 0x00000080 +#define NDIS_ATTRIBUTE_NOT_CO_NDIS 0x00000100 +#define NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS 0x00000200 + +#define NDIS_SERIALIZED(block) \ + (((block)->nmb_flags & NDIS_ATTRIBUTE_DESERIALIZE) == 0) + +enum ndis_media_state { + nmc_connected, + nmc_disconnected +}; + +typedef enum ndis_media_state ndis_media_state; + +/* Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER). */ + +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 +#define NDIS_PACKET_TYPE_SMT 0x00000040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 +#define NDIS_PACKET_TYPE_GROUP 0x00001000 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00002000 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00004000 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x00008000 + + +/* Ndis MAC option bits (OID_GEN_MAC_OPTIONS). */ + +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 +#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 +#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 +#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 +#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 +#define NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00000080 +#define NDIS_MAC_OPTION_RECEIVE_AT_DPC 0x00000100 +#define NDIS_MAC_OPTION_8021Q_VLAN 0x00000200 +#define NDIS_MAC_OPTION_RESERVED 0x80000000 + +#define NDIS_DMA_24BITS 0x00 +#define NDIS_DMA_32BITS 0x01 +#define NDIS_DMA_64BITS 0x02 + +/* +struct ndis_physaddr { +#ifdef __i386__ + uint64_t np_quad; +#endif +#ifdef __amd64__ + uint32_t np_low; + uint32_t np_high; +#define np_quad np_low +#endif +#ifdef notdef + uint32_t np_low; + uint32_t np_high; +#endif +}; +*/ + +typedef struct physaddr ndis_physaddr; + +struct ndis_ansi_string { + uint16_t nas_len; + uint16_t nas_maxlen; + char *nas_buf; +}; + +typedef struct ndis_ansi_string ndis_ansi_string; + +#ifdef notdef +/* + * nus_buf is really a wchar_t *, but it's inconvenient to include + * all the necessary header goop needed to define it, and it's a + * pointer anyway, so for now, just make it a uint16_t *. + */ +struct ndis_unicode_string { + uint16_t nus_len; + uint16_t nus_maxlen; + uint16_t *nus_buf; +}; +typedef struct ndis_unicode_string ndis_unicode_string; +#endif + +typedef unicode_string ndis_unicode_string; + +enum ndis_parm_type { + ndis_parm_int, + ndis_parm_hexint, + ndis_parm_string, + ndis_parm_multistring, + ndis_parm_binary +}; + +typedef enum ndis_parm_type ndis_parm_type; + +struct ndis_binary_data { + uint16_t nbd_len; + void *nbd_buf; +}; + +typedef struct ndis_binary_data ndis_binary_data; + +struct ndis_config_parm { + ndis_parm_type ncp_type; + union { + uint32_t ncp_intdata; + ndis_unicode_string ncp_stringdata; + ndis_binary_data ncp_binarydata; + } ncp_parmdata; +}; + +typedef struct ndis_config_parm ndis_config_parm; + +#ifdef notdef +struct ndis_list_entry { + struct ndis_list_entry *nle_flink; + struct ndis_list_entry *nle_blink; +}; + +typedef struct ndis_list_entry ndis_list_entry; +#endif + +struct ndis_bind_paths { + uint32_t nbp_number; + ndis_unicode_string nbp_paths[1]; +}; + +typedef struct ndis_bind_paths ndis_bind_paths; + +#ifdef notdef +struct dispatch_header { + uint8_t dh_type; + uint8_t dh_abs; + uint8_t dh_size; + uint8_t dh_inserted; + uint32_t dh_sigstate; + list_entry dh_waitlisthead; +}; +#endif + +#define dispatch_header nt_dispatch_header + +struct ndis_ktimer { + struct dispatch_header nk_header; + uint64_t nk_duetime; + list_entry nk_timerlistentry; + void *nk_dpc; + uint32_t nk_period; +}; + +struct ndis_kevent { + struct dispatch_header nk_header; +}; + +struct ndis_event { + struct nt_kevent ne_event; +}; + +typedef struct ndis_event ndis_event; + +/* Kernel defered procedure call (i.e. timer callback) */ + +struct ndis_kdpc; +typedef void (*ndis_kdpc_func)(struct ndis_kdpc *, void *, void *, void *); + +struct ndis_kdpc { + uint16_t nk_type; + uint8_t nk_num; + uint8_t nk_importance; + list_entry nk_dpclistentry; + ndis_kdpc_func nk_deferedfunc; + void *nk_deferredctx; + void *nk_sysarg1; + void *nk_sysarg2; + uint32_t *nk_lock; +}; + +struct ndis_timer { + struct ktimer nt_ktimer; + struct kdpc nt_kdpc; +}; + +typedef struct ndis_timer ndis_timer; + +typedef __stdcall void (*ndis_timer_function)(void *, void *, void *, void *); + +struct ndis_miniport_timer { + struct ktimer nmt_ktimer; + struct kdpc nmt_kdpc; + ndis_timer_function nmt_timerfunc; + void *nmt_timerctx; + ndis_miniport_block *nmt_block; + struct ndis_miniport_timer *nmt_nexttimer; +}; + +typedef struct ndis_miniport_timer ndis_miniport_timer; + +struct ndis_spin_lock { + ndis_kspin_lock nsl_spinlock; + ndis_kirql nsl_kirql; +}; + +typedef struct ndis_spin_lock ndis_spin_lock; + +struct ndis_request { + uint8_t nr_macreserved[4*sizeof(void *)]; + uint32_t nr_requesttype; + union _ndis_data { + struct _ndis_query_information { + ndis_oid nr_oid; + void *nr_infobuf; + uint32_t nr_infobuflen; + uint32_t nr_byteswritten; + uint32_t nr_bytesneeded; + } ndis_query_information; + struct _ndis_set_information { + ndis_oid nr_oid; + void *nr_infobuf; + uint32_t nr_infobuflen; + uint32_t nr_byteswritten; + uint32_t nr_bytesneeded; + } ndis_set_information; + } ndis_data; + /* NDIS 5.0 extentions */ + uint8_t nr_ndis_rsvd[9 * sizeof(void *)]; + union { + uint8_t nr_callmgr_rsvd[2 * sizeof(void *)]; + uint8_t nr_protocol_rsvd[2 * sizeof(void *)]; + } u; + uint8_t nr_miniport_rsvd[2 * sizeof(void *)]; +}; + +typedef struct ndis_request ndis_request; + +/* + * Filler, not used. + */ +struct ndis_miniport_interrupt { + void *ni_introbj; + ndis_kspin_lock ni_dpccountlock; + void *ni_rsvd; + void *ni_isrfunc; + void *ni_dpcfunc; + struct ndis_kdpc ni_dpc; + ndis_miniport_block *ni_block; + uint8_t ni_dpccnt; + uint8_t ni_filler1; + struct ndis_kevent ni_dpcsdoneevent; + uint8_t ni_shared; + uint8_t ni_isrreq; +}; + +typedef struct ndis_miniport_interrupt ndis_miniport_interrupt; + +enum ndis_interrupt_mode { + nim_level, + nim_latched +}; + +typedef enum ndis_interrupt_mode ndis_interrupt_mode; + +struct ndis_work_item; + +typedef void (*ndis_proc)(struct ndis_work_item *, void *); + +struct ndis_work_item { + void *nwi_ctx; + void *nwi_func; + uint8_t nwi_wraprsvd[sizeof(void *) * 8]; +}; + +typedef struct ndis_work_item ndis_work_item; + +#ifdef notdef +struct ndis_buffer { + struct ndis_buffer *nb_next; + uint16_t nb_size; + uint16_t nb_flags; + void *nb_process; + void *nb_mappedsystemva; + void *nb_startva; + uint32_t nb_bytecount; + uint32_t nb_byteoffset; +}; + +typedef struct ndis_buffer ndis_buffer; +#endif + +struct ndis_sc_element { + ndis_physaddr nse_addr; + uint32_t nse_len; + uint32_t *nse_rsvd; +}; + +typedef struct ndis_sc_element ndis_sc_element; + +#define NDIS_MAXSEG 32 +#define NDIS_BUS_SPACE_SHARED_MAXADDR 0x3E7FFFFF + +struct ndis_sc_list { + uint32_t nsl_frags; + uint32_t *nsl_rsvd; + ndis_sc_element nsl_elements[NDIS_MAXSEG]; +}; + +typedef struct ndis_sc_list ndis_sc_list; + +struct ndis_tcpip_csum { + union { + uint32_t ntc_txflags; + uint32_t ntc_rxflags; + uint32_t ntc_val; + } u; +}; + +typedef struct ndis_tcpip_csum ndis_tcpip_csum; + +#define NDIS_TXCSUM_DO_IPV4 0x00000001 +#define NDIS_TXCSUM_DO_IPV6 0x00000002 +#define NDIS_TXCSUM_DO_TCP 0x00000004 +#define NDIS_TXCSUM_DO_UDP 0x00000008 +#define NDIS_TXCSUM_DO_IP 0x00000010 + +#define NDIS_RXCSUM_TCP_FAILED 0x00000001 +#define NDIS_RXCSUM_UDP_FAILED 0x00000002 +#define NDIS_RXCSUM_IP_FAILED 0x00000004 +#define NDIS_RXCSUM_TCP_PASSED 0x00000008 +#define NDIS_RXCSUM_UDP_PASSED 0x00000010 +#define NDIS_RXCSUM_IP_PASSED 0x00000020 +#define NDIS_RXCSUM_LOOPBACK 0x00000040 + +struct ndis_vlan { + union { + struct { + uint32_t nvt_userprio:3; + uint32_t nvt_canformatid:1; + uint32_t nvt_vlanid:12; + uint32_t nvt_rsvd:16; + } nv_taghdr; + } u; +}; + +typedef struct ndis_vlan ndis_vlan; + +enum ndis_perpkt_info { + ndis_tcpipcsum_info, + ndis_ipsec_info, + ndis_largesend_info, + ndis_classhandle_info, + ndis_rsvd, + ndis_sclist_info, + ndis_ieee8021q_info, + ndis_originalpkt_info, + ndis_packetcancelid, + ndis_maxpkt_info +}; + +typedef enum ndis_perpkt_info ndis_perpkt_info; + +struct ndis_packet_extension { + void *npe_info[ndis_maxpkt_info]; +}; + +typedef struct ndis_packet_extension ndis_packet_extension; + +struct ndis_packet_private { + uint32_t npp_physcnt; + uint32_t npp_totlen; + ndis_buffer *npp_head; + ndis_buffer *npp_tail; + + void *npp_pool; + uint32_t npp_count; + uint32_t npp_flags; + uint8_t npp_validcounts; + uint8_t npp_ndispktflags; + uint16_t npp_packetooboffset; +}; + +#define NDIS_FLAGS_PROTOCOL_ID_MASK 0x0000000F +#define NDIS_FLAGS_MULTICAST_PACKET 0x00000010 +#define NDIS_FLAGS_RESERVED2 0x00000020 +#define NDIS_FLAGS_RESERVED3 0x00000040 +#define NDIS_FLAGS_DONT_LOOPBACK 0x00000080 +#define NDIS_FLAGS_IS_LOOPBACK_PACKET 0x00000100 +#define NDIS_FLAGS_LOOPBACK_ONLY 0x00000200 +#define NDIS_FLAGS_RESERVED4 0x00000400 +#define NDIS_FLAGS_DOUBLE_BUFFERED 0x00000800 +#define NDIS_FLAGS_SENT_AT_DPC 0x00001000 +#define NDIS_FLAGS_USES_SG_BUFFER_LIST 0x00002000 + +#define NDIS_PACKET_WRAPPER_RESERVED 0x3F +#define NDIS_PACKET_CONTAINS_MEDIA_SPECIFIC_INFO 0x40 +#define NDIS_PACKET_ALLOCATED_BY_NDIS 0x80 + +#define NDIS_PROTOCOL_ID_DEFAULT 0x00 +#define NDIS_PROTOCOL_ID_TCP_IP 0x02 +#define NDIS_PROTOCOL_ID_IPX 0x06 +#define NDIS_PROTOCOL_ID_NBF 0x07 +#define NDIS_PROTOCOL_ID_MAX 0x0F +#define NDIS_PROTOCOL_ID_MASK 0x0F + +typedef struct ndis_packet_private ndis_packet_private; + +enum ndis_classid { + ndis_class_802_3prio, + ndis_class_wirelesswan_mbx, + ndis_class_irda_packetinfo, + ndis_class_atm_aainfo +}; + +typedef enum ndis_classid ndis_classid; + +struct ndis_mediaspecific_info { + uint32_t nmi_nextentoffset; + ndis_classid nmi_classid; + uint32_t nmi_size; + uint8_t nmi_classinfo[1]; +}; + +typedef struct ndis_mediaspecific_info ndis_mediaspecific_info; + +struct ndis_packet_oob { + union { + uint64_t npo_timetotx; + uint64_t npo_timetxed; + } u; + uint64_t npo_timerxed; + uint32_t npo_hdrlen; + uint32_t npo_mediaspecific_len; + void *npo_mediaspecific; + ndis_status npo_status; +}; + +typedef struct ndis_packet_oob ndis_packet_oob; + +struct ndis_packet { + ndis_packet_private np_private; + union { + /* For connectionless miniports. */ + struct { + uint8_t np_miniport_rsvd[2 * sizeof(void *)]; + uint8_t np_wrapper_rsvd[2 * sizeof(void *)]; + } np_clrsvd; + /* For de-serialized miniports */ + struct { + uint8_t np_miniport_rsvdex[3 * sizeof(void *)]; + uint8_t np_wrapper_rsvdex[sizeof(void *)]; + } np_dsrsvd; + struct { + uint8_t np_mac_rsvd[4 * sizeof(void *)]; + } np_macrsvd; + } u; + uint32_t *np_rsvd[2]; + uint8_t nm_protocolreserved[1]; + + /* + * This next part is probably wrong, but we need some place + * to put the out of band data structure... + */ + ndis_packet_oob np_oob; + ndis_packet_extension np_ext; + ndis_sc_list np_sclist; + + /* BSD-specific stuff which should be invisible to drivers. */ + + uint32_t np_refcnt; + void *np_softc; + void *np_m0; + int np_txidx; + kspin_lock np_lock; +}; + +typedef struct ndis_packet ndis_packet; + +#define PROTOCOL_RESERVED_SIZE_IN_PACKET (4 * sizeof(void *)) + +/* mbuf ext type for NDIS */ +#define EXT_NDIS 0x999 + +/* mtx type for NDIS */ +#define MTX_NDIS_LOCK "NDIS lock" + +struct ndis_filterdbs { + union { + void *nf_ethdb; + void *nf_nulldb; + } u; + void *nf_trdb; + void *nf_fddidb; + void *nf_arcdb; +}; + +typedef struct ndis_filterdbs ndis_filterdbs; + +enum ndis_medium { + NdisMedium802_3, + NdisMedium802_5, + NdisMediumFddi, + NdisMediumWan, + NdisMediumLocalTalk, + NdisMediumDix, /* defined for convenience, not a real medium */ + NdisMediumArcnetRaw, + NdisMediumArcnet878_2, + NdisMediumAtm, + NdisMediumWirelessWan, + NdisMediumIrda, + NdisMediumBpc, + NdisMediumCoWan, + NdisMedium1394, + NdisMediumMax +}; + +typedef enum ndis_medium ndis_medium; +/* +enum interface_type { + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + MaximumInterfaceType +}; +*/ +enum ndis_interface_type { + NdisInterfaceInternal = Internal, + NdisInterfaceIsa = Isa, + NdisInterfaceEisa = Eisa, + NdisInterfaceMca = MicroChannel, + NdisInterfaceTurboChannel = TurboChannel, + NdisInterfacePci = PCIBus, + NdisInterfacePcMcia = PCMCIABus +}; + +typedef enum ndis_interface_type ndis_interface_type; + +struct ndis_paddr_unit { + ndis_physaddr npu_physaddr; + uint32_t npu_len; +}; + +typedef struct ndis_paddr_unit ndis_paddr_unit; + +struct ndis_map_arg { + ndis_paddr_unit *nma_fraglist; + int nma_cnt; + int nma_max; +}; + +/* + * Miniport characteristics were originally defined in the NDIS 3.0 + * spec and then extended twice, in NDIS 4.0 and 5.0. + */ + +struct ndis_miniport_characteristics { + + /* NDIS 3.0 */ + + uint8_t nmc_version_major; + uint8_t nmc_version_minor; + uint16_t nmc_pad; + uint32_t nmc_rsvd; + void * nmc_checkhang_func; + void * nmc_disable_interrupts_func; + void * nmc_enable_interrupts_func; + void * nmc_halt_func; + void * nmc_interrupt_func; + void * nmc_init_func; + void * nmc_isr_func; + void * nmc_queryinfo_func; + void * nmc_reconfig_func; + void * nmc_reset_func; + void * nmc_sendsingle_func; + void * nmc_setinfo_func; + void * nmc_transferdata_func; + + /* NDIS 4.0 extentions */ + + void * nmc_return_packet_func; + void * nmc_sendmulti_func; + void * nmc_allocate_complete_func; + + /* NDIS 5.0 extensions */ + + void * nmc_cocreatevc_func; + void * nmc_codeletevc_func; + void * nmc_coactivatevc_func; + void * nmc_codeactivatevc_func; + void * nmc_comultisend_func; + void * nmc_corequest_func; + + /* NDIS 5.1 extentions */ + + void * nmc_canceltxpkts_handler; + void * nmc_pnpevent_handler; + void * nmc_shutdown_handler; + void * nmc_rsvd0; + void * nmc_rsvd1; + void * nmc_rsvd2; + void * nmc_rsvd3; +}; + +typedef struct ndis_miniport_characteristics ndis_miniport_characteristics; + +struct ndis_driver_object { + char *ndo_ifname; + void *ndo_softc; + ndis_miniport_characteristics ndo_chars; +}; + +typedef struct ndis_driver_object ndis_driver_object; + +struct ndis_reference { + ndis_kspin_lock nr_spinlock; + uint16_t nr_refcnt; + uint8_t nr_closing; +}; + +typedef struct ndis_reference ndis_reference; + +struct ndis_timer_entry { + struct callout nte_ch; + ndis_miniport_timer *nte_timer; + TAILQ_ENTRY(ndis_timer_entry) link; +}; + +TAILQ_HEAD(nte_head, ndis_timer_entry); + +#define NDIS_FH_TYPE_VFS 0 +#define NDIS_FH_TYPE_MODULE 1 + +struct ndis_fh { + int nf_type; + void *nf_vp; + void *nf_map; + uint32_t nf_maplen; +}; + +typedef struct ndis_fh ndis_fh; + +/* + * The miniport block is basically the internal NDIS handle. We need + * to define this because, unfortunately, it is not entirely opaque + * to NDIS drivers. For one thing, it contains the function pointer + * to the NDIS packet receive handler, which is invoked out of the + * NDIS block via a macro rather than a function pointer. (The + * NdisMIndicateReceivePacket() routine is a macro rather than + * a function.) For another, the driver maintains a pointer to the + * miniport block and passes it as a handle to various NDIS functions. + * (The driver never really knows this because it's hidden behind + * an ndis_handle though.) + * + * The miniport block has two parts: the first part contains fields + * that must never change, since they are referenced by driver + * binaries through macros. The second part is ignored by the driver, + * but contains various things used internaly by NDIS.SYS. In our + * case, we define the first 'immutable' part exactly as it appears + * in Windows, but don't bother duplicating the Windows definitions + * for the second part. Instead, we replace them with a few BSD-specific + * things. + */ + +struct ndis_miniport_block { + /* + * Windows-specific portion -- DO NOT MODIFY OR NDIS + * DRIVERS WILL NOT WORK. + */ + void *nmb_signature; /* magic number */ + ndis_miniport_block *nmb_nextminiport; + ndis_mdriver_block *nmb_driverhandle; + ndis_handle nmb_miniportadapterctx; + ndis_unicode_string nmb_name; + ndis_bind_paths *nmb_bindpaths; + ndis_handle nmb_openqueue; + ndis_reference nmb_ref; + ndis_handle nmb_devicectx; + uint8_t nmb_padding; + uint8_t nmb_lockacquired; + uint8_t nmb_pmodeopens; + uint8_t nmb_assignedcpu; + ndis_kspin_lock nmb_lock; + ndis_request *nmb_mediarequest; + ndis_miniport_interrupt *nmb_interrupt; + uint32_t nmb_flags; + uint32_t nmb_pnpflags; + list_entry nmb_packetlist; + ndis_packet *nmb_firstpendingtxpacket; + ndis_packet *nmb_returnpacketqueue; + uint32_t nmb_requestbuffer; + void *nmb_setmcastbuf; + ndis_miniport_block *nmb_primaryminiport; + void *nmb_wrapperctx; + void *nmb_busdatactx; + uint32_t nmb_pnpcaps; + cm_resource_list *nmb_resources; + ndis_timer nmb_wkupdpctimer; + ndis_unicode_string nmb_basename; + ndis_unicode_string nmb_symlinkname; + uint32_t nmb_checkforhangsecs; + uint16_t nmb_cfhticks; + uint16_t nmb_cfhcurrticks; + ndis_status nmb_resetstatus; + ndis_handle nmb_resetopen; + ndis_filterdbs nmb_filterdbs; + void *nmb_pktind_func; + void *nmb_senddone_func; + void *nmb_sendrsrc_func; + void *nmb_resetdone_func; + ndis_medium nmb_medium; + uint32_t nmb_busnum; + uint32_t nmb_bustype; + uint32_t nmb_adaptertype; + device_object *nmb_deviceobj; /* Functional device */ + device_object *nmb_physdeviceobj; /* Physical device */ + device_object *nmb_nextdeviceobj; /* Next dev in stack */ + void *nmb_mapreg; + void *nmb_callmgraflist; + void *nmb_miniportthread; + void *nmb_setinfobuf; + uint16_t nmb_setinfobuflen; + uint16_t nmb_maxsendpkts; + ndis_status nmb_fakestatus; + void *nmb_lockhandler; + ndis_unicode_string *nmb_adapterinstancename; + void *nmb_timerqueue; + uint32_t nmb_mactoptions; + ndis_request *nmb_pendingreq; + uint32_t nmb_maxlongaddrs; + uint32_t nmb_maxshortaddrs; + uint32_t nmb_currlookahead; + uint32_t nmb_maxlookahead; + void *nmb_interrupt_func; + void *nmb_disableintr_func; + void *nmb_enableintr_func; + void *nmb_sendpkts_func; + void *nmb_deferredsend_func; + void *nmb_ethrxindicate_func; + void *nmb_txrxindicate_func; + void *nmb_fddirxindicate_func; + void *nmb_ethrxdone_func; + void *nmb_txrxdone_func; + void *nmb_fddirxcond_func; + void *nmb_status_func; + void *nmb_statusdone_func; + void *nmb_tdcond_func; + void *nmb_querydone_func; + void *nmb_setdone_func; + void *nmb_wantxdone_func; + void *nmb_wanrx_func; + void *nmb_wanrxdone_func; + /* + * End of windows-specific portion of miniport block. Everything + * below is BSD-specific. + */ + struct ifnet *nmb_ifp; + uint8_t nmb_dummybuf[128]; + device_object nmb_devobj; + ndis_config_parm nmb_replyparm; + int nmb_pciidx; + device_t nmb_dev; + ndis_resource_list *nmb_rlist; + ndis_status nmb_getstat; + ndis_status nmb_setstat; + vm_offset_t nmb_img; + TAILQ_ENTRY(ndis_miniport_block) link; +}; + +TAILQ_HEAD(nd_head, ndis_miniport_block); + +typedef ndis_status (*ndis_init_handler)(ndis_status *, uint32_t *, + ndis_medium *, uint32_t, ndis_handle, ndis_handle); +typedef ndis_status (*ndis_queryinfo_handler)(ndis_handle, ndis_oid, + void *, uint32_t, uint32_t *, uint32_t *); +typedef ndis_status (*ndis_setinfo_handler)(ndis_handle, ndis_oid, + void *, uint32_t, uint32_t *, uint32_t *); +typedef ndis_status (*ndis_sendsingle_handler)(ndis_handle, + ndis_packet *, uint32_t); +typedef ndis_status (*ndis_sendmulti_handler)(ndis_handle, + ndis_packet **, uint32_t); +typedef void (*ndis_isr_handler)(uint8_t *, uint8_t *, ndis_handle); +typedef void (*ndis_interrupt_handler)(ndis_handle); +typedef int (*ndis_reset_handler)(uint8_t *, ndis_handle); +typedef void (*ndis_halt_handler)(ndis_handle); +typedef void (*ndis_return_handler)(ndis_handle, ndis_packet *); +typedef void (*ndis_enable_interrupts_handler)(ndis_handle); +typedef void (*ndis_disable_interrupts_handler)(ndis_handle); +typedef void (*ndis_shutdown_handler)(void *); +typedef void (*ndis_allocdone_handler)(ndis_handle, void *, + ndis_physaddr *, uint32_t, void *); +typedef uint8_t (*ndis_checkforhang_handler)(ndis_handle); + +typedef __stdcall ndis_status (*driver_entry)(void *, unicode_string *); + +extern image_patch_table ndis_functbl[]; + +#define NDIS_TASKQUEUE 1 +#define NDIS_SWI 2 + +#define NDIS_PSTATE_RUNNING 1 +#define NDIS_PSTATE_SLEEPING 2 + +#define NdisQueryPacket(p, pbufcnt, bufcnt, firstbuf, plen) \ + do { \ + if ((firstbuf) != NULL) { \ + ndis_buffer **_first; \ + _first = firstbuf; \ + *(_first) = (p)->np_private.npp_head; \ + } \ + if ((plen) || (bufcnt) || (pbufcnt)) { \ + if ((p)->np_private.npp_validcounts == FALSE) { \ + ndis_buffer *tmp; \ + unsigned int tlen = 0, pcnt = 0; \ + unsigned int add = 0; \ + unsigned int pktlen, off; \ + \ + tmp = (p)->np_private.npp_head; \ + while (tmp != NULL) { \ + off = MmGetMdlByteOffset(tmp); \ + pktlen = MmGetMdlByteCount(tmp);\ + tlen += pktlen; \ + pcnt += \ + NDIS_BUFFER_TO_SPAN_PAGES(tmp); \ + add++; \ + tmp = tmp->mdl_next; \ + } \ + (p)->np_private.npp_count = add; \ + (p)->np_private.npp_totlen = tlen; \ + (p)->np_private.npp_physcnt = pcnt; \ + (p)->np_private.npp_validcounts = TRUE; \ + } \ + if (pbufcnt) { \ + unsigned int *_pbufcnt; \ + _pbufcnt = (pbufcnt); \ + *(_pbufcnt) = (p)->np_private.npp_physcnt; \ + } \ + if (bufcnt) { \ + unsigned int *_bufcnt; \ + _bufcnt = (bufcnt); \ + *(_bufcnt) = (p)->np_private.npp_count; \ + } \ + if (plen) { \ + unsigned int *_plen; \ + _plen = (plen); \ + *(_plen) = (p)->np_private.npp_totlen; \ + } \ + } \ + } while (0) + +__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 **); +extern int ndis_ptom(struct mbuf **, ndis_packet *); +extern int ndis_get_info(void *, ndis_oid, void *, int *); +extern int ndis_set_info(void *, ndis_oid, void *, int *); +extern int ndis_get_supported_oids(void *, ndis_oid **, int *); +extern int ndis_send_packets(void *, ndis_packet **, int); +extern int ndis_send_packet(void *, ndis_packet *); +extern int ndis_convert_res(void *); +extern int ndis_alloc_amem(void *); +extern void ndis_free_amem(void *); +extern void ndis_free_packet(ndis_packet *); +extern void ndis_free_bufs(ndis_buffer *); +extern int ndis_reset_nic(void *); +extern int ndis_halt_nic(void *); +extern int ndis_shutdown_nic(void *); +extern int ndis_init_nic(void *); +extern int ndis_isr(void *, int *, int *); +extern void ndis_return_packet(void *, void *); +extern void ndis_enable_intr(void *); +extern void ndis_disable_intr(void *); +extern int ndis_init_dma(void *); +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_sched(void (*)(void *), void *, int); +extern int ndis_unsched(void (*)(void *), void *, int); +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); + +__stdcall extern uint32_t NdisAddDevice(driver_object *, device_object *); +__stdcall extern void NdisAllocatePacketPool(ndis_status *, + ndis_handle *, uint32_t, uint32_t); +__stdcall extern void NdisAllocatePacketPoolEx(ndis_status *, + ndis_handle *, uint32_t, uint32_t, uint32_t); +__stdcall extern uint32_t NdisPacketPoolUsage(ndis_handle); +__stdcall extern void NdisFreePacketPool(ndis_handle); +__stdcall extern void NdisAllocatePacket(ndis_status *, + ndis_packet **, ndis_handle); +__stdcall extern void NdisFreePacket(ndis_packet *); + +__END_DECLS + +#endif /* _NDIS_VAR_H_ */ diff --git a/sys/compat/ndis/ntoskrnl_var.h b/sys/compat/ndis/ntoskrnl_var.h new file mode 100644 index 000000000000..399ed54332d5 --- /dev/null +++ b/sys/compat/ndis/ntoskrnl_var.h @@ -0,0 +1,1253 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/compat/ndis/ntoskrnl_var.h,v 1.17.2.4 2005/03/31 04:24:35 wpaul Exp $ + */ + +#ifndef _NTOSKRNL_VAR_H_ +#define _NTOSKRNL_VAR_H_ + +/* + * us_buf is really a wchar_t *, but it's inconvenient to include + * all the necessary header goop needed to define it, and it's a + * pointer anyway, so for now, just make it a uint16_t *. + */ +struct unicode_string { + uint16_t us_len; + uint16_t us_maxlen; + uint16_t *us_buf; +}; + +typedef struct unicode_string unicode_string; + +/* + * Windows memory descriptor list. In Windows, it's possible for + * buffers to be passed between user and kernel contexts without + * copying. Buffers may also be allocated in either paged or + * non-paged memory regions. An MDL describes the pages of memory + * used to contain a particular buffer. Note that a single MDL + * may describe a buffer that spans multiple pages. An array of + * page addresses appears immediately after the MDL structure itself. + * MDLs are therefore implicitly variably sized, even though they + * don't look it. + * + * Note that in FreeBSD, we can take many shortcuts in the way + * we handle MDLs because: + * + * - We are only concerned with pages in kernel context. This means + * we will only ever use the kernel's memory map, and remapping + * of buffers is never needed. + * + * - Kernel pages can never be paged out, so we don't have to worry + * about whether or not a page is actually mapped before going to + * touch it. + */ + +struct mdl { + struct mdl *mdl_next; + uint16_t mdl_size; + uint16_t mdl_flags; + void *mdl_process; + void *mdl_mappedsystemva; + void *mdl_startva; + uint32_t mdl_bytecount; + uint32_t mdl_byteoffset; +}; + +typedef struct mdl mdl, ndis_buffer; + +/* MDL flags */ + +#define MDL_MAPPED_TO_SYSTEM_VA 0x0001 +#define MDL_PAGES_LOCKED 0x0002 +#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004 +#define MDL_ALLOCATED_FIXED_SIZE 0x0008 +#define MDL_PARTIAL 0x0010 +#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020 +#define MDL_IO_PAGE_READ 0x0040 +#define MDL_WRITE_OPERATION 0x0080 +#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100 +#define MDL_FREE_EXTRA_PTES 0x0200 +#define MDL_IO_SPACE 0x0800 +#define MDL_NETWORK_HEADER 0x1000 +#define MDL_MAPPING_CAN_FAIL 0x2000 +#define MDL_ALLOCATED_MUST_SUCCEED 0x4000 +#define MDL_ZONE_ALLOCED 0x8000 /* BSD private */ + +#define MDL_ZONE_PAGES 16 +#define MDL_ZONE_SIZE (sizeof(mdl) + (sizeof(vm_offset_t) * MDL_ZONE_PAGES)) + +/* Note: assumes x86 page size of 4K. */ + +#if PAGE_SIZE == 4096 +#define PAGE_SHIFT 12 +#elif PAGE_SIZE == 8192 +#define PAGE_SHIFT 13 +#else +#error PAGE_SHIFT undefined! +#endif + +#define SPAN_PAGES(ptr, len) \ + ((uint32_t)((((uintptr_t)(ptr) & (PAGE_SIZE - 1)) + \ + (len) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)) + +#define PAGE_ALIGN(ptr) \ + ((void *)((uintptr_t)(ptr) & ~(PAGE_SIZE - 1))) + +#define BYTE_OFFSET(ptr) \ + ((uint32_t)((uintptr_t)(ptr) & (PAGE_SIZE - 1))) + +#define MDL_PAGES(m) (vm_offset_t *)(m + 1) + +#define MmInitializeMdl(b, baseva, len) \ + (b)->mdl_next = NULL; \ + (b)->mdl_size = (uint16_t)(sizeof(mdl) + \ + (sizeof(vm_offset_t) * SPAN_PAGES((baseva), (len)))); \ + (b)->mdl_flags = 0; \ + (b)->mdl_startva = (void *)PAGE_ALIGN((baseva)); \ + (b)->mdl_byteoffset = BYTE_OFFSET((baseva)); \ + (b)->mdl_bytecount = (uint32_t)(len); + +#define MmGetMdlByteOffset(mdl) ((mdl)->mdl_byteoffset) +#define MmGetMdlByteCount(mdl) ((mdl)->mdl_bytecount) +#define MmGetMdlVirtualAddress(mdl) \ + ((void *)((char *)((mdl)->mdl_startva) + (mdl)->mdl_byteoffset)) +#define MmGetMdlStartVa(mdl) ((mdl)->mdl_startva) +#define MmGetMdlPfnArray(mdl) MDL_PAGES(mdl) + +#define WDM_MAJOR 1 +#define WDM_MINOR_WIN98 0x00 +#define WDM_MINOR_WINME 0x05 +#define WDM_MINOR_WIN2000 0x10 +#define WDM_MINOR_WINXP 0x20 +#define WDM_MINOR_WIN2003 0x30 + +/*- + * The ndis_kspin_lock type is called KSPIN_LOCK in MS-Windows. + * According to the Windows DDK header files, KSPIN_LOCK is defined like this: + * typedef ULONG_PTR KSPIN_LOCK; + * + * From basetsd.h (SDK, Feb. 2003): + * typedef [public] unsigned __int3264 ULONG_PTR, *PULONG_PTR; + * typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; + * typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR; + * + * The keyword __int3264 specifies an integral type that has the following + * properties: + * + It is 32-bit on 32-bit platforms + * + It is 64-bit on 64-bit platforms + * + It is 32-bit on the wire for backward compatibility. + * It gets truncated on the sending side and extended appropriately + * (signed or unsigned) on the receiving side. + * + * Thus register_t seems the proper mapping onto FreeBSD for spin locks. + */ + +typedef register_t kspin_lock; + +struct slist_entry { + struct slist_entry *sl_next; +}; + +typedef struct slist_entry slist_entry; + +union slist_header { + uint64_t slh_align; + struct { + struct slist_entry *slh_next; + uint16_t slh_depth; + uint16_t slh_seq; + } slh_list; +}; + +typedef union slist_header slist_header; + +struct list_entry { + struct list_entry *nle_flink; + struct list_entry *nle_blink; +}; + +typedef struct list_entry list_entry; + +#define INIT_LIST_HEAD(l) \ + (l)->nle_flink = (l)->nle_blink = (l) + +#define REMOVE_LIST_ENTRY(e) \ + do { \ + list_entry *b; \ + list_entry *f; \ + \ + 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) + +#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) + +#define INSERT_LIST_TAIL(l, e) \ + do { \ + list_entry *b; \ + \ + b = l->nle_blink; \ + e->nle_flink = l; \ + e->nle_blink = b; \ + b->nle_flink = (e); \ + l->nle_blink = (e); \ + } while (0) + +#define INSERT_LIST_HEAD(l, e) \ + do { \ + list_entry *f; \ + \ + f = l->nle_flink; \ + e->nle_flink = f; \ + e->nle_blink = l; \ + f->nle_blink = e; \ + l->nle_flink = e; \ + } while (0) + +struct nt_dispatch_header { + uint8_t dh_type; + uint8_t dh_abs; + uint8_t dh_size; + uint8_t dh_inserted; + uint32_t dh_sigstate; + list_entry dh_waitlisthead; +}; + +typedef struct nt_dispatch_header nt_dispatch_header; + +#define OTYPE_EVENT 0 +#define OTYPE_MUTEX 1 +#define OTYPE_THREAD 2 +#define OTYPE_TIMER 3 + +/* Windows dispatcher levels. */ + +#define PASSIVE_LEVEL 0 +#define LOW_LEVEL 0 +#define APC_LEVEL 1 +#define DISPATCH_LEVEL 2 +#define DEVICE_LEVEL (DISPATCH_LEVEL + 1) +#define PROFILE_LEVEL 27 +#define CLOCK1_LEVEL 28 +#define CLOCK2_LEVEL 28 +#define IPI_LEVEL 29 +#define POWER_LEVEL 30 +#define HIGH_LEVEL 31 + +#define SYNC_LEVEL_UP DISPATCH_LEVEL +#define SYNC_LEVEL_MP (IPI_LEVEL - 1) + +#define AT_PASSIVE_LEVEL(td) \ + ((td)->td_proc->p_flag & P_KTHREAD == FALSE) + +#define AT_DISPATCH_LEVEL(td) \ + ((td)->td_base_pri == PI_REALTIME) + +#define AT_DIRQL_LEVEL(td) \ + ((td)->td_priority <= PI_NET) + +#define AT_HIGH_LEVEL(td) \ + ((td)->td_critnest != 0) + +struct nt_objref { + nt_dispatch_header no_dh; + void *no_obj; + TAILQ_ENTRY(nt_objref) link; +}; + +TAILQ_HEAD(nt_objref_head, nt_objref); + +typedef struct nt_objref nt_objref; + +#define EVENT_TYPE_NOTIFY 0 +#define EVENT_TYPE_SYNC 1 + +/* + * We need to use the timeout()/untimeout() API for ktimers + * since timers can be initialized, but not destroyed (so + * malloc()ing our own callout structures would mean a leak, + * since there'd be no way to free() them). This means we + * need to use struct callout_handle, which is really just a + * pointer. To make it easier to deal with, we use a union + * to overlay the callout_handle over the k_timerlistentry. + * The latter is a list_entry, which is two pointers, so + * there's enough space available to hide a callout_handle + * there. + */ + +struct ktimer { + nt_dispatch_header k_header; + uint64_t k_duetime; + union { + list_entry k_timerlistentry; + struct callout_handle k_handle; + } u; + void *k_dpc; + uint32_t k_period; +}; + +#define k_timerlistentry u.k_timerlistentry +#define k_handle u.k_handle + +typedef struct ktimer ktimer; + +struct nt_kevent { + nt_dispatch_header k_header; +}; + +typedef struct nt_kevent nt_kevent; + +/* Kernel defered procedure call (i.e. timer callback) */ + +struct kdpc; +typedef __stdcall void (*kdpc_func)(struct kdpc *, void *, void *, void *); + +struct kdpc { + uint16_t k_type; + uint8_t k_num; + uint8_t k_importance; + list_entry k_dpclistentry; + void *k_deferedfunc; + void *k_deferredctx; + void *k_sysarg1; + void *k_sysarg2; + register_t k_lock; +}; + +typedef struct kdpc kdpc; + +/* + * Note: the acquisition count is BSD-specific. The Microsoft + * documentation says that mutexes can be acquired recursively + * by a given thread, but that you must release the mutex as + * many times as you acquired it before it will be set to the + * signalled state (i.e. before any other threads waiting on + * the object will be woken up). However the Windows KMUTANT + * structure has no field for keeping track of the number of + * acquisitions, so we need to add one ourselves. As long as + * driver code treats the mutex as opaque, we should be ok. + */ +struct kmutant { + nt_dispatch_header km_header; + union { + list_entry km_listentry; + uint32_t km_acquirecnt; + } u; + 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 + +struct general_lookaside { + slist_header gl_listhead; + uint16_t gl_depth; + uint16_t gl_maxdepth; + uint32_t gl_totallocs; + union { + uint32_t gl_allocmisses; + uint32_t gl_allochits; + } u_a; + uint32_t gl_totalfrees; + union { + uint32_t gl_freemisses; + uint32_t gl_freehits; + } u_m; + uint32_t gl_type; + uint32_t gl_tag; + uint32_t gl_size; + void *gl_allocfunc; + void *gl_freefunc; + list_entry gl_listent; + uint32_t gl_lasttotallocs; + union { + uint32_t gl_lastallocmisses; + uint32_t gl_lastallochits; + } u_l; + uint32_t gl_rsvd[2]; +}; + +typedef struct general_lookaside general_lookaside; + +struct npaged_lookaside_list { + general_lookaside nll_l; +#ifdef __i386__ + kspin_lock nll_obsoletelock; +#endif +}; + +typedef struct npaged_lookaside_list npaged_lookaside_list; +typedef struct npaged_lookaside_list paged_lookaside_list; + +typedef void * (*lookaside_alloc_func)(uint32_t, size_t, uint32_t); +typedef void (*lookaside_free_func)(void *); + +struct irp; + +struct kdevice_qentry { + list_entry kqe_devlistent; + uint32_t kqe_sortkey; + uint8_t kqe_inserted; +}; + +typedef struct kdevice_qentry kdevice_qentry; + +struct kdevice_queue { + uint16_t kq_type; + uint16_t kq_size; + list_entry kq_devlisthead; + kspin_lock kq_lock; + uint8_t kq_busy; +}; + +typedef struct kdevice_queue kdevice_queue; + +struct wait_ctx_block { + kdevice_qentry wcb_waitqueue; + void *wcb_devfunc; + void *wcb_devctx; + uint32_t wcb_mapregcnt; + void *wcb_devobj; + void *wcb_curirp; + void *wcb_bufchaindpc; +}; + +typedef struct wait_ctx_block wait_ctx_block; + +struct wait_block { + list_entry wb_waitlist; + void *wb_kthread; + nt_dispatch_header *wb_object; + struct wait_block *wb_next; + uint16_t wb_waitkey; + uint16_t wb_waittype; +}; + +typedef struct wait_block wait_block; + +#define THREAD_WAIT_OBJECTS 3 +#define MAX_WAIT_OBJECTS 64 + +#define WAITTYPE_ALL 0 +#define WAITTYPE_ANY 1 + +struct thread_context { + void *tc_thrctx; + void *tc_thrfunc; +}; + +typedef struct thread_context thread_context; + +/* Forward declaration */ +struct driver_object; +struct devobj_extension; + +struct driver_extension { + struct driver_object *dre_driverobj; + void *dre_adddevicefunc; + uint32_t dre_reinitcnt; + unicode_string dre_srvname; + + /* + * Drivers are allowed to add one or more custom extensions + * to the driver object, but there's no special pointer + * for them. Hang them off here for now. + */ + + list_entry dre_usrext; +}; + +typedef struct driver_extension driver_extension; + +struct custom_extension { + list_entry ce_list; + void *ce_clid; +}; + +typedef struct custom_extension custom_extension; + +/* + * 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 + * bus driver might detect two PCI ethernet cards on a given + * bus. The PCI bus driver will then allocate two device_objects + * for its own internal bookeeping purposes. This is analagous + * to the device_t that the FreeBSD PCI code allocates and passes + * into each PCI driver's probe and attach routines. + * + * When an ethernet driver claims one of the ethernet cards + * on the bus, it will create its own device_object. This is + * the Functional Device Object. This object is analagous to the + * device-specific softc structure. + */ + +struct device_object { + uint16_t do_type; + uint16_t do_size; + uint32_t do_refcnt; + struct driver_object *do_drvobj; + struct device_object *do_nextdev; + struct device_object *do_attacheddev; + struct irp *do_currirp; + void *do_iotimer; + uint32_t do_flags; + uint32_t do_characteristics; + void *do_vpb; + void *do_devext; + uint32_t do_devtype; + uint8_t do_stacksize; + union { + list_entry do_listent; + wait_ctx_block do_wcb; + } queue; + uint32_t do_alignreq; + kdevice_queue do_devqueue; + struct kdpc do_dpc; + uint32_t do_activethreads; + void *do_securitydesc; + struct nt_kevent do_devlock; + uint16_t do_sectorsz; + uint16_t do_spare1; + struct devobj_extension *do_devobj_ext; + void *do_rsvd; +}; + +typedef struct device_object device_object; + +struct devobj_extension { + uint16_t dve_type; + uint16_t dve_size; + device_object *dve_devobj; +}; + +typedef struct devobj_extension devobj_extension; + +/* Device object flags */ + +#define DO_VERIFY_VOLUME 0x00000002 +#define DO_BUFFERED_IO 0x00000004 +#define DO_EXCLUSIVE 0x00000008 +#define DO_DIRECT_IO 0x00000010 +#define DO_MAP_IO_BUFFER 0x00000020 +#define DO_DEVICE_HAS_NAME 0x00000040 +#define DO_DEVICE_INITIALIZING 0x00000080 +#define DO_SYSTEM_BOOT_PARTITION 0x00000100 +#define DO_LONG_TERM_REQUESTS 0x00000200 +#define DO_NEVER_LAST_DEVICE 0x00000400 +#define DO_SHUTDOWN_REGISTERED 0x00000800 +#define DO_BUS_ENUMERATED_DEVICE 0x00001000 +#define DO_POWER_PAGABLE 0x00002000 +#define DO_POWER_INRUSH 0x00004000 +#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000 + +/* Priority boosts */ + +#define IO_NO_INCREMENT 0 +#define IO_CD_ROM_INCREMENT 1 +#define IO_DISK_INCREMENT 1 +#define IO_KEYBOARD_INCREMENT 6 +#define IO_MAILSLOT_INCREMENT 2 +#define IO_MOUSE_INCREMENT 6 +#define IO_NAMED_PIPE_INCREMENT 2 +#define IO_NETWORK_INCREMENT 2 +#define IO_PARALLEL_INCREMENT 1 +#define IO_SERIAL_INCREMENT 2 +#define IO_SOUND_INCREMENT 8 +#define IO_VIDEO_INCREMENT 1 + +/* IRP major codes */ + +#define IRP_MJ_CREATE 0x00 +#define IRP_MJ_CREATE_NAMED_PIPE 0x01 +#define IRP_MJ_CLOSE 0x02 +#define IRP_MJ_READ 0x03 +#define IRP_MJ_WRITE 0x04 +#define IRP_MJ_QUERY_INFORMATION 0x05 +#define IRP_MJ_SET_INFORMATION 0x06 +#define IRP_MJ_QUERY_EA 0x07 +#define IRP_MJ_SET_EA 0x08 +#define IRP_MJ_FLUSH_BUFFERS 0x09 +#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a +#define IRP_MJ_SET_VOLUME_INFORMATION 0x0b +#define IRP_MJ_DIRECTORY_CONTROL 0x0c +#define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d +#define IRP_MJ_DEVICE_CONTROL 0x0e +#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f +#define IRP_MJ_SHUTDOWN 0x10 +#define IRP_MJ_LOCK_CONTROL 0x11 +#define IRP_MJ_CLEANUP 0x12 +#define IRP_MJ_CREATE_MAILSLOT 0x13 +#define IRP_MJ_QUERY_SECURITY 0x14 +#define IRP_MJ_SET_SECURITY 0x15 +#define IRP_MJ_POWER 0x16 +#define IRP_MJ_SYSTEM_CONTROL 0x17 +#define IRP_MJ_DEVICE_CHANGE 0x18 +#define IRP_MJ_QUERY_QUOTA 0x19 +#define IRP_MJ_SET_QUOTA 0x1a +#define IRP_MJ_PNP 0x1b +#define IRP_MJ_PNP_POWER IRP_MJ_PNP // Obsolete.... +#define IRP_MJ_MAXIMUM_FUNCTION 0x1b +#define IRP_MJ_SCSI IRP_MJ_INTERNAL_DEVICE_CONTROL + +/* IRP minor codes */ + +#define IRP_MN_QUERY_DIRECTORY 0x01 +#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02 +#define IRP_MN_USER_FS_REQUEST 0x00 + +#define IRP_MN_MOUNT_VOLUME 0x01 +#define IRP_MN_VERIFY_VOLUME 0x02 +#define IRP_MN_LOAD_FILE_SYSTEM 0x03 +#define IRP_MN_TRACK_LINK 0x04 +#define IRP_MN_KERNEL_CALL 0x04 + +#define IRP_MN_LOCK 0x01 +#define IRP_MN_UNLOCK_SINGLE 0x02 +#define IRP_MN_UNLOCK_ALL 0x03 +#define IRP_MN_UNLOCK_ALL_BY_KEY 0x04 + +#define IRP_MN_NORMAL 0x00 +#define IRP_MN_DPC 0x01 +#define IRP_MN_MDL 0x02 +#define IRP_MN_COMPLETE 0x04 +#define IRP_MN_COMPRESSED 0x08 + +#define IRP_MN_MDL_DPC (IRP_MN_MDL | IRP_MN_DPC) +#define IRP_MN_COMPLETE_MDL (IRP_MN_COMPLETE | IRP_MN_MDL) +#define IRP_MN_COMPLETE_MDL_DPC (IRP_MN_COMPLETE_MDL | IRP_MN_DPC) + +#define IRP_MN_SCSI_CLASS 0x01 + +#define IRP_MN_START_DEVICE 0x00 +#define IRP_MN_QUERY_REMOVE_DEVICE 0x01 +#define IRP_MN_REMOVE_DEVICE 0x02 +#define IRP_MN_CANCEL_REMOVE_DEVICE 0x03 +#define IRP_MN_STOP_DEVICE 0x04 +#define IRP_MN_QUERY_STOP_DEVICE 0x05 +#define IRP_MN_CANCEL_STOP_DEVICE 0x06 + +#define IRP_MN_QUERY_DEVICE_RELATIONS 0x07 +#define IRP_MN_QUERY_INTERFACE 0x08 +#define IRP_MN_QUERY_CAPABILITIES 0x09 +#define IRP_MN_QUERY_RESOURCES 0x0A +#define IRP_MN_QUERY_RESOURCE_REQUIREMENTS 0x0B +#define IRP_MN_QUERY_DEVICE_TEXT 0x0C +#define IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D + +#define IRP_MN_READ_CONFIG 0x0F +#define IRP_MN_WRITE_CONFIG 0x10 +#define IRP_MN_EJECT 0x11 +#define IRP_MN_SET_LOCK 0x12 +#define IRP_MN_QUERY_ID 0x13 +#define IRP_MN_QUERY_PNP_DEVICE_STATE 0x14 +#define IRP_MN_QUERY_BUS_INFORMATION 0x15 +#define IRP_MN_DEVICE_USAGE_NOTIFICATION 0x16 +#define IRP_MN_SURPRISE_REMOVAL 0x17 +#define IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18 + +#define IRP_MN_WAIT_WAKE 0x00 +#define IRP_MN_POWER_SEQUENCE 0x01 +#define IRP_MN_SET_POWER 0x02 +#define IRP_MN_QUERY_POWER 0x03 + +#define IRP_MN_QUERY_ALL_DATA 0x00 +#define IRP_MN_QUERY_SINGLE_INSTANCE 0x01 +#define IRP_MN_CHANGE_SINGLE_INSTANCE 0x02 +#define IRP_MN_CHANGE_SINGLE_ITEM 0x03 +#define IRP_MN_ENABLE_EVENTS 0x04 +#define IRP_MN_DISABLE_EVENTS 0x05 +#define IRP_MN_ENABLE_COLLECTION 0x06 +#define IRP_MN_DISABLE_COLLECTION 0x07 +#define IRP_MN_REGINFO 0x08 +#define IRP_MN_EXECUTE_METHOD 0x09 +#define IRP_MN_REGINFO_EX 0x0b + +/* IRP flags */ + +#define IRP_NOCACHE 0x00000001 +#define IRP_PAGING_IO 0x00000002 +#define IRP_MOUNT_COMPLETION 0x00000002 +#define IRP_SYNCHRONOUS_API 0x00000004 +#define IRP_ASSOCIATED_IRP 0x00000008 +#define IRP_BUFFERED_IO 0x00000010 +#define IRP_DEALLOCATE_BUFFER 0x00000020 +#define IRP_INPUT_OPERATION 0x00000040 +#define IRP_SYNCHRONOUS_PAGING_IO 0x00000040 +#define IRP_CREATE_OPERATION 0x00000080 +#define IRP_READ_OPERATION 0x00000100 +#define IRP_WRITE_OPERATION 0x00000200 +#define IRP_CLOSE_OPERATION 0x00000400 +#define IRP_DEFER_IO_COMPLETION 0x00000800 +#define IRP_OB_QUERY_NAME 0x00001000 +#define IRP_HOLD_DEVICE_QUEUE 0x00002000 +#define IRP_RETRY_IO_COMPLETION 0x00004000 +#define IRP_CLASS_CACHE_OPERATION 0x00008000 +#define IRP_SET_USER_EVENT IRP_CLOSE_OPERATION + +/* IRP I/O control flags */ + +#define IRP_QUOTA_CHARGED 0x01 +#define IRP_ALLOCATED_MUST_SUCCEED 0x02 +#define IRP_ALLOCATED_FIXED_SIZE 0x04 +#define IRP_LOOKASIDE_ALLOCATION 0x08 + +/* I/O method types */ + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* File access types */ + +#define FILE_ANY_ACCESS 0x0000 +#define FILE_SPECIAL_ACCESS FILE_ANY_ACCESS +#define FILE_READ_ACCESS 0x0001 +#define FILE_WRITE_ACCESS 0x0002 + +/* Recover I/O access method from IOCTL code. */ + +#define IO_METHOD(x) ((x) & 0xFFFFFFFC) + +/* Recover function code from IOCTL code */ + +#define IO_FUNC(x) (((x) & 0x7FFC) >> 2) + +/* Macro to construct an IOCTL code. */ + +#define IOCTL_CODE(dev, func, iomethod, acc) \ + ((dev) << 16) | (acc << 14) | (func << 2) | (iomethod)) + + +struct io_status_block { + union { + uint32_t isb_status; + void *isb_ptr; + } u; + register_t isb_info; +}; +#define isb_status u.isb_status +#define isb_ptr u.isb_ptr + +typedef struct io_status_block io_status_block; + +struct kapc { + uint16_t apc_type; + uint16_t apc_size; + uint32_t apc_spare0; + void *apc_thread; + list_entry apc_list; + void *apc_kernfunc; + void *apc_rundownfunc; + void *apc_normalfunc; + void *apc_normctx; + void *apc_sysarg1; + void *apc_sysarg2; + uint8_t apc_stateidx; + uint8_t apc_cpumode; + uint8_t apc_inserted; +}; + +typedef struct kapc kapc; + +typedef __stdcall uint32_t (*completion_func)(device_object *, + struct irp *, void *); +typedef __stdcall uint32_t (*cancel_func)(device_object *, + struct irp *); + +struct io_stack_location { + uint8_t isl_major; + uint8_t isl_minor; + uint8_t isl_flags; + uint8_t isl_ctl; + + /* + * There's a big-ass union here in the actual Windows + * definition of the stucture, but it contains stuff + * that doesn't really apply to BSD, and defining it + * all properly would require duplicating over a dozen + * other structures that we'll never use. Since the + * io_stack_location structure is opaque to drivers + * anyway, I'm not going to bother with the extra crap. + */ + + union { + struct { + uint32_t isl_len; + uint32_t *isl_key; + uint64_t isl_byteoff; + } isl_read; + struct { + uint32_t isl_len; + uint32_t *isl_key; + uint64_t isl_byteoff; + } isl_write; + struct { + uint32_t isl_obuflen; + uint32_t isl_ibuflen; + uint32_t isl_iocode; + void *isl_type3ibuf; + } isl_ioctl; + struct { + void *isl_arg1; + void *isl_arg2; + void *isl_arg3; + void *isl_arg4; + } isl_others; + } isl_parameters __attribute__((packed)); + + void *isl_devobj; + void *isl_fileobj; + completion_func isl_completionfunc; + void *isl_completionctx; +}; + +typedef struct io_stack_location io_stack_location; + +/* Stack location control flags */ + +#define SL_PENDING_RETURNED 0x01 +#define SL_INVOKE_ON_CANCEL 0x20 +#define SL_INVOKE_ON_SUCCESS 0x40 +#define SL_INVOKE_ON_ERROR 0x80 + +struct irp { + uint16_t irp_type; + uint16_t irp_size; + mdl *irp_mdl; + uint32_t irp_flags; + union { + struct irp *irp_master; + uint32_t irp_irpcnt; + void *irp_sysbuf; + } irp_assoc; + list_entry irp_thlist; + io_status_block irp_iostat; + uint8_t irp_reqmode; + uint8_t irp_pendingreturned; + uint8_t irp_stackcnt; + uint8_t irp_currentstackloc; + uint8_t irp_cancel; + uint8_t irp_cancelirql; + uint8_t irp_apcenv; + uint8_t irp_allocflags; + io_status_block *irp_usriostat; + nt_kevent *irp_usrevent; + union { + struct { + void *irp_apcfunc; + void *irp_apcctx; + } irp_asyncparms; + uint64_t irp_allocsz; + } irp_overlay; + cancel_func irp_cancelfunc; + void *irp_userbuf; + + /* Windows kernel info */ + + union { + struct { + union { + kdevice_qentry irp_dqe; + struct { + void *irp_drvctx[4]; + } s1; + } u1; + void *irp_thread; + char *irp_auxbuf; + struct { + list_entry irp_list; + union { + io_stack_location *irp_csl; + uint32_t irp_pkttype; + } u2; + } s2; + void *irp_fileobj; + } irp_overlay; + kapc irp_apc; + void *irp_compkey; + } irp_tail; +}; + +#define irp_csl s2.u2.irp_csl +#define irp_pkttype s2.u2.irp_pkttype + +typedef struct irp irp; + +#define InterlockedExchangePointer(dst, val) \ + (void *)FASTCALL2(InterlockedExchange, (uint32_t *)(dst), \ + (uintptr_t)(val)) + +#define IoSizeOfIrp(ssize) \ + ((uint16_t) (sizeof(irp) + ((ssize) * (sizeof(io_stack_location))))) + +#define IoSetCancelRoutine(irp, func) \ + (cancel_func)InterlockedExchangePointer( \ + (void *)&(ip)->irp_cancelfunc, (void *)(func)) + +#define IoGetCurrentIrpStackLocation(irp) \ + (irp)->irp_tail.irp_overlay.irp_csl + +#define IoGetNextIrpStackLocation(irp) \ + ((irp)->irp_tail.irp_overlay.irp_csl - 1) + +#define IoSetNextIrpStackLocation(irp) \ + do { \ + irp->irp_currentstackloc--; \ + irp->irp_tail.irp_overlay.irp_csl--; \ + } while(0) + +#define IoSetCompletionRoutine(irp, func, ctx, ok, err, cancel) \ + do { \ + io_stack_location *s; \ + s = IoGetNextIrpStackLocation((irp)); \ + s->isl_completionfunc = (func); \ + s->isl_completionctx = (ctx); \ + s->isl_ctl = 0; \ + if (ok) s->isl_ctl = SL_INVOKE_ON_SUCCESS; \ + if (err) s->isl_ctl |= SL_INVOKE_ON_ERROR; \ + if (cancel) s->isl_ctl |= SL_INVOKE_ON_CANCEL; \ + } while(0) + +#define IoMarkIrpPending(irp) \ + IoGetCurrentIrpStackLocation(irp)->isl_ctl |= SL_PENDING_RETURNED + +#define IoCopyCurrentIrpStackLocationToNext(irp) \ + do { \ + io_stack_location *src, *dst; \ + src = IoGetCurrentIrpStackLocation(irp); \ + dst = IoGetNextIrpStackLocation(irp); \ + bcopy((char *)src, (char *)dst, \ + offsetof(io_stack_location, isl_completionfunc)); \ + } while(0) + +#define IoSkipCurrentIrpStackLocation(irp) \ + do { \ + (irp)->irp_currentstackloc++; \ + (irp)->irp_tail.irp_overlay.irp_csl++; \ + } while(0) + +#define IoInitializeDpcRequest(dobj, dpcfunc) \ + KeInitializeDpc(&(dobj)->do_dpc, dpcfunc, dobj) + +#define IoRequestDpc(dobj, irp, ctx) \ + KeInsertQueueDpc(&(dobj)->do_dpc, irp, ctx) + +typedef __stdcall uint32_t (*driver_dispatch)(device_object *, irp *); + +/* + * The driver_object is allocated once for each driver that's loaded + * into the system. A new one is allocated for each driver and + * populated a bit via the driver's DriverEntry function. + * In general, a Windows DriverEntry() function will provide a pointer + * to its AddDevice() method and set up the dispatch table. + * For NDIS drivers, this is all done behind the scenes in the + * NdisInitializeWrapper() and/or NdisMRegisterMiniport() routines. + */ + +struct driver_object { + uint16_t dro_type; + uint16_t dro_size; + device_object *dro_devobj; + uint32_t dro_flags; + void *dro_driverstart; + uint32_t dro_driversize; + void *dro_driversection; + driver_extension *dro_driverext; + unicode_string dro_drivername; + unicode_string *dro_hwdb; + void *dro_pfastiodispatch; + void *dro_driverinitfunc; + void *dro_driverstartiofunc; + void *dro_driverunloadfunc; + driver_dispatch dro_dispatch[IRP_MJ_MAXIMUM_FUNCTION + 1]; +}; + +typedef struct driver_object driver_object; + +#define DEVPROP_DEVICE_DESCRIPTION 0x00000000 +#define DEVPROP_HARDWARE_ID 0x00000001 +#define DEVPROP_COMPATIBLE_IDS 0x00000002 +#define DEVPROP_BOOTCONF 0x00000003 +#define DEVPROP_BOOTCONF_TRANSLATED 0x00000004 +#define DEVPROP_CLASS_NAME 0x00000005 +#define DEVPROP_CLASS_GUID 0x00000006 +#define DEVPROP_DRIVER_KEYNAME 0x00000007 +#define DEVPROP_MANUFACTURER 0x00000008 +#define DEVPROP_FRIENDLYNAME 0x00000009 +#define DEVPROP_LOCATION_INFO 0x0000000A +#define DEVPROP_PHYSDEV_NAME 0x0000000B +#define DEVPROP_BUSTYPE_GUID 0x0000000C +#define DEVPROP_LEGACY_BUSTYPE 0x0000000D +#define DEVPROP_BUS_NUMBER 0x0000000E +#define DEVPROP_ENUMERATOR_NAME 0x0000000F +#define DEVPROP_ADDRESS 0x00000010 +#define DEVPROP_UINUMBER 0x00000011 +#define DEVPROP_INSTALL_STATE 0x00000012 +#define DEVPROP_REMOVAL_POLICY 0x00000013 + +/* Various supported device types (used with IoCreateDevice()) */ + +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000A +#define FILE_DEVICE_KEYBOARD 0x0000000B +#define FILE_DEVICE_MAILSLOT 0x0000000C +#define FILE_DEVICE_MIDI_IN 0x0000000D +#define FILE_DEVICE_MIDI_OUT 0x0000000E +#define FILE_DEVICE_MOUSE 0x0000000F +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001A +#define FILE_DEVICE_SERIAL_PORT 0x0000001B +#define FILE_DEVICE_SCREEN 0x0000001C +#define FILE_DEVICE_SOUND 0x0000001D +#define FILE_DEVICE_STREAMS 0x0000001E +#define FILE_DEVICE_TAPE 0x0000001F +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002A +#define FILE_DEVICE_MODEM 0x0000002B +#define FILE_DEVICE_VDM 0x0000002C +#define FILE_DEVICE_MASS_STORAGE 0x0000002D +#define FILE_DEVICE_SMB 0x0000002E +#define FILE_DEVICE_KS 0x0000002F +#define FILE_DEVICE_CHANGER 0x00000030 +#define FILE_DEVICE_SMARTCARD 0x00000031 +#define FILE_DEVICE_ACPI 0x00000032 +#define FILE_DEVICE_DVD 0x00000033 +#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 +#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 +#define FILE_DEVICE_DFS_VOLUME 0x00000036 +#define FILE_DEVICE_SERENUM 0x00000037 +#define FILE_DEVICE_TERMSRV 0x00000038 +#define FILE_DEVICE_KSEC 0x00000039 +#define FILE_DEVICE_FIPS 0x0000003A + +/* Device characteristics */ + +#define FILE_REMOVABLE_MEDIA 0x00000001 +#define FILE_READ_ONLY_DEVICE 0x00000002 +#define FILE_FLOPPY_DISKETTE 0x00000004 +#define FILE_WRITE_ONCE_MEDIA 0x00000008 +#define FILE_REMOTE_DEVICE 0x00000010 +#define FILE_DEVICE_IS_MOUNTED 0x00000020 +#define FILE_VIRTUAL_VOLUME 0x00000040 +#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 +#define FILE_DEVICE_SECURE_OPEN 0x00000100 + +/* Status codes */ + +#define STATUS_SUCCESS 0x00000000 +#define STATUS_USER_APC 0x000000C0 +#define STATUS_KERNEL_APC 0x00000100 +#define STATUS_ALERTED 0x00000101 +#define STATUS_TIMEOUT 0x00000102 +#define STATUS_PENDING 0x00000103 +#define STATUS_INVALID_PARAMETER 0xC000000D +#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010 +#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 +#define STATUS_BUFFER_TOO_SMALL 0xC0000023 +#define STATUS_MUTANT_NOT_OWNED 0xC0000046 +#define STATUS_INVALID_PARAMETER_2 0xC00000F0 +#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A + +#define STATUS_WAIT_0 0x00000000 + +/* Memory pool types, for ExAllocatePoolWithTag() */ + +#define NonPagedPool 0x00000000 +#define PagedPool 0x00000001 +#define NonPagedPoolMustSucceed 0x00000002 +#define DontUseThisType 0x00000003 +#define NonPagedPoolCacheAligned 0x00000004 +#define PagedPoolCacheAligned 0x00000005 +#define NonPagedPoolCacheAlignedMustS 0x00000006 +#define MaxPoolType 0x00000007 + +/* + * FreeBSD's kernel stack is 2 pages in size by default. The + * Windows stack is larger, so we need to give our threads more + * stack pages. 4 should be enough, we use 8 just to extra safe. + */ +#define NDIS_KSTACK_PAGES 8 + +extern image_patch_table ntoskrnl_functbl[]; +typedef void (*funcptr)(void); + +__BEGIN_DECLS +extern int windrv_libinit(void); +extern int windrv_libfini(void); +extern driver_object *windrv_lookup(vm_offset_t, char *); +extern int windrv_load(module_t, vm_offset_t, int); +extern int windrv_unload(module_t, vm_offset_t, int); +extern int windrv_create_pdo(driver_object *, device_t); +extern void windrv_destroy_pdo(driver_object *, device_t); +extern device_object *windrv_find_pdo(driver_object *, device_t); +extern int windrv_bus_attach(driver_object *, char *); +extern int windrv_wrap(funcptr, funcptr *); +extern int windrv_unwrap(funcptr); + +extern int ntoskrnl_libinit(void); +extern int ntoskrnl_libfini(void); +__stdcall extern void KeInitializeDpc(kdpc *, void *, void *); +__stdcall extern uint8_t KeInsertQueueDpc(kdpc *, void *, void *); +__stdcall extern uint8_t KeRemoveQueueDpc(kdpc *); +__stdcall extern void KeInitializeTimer(ktimer *); +__stdcall extern void KeInitializeTimerEx(ktimer *, uint32_t); +__stdcall extern uint8_t KeSetTimer(ktimer *, int64_t, kdpc *); +__stdcall extern uint8_t KeSetTimerEx(ktimer *, int64_t, uint32_t, kdpc *); +__stdcall extern uint8_t KeCancelTimer(ktimer *); +__stdcall extern uint8_t KeReadStateTimer(ktimer *); +__stdcall extern uint32_t KeWaitForSingleObject(nt_dispatch_header *, uint32_t, + uint32_t, uint8_t, int64_t *); +__stdcall extern void KeInitializeEvent(nt_kevent *, uint32_t, uint8_t); +__stdcall extern void KeClearEvent(nt_kevent *); +__stdcall extern uint32_t KeReadStateEvent(nt_kevent *); +__stdcall extern uint32_t KeSetEvent(nt_kevent *, uint32_t, uint8_t); +__stdcall extern uint32_t KeResetEvent(nt_kevent *); +#ifdef __i386__ +__fastcall extern void KefAcquireSpinLockAtDpcLevel(REGARGS1(kspin_lock *)); +__fastcall extern void KefReleaseSpinLockFromDpcLevel(REGARGS1(kspin_lock *)); +__stdcall extern uint8_t KeAcquireSpinLockRaiseToDpc(kspin_lock *); +#else +__stdcall extern void KeAcquireSpinLockAtDpcLevel(kspin_lock *); +__stdcall extern void KeReleaseSpinLockFromDpcLevel(kspin_lock *); +#endif +__stdcall extern void KeInitializeSpinLock(kspin_lock *); +__fastcall extern uintptr_t InterlockedExchange(REGARGS2(volatile uint32_t *, + uintptr_t)); +__stdcall extern void *ExAllocatePoolWithTag(uint32_t, size_t, uint32_t); +__stdcall extern void ExFreePool(void *); +__stdcall extern uint32_t IoAllocateDriverObjectExtension(driver_object *, + void *, uint32_t, void **); +__stdcall extern void *IoGetDriverObjectExtension(driver_object *, void *); +__stdcall extern uint32_t IoCreateDevice(driver_object *, uint32_t, + unicode_string *, uint32_t, uint32_t, uint8_t, device_object **); +__stdcall extern void IoDeleteDevice(device_object *); +__stdcall extern device_object *IoGetAttachedDevice(device_object *); +__fastcall extern uint32_t IofCallDriver(REGARGS2(device_object *, irp *)); +__fastcall extern void IofCompleteRequest(REGARGS2(irp *, uint8_t)); +__stdcall extern void IoAcquireCancelSpinLock(uint8_t *); +__stdcall extern void IoReleaseCancelSpinLock(uint8_t); +__stdcall extern uint8_t IoCancelIrp(irp *); +__stdcall extern void IoDetachDevice(device_object *); +__stdcall extern device_object *IoAttachDeviceToDeviceStack(device_object *, + device_object *); +__stdcall mdl *IoAllocateMdl(void *, uint32_t, uint8_t, uint8_t, irp *); +__stdcall void IoFreeMdl(mdl *); + +#define IoCallDriver(a, b) FASTCALL2(IofCallDriver, a, b) +#define IoCompleteRequest(a, b) FASTCALL2(IofCompleteRequest, a, b) + +/* + * On the Windows x86 arch, KeAcquireSpinLock() and KeReleaseSpinLock() + * routines live in the HAL. We try to imitate this behavior. + */ +#ifdef __i386__ +#define KeAcquireSpinLock(a, b) *(b) = FASTCALL1(KfAcquireSpinLock, a) +#define KeReleaseSpinLock(a, b) FASTCALL2(KfReleaseSpinLock, a, b) +#define KeRaiseIrql(a) FASTCALL1(KfRaiseIrql, a) +#define KeLowerIrql(a) FASTCALL1(KfLowerIrql, a) +#define KeAcquireSpinLockAtDpcLevel(a) \ + FASTCALL1(KefAcquireSpinLockAtDpcLevel, a) +#define KeReleaseSpinLockFromDpcLevel(a) \ + FASTCALL1(KefReleaseSpinLockFromDpcLevel, a) +#endif /* __i386__ */ + +#ifdef __amd64__ +#define KeAcquireSpinLock(a, b) *(b) = KfAcquireSpinLock(a) +#define KeReleaseSpinLock(a, b) KfReleaseSpinLock(a, b) + +/* + * These may need to be redefined later; + * not sure where they live on amd64 yet. + */ +#define KeRaiseIrql(a) KfRaiseIrql(a) +#define KeLowerIrql(a) KfLowerIrql(a) +#endif /* __amd64__ */ + +__END_DECLS + +#endif /* _NTOSKRNL_VAR_H_ */ diff --git a/sys/compat/ndis/pe_var.h b/sys/compat/ndis/pe_var.h new file mode 100644 index 000000000000..aa74e222df9b --- /dev/null +++ b/sys/compat/ndis/pe_var.h @@ -0,0 +1,573 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/compat/ndis/pe_var.h,v 1.8.2.2 2005/02/18 16:30:09 wpaul Exp $ + */ + +#ifndef _PE_VAR_H_ +#define _PE_VAR_H_ + +/* + * Image Format + */ + +#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ +#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ +#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ +#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ +#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ + +/* + * All PE files have one of these, just so if you attempt to + * run them, they'll print out a message telling you they can + * only be run in Windows. + */ + +struct image_dos_header { + uint16_t idh_magic; /* Magic number */ + uint16_t idh_cblp; /* Bytes on last page of file */ + uint16_t idh_cp; /* Pages in file */ + uint16_t idh_crlc; /* Relocations */ + uint16_t idh_cparhdr; /* Size of header in paragraphs */ + uint16_t idh_minalloc; /* Minimum extra paragraphs needed */ + uint16_t idh_maxalloc; /* Maximum extra paragraphs needed */ + uint16_t idh_ss; /* Initial (relative) SS value */ + uint16_t idh_sp; /* Initial SP value */ + uint16_t idh_csum; /* Checksum */ + uint16_t idh_ip; /* Initial IP value */ + uint16_t idh_cs; /* Initial (relative) CS value */ + uint16_t idh_lfarlc; /* File address of relocation table */ + uint16_t idh_ovno; /* Overlay number */ + uint16_t idh_rsvd1[4]; /* Reserved words */ + uint16_t idh_oemid; /* OEM identifier (for idh_oeminfo) */ + uint16_t idh_oeminfo; /* OEM information; oemid specific */ + uint16_t idh_rsvd2[10]; /* Reserved words */ + uint32_t idh_lfanew; /* File address of new exe header */ +}; + +typedef struct image_dos_header image_dos_header; + +/* + * File header format. + */ + +struct image_file_header { + uint16_t ifh_machine; /* Machine type */ + uint16_t ifh_numsections; /* # of sections */ + uint32_t ifh_timestamp; /* Date/time stamp */ + uint32_t ifh_symtblptr; /* Offset to symbol table */ + uint32_t ifh_numsyms; /* # of symbols */ + uint16_t ifh_optionalhdrlen; /* Size of optional header */ + uint16_t ifh_characteristics; /* Characteristics */ +}; + +typedef struct image_file_header image_file_header; + +/* Machine types */ + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I860 0x014d +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_R3000 0x0162 +#define IMAGE_FILE_MACHINE_R4000 0x0166 +#define IMAGE_FILE_MACHINE_R10000 0x0168 +#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 +#define IMAGE_FILE_MACHINE_ALPHA 0x0184 +#define IMAGE_FILE_MACHINE_SH3 0x01a2 +#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 +#define IMAGE_FILE_MACHINE_SH3E 0x01a4 +#define IMAGE_FILE_MACHINE_SH4 0x01a6 +#define IMAGE_FILE_MACHINE_SH5 0x01a8 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_AM33 0x01d3 +#define IMAGE_FILE_MACHINE_POWERPC 0x01f0 +#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_MIPS16 0x0266 +#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 +#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 +#define IMAGE_FILE_MACHINE_TRICORE 0x0520 +#define IMAGE_FILE_MACHINE_CEF 0x0cef +#define IMAGE_FILE_MACHINE_EBC 0x0ebc +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_M32R 0x9041 +#define IMAGE_FILE_MACHINE_CEE 0xc0ee + +/* Characteristics */ + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +#define IMAGE_FILE_16BIT_MACHINE 0x0040 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +/* + * Directory format. + */ + +struct image_data_directory { + uint32_t idd_vaddr; /* virtual address */ + uint32_t idd_size; /* size */ +}; + +typedef struct image_data_directory image_data_directory; + +#define IMAGE_DIRECTORY_ENTRIES_MAX 16 + +/* + * Optional header format. + */ + +struct image_optional_header { + + /* Standard fields */ + + uint16_t ioh_magic; + uint8_t ioh_linkerver_major; + uint8_t ioh_linkerver_minor; + uint32_t ioh_codesize; + uint32_t ioh_datasize; + uint32_t ioh_bsssize; + uint32_t ioh_entryaddr; + uint32_t ioh_codebaseaddr; +#ifndef __amd64__ + uint32_t ioh_databaseaddr; +#endif + + /* NT-specific fields */ + + uintptr_t ioh_imagebase; + uint32_t ioh_sectalign; + uint32_t ioh_filealign; + uint16_t ioh_osver_major; + uint16_t ioh_osver_minor; + uint16_t ioh_imagever_major; + uint16_t ioh_imagever_minor; + uint16_t ioh_subsys_major; + uint16_t ioh_subsys_minor; + uint32_t ioh_win32ver; + uint32_t ioh_imagesize; + uint32_t ioh_headersize; + uint32_t ioh_csum; + uint16_t ioh_subsys; + uint16_t ioh_dll_characteristics; + uintptr_t ioh_stackreservesize; + uintptr_t ioh_stackcommitsize; + uintptr_t ioh_heapreservesize; + uintptr_t ioh_heapcommitsize; + uint16_t ioh_loaderflags; + uint32_t ioh_rva_size_cnt; + image_data_directory ioh_datadir[IMAGE_DIRECTORY_ENTRIES_MAX]; +}; + +typedef struct image_optional_header image_optional_header; + +struct image_nt_header { + uint32_t inh_signature; + image_file_header inh_filehdr; + image_optional_header inh_optionalhdr; +}; + +typedef struct image_nt_header image_nt_header; + +/* Directory Entries */ + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */ +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /* Exception Directory */ +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /* Security Directory */ +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /* Base Relocation Table */ +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /* Debug Directory */ +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 /* Description String */ +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* Machine Value (MIPS GP) */ +#define IMAGE_DIRECTORY_ENTRY_TLS 9 /* TLS Directory */ +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 /* Load Configuration Directory */ +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 /* Bound Import Directory in headers */ +#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + +/* Resource types */ + +#define RT_CURSOR 1 +#define RT_BITMAP 2 +#define RT_ICON 3 +#define RT_MENU 4 +#define RT_DIALOG 5 +#define RT_STRING 6 +#define RT_FONTDIR 7 +#define RT_FONT 8 +#define RT_ACCELERATOR 9 +#define RT_RCDATA 10 +#define RT_MESSAGETABLE 11 +#define RT_GROUP_CURSOR 12 +#define RT_GROUP_ICON 14 +#define RT_VERSION 16 +#define RT_DLGINCLUDE 17 +#define RT_PLUGPLAY 19 +#define RT_VXD 20 +#define RT_ANICURSOR 21 +#define RT_ANIICON 22 +#define RT_HTML 23 + +/* + * Section header format. + */ + +#define IMAGE_SHORT_NAME_LEN 8 + +struct image_section_header { + uint8_t ish_name[IMAGE_SHORT_NAME_LEN]; + union { + uint32_t ish_paddr; + uint32_t ish_vsize; + } ish_misc; + uint32_t ish_vaddr; + uint32_t ish_rawdatasize; + uint32_t ish_rawdataaddr; + uint32_t ish_relocaddr; + uint32_t ish_linenumaddr; + uint16_t ish_numrelocs; + uint16_t ish_numlinenums; + uint32_t ish_characteristics; +}; + +typedef struct image_section_header image_section_header; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +/* + * Import format + */ + +struct image_import_by_name { + uint16_t iibn_hint; + uint8_t iibn_name[1]; +}; + +#define IMAGE_ORDINAL_FLAG 0x80000000 +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +struct image_import_descriptor { + uint32_t iid_import_name_table_addr; + uint32_t iid_timestamp; + uint32_t iid_forwardchain; + uint32_t iid_nameaddr; + uint32_t iid_import_address_table_addr; +}; + +typedef struct image_import_descriptor image_import_descriptor; + +struct image_base_reloc { + uint32_t ibr_vaddr; + uint32_t ibr_blocksize; + uint16_t ibr_rel[1]; +}; + +typedef struct image_base_reloc image_base_reloc; + +#define IMR_RELTYPE(x) ((x >> 12) & 0xF) +#define IMR_RELOFFSET(x) (x & 0xFFF) + +/* generic relocation types */ +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_SECTION 6 +#define IMAGE_REL_BASED_REL 7 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ +#define IMAGE_REL_BASED_DIR64 10 +#define IMAGE_REL_BASED_HIGH3ADJ 11 + +struct image_resource_directory_entry { + uint32_t irde_name; + uint32_t irde_dataoff; +}; + +typedef struct image_resource_directory_entry image_resource_directory_entry; + +#define RESOURCE_NAME_STR 0x80000000 +#define RESOURCE_DIR_FLAG 0x80000000 + +struct image_resource_directory { + uint32_t ird_characteristics; + uint32_t ird_timestamp; + uint16_t ird_majorver; + uint16_t ird_minorver; + uint16_t ird_named_entries; + uint16_t ird_id_entries; +#ifdef notdef + image_resource_directory_entry ird_entries[1]; +#endif +}; + +typedef struct image_resource_directory image_resource_directory; + +struct image_resource_directory_string { + uint16_t irds_len; + char irds_name[1]; +}; + +typedef struct image_resource_directory_string image_resource_directory_string; + +struct image_resource_directory_string_u { + uint16_t irds_len; + char irds_name[1]; +}; + +typedef struct image_resource_directory_string_u + image_resource_directory_string_u; + +struct image_resource_data_entry { + uint32_t irde_offset; + uint32_t irde_size; + uint32_t irde_codepage; + uint32_t irde_rsvd; +}; + +typedef struct image_resource_data_entry image_resource_data_entry; + +struct message_resource_data { + uint32_t mrd_numblocks; +#ifdef notdef + message_resource_block mrd_blocks[1]; +#endif +}; + +typedef struct message_resource_data message_resource_data; + +struct message_resource_block { + uint32_t mrb_lowid; + uint32_t mrb_highid; + uint32_t mrb_entryoff; +}; + +typedef struct message_resource_block message_resource_block; + +struct message_resource_entry { + uint16_t mre_len; + uint16_t mre_flags; + char mre_text[]; +}; + +typedef struct message_resource_entry message_resource_entry; + +#define MESSAGE_RESOURCE_UNICODE 0x0001 + +struct image_patch_table { + char *ipt_name; + void (*ipt_func)(void); + void (*ipt_wrap)(void); +}; + +typedef struct image_patch_table image_patch_table; + +/* + * Note: Windows uses the _stdcall calling convention. This means + * that the callback functions provided in the function table must + * be declared using __attribute__((__stdcall__)), otherwise the + * Windows code will likely screw up the %esp register and cause + * us to jump to an invalid address when it returns. + */ + +#ifdef __amd64__ +#define __stdcall +#define __regcall +#define __fastcall +#define REGARGS1(decl1) decl1 +#define REGARGS2(decl1, decl2) decl1, decl2 +#define REGCALL1(arg1) arg1 +#define REGCALL2(arg1, arg2) arg1, arg2 +#else +#define __stdcall __attribute__((__stdcall__)) +#define __regcall __attribute__((__regparm__(3))) +#define __fastcall __stdcall __regcall +#define REGARGS1(decl1) int dummy1, int dummy2, decl1 +#define REGARGS2(decl1, decl2) int dummy1, decl2, decl1 +#define REGCALL1(arg1) 0, 0, arg1 +#define REGCALL2(arg1, arg2) 0, arg2, arg1 +#endif + + +/* + * This mess allows us to call a _fastcall style routine with our + * version of gcc, which lacks __attribute__((__fastcall__)). Only + * has meaning on x86; everywhere else, it's a no-op. + */ + +#ifdef __i386__ +typedef __fastcall int (*fcall1)(REGARGS1(uint32_t)); +typedef __fastcall int (*fcall2)(REGARGS2(uint32_t, uint32_t)); +typedef __fastcall int (*fcall3)(REGARGS2(uint32_t, uint32_t), uint32_t); + +static __inline uint32_t +fastcall1(fcall1 f, uint32_t a) +{ + return(f(REGCALL1(a))); +} + +static __inline uint32_t +fastcall2(fcall2 f, uint32_t a, uint32_t b) +{ + return(f(REGCALL2(a, b))); +} + +static __inline uint32_t +fastcall3(fcall3 f, uint32_t a, uint32_t b, uint32_t c) +{ + return(f(REGCALL2(a, b), c)); +} + +#define FASTCALL1(f, a) \ + fastcall1((fcall1)(f), (uint32_t)(a)) +#define FASTCALL2(f, a, b) \ + fastcall2((fcall2)(f), (uint32_t)(a), (uint32_t)(b)) +#define FASTCALL3(f, a, b, c) \ + fastcall3((fcall3)(f), (uint32_t)(a), (uint32_t)(b), (uint32_t)(c)) +#else +#define FASTCALL1(f, a) (f)((a)) +#define FASTCALL2(f, a, b) (f)((a), (b)) +#define FASTCALL3(f, a, b, c) (f)((a), (b), (c)) +#endif /* __i386__ */ + + +/* + * AMD64 support. Microsoft uses a different calling convention + * than everyone else on the amd64 platform. Sadly, gcc has no + * built-in support for it (yet). + * + * The three major differences we're concerned with are: + * + * - The first 4 register-sized arguments are passed in the + * %rcx, %rdx, %r8 and %r9 registers, and the rest are pushed + * onto the stack. (The ELF ABI uses 6 registers, not 4). + * + * - The caller must reserve space on the stack for the 4 + * register arguments in case the callee has to spill them. + * + * - The stack myst be 16-byte aligned by the time the callee + * executes. A call instruction implicitly pushes an 8 byte + * return address onto the stack. We have to make sure that + * the amount of space we consume, plus the return address, + * is a multiple of 16 bytes in size. This means that in + * some cases, we may need to chew up an extra 8 bytes on + * the stack that will be unused. + * + * On the bright side, Microsoft seems to be using just the one + * calling convention for all functions on amd64, unlike x86 where + * they use a mix of _stdcall, _fastcall and _cdecl. + */ + +#ifdef __amd64__ + +extern uint64_t x86_64_call1(void *, uint64_t); +extern uint64_t x86_64_call2(void *, uint64_t, uint64_t); +extern uint64_t x86_64_call3(void *, uint64_t, uint64_t, uint64_t); +extern uint64_t x86_64_call4(void *, uint64_t, uint64_t, uint64_t, uint64_t); +extern uint64_t x86_64_call5(void *, uint64_t, uint64_t, uint64_t, uint64_t, + uint64_t); +extern uint64_t x86_64_call6(void *, uint64_t, uint64_t, uint64_t, uint64_t, + uint64_t, uint64_t); + + +#define MSCALL1(fn, a) \ + x86_64_call1((fn), (uint64_t)(a)) +#define MSCALL2(fn, a, b) \ + x86_64_call2((fn), (uint64_t)(a), (uint64_t)(b)) +#define MSCALL3(fn, a, b, c) \ + x86_64_call3((fn), (uint64_t)(a), (uint64_t)(b), \ + (uint64_t)(c)) +#define MSCALL4(fn, a, b, c, d) \ + x86_64_call4((fn), (uint64_t)(a), (uint64_t)(b), \ + (uint64_t)(c), (uint64_t)(d)) +#define MSCALL5(fn, a, b, c, d, e) \ + x86_64_call5((fn), (uint64_t)(a), (uint64_t)(b), \ + (uint64_t)(c), (uint64_t)(d), (uint64_t)(e)) +#define MSCALL6(fn, a, b, c, d, e, f) \ + x86_64_call6((fn), (uint64_t)(a), (uint64_t)(b), \ + (uint64_t)(c), (uint64_t)(d), (uint64_t)(e), (uint64_t)(f)) + +#else /* __amd64__ */ + +#define MSCALL1(fn, a) (fn)((a)) +#define MSCALL2(fn, a, b) (fn)((a), (b)) +#define MSCALL3(fn, a, b, c) (fn)((a), (b), (c)) +#define MSCALL4(fn, a, b, c, d) (fn)((a), (b), (c), (d)) +#define MSCALL5(fn, a, b, c, d, e) (fn)((a), (b), (c), (d), (e)) +#define MSCALL6(fn, a, b, c, d, e, f) (fn)((a), (b), (c), (d), (e), (f)) + +#endif /* __amd64__ */ + + +#define FUNC void(*)(void) +#define IMPORT_FUNC(x) { #x, (FUNC)x, NULL } +#define IMPORT_FUNC_MAP(x, y) { #x, (FUNC)y, NULL } + +__BEGIN_DECLS +extern int pe_get_dos_header(vm_offset_t, image_dos_header *); +extern int pe_is_nt_image(vm_offset_t); +extern int pe_get_optional_header(vm_offset_t, image_optional_header *); +extern int pe_get_file_header(vm_offset_t, image_file_header *); +extern int pe_get_section_header(vm_offset_t, image_section_header *); +extern int pe_numsections(vm_offset_t); +extern vm_offset_t pe_imagebase(vm_offset_t); +extern vm_offset_t pe_directory_offset(vm_offset_t, uint32_t); +extern vm_offset_t pe_translate_addr (vm_offset_t, vm_offset_t); +extern int pe_get_section(vm_offset_t, image_section_header *, const char *); +extern int pe_relocate(vm_offset_t); +extern int pe_get_import_descriptor(vm_offset_t, image_import_descriptor *, char *); +extern int pe_patch_imports(vm_offset_t, char *, image_patch_table *); +extern int pe_get_messagetable(vm_offset_t, message_resource_data **); +extern int pe_get_message(vm_offset_t, uint32_t, char **, int *, uint16_t *); +__END_DECLS + +#endif /* _PE_VAR_H_ */ diff --git a/sys/compat/ndis/resource_var.h b/sys/compat/ndis/resource_var.h new file mode 100644 index 000000000000..ddebaf7e4b81 --- /dev/null +++ b/sys/compat/ndis/resource_var.h @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 2005 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/compat/ndis/resource_var.h,v 1.2.2.1 2005/02/18 16:30:09 wpaul Exp $ + */ + +#ifndef _RESOURCE_VAR_H_ +#define _RESOURCE_VAR_H_ + +typedef int cm_resource_type; + +struct physaddr { + uint64_t np_quad; +#ifdef notdef + uint32_t np_low; + uint32_t np_high; +#endif +}; + +typedef struct physaddr physaddr; + +enum interface_type { + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + MaximumInterfaceType +}; + +typedef enum interface_type interface_type; + +#define CmResourceTypeNull 0 /* ResType_All or ResType_None (0x0000) */ +#define CmResourceTypePort 1 /* ResType_IO (0x0002) */ +#define CmResourceTypeInterrupt 2 /* ResType_IRQ (0x0004) */ +#define CmResourceTypeMemory 3 /* ResType_Mem (0x0001) */ +#define CmResourceTypeDma 4 /* ResType_DMA (0x0003) */ +#define CmResourceTypeDeviceSpecific 5 /* ResType_ClassSpecific (0xFFFF) */ +#define CmResourceTypeBusNumber 6 /* ResType_BusNumber (0x0006) */ +#define CmResourceTypeMaximum 7 +#define CmResourceTypeNonArbitrated 128 /* Not arbitrated if 0x80 bit set */ +#define CmResourceTypeConfigData 128 /* ResType_Reserved (0x8000) */ +#define CmResourceTypeDevicePrivate 129 /* ResType_DevicePrivate (0x8001) */ +#define CmResourceTypePcCardConfig 130 /* ResType_PcCardConfig (0x8002) */ + +enum cm_share_disposition { + CmResourceShareUndetermined = 0, /* Reserved */ + CmResourceShareDeviceExclusive, + CmResourceShareDriverExclusive, + CmResourceShareShared +}; + +typedef enum cm_share_disposition cm_share_disposition; + +/* Define the bit masks for Flags when type is CmResourceTypeInterrupt */ + +#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0 +#define CM_RESOURCE_INTERRUPT_LATCHED 1 + +/* Define the bit masks for Flags when type is CmResourceTypeMemory */ + +#define CM_RESOURCE_MEMORY_READ_WRITE 0x0000 +#define CM_RESOURCE_MEMORY_READ_ONLY 0x0001 +#define CM_RESOURCE_MEMORY_WRITE_ONLY 0x0002 +#define CM_RESOURCE_MEMORY_PREFETCHABLE 0x0004 + +#define CM_RESOURCE_MEMORY_COMBINEDWRITE 0x0008 +#define CM_RESOURCE_MEMORY_24 0x0010 +#define CM_RESOURCE_MEMORY_CACHEABLE 0x0020 + +/* Define the bit masks for Flags when type is CmResourceTypePort */ + +#define CM_RESOURCE_PORT_MEMORY 0x0000 +#define CM_RESOURCE_PORT_IO 0x0001 +#define CM_RESOURCE_PORT_10_BIT_DECODE 0x0004 +#define CM_RESOURCE_PORT_12_BIT_DECODE 0x0008 +#define CM_RESOURCE_PORT_16_BIT_DECODE 0x0010 +#define CM_RESOURCE_PORT_POSITIVE_DECODE 0x0020 +#define CM_RESOURCE_PORT_PASSIVE_DECODE 0x0040 +#define CM_RESOURCE_PORT_WINDOW_DECODE 0x0080 + +/* Define the bit masks for Flags when type is CmResourceTypeDma */ + +#define CM_RESOURCE_DMA_8 0x0000 +#define CM_RESOURCE_DMA_16 0x0001 +#define CM_RESOURCE_DMA_32 0x0002 +#define CM_RESOURCE_DMA_8_AND_16 0x0004 +#define CM_RESOURCE_DMA_BUS_MASTER 0x0008 +#define CM_RESOURCE_DMA_TYPE_A 0x0010 +#define CM_RESOURCE_DMA_TYPE_B 0x0020 +#define CM_RESOURCE_DMA_TYPE_F 0x0040 + +struct cm_partial_resource_desc { + uint8_t cprd_type; + uint8_t cprd_sharedisp; + uint16_t cprd_flags; + union { + struct { + physaddr cprd_start; + uint32_t cprd_len; + } cprd_generic; + struct { + physaddr cprd_start; + uint32_t cprd_len; + } cprd_port; + struct { + uint32_t cprd_level; + uint32_t cprd_vector; + uint32_t cprd_affinity; + } cprd_intr; + struct { + physaddr cprd_start; + uint32_t cprd_len; + } cprd_mem; + struct { + uint32_t cprd_chan; + uint32_t cprd_port; + uint32_t cprd_rsvd; + } cprd_dmachan; + struct { + uint32_t cprd_data[3]; + } cprd_devpriv; + struct { + uint32_t cprd_datasize; + uint32_t cprd_rsvd1; + uint32_t cprd_rsvd2; + } cprd_devspec; + } u __attribute__((packed)); +}; + +typedef struct cm_partial_resource_desc cm_partial_resource_desc; + +struct cm_partial_resource_list { + uint16_t cprl_version; + uint16_t cprl_revision; + uint32_t cprl_count; + cm_partial_resource_desc cprl_partial_descs[1]; +}; + +typedef struct cm_partial_resource_list cm_partial_resource_list; + +struct cm_full_resource_list { + interface_type cfrl_type; + uint32_t cfrl_busnum; + cm_partial_resource_desc cfrl_partiallist; +}; + +typedef struct cm_full_resource_list cm_full_resource_list; + +struct cm_resource_list { + uint32_t crl_count; + cm_full_resource_list crl_rlist; +}; + +typedef struct cm_resource_list cm_resource_list; + +typedef cm_partial_resource_list ndis_resource_list; + +#endif /* _RESOURCE_VAR_H_ */ diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c new file mode 100644 index 000000000000..2f1c9e4d08be --- /dev/null +++ b/sys/compat/ndis/subr_hal.c @@ -0,0 +1,412 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_hal.c,v 1.13.2.3 2005/03/31 04:24:35 wpaul Exp $"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +__stdcall static void KeStallExecutionProcessor(uint32_t); +__stdcall static void WRITE_PORT_BUFFER_ULONG(uint32_t *, + uint32_t *, uint32_t); +__stdcall static void WRITE_PORT_BUFFER_USHORT(uint16_t *, + uint16_t *, uint32_t); +__stdcall static void WRITE_PORT_BUFFER_UCHAR(uint8_t *, + uint8_t *, uint32_t); +__stdcall static void WRITE_PORT_ULONG(uint32_t *, uint32_t); +__stdcall static void WRITE_PORT_USHORT(uint16_t *, uint16_t); +__stdcall static void WRITE_PORT_UCHAR(uint8_t *, uint8_t); +__stdcall static uint32_t READ_PORT_ULONG(uint32_t *); +__stdcall static uint16_t READ_PORT_USHORT(uint16_t *); +__stdcall static uint8_t READ_PORT_UCHAR(uint8_t *); +__stdcall static void READ_PORT_BUFFER_ULONG(uint32_t *, + uint32_t *, uint32_t); +__stdcall static void READ_PORT_BUFFER_USHORT(uint16_t *, + uint16_t *, uint32_t); +__stdcall static void READ_PORT_BUFFER_UCHAR(uint8_t *, + uint8_t *, uint32_t); +__stdcall static uint64_t KeQueryPerformanceCounter(uint64_t *); +__stdcall static void dummy (void); + +extern struct mtx_pool *ndis_mtxpool; + +int +hal_libinit() +{ + image_patch_table *patch; + + patch = hal_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap); + patch++; + } + + return(0); +} + +int +hal_libfini() +{ + image_patch_table *patch; + + patch = hal_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + return(0); +} + +__stdcall static void +KeStallExecutionProcessor(usecs) + uint32_t usecs; +{ + DELAY(usecs); + return; +} + +__stdcall static void +WRITE_PORT_ULONG(port, val) + uint32_t *port; + uint32_t val; +{ + bus_space_write_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); + return; +} + +__stdcall static void +WRITE_PORT_USHORT(port, val) + uint16_t *port; + uint16_t val; +{ + bus_space_write_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); + return; +} + +__stdcall static void +WRITE_PORT_UCHAR(port, val) + uint8_t *port; + uint8_t val; +{ + bus_space_write_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); + return; +} + +__stdcall static void +WRITE_PORT_BUFFER_ULONG(port, val, cnt) + uint32_t *port; + uint32_t *val; + uint32_t cnt; +{ + bus_space_write_multi_4(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); + return; +} + +__stdcall static void +WRITE_PORT_BUFFER_USHORT(port, val, cnt) + uint16_t *port; + uint16_t *val; + uint32_t cnt; +{ + bus_space_write_multi_2(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); + return; +} + +__stdcall static void +WRITE_PORT_BUFFER_UCHAR(port, val, cnt) + uint8_t *port; + uint8_t *val; + uint32_t cnt; +{ + bus_space_write_multi_1(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); + return; +} + +__stdcall static uint16_t +READ_PORT_USHORT(port) + uint16_t *port; +{ + return(bus_space_read_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); +} + +__stdcall static uint32_t +READ_PORT_ULONG(port) + uint32_t *port; +{ + return(bus_space_read_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); +} + +__stdcall static uint8_t +READ_PORT_UCHAR(port) + uint8_t *port; +{ + return(bus_space_read_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); +} + +__stdcall static void +READ_PORT_BUFFER_ULONG(port, val, cnt) + uint32_t *port; + uint32_t *val; + uint32_t cnt; +{ + bus_space_read_multi_4(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); + return; +} + +__stdcall static void +READ_PORT_BUFFER_USHORT(port, val, cnt) + uint16_t *port; + uint16_t *val; + uint32_t cnt; +{ + bus_space_read_multi_2(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); + return; +} + +__stdcall static void +READ_PORT_BUFFER_UCHAR(port, val, cnt) + uint8_t *port; + uint8_t *val; + uint32_t cnt; +{ + bus_space_read_multi_1(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); + return; +} + +/* + * The spinlock implementation in Windows differs from that of FreeBSD. + * The basic operation of spinlocks involves two steps: 1) spin in a + * tight loop while trying to acquire a lock, 2) after obtaining the + * lock, disable preemption. (Note that on uniprocessor systems, you're + * allowed to skip the first step and just lock out pre-emption, since + * it's not possible for you to be in contention with another running + * thread.) Later, you release the lock then re-enable preemption. + * The difference between Windows and FreeBSD lies in how preemption + * is disabled. In FreeBSD, it's done using critical_enter(), which on + * the x86 arch translates to a cli instruction. This masks off all + * interrupts, and effectively stops the scheduler from ever running + * so _nothing_ can execute except the current thread. In Windows, + * preemption is disabled by raising the processor IRQL to DISPATCH_LEVEL. + * This stops other threads from running, but does _not_ block device + * interrupts. This means ISRs can still run, and they can make other + * threads runable, but those other threads won't be able to execute + * until the current thread lowers the IRQL to something less than + * DISPATCH_LEVEL. + * + * There's another commonly used IRQL in Windows, which is APC_LEVEL. + * An APC is an Asynchronous Procedure Call, which differs from a DPC + * (Defered Procedure Call) in that a DPC is queued up to run in + * another thread, while an APC runs in the thread that scheduled + * it (similar to a signal handler in a UNIX process). We don't + * actually support the notion of APCs in FreeBSD, so for now, the + * only IRQLs we're interested in are DISPATCH_LEVEL and PASSIVE_LEVEL. + * + * To simulate DISPATCH_LEVEL, we raise the current thread's priority + * to PI_REALTIME, which is the highest we can give it. This should, + * if I understand things correctly, prevent anything except for an + * interrupt thread from preempting us. PASSIVE_LEVEL is basically + * everything else. + * + * Be aware that, at least on the x86 arch, the Windows spinlock + * functions are divided up in peculiar ways. The actual spinlock + * functions are KfAcquireSpinLock() and KfReleaseSpinLock(), and + * they live in HAL.dll. Meanwhile, KeInitializeSpinLock(), + * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel() + * live in ntoskrnl.exe. Most Windows source code will call + * KeAcquireSpinLock() and KeReleaseSpinLock(), but these are just + * macros that call KfAcquireSpinLock() and KfReleaseSpinLock(). + * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel() + * perform the lock aquisition/release functions without doing the + * IRQL manipulation, and are used when one is already running at + * DISPATCH_LEVEL. Make sense? Good. + * + * According to the Microsoft documentation, any thread that calls + * 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. + */ + +__fastcall uint8_t +KfAcquireSpinLock(REGARGS1(kspin_lock *lock)) +{ + uint8_t oldirql; + + /* I am so going to hell for this. */ + if (KeGetCurrentIrql() > DISPATCH_LEVEL) + panic("IRQL_NOT_LESS_THAN_OR_EQUAL"); + + oldirql = KeRaiseIrql(DISPATCH_LEVEL); + KeAcquireSpinLockAtDpcLevel(lock); + + return(oldirql); +} + +__fastcall void +KfReleaseSpinLock(REGARGS2(kspin_lock *lock, uint8_t newirql)) +{ + KeReleaseSpinLockFromDpcLevel(lock); + KeLowerIrql(newirql); + + return; +} + +__stdcall uint8_t +KeGetCurrentIrql(void) +{ + if (AT_DISPATCH_LEVEL(curthread)) + return(DISPATCH_LEVEL); + return(PASSIVE_LEVEL); +} + +__stdcall static uint64_t +KeQueryPerformanceCounter(freq) + uint64_t *freq; +{ + if (freq != NULL) + *freq = hz; + + return((uint64_t)ticks); +} + +__fastcall uint8_t +KfRaiseIrql(REGARGS1(uint8_t irql)) +{ + uint8_t oldirql; + + if (irql < KeGetCurrentIrql()) + 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); + + return(oldirql); +} + +__fastcall void +KfLowerIrql(REGARGS1(uint8_t oldirql)) +{ + if (oldirql == DISPATCH_LEVEL) + return; + + 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); + + return; +} + +__stdcall +static void dummy() +{ + printf ("hal dummy called...\n"); + return; +} + +image_patch_table hal_functbl[] = { + IMPORT_FUNC(KeStallExecutionProcessor), + IMPORT_FUNC(WRITE_PORT_ULONG), + IMPORT_FUNC(WRITE_PORT_USHORT), + IMPORT_FUNC(WRITE_PORT_UCHAR), + IMPORT_FUNC(WRITE_PORT_BUFFER_ULONG), + IMPORT_FUNC(WRITE_PORT_BUFFER_USHORT), + IMPORT_FUNC(WRITE_PORT_BUFFER_UCHAR), + IMPORT_FUNC(READ_PORT_ULONG), + IMPORT_FUNC(READ_PORT_USHORT), + IMPORT_FUNC(READ_PORT_UCHAR), + IMPORT_FUNC(READ_PORT_BUFFER_ULONG), + IMPORT_FUNC(READ_PORT_BUFFER_USHORT), + IMPORT_FUNC(READ_PORT_BUFFER_UCHAR), + IMPORT_FUNC(KfAcquireSpinLock), + IMPORT_FUNC(KfReleaseSpinLock), + IMPORT_FUNC(KeGetCurrentIrql), + IMPORT_FUNC(KeQueryPerformanceCounter), + IMPORT_FUNC(KfLowerIrql), + IMPORT_FUNC(KfRaiseIrql), + + /* + * This last entry is a catch-all for any function we haven't + * implemented yet. The PE import list patching routine will + * use it for any function that doesn't have an explicit match + * in this table. + */ + + { NULL, (FUNC)dummy, NULL }, + + /* End of list. */ + + { NULL, NULL, NULL } +}; diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c new file mode 100644 index 000000000000..d4badc3c8f5b --- /dev/null +++ b/sys/compat/ndis/subr_ndis.c @@ -0,0 +1,3305 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_ndis.c,v 1.67.2.7 2005/03/31 21:50:11 wpaul Exp $"); + +/* + * This file implements a translation layer between the BSD networking + * infrasturcture and Windows(R) NDIS network driver modules. A Windows + * NDIS driver calls into several functions in the NDIS.SYS Windows + * kernel module and exports a table of functions designed to be called + * by the NDIS subsystem. Using the PE loader, we can patch our own + * versions of the NDIS routines into a given Windows driver module and + * convince the driver that it is in fact running on Windows. + * + * We provide a table of all our implemented NDIS routines which is patched + * into the driver object code. All our exported routines must use the + * _stdcall calling convention, since that's what the Windows object code + * expects. + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static char ndis_filepath[MAXPATHLEN]; +extern struct nd_head ndis_devhead; + +SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath, + MAXPATHLEN, "Path used by NdisOpenFile() to search for files"); + +__stdcall static void NdisInitializeWrapper(ndis_handle *, + driver_object *, void *, void *); +__stdcall static ndis_status NdisMRegisterMiniport(ndis_handle, + ndis_miniport_characteristics *, int); +__stdcall static ndis_status NdisAllocateMemoryWithTag(void **, + uint32_t, uint32_t); +__stdcall static ndis_status NdisAllocateMemory(void **, + uint32_t, uint32_t, ndis_physaddr); +__stdcall static void NdisFreeMemory(void *, uint32_t, uint32_t); +__stdcall static ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle, + uint32_t, uint32_t, ndis_interface_type); +__stdcall static void NdisOpenConfiguration(ndis_status *, + ndis_handle *, ndis_handle); +__stdcall static void NdisOpenConfigurationKeyByIndex(ndis_status *, + ndis_handle, uint32_t, ndis_unicode_string *, ndis_handle *); +__stdcall static void NdisOpenConfigurationKeyByName(ndis_status *, + ndis_handle, ndis_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 *); +__stdcall static void NdisReadConfiguration(ndis_status *, ndis_config_parm **, + ndis_handle, ndis_unicode_string *, ndis_parm_type); +__stdcall static void NdisWriteConfiguration(ndis_status *, ndis_handle, + ndis_unicode_string *, ndis_config_parm *); +__stdcall static void NdisCloseConfiguration(ndis_handle); +__stdcall static void NdisAllocateSpinLock(ndis_spin_lock *); +__stdcall static void NdisFreeSpinLock(ndis_spin_lock *); +__stdcall static void NdisAcquireSpinLock(ndis_spin_lock *); +__stdcall static void NdisReleaseSpinLock(ndis_spin_lock *); +__stdcall static void NdisDprAcquireSpinLock(ndis_spin_lock *); +__stdcall static void NdisDprReleaseSpinLock(ndis_spin_lock *); +__stdcall static uint32_t NdisReadPciSlotInformation(ndis_handle, uint32_t, + uint32_t, void *, uint32_t); +__stdcall static uint32_t NdisWritePciSlotInformation(ndis_handle, uint32_t, + uint32_t, void *, uint32_t); +static void NdisWriteErrorLogEntry(ndis_handle, ndis_error_code, uint32_t, ...); +static void ndis_map_cb(void *, bus_dma_segment_t *, int, int); +__stdcall static void NdisMStartBufferPhysicalMapping(ndis_handle, + ndis_buffer *, uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *); +__stdcall static void NdisMCompleteBufferPhysicalMapping(ndis_handle, + ndis_buffer *, uint32_t); +__stdcall static void NdisMInitializeTimer(ndis_miniport_timer *, ndis_handle, + ndis_timer_function, void *); +__stdcall static void NdisInitializeTimer(ndis_timer *, + ndis_timer_function, void *); +__stdcall static void NdisSetTimer(ndis_timer *, uint32_t); +__stdcall static void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t); +__stdcall static void NdisMCancelTimer(ndis_timer *, uint8_t *); +__stdcall static void ndis_timercall(kdpc *, ndis_miniport_timer *, + void *, void *); +__stdcall static void NdisMQueryAdapterResources(ndis_status *, ndis_handle, + ndis_resource_list *, uint32_t *); +__stdcall static ndis_status NdisMRegisterIoPortRange(void **, + ndis_handle, uint32_t, uint32_t); +__stdcall static void NdisMDeregisterIoPortRange(ndis_handle, + uint32_t, uint32_t, void *); +__stdcall static void NdisReadNetworkAddress(ndis_status *, void **, + uint32_t *, ndis_handle); +__stdcall static ndis_status NdisQueryMapRegisterCount(uint32_t, uint32_t *); +__stdcall static ndis_status NdisMAllocateMapRegisters(ndis_handle, + uint32_t, uint8_t, uint32_t, uint32_t); +__stdcall static void NdisMFreeMapRegisters(ndis_handle); +static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int); +__stdcall static void NdisMAllocateSharedMemory(ndis_handle, uint32_t, + uint8_t, void **, ndis_physaddr *); +static void ndis_asyncmem_complete(void *); +__stdcall static ndis_status NdisMAllocateSharedMemoryAsync(ndis_handle, + uint32_t, uint8_t, void *); +__stdcall static void NdisMFreeSharedMemory(ndis_handle, uint32_t, + uint8_t, void *, ndis_physaddr); +__stdcall static ndis_status NdisMMapIoSpace(void **, ndis_handle, + ndis_physaddr, uint32_t); +__stdcall static void NdisMUnmapIoSpace(ndis_handle, void *, uint32_t); +__stdcall static uint32_t NdisGetCacheFillSize(void); +__stdcall static uint32_t NdisMGetDmaAlignment(ndis_handle); +__stdcall static ndis_status NdisMInitializeScatterGatherDma(ndis_handle, + uint8_t, uint32_t); +__stdcall static void NdisUnchainBufferAtFront(ndis_packet *, ndis_buffer **); +__stdcall static void NdisUnchainBufferAtBack(ndis_packet *, ndis_buffer **); +__stdcall static void NdisAllocateBufferPool(ndis_status *, + ndis_handle *, uint32_t); +__stdcall static void NdisFreeBufferPool(ndis_handle); +__stdcall static void NdisAllocateBuffer(ndis_status *, ndis_buffer **, + ndis_handle, void *, uint32_t); +__stdcall static void NdisFreeBuffer(ndis_buffer *); +__stdcall static uint32_t NdisBufferLength(ndis_buffer *); +__stdcall static void NdisQueryBuffer(ndis_buffer *, void **, uint32_t *); +__stdcall static void NdisQueryBufferSafe(ndis_buffer *, void **, + uint32_t *, uint32_t); +__stdcall static void *NdisBufferVirtualAddress(ndis_buffer *); +__stdcall static void *NdisBufferVirtualAddressSafe(ndis_buffer *, uint32_t); +__stdcall static void NdisAdjustBufferLength(ndis_buffer *, int); +__stdcall static uint32_t NdisInterlockedIncrement(uint32_t *); +__stdcall static uint32_t NdisInterlockedDecrement(uint32_t *); +__stdcall static void NdisInitializeEvent(ndis_event *); +__stdcall static void NdisSetEvent(ndis_event *); +__stdcall static void NdisResetEvent(ndis_event *); +__stdcall static uint8_t NdisWaitEvent(ndis_event *, uint32_t); +__stdcall static ndis_status NdisUnicodeStringToAnsiString(ndis_ansi_string *, + ndis_unicode_string *); +__stdcall static ndis_status + NdisAnsiStringToUnicodeString(ndis_unicode_string *, + ndis_ansi_string *); +__stdcall static ndis_status NdisMPciAssignResources(ndis_handle, + uint32_t, ndis_resource_list **); +__stdcall static ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *, + ndis_handle, uint32_t, uint32_t, uint8_t, + uint8_t, ndis_interrupt_mode); +__stdcall static void NdisMDeregisterInterrupt(ndis_miniport_interrupt *); +__stdcall static void NdisMRegisterAdapterShutdownHandler(ndis_handle, void *, + ndis_shutdown_handler); +__stdcall static void NdisMDeregisterAdapterShutdownHandler(ndis_handle); +__stdcall static uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *); +__stdcall static void NdisGetBufferPhysicalArraySize(ndis_buffer *, + uint32_t *); +__stdcall static void NdisQueryBufferOffset(ndis_buffer *, + uint32_t *, uint32_t *); +__stdcall static void NdisMSleep(uint32_t); +__stdcall static uint32_t NdisReadPcmciaAttributeMemory(ndis_handle, + uint32_t, void *, uint32_t); +__stdcall static uint32_t NdisWritePcmciaAttributeMemory(ndis_handle, + uint32_t, void *, uint32_t); +__stdcall static list_entry *NdisInterlockedInsertHeadList(list_entry *, + list_entry *, ndis_spin_lock *); +__stdcall static list_entry *NdisInterlockedRemoveHeadList(list_entry *, + ndis_spin_lock *); +__stdcall static list_entry *NdisInterlockedInsertTailList(list_entry *, + list_entry *, ndis_spin_lock *); +__stdcall static uint8_t + NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *, + void *, void *); +__stdcall static void NdisGetCurrentSystemTime(uint64_t *); +__stdcall static void NdisGetSystemUpTime(uint32_t *); +__stdcall static void NdisInitializeString(ndis_unicode_string *, char *); +__stdcall static void NdisInitAnsiString(ndis_ansi_string *, char *); +__stdcall static void NdisInitUnicodeString(ndis_unicode_string *, + uint16_t *); +__stdcall static void NdisFreeString(ndis_unicode_string *); +__stdcall static ndis_status NdisMRemoveMiniport(ndis_handle *); +__stdcall static void NdisTerminateWrapper(ndis_handle, void *); +__stdcall static void NdisMGetDeviceProperty(ndis_handle, device_object **, + device_object **, device_object **, cm_resource_list *, + cm_resource_list *); +__stdcall static void NdisGetFirstBufferFromPacket(ndis_packet *, + ndis_buffer **, void **, uint32_t *, uint32_t *); +__stdcall 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 *); +__stdcall static void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *, + ndis_unicode_string *, ndis_physaddr); +__stdcall static void NdisMapFile(ndis_status *, void **, ndis_handle); +__stdcall static void NdisUnmapFile(ndis_handle); +__stdcall static void NdisCloseFile(ndis_handle); +__stdcall static uint8_t NdisSystemProcessorCount(void); +__stdcall static void NdisMIndicateStatusComplete(ndis_handle); +__stdcall static void NdisMIndicateStatus(ndis_handle, ndis_status, + void *, uint32_t); +static void ndis_workfunc(void *); +static funcptr ndis_findwrap(funcptr); +__stdcall static ndis_status NdisScheduleWorkItem(ndis_work_item *); +__stdcall static void NdisCopyFromPacketToPacket(ndis_packet *, + uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *); +__stdcall static void NdisCopyFromPacketToPacketSafe(ndis_packet *, + uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t); +__stdcall static ndis_status NdisMRegisterDevice(ndis_handle, + ndis_unicode_string *, ndis_unicode_string *, driver_dispatch **, + void **, ndis_handle *); +__stdcall static ndis_status NdisMDeregisterDevice(ndis_handle); +__stdcall static ndis_status + NdisMQueryAdapterInstanceName(ndis_unicode_string *, + ndis_handle); +__stdcall static void NdisMRegisterUnloadHandler(ndis_handle, void *); +__stdcall static void dummy(void); + +/* + * Some really old drivers do not properly check the return value + * from NdisAllocatePacket() and NdisAllocateBuffer() and will + * sometimes allocate few more buffers/packets that they originally + * requested when they created the pool. To prevent this from being + * a problem, we allocate a few extra buffers/packets beyond what + * the driver asks for. This #define controls how many. + */ +#define NDIS_POOL_EXTRA 16 + +int +ndis_libinit() +{ + image_patch_table *patch; + + strcpy(ndis_filepath, "/compat/ndis"); + + patch = ndis_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap); + patch++; + } + + return(0); +} + +int +ndis_libfini() +{ + image_patch_table *patch; + + patch = ndis_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + return(0); +} + +static funcptr +ndis_findwrap(func) + funcptr func; +{ + image_patch_table *patch; + + patch = ndis_functbl; + while (patch->ipt_func != NULL) { + if ((funcptr)patch->ipt_func == func) + return((funcptr)patch->ipt_wrap); + patch++; + } + + return(NULL); +} + +/* + * 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 + */ +__stdcall static void +NdisInitializeWrapper(wrapper, drv, path, unused) + ndis_handle *wrapper; + driver_object *drv; + void *path; + void *unused; +{ + /* + * As of yet, I haven't come up with a compelling + * reason to define a private NDIS wrapper structure, + * so we use a pointer to the driver object as the + * wrapper handle. The driver object has the miniport + * characteristics struct for this driver hung off it + * via IoAllocateDriverObjectExtension(), and that's + * really all the private data we need. + */ + + *wrapper = drv; + + /* + * If this was really Windows, we'd be registering dispatch + * routines for the NDIS miniport module here, but we're + * not Windows so all we really need to do is set up an + * AddDevice function that'll be invoked when a new device + * instance appears. + */ + + drv->dro_driverext->dre_adddevicefunc = NdisAddDevice; + + return; +} + +__stdcall static void +NdisTerminateWrapper(handle, syspec) + ndis_handle handle; + void *syspec; +{ + /* Nothing to see here, move along. */ + return; +} + +__stdcall static ndis_status +NdisMRegisterMiniport(handle, characteristics, len) + ndis_handle handle; + ndis_miniport_characteristics *characteristics; + int len; +{ + ndis_miniport_characteristics *ch = NULL; + driver_object *drv; + + drv = (driver_object *)handle; + + /* + * We need to save the NDIS miniport characteristics + * somewhere. This data is per-driver, not per-device + * (all devices handled by the same driver have the + * same characteristics) so we hook it onto the driver + * object using IoAllocateDriverObjectExtension(). + * The extra extension info is automagically deleted when + * the driver is unloaded (see windrv_unload()). + */ + + if (IoAllocateDriverObjectExtension(drv, (void *)1, + sizeof(ndis_miniport_characteristics), (void **)&ch) != + STATUS_SUCCESS) + return(NDIS_STATUS_RESOURCES); + + bzero((char *)ch, sizeof(ndis_miniport_characteristics)); + + bcopy((char *)characteristics, (char *)ch, len); + + if (ch->nmc_version_major < 5 || ch->nmc_version_minor < 1) { + ch->nmc_shutdown_handler = NULL; + ch->nmc_canceltxpkts_handler = NULL; + ch->nmc_pnpevent_handler = NULL; + } + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +NdisAllocateMemoryWithTag(vaddr, len, tag) + void **vaddr; + uint32_t len; + uint32_t tag; +{ + void *mem; + + + mem = ExAllocatePoolWithTag(NonPagedPool, len, tag); + if (mem == NULL) + return(NDIS_STATUS_RESOURCES); + *vaddr = mem; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +NdisAllocateMemory(vaddr, len, flags, highaddr) + void **vaddr; + uint32_t len; + uint32_t flags; + ndis_physaddr highaddr; +{ + void *mem; + + mem = ExAllocatePoolWithTag(NonPagedPool, len, 0); + if (mem == NULL) + return(NDIS_STATUS_RESOURCES); + *vaddr = mem; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisFreeMemory(vaddr, len, flags) + void *vaddr; + uint32_t len; + uint32_t flags; +{ + if (len == 0) + return; + + ExFreePool(vaddr); + + return; +} + +__stdcall static ndis_status +NdisMSetAttributesEx(adapter_handle, adapter_ctx, hangsecs, + flags, iftype) + ndis_handle adapter_handle; + ndis_handle adapter_ctx; + uint32_t hangsecs; + uint32_t flags; + ndis_interface_type iftype; +{ + ndis_miniport_block *block; + + /* + * Save the adapter context, we need it for calling + * the driver's internal functions. + */ + block = (ndis_miniport_block *)adapter_handle; + block->nmb_miniportadapterctx = adapter_ctx; + block->nmb_checkforhangsecs = hangsecs; + block->nmb_flags = flags; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisOpenConfiguration(status, cfg, wrapctx) + ndis_status *status; + ndis_handle *cfg; + ndis_handle wrapctx; +{ + + *cfg = wrapctx; + *status = NDIS_STATUS_SUCCESS; + + return; +} + +__stdcall static void +NdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle) + ndis_status *status; + ndis_handle cfg; + ndis_unicode_string *subkey; + ndis_handle *subhandle; +{ + *subhandle = cfg; + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall static void +NdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle) + ndis_status *status; + ndis_handle cfg; + uint32_t idx; + ndis_unicode_string *subkey; + ndis_handle *subhandle; +{ + *status = NDIS_STATUS_FAILURE; + return; +} + +static ndis_status +ndis_encode_parm(block, oid, type, parm) + ndis_miniport_block *block; + struct sysctl_oid *oid; + ndis_parm_type type; + ndis_config_parm **parm; +{ + uint16_t *unicode; + ndis_unicode_string *ustr; + int base = 0; + + unicode = (uint16_t *)&block->nmb_dummybuf; + + 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; + 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 = + strtol((char *)oid->oid_arg1, NULL, base); + break; + case ndis_parm_hexint: + 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 = + strtoul((char *)oid->oid_arg1, NULL, base); + break; + default: + return(NDIS_STATUS_FAILURE); + break; + } + + return(NDIS_STATUS_SUCCESS); +} + +int +ndis_strcasecmp(s1, s2) + const char *s1; + const char *s2; +{ + char a, b; + + /* + * In the kernel, toupper() is a macro. Have to be careful + * not to use pointer arithmetic when passing it arguments. + */ + + while(1) { + a = *s1; + b = *s2++; + if (toupper(a) != toupper(b)) + break; + if (*s1++ == '\0') + return(0); + } + + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} + +int +ndis_strncasecmp(s1, s2, n) + const char *s1; + const char *s2; + size_t n; +{ + char a, b; + + if (n != 0) { + do { + a = *s1; + b = *s2++; + if (toupper(a) != toupper(b)) + return (*(const unsigned char *)s1 - + *(const unsigned char *)(s2 - 1)); + if (*s1++ == '\0') + break; + } while (--n != 0); + } + + return(0); +} + +__stdcall static void +NdisReadConfiguration(status, parm, cfg, key, type) + ndis_status *status; + ndis_config_parm **parm; + ndis_handle cfg; + ndis_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; + + block = (ndis_miniport_block *)cfg; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (key->us_len == 0 || key->us_buf == NULL) { + *status = NDIS_STATUS_FAILURE; + 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; + + /* + * See if registry key is already in a list of known keys + * included with the driver. + */ +#if __FreeBSD_version < 502113 + TAILQ_FOREACH(e, &sc->ndis_ctx, link) { +#else + TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { +#endif + oidp = e->entry; + if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) { + if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) { + free(keystr, M_DEVBUF); + *status = NDIS_STATUS_FAILURE; + return; + } + *status = ndis_encode_parm(block, oidp, type, parm); + free(keystr, M_DEVBUF); + return; + } + } + + /* + * If the key didn't match, add it to the list of dynamically + * created ones. Sometimes, drivers refer to registry keys + * that aren't documented in their .INF files. These keys + * are supposed to be created by some sort of utility or + * control panel snap-in that comes with the driver software. + * Sometimes it's useful to be able to manipulate these. + * If the driver requests the key in the form of a string, + * make its default value an empty string, otherwise default + * it to "0". + */ + + if (type == ndis_parm_int || type == ndis_parm_hexint) + ndis_add_sysctl(sc, keystr, "(dynamic integer key)", + "UNSET", CTLFLAG_RW); + else + ndis_add_sysctl(sc, keystr, "(dynamic string key)", + "UNSET", CTLFLAG_RW); + + free(keystr, M_DEVBUF); + *status = NDIS_STATUS_FAILURE; + return; +} + +static ndis_status +ndis_decode_parm(block, parm, val) + ndis_miniport_block *block; + ndis_config_parm *parm; + char *val; +{ + ndis_unicode_string *ustr; + char *astr = NULL; + + 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); + break; + case ndis_parm_int: + sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata); + break; + case ndis_parm_hexint: + sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata); + break; + default: + return(NDIS_STATUS_FAILURE); + break; + } + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisWriteConfiguration(status, cfg, key, parm) + ndis_status *status; + ndis_handle cfg; + ndis_unicode_string *key; + ndis_config_parm *parm; +{ + char *keystr = NULL; + ndis_miniport_block *block; + struct ndis_softc *sc; + struct sysctl_oid *oidp; + struct sysctl_ctx_entry *e; + char val[256]; + + 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); + + /* 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); + return; + } + + /* See if the key already exists. */ + +#if __FreeBSD_version < 502113 + TAILQ_FOREACH(e, &sc->ndis_ctx, link) { +#else + TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { +#endif + oidp = e->entry; + if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) { + /* Found it, set the value. */ + strcpy((char *)oidp->oid_arg1, val); + free(keystr, M_DEVBUF); + return; + } + } + + /* Not found, add a new key with the specified value. */ + ndis_add_sysctl(sc, keystr, "(dynamically set key)", + val, CTLFLAG_RW); + + free(keystr, M_DEVBUF); + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall static void +NdisCloseConfiguration(cfg) + ndis_handle cfg; +{ + return; +} + +/* + * Initialize a Windows spinlock. + */ +__stdcall static void +NdisAllocateSpinLock(lock) + ndis_spin_lock *lock; +{ + KeInitializeSpinLock(&lock->nsl_spinlock); + lock->nsl_kirql = 0; + + return; +} + +/* + * Destroy a Windows spinlock. This is a no-op for now. There are two reasons + * for this. One is that it's sort of superfluous: we don't have to do anything + * special to deallocate the spinlock. The other is that there are some buggy + * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on + * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm + * talking to you.) + */ +__stdcall static void +NdisFreeSpinLock(lock) + ndis_spin_lock *lock; +{ +#ifdef notdef + KeInitializeSpinLock(&lock->nsl_spinlock); + lock->nsl_kirql = 0; +#endif + return; +} + +/* + * Acquire a spinlock from IRQL <= DISPATCH_LEVEL. + */ + +__stdcall static void +NdisAcquireSpinLock(lock) + ndis_spin_lock *lock; +{ + KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); + return; +} + +/* + * Release a spinlock from IRQL == DISPATCH_LEVEL. + */ + +__stdcall static void +NdisReleaseSpinLock(lock) + ndis_spin_lock *lock; +{ + KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); + return; +} + +/* + * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL. + */ +__stdcall static void +NdisDprAcquireSpinLock(lock) + ndis_spin_lock *lock; +{ + KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock); + return; +} + +/* + * Release a spinlock without leaving IRQL == DISPATCH_LEVEL. + */ +__stdcall static void +NdisDprReleaseSpinLock(lock) + ndis_spin_lock *lock; +{ + KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock); + return; +} + +__stdcall static uint32_t +NdisReadPciSlotInformation(adapter, slot, offset, buf, len) + ndis_handle adapter; + uint32_t slot; + uint32_t offset; + void *buf; + uint32_t len; +{ + ndis_miniport_block *block; + int i; + char *dest; + device_t dev; + + block = (ndis_miniport_block *)adapter; + dest = buf; + if (block == NULL) + return(0); + + dev = block->nmb_physdeviceobj->do_devext; + + /* + * I have a test system consisting of a Sun w2100z + * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g + * "Aries" miniPCI NIC. (The NIC is installed in the + * machine using a miniPCI to PCI bus adapter card.) + * When running in SMP mode, I found that + * performing a large number of consecutive calls to + * NdisReadPciSlotInformation() would result in a + * sudden system reset (or in some cases a freeze). + * My suspicion is that the multiple reads are somehow + * triggering a fatal PCI bus error that leads to a + * machine check. The 1us delay in the loop below + * seems to prevent this problem. + */ + + for (i = 0; i < len; i++) { + DELAY(1); + dest[i] = pci_read_config(dev, i + offset, 1); + } + + return(len); +} + +__stdcall static uint32_t +NdisWritePciSlotInformation(adapter, slot, offset, buf, len) + ndis_handle adapter; + uint32_t slot; + uint32_t offset; + void *buf; + uint32_t len; +{ + ndis_miniport_block *block; + int i; + char *dest; + device_t dev; + + block = (ndis_miniport_block *)adapter; + dest = buf; + + if (block == NULL) + return(0); + + dev = block->nmb_physdeviceobj->do_devext; + for (i = 0; i < len; i++) { + DELAY(1); + pci_write_config(dev, i + offset, dest[i], 1); + } + + return(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, + uint32_t numerrors, ...) +{ + ndis_miniport_block *block; + va_list ap; + int i, error; + char *str = NULL, *ustr = NULL; + uint16_t flags; + char msgbuf[ERRMSGLEN]; + device_t dev; + driver_object *drv; + + block = (ndis_miniport_block *)adapter; + dev = block->nmb_physdeviceobj->do_devext; + drv = block->nmb_physdeviceobj->do_drvobj; + + error = pe_get_message((vm_offset_t)drv->dro_driverstart, + code, &str, &i, &flags); + if (error == 0 && flags & MESSAGE_RESOURCE_UNICODE) { + ustr = msgbuf; + ndis_unicode_to_ascii((uint16_t *)str, + ((i / 2)) > (ERRMSGLEN - 1) ? ERRMSGLEN : i, &ustr); + str = ustr; + } + device_printf (dev, "NDIS ERROR: %x (%s)\n", code, + str == NULL ? "unknown error" : str); + device_printf (dev, "NDIS NUMERRORS: %x\n", numerrors); + + va_start(ap, numerrors); + for (i = 0; i < numerrors; i++) + device_printf (dev, "argptr: %p\n", + va_arg(ap, void *)); + va_end(ap); + + return; +} + +static void +ndis_map_cb(arg, segs, nseg, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + int error; +{ + struct ndis_map_arg *ctx; + int i; + + if (error) + return; + + ctx = arg; + + for (i = 0; i < nseg; i++) { + ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr; + ctx->nma_fraglist[i].npu_len = segs[i].ds_len; + } + + ctx->nma_cnt = nseg; + + return; +} + +__stdcall static void +NdisMStartBufferPhysicalMapping(adapter, buf, mapreg, writedev, addrarray, arraysize) + ndis_handle adapter; + ndis_buffer *buf; + uint32_t mapreg; + uint8_t writedev; + ndis_paddr_unit *addrarray; + uint32_t *arraysize; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ndis_map_arg nma; + bus_dmamap_t map; + int error; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (mapreg > sc->ndis_mmapcnt) + return; + + map = sc->ndis_mmaps[mapreg]; + nma.nma_fraglist = addrarray; + + error = bus_dmamap_load(sc->ndis_mtag, map, + MmGetMdlVirtualAddress(buf), MmGetMdlByteCount(buf), ndis_map_cb, + (void *)&nma, BUS_DMA_NOWAIT); + + if (error) + return; + + bus_dmamap_sync(sc->ndis_mtag, map, + writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD); + + *arraysize = nma.nma_cnt; + + return; +} + +__stdcall static void +NdisMCompleteBufferPhysicalMapping(adapter, buf, mapreg) + ndis_handle adapter; + ndis_buffer *buf; + uint32_t mapreg; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + bus_dmamap_t map; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (mapreg > sc->ndis_mmapcnt) + return; + + map = sc->ndis_mmaps[mapreg]; + + bus_dmamap_sync(sc->ndis_mtag, map, + BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + + bus_dmamap_unload(sc->ndis_mtag, map); + + return; +} + +/* + * This is an older (?) timer init routine which doesn't + * accept a miniport context handle. Serialized miniports should + * never call this function. + */ + +__stdcall static void +NdisInitializeTimer(timer, func, ctx) + ndis_timer *timer; + ndis_timer_function func; + void *ctx; +{ + KeInitializeTimer(&timer->nt_ktimer); + KeInitializeDpc(&timer->nt_kdpc, func, ctx); + + return; +} + +__stdcall static void +ndis_timercall(dpc, timer, sysarg1, sysarg2) + kdpc *dpc; + ndis_miniport_timer *timer; + void *sysarg1; + void *sysarg2; +{ + /* + * Since we're called as a DPC, we should be running + * at DISPATCH_LEVEL here. This means to acquire the + * spinlock, we can use KeAcquireSpinLockAtDpcLevel() + * rather than KeAcquireSpinLock(). + */ + if (NDIS_SERIALIZED(timer->nmt_block)) + KeAcquireSpinLockAtDpcLevel(&timer->nmt_block->nmb_lock); + + MSCALL4(timer->nmt_timerfunc, dpc, timer->nmt_timerctx, + sysarg1, sysarg2); + + if (NDIS_SERIALIZED(timer->nmt_block)) + KeReleaseSpinLockFromDpcLevel(&timer->nmt_block->nmb_lock); + + return; +} + +/* + * For a long time I wondered why there were two NDIS timer initialization + * routines, and why this one needed an NDIS_MINIPORT_TIMER and the + * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout + * function and context pointers separate from those in the DPC, which + * allows for another level of indirection: when the timer fires, we + * can have our own timer function invoked, and from there we can call + * the driver's function. But why go to all that trouble? Then it hit + * me: for serialized miniports, the timer callouts are not re-entrant. + * By trapping the callouts and having access to the MiniportAdapterHandle, + * we can protect the driver callouts by acquiring the NDIS serialization + * lock. This is essential for allowing serialized miniports to work + * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL + * is enough to prevent other threads from pre-empting you, but with + * SMP, you must acquire a lock as well, otherwise the other CPU is + * free to clobber you. + */ +__stdcall static void +NdisMInitializeTimer(timer, handle, func, ctx) + ndis_miniport_timer *timer; + ndis_handle handle; + ndis_timer_function func; + void *ctx; +{ + /* Save the driver's funcptr and context */ + + timer->nmt_timerfunc = func; + timer->nmt_timerctx = ctx; + timer->nmt_block = handle; + + /* + * Set up the timer so it will call our intermediate DPC. + * Be sure to use the wrapped entry point, since + * ntoskrnl_run_dpc() expects to invoke a function with + * Microsoft calling conventions. + */ + KeInitializeTimer(&timer->nmt_ktimer); + KeInitializeDpc(&timer->nmt_kdpc, + ndis_findwrap((funcptr)ndis_timercall), timer); + + return; +} + +/* + * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(), + * but the former is just a macro wrapper around the latter. + */ +__stdcall static void +NdisSetTimer(timer, msecs) + ndis_timer *timer; + uint32_t msecs; +{ + /* + * KeSetTimer() wants the period in + * hundred nanosecond intervals. + */ + KeSetTimer(&timer->nt_ktimer, + ((int64_t)msecs * -10000), &timer->nt_kdpc); + + return; +} + +__stdcall static void +NdisMSetPeriodicTimer(timer, msecs) + ndis_miniport_timer *timer; + uint32_t msecs; +{ + KeSetTimerEx(&timer->nmt_ktimer, + ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc); + + return; +} + +/* + * Technically, this is really NdisCancelTimer(), but we also + * (ab)use it for NdisMCancelTimer(), since in our implementation + * we don't need the extra info in the ndis_miniport_timer + * structure just to cancel a timer. + */ + +__stdcall static void +NdisMCancelTimer(timer, cancelled) + ndis_timer *timer; + uint8_t *cancelled; +{ + *cancelled = KeCancelTimer(&timer->nt_ktimer); + + return; +} + +__stdcall static void +NdisMQueryAdapterResources(status, adapter, list, buflen) + ndis_status *status; + ndis_handle adapter; + ndis_resource_list *list; + uint32_t *buflen; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + int rsclen; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + rsclen = sizeof(ndis_resource_list) + + (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)); + if (*buflen < rsclen) { + *buflen = rsclen; + *status = NDIS_STATUS_INVALID_LENGTH; + return; + } + + bcopy((char *)block->nmb_rlist, (char *)list, rsclen); + *status = NDIS_STATUS_SUCCESS; + + return; +} + +__stdcall static ndis_status +NdisMRegisterIoPortRange(offset, adapter, port, numports) + void **offset; + ndis_handle adapter; + uint32_t port; + uint32_t numports; +{ + struct ndis_miniport_block *block; + struct ndis_softc *sc; + + if (adapter == NULL) + return(NDIS_STATUS_FAILURE); + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (sc->ndis_res_io == NULL) + return(NDIS_STATUS_FAILURE); + + /* Don't let the device map more ports than we have. */ + if (rman_get_size(sc->ndis_res_io) < numports) + return(NDIS_STATUS_INVALID_LENGTH); + + *offset = (void *)rman_get_start(sc->ndis_res_io); + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisMDeregisterIoPortRange(adapter, port, numports, offset) + ndis_handle adapter; + uint32_t port; + uint32_t numports; + void *offset; +{ + return; +} + +__stdcall static void +NdisReadNetworkAddress(status, addr, addrlen, adapter) + ndis_status *status; + void **addr; + uint32_t *addrlen; + ndis_handle adapter; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + uint8_t empty[] = { 0, 0, 0, 0, 0, 0 }; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0) + *status = NDIS_STATUS_FAILURE; + else { + *addr = sc->arpcom.ac_enaddr; + *addrlen = ETHER_ADDR_LEN; + *status = NDIS_STATUS_SUCCESS; + } + + return; +} + +__stdcall static ndis_status +NdisQueryMapRegisterCount(bustype, cnt) + uint32_t bustype; + uint32_t *cnt; +{ + *cnt = 8192; + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +NdisMAllocateMapRegisters(adapter, dmachannel, dmasize, physmapneeded, maxmap) + ndis_handle adapter; + uint32_t dmachannel; + uint8_t dmasize; + uint32_t physmapneeded; + uint32_t maxmap; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + int error, i, nseg = NDIS_MAXSEG; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded, + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (sc->ndis_mmaps == NULL) + return(NDIS_STATUS_RESOURCES); + + error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, + NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW, + NULL, NULL, &sc->ndis_mtag); + + if (error) { + free(sc->ndis_mmaps, M_DEVBUF); + return(NDIS_STATUS_RESOURCES); + } + + for (i = 0; i < physmapneeded; i++) + bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]); + + sc->ndis_mmapcnt = physmapneeded; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisMFreeMapRegisters(adapter) + ndis_handle adapter; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + int i; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + for (i = 0; i < sc->ndis_mmapcnt; i++) + bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]); + + free(sc->ndis_mmaps, M_DEVBUF); + + bus_dma_tag_destroy(sc->ndis_mtag); + + return; +} + +static void +ndis_mapshared_cb(arg, segs, nseg, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + int error; +{ + ndis_physaddr *p; + + if (error || nseg > 1) + return; + + p = arg; + + p->np_quad = segs[0].ds_addr; + + return; +} + +/* + * This maps to bus_dmamem_alloc(). + */ +__stdcall static void +NdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr) + ndis_handle adapter; + uint32_t len; + uint8_t cached; + void **vaddr; + ndis_physaddr *paddr; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ndis_shmem *sh; + int error; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO); + if (sh == NULL) + return; + + /* + * When performing shared memory allocations, create a tag + * with a lowaddr limit that restricts physical memory mappings + * so that they all fall within the first 1GB of memory. + * At least one device/driver combination (Linksys Instant + * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have + * problems with performing DMA operations with physical + * addresses that lie above the 1GB mark. I don't know if this + * is a hardware limitation or if the addresses are being + * truncated within the driver, but this seems to be the only + * way to make these cards work reliably in systems with more + * than 1GB of physical memory. + */ + + error = bus_dma_tag_create(sc->ndis_parent_tag, 64, + 0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL, + NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL, + &sh->ndis_stag); + + if (error) { + free(sh, M_DEVBUF); + return; + } + + error = bus_dmamem_alloc(sh->ndis_stag, vaddr, + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap); + + if (error) { + bus_dma_tag_destroy(sh->ndis_stag); + free(sh, M_DEVBUF); + return; + } + + error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr, + len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT); + + if (error) { + bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap); + bus_dma_tag_destroy(sh->ndis_stag); + free(sh, M_DEVBUF); + return; + } + + sh->ndis_saddr = *vaddr; + sh->ndis_next = sc->ndis_shlist; + sc->ndis_shlist = sh; + + return; +} + +struct ndis_allocwork { + ndis_handle na_adapter; + uint32_t na_len; + uint8_t na_cached; + void *na_ctx; +}; + +static void +ndis_asyncmem_complete(arg) + void *arg; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ndis_allocwork *w; + void *vaddr; + ndis_physaddr paddr; + __stdcall ndis_allocdone_handler donefunc; + + w = arg; + block = (ndis_miniport_block *)w->na_adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + vaddr = NULL; + paddr.np_quad = 0; + + donefunc = sc->ndis_chars->nmc_allocate_complete_func; + NdisMAllocateSharedMemory(w->na_adapter, w->na_len, + w->na_cached, &vaddr, &paddr); + MSCALL5(donefunc, w->na_adapter, vaddr, &paddr, w->na_len, w->na_ctx); + + free(arg, M_DEVBUF); + + return; +} + +__stdcall static ndis_status +NdisMAllocateSharedMemoryAsync(adapter, len, cached, ctx) + ndis_handle adapter; + uint32_t len; + uint8_t cached; + void *ctx; +{ + struct ndis_allocwork *w; + + if (adapter == NULL) + return(NDIS_STATUS_FAILURE); + + w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT); + + if (w == NULL) + return(NDIS_STATUS_FAILURE); + + w->na_adapter = adapter; + w->na_cached = cached; + w->na_len = len; + w->na_ctx = ctx; + + /* + * Pawn this work off on the SWI thread instead of the + * taskqueue thread, because sometimes drivers will queue + * up work items on the taskqueue thread that will block, + * which would prevent the memory allocation from completing + * when we need it. + */ + ndis_sched(ndis_asyncmem_complete, w, NDIS_SWI); + + return(NDIS_STATUS_PENDING); +} + +__stdcall static void +NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr) + ndis_handle adapter; + uint32_t len; + uint8_t cached; + void *vaddr; + ndis_physaddr paddr; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ndis_shmem *sh, *prev; + + 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) + return; + + while (sh) { + if (sh->ndis_saddr == vaddr) + break; + prev = sh; + sh = sh->ndis_next; + } + + bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap); + bus_dmamem_free(sh->ndis_stag, vaddr, 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; +} + +__stdcall static ndis_status +NdisMMapIoSpace(vaddr, adapter, paddr, len) + void **vaddr; + ndis_handle adapter; + ndis_physaddr paddr; + uint32_t len; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + + if (adapter == NULL) + return(NDIS_STATUS_FAILURE); + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (sc->ndis_res_mem != NULL && + paddr.np_quad == rman_get_start(sc->ndis_res_mem)) + *vaddr = (void *)rman_get_virtual(sc->ndis_res_mem); + else if (sc->ndis_res_altmem != NULL && + paddr.np_quad == rman_get_start(sc->ndis_res_altmem)) + *vaddr = (void *)rman_get_virtual(sc->ndis_res_altmem); + else if (sc->ndis_res_am != NULL && + paddr.np_quad == rman_get_start(sc->ndis_res_am)) + *vaddr = (void *)rman_get_virtual(sc->ndis_res_am); + else + return(NDIS_STATUS_FAILURE); + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisMUnmapIoSpace(adapter, vaddr, len) + ndis_handle adapter; + void *vaddr; + uint32_t len; +{ + return; +} + +__stdcall static uint32_t +NdisGetCacheFillSize(void) +{ + return(128); +} + +__stdcall static uint32_t +NdisMGetDmaAlignment(handle) + ndis_handle handle; +{ + return(128); +} + +/* + * NDIS has two methods for dealing with NICs that support DMA. + * One is to just pass packets to the driver and let it call + * NdisMStartBufferPhysicalMapping() to map each buffer in the packet + * all by itself, and the other is to let the NDIS library handle the + * buffer mapping internally, and hand the driver an already populated + * scatter/gather fragment list. If the driver calls + * NdisMInitializeScatterGatherDma(), it wants to use the latter + * method. + */ + +__stdcall static ndis_status +NdisMInitializeScatterGatherDma(adapter, is64, maxphysmap) + ndis_handle adapter; + uint8_t is64; + uint32_t maxphysmap; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + int error; + + if (adapter == NULL) + return(NDIS_STATUS_FAILURE); + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + /* Don't do this twice. */ + if (sc->ndis_sc == 1) + return(NDIS_STATUS_SUCCESS); + + error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW, + NULL, NULL, &sc->ndis_ttag); + + sc->ndis_sc = 1; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall void +NdisAllocatePacketPool(status, pool, descnum, protrsvdlen) + ndis_status *status; + ndis_handle *pool; + uint32_t descnum; + uint32_t protrsvdlen; +{ + ndis_packet *cur; + int i; + + *pool = malloc((sizeof(ndis_packet) + protrsvdlen) * + ((descnum + NDIS_POOL_EXTRA) + 1), + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (*pool == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + cur = (ndis_packet *)*pool; + KeInitializeSpinLock(&cur->np_lock); + cur->np_private.npp_flags = 0x1; /* mark the head of the list */ + cur->np_private.npp_totlen = 0; /* init deletetion flag */ + for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) { + cur->np_private.npp_head = (ndis_handle)(cur + 1); + cur++; + } + + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall void +NdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen) + ndis_status *status; + ndis_handle *pool; + uint32_t descnum; + uint32_t oflowdescnum; + uint32_t protrsvdlen; +{ + return(NdisAllocatePacketPool(status, pool, + descnum + oflowdescnum, protrsvdlen)); +} + +__stdcall uint32_t +NdisPacketPoolUsage(pool) + ndis_handle pool; +{ + ndis_packet *head; + uint8_t irql; + uint32_t cnt; + + head = (ndis_packet *)pool; + KeAcquireSpinLock(&head->np_lock, &irql); + cnt = head->np_private.npp_count; + KeReleaseSpinLock(&head->np_lock, irql); + + return(cnt); +} + +__stdcall void +NdisFreePacketPool(pool) + ndis_handle pool; +{ + ndis_packet *head; + uint8_t irql; + + head = pool; + + /* Mark this pool as 'going away.' */ + + KeAcquireSpinLock(&head->np_lock, &irql); + head->np_private.npp_totlen = 1; + + /* If there are no buffers loaned out, destroy the pool. */ + + if (head->np_private.npp_count == 0) { + KeReleaseSpinLock(&head->np_lock, irql); + free(pool, M_DEVBUF); + } else { + printf("NDIS: buggy driver deleting active packet pool!\n"); + KeReleaseSpinLock(&head->np_lock, irql); + } + + return; +} + +__stdcall void +NdisAllocatePacket(status, packet, pool) + ndis_status *status; + ndis_packet **packet; + ndis_handle pool; +{ + ndis_packet *head, *pkt; + uint8_t irql; + + head = (ndis_packet *)pool; + KeAcquireSpinLock(&head->np_lock, &irql); + + if (head->np_private.npp_flags != 0x1) { + *status = NDIS_STATUS_FAILURE; + KeReleaseSpinLock(&head->np_lock, irql); + return; + } + + /* + * If this pool is marked as 'going away' don't allocate any + * more packets out of it. + */ + + if (head->np_private.npp_totlen) { + *status = NDIS_STATUS_FAILURE; + KeReleaseSpinLock(&head->np_lock, irql); + return; + } + + pkt = (ndis_packet *)head->np_private.npp_head; + + if (pkt == NULL) { + *status = NDIS_STATUS_RESOURCES; + KeReleaseSpinLock(&head->np_lock, irql); + return; + } + + head->np_private.npp_head = pkt->np_private.npp_head; + + pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL; + /* Save pointer to the pool. */ + pkt->np_private.npp_pool = head; + + /* Set the oob offset pointer. Lots of things expect this. */ + pkt->np_private.npp_packetooboffset = + offsetof(ndis_packet, np_oob); + + /* + * We must initialize the packet flags correctly in order + * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and + * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work + * correctly. + */ + pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; + pkt->np_private.npp_validcounts = FALSE; + + *packet = pkt; + + head->np_private.npp_count++; + *status = NDIS_STATUS_SUCCESS; + + KeReleaseSpinLock(&head->np_lock, irql); + + return; +} + +__stdcall void +NdisFreePacket(packet) + ndis_packet *packet; +{ + ndis_packet *head; + uint8_t irql; + + if (packet == NULL || packet->np_private.npp_pool == NULL) + return; + + head = packet->np_private.npp_pool; + KeAcquireSpinLock(&head->np_lock, &irql); + + if (head->np_private.npp_flags != 0x1) { + KeReleaseSpinLock(&head->np_lock, irql); + return; + } + + packet->np_private.npp_head = head->np_private.npp_head; + head->np_private.npp_head = (ndis_buffer *)packet; + head->np_private.npp_count--; + + /* + * If the pool has been marked for deletion and there are + * no more packets outstanding, nuke the pool. + */ + + if (head->np_private.npp_totlen && head->np_private.npp_count == 0) { + KeReleaseSpinLock(&head->np_lock, irql); + free(head, M_DEVBUF); + } else + KeReleaseSpinLock(&head->np_lock, irql); + + return; +} + +__stdcall static void +NdisUnchainBufferAtFront(packet, buf) + ndis_packet *packet; + ndis_buffer **buf; +{ + ndis_packet_private *priv; + + if (packet == NULL || buf == NULL) + return; + + priv = &packet->np_private; + + priv->npp_validcounts = FALSE; + + if (priv->npp_head == priv->npp_tail) { + *buf = priv->npp_head; + priv->npp_head = priv->npp_tail = NULL; + } else { + *buf = priv->npp_head; + priv->npp_head = (*buf)->mdl_next; + } + + return; +} + +__stdcall static void +NdisUnchainBufferAtBack(packet, buf) + ndis_packet *packet; + ndis_buffer **buf; +{ + ndis_packet_private *priv; + ndis_buffer *tmp; + + if (packet == NULL || buf == NULL) + return; + + priv = &packet->np_private; + + priv->npp_validcounts = FALSE; + + if (priv->npp_head == priv->npp_tail) { + *buf = priv->npp_head; + priv->npp_head = priv->npp_tail = NULL; + } else { + *buf = priv->npp_tail; + tmp = priv->npp_head; + while (tmp->mdl_next != priv->npp_tail) + tmp = tmp->mdl_next; + priv->npp_tail = tmp; + tmp->mdl_next = NULL; + } + + return; +} + +/* + * The NDIS "buffer" is really an MDL (memory descriptor list) + * which is used to describe a buffer in a way that allows it + * to mapped into different contexts. We have to be careful how + * we handle them: in some versions of Windows, the NdisFreeBuffer() + * routine is an actual function in the NDIS API, but in others + * it's just a macro wrapper around IoFreeMdl(). There's really + * no way to use the 'descnum' parameter to count how many + * "buffers" are allocated since in order to use IoFreeMdl() to + * dispose of a buffer, we have to use IoAllocateMdl() to allocate + * them, and IoAllocateMdl() just grabs them out of the heap. + */ + +__stdcall static void +NdisAllocateBufferPool(status, pool, descnum) + ndis_status *status; + 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 + * it against. + */ + + *pool = NonPagedPool; + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall static void +NdisFreeBufferPool(pool) + ndis_handle pool; +{ + return; +} + +__stdcall static void +NdisAllocateBuffer(status, buffer, pool, vaddr, len) + ndis_status *status; + ndis_buffer **buffer; + ndis_handle pool; + void *vaddr; + uint32_t len; +{ + ndis_buffer *buf; + + buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL); + if (buf == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + *buffer = buf; + *status = NDIS_STATUS_SUCCESS; + + return; +} + +__stdcall static void +NdisFreeBuffer(buf) + ndis_buffer *buf; +{ + IoFreeMdl(buf); + return; +} + +/* Aw c'mon. */ + +__stdcall static uint32_t +NdisBufferLength(buf) + ndis_buffer *buf; +{ + return(MmGetMdlByteCount(buf)); +} + +/* + * Get the virtual address and length of a buffer. + * Note: the vaddr argument is optional. + */ + +__stdcall static void +NdisQueryBuffer(buf, vaddr, len) + ndis_buffer *buf; + void **vaddr; + uint32_t *len; +{ + if (vaddr != NULL) + *vaddr = MmGetMdlVirtualAddress(buf); + *len = MmGetMdlByteCount(buf); + + return; +} + +/* Same as above -- we don't care about the priority. */ + +__stdcall static void +NdisQueryBufferSafe(buf, vaddr, len, prio) + ndis_buffer *buf; + void **vaddr; + uint32_t *len; + uint32_t prio; +{ + if (vaddr != NULL) + *vaddr = MmGetMdlVirtualAddress(buf); + *len = MmGetMdlByteCount(buf); + + return; +} + +/* Damnit Microsoft!! How many ways can you do the same thing?! */ + +__stdcall static void * +NdisBufferVirtualAddress(buf) + ndis_buffer *buf; +{ + return(MmGetMdlVirtualAddress(buf)); +} + +__stdcall static void * +NdisBufferVirtualAddressSafe(buf, prio) + ndis_buffer *buf; + uint32_t prio; +{ + return(MmGetMdlVirtualAddress(buf)); +} + +__stdcall static void +NdisAdjustBufferLength(buf, len) + ndis_buffer *buf; + int len; +{ + MmGetMdlByteCount(buf) = len; + + return; +} + +__stdcall static uint32_t +NdisInterlockedIncrement(addend) + uint32_t *addend; +{ + atomic_add_long((u_long *)addend, 1); + return(*addend); +} + +__stdcall static uint32_t +NdisInterlockedDecrement(addend) + uint32_t *addend; +{ + atomic_subtract_long((u_long *)addend, 1); + return(*addend); +} + +__stdcall static void +NdisInitializeEvent(event) + ndis_event *event; +{ + /* + * NDIS events are always notification + * events, and should be initialized to the + * not signaled state. + */ + + KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE); + return; +} + +__stdcall static void +NdisSetEvent(event) + ndis_event *event; +{ + KeSetEvent(&event->ne_event, 0, 0); + return; +} + +__stdcall static void +NdisResetEvent(event) + ndis_event *event; +{ + KeResetEvent(&event->ne_event); + return; +} + +__stdcall static uint8_t +NdisWaitEvent(event, msecs) + ndis_event *event; + uint32_t msecs; +{ + int64_t duetime; + uint32_t rval; + + duetime = ((int64_t)msecs * -10000); + + rval = KeWaitForSingleObject((nt_dispatch_header *)event, + 0, 0, TRUE, msecs ? &duetime : NULL); + + if (rval == STATUS_TIMEOUT) + return(FALSE); + + return(TRUE); +} + +__stdcall static ndis_status +NdisUnicodeStringToAnsiString(dstr, sstr) + ndis_ansi_string *dstr; + ndis_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)) + return(NDIS_STATUS_FAILURE); + dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf); + return (NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +NdisAnsiStringToUnicodeString(dstr, sstr) + ndis_unicode_string *dstr; + ndis_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); + return(NDIS_STATUS_FAILURE); + } + dstr->us_len = dstr->us_maxlen = sstr->nas_len * 2; + free(str, M_DEVBUF); + return (NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +NdisMPciAssignResources(adapter, slot, list) + ndis_handle adapter; + uint32_t slot; + ndis_resource_list **list; +{ + ndis_miniport_block *block; + + if (adapter == NULL || list == NULL) + return (NDIS_STATUS_FAILURE); + + block = (ndis_miniport_block *)adapter; + *list = block->nmb_rlist; + + return (NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode) + ndis_miniport_interrupt *intr; + ndis_handle adapter; + uint32_t ivec; + uint32_t ilevel; + uint8_t reqisr; + uint8_t shared; + ndis_interrupt_mode imode; +{ + ndis_miniport_block *block; + + block = adapter; + + intr->ni_block = adapter; + intr->ni_isrreq = reqisr; + intr->ni_shared = shared; + block->nmb_interrupt = intr; + + KeInitializeSpinLock(&intr->ni_dpccountlock); + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisMDeregisterInterrupt(intr) + ndis_miniport_interrupt *intr; +{ + return; +} + +__stdcall static void +NdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc) + ndis_handle adapter; + void *shutdownctx; + ndis_shutdown_handler shutdownfunc; +{ + ndis_miniport_block *block; + ndis_miniport_characteristics *chars; + struct ndis_softc *sc; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + chars = sc->ndis_chars; + + chars->nmc_shutdown_handler = shutdownfunc; + chars->nmc_rsvd0 = shutdownctx; + + return; +} + +__stdcall static void +NdisMDeregisterAdapterShutdownHandler(adapter) + ndis_handle adapter; +{ + ndis_miniport_block *block; + ndis_miniport_characteristics *chars; + struct ndis_softc *sc; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + chars = sc->ndis_chars; + + chars->nmc_shutdown_handler = NULL; + chars->nmc_rsvd0 = NULL; + + return; +} + +__stdcall static uint32_t +NDIS_BUFFER_TO_SPAN_PAGES(buf) + ndis_buffer *buf; +{ + if (buf == NULL) + return(0); + if (MmGetMdlByteCount(buf) == 0) + return(1); + return(SPAN_PAGES(MmGetMdlVirtualAddress(buf), + MmGetMdlByteCount(buf))); +} + +__stdcall static void +NdisGetBufferPhysicalArraySize(buf, pages) + ndis_buffer *buf; + uint32_t *pages; +{ + if (buf == NULL) + return; + + *pages = NDIS_BUFFER_TO_SPAN_PAGES(buf); + return; +} + +__stdcall static void +NdisQueryBufferOffset(buf, off, len) + ndis_buffer *buf; + uint32_t *off; + uint32_t *len; +{ + if (buf == NULL) + return; + + *off = MmGetMdlByteOffset(buf); + *len = MmGetMdlByteCount(buf); + + return; +} + +__stdcall static void +NdisMSleep(usecs) + uint32_t usecs; +{ + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = usecs; + + ndis_thsuspend(curthread->td_proc, NULL, tvtohz(&tv)); + + return; +} + +__stdcall static uint32_t +NdisReadPcmciaAttributeMemory(handle, offset, buf, len) + ndis_handle handle; + uint32_t offset; + void *buf; + uint32_t len; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + bus_space_handle_t bh; + bus_space_tag_t bt; + char *dest; + int i; + + if (handle == NULL) + return(0); + + block = (ndis_miniport_block *)handle; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + dest = buf; + + bh = rman_get_bushandle(sc->ndis_res_am); + bt = rman_get_bustag(sc->ndis_res_am); + + for (i = 0; i < len; i++) + dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2); + + return(i); +} + +__stdcall static uint32_t +NdisWritePcmciaAttributeMemory(handle, offset, buf, len) + ndis_handle handle; + uint32_t offset; + void *buf; + uint32_t len; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + bus_space_handle_t bh; + bus_space_tag_t bt; + char *src; + int i; + + if (handle == NULL) + return(0); + + block = (ndis_miniport_block *)handle; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + src = buf; + + bh = rman_get_bushandle(sc->ndis_res_am); + bt = rman_get_bustag(sc->ndis_res_am); + + for (i = 0; i < len; i++) + bus_space_write_1(bt, bh, (offset + i) * 2, src[i]); + + return(i); +} + +__stdcall static list_entry * +NdisInterlockedInsertHeadList(head, entry, lock) + list_entry *head; + list_entry *entry; + ndis_spin_lock *lock; +{ + list_entry *flink; + + KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); + flink = head->nle_flink; + entry->nle_flink = flink; + entry->nle_blink = head; + flink->nle_blink = entry; + head->nle_flink = entry; + KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); + + return(flink); +} + +__stdcall static list_entry * +NdisInterlockedRemoveHeadList(head, lock) + list_entry *head; + ndis_spin_lock *lock; +{ + list_entry *flink; + list_entry *entry; + + KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); + entry = head->nle_flink; + flink = entry->nle_flink; + head->nle_flink = flink; + flink->nle_blink = head; + KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); + + return(entry); +} + +__stdcall static list_entry * +NdisInterlockedInsertTailList(head, entry, lock) + list_entry *head; + list_entry *entry; + ndis_spin_lock *lock; +{ + list_entry *blink; + + KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); + blink = head->nle_blink; + entry->nle_flink = head; + entry->nle_blink = blink; + blink->nle_flink = entry; + head->nle_blink = entry; + KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); + + return(blink); +} + +__stdcall static uint8_t +NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx) + ndis_miniport_interrupt *intr; + void *syncfunc; + void *syncctx; +{ + __stdcall 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 the number of 100 nanosecond intervals since + * January 1, 1601. (?!?!) + */ +__stdcall static void +NdisGetCurrentSystemTime(tval) + uint64_t *tval; +{ + struct timespec ts; + + nanotime(&ts); + *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 + + 11644473600; + + return; +} + +/* + * Return the number of milliseconds since the system booted. + */ +__stdcall static void +NdisGetSystemUpTime(tval) + uint32_t *tval; +{ + *tval = (ticks * hz) / 1000; + + return; +} + +__stdcall static void +NdisInitializeString(dst, src) + ndis_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; + return; +} + +__stdcall static void +NdisFreeString(str) + ndis_unicode_string *str; +{ + if (str == NULL) + return; + if (str->us_buf != NULL) + free(str->us_buf, M_DEVBUF); + free(str, M_DEVBUF); + return; +} + +__stdcall static ndis_status +NdisMRemoveMiniport(adapter) + ndis_handle *adapter; +{ + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisInitAnsiString(dst, src) + ndis_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); + } + + return; +} + +__stdcall static void +NdisInitUnicodeString(dst, src) + ndis_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; + } + + return; +} + +__stdcall static void NdisMGetDeviceProperty(adapter, phydevobj, + funcdevobj, nextdevobj, resources, transresources) + ndis_handle adapter; + device_object **phydevobj; + device_object **funcdevobj; + device_object **nextdevobj; + cm_resource_list *resources; + cm_resource_list *transresources; +{ + ndis_miniport_block *block; + + block = (ndis_miniport_block *)adapter; + + if (phydevobj != NULL) + *phydevobj = block->nmb_physdeviceobj; + if (funcdevobj != NULL) + *funcdevobj = block->nmb_deviceobj; + if (nextdevobj != NULL) + *nextdevobj = block->nmb_nextdeviceobj; + + return; +} + +__stdcall static void +NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen) + ndis_packet *packet; + ndis_buffer **buf; + void **firstva; + uint32_t *firstlen; + uint32_t *totlen; +{ + ndis_buffer *tmp; + + tmp = packet->np_private.npp_head; + *buf = tmp; + if (tmp == NULL) { + *firstva = NULL; + *firstlen = *totlen = 0; + } else { + *firstva = MmGetMdlVirtualAddress(tmp); + *firstlen = *totlen = MmGetMdlByteCount(tmp); + for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next) + *totlen += MmGetMdlByteCount(tmp); + } + + return; +} + +__stdcall static void +NdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio) + ndis_packet *packet; + ndis_buffer **buf; + void **firstva; + uint32_t *firstlen; + uint32_t *totlen; + uint32_t prio; +{ + NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen); +} + +static int +ndis_find_sym(lf, filename, suffix, sym) + linker_file_t lf; + char *filename; + char *suffix; + caddr_t *sym; +{ + char *fullsym; + char *suf; + int i; + + fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); + if (fullsym == NULL) + return(ENOMEM); + + bzero(fullsym, MAXPATHLEN); + strncpy(fullsym, filename, MAXPATHLEN); + if (strlen(filename) < 4) { + ExFreePool(fullsym); + return(EINVAL); + } + + /* If the filename has a .ko suffix, strip if off. */ + suf = fullsym + (strlen(filename) - 3); + if (strcmp(suf, ".ko") == 0) + *suf = '\0'; + + for (i = 0; i < strlen(fullsym); i++) { + if (fullsym[i] == '.') + fullsym[i] = '_'; + else + fullsym[i] = tolower(fullsym[i]); + } + strcat(fullsym, suffix); + *sym = linker_file_lookup_symbol(lf, fullsym, 0); + ExFreePool(fullsym); + if (*sym == 0) + return(ENOENT); + + return(0); +} + +/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ +__stdcall static void +NdisOpenFile(status, filehandle, filelength, filename, highestaddr) + ndis_status *status; + ndis_handle *filehandle; + uint32_t *filelength; + ndis_unicode_string *filename; + ndis_physaddr highestaddr; +{ + char *afilename = NULL; + struct thread *td = curthread; + struct nameidata nd; + int flags, error; + struct vattr vat; + struct vattr *vap = &vat; + ndis_fh *fh; + char *path; + linker_file_t head, lf; + caddr_t kldstart, kldend; + + ndis_unicode_to_ascii(filename->us_buf, + filename->us_len, &afilename); + + fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0); + if (fh == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + /* + * During system bootstrap, it's impossible to load files + * from the rootfs since it's not mounted yet. We therefore + * offer the possibility of opening files that have been + * preloaded as modules instead. Both choices will work + * when kldloading a module from multiuser, but only the + * module option will work during bootstrap. The module + * loading option works by using the ndiscvt(8) utility + * to convert the arbitrary file into a .ko using objcopy(1). + * This file will contain two special symbols: filename_start + * and filename_end. All we have to do is traverse the KLD + * list in search of those symbols and we've found the file + * data. As an added bonus, ndiscvt(8) will also generate + * a normal .o file which can be linked statically with + * the kernel. This means that the symbols will actual reside + * in the kernel's symbol table, but that doesn't matter to + * us since the kernel appears to us as just another module. + */ + + /* + * This is an evil trick for getting the head of the linked + * file list, which is not exported from kern_linker.o. It + * happens that linker file #1 is always the kernel, and is + * always the first element in the list. + */ + + head = linker_find_file_by_id(1); + for (lf = head; lf != NULL; lf = TAILQ_NEXT(lf, link)) { + if (ndis_find_sym(lf, afilename, "_start", &kldstart)) + continue; + if (ndis_find_sym(lf, afilename, "_end", &kldend)) + continue; + fh->nf_vp = lf; + fh->nf_map = NULL; + fh->nf_type = NDIS_FH_TYPE_MODULE; + *filelength = fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; + *filehandle = fh; + free(afilename, M_DEVBUF); + *status = NDIS_STATUS_SUCCESS; + return; + } + + if (TAILQ_EMPTY(&mountlist)) { + ExFreePool(fh); + *status = NDIS_STATUS_FILE_NOT_FOUND; + printf("NDIS: could not find file %s in linker list\n", + afilename); + printf("NDIS: and no filesystems mounted yet, " + "aborting NdisOpenFile()\n"); + free(afilename, M_DEVBUF); + return; + } + + path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); + if (path == NULL) { + ExFreePool(fh); + *status = NDIS_STATUS_RESOURCES; + return; + } + + snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename); + free(afilename, M_DEVBUF); + + mtx_lock(&Giant); + + /* Some threads don't have a current working directory. */ + + if (td->td_proc->p_fd->fd_rdir == NULL) + td->td_proc->p_fd->fd_rdir = rootvnode; + if (td->td_proc->p_fd->fd_cdir == NULL) + td->td_proc->p_fd->fd_cdir = rootvnode; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td); + + flags = FREAD; + error = vn_open(&nd, &flags, 0, -1); + if (error) { + mtx_unlock(&Giant); + *status = NDIS_STATUS_FILE_NOT_FOUND; + ExFreePool(fh); + printf("NDIS: open file %s failed: %d\n", path, error); + ExFreePool(path); + return; + } + + ExFreePool(path); + + NDFREE(&nd, NDF_ONLY_PNBUF); + + /* Get the file size. */ + VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); + VOP_UNLOCK(nd.ni_vp, 0, td); + mtx_unlock(&Giant); + + fh->nf_vp = nd.ni_vp; + fh->nf_map = NULL; + fh->nf_type = NDIS_FH_TYPE_VFS; + *filehandle = fh; + *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF; + *status = NDIS_STATUS_SUCCESS; + + return; +} + +__stdcall static void +NdisMapFile(status, mappedbuffer, filehandle) + ndis_status *status; + void **mappedbuffer; + ndis_handle filehandle; +{ + ndis_fh *fh; + struct thread *td = curthread; + linker_file_t lf; + caddr_t kldstart; + int error, resid; + + if (filehandle == NULL) { + *status = NDIS_STATUS_FAILURE; + return; + } + + fh = (ndis_fh *)filehandle; + + if (fh->nf_vp == NULL) { + *status = NDIS_STATUS_FAILURE; + return; + } + + if (fh->nf_map != NULL) { + *status = NDIS_STATUS_ALREADY_MAPPED; + return; + } + + if (fh->nf_type == NDIS_FH_TYPE_MODULE) { + lf = fh->nf_vp; + if (ndis_find_sym(lf, lf->filename, "_start", &kldstart)) { + *status = NDIS_STATUS_FAILURE; + return; + } + fh->nf_map = kldstart; + *status = NDIS_STATUS_SUCCESS; + *mappedbuffer = fh->nf_map; + return; + } + + fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0); + + if (fh->nf_map == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + mtx_lock(&Giant); + error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0, + UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td); + mtx_unlock(&Giant); + + if (error) + *status = NDIS_STATUS_FAILURE; + else { + *status = NDIS_STATUS_SUCCESS; + *mappedbuffer = fh->nf_map; + } + + return; +} + +__stdcall static void +NdisUnmapFile(filehandle) + ndis_handle filehandle; +{ + ndis_fh *fh; + fh = (ndis_fh *)filehandle; + + if (fh->nf_map == NULL) + return; + + if (fh->nf_type == NDIS_FH_TYPE_VFS) + ExFreePool(fh->nf_map); + fh->nf_map = NULL; + + return; +} + +__stdcall static void +NdisCloseFile(filehandle) + ndis_handle filehandle; +{ + struct thread *td = curthread; + ndis_fh *fh; + + if (filehandle == NULL) + return; + + fh = (ndis_fh *)filehandle; + if (fh->nf_map != NULL) { + if (fh->nf_type == NDIS_FH_TYPE_VFS) + ExFreePool(fh->nf_map); + fh->nf_map = NULL; + } + + if (fh->nf_vp == NULL) + return; + + if (fh->nf_type == NDIS_FH_TYPE_VFS) { + mtx_lock(&Giant); + vn_close(fh->nf_vp, FREAD, td->td_ucred, td); + mtx_unlock(&Giant); + } + + fh->nf_vp = NULL; + ExFreePool(fh); + + return; +} + +__stdcall static uint8_t +NdisSystemProcessorCount() +{ + return(mp_ncpus); +} + +typedef void (*ndis_statusdone_handler)(ndis_handle); +typedef void (*ndis_status_handler)(ndis_handle, ndis_status, + void *, uint32_t); + +__stdcall static void +NdisMIndicateStatusComplete(adapter) + ndis_handle adapter; +{ + ndis_miniport_block *block; + __stdcall ndis_statusdone_handler statusdonefunc; + + block = (ndis_miniport_block *)adapter; + statusdonefunc = block->nmb_statusdone_func; + + MSCALL1(statusdonefunc, adapter); + return; +} + +__stdcall static void +NdisMIndicateStatus(adapter, status, sbuf, slen) + ndis_handle adapter; + ndis_status status; + void *sbuf; + uint32_t slen; +{ + ndis_miniport_block *block; + __stdcall ndis_status_handler statusfunc; + + block = (ndis_miniport_block *)adapter; + statusfunc = block->nmb_status_func; + + MSCALL4(statusfunc, adapter, status, sbuf, slen); + return; +} + +static void +ndis_workfunc(ctx) + void *ctx; +{ + ndis_work_item *work; + __stdcall ndis_proc workfunc; + + work = ctx; + workfunc = work->nwi_func; + MSCALL2(workfunc, work, work->nwi_ctx); + return; +} + +__stdcall static ndis_status +NdisScheduleWorkItem(work) + ndis_work_item *work; +{ + ndis_sched(ndis_workfunc, work, NDIS_TASKQUEUE); + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen) + ndis_packet *dpkt; + uint32_t doff; + uint32_t reqlen; + ndis_packet *spkt; + uint32_t soff; + uint32_t *cpylen; +{ + ndis_buffer *src, *dst; + char *sptr, *dptr; + int resid, copied, len, scnt, dcnt; + + *cpylen = 0; + + src = spkt->np_private.npp_head; + dst = dpkt->np_private.npp_head; + + sptr = MmGetMdlVirtualAddress(src); + dptr = MmGetMdlVirtualAddress(dst); + scnt = MmGetMdlByteCount(src); + dcnt = MmGetMdlByteCount(dst); + + while (soff) { + if (MmGetMdlByteCount(src) > soff) { + sptr += soff; + scnt = MmGetMdlByteCount(src)- soff; + break; + } + soff -= MmGetMdlByteCount(src); + src = src->mdl_next; + if (src == NULL) + return; + sptr = MmGetMdlVirtualAddress(src); + } + + while (doff) { + if (MmGetMdlByteCount(dst) > doff) { + dptr += doff; + dcnt = MmGetMdlByteCount(dst) - doff; + break; + } + doff -= MmGetMdlByteCount(dst); + dst = dst->mdl_next; + if (dst == NULL) + return; + dptr = MmGetMdlVirtualAddress(dst); + } + + resid = reqlen; + copied = 0; + + while(1) { + if (resid < scnt) + len = resid; + else + len = scnt; + if (dcnt < len) + len = dcnt; + + bcopy(sptr, dptr, len); + + copied += len; + resid -= len; + if (resid == 0) + break; + + dcnt -= len; + if (dcnt == 0) { + dst = dst->mdl_next; + if (dst == NULL) + break; + dptr = MmGetMdlVirtualAddress(dst); + dcnt = MmGetMdlByteCount(dst); + } + + scnt -= len; + if (scnt == 0) { + src = src->mdl_next; + if (src == NULL) + break; + sptr = MmGetMdlVirtualAddress(src); + scnt = MmGetMdlByteCount(src); + } + } + + *cpylen = copied; + return; +} + +__stdcall static void +NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio) + ndis_packet *dpkt; + uint32_t doff; + uint32_t reqlen; + ndis_packet *spkt; + uint32_t soff; + uint32_t *cpylen; + uint32_t prio; +{ + NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen); + return; +} + +__stdcall static ndis_status +NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle) + ndis_handle handle; + ndis_unicode_string *devname; + ndis_unicode_string *symname; + driver_dispatch *majorfuncs[]; + void **devobj; + ndis_handle *devhandle; +{ + ndis_miniport_block *block; + + block = (ndis_miniport_block *)handle; + *devobj = block->nmb_deviceobj; + *devhandle = handle; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +NdisMDeregisterDevice(handle) + ndis_handle handle; +{ + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +NdisMQueryAdapterInstanceName(name, handle) + ndis_unicode_string *name; + ndis_handle handle; +{ + ndis_miniport_block *block; + device_t dev; + + 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; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +NdisMRegisterUnloadHandler(handle, func) + ndis_handle handle; + void *func; +{ + return; +} + +__stdcall static void +dummy() +{ + printf ("NDIS dummy called...\n"); + return; +} + +image_patch_table ndis_functbl[] = { + IMPORT_FUNC(NdisCopyFromPacketToPacket), + IMPORT_FUNC(NdisCopyFromPacketToPacketSafe), + IMPORT_FUNC(NdisScheduleWorkItem), + IMPORT_FUNC(NdisMIndicateStatusComplete), + IMPORT_FUNC(NdisMIndicateStatus), + IMPORT_FUNC(NdisSystemProcessorCount), + IMPORT_FUNC(NdisUnchainBufferAtBack), + IMPORT_FUNC(NdisGetFirstBufferFromPacket), + IMPORT_FUNC(NdisGetFirstBufferFromPacketSafe), + IMPORT_FUNC(NdisGetBufferPhysicalArraySize), + IMPORT_FUNC(NdisMGetDeviceProperty), + IMPORT_FUNC(NdisInitAnsiString), + IMPORT_FUNC(NdisInitUnicodeString), + IMPORT_FUNC(NdisWriteConfiguration), + IMPORT_FUNC(NdisAnsiStringToUnicodeString), + IMPORT_FUNC(NdisTerminateWrapper), + IMPORT_FUNC(NdisOpenConfigurationKeyByName), + IMPORT_FUNC(NdisOpenConfigurationKeyByIndex), + IMPORT_FUNC(NdisMRemoveMiniport), + IMPORT_FUNC(NdisInitializeString), + IMPORT_FUNC(NdisFreeString), + IMPORT_FUNC(NdisGetCurrentSystemTime), + IMPORT_FUNC(NdisGetSystemUpTime), + IMPORT_FUNC(NdisMSynchronizeWithInterrupt), + IMPORT_FUNC(NdisMAllocateSharedMemoryAsync), + IMPORT_FUNC(NdisInterlockedInsertHeadList), + IMPORT_FUNC(NdisInterlockedInsertTailList), + IMPORT_FUNC(NdisInterlockedRemoveHeadList), + IMPORT_FUNC(NdisInitializeWrapper), + IMPORT_FUNC(NdisMRegisterMiniport), + IMPORT_FUNC(NdisAllocateMemoryWithTag), + IMPORT_FUNC(NdisAllocateMemory), + IMPORT_FUNC(NdisMSetAttributesEx), + IMPORT_FUNC(NdisCloseConfiguration), + IMPORT_FUNC(NdisReadConfiguration), + IMPORT_FUNC(NdisOpenConfiguration), + IMPORT_FUNC(NdisAcquireSpinLock), + IMPORT_FUNC(NdisReleaseSpinLock), + IMPORT_FUNC(NdisDprAcquireSpinLock), + IMPORT_FUNC(NdisDprReleaseSpinLock), + IMPORT_FUNC(NdisAllocateSpinLock), + IMPORT_FUNC(NdisFreeSpinLock), + IMPORT_FUNC(NdisFreeMemory), + IMPORT_FUNC(NdisReadPciSlotInformation), + IMPORT_FUNC(NdisWritePciSlotInformation), + IMPORT_FUNC_MAP(NdisImmediateReadPciSlotInformation, + NdisReadPciSlotInformation), + IMPORT_FUNC_MAP(NdisImmediateWritePciSlotInformation, + NdisWritePciSlotInformation), + IMPORT_FUNC(NdisWriteErrorLogEntry), + IMPORT_FUNC(NdisMStartBufferPhysicalMapping), + IMPORT_FUNC(NdisMCompleteBufferPhysicalMapping), + IMPORT_FUNC(NdisMInitializeTimer), + IMPORT_FUNC(NdisInitializeTimer), + IMPORT_FUNC(NdisSetTimer), + IMPORT_FUNC(NdisMCancelTimer), + IMPORT_FUNC_MAP(NdisCancelTimer, NdisMCancelTimer), + IMPORT_FUNC(NdisMSetPeriodicTimer), + IMPORT_FUNC(NdisMQueryAdapterResources), + IMPORT_FUNC(NdisMRegisterIoPortRange), + IMPORT_FUNC(NdisMDeregisterIoPortRange), + IMPORT_FUNC(NdisReadNetworkAddress), + IMPORT_FUNC(NdisQueryMapRegisterCount), + IMPORT_FUNC(NdisMAllocateMapRegisters), + IMPORT_FUNC(NdisMFreeMapRegisters), + IMPORT_FUNC(NdisMAllocateSharedMemory), + IMPORT_FUNC(NdisMMapIoSpace), + IMPORT_FUNC(NdisMUnmapIoSpace), + IMPORT_FUNC(NdisGetCacheFillSize), + IMPORT_FUNC(NdisMGetDmaAlignment), + IMPORT_FUNC(NdisMInitializeScatterGatherDma), + IMPORT_FUNC(NdisAllocatePacketPool), + IMPORT_FUNC(NdisAllocatePacketPoolEx), + IMPORT_FUNC(NdisAllocatePacket), + IMPORT_FUNC(NdisFreePacket), + IMPORT_FUNC(NdisFreePacketPool), + IMPORT_FUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket), + IMPORT_FUNC_MAP(NdisDprFreePacket, NdisFreePacket), + IMPORT_FUNC(NdisAllocateBufferPool), + IMPORT_FUNC(NdisAllocateBuffer), + IMPORT_FUNC(NdisQueryBuffer), + IMPORT_FUNC(NdisQueryBufferSafe), + IMPORT_FUNC(NdisBufferVirtualAddress), + IMPORT_FUNC(NdisBufferVirtualAddressSafe), + IMPORT_FUNC(NdisBufferLength), + IMPORT_FUNC(NdisFreeBuffer), + IMPORT_FUNC(NdisFreeBufferPool), + IMPORT_FUNC(NdisInterlockedIncrement), + IMPORT_FUNC(NdisInterlockedDecrement), + IMPORT_FUNC(NdisInitializeEvent), + IMPORT_FUNC(NdisSetEvent), + IMPORT_FUNC(NdisResetEvent), + IMPORT_FUNC(NdisWaitEvent), + IMPORT_FUNC(NdisUnicodeStringToAnsiString), + IMPORT_FUNC(NdisMPciAssignResources), + IMPORT_FUNC(NdisMFreeSharedMemory), + IMPORT_FUNC(NdisMRegisterInterrupt), + IMPORT_FUNC(NdisMDeregisterInterrupt), + IMPORT_FUNC(NdisMRegisterAdapterShutdownHandler), + IMPORT_FUNC(NdisMDeregisterAdapterShutdownHandler), + IMPORT_FUNC(NDIS_BUFFER_TO_SPAN_PAGES), + IMPORT_FUNC(NdisQueryBufferOffset), + IMPORT_FUNC(NdisAdjustBufferLength), + IMPORT_FUNC(NdisPacketPoolUsage), + IMPORT_FUNC(NdisMSleep), + IMPORT_FUNC(NdisUnchainBufferAtFront), + IMPORT_FUNC(NdisReadPcmciaAttributeMemory), + IMPORT_FUNC(NdisWritePcmciaAttributeMemory), + IMPORT_FUNC(NdisOpenFile), + IMPORT_FUNC(NdisMapFile), + IMPORT_FUNC(NdisUnmapFile), + IMPORT_FUNC(NdisCloseFile), + IMPORT_FUNC(NdisMRegisterDevice), + IMPORT_FUNC(NdisMDeregisterDevice), + IMPORT_FUNC(NdisMQueryAdapterInstanceName), + IMPORT_FUNC(NdisMRegisterUnloadHandler), + IMPORT_FUNC(ndis_timercall), + + /* + * This last entry is a catch-all for any function we haven't + * implemented yet. The PE import list patching routine will + * use it for any function that doesn't have an explicit match + * in this table. + */ + + { NULL, (FUNC)dummy, NULL }, + + /* End of list. */ + + { NULL, NULL, NULL } +}; diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c new file mode 100644 index 000000000000..926e171716e7 --- /dev/null +++ b/sys/compat/ndis/subr_ntoskrnl.c @@ -0,0 +1,2811 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_ntoskrnl.c,v 1.43.2.5 2005/03/31 04:24:36 wpaul Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if __FreeBSD_version > 502113 +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define __regparm __attribute__((regparm(3))) + +__stdcall static uint8_t RtlEqualUnicodeString(ndis_unicode_string *, + ndis_unicode_string *, uint8_t); +__stdcall static void RtlCopyUnicodeString(ndis_unicode_string *, + ndis_unicode_string *); +__stdcall static ndis_status RtlUnicodeStringToAnsiString(ndis_ansi_string *, + ndis_unicode_string *, uint8_t); +__stdcall static ndis_status RtlAnsiStringToUnicodeString(ndis_unicode_string *, + ndis_ansi_string *, uint8_t); +__stdcall static irp *IoBuildSynchronousFsdRequest(uint32_t, device_object *, + void *, uint32_t, uint64_t *, nt_kevent *, io_status_block *); +__stdcall static irp *IoBuildAsynchronousFsdRequest(uint32_t, + device_object *, void *, uint32_t, uint64_t *, io_status_block *); +__stdcall static irp *IoBuildDeviceIoControlRequest(uint32_t, + device_object *, void *, uint32_t, void *, uint32_t, + uint8_t, nt_kevent *, io_status_block *); +__stdcall static irp *IoAllocateIrp(uint8_t, uint8_t); +__stdcall static void IoReuseIrp(irp *, uint32_t); +__stdcall static void IoFreeIrp(irp *); +__stdcall static void IoInitializeIrp(irp *, uint16_t, uint8_t); +__stdcall static irp *IoMakeAssociatedIrp(irp *, uint8_t); +__stdcall 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_timercall(void *); +static void ntoskrnl_run_dpc(void *); +__stdcall static void WRITE_REGISTER_USHORT(uint16_t *, uint16_t); +__stdcall static uint16_t READ_REGISTER_USHORT(uint16_t *); +__stdcall static void WRITE_REGISTER_ULONG(uint32_t *, uint32_t); +__stdcall static uint32_t READ_REGISTER_ULONG(uint32_t *); +__stdcall static void WRITE_REGISTER_UCHAR(uint8_t *, uint8_t); +__stdcall static uint8_t READ_REGISTER_UCHAR(uint8_t *); +__stdcall static int64_t _allmul(int64_t, int64_t); +__stdcall static int64_t _alldiv(int64_t, int64_t); +__stdcall static int64_t _allrem(int64_t, int64_t); +__regparm static int64_t _allshr(int64_t, uint8_t); +__regparm static int64_t _allshl(int64_t, uint8_t); +__stdcall static uint64_t _aullmul(uint64_t, uint64_t); +__stdcall static uint64_t _aulldiv(uint64_t, uint64_t); +__stdcall static uint64_t _aullrem(uint64_t, uint64_t); +__regparm static uint64_t _aullshr(uint64_t, uint8_t); +__regparm static uint64_t _aullshl(uint64_t, uint8_t); +static slist_entry *ntoskrnl_pushsl(slist_header *, slist_entry *); +static slist_entry *ntoskrnl_popsl(slist_header *); +__stdcall static void ExInitializePagedLookasideList(paged_lookaside_list *, + lookaside_alloc_func *, lookaside_free_func *, + uint32_t, size_t, uint32_t, uint16_t); +__stdcall static void ExDeletePagedLookasideList(paged_lookaside_list *); +__stdcall static void ExInitializeNPagedLookasideList(npaged_lookaside_list *, + lookaside_alloc_func *, lookaside_free_func *, + uint32_t, size_t, uint32_t, uint16_t); +__stdcall static void ExDeleteNPagedLookasideList(npaged_lookaside_list *); +__fastcall static slist_entry + *InterlockedPushEntrySList(REGARGS2(slist_header *head, + slist_entry *entry)); +__fastcall static slist_entry *InterlockedPopEntrySList(REGARGS1(slist_header + *head)); +__fastcall static slist_entry + *ExInterlockedPushEntrySList(REGARGS2(slist_header *head, + slist_entry *entry), kspin_lock *lock); +__fastcall static slist_entry + *ExInterlockedPopEntrySList(REGARGS2(slist_header *head, + kspin_lock *lock)); +__stdcall static uint16_t + ExQueryDepthSList(slist_header *); +__fastcall static uint32_t + InterlockedIncrement(REGARGS1(volatile uint32_t *addend)); +__fastcall static uint32_t + InterlockedDecrement(REGARGS1(volatile uint32_t *addend)); +__fastcall static void + ExInterlockedAddLargeStatistic(REGARGS2(uint64_t *addend, uint32_t)); +__stdcall static uint32_t MmSizeOfMdl(void *, size_t); +__stdcall static void MmBuildMdlForNonPagedPool(mdl *); +__stdcall static void *MmMapLockedPages(mdl *, uint8_t); +__stdcall static void *MmMapLockedPagesSpecifyCache(mdl *, + uint8_t, uint32_t, void *, uint32_t, uint32_t); +__stdcall static void MmUnmapLockedPages(void *, mdl *); +__stdcall static size_t RtlCompareMemory(const void *, const void *, size_t); +__stdcall static void RtlInitAnsiString(ndis_ansi_string *, char *); +__stdcall static void RtlInitUnicodeString(ndis_unicode_string *, + uint16_t *); +__stdcall static void RtlFreeUnicodeString(ndis_unicode_string *); +__stdcall static void RtlFreeAnsiString(ndis_ansi_string *); +__stdcall static ndis_status RtlUnicodeStringToInteger(ndis_unicode_string *, + uint32_t, uint32_t *); +static int atoi (const char *); +static long atol (const char *); +static int rand(void); +static void srand(unsigned int); +static void ntoskrnl_time(uint64_t *); +__stdcall static uint8_t IoIsWdmVersionAvailable(uint8_t, uint8_t); +static void ntoskrnl_thrfunc(void *); +__stdcall static ndis_status PsCreateSystemThread(ndis_handle *, + uint32_t, void *, ndis_handle, void *, void *, void *); +__stdcall static ndis_status PsTerminateSystemThread(ndis_status); +__stdcall static ndis_status IoGetDeviceProperty(device_object *, uint32_t, + uint32_t, void *, uint32_t *); +__stdcall static void KeInitializeMutex(kmutant *, uint32_t); +__stdcall static uint32_t KeReleaseMutex(kmutant *, uint8_t); +__stdcall static uint32_t KeReadStateMutex(kmutant *); +__stdcall static ndis_status ObReferenceObjectByHandle(ndis_handle, + uint32_t, void *, uint8_t, void **, void **); +__fastcall static void ObfDereferenceObject(REGARGS1(void *object)); +__stdcall static uint32_t ZwClose(ndis_handle); +static void *ntoskrnl_memset(void *, int, size_t); +static funcptr ntoskrnl_findwrap(funcptr); +static uint32_t DbgPrint(char *, ...); +__stdcall static void DbgBreakPoint(void); +__stdcall static void dummy(void); + +static struct mtx ntoskrnl_dispatchlock; +static kspin_lock ntoskrnl_global; +static kspin_lock ntoskrnl_cancellock; +static int ntoskrnl_kth = 0; +static struct nt_objref_head ntoskrnl_reflist; +static uma_zone_t mdl_zone; + +int +ntoskrnl_libinit() +{ + image_patch_table *patch; + + mtx_init(&ntoskrnl_dispatchlock, + "ntoskrnl dispatch lock", MTX_NDIS_LOCK, MTX_DEF); + KeInitializeSpinLock(&ntoskrnl_global); + KeInitializeSpinLock(&ntoskrnl_cancellock); + TAILQ_INIT(&ntoskrnl_reflist); + + patch = ntoskrnl_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap); + patch++; + } + + /* + * MDLs are supposed to be variable size (they describe + * buffers containing some number of pages, but we don't + * know ahead of time how many pages that will be). But + * always allocating them off the heap is very slow. As + * a compromize, we create an MDL UMA zone big enough to + * handle any buffer requiring up to 16 pages, and we + * use those for any MDLs for buffers of 16 pages or less + * in size. For buffers larger than that (which we assume + * will be few and far between, we allocate the MDLs off + * the heap. + */ + + mdl_zone = uma_zcreate("Windows MDL", MDL_ZONE_SIZE, + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + + return(0); +} + +int +ntoskrnl_libfini() +{ + image_patch_table *patch; + + patch = ntoskrnl_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + uma_zdestroy(mdl_zone); + + mtx_destroy(&ntoskrnl_dispatchlock); + + return(0); +} + +/* + * We need to be able to reference this externally from the wrapper; + * GCC only generates a local implementation of memset. + */ +static void * +ntoskrnl_memset(buf, ch, size) + void *buf; + int ch; + size_t size; +{ + return(memset(buf, ch, size)); +} + +__stdcall static uint8_t +RtlEqualUnicodeString(str1, str2, caseinsensitive) + ndis_unicode_string *str1; + ndis_unicode_string *str2; + uint8_t caseinsensitive; +{ + int i; + + if (str1->us_len != str2->us_len) + return(FALSE); + + for (i = 0; i < str1->us_len; i++) { + if (caseinsensitive == TRUE) { + if (toupper((char)(str1->us_buf[i] & 0xFF)) != + toupper((char)(str2->us_buf[i] & 0xFF))) + return(FALSE); + } else { + if (str1->us_buf[i] != str2->us_buf[i]) + return(FALSE); + } + } + + return(TRUE); +} + +__stdcall static void +RtlCopyUnicodeString(dest, src) + ndis_unicode_string *dest; + ndis_unicode_string *src; +{ + + if (dest->us_maxlen >= src->us_len) + dest->us_len = src->us_len; + else + dest->us_len = dest->us_maxlen; + memcpy(dest->us_buf, src->us_buf, dest->us_len); + return; +} + +__stdcall static ndis_status +RtlUnicodeStringToAnsiString(dest, src, allocate) + ndis_ansi_string *dest; + ndis_unicode_string *src; + uint8_t allocate; +{ + char *astr = NULL; + + if (dest == NULL || src == NULL) + return(NDIS_STATUS_FAILURE); + + 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); + } 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); + } + return (NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +RtlAnsiStringToUnicodeString(dest, src, allocate) + ndis_unicode_string *dest; + ndis_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; + } else { + dest->us_len = src->nas_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); +} + +__stdcall void * +ExAllocatePoolWithTag(pooltype, len, tag) + uint32_t pooltype; + size_t len; + uint32_t tag; +{ + void *buf; + + buf = malloc(len, M_DEVBUF, M_NOWAIT); + if (buf == NULL) + return(NULL); + return(buf); +} + +__stdcall void +ExFreePool(buf) + void *buf; +{ + free(buf, M_DEVBUF); + return; +} + +__stdcall uint32_t +IoAllocateDriverObjectExtension(drv, clid, extlen, ext) + driver_object *drv; + void *clid; + uint32_t extlen; + void **ext; +{ + custom_extension *ce; + + ce = ExAllocatePoolWithTag(NonPagedPool, sizeof(custom_extension) + + extlen, 0); + + if (ce == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + ce->ce_clid = clid; + INSERT_LIST_TAIL((&drv->dro_driverext->dre_usrext), (&ce->ce_list)); + + *ext = (void *)(ce + 1); + + return(STATUS_SUCCESS); +} + +__stdcall void * +IoGetDriverObjectExtension(drv, clid) + driver_object *drv; + void *clid; +{ + list_entry *e; + custom_extension *ce; + + e = drv->dro_driverext->dre_usrext.nle_flink; + while (e != &drv->dro_driverext->dre_usrext) { + ce = (custom_extension *)e; + if (ce->ce_clid == clid) + return((void *)(ce + 1)); + e = e->nle_flink; + } + + return(NULL); +} + + +__stdcall uint32_t +IoCreateDevice(drv, devextlen, devname, devtype, devchars, exclusive, newdev) + driver_object *drv; + uint32_t devextlen; + unicode_string *devname; + uint32_t devtype; + uint32_t devchars; + uint8_t exclusive; + device_object **newdev; +{ + device_object *dev; + + dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device_object), 0); + if (dev == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + dev->do_type = devtype; + dev->do_drvobj = drv; + dev->do_currirp = NULL; + dev->do_flags = 0; + + if (devextlen) { + dev->do_devext = ExAllocatePoolWithTag(NonPagedPool, + devextlen, 0); + + if (dev->do_devext == NULL) { + ExFreePool(dev); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + bzero(dev->do_devext, devextlen); + } else + dev->do_devext = NULL; + + dev->do_size = sizeof(device_object) + devextlen; + dev->do_refcnt = 1; + dev->do_attacheddev = NULL; + dev->do_nextdev = NULL; + dev->do_devtype = devtype; + dev->do_stacksize = 1; + dev->do_alignreq = 1; + dev->do_characteristics = devchars; + dev->do_iotimer = NULL; + KeInitializeEvent(&dev->do_devlock, EVENT_TYPE_SYNC, TRUE); + + /* + * Vpd is used for disk/tape devices, + * but we don't support those. (Yet.) + */ + dev->do_vpb = NULL; + + dev->do_devobj_ext = ExAllocatePoolWithTag(NonPagedPool, + sizeof(devobj_extension), 0); + + if (dev->do_devobj_ext == NULL) { + if (dev->do_devext != NULL) + ExFreePool(dev->do_devext); + ExFreePool(dev); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + dev->do_devobj_ext->dve_type = 0; + dev->do_devobj_ext->dve_size = sizeof(devobj_extension); + dev->do_devobj_ext->dve_devobj = dev; + + /* + * Attach this device to the driver object's list + * of devices. Note: this is not the same as attaching + * the device to the device stack. The driver's AddDevice + * routine must explicitly call IoAddDeviceToDeviceStack() + * to do that. + */ + + if (drv->dro_devobj == NULL) { + drv->dro_devobj = dev; + dev->do_nextdev = NULL; + } else { + dev->do_nextdev = drv->dro_devobj; + drv->dro_devobj = dev; + } + + *newdev = dev; + + return(STATUS_SUCCESS); +} + +__stdcall void +IoDeleteDevice(dev) + device_object *dev; +{ + device_object *prev; + + if (dev == NULL) + return; + + if (dev->do_devobj_ext != NULL) + ExFreePool(dev->do_devobj_ext); + + if (dev->do_devext != NULL) + ExFreePool(dev->do_devext); + + /* Unlink the device from the driver's device list. */ + + prev = dev->do_drvobj->dro_devobj; + if (prev == dev) + dev->do_drvobj->dro_devobj = dev->do_nextdev; + else { + while (prev->do_nextdev != dev) + prev = prev->do_nextdev; + prev->do_nextdev = dev->do_nextdev; + } + + ExFreePool(dev); + + return; +} + +__stdcall device_object * +IoGetAttachedDevice(dev) + device_object *dev; +{ + device_object *d; + + if (dev == NULL) + return (NULL); + + d = dev; + + while (d->do_attacheddev != NULL) + d = d->do_attacheddev; + + return (d); +} + +__stdcall static irp * +IoBuildSynchronousFsdRequest(func, dobj, buf, len, off, event, status) + uint32_t func; + device_object *dobj; + void *buf; + uint32_t len; + uint64_t *off; + nt_kevent *event; + io_status_block *status; +{ + irp *ip; + + ip = IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status); + if (ip == NULL) + return(NULL); + ip->irp_usrevent = event; + + return(ip); +} + +__stdcall static irp * +IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status) + uint32_t func; + device_object *dobj; + void *buf; + uint32_t len; + uint64_t *off; + io_status_block *status; +{ + irp *ip; + io_stack_location *sl; + + ip = IoAllocateIrp(dobj->do_stacksize, TRUE); + if (ip == NULL) + return(NULL); + + ip->irp_usriostat = status; + ip->irp_tail.irp_overlay.irp_thread = NULL; + + sl = IoGetNextIrpStackLocation(ip); + sl->isl_major = func; + sl->isl_minor = 0; + sl->isl_flags = 0; + sl->isl_ctl = 0; + sl->isl_devobj = dobj; + sl->isl_fileobj = NULL; + sl->isl_completionfunc = NULL; + + ip->irp_userbuf = buf; + + if (dobj->do_flags & DO_BUFFERED_IO) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, len, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return(NULL); + } + bcopy(buf, ip->irp_assoc.irp_sysbuf, len); + } + + if (dobj->do_flags & DO_DIRECT_IO) { + ip->irp_mdl = IoAllocateMdl(buf, len, FALSE, FALSE, ip); + if (ip->irp_mdl == NULL) { + if (ip->irp_assoc.irp_sysbuf != NULL) + ExFreePool(ip->irp_assoc.irp_sysbuf); + IoFreeIrp(ip); + return(NULL); + } + ip->irp_userbuf = NULL; + ip->irp_assoc.irp_sysbuf = NULL; + } + + if (func == IRP_MJ_READ) { + sl->isl_parameters.isl_read.isl_len = len; + if (off != NULL) + sl->isl_parameters.isl_read.isl_byteoff = *off; + else + sl->isl_parameters.isl_read.isl_byteoff = 0; + } + + if (func == IRP_MJ_WRITE) { + sl->isl_parameters.isl_write.isl_len = len; + if (off != NULL) + sl->isl_parameters.isl_write.isl_byteoff = *off; + else + sl->isl_parameters.isl_write.isl_byteoff = 0; + } + + return(ip); +} + +__stdcall static irp * +IoBuildDeviceIoControlRequest(iocode, dobj, ibuf, ilen, obuf, olen, + isinternal, event, status) + uint32_t iocode; + device_object *dobj; + void *ibuf; + uint32_t ilen; + void *obuf; + uint32_t olen; + uint8_t isinternal; + nt_kevent *event; + io_status_block *status; +{ + irp *ip; + io_stack_location *sl; + uint32_t buflen; + + ip = IoAllocateIrp(dobj->do_stacksize, TRUE); + if (ip == NULL) + return(NULL); + ip->irp_usrevent = event; + ip->irp_usriostat = status; + ip->irp_tail.irp_overlay.irp_thread = NULL; + + sl = IoGetNextIrpStackLocation(ip); + sl->isl_major = isinternal == TRUE ? + IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; + sl->isl_minor = 0; + sl->isl_flags = 0; + sl->isl_ctl = 0; + sl->isl_devobj = dobj; + sl->isl_fileobj = NULL; + sl->isl_completionfunc = NULL; + sl->isl_parameters.isl_ioctl.isl_iocode = iocode; + sl->isl_parameters.isl_ioctl.isl_ibuflen = ilen; + sl->isl_parameters.isl_ioctl.isl_obuflen = olen; + + switch(IO_METHOD(iocode)) { + case METHOD_BUFFERED: + if (ilen > olen) + buflen = ilen; + else + buflen = olen; + if (buflen) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, buflen, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return(NULL); + } + } + if (ilen && ibuf != NULL) { + bcopy(ibuf, ip->irp_assoc.irp_sysbuf, ilen); + bzero((char *)ip->irp_assoc.irp_sysbuf + ilen, + buflen - ilen); + } else + bzero(ip->irp_assoc.irp_sysbuf, ilen); + ip->irp_userbuf = obuf; + break; + case METHOD_IN_DIRECT: + case METHOD_OUT_DIRECT: + if (ilen && ibuf != NULL) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, ilen, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return(NULL); + } + bcopy(ibuf, ip->irp_assoc.irp_sysbuf, ilen); + } + if (olen && obuf != NULL) { + ip->irp_mdl = IoAllocateMdl(obuf, olen, + FALSE, FALSE, ip); + /* + * Normally we would MmProbeAndLockPages() + * here, but we don't have to in our + * imlementation. + */ + } + break; + case METHOD_NEITHER: + ip->irp_userbuf = obuf; + sl->isl_parameters.isl_ioctl.isl_type3ibuf = ibuf; + break; + default: + break; + } + + /* + * Ideally, we should associate this IRP with the calling + * thread here. + */ + + return (ip); +} + +__stdcall static irp * +IoAllocateIrp(stsize, chargequota) + uint8_t stsize; + uint8_t chargequota; +{ + irp *i; + + i = ExAllocatePoolWithTag(NonPagedPool, IoSizeOfIrp(stsize), 0); + if (i == NULL) + return (NULL); + + IoInitializeIrp(i, IoSizeOfIrp(stsize), stsize); + + return (i); +} + +__stdcall static irp * +IoMakeAssociatedIrp(ip, stsize) + irp *ip; + uint8_t stsize; +{ + irp *associrp; + + associrp = IoAllocateIrp(stsize, FALSE); + if (associrp == NULL) + return(NULL); + + mtx_lock(&ntoskrnl_dispatchlock); + associrp->irp_flags |= IRP_ASSOCIATED_IRP; + associrp->irp_tail.irp_overlay.irp_thread = + ip->irp_tail.irp_overlay.irp_thread; + associrp->irp_assoc.irp_master = ip; + mtx_unlock(&ntoskrnl_dispatchlock); + + return(associrp); +} + +__stdcall static void +IoFreeIrp(ip) + irp *ip; +{ + ExFreePool(ip); + return; +} + +__stdcall static void +IoInitializeIrp(io, psize, ssize) + irp *io; + uint16_t psize; + uint8_t ssize; +{ + bzero((char *)io, IoSizeOfIrp(ssize)); + io->irp_size = psize; + io->irp_stackcnt = ssize; + io->irp_currentstackloc = ssize; + INIT_LIST_HEAD(&io->irp_thlist); + io->irp_tail.irp_overlay.irp_csl = + (io_stack_location *)(io + 1) + ssize; + + return; +} + +__stdcall static void +IoReuseIrp(ip, status) + irp *ip; + uint32_t status; +{ + uint8_t allocflags; + + allocflags = ip->irp_allocflags; + IoInitializeIrp(ip, ip->irp_size, ip->irp_stackcnt); + ip->irp_iostat.isb_status = status; + ip->irp_allocflags = allocflags; + + return; +} + +__stdcall void +IoAcquireCancelSpinLock(irql) + uint8_t *irql; +{ + KeAcquireSpinLock(&ntoskrnl_cancellock, irql); + return; +} + +__stdcall void +IoReleaseCancelSpinLock(irql) + uint8_t irql; +{ + KeReleaseSpinLock(&ntoskrnl_cancellock, irql); + return; +} + +__stdcall uint8_t +IoCancelIrp(irp *ip) +{ + cancel_func cfunc; + + IoAcquireCancelSpinLock(&ip->irp_cancelirql); + cfunc = IoSetCancelRoutine(ip, NULL); + ip->irp_cancel = TRUE; + if (ip->irp_cancelfunc == NULL) { + IoReleaseCancelSpinLock(ip->irp_cancelirql); + return(FALSE); + } + MSCALL2(cfunc, IoGetCurrentIrpStackLocation(ip)->isl_devobj, ip); + return(TRUE); +} + +__fastcall uint32_t +IofCallDriver(REGARGS2(device_object *dobj, irp *ip)) +{ + driver_object *drvobj; + io_stack_location *sl; + uint32_t status; + driver_dispatch disp; + + drvobj = dobj->do_drvobj; + + if (ip->irp_currentstackloc <= 0) + panic("IoCallDriver(): out of stack locations"); + + IoSetNextIrpStackLocation(ip); + sl = IoGetCurrentIrpStackLocation(ip); + + sl->isl_devobj = dobj; + + disp = drvobj->dro_dispatch[sl->isl_major]; + status = MSCALL2(disp, dobj, ip); + + return(status); +} + +__fastcall void +IofCompleteRequest(REGARGS2(irp *ip, uint8_t prioboost)) +{ + uint32_t i; + uint32_t status; + device_object *dobj; + io_stack_location *sl; + completion_func cf; + + ip->irp_pendingreturned = + IoGetCurrentIrpStackLocation(ip)->isl_ctl & SL_PENDING_RETURNED; + sl = (io_stack_location *)(ip + 1); + + for (i = ip->irp_currentstackloc; i < (uint32_t)ip->irp_stackcnt; i++) { + if (ip->irp_currentstackloc < ip->irp_stackcnt - 1) { + IoSkipCurrentIrpStackLocation(ip); + dobj = IoGetCurrentIrpStackLocation(ip)->isl_devobj; + } else + dobj = NULL; + + if (sl[i].isl_completionfunc != NULL && + ((ip->irp_iostat.isb_status == STATUS_SUCCESS && + sl->isl_ctl & SL_INVOKE_ON_SUCCESS) || + (ip->irp_iostat.isb_status != STATUS_SUCCESS && + sl->isl_ctl & SL_INVOKE_ON_ERROR) || + (ip->irp_cancel == TRUE && + sl->isl_ctl & SL_INVOKE_ON_CANCEL))) { + cf = sl->isl_completionfunc; + status = MSCALL3(cf, dobj, ip, sl->isl_completionctx); + if (status == STATUS_MORE_PROCESSING_REQUIRED) + return; + } + + if (IoGetCurrentIrpStackLocation(ip)->isl_ctl & + SL_PENDING_RETURNED) + ip->irp_pendingreturned = TRUE; + } + + /* Handle any associated IRPs. */ + + if (ip->irp_flags & IRP_ASSOCIATED_IRP) { + uint32_t masterirpcnt; + irp *masterirp; + mdl *m; + + masterirp = ip->irp_assoc.irp_master; + masterirpcnt = FASTCALL1(InterlockedDecrement, + &masterirp->irp_assoc.irp_irpcnt); + + while ((m = ip->irp_mdl) != NULL) { + ip->irp_mdl = m->mdl_next; + IoFreeMdl(m); + } + IoFreeIrp(ip); + if (masterirpcnt == 0) + IoCompleteRequest(masterirp, IO_NO_INCREMENT); + return; + } + + /* With any luck, these conditions will never arise. */ + + if (ip->irp_flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION)) { + if (ip->irp_usriostat != NULL) + *ip->irp_usriostat = ip->irp_iostat; + if (ip->irp_usrevent != NULL) + KeSetEvent(ip->irp_usrevent, prioboost, FALSE); + if (ip->irp_flags & IRP_PAGING_IO) { + if (ip->irp_mdl != NULL) + IoFreeMdl(ip->irp_mdl); + IoFreeIrp(ip); + } + } + + return; +} + +__stdcall device_object * +IoAttachDeviceToDeviceStack(src, dst) + device_object *src; + device_object *dst; +{ + device_object *attached; + + mtx_lock(&ntoskrnl_dispatchlock); + attached = IoGetAttachedDevice(dst); + attached->do_attacheddev = src; + src->do_attacheddev = NULL; + src->do_stacksize = attached->do_stacksize + 1; + mtx_unlock(&ntoskrnl_dispatchlock); + + return(attached); +} + +__stdcall void +IoDetachDevice(topdev) + device_object *topdev; +{ + device_object *tail; + + mtx_lock(&ntoskrnl_dispatchlock); + + /* First, break the chain. */ + tail = topdev->do_attacheddev; + if (tail == NULL) { + mtx_unlock(&ntoskrnl_dispatchlock); + return; + } + topdev->do_attacheddev = tail->do_attacheddev; + topdev->do_refcnt--; + + /* Now reduce the stacksize count for the tail objects. */ + + tail = topdev->do_attacheddev; + while (tail != NULL) { + tail->do_stacksize--; + tail = tail->do_attacheddev; + } + + mtx_unlock(&ntoskrnl_dispatchlock); + + return; +} + +/* Always called with dispatcher lock held. */ +static void +ntoskrnl_wakeup(arg) + void *arg; +{ + nt_dispatch_header *obj; + wait_block *w; + list_entry *e; + struct thread *td; + + obj = arg; + + obj->dh_sigstate = TRUE; + 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; + e = e->nle_flink; + } + + return; +} + +static void +ntoskrnl_time(tval) + uint64_t *tval; +{ + struct timespec ts; + + nanotime(&ts); + *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 + + 11644473600; + + return; +} + +/* + * KeWaitForSingleObject() is a tricky beast, because it can be used + * with several different object types: semaphores, timers, events, + * mutexes and threads. Semaphores don't appear very often, but the + * other object types are quite common. KeWaitForSingleObject() is + * what's normally used to acquire a mutex, and it can be used to + * wait for a thread termination. + * + * The Windows NDIS API is implemented in terms of Windows kernel + * primitives, and some of the object manipulation is duplicated in + * NDIS. For example, NDIS has timers and events, which are actually + * Windows kevents and ktimers. Now, you're supposed to only use the + * NDIS variants of these objects within the confines of the NDIS API, + * but there are some naughty developers out there who will use + * KeWaitForSingleObject() on NDIS timer and event objects, so we + * have to support that as well. Conseqently, our NDIS timer and event + * code has to be closely tied into our ntoskrnl timer and event code, + * just as it is in Windows. + * + * KeWaitForSingleObject() may do different things for different kinds + * of objects: + * + * - For events, we check if the event has been signalled. If the + * event is already in the signalled state, we just return immediately, + * otherwise we wait for it to be set to the signalled state by someone + * else calling KeSetEvent(). Events can be either synchronization or + * notification events. + * + * - For timers, if the timer has already fired and the timer is in + * the signalled state, we just return, otherwise we wait on the + * timer. Unlike an event, timers get signalled automatically when + * they expire rather than someone having to trip them manually. + * Timers initialized with KeInitializeTimer() are always notification + * events: KeInitializeTimerEx() lets you initialize a timer as + * either a notification or synchronization event. + * + * - 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 + * threads waiting to acquire it. Mutexes are always synchronization + * events. + * + * - For threads, the only thing we do is wait until the thread object + * enters a signalled state, which occurs when the thread terminates. + * Threads are always notification events. + * + * A notification event wakes up all threads waiting on an object. A + * synchronization event wakes up just one. Also, a synchronization event + * is auto-clearing, which means we automatically set the event back to + * the non-signalled state once the wakeup is done. + */ + +__stdcall uint32_t +KeWaitForSingleObject(obj, reason, mode, alertable, duetime) + nt_dispatch_header *obj; + uint32_t reason; + uint32_t mode; + uint8_t alertable; + int64_t *duetime; +{ + struct thread *td = curthread; + kmutant *km; + wait_block w; + struct timeval tv; + int error = 0; + uint64_t curtime; + + if (obj == NULL) + return(STATUS_INVALID_PARAMETER); + + mtx_lock(&ntoskrnl_dispatchlock); + + /* + * 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. + */ + + 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; + mtx_unlock(&ntoskrnl_dispatchlock); + return (STATUS_SUCCESS); + } + } else if (obj->dh_sigstate == TRUE) { + if (obj->dh_type == EVENT_TYPE_SYNC) + obj->dh_sigstate = FALSE; + mtx_unlock(&ntoskrnl_dispatchlock); + return (STATUS_SUCCESS); + } + + w.wb_object = obj; + w.wb_kthread = td; + + INSERT_LIST_TAIL((&obj->dh_waitlisthead), (&w.wb_waitlist)); + + /* + * The timeout value is specified in 100 nanosecond units + * and can be a positive or negative number. If it's positive, + * then the duetime is absolute, and we need to convert it + * to an absolute offset relative to now in order to use it. + * If it's negative, then the duetime is relative and we + * just have to convert the units. + */ + + if (duetime != NULL) { + if (*duetime < 0) { + tv.tv_sec = - (*duetime) / 10000000; + tv.tv_usec = (- (*duetime) / 10) - + (tv.tv_sec * 1000000); + } else { + ntoskrnl_time(&curtime); + if (*duetime < curtime) + tv.tv_sec = tv.tv_usec = 0; + else { + tv.tv_sec = ((*duetime) - curtime) / 10000000; + tv.tv_usec = ((*duetime) - curtime) / 10 - + (tv.tv_sec * 1000000); + } + } + } + + error = ndis_thsuspend(td->td_proc, &ntoskrnl_dispatchlock, + duetime == NULL ? 0 : tvtohz(&tv)); + + /* We timed out. Leave the object alone and return status. */ + + if (error == EWOULDBLOCK) { + REMOVE_LIST_ENTRY((&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)); + + mtx_unlock(&ntoskrnl_dispatchlock); + + return(STATUS_SUCCESS); +} + +__stdcall static uint32_t +KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode, + alertable, duetime, wb_array) + uint32_t cnt; + nt_dispatch_header *obj[]; + uint32_t wtype; + uint32_t reason; + uint32_t mode; + uint8_t alertable; + int64_t *duetime; + wait_block *wb_array; +{ + struct thread *td = curthread; + kmutant *km; + wait_block _wb_array[THREAD_WAIT_OBJECTS]; + wait_block *w; + struct timeval tv; + int i, wcnt = 0, widx = 0, error = 0; + uint64_t curtime; + struct timespec t1, t2; + + if (cnt > MAX_WAIT_OBJECTS) + return(STATUS_INVALID_PARAMETER); + if (cnt > THREAD_WAIT_OBJECTS && wb_array == NULL) + return(STATUS_INVALID_PARAMETER); + + mtx_lock(&ntoskrnl_dispatchlock); + + if (wb_array == NULL) + w = &_wb_array[0]; + else + w = wb_array; + + /* First pass: see if we can satisfy any waits immediately. */ + + 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); + } + } + } else if (obj[i]->dh_sigstate == TRUE) { + if (obj[i]->dh_type == EVENT_TYPE_SYNC) + obj[i]->dh_sigstate = FALSE; + if (wtype == WAITTYPE_ANY) { + mtx_unlock(&ntoskrnl_dispatchlock); + return (STATUS_WAIT_0 + i); + } + } + } + + /* + * Second pass: set up wait for anything we can't + * satisfy immediately. + */ + + 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 (duetime != NULL) { + if (*duetime < 0) { + tv.tv_sec = - (*duetime) / 10000000; + tv.tv_usec = (- (*duetime) / 10) - + (tv.tv_sec * 1000000); + } else { + ntoskrnl_time(&curtime); + if (*duetime < curtime) + tv.tv_sec = tv.tv_usec = 0; + else { + tv.tv_sec = ((*duetime) - curtime) / 10000000; + tv.tv_usec = ((*duetime) - curtime) / 10 - + (tv.tv_sec * 1000000); + } + } + } + + while (wcnt) { + nanotime(&t1); + + error = ndis_thsuspend(td->td_proc, &ntoskrnl_dispatchlock, + duetime == NULL ? 0 : tvtohz(&tv)); + + 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++; + } + } + 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)); + wcnt--; + } + } + + if (error || wtype == WAITTYPE_ANY) + break; + + if (duetime != NULL) { + tv.tv_sec -= (t2.tv_sec - t1.tv_sec); + tv.tv_usec -= (t2.tv_nsec - t1.tv_nsec) / 1000; + } + } + + if (wcnt) { + for (i = 0; i < cnt; i++) + REMOVE_LIST_ENTRY((&w[i].wb_waitlist)); + } + + if (error == EWOULDBLOCK) { + mtx_unlock(&ntoskrnl_dispatchlock); + return(STATUS_TIMEOUT); + } + + if (wtype == WAITTYPE_ANY && wcnt) { + mtx_unlock(&ntoskrnl_dispatchlock); + return(STATUS_WAIT_0 + widx); + } + + mtx_unlock(&ntoskrnl_dispatchlock); + + return(STATUS_SUCCESS); +} + +__stdcall static void +WRITE_REGISTER_USHORT(reg, val) + uint16_t *reg; + uint16_t val; +{ + bus_space_write_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val); + return; +} + +__stdcall static uint16_t +READ_REGISTER_USHORT(reg) + uint16_t *reg; +{ + return(bus_space_read_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg)); +} + +__stdcall static void +WRITE_REGISTER_ULONG(reg, val) + uint32_t *reg; + uint32_t val; +{ + bus_space_write_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val); + return; +} + +__stdcall static uint32_t +READ_REGISTER_ULONG(reg) + uint32_t *reg; +{ + return(bus_space_read_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg)); +} + +__stdcall static uint8_t +READ_REGISTER_UCHAR(reg) + uint8_t *reg; +{ + return(bus_space_read_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg)); +} + +__stdcall static void +WRITE_REGISTER_UCHAR(reg, val) + uint8_t *reg; + uint8_t val; +{ + bus_space_write_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val); + return; +} + +__stdcall static int64_t +_allmul(a, b) + int64_t a; + int64_t b; +{ + return (a * b); +} + +__stdcall static int64_t +_alldiv(a, b) + int64_t a; + int64_t b; +{ + return (a / b); +} + +__stdcall static int64_t +_allrem(a, b) + int64_t a; + int64_t b; +{ + return (a % b); +} + +__stdcall static uint64_t +_aullmul(a, b) + uint64_t a; + uint64_t b; +{ + return (a * b); +} + +__stdcall static uint64_t +_aulldiv(a, b) + uint64_t a; + uint64_t b; +{ + return (a / b); +} + +__stdcall static uint64_t +_aullrem(a, b) + uint64_t a; + uint64_t b; +{ + return (a % b); +} + +__regparm static int64_t +_allshl(a, b) + int64_t a; + uint8_t b; +{ + return (a << b); +} + +__regparm static uint64_t +_aullshl(a, b) + uint64_t a; + uint8_t b; +{ + return (a << b); +} + +__regparm static int64_t +_allshr(a, b) + int64_t a; + uint8_t b; +{ + return (a >> b); +} + +__regparm static uint64_t +_aullshr(a, b) + uint64_t a; + uint8_t b; +{ + return (a >> b); +} + +static slist_entry * +ntoskrnl_pushsl(head, entry) + slist_header *head; + slist_entry *entry; +{ + slist_entry *oldhead; + + oldhead = head->slh_list.slh_next; + entry->sl_next = head->slh_list.slh_next; + head->slh_list.slh_next = entry; + head->slh_list.slh_depth++; + head->slh_list.slh_seq++; + + return(oldhead); +} + +static slist_entry * +ntoskrnl_popsl(head) + slist_header *head; +{ + slist_entry *first; + + first = head->slh_list.slh_next; + if (first != NULL) { + head->slh_list.slh_next = first->sl_next; + head->slh_list.slh_depth--; + head->slh_list.slh_seq++; + } + + return(first); +} + +/* + * We need this to make lookaside lists work for amd64. + * We pass a pointer to ExAllocatePoolWithTag() the lookaside + * list structure. For amd64 to work right, this has to be a + * pointer to the wrapped version of the routine, not the + * original. Letting the Windows driver invoke the original + * function directly will result in a convention calling + * mismatch and a pretty crash. On x86, this effectively + * becomes a no-op since ipt_func and ipt_wrap are the same. + */ + +static funcptr +ntoskrnl_findwrap(func) + funcptr func; +{ + image_patch_table *patch; + + patch = ntoskrnl_functbl; + while (patch->ipt_func != NULL) { + if ((funcptr)patch->ipt_func == func) + return((funcptr)patch->ipt_wrap); + patch++; + } + + return(NULL); +} + +__stdcall static void +ExInitializePagedLookasideList(lookaside, allocfunc, freefunc, + flags, size, tag, depth) + paged_lookaside_list *lookaside; + lookaside_alloc_func *allocfunc; + lookaside_free_func *freefunc; + uint32_t flags; + size_t size; + uint32_t tag; + uint16_t depth; +{ + bzero((char *)lookaside, sizeof(paged_lookaside_list)); + + if (size < sizeof(slist_entry)) + lookaside->nll_l.gl_size = sizeof(slist_entry); + else + lookaside->nll_l.gl_size = size; + lookaside->nll_l.gl_tag = tag; + if (allocfunc == NULL) + lookaside->nll_l.gl_allocfunc = + ntoskrnl_findwrap((funcptr)ExAllocatePoolWithTag); + else + lookaside->nll_l.gl_allocfunc = allocfunc; + + if (freefunc == NULL) + lookaside->nll_l.gl_freefunc = + ntoskrnl_findwrap((funcptr)ExFreePool); + else + lookaside->nll_l.gl_freefunc = freefunc; + +#ifdef __i386__ + KeInitializeSpinLock(&lookaside->nll_obsoletelock); +#endif + + lookaside->nll_l.gl_type = NonPagedPool; + lookaside->nll_l.gl_depth = depth; + lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH; + + return; +} + +__stdcall static void +ExDeletePagedLookasideList(lookaside) + paged_lookaside_list *lookaside; +{ + void *buf; + __stdcall void (*freefunc)(void *); + + freefunc = lookaside->nll_l.gl_freefunc; + while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL) + MSCALL1(freefunc, buf); + + return; +} + +__stdcall static void +ExInitializeNPagedLookasideList(lookaside, allocfunc, freefunc, + flags, size, tag, depth) + npaged_lookaside_list *lookaside; + lookaside_alloc_func *allocfunc; + lookaside_free_func *freefunc; + uint32_t flags; + size_t size; + uint32_t tag; + uint16_t depth; +{ + bzero((char *)lookaside, sizeof(npaged_lookaside_list)); + + if (size < sizeof(slist_entry)) + lookaside->nll_l.gl_size = sizeof(slist_entry); + else + lookaside->nll_l.gl_size = size; + lookaside->nll_l.gl_tag = tag; + if (allocfunc == NULL) + lookaside->nll_l.gl_allocfunc = + ntoskrnl_findwrap((funcptr)ExAllocatePoolWithTag); + else + lookaside->nll_l.gl_allocfunc = allocfunc; + + if (freefunc == NULL) + lookaside->nll_l.gl_freefunc = + ntoskrnl_findwrap((funcptr)ExFreePool); + else + lookaside->nll_l.gl_freefunc = freefunc; + +#ifdef __i386__ + KeInitializeSpinLock(&lookaside->nll_obsoletelock); +#endif + + lookaside->nll_l.gl_type = NonPagedPool; + lookaside->nll_l.gl_depth = depth; + lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH; + + return; +} + +__stdcall static void +ExDeleteNPagedLookasideList(lookaside) + npaged_lookaside_list *lookaside; +{ + void *buf; + __stdcall void (*freefunc)(void *); + + freefunc = lookaside->nll_l.gl_freefunc; + while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL) + MSCALL1(freefunc, buf); + + return; +} + +/* + * Note: the interlocked slist push and pop routines are + * declared to be _fastcall in Windows. gcc 3.4 is supposed + * to have support for this calling convention, however we + * don't have that version available yet, so we kludge things + * up using __regparm__(3) and some argument shuffling. + */ + +__fastcall static slist_entry * +InterlockedPushEntrySList(REGARGS2(slist_header *head, slist_entry *entry)) +{ + slist_entry *oldhead; + + oldhead = (slist_entry *)FASTCALL3(ExInterlockedPushEntrySList, + head, entry, &ntoskrnl_global); + + return(oldhead); +} + +__fastcall static slist_entry * +InterlockedPopEntrySList(REGARGS1(slist_header *head)) +{ + slist_entry *first; + + first = (slist_entry *)FASTCALL2(ExInterlockedPopEntrySList, + head, &ntoskrnl_global); + + return(first); +} + +__fastcall static slist_entry * +ExInterlockedPushEntrySList(REGARGS2(slist_header *head, + slist_entry *entry), kspin_lock *lock) +{ + slist_entry *oldhead; + uint8_t irql; + + KeAcquireSpinLock(lock, &irql); + oldhead = ntoskrnl_pushsl(head, entry); + KeReleaseSpinLock(lock, irql); + + return(oldhead); +} + +__fastcall static slist_entry * +ExInterlockedPopEntrySList(REGARGS2(slist_header *head, kspin_lock *lock)) +{ + slist_entry *first; + uint8_t irql; + + KeAcquireSpinLock(lock, &irql); + first = ntoskrnl_popsl(head); + KeReleaseSpinLock(lock, irql); + + return(first); +} + +__stdcall static uint16_t +ExQueryDepthSList(head) + slist_header *head; +{ + uint16_t depth; + uint8_t irql; + + KeAcquireSpinLock(&ntoskrnl_global, &irql); + depth = head->slh_list.slh_depth; + KeReleaseSpinLock(&ntoskrnl_global, irql); + + return(depth); +} + +/* + * The KeInitializeSpinLock(), KefAcquireSpinLockAtDpcLevel() + * and KefReleaseSpinLockFromDpcLevel() appear to be analagous + * to splnet()/splx() in their use. We can't create a new mutex + * lock here because there is no complimentary KeFreeSpinLock() + * function. Instead, we grab a mutex from the mutex pool. + */ +__stdcall void +KeInitializeSpinLock(lock) + kspin_lock *lock; +{ + *lock = 0; + + return; +} + +#ifdef __i386__ +__fastcall void +KefAcquireSpinLockAtDpcLevel(REGARGS1(kspin_lock *lock)) +{ + while (atomic_cmpset_acq_int((volatile u_int *)lock, 0, 1) == 0) + /* sit and spin */; + + return; +} + +__fastcall void +KefReleaseSpinLockFromDpcLevel(REGARGS1(kspin_lock *lock)) +{ + atomic_store_rel_int((volatile u_int *)lock, 0); + + return; +} + +__stdcall uint8_t +KeAcquireSpinLockRaiseToDpc(kspin_lock *lock) +{ + uint8_t oldirql; + + if (KeGetCurrentIrql() > DISPATCH_LEVEL) + panic("IRQL_NOT_LESS_THAN_OR_EQUAL"); + + oldirql = KeRaiseIrql(DISPATCH_LEVEL); + KeAcquireSpinLockAtDpcLevel(lock); + + return(oldirql); +} +#else +__stdcall void +KeAcquireSpinLockAtDpcLevel(kspin_lock *lock) +{ + while (atomic_cmpset_acq_int((volatile u_int *)lock, 0, 1) == 0) + /* sit and spin */; + + return; +} + +__stdcall void +KeReleaseSpinLockFromDpcLevel(kspin_lock *lock) +{ + atomic_store_rel_int((volatile u_int *)lock, 0); + + return; +} +#endif /* __i386__ */ + +__fastcall uintptr_t +InterlockedExchange(REGARGS2(volatile uint32_t *dst, uintptr_t val)) +{ + uint8_t irql; + uintptr_t r; + + KeAcquireSpinLock(&ntoskrnl_global, &irql); + r = *dst; + *dst = val; + KeReleaseSpinLock(&ntoskrnl_global, irql); + + return(r); +} + +__fastcall static uint32_t +InterlockedIncrement(REGARGS1(volatile uint32_t *addend)) +{ + atomic_add_long((volatile u_long *)addend, 1); + return(*addend); +} + +__fastcall static uint32_t +InterlockedDecrement(REGARGS1(volatile uint32_t *addend)) +{ + atomic_subtract_long((volatile u_long *)addend, 1); + return(*addend); +} + +__fastcall static void +ExInterlockedAddLargeStatistic(REGARGS2(uint64_t *addend, uint32_t inc)) +{ + uint8_t irql; + + KeAcquireSpinLock(&ntoskrnl_global, &irql); + *addend += inc; + KeReleaseSpinLock(&ntoskrnl_global, irql); + + return; +}; + +__stdcall mdl * +IoAllocateMdl(vaddr, len, secondarybuf, chargequota, iopkt) + void *vaddr; + uint32_t len; + uint8_t secondarybuf; + uint8_t chargequota; + irp *iopkt; +{ + mdl *m; + int zone = 0; + + if (MmSizeOfMdl(vaddr, len) > MDL_ZONE_SIZE) + m = ExAllocatePoolWithTag(NonPagedPool, + MmSizeOfMdl(vaddr, len), 0); + else { + m = uma_zalloc(mdl_zone, M_NOWAIT | M_ZERO); + zone++; + } + + if (m == NULL) + return (NULL); + + MmInitializeMdl(m, vaddr, len); + + /* + * MmInitializMdl() clears the flags field, so we + * have to set this here. If the MDL came from the + * MDL UMA zone, tag it so we can release it to + * the right place later. + */ + if (zone) + m->mdl_flags = MDL_ZONE_ALLOCED; + + if (iopkt != NULL) { + if (secondarybuf == TRUE) { + mdl *last; + last = iopkt->irp_mdl; + while (last->mdl_next != NULL) + last = last->mdl_next; + last->mdl_next = m; + } else { + if (iopkt->irp_mdl != NULL) + panic("leaking an MDL in IoAllocateMdl()"); + iopkt->irp_mdl = m; + } + } + + return (m); +} + +__stdcall void +IoFreeMdl(m) + mdl *m; +{ + if (m == NULL) + return; + + if (m->mdl_flags & MDL_ZONE_ALLOCED) + uma_zfree(mdl_zone, m); + else + ExFreePool(m); + + return; +} + +__stdcall static uint32_t +MmSizeOfMdl(vaddr, len) + void *vaddr; + size_t len; +{ + uint32_t l; + + l = sizeof(struct mdl) + + (sizeof(vm_offset_t *) * SPAN_PAGES(vaddr, len)); + + return(l); +} + +/* + * The Microsoft documentation says this routine fills in the + * page array of an MDL with the _physical_ page addresses that + * comprise the buffer, but we don't really want to do that here. + * Instead, we just fill in the page array with the kernel virtual + * addresses of the buffers. + */ +__stdcall static void +MmBuildMdlForNonPagedPool(m) + mdl *m; +{ + vm_offset_t *mdl_pages; + int pagecnt, i; + + pagecnt = SPAN_PAGES(m->mdl_byteoffset, m->mdl_bytecount); + + if (pagecnt > (m->mdl_size - sizeof(mdl)) / sizeof(vm_offset_t *)) + panic("not enough pages in MDL to describe buffer"); + + mdl_pages = MmGetMdlPfnArray(m); + + for (i = 0; i < pagecnt; i++) + *mdl_pages = (vm_offset_t)m->mdl_startva + (i * PAGE_SIZE); + + m->mdl_flags |= MDL_SOURCE_IS_NONPAGED_POOL; + m->mdl_mappedsystemva = MmGetMdlVirtualAddress(m); + + return; +} + +__stdcall static void * +MmMapLockedPages(buf, accessmode) + mdl *buf; + uint8_t accessmode; +{ + buf->mdl_flags |= MDL_MAPPED_TO_SYSTEM_VA; + return(MmGetMdlVirtualAddress(buf)); +} + +__stdcall static void * +MmMapLockedPagesSpecifyCache(buf, accessmode, cachetype, vaddr, + bugcheck, prio) + mdl *buf; + uint8_t accessmode; + uint32_t cachetype; + void *vaddr; + uint32_t bugcheck; + uint32_t prio; +{ + return(MmMapLockedPages(buf, accessmode)); +} + +__stdcall static void +MmUnmapLockedPages(vaddr, buf) + void *vaddr; + mdl *buf; +{ + buf->mdl_flags &= ~MDL_MAPPED_TO_SYSTEM_VA; + return; +} + +__stdcall static size_t +RtlCompareMemory(s1, s2, len) + const void *s1; + const void *s2; + size_t len; +{ + size_t i, total = 0; + uint8_t *m1, *m2; + + m1 = __DECONST(char *, s1); + m2 = __DECONST(char *, s2); + + for (i = 0; i < len; i++) { + if (m1[i] == m2[i]) + total++; + } + return(total); +} + +__stdcall static void +RtlInitAnsiString(dst, src) + ndis_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); + } + + return; +} + +__stdcall static void +RtlInitUnicodeString(dst, src) + ndis_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; + } + + return; +} + +__stdcall ndis_status +RtlUnicodeStringToInteger(ustr, base, val) + ndis_unicode_string *ustr; + uint32_t base; + uint32_t *val; +{ + uint16_t *uchr; + int len, neg = 0; + char abuf[64]; + char *astr; + + uchr = ustr->us_buf; + len = ustr->us_len; + bzero(abuf, sizeof(abuf)); + + if ((char)((*uchr) & 0xFF) == '-') { + neg = 1; + uchr++; + len -= 2; + } else if ((char)((*uchr) & 0xFF) == '+') { + neg = 0; + uchr++; + len -= 2; + } + + if (base == 0) { + if ((char)((*uchr) & 0xFF) == 'b') { + base = 2; + uchr++; + len -= 2; + } else if ((char)((*uchr) & 0xFF) == 'o') { + base = 8; + uchr++; + len -= 2; + } else if ((char)((*uchr) & 0xFF) == 'x') { + base = 16; + uchr++; + len -= 2; + } else + base = 10; + } + + astr = abuf; + if (neg) { + strcpy(astr, "-"); + astr++; + } + + ndis_unicode_to_ascii(uchr, len, &astr); + *val = strtoul(abuf, NULL, base); + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +RtlFreeUnicodeString(ustr) + ndis_unicode_string *ustr; +{ + if (ustr->us_buf == NULL) + return; + free(ustr->us_buf, M_DEVBUF); + ustr->us_buf = NULL; + return; +} + +__stdcall static void +RtlFreeAnsiString(astr) + ndis_ansi_string *astr; +{ + if (astr->nas_buf == NULL) + return; + free(astr->nas_buf, M_DEVBUF); + astr->nas_buf = NULL; + return; +} + +static int +atoi(str) + const char *str; +{ + return (int)strtol(str, (char **)NULL, 10); +} + +static long +atol(str) + const char *str; +{ + return strtol(str, (char **)NULL, 10); +} + +static int +rand(void) +{ + struct timeval tv; + + microtime(&tv); + srandom(tv.tv_usec); + return((int)random()); +} + +static void +srand(seed) + unsigned int seed; +{ + srandom(seed); + return; +} + +__stdcall static uint8_t +IoIsWdmVersionAvailable(major, minor) + uint8_t major; + uint8_t minor; +{ + if (major == WDM_MAJOR && minor == WDM_MINOR_WINXP) + return(TRUE); + return(FALSE); +} + +__stdcall static ndis_status +IoGetDeviceProperty(devobj, regprop, buflen, prop, reslen) + device_object *devobj; + uint32_t regprop; + uint32_t buflen; + void *prop; + uint32_t *reslen; +{ + driver_object *drv; + uint16_t **name; + + drv = devobj->do_drvobj; + + switch (regprop) { + case DEVPROP_DRIVER_KEYNAME: + name = prop; + *name = drv->dro_drivername.us_buf; + *reslen = drv->dro_drivername.us_len; + break; + default: + return(STATUS_INVALID_PARAMETER_2); + break; + } + + return(STATUS_SUCCESS); +} + +__stdcall static void +KeInitializeMutex(kmutex, level) + kmutant *kmutex; + uint32_t level; +{ + INIT_LIST_HEAD((&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_ownerthread = NULL; + return; +} + +__stdcall static uint32_t +KeReleaseMutex(kmutex, kwait) + kmutant *kmutex; + uint8_t kwait; +{ + mtx_lock(&ntoskrnl_dispatchlock); + if (kmutex->km_ownerthread != curthread->td_proc) { + mtx_unlock(&ntoskrnl_dispatchlock); + return(STATUS_MUTANT_NOT_OWNED); + } + kmutex->km_acquirecnt--; + if (kmutex->km_acquirecnt == 0) { + kmutex->km_ownerthread = NULL; + ntoskrnl_wakeup(&kmutex->km_header); + } + mtx_unlock(&ntoskrnl_dispatchlock); + + return(kmutex->km_acquirecnt); +} + +__stdcall static uint32_t +KeReadStateMutex(kmutex) + kmutant *kmutex; +{ + return(kmutex->km_header.dh_sigstate); +} + +__stdcall void +KeInitializeEvent(kevent, type, state) + nt_kevent *kevent; + uint32_t type; + uint8_t state; +{ + INIT_LIST_HEAD((&kevent->k_header.dh_waitlisthead)); + kevent->k_header.dh_sigstate = state; + kevent->k_header.dh_type = type; + kevent->k_header.dh_size = OTYPE_EVENT; + return; +} + +__stdcall uint32_t +KeResetEvent(kevent) + nt_kevent *kevent; +{ + uint32_t prevstate; + + mtx_lock(&ntoskrnl_dispatchlock); + prevstate = kevent->k_header.dh_sigstate; + kevent->k_header.dh_sigstate = FALSE; + mtx_unlock(&ntoskrnl_dispatchlock); + + return(prevstate); +} + +__stdcall uint32_t +KeSetEvent(kevent, increment, kwait) + nt_kevent *kevent; + uint32_t increment; + uint8_t kwait; +{ + uint32_t prevstate; + + mtx_lock(&ntoskrnl_dispatchlock); + prevstate = kevent->k_header.dh_sigstate; + ntoskrnl_wakeup(&kevent->k_header); + mtx_unlock(&ntoskrnl_dispatchlock); + + return(prevstate); +} + +__stdcall void +KeClearEvent(kevent) + nt_kevent *kevent; +{ + kevent->k_header.dh_sigstate = FALSE; + return; +} + +__stdcall uint32_t +KeReadStateEvent(kevent) + nt_kevent *kevent; +{ + return(kevent->k_header.dh_sigstate); +} + +__stdcall static ndis_status +ObReferenceObjectByHandle(handle, reqaccess, otype, + accessmode, object, handleinfo) + ndis_handle handle; + uint32_t reqaccess; + void *otype; + uint8_t accessmode; + void **object; + void **handleinfo; +{ + nt_objref *nr; + + nr = malloc(sizeof(nt_objref), M_DEVBUF, M_NOWAIT|M_ZERO); + if (nr == NULL) + return(NDIS_STATUS_FAILURE); + + INIT_LIST_HEAD((&nr->no_dh.dh_waitlisthead)); + nr->no_obj = handle; + nr->no_dh.dh_size = OTYPE_THREAD; + TAILQ_INSERT_TAIL(&ntoskrnl_reflist, nr, link); + *object = nr; + + return(NDIS_STATUS_SUCCESS); +} + +__fastcall static void +ObfDereferenceObject(REGARGS1(void *object)) +{ + nt_objref *nr; + + nr = object; + TAILQ_REMOVE(&ntoskrnl_reflist, nr, link); + free(nr, M_DEVBUF); + + return; +} + +__stdcall static uint32_t +ZwClose(handle) + ndis_handle handle; +{ + return(STATUS_SUCCESS); +} + +/* + * This is here just in case the thread returns without calling + * PsTerminateSystemThread(). + */ +static void +ntoskrnl_thrfunc(arg) + void *arg; +{ + thread_context *thrctx; + __stdcall uint32_t (*tfunc)(void *); + void *tctx; + uint32_t rval; + + thrctx = arg; + tfunc = thrctx->tc_thrfunc; + tctx = thrctx->tc_thrctx; + free(thrctx, M_TEMP); + + rval = MSCALL1(tfunc, tctx); + + PsTerminateSystemThread(rval); + return; /* notreached */ +} + +__stdcall static ndis_status +PsCreateSystemThread(handle, reqaccess, objattrs, phandle, + clientid, thrfunc, thrctx) + ndis_handle *handle; + uint32_t reqaccess; + void *objattrs; + ndis_handle phandle; + void *clientid; + void *thrfunc; + void *thrctx; +{ + int error; + char tname[128]; + thread_context *tc; + struct proc *p; + + tc = malloc(sizeof(thread_context), M_TEMP, M_NOWAIT); + if (tc == NULL) + return(NDIS_STATUS_FAILURE); + + tc->tc_thrctx = thrctx; + tc->tc_thrfunc = thrfunc; + + sprintf(tname, "windows kthread %d", ntoskrnl_kth); + error = kthread_create(ntoskrnl_thrfunc, tc, &p, + RFHIGHPID, NDIS_KSTACK_PAGES, tname); + *handle = p; + + ntoskrnl_kth++; + + return(error); +} + +/* + * In Windows, the exit of a thread is an event that you're allowed + * to wait on, assuming you've obtained a reference to the thread using + * ObReferenceObjectByHandle(). Unfortunately, the only way we can + * simulate this behavior is to register each thread we create in a + * reference list, and if someone holds a reference to us, we poke + * them. + */ +__stdcall static ndis_status +PsTerminateSystemThread(status) + ndis_status status; +{ + struct nt_objref *nr; + + mtx_lock(&ntoskrnl_dispatchlock); + TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) { + if (nr->no_obj != curthread->td_proc) + continue; + ntoskrnl_wakeup(&nr->no_dh); + break; + } + mtx_unlock(&ntoskrnl_dispatchlock); + + ntoskrnl_kth--; + +#if __FreeBSD_version < 502113 + mtx_lock(&Giant); +#endif + kthread_exit(0); + return(0); /* notreached */ +} + +static uint32_t +DbgPrint(char *fmt, ...) +{ + va_list ap; + + if (bootverbose) { + va_start(ap, fmt); + vprintf(fmt, ap); + } + + return(STATUS_SUCCESS); +} + +__stdcall static void +DbgBreakPoint(void) +{ + +#if __FreeBSD_version < 502113 + Debugger("DbgBreakPoint(): breakpoint"); +#else + kdb_enter("DbgBreakPoint(): breakpoint"); +#endif +} + +static void +ntoskrnl_timercall(arg) + void *arg; +{ + ktimer *timer; + struct timeval tv; + + mtx_unlock(&Giant); + + mtx_lock(&ntoskrnl_dispatchlock); + + timer = arg; + + timer->k_header.dh_inserted = FALSE; + + /* + * If this is a periodic timer, re-arm it + * so it will fire again. We do this before + * calling any deferred procedure calls because + * it's possible the DPC might cancel the timer, + * in which case it would be wrong for us to + * re-arm it again afterwards. + */ + + if (timer->k_period) { + 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)); + } + + if (timer->k_dpc != NULL) + KeInsertQueueDpc(timer->k_dpc, NULL, NULL); + + ntoskrnl_wakeup(&timer->k_header); + mtx_unlock(&ntoskrnl_dispatchlock); + + mtx_lock(&Giant); + + return; +} + +__stdcall void +KeInitializeTimer(timer) + ktimer *timer; +{ + if (timer == NULL) + return; + + KeInitializeTimerEx(timer, EVENT_TYPE_NOTIFY); + + return; +} + +__stdcall void +KeInitializeTimerEx(timer, type) + ktimer *timer; + uint32_t type; +{ + if (timer == NULL) + return; + + INIT_LIST_HEAD((&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); + + return; +} + +/* + * This is a wrapper for Windows deferred procedure calls that + * have been placed on an NDIS thread work queue. We need it + * since the DPC could be a _stdcall function. Also, as far as + * I can tell, defered procedure calls must run at DISPATCH_LEVEL. + */ +static void +ntoskrnl_run_dpc(arg) + void *arg; +{ + __stdcall kdpc_func dpcfunc; + kdpc *dpc; + uint8_t irql; + + dpc = arg; + dpcfunc = dpc->k_deferedfunc; + irql = KeRaiseIrql(DISPATCH_LEVEL); + MSCALL4(dpcfunc, dpc, dpc->k_deferredctx, + dpc->k_sysarg1, dpc->k_sysarg2); + KeLowerIrql(irql); + + return; +} + +__stdcall void +KeInitializeDpc(dpc, dpcfunc, dpcctx) + kdpc *dpc; + void *dpcfunc; + void *dpcctx; +{ + + if (dpc == NULL) + return; + + dpc->k_deferedfunc = dpcfunc; + dpc->k_deferredctx = dpcctx; + + return; +} + +__stdcall uint8_t +KeInsertQueueDpc(dpc, sysarg1, sysarg2) + kdpc *dpc; + void *sysarg1; + void *sysarg2; +{ + dpc->k_sysarg1 = sysarg1; + dpc->k_sysarg2 = sysarg2; + + if (ndis_sched(ntoskrnl_run_dpc, dpc, NDIS_SWI)) + return(FALSE); + + return(TRUE); +} + +__stdcall uint8_t +KeRemoveQueueDpc(dpc) + kdpc *dpc; +{ + if (ndis_unsched(ntoskrnl_run_dpc, dpc, NDIS_SWI)) + return(FALSE); + + return(TRUE); +} + +__stdcall uint8_t +KeSetTimerEx(timer, duetime, period, dpc) + ktimer *timer; + int64_t duetime; + uint32_t period; + kdpc *dpc; +{ + struct timeval tv; + uint64_t curtime; + uint8_t pending; + + if (timer == NULL) + return(FALSE); + + mtx_lock(&ntoskrnl_dispatchlock); + + if (timer->k_header.dh_inserted == TRUE) { + untimeout(ntoskrnl_timercall, timer, timer->k_handle); + timer->k_header.dh_inserted = FALSE; + pending = TRUE; + } else + pending = FALSE; + + timer->k_duetime = duetime; + timer->k_period = period; + timer->k_header.dh_sigstate = FALSE; + timer->k_dpc = dpc; + + if (duetime < 0) { + tv.tv_sec = - (duetime) / 10000000; + tv.tv_usec = (- (duetime) / 10) - + (tv.tv_sec * 1000000); + } else { + ntoskrnl_time(&curtime); + if (duetime < curtime) + tv.tv_sec = tv.tv_usec = 0; + else { + tv.tv_sec = ((duetime) - curtime) / 10000000; + tv.tv_usec = ((duetime) - curtime) / 10 - + (tv.tv_sec * 1000000); + } + } + + timer->k_header.dh_inserted = TRUE; + timer->k_handle = timeout(ntoskrnl_timercall, timer, tvtohz(&tv)); + + mtx_unlock(&ntoskrnl_dispatchlock); + + return(pending); +} + +__stdcall uint8_t +KeSetTimer(timer, duetime, dpc) + ktimer *timer; + int64_t duetime; + kdpc *dpc; +{ + return (KeSetTimerEx(timer, duetime, 0, dpc)); +} + +__stdcall uint8_t +KeCancelTimer(timer) + ktimer *timer; +{ + uint8_t pending; + + if (timer == NULL) + return(FALSE); + + mtx_lock(&ntoskrnl_dispatchlock); + + if (timer->k_header.dh_inserted == TRUE) { + untimeout(ntoskrnl_timercall, timer, timer->k_handle); + pending = TRUE; + } else + pending = KeRemoveQueueDpc(timer->k_dpc); + + mtx_unlock(&ntoskrnl_dispatchlock); + + return(pending); +} + +__stdcall uint8_t +KeReadStateTimer(timer) + ktimer *timer; +{ + return(timer->k_header.dh_sigstate); +} + +__stdcall static void +dummy() +{ + printf ("ntoskrnl dummy called...\n"); + return; +} + + +image_patch_table ntoskrnl_functbl[] = { + IMPORT_FUNC(RtlCompareMemory), + IMPORT_FUNC(RtlEqualUnicodeString), + IMPORT_FUNC(RtlCopyUnicodeString), + IMPORT_FUNC(RtlUnicodeStringToAnsiString), + IMPORT_FUNC(RtlAnsiStringToUnicodeString), + IMPORT_FUNC(RtlInitAnsiString), + IMPORT_FUNC_MAP(RtlInitString, RtlInitAnsiString), + IMPORT_FUNC(RtlInitUnicodeString), + IMPORT_FUNC(RtlFreeAnsiString), + IMPORT_FUNC(RtlFreeUnicodeString), + IMPORT_FUNC(RtlUnicodeStringToInteger), + IMPORT_FUNC(sprintf), + IMPORT_FUNC(vsprintf), + IMPORT_FUNC_MAP(_snprintf, snprintf), + IMPORT_FUNC_MAP(_vsnprintf, vsnprintf), + IMPORT_FUNC(DbgPrint), + IMPORT_FUNC(DbgBreakPoint), + IMPORT_FUNC(strncmp), + IMPORT_FUNC(strcmp), + IMPORT_FUNC(strncpy), + IMPORT_FUNC(strcpy), + IMPORT_FUNC(strlen), + IMPORT_FUNC(memcpy), + IMPORT_FUNC_MAP(memmove, ntoskrnl_memset), + IMPORT_FUNC_MAP(memset, ntoskrnl_memset), + IMPORT_FUNC(IoAllocateDriverObjectExtension), + IMPORT_FUNC(IoGetDriverObjectExtension), + IMPORT_FUNC(IofCallDriver), + IMPORT_FUNC(IofCompleteRequest), + IMPORT_FUNC(IoAcquireCancelSpinLock), + IMPORT_FUNC(IoReleaseCancelSpinLock), + IMPORT_FUNC(IoCancelIrp), + IMPORT_FUNC(IoCreateDevice), + IMPORT_FUNC(IoDeleteDevice), + IMPORT_FUNC(IoGetAttachedDevice), + IMPORT_FUNC(IoAttachDeviceToDeviceStack), + IMPORT_FUNC(IoDetachDevice), + IMPORT_FUNC(IoBuildSynchronousFsdRequest), + IMPORT_FUNC(IoBuildAsynchronousFsdRequest), + IMPORT_FUNC(IoBuildDeviceIoControlRequest), + IMPORT_FUNC(IoAllocateIrp), + IMPORT_FUNC(IoReuseIrp), + IMPORT_FUNC(IoMakeAssociatedIrp), + IMPORT_FUNC(IoFreeIrp), + IMPORT_FUNC(IoInitializeIrp), + IMPORT_FUNC(KeWaitForSingleObject), + IMPORT_FUNC(KeWaitForMultipleObjects), + IMPORT_FUNC(_allmul), + IMPORT_FUNC(_alldiv), + IMPORT_FUNC(_allrem), + IMPORT_FUNC(_allshr), + IMPORT_FUNC(_allshl), + IMPORT_FUNC(_aullmul), + IMPORT_FUNC(_aulldiv), + IMPORT_FUNC(_aullrem), + IMPORT_FUNC(_aullshr), + IMPORT_FUNC(_aullshl), + IMPORT_FUNC(atoi), + IMPORT_FUNC(atol), + IMPORT_FUNC(rand), + IMPORT_FUNC(srand), + IMPORT_FUNC(WRITE_REGISTER_USHORT), + IMPORT_FUNC(READ_REGISTER_USHORT), + IMPORT_FUNC(WRITE_REGISTER_ULONG), + IMPORT_FUNC(READ_REGISTER_ULONG), + IMPORT_FUNC(READ_REGISTER_UCHAR), + IMPORT_FUNC(WRITE_REGISTER_UCHAR), + IMPORT_FUNC(ExInitializePagedLookasideList), + IMPORT_FUNC(ExDeletePagedLookasideList), + IMPORT_FUNC(ExInitializeNPagedLookasideList), + IMPORT_FUNC(ExDeleteNPagedLookasideList), + IMPORT_FUNC(InterlockedPopEntrySList), + IMPORT_FUNC(InterlockedPushEntrySList), + IMPORT_FUNC(ExQueryDepthSList), + IMPORT_FUNC_MAP(ExpInterlockedPopEntrySList, InterlockedPopEntrySList), + IMPORT_FUNC_MAP(ExpInterlockedPushEntrySList, + InterlockedPushEntrySList), + IMPORT_FUNC(ExInterlockedPopEntrySList), + IMPORT_FUNC(ExInterlockedPushEntrySList), + IMPORT_FUNC(ExAllocatePoolWithTag), + IMPORT_FUNC(ExFreePool), +#ifdef __i386__ + IMPORT_FUNC(KefAcquireSpinLockAtDpcLevel), + IMPORT_FUNC(KefReleaseSpinLockFromDpcLevel), + IMPORT_FUNC(KeAcquireSpinLockRaiseToDpc), +#else + /* + * For AMD64, we can get away with just mapping + * KeAcquireSpinLockRaiseToDpc() directly to KfAcquireSpinLock() + * because the calling conventions end up being the same. + * On i386, we have to be careful because KfAcquireSpinLock() + * is _fastcall but KeAcquireSpinLockRaiseToDpc() isn't. + */ + IMPORT_FUNC(KeAcquireSpinLockAtDpcLevel), + IMPORT_FUNC(KeReleaseSpinLockFromDpcLevel), + IMPORT_FUNC_MAP(KeAcquireSpinLockRaiseToDpc, KfAcquireSpinLock), +#endif + IMPORT_FUNC_MAP(KeReleaseSpinLock, KfReleaseSpinLock), + IMPORT_FUNC(InterlockedIncrement), + IMPORT_FUNC(InterlockedDecrement), + IMPORT_FUNC(ExInterlockedAddLargeStatistic), + IMPORT_FUNC(IoAllocateMdl), + IMPORT_FUNC(IoFreeMdl), + IMPORT_FUNC(MmSizeOfMdl), + IMPORT_FUNC(MmMapLockedPages), + IMPORT_FUNC(MmMapLockedPagesSpecifyCache), + IMPORT_FUNC(MmUnmapLockedPages), + IMPORT_FUNC(MmBuildMdlForNonPagedPool), + IMPORT_FUNC(KeInitializeSpinLock), + IMPORT_FUNC(IoIsWdmVersionAvailable), + IMPORT_FUNC(IoGetDeviceProperty), + IMPORT_FUNC(KeInitializeMutex), + IMPORT_FUNC(KeReleaseMutex), + IMPORT_FUNC(KeReadStateMutex), + IMPORT_FUNC(KeInitializeEvent), + IMPORT_FUNC(KeSetEvent), + IMPORT_FUNC(KeResetEvent), + IMPORT_FUNC(KeClearEvent), + IMPORT_FUNC(KeReadStateEvent), + IMPORT_FUNC(KeInitializeTimer), + IMPORT_FUNC(KeInitializeTimerEx), + IMPORT_FUNC(KeSetTimer), + IMPORT_FUNC(KeSetTimerEx), + IMPORT_FUNC(KeCancelTimer), + IMPORT_FUNC(KeReadStateTimer), + IMPORT_FUNC(KeInitializeDpc), + IMPORT_FUNC(KeInsertQueueDpc), + IMPORT_FUNC(KeRemoveQueueDpc), + IMPORT_FUNC(ObReferenceObjectByHandle), + IMPORT_FUNC(ObfDereferenceObject), + IMPORT_FUNC(ZwClose), + IMPORT_FUNC(PsCreateSystemThread), + IMPORT_FUNC(PsTerminateSystemThread), + + /* + * This last entry is a catch-all for any function we haven't + * implemented yet. The PE import list patching routine will + * use it for any function that doesn't have an explicit match + * in this table. + */ + + { NULL, (FUNC)dummy, NULL }, + + /* End of list. */ + + { NULL, NULL, NULL } +}; diff --git a/sys/compat/ndis/subr_pe.c b/sys/compat/ndis/subr_pe.c new file mode 100644 index 000000000000..11802b18d9b3 --- /dev/null +++ b/sys/compat/ndis/subr_pe.c @@ -0,0 +1,638 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.7.2.3 2005/03/31 04:24:36 wpaul Exp $"); + +/* + * This file contains routines for relocating and dynamically linking + * executable object code files in the Windows(r) PE (Portable Executable) + * format. In Windows, anything with a .EXE, .DLL or .SYS extention is + * considered an executable, and all such files have some structures in + * common. The PE format was apparently based largely on COFF but has + * mutated significantly over time. We are mainly concerned with .SYS files, + * so this module implements only enough routines to be able to parse the + * headers and sections of a .SYS object file and perform the necessary + * relocations and jump table patching to allow us to call into it + * (and to have it call back to us). Note that while this module + * can handle fixups for imported symbols, it knows nothing about + * exporting them. + */ + +#include +#include +#include +#ifdef _KERNEL +#include +extern int ndis_strncasecmp(const char *, const char *, size_t); +#define strncasecmp(a, b, c) ndis_strncasecmp(a, b, c) +#else +#include +#include +#include +#include +#endif + +#include + +static vm_offset_t pe_functbl_match(image_patch_table *, char *); + +/* + * Check for an MS-DOS executable header. All Windows binaries + * have a small MS-DOS executable prepended to them to print out + * the "This program requires Windows" message. Even .SYS files + * have this header, in spite of the fact that you're can't actually + * run them directly. + */ + +int +pe_get_dos_header(imgbase, hdr) + vm_offset_t imgbase; + image_dos_header *hdr; +{ + uint16_t signature; + + if (imgbase == 0 || hdr == NULL) + return (EINVAL); + + signature = *(uint16_t *)imgbase; + if (signature != IMAGE_DOS_SIGNATURE) + return (ENOEXEC); + + bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header)); + + return(0); +} + +/* + * Verify that this image has a Windows NT PE signature. + */ + +int +pe_is_nt_image(imgbase) + vm_offset_t imgbase; +{ + uint32_t signature; + image_dos_header *dos_hdr; + + if (imgbase == 0) + return (EINVAL); + + signature = *(uint16_t *)imgbase; + if (signature == IMAGE_DOS_SIGNATURE) { + dos_hdr = (image_dos_header *)imgbase; + signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew); + if (signature == IMAGE_NT_SIGNATURE) + return(0); + } + + return(ENOEXEC); +} + +/* + * Return a copy of the optional header. This contains the + * executable entry point and the directory listing which we + * need to find the relocations and imports later. + */ + +int +pe_get_optional_header(imgbase, hdr) + vm_offset_t imgbase; + image_optional_header *hdr; +{ + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + + if (imgbase == 0 || hdr == NULL) + return(EINVAL); + + if (pe_is_nt_image(imgbase)) + return (EINVAL); + + dos_hdr = (image_dos_header *)(imgbase); + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + + bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr, + sizeof(image_optional_header)); + + return(0); +} + +/* + * Return a copy of the file header. Contains the number of + * sections in this image. + */ + +int +pe_get_file_header(imgbase, hdr) + vm_offset_t imgbase; + image_file_header *hdr; +{ + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + + if (imgbase == 0 || hdr == NULL) + return(EINVAL); + + if (pe_is_nt_image(imgbase)) + return (EINVAL); + + dos_hdr = (image_dos_header *)imgbase; + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + + bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr, + sizeof(image_file_header)); + + return(0); +} + +/* + * Return the header of the first section in this image (usually + * .text). + */ + +int +pe_get_section_header(imgbase, hdr) + vm_offset_t imgbase; + image_section_header *hdr; +{ + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + image_section_header *sect_hdr; + + if (imgbase == 0 || hdr == NULL) + return(EINVAL); + + if (pe_is_nt_image(imgbase)) + return (EINVAL); + + dos_hdr = (image_dos_header *)imgbase; + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + + sizeof(image_nt_header)); + + bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header)); + + return(0); +} + +/* + * Return the number of sections in this executable, or 0 on error. + */ + +int +pe_numsections(imgbase) + vm_offset_t imgbase; +{ + image_file_header file_hdr; + + if (pe_get_file_header(imgbase, &file_hdr)) + return(0); + + return (file_hdr.ifh_numsections); +} + +/* + * Return the base address that this image was linked for. + * This helps us calculate relocation addresses later. + */ + +vm_offset_t +pe_imagebase(imgbase) + vm_offset_t imgbase; +{ + image_optional_header optional_hdr; + + if (pe_get_optional_header(imgbase, &optional_hdr)) + return(0); + + return (optional_hdr.ioh_imagebase); +} + +/* + * Return the offset of a given directory structure within the + * image. Directories reside within sections. + */ + +vm_offset_t +pe_directory_offset(imgbase, diridx) + vm_offset_t imgbase; + uint32_t diridx; +{ + image_optional_header opt_hdr; + vm_offset_t dir; + + if (pe_get_optional_header(imgbase, &opt_hdr)) + return(0); + + if (diridx >= opt_hdr.ioh_rva_size_cnt) + return(0); + + dir = opt_hdr.ioh_datadir[diridx].idd_vaddr; + + return(pe_translate_addr(imgbase, dir)); +} + +vm_offset_t +pe_translate_addr(imgbase, rva) + vm_offset_t imgbase; + vm_offset_t rva; +{ + image_optional_header opt_hdr; + image_section_header *sect_hdr; + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + int i = 0, sections, fixedlen; + + if (pe_get_optional_header(imgbase, &opt_hdr)) + return(0); + + sections = pe_numsections(imgbase); + + dos_hdr = (image_dos_header *)imgbase; + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + + sizeof(image_nt_header)); + + /* + * The test here is to see if the RVA falls somewhere + * inside the section, based on the section's start RVA + * and its length. However it seems sometimes the + * virtual length isn't enough to cover the entire + * area of the section. We fudge by taking into account + * the section alignment and rounding the section length + * up to a page boundary. + */ + while (i++ < sections) { + fixedlen = sect_hdr->ish_misc.ish_vsize; + fixedlen += ((opt_hdr.ioh_sectalign - 1) - + sect_hdr->ish_misc.ish_vsize) & + (opt_hdr.ioh_sectalign - 1); + if (sect_hdr->ish_vaddr <= (uint32_t)rva && + (sect_hdr->ish_vaddr + fixedlen) > + (uint32_t)rva) + break; + sect_hdr++; + } + + if (i > sections) + return(0); + + return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr + + sect_hdr->ish_rawdataaddr)); +} + +/* + * Get the section header for a particular section. Note that + * section names can be anything, but there are some standard + * ones (.text, .data, .rdata, .reloc). + */ + +int +pe_get_section(imgbase, hdr, name) + vm_offset_t imgbase; + image_section_header *hdr; + const char *name; +{ + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + image_section_header *sect_hdr; + + int i, sections; + + if (imgbase == 0 || hdr == NULL) + return(EINVAL); + + if (pe_is_nt_image(imgbase)) + return (EINVAL); + + sections = pe_numsections(imgbase); + + dos_hdr = (image_dos_header *)imgbase; + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + + sizeof(image_nt_header)); + + for (i = 0; i < sections; i++) { + if (!strcmp ((char *)§_hdr->ish_name, name)) { + bcopy((char *)sect_hdr, (char *)hdr, + sizeof(image_section_header)); + return(0); + } else + sect_hdr++; + } + + return (ENOEXEC); +} + +/* + * Apply the base relocations to this image. The relocation table + * resides within the .reloc section. Relocations are specified in + * blocks which refer to a particular page. We apply the relocations + * one page block at a time. + */ + +int +pe_relocate(imgbase) + vm_offset_t imgbase; +{ + image_section_header sect; + image_base_reloc *relhdr; + uint16_t rel, *sloc; + vm_offset_t base; + vm_size_t delta; + uint32_t *lloc; + uint64_t *qloc; + int i, count; + vm_offset_t txt; + + base = pe_imagebase(imgbase); + pe_get_section(imgbase, §, ".text"); + txt = pe_translate_addr(imgbase, sect.ish_vaddr); + delta = (uint32_t)(txt) - base - sect.ish_vaddr; + + pe_get_section(imgbase, §, ".reloc"); + + relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); + + do { + count = (relhdr->ibr_blocksize - + (sizeof(uint32_t) * 2)) / sizeof(uint16_t); + for (i = 0; i < count; i++) { + rel = relhdr->ibr_rel[i]; + switch (IMR_RELTYPE(rel)) { + case IMAGE_REL_BASED_ABSOLUTE: + break; + case IMAGE_REL_BASED_HIGHLOW: + lloc = (uint32_t *)pe_translate_addr(imgbase, + relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); + *lloc = pe_translate_addr(imgbase, + (*lloc - base)); + break; + case IMAGE_REL_BASED_HIGH: + sloc = (uint16_t *)pe_translate_addr(imgbase, + relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); + *sloc += (delta & 0xFFFF0000) >> 16; + break; + case IMAGE_REL_BASED_LOW: + sloc = (uint16_t *)pe_translate_addr(imgbase, + relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); + *sloc += (delta & 0xFFFF); + break; + case IMAGE_REL_BASED_DIR64: + qloc = (uint64_t *)pe_translate_addr(imgbase, + relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); + *qloc = pe_translate_addr(imgbase, + (*qloc - base)); + break; + + default: + printf ("[%d]reloc type: %d\n",i, + IMR_RELTYPE(rel)); + break; + } + } + relhdr = (image_base_reloc *)((vm_offset_t)relhdr + + relhdr->ibr_blocksize); + } while (relhdr->ibr_blocksize); + + return(0); +} + +/* + * Return the import descriptor for a particular module. An image + * may be linked against several modules, typically HAL.dll, ntoskrnl.exe + * and NDIS.SYS. For each module, there is a list of imported function + * names and their addresses. + * + * Note: module names are case insensitive! + */ + +int +pe_get_import_descriptor(imgbase, desc, module) + vm_offset_t imgbase; + image_import_descriptor *desc; + char *module; +{ + vm_offset_t offset; + image_import_descriptor *imp_desc; + char *modname; + + if (imgbase == 0 || module == NULL || desc == NULL) + return(EINVAL); + + offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); + if (offset == 0) + return (ENOENT); + + imp_desc = (void *)offset; + + while (imp_desc->iid_nameaddr) { + modname = (char *)pe_translate_addr(imgbase, + imp_desc->iid_nameaddr); + if (!strncasecmp(module, modname, strlen(module))) { + bcopy((char *)imp_desc, (char *)desc, + sizeof(image_import_descriptor)); + return(0); + } + imp_desc++; + } + + return (ENOENT); +} + +int +pe_get_messagetable(imgbase, md) + vm_offset_t imgbase; + message_resource_data **md; +{ + image_resource_directory *rdir, *rtype; + image_resource_directory_entry *dent, *dent2; + image_resource_data_entry *rent; + vm_offset_t offset; + int i; + + if (imgbase == 0) + return(EINVAL); + + offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); + if (offset == 0) + return (ENOENT); + + rdir = (image_resource_directory *)offset; + + dent = (image_resource_directory_entry *)(offset + + sizeof(image_resource_directory)); + + for (i = 0; i < rdir->ird_id_entries; i++){ + if (dent->irde_name != RT_MESSAGETABLE) { + dent++; + continue; + } + dent2 = dent; + while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { + rtype = (image_resource_directory *)(offset + + (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); + dent2 = (image_resource_directory_entry *) + ((uintptr_t)rtype + + sizeof(image_resource_directory)); + } + rent = (image_resource_data_entry *)(offset + + dent2->irde_dataoff); + *md = (message_resource_data *)pe_translate_addr(imgbase, + rent->irde_offset); + return(0); + } + + return(ENOENT); +} + +int +pe_get_message(imgbase, id, str, len, flags) + vm_offset_t imgbase; + uint32_t id; + char **str; + int *len; + uint16_t *flags; +{ + message_resource_data *md = NULL; + message_resource_block *mb; + message_resource_entry *me; + uint32_t i; + + pe_get_messagetable(imgbase, &md); + + if (md == NULL) + return(ENOENT); + + mb = (message_resource_block *)((uintptr_t)md + + sizeof(message_resource_data)); + + for (i = 0; i < md->mrd_numblocks; i++) { + if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { + me = (message_resource_entry *)((uintptr_t)md + + mb->mrb_entryoff); + for (i = id - mb->mrb_lowid; i > 0; i--) + me = (message_resource_entry *)((uintptr_t)me + + me->mre_len); + *str = me->mre_text; + *len = me->mre_len; + *flags = me->mre_flags; + return(0); + } + mb++; + } + + return(ENOENT); +} + +/* + * Find the function that matches a particular name. This doesn't + * need to be particularly speedy since it's only run when loading + * a module for the first time. + */ + +static vm_offset_t +pe_functbl_match(functbl, name) + image_patch_table *functbl; + char *name; +{ + image_patch_table *p; + + if (functbl == NULL || name == NULL) + return(0); + + p = functbl; + + while (p->ipt_name != NULL) { + if (!strcmp(p->ipt_name, name)) + return((vm_offset_t)p->ipt_wrap); + p++; + } + printf ("no match for %s\n", name); + + /* + * Return the wrapper pointer for this routine. + * For x86, this is the same as the funcptr. + * For amd64, this points to a wrapper routine + * that does calling convention translation and + * then invokes the underlying routine. + */ + return((vm_offset_t)p->ipt_wrap); +} + +/* + * Patch the imported function addresses for a given module. + * The caller must specify the module name and provide a table + * of function pointers that will be patched into the jump table. + * Note that there are actually two copies of the jump table: one + * copy is left alone. In a .SYS file, the jump tables are usually + * merged into the INIT segment. + */ + +int +pe_patch_imports(imgbase, module, functbl) + vm_offset_t imgbase; + char *module; + image_patch_table *functbl; +{ + image_import_descriptor imp_desc; + char *fname; + vm_offset_t *nptr, *fptr; + vm_offset_t func; + + if (imgbase == 0 || module == NULL || functbl == NULL) + return(EINVAL); + + if (pe_get_import_descriptor(imgbase, &imp_desc, module)) + return(ENOEXEC); + + nptr = (vm_offset_t *)pe_translate_addr(imgbase, + imp_desc.iid_import_name_table_addr); + fptr = (vm_offset_t *)pe_translate_addr(imgbase, + imp_desc.iid_import_address_table_addr); + + while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) { + fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2); + func = pe_functbl_match(functbl, fname); + if (func) + *fptr = func; +#ifdef notdef + if (*fptr == 0) + return(ENOENT); +#endif + nptr++; + fptr++; + } + + return(0); +} diff --git a/sys/compat/ndis/subr_usbd.c b/sys/compat/ndis/subr_usbd.c new file mode 100644 index 000000000000..bba1a5f6e030 --- /dev/null +++ b/sys/compat/ndis/subr_usbd.c @@ -0,0 +1,156 @@ +/*- + * Copyright (c) 2005 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_usbd.c,v 1.1.2.1 2005/03/31 04:24:36 wpaul Exp $"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +static driver_object usbd_driver; + +__stdcall static uint32_t usbd_iodispatch(device_object *, irp *); + +__stdcall static void USBD_GetUSBDIVersion(usbd_version_info *); +__stdcall static void dummy(void); + +int +usbd_libinit(void) +{ + image_patch_table *patch; + + patch = usbd_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap); + patch++; + } + + /* Create a fake USB driver instance. */ + + windrv_bus_attach(&usbd_driver, "USB Bus"); + + /* Set up our dipatch routine. */ + + usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] = + (driver_dispatch)usbd_iodispatch; + + return(0); +} + +int +usbd_libfini(void) +{ + image_patch_table *patch; + + patch = usbd_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + free(usbd_driver.dro_drivername.us_buf, M_DEVBUF); + + return(0); +} + +__stdcall static uint32_t +usbd_iodispatch(dobj, ip) + device_object *dobj; + irp *ip; +{ + return(0); +} + +__stdcall static void +USBD_GetUSBDIVersion(ui) + usbd_version_info *ui; +{ + /* Pretend to be Windows XP. */ + + ui->uvi_usbdi_vers = USBDI_VERSION; + ui->uvi_supported_vers = USB_VER_2_0; + + return; +} + +__stdcall static void +dummy(void) +{ + printf("USBD dummy called\n"); + return; +} + +image_patch_table usbd_functbl[] = { + IMPORT_FUNC(USBD_GetUSBDIVersion), +#ifdef notyet + IMPORT_FUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28, + USBD_ParseConfigurationDescriptorEx), + IMPORT_FUNC_MAP(_USBD_CreateConfigurationRequestEx@8, + USBD_CreateConfigurationRequestEx), +#endif + + /* + * This last entry is a catch-all for any function we haven't + * implemented yet. The PE import list patching routine will + * use it for any function that doesn't have an explicit match + * in this table. + */ + + { NULL, (FUNC)dummy, NULL }, + + /* End of list. */ + + { NULL, NULL, NULL } +}; + diff --git a/sys/compat/ndis/usbd_var.h b/sys/compat/ndis/usbd_var.h new file mode 100644 index 000000000000..f679fb72ec17 --- /dev/null +++ b/sys/compat/ndis/usbd_var.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2003 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/compat/ndis/usbd_var.h,v 1.1.2.1 2005/03/31 04:24:36 wpaul Exp $ + */ + +#ifndef _USBD_VAR_H_ +#define _USBD_VAR_H_ + +#define USBDI_VERSION 0x00000500 +#define USB_VER_1_1 0x00000110 +#define USB_VER_2_0 0x00000200 + +struct usbd_version_info { + uint32_t uvi_usbdi_vers; + uint32_t uvi_supported_vers; +}; + +typedef struct usbd_version_info usbd_version_info; + +extern image_patch_table usbd_functbl[]; + +__BEGIN_DECLS +extern int usbd_libinit(void); +extern int usbd_libfini(void); +__END_DECLS + +#endif /* _USBD_VAR_H_ */ diff --git a/sys/compat/ndis/winx64_wrap.S b/sys/compat/ndis/winx64_wrap.S new file mode 100644 index 000000000000..ac430b12edc2 --- /dev/null +++ b/sys/compat/ndis/winx64_wrap.S @@ -0,0 +1,177 @@ +/*- + * Copyright (c) 2005 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * The x86_64 callback routines were written and graciously submitted + * by Ville-Pertti Keinonen . + * + * $FreeBSD: src/sys/compat/ndis/winx64_wrap.S,v 1.3.2.1 2005/02/18 16:30:09 wpaul Exp $ + */ + +#include + +/* + * Wrapper for handling up to 16 arguments. We can't really + * know how many arguments the caller will pass us. I'm taking an + * educated guess that we'll never get over 16. Handling too + * few arguments is bad. Handling too many is inefficient, but + * not fatal. If someone can think of a way to handle an arbitrary + * number of arguments with more elegant code, freel free to let + * me know. + * + * Standard amd64 calling conventions specify the following registers + * to be used for passing the first 6 arguments: + * + * %rdi, %rsi, %rdx, %rcx, %r8, %r9 + * + * Further arguments are passed on the stack (the 7th argument is + * located immediately after the return address). + * + * Windows x86_64 calling conventions only pass the first 4 + * arguments in registers: + * + * %rcx, %rdx, %r8, %r9 + * + * Even when arguments are passed in registers, the stack must have + * space reserved for those arguments. Thus the 5th argument (the + * first non-register argument) is placed 32 bytes after the return + * address. Additionally, %rdi and %rsi must be preserved. (These + * two registers are not scratch registers in the standard convention.) + * + * Note that in this template, we load a contrived 64 bit address into + * %r11 to represent our jump address. This is to guarantee that the + * assembler leaves enough room to patch in an absolute 64-bit address + * later. The idea behind this code is that we want to avoid having to + * manually create all the wrapper functions at compile time with + * a bunch of macros. This is doable, but a) messy and b) requires + * us to maintain two separate tables (one for the UNIX function + * pointers and another with the wrappers). This means I'd have to + * update two different tables each time I added a function. + * + * To avoid this, we create the wrappers at runtime instead. The + * image patch tables now contain two pointers: one two the normal + * routine, and a blank one for the wrapper. To construct a wrapper, + * we allocate some memory and copy the template function into it, + * then patch the function pointer for the routine we want to wrap + * into the newly created wrapper. The subr_pe module can then + * simply patch the wrapper routine into the jump table into the + * windows image. As a bonus, the wrapper pointer not only serves + * as the wrapper entry point address, it's also a data pointer + * that we can pass to free() later when we unload the module. + */ + + .globl x86_64_wrap_call + .globl x86_64_wrap_end + +ENTRY(x86_64_wrap) + subq $96,%rsp # allocate space on stack + mov %rsi,96-8(%rsp) # save %rsi + mov %rdi,96-16(%rsp)# save %rdi + mov %rcx,%r10 # temporarily save %rcx in scratch + mov %rsp,%rsi + add $96+56,%rsi # source == old stack top (stack+56) + mov %rsp,%rdi # destination == new stack top + mov $10,%rcx # count == 10 quadwords + rep + movsq # copy old stack contents to new location + mov %r10,%rdi # set up arg0 (%rcx -> %rdi) + mov %rdx,%rsi # set up arg1 (%rdx -> %rsi) + mov %r8,%rdx # set up arg2 (%r8 -> %rdx) + mov %r9,%rcx # set up arg3 (%r9 -> %rcx) + mov 96+40(%rsp),%r8 # set up arg4 (stack+40 -> %r8) + mov 96+48(%rsp),%r9 # set up arg5 (stack+48 -> %r9) + xor %rax,%rax # clear return value +x86_64_wrap_call: + mov $0xFF00FF00FF00FF00,%r11 + callq *%r11 # call routine + mov 96-16(%rsp),%rdi# restore %rdi + mov 96-8(%rsp),%rsi # restore %rsi + addq $96,%rsp # delete space on stack + ret +x86_64_wrap_end: + +/* + * Functions for invoking x86_64 callbacks. In each case, the first + * argument is a pointer to the function. + */ + +ENTRY(x86_64_call1) + subq $8,%rsp + mov %rsi,%rcx + call *%rdi + addq $8,%rsp + ret + +ENTRY(x86_64_call2) + subq $24,%rsp + mov %rsi,%rcx + /* %rdx is already correct */ + call *%rdi + addq $24,%rsp + ret + +ENTRY(x86_64_call3) + subq $24,%rsp + mov %rcx,%r8 + mov %rsi,%rcx + call *%rdi + addq $24,%rsp + ret + +ENTRY(x86_64_call4) + subq $40,%rsp + mov %r8,%r9 + mov %rcx,%r8 + mov %rsi,%rcx + call *%rdi + addq $40,%rsp + ret + +ENTRY(x86_64_call5) + subq $40,%rsp + mov %r9,32(%rsp) + mov %r8,%r9 + mov %rcx,%r8 + mov %rsi,%rcx + call *%rdi + addq $40,%rsp + ret + +ENTRY(x86_64_call6) + subq $56,%rsp + mov 56+8(%rsp),%rax + mov %r9,32(%rsp) + mov %rax,40(%rsp) + mov %r8,%r9 + mov %rcx,%r8 + mov %rsi,%rcx + call *%rdi + addq $56,%rsp + ret