diff options
author | Bill Paul <wpaul@FreeBSD.org> | 2003-12-11 22:34:37 +0000 |
---|---|---|
committer | Bill Paul <wpaul@FreeBSD.org> | 2003-12-11 22:34:37 +0000 |
commit | c854fc10923e591ed41cc3f76d240aebdbb3f396 (patch) | |
tree | c45ddc74a90d2271d53841e2eeeace32996042a6 | |
parent | 0d27d14070ce3c94ce7129dfa0788df107eecdfa (diff) |
Notes
-rw-r--r-- | share/man/man4/man4.i386/Makefile | 2 | ||||
-rw-r--r-- | share/man/man4/man4.i386/ndis.4 | 124 | ||||
-rw-r--r-- | sys/compat/ndis/cfg_var.h | 46 | ||||
-rw-r--r-- | sys/compat/ndis/hal_var.h | 40 | ||||
-rw-r--r-- | sys/compat/ndis/kern_ndis.c | 1049 | ||||
-rw-r--r-- | sys/compat/ndis/ndis_var.h | 1174 | ||||
-rw-r--r-- | sys/compat/ndis/ntoskrnl_var.h | 105 | ||||
-rw-r--r-- | sys/compat/ndis/pe_var.h | 330 | ||||
-rw-r--r-- | sys/compat/ndis/resource_var.h | 160 | ||||
-rw-r--r-- | sys/compat/ndis/subr_hal.c | 152 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ndis.c | 1930 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ntoskrnl.c | 497 | ||||
-rw-r--r-- | sys/compat/ndis/subr_pe.c | 537 | ||||
-rw-r--r-- | sys/conf/files.i386 | 6 | ||||
-rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 961 | ||||
-rw-r--r-- | sys/dev/if_ndis/if_ndisvar.h | 121 | ||||
-rw-r--r-- | sys/modules/Makefile | 2 | ||||
-rw-r--r-- | sys/modules/if_ndis/Makefile | 9 | ||||
-rw-r--r-- | sys/modules/ndis/Makefile | 9 |
19 files changed, 7253 insertions, 1 deletions
diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile index f0ea9b954ecf..119d870101e8 100644 --- a/share/man/man4/man4.i386/Makefile +++ b/share/man/man4/man4.i386/Makefile @@ -4,7 +4,7 @@ MAN= aic.4 alpm.4 amdpm.4 apm.4 ar.4 asc.4 \ CPU_ELAN.4 cs.4 cx.4 cy.4 \ el.4 ep.4 ex.4 fe.4 gsc.4 \ ie.4 io.4 le.4 linux.4 lnc.4 longrun.4 mcd.4 \ - mse.4 npx.4 \ + mse.4 ndis.4 npx.4 \ pae.4 pcf.4 perfmon.4 pnp.4 pnpbios.4 \ ray.4 rdp.4 sbni.4 smapi.4 scd.4 \ spkr.4 sr.4 streams.4 svr4.4 \ diff --git a/share/man/man4/man4.i386/ndis.4 b/share/man/man4/man4.i386/ndis.4 new file mode 100644 index 000000000000..8da53e0c7459 --- /dev/null +++ b/share/man/man4/man4.i386/ndis.4 @@ -0,0 +1,124 @@ +.\" Copyright (c) 2003 +.\" Bill Paul <wpaul@windriver.com>. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Bill Paul. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +.\" THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd December 10, 2003 +.Dt NDIS 4 +.Os +.Sh NAME +.Nm ndis +.Nd NDIS miniport driver wrapper +.Sh SYNOPSIS +.Cd "options NDISAPI" +.Cd "device ndis" +.Sh DESCRIPTION +The +.Nm +driver is a wrapper designed to allow binary Windows(r) NDIS miniport +network drivers to be used with +.Fx . +The +.Nm +driver is provided in source code form and must be combined with +the Windows(r) driver supplied with your network adapter. The +.Nm +driver uses the +.Xr ndisapi 9 +kernel subsystem to relocate and link the Windows(r) binary so +that it can be used in conjunction with native code. The +.Xr ndisapi 9 +subsystem provides an interface between the NDIS API and the +.Fx +networking infrastructure. The Windows(r) driver is essentially +fooled into thinking it's running on Windows(r). Note that this +means the +.Nm +driver is only useful on x86 machines. +.Pp +To build a functional driver, the user must have a copy of the +driver distribution media for his or her card. From this distribution, +the user must extract two files: the .SYS file containing the driver +binary code, and its companion .INF file, which contains the +definitions for driver-specific registry keys and other installation +data such as device identifiers. These two files can be converted +into a +.Pa ndis_driver_data.h +file using the +.Xr ndiscvt 8 +utility. This file contains a binary image of the driver plus +registry key data. When the +.Nm +driver loads, it will create +.Xr sysctl 9 +nodes for each registry key extracted from the .INF file. +.Pp +The +.Nm +driver is designed to support mainly ethernet and wireless +network devices with PCI and PCMCIA bus attachments. (Cardbus +devices are also supported as a subset of PCI.) It there can +support many different media types and speeds. One limitation +however, is that there is no consistent way to learn if an +ethernet device is operating in full or half duplex mode. +The NDIS API allows for a generic means for determining link +state and speed, but not the duplex setting. There may be +driver-specific registry keys to control the media setting +which can be configured via the +.Xr sysctl 8 +command. +.Sh DIAGNOSTICS +.Bl -diag +.It "ndis%d: watchdog timeout" +A packet was queued for transmission and a transmit command was +issued, however the device failed to acknowledge the transmission +before a timeout expired. +.El +.Sh SEE ALSO +.Xr arp 4 , +.Xr netintro 4 , +.Xr ng_ether 4 , +.Xr ifconfig 8 , +.Xr ndisapi 9, +.Xr ndiscvt 8 +.Rs +.%T "NDIS 5.1 specification" +.%O http://www.microsoft.com +.Re +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 5.3 . +.Sh AUTHORS +The +.Nm +driver was written by +.An Bill Paul Aq wpaul@windriver.com . diff --git a/sys/compat/ndis/cfg_var.h b/sys/compat/ndis/cfg_var.h new file mode 100644 index 000000000000..831239c54804 --- /dev/null +++ b/sys/compat/ndis/cfg_var.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CFG_VAR_H_ +#define _CFG_VAR_H_ + +struct ndis_cfg { + char *nc_cfgkey; + char *nc_cfgdesc; + char nc_val[256]; +}; + +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..d18ae3e6102f --- /dev/null +++ b/sys/compat/ndis/hal_var.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _HAL_VAR_H_ +#define _HAL_VAR_H_ + +extern image_patch_table hal_functbl[]; + +#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..b36831f17ce1 --- /dev/null +++ b/sys/compat/ndis/kern_ndis.c @@ -0,0 +1,1049 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/callout.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <sys/sysctl.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/conf.h> + +#include <sys/kernel.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <dev/pccard/pccardvar.h> +#include "card_if.h" + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ndis_var.h> +#include <compat/ndis/hal_var.h> +#include <compat/ndis/ntoskrnl_var.h> +#include <compat/ndis/cfg_var.h> +#include <dev/if_ndis/if_ndisvar.h> + +#define __stdcall __attribute__((__stdcall__)) +#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_resetdone_func(ndis_handle, ndis_status, uint8_t); + +/* + * 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) +{ + return(0); +} +DEV_MODULE(ndisapi, ndis_modevent, NULL); +MODULE_VERSION(ndisapi, 1); + + +__stdcall static void +ndis_status_func(adapter, status, sbuf, slen) + ndis_handle adapter; + ndis_status status; + void *sbuf; + uint32_t slen; +{ + printf ("status: %x\n", status); + return; +} + +__stdcall static void +ndis_statusdone_func(adapter) + ndis_handle adapter; +{ + printf ("status complete\n"); + return; +} + +__stdcall static void +ndis_setdone_func(adapter, status) + ndis_handle adapter; + ndis_status status; +{ + printf ("Setup done... %x\n", status); + return; +} + +__stdcall static void +ndis_resetdone_func(adapter, status, addressingreset) + ndis_handle adapter; + ndis_status status; + uint8_t addressingreset; +{ + printf ("reset done...\n"); + return; +} + +#define NDIS_AM_RID 3 + +int +ndis_alloc_amem(arg) + void *arg; +{ + struct ndis_softc *sc; + int error, rid; + + if (arg == NULL) + return(EINVAL); + + sc = arg; + rid = NDIS_AM_RID; + sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, + &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); + + if (sc->ndis_res_am == NULL) { + printf("ndis%d: failed to allocate attribute memory\n", + sc->ndis_unit); + return(ENXIO); + } + + error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), + sc->ndis_dev, rid, 0, NULL); + + if (error) { + printf("ndis%d: CARD_SET_MEMORY_OFFSET() returned 0x%x\n", + sc->ndis_unit, error); + return(error); + } + + error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), + sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); + + if (error) { + printf("ndis%d: CARD_SET_RES_FLAGS() returned 0x%x\n", + sc->ndis_unit, error); + return(error); + } + + return(0); +} + +int +ndis_create_sysctls(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_cfg *vals; + char buf[256]; + + if (arg == NULL) + return(EINVAL); + + sc = arg; + vals = sc->ndis_regvals; + + TAILQ_INIT(&sc->ndis_cfglist_head); + + /* 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)); + + /* Add the driver-specific registry keys. */ + + vals = sc->ndis_regvals; + while(1) { + if (vals->nc_cfgkey == NULL) + break; + SYSCTL_ADD_STRING(&sc->ndis_ctx, + SYSCTL_CHILDREN(sc->ndis_tree), + OID_AUTO, vals->nc_cfgkey, + CTLFLAG_RW, vals->nc_val, + sizeof(vals->nc_val), + vals->nc_cfgdesc); + 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\n", (int)sc->ndis_iftype); + ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); + + if (sc->ndis_res_io != NULL) { + sprintf(buf, "0x%lx\n", 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\n", 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); + + SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), + OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, + cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), + cfg->ndis_cfg.nc_cfgdesc); + + 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); +} + +void +ndis_return_packet(packet, arg) + void *packet; + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_return_handler returnfunc; + + if (arg == NULL || packet == NULL) + return; + + sc = arg; + returnfunc = sc->ndis_chars.nmc_return_packet_func; + adapter = sc->ndis_block.nmb_miniportadapterctx; + if (returnfunc == NULL) + ndis_free_packet((ndis_packet *)packet); + else + returnfunc(adapter, (ndis_packet *)packet); + return; +} + +void +ndis_free_bufs(b0) + ndis_buffer *b0; +{ + ndis_buffer *next; + + if (b0 == NULL) + return; + + while(b0 != NULL) { + next = b0->nb_next; + free (b0, M_DEVBUF); + b0 = next; + } + + return; +} + +void +ndis_free_packet(p) + ndis_packet *p; +{ + if (p == NULL) + return; + + ndis_free_bufs(p->np_private.npp_head); + free(p, M_DEVBUF); + + 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; + + sc = arg; + block = &sc->ndis_block; + + 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; + if (sc->ndis_res_io) { + prd->cprd_type = CmResourceTypePort; + prd->u.cprd_port.cprd_start.np_quad = + rman_get_start(sc->ndis_res_io); + prd->u.cprd_port.cprd_len = + rman_get_size(sc->ndis_res_io); + prd++; + } + + if (sc->ndis_res_mem) { + prd->cprd_type = CmResourceTypeMemory; + prd->u.cprd_mem.cprd_start.np_quad = + rman_get_start(sc->ndis_res_mem); + prd->u.cprd_mem.cprd_len = + rman_get_size(sc->ndis_res_mem); + prd++; + } + + if (sc->ndis_irq) { + prd->cprd_type = CmResourceTypeInterrupt; + prd->u.cprd_intr.cprd_level = + rman_get_start(sc->ndis_irq); + prd->u.cprd_intr.cprd_vector = + rman_get_start(sc->ndis_irq); + prd->u.cprd_intr.cprd_affinity = 0; + } + + block->nmb_rlist = rl; + + return(0); +} + +/* + * 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; + + for (buf = priv->npp_head; buf != NULL; buf = buf->nb_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); + } + + /* + * Note: there's some hackery going on here. We want + * to mate the mbufs to the buffers in the NDIS packet, + * but we don't mark the mbufs with the M_EXT flag to + * indicate external storage. This is because we don't + * want anything special done to free the buffers. + * Depending on the circumstances, the caller may want + * the entire packet to be released, buffers and all, + * by calling ndis_return_packet(), or ndis_free_packet(). + * We leave it up to the caller to do the MEXTADD() to + * set up the free mechanism in the first mbuf of the + * chain. + */ + if (buf->nb_size) + m->m_len = buf->nb_size; + else + m->m_len = buf->nb_bytecount; + m->m_data = buf->nb_mappedsystemva; + 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 mbuf chain from an NDIS packet 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 || m0 == NULL) + return(EINVAL); + + /* If caller didn't supply a packet, make one. */ + if (*p == NULL) { + *p = malloc(sizeof(ndis_packet), M_DEVBUF, M_NOWAIT|M_ZERO); + + if (*p == NULL) + return(ENOMEM); + } + + priv = &(*p)->np_private; + priv->npp_totlen = m0->m_pkthdr.len; + priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); + + for (m = m0; m != NULL; m = m->m_next) { + if (m->m_len == NULL) + continue; + + buf = malloc(sizeof(ndis_buffer), M_DEVBUF, M_NOWAIT|M_ZERO); + if (buf == NULL) { + ndis_free_packet(*p); + *p = NULL; + return(ENOMEM); + } + + buf->nb_bytecount = m->m_len; + buf->nb_mappedsystemva = m->m_data; + if (priv->npp_head == NULL) + priv->npp_head = buf; + else + prev->nb_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; + + sc = arg; + setfunc = sc->ndis_chars.nmc_setinfo_func; + adapter = sc->ndis_block.nmb_miniportadapterctx; + + rval = setfunc(adapter, oid, buf, *buflen, + &byteswritten, &bytesneeded); + + 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_PENDING) + return(EAGAIN); + + return(0); +} + +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; + + sc = arg; + adapter = sc->ndis_block.nmb_miniportadapterctx; + sendfunc = sc->ndis_chars.nmc_sendmulti_func; + sendfunc(adapter, packets, cnt); + + 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); + + sc->ndis_mbufs = malloc(sizeof(struct mbuf) * sc->ndis_maxpkts, + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (sc->ndis_mbufs == NULL) { + free(sc->ndis_tmaps, M_DEVBUF); + 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); + free(sc->ndis_mbufs, M_DEVBUF); + return(ENODEV); + } + } + + return(0); +} + +int +ndis_destroy_dma(arg) + void *arg; +{ + struct ndis_softc *sc; + int i; + + sc = arg; + + for (i = 0; i < sc->ndis_maxpkts; i++) { + if (sc->ndis_mbufs[i] != NULL) + m_freem(sc->ndis_mbufs[i]); + bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); + } + + free(sc->ndis_tmaps, M_DEVBUF); + free(sc->ndis_mbufs, 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; + + sc = arg; + ifp = &sc->arpcom.ac_if; + adapter = sc->ndis_block.nmb_miniportadapterctx; + if (adapter == NULL) + return(EIO); + resetfunc = sc->ndis_chars.nmc_reset_func; + + if (resetfunc == NULL) + return(EINVAL); + + resetfunc(&addressing_reset, adapter); + + 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; + adapter = sc->ndis_block.nmb_miniportadapterctx; + if (adapter == NULL) + return(EIO); + haltfunc = sc->ndis_chars.nmc_halt_func; + + if (haltfunc == NULL) + return(EINVAL); + + haltfunc(adapter); + + /* + * The adapter context is only valid after the init + * handler has been called, and is invalid once the + * halt handler has been called. + */ + + sc->ndis_block.nmb_miniportadapterctx = NULL; + + return(0); +} + +int +ndis_shutdown_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_shutdown_handler shutdownfunc; + + + sc = arg; + adapter = sc->ndis_block.nmb_miniportadapterctx; + if (adapter == NULL) + return(EIO); + shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; + + if (shutdownfunc == NULL) + return(EINVAL); + + shutdownfunc(sc->ndis_chars.nmc_rsvd0); + + 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; + block = &sc->ndis_block; + initfunc = sc->ndis_chars.nmc_init_func; + + for (i = 0; i < NdisMediumMax; i++) + mediumarray[i] = i; + + status = 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) { + bzero((char *)&sc->ndis_chars, + sizeof(ndis_miniport_characteristics)); + 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; + if (adapter == NULL) + return; + intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; + if (intrenbfunc == NULL) + return; + 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; + if (adapter == NULL) + return; + intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; + if (intrdisfunc == NULL) + return; + 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; + isrfunc(&accepted, &queue, adapter); + *ourintr = accepted; + *callhandler = queue; + + return(0); +} + +int +ndis_intrhand(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + __stdcall ndis_interrupt_handler intrfunc; + + if (arg == NULL) + return(EINVAL); + + sc = arg; + adapter = sc->ndis_block.nmb_miniportadapterctx; + intrfunc = sc->ndis_chars.nmc_interrupt_func; + intrfunc(adapter); + + return(0); +} + +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; + + sc = arg; + queryfunc = sc->ndis_chars.nmc_queryinfo_func; + adapter = sc->ndis_block.nmb_miniportadapterctx; + + rval = queryfunc(adapter, oid, buf, *buflen, + &byteswritten, &bytesneeded); + + 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_PENDING) + return(EAGAIN); + + return(0); +} + +int +ndis_unload_driver(arg) + void *arg; +{ + struct ndis_softc *sc; + + sc = arg; + + free(sc->ndis_block.nmb_rlist, M_DEVBUF); + + ndis_flush_sysctls(sc); + ndis_libfini(); + ntoskrnl_libfini(); + + return(0); +} + +int +ndis_load_driver(img, arg) + vm_offset_t img; + void *arg; +{ + __stdcall driver_entry entry; + image_optional_header opt_hdr; + image_import_descriptor imp_desc; + ndis_unicode_string dummystr; + ndis_driver_object drv; + ndis_miniport_block *block; + ndis_status status; + int idx; + uint32_t *ptr; + struct ndis_softc *sc; + + sc = arg; + + /* 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); + } + + /* Initialize subsystems */ + ndis_libinit(); + ntoskrnl_libinit(); + + /* Locate the driver entry point */ + pe_get_optional_header(img, &opt_hdr); + entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); + + /* + * Now call the DriverEntry() routine. This will cause + * a callout to the NdisInitializeWrapper() and + * NdisMRegisterMiniport() routines. + */ + dummystr.nus_len = strlen(NDIS_DUMMY_PATH); + dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH); + dummystr.nus_buf = NULL; + ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); + drv.ndo_ifname = "ndis0"; + + status = entry(&drv, &dummystr); + + free (dummystr.nus_buf, M_DEVBUF); + + if (status != NDIS_STATUS_SUCCESS) + return(ENODEV); + + /* + * Now that we have the miniport driver characteristics, + * create an NDIS block and call the init handler. + * This will cause the driver to try to probe for + * a device. + */ + + block = &sc->ndis_block; + bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars, + sizeof(ndis_miniport_characteristics)); + + /*block->nmb_signature = 0xcafebabe;*/ + + ptr = (uint32_t *)block; + for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { + *ptr = idx | 0xdead0000; + ptr++; + } + + block->nmb_signature = (void *)0xcafebabe; + block->nmb_setdone_func = ndis_setdone_func; + block->nmb_status_func = ndis_status_func; + block->nmb_statusdone_func = ndis_statusdone_func; + block->nmb_resetdone_func = ndis_resetdone_func; + + block->nmb_ifp = &sc->arpcom.ac_if; + block->nmb_dev = sc->ndis_dev; + + return(0); +} diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h new file mode 100644 index 000000000000..78bcfd2c9b7e --- /dev/null +++ b/sys/compat/ndis/ndis_var.h @@ -0,0 +1,1174 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#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 uint32_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_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_RELOAD_DEFAULTS 0x0D01011C + +/* structures/definitions for 802.11 */ +#define NDIS_80211_NETTYPE_11FH 0x00000000 +#define NDIS_80211_NETTYPE_11DS 0x00000001 + +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; + uint32_t nw_keydata[1]; +}; + +typedef struct ndis_80211_wep ndis_80211_wep; + +#define NDIS_80211_NET_INFRA_BSS 0x00000000 +#define NDIS_80211_NET_INFRA_IBSS 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 + +typedef uint8_t ndis_80211_rates[8]; +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; + +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_DISABLED 0x00000001 +#define NDIS_80211_WEPSTAT_KEYABSENT 0x00000002 +#define NDIS_80211_WEPSTAT_NOTSUPPORTED 0x00000003 + +#define NDIS_80211_RELOADDEFAULT_WEP 0x00000000 + +/* + * 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 + +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 { + uint64_t np_quad; +#ifdef notdef + uint32_t np_low; + uint32_t np_high; +#endif +}; + +typedef struct ndis_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; + +/* + * 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; + + +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; + +struct ndis_list_entry { + struct ndis_list_entry *nle_flink; + struct ndis_list_entry *nle_blink; +}; + +typedef struct ndis_list_entry ndis_list_entry; + +struct ndis_bind_paths { + uint32_t nbp_number; + ndis_unicode_string nbp_paths[1]; +}; + +typedef struct ndis_bind_paths ndis_bind_paths; + +struct dispatch_header { + uint8_t dh_type; + uint8_t dh_abs; + uint8_t dh_size; + uint8_t dh_inserted; + uint32_t dh_sigstate; + ndis_list_entry dh_waitlisthead; +}; + +struct ndis_ktimer { + struct dispatch_header nk_header; + uint64_t nk_duetime; + ndis_list_entry nk_timerlistentry; + void *nk_dpc; + uint32_t nk_period; +}; + +struct ndis_kevent { + struct dispatch_header nk_header; +}; + +struct ndis_event { + struct ndis_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; + ndis_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 ndis_ktimer nt_timer; + struct ndis_kdpc nt_dpc; +}; + +typedef struct ndis_timer ndis_timer; + +typedef void (*ndis_timer_function)(void *, void *, void *, void *); + +struct ndis_miniport_timer { + struct ndis_ktimer nmt_ktimer; + struct ndis_kdpc nmt_dpc; + ndis_timer_function nmt_timerfunc; + void *nmt_timerctx; + 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_spin_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_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; + +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 +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; + +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_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 { + struct { + uint8_t np_miniport_rsvd[2 * sizeof(void *)]; + uint8_t np_wrapper_rsvd[2 * sizeof(void *)]; + } np_rsvd; + struct { + uint8_t np_miniport_rsvdex[3 * sizeof(void *)]; + uint8_t np_wrapper_rsvdex[sizeof(void *)]; + } np_rsvdrx; + struct { + uint8_t np_mac_rsvd[4 * sizeof(void *)]; + } np_macrsvd; + } u; + uint32_t *np_rsvd[2]; + uint8_t np_proto_rsvd[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; +}; + +typedef struct ndis_packet ndis_packet; + +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; + +/* + * 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; + ndis_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_bustye; + uint32_t nmb_adaptertype; + void *nmb_deviceobj; + void *nmb_physdeviceobj; + void *nmb_nextdeviceobj; + 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]; + ndis_config_parm nmb_replyparm; + int nmb_pciidx; + device_t nmb_dev; + ndis_resource_list *nmb_rlist; +}; + +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 void (*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 ndis_status (*driver_entry)(void *, ndis_unicode_string *); + +extern image_patch_table ndis_functbl[]; + +__BEGIN_DECLS +extern int ndis_libinit(void); +extern int ndis_libfini(void); +extern int ndis_ascii_to_unicode(char *, uint16_t **); +extern int ndis_unicode_to_ascii(uint16_t *, int, char **); +extern int ndis_load_driver(vm_offset_t, void *); +extern int ndis_unload_driver(void *); +extern int ndis_mtop(struct mbuf *, ndis_packet **); +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_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 int ndis_intrhand(void *); +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 *); +__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..236d6fd3610c --- /dev/null +++ b/sys/compat/ndis/ntoskrnl_var.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _NTOSKRNL_VAR_H_ +#define _NTOSKRNL_VAR_H_ + +typedef uint32_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 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; + 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; + kspin_lock nll_obsoletelock; +}; + +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 *); + + +extern image_patch_table ntoskrnl_functbl[]; + +__BEGIN_DECLS +extern int ntoskrnl_libinit(void); +extern int ntoskrnl_libfini(void); +__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..a0a2cc9a535d --- /dev/null +++ b/sys/compat/ndis/pe_var.h @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#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; + uint32_t ioh_databaseaddr; + + /* NT-specific fields */ + + uint32_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; + uint32_t ioh_stackreservesize; + uint32_t ioh_stackcommitsize; + uint32_t ioh_heapreservesize; + uint32_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 + +/* + * 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; + u_int8_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_patch_table { + char *ipt_name; + void (*ipt_func)(void); +}; + +typedef struct image_patch_table image_patch_table; + +__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, uint32_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 *); +__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..079193bf351c --- /dev/null +++ b/sys/compat/ndis/resource_var.h @@ -0,0 +1,160 @@ + +/* + * $FreeBSD$ + */ + +typedef int cm_resource_type; + +struct physaddr { + uint64_t np_quad; +}; + +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; + 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; +}; + +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; diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c new file mode 100644 index 000000000000..442b7ef47de1 --- /dev/null +++ b/sys/compat/ndis/subr_hal.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> + +#include <sys/callout.h> +#include <sys/kernel.h> + +#include <sys/systm.h> +#include <machine/clock.h> +#include <machine/bus_memio.h> +#include <machine/bus_pio.h> +#include <machine/bus.h> + +#include <sys/bus.h> +#include <sys/rman.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/hal_var.h> + +#define __stdcall __attribute__((__stdcall__)) +#define FUNC void(*)(void) + +__stdcall static void hal_stall_exec_cpu(uint32_t); +__stdcall static void hal_writeport_ulong(uint32_t *, uint32_t); +__stdcall static void hal_writeport_ushort(uint16_t *, uint16_t); +__stdcall static void hal_writeport_uchar(uint8_t *, uint8_t); +__stdcall static uint32_t hal_readport_ulong(uint32_t *); +__stdcall static uint16_t hal_readport_ushort(uint16_t *); +__stdcall static uint8_t hal_readport_uchar(uint8_t *); +__stdcall static void dummy (void); + +__stdcall static void +hal_stall_exec_cpu(usecs) + uint32_t usecs; +{ + DELAY(usecs); + return; +} + +__stdcall static void +hal_writeport_ulong(port, val) + uint32_t *port; + uint32_t val; +{ + bus_space_write_4(I386_BUS_SPACE_IO, 0x0, (uint32_t)port, val); + return; +} + +__stdcall static void +hal_writeport_ushort(port, val) + uint16_t *port; + uint16_t val; +{ + bus_space_write_2(I386_BUS_SPACE_IO, 0x0, (uint32_t)port, val); + return; +} + +__stdcall static void +hal_writeport_uchar(port, val) + uint8_t *port; + uint8_t val; +{ + bus_space_write_1(I386_BUS_SPACE_IO, 0x0, (uint32_t)port, val); + return; +} + +__stdcall static uint16_t +hal_readport_ushort(port) + uint16_t *port; +{ + return(bus_space_read_2(I386_BUS_SPACE_IO, 0x0, (uint32_t)port)); +} + +__stdcall static uint32_t +hal_readport_ulong(port) + uint32_t *port; +{ + return(bus_space_read_4(I386_BUS_SPACE_IO, 0x0, (uint32_t)port)); +} + +__stdcall static uint8_t +hal_readport_uchar(port) + uint8_t *port; +{ + return(bus_space_read_1(I386_BUS_SPACE_IO, 0x0, (uint32_t)port)); +} + +__stdcall +static void dummy() +{ + printf ("hal dummy called...\n"); + return; +} + + +image_patch_table hal_functbl[] = { + { "KeStallExecutionProcessor", (FUNC)hal_stall_exec_cpu }, + { "WRITE_PORT_ULONG", (FUNC)hal_writeport_ulong }, + { "WRITE_PORT_USHORT", (FUNC)hal_writeport_ushort }, + { "WRITE_PORT_UCHAR", (FUNC)hal_writeport_uchar }, + { "READ_PORT_ULONG", (FUNC)hal_readport_ulong }, + { "READ_PORT_USHORT", (FUNC)hal_readport_ushort }, + { "READ_PORT_UCHAR", (FUNC)hal_readport_uchar }, + + /* + * 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 }, + + /* End of list. */ + + { NULL, NULL }, +}; diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c new file mode 100644 index 000000000000..f45b6029cfd5 --- /dev/null +++ b/sys/compat/ndis/subr_ndis.c @@ -0,0 +1,1930 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * 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 <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> + +#include <sys/callout.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/socket.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <machine/bus_memio.h> +#include <machine/bus_pio.h> +#include <machine/bus.h> +#include <machine/resource.h> + +#include <sys/bus.h> +#include <sys/rman.h> + +#include <machine/stdarg.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ndis_var.h> +#include <compat/ndis/cfg_var.h> +#include <dev/if_ndis/if_ndisvar.h> + +#define __stdcall __attribute__((__stdcall__)) +#define FUNC void(*)(void) + +static struct mtx ndis_interlock; +static int ndis_inits = 0; + +__stdcall static void ndis_initwrap(ndis_handle, + ndis_driver_object *, void *, void *); +__stdcall static ndis_status ndis_register_miniport(ndis_handle, + ndis_miniport_characteristics *, int); +__stdcall static ndis_status ndis_malloc_withtag(void **, uint32_t, uint32_t); +__stdcall static ndis_status ndis_malloc(void **, + uint32_t, uint32_t, ndis_physaddr); +__stdcall static void ndis_free(void *, uint32_t, uint32_t); +__stdcall static ndis_status ndis_setattr_ex(ndis_handle, ndis_handle, + uint32_t, uint32_t, ndis_interface_type); +__stdcall static void ndis_open_cfg(ndis_status *, ndis_handle *, ndis_handle); +static ndis_status ndis_encode_parm(ndis_miniport_block *, + struct sysctl_oid *, ndis_parm_type, ndis_config_parm **); +__stdcall static void ndis_read_cfg(ndis_status *, ndis_config_parm **, + ndis_handle, ndis_unicode_string *, ndis_parm_type); +__stdcall static void ndis_close_cfg(ndis_handle); +__stdcall static void ndis_create_lock(ndis_spin_lock *); +__stdcall static void ndis_destroy_lock(ndis_spin_lock *); +__stdcall static void ndis_lock(ndis_spin_lock *); +__stdcall static void ndis_unlock(ndis_spin_lock *); +__stdcall static uint32_t ndis_read_pci(ndis_handle, uint32_t, + uint32_t, void *, uint32_t); +__stdcall static uint32_t ndis_write_pci(ndis_handle, uint32_t, + uint32_t, void *, uint32_t); +static void ndis_syslog(ndis_handle, ndis_error_code, uint32_t, ...); +static void ndis_map_cb(void *, bus_dma_segment_t *, int, int); +__stdcall static void ndis_vtophys_load(ndis_handle, ndis_buffer *, + uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *); +__stdcall static void ndis_vtophys_unload(ndis_handle, ndis_buffer *, uint32_t); +__stdcall static void ndis_create_timer(ndis_miniport_timer *, ndis_handle *, + ndis_timer_function, void *); +static void ndis_timercall(void *); +__stdcall static void ndis_set_timer(ndis_miniport_timer *, uint32_t); +static void ndis_tick(void *); +__stdcall static void ndis_set_periodic_timer(ndis_miniport_timer *, uint32_t); +__stdcall static void ndis_cancel_timer(ndis_miniport_timer *, uint8_t *); +__stdcall static void ndis_query_resources(ndis_status *, ndis_handle, + ndis_resource_list *, uint32_t *); +__stdcall static ndis_status ndis_register_ioport(void **, + ndis_handle, uint32_t, uint32_t); +__stdcall static void ndis_deregister_ioport(ndis_handle, + uint32_t, uint32_t, void *); +__stdcall static void ndis_read_netaddr(ndis_status *, void **, + uint32_t *, ndis_handle); +__stdcall static ndis_status ndis_alloc_mapreg(ndis_handle, + uint32_t, uint8_t, uint32_t, uint32_t); +__stdcall static void ndis_free_mapreg(ndis_handle); +static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int); +__stdcall static void ndis_alloc_sharedmem(ndis_handle, uint32_t, + uint8_t, void **, ndis_physaddr *); +__stdcall static void ndis_alloc_sharedmem_async(ndis_handle, + uint32_t, uint8_t, void *); +__stdcall static void ndis_free_sharedmem(ndis_handle, uint32_t, + uint8_t, void *, ndis_physaddr); +__stdcall static ndis_status ndis_map_iospace(void **, ndis_handle, + ndis_physaddr, uint32_t); +__stdcall static void ndis_unmap_iospace(ndis_handle, void *, uint32_t); +__stdcall static uint32_t ndis_cachefill(void); +__stdcall static uint32_t ndis_dma_align(ndis_handle); +__stdcall static ndis_status ndis_init_sc_dma(ndis_handle, + uint8_t, uint32_t); +__stdcall static void ndis_alloc_packetpool(ndis_status *, + ndis_handle *, uint32_t, uint32_t); +__stdcall static void ndis_ex_alloc_packetpool(ndis_status *, + ndis_handle *, uint32_t, uint32_t, uint32_t); +__stdcall static uint32_t ndis_packetpool_use(ndis_handle); +__stdcall static void ndis_free_packetpool(ndis_handle); +__stdcall static void ndis_alloc_packet(ndis_status *, + ndis_packet **, ndis_handle); +__stdcall static void ndis_release_packet(ndis_packet *); +__stdcall static void ndis_unchain_headbuf(ndis_packet *, ndis_buffer **); +__stdcall static void ndis_alloc_bufpool(ndis_status *, + ndis_handle *, uint32_t); +__stdcall static void ndis_free_bufpool(ndis_handle); +__stdcall static void ndis_alloc_buf(ndis_status *, ndis_buffer **, + ndis_handle, void *, uint32_t); +__stdcall static void ndis_release_buf(ndis_buffer *); +__stdcall static void ndis_query_buf(ndis_buffer *, void **, uint32_t *); +__stdcall static void ndis_query_buf_safe(ndis_buffer *, void **, + uint32_t *, uint32_t); +__stdcall static void ndis_adjust_buflen(ndis_buffer *, int); +__stdcall static uint32_t ndis_interlock_inc(uint32_t *); +__stdcall static uint32_t ndis_interlock_dec(uint32_t *); +__stdcall static void ndis_init_event(ndis_event *); +__stdcall static void ndis_set_event(ndis_event *); +__stdcall static void ndis_reset_event(ndis_event *); +__stdcall static uint8_t ndis_wait_event(ndis_event *, uint32_t); +__stdcall static ndis_status ndis_unicode2ansi(ndis_ansi_string *, + ndis_unicode_string *); +__stdcall static ndis_status ndis_assign_pcirsrc(ndis_handle, + uint32_t, ndis_resource_list **); +__stdcall static ndis_status ndis_register_intr(ndis_miniport_interrupt *, + ndis_handle, uint32_t, uint32_t, uint8_t, + uint8_t, ndis_interrupt_mode); +__stdcall static void ndis_deregister_intr(ndis_miniport_interrupt *); +__stdcall static void ndis_register_shutdown(ndis_handle, void *, + ndis_shutdown_handler); +__stdcall static void ndis_deregister_shutdown(ndis_handle); +__stdcall static uint32_t ndis_numpages(ndis_buffer *); +__stdcall static void ndis_query_bufoffset(ndis_buffer *, + uint32_t *, uint32_t *); +__stdcall static void ndis_sleep(uint32_t); +__stdcall static uint32_t ndis_read_pccard_amem(ndis_handle, + uint32_t, void *, uint32_t); +__stdcall static uint32_t ndis_write_pccard_amem(ndis_handle, + uint32_t, void *, uint32_t); +__stdcall static ndis_list_entry *ndis_insert_head(ndis_list_entry *, + ndis_list_entry *, ndis_spin_lock *); +__stdcall static ndis_list_entry *ndis_remove_head(ndis_list_entry *, + ndis_spin_lock *); +__stdcall static ndis_list_entry *ndis_insert_tail(ndis_list_entry *, + ndis_list_entry *, ndis_spin_lock *); +__stdcall static uint8_t ndis_sync_with_intr(ndis_miniport_interrupt *, + void *, void *); +__stdcall static void dummy(void); + + +int +ndis_libinit() +{ + if (ndis_inits) { + ndis_inits++; + return(0); + } + + mtx_init(&ndis_interlock, "ndislock", MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE | MTX_DUPOK); + + ndis_inits++; + return(0); +} + +int +ndis_libfini() +{ + if (ndis_inits != 1) { + ndis_inits--; + return(0); + } + + mtx_destroy(&ndis_interlock); + ndis_inits--; + + return(0); +} + +/* + * 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_WAITOK); + + 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, M_DEVBUF, M_WAITOK); + + if (*ascii == NULL) + return(ENOMEM); + astr = *ascii; + for (i = 0; i < ulen; i++) { + *astr = (uint8_t)unicode[i]; + astr++; + } + + return(0); +} + +__stdcall static void +ndis_initwrap(wrapper, drv_obj, path, unused) + ndis_handle wrapper; + ndis_driver_object *drv_obj; + void *path; + void *unused; +{ + ndis_driver_object **drv; + + drv = wrapper; + *drv = drv_obj; + + return; +} + +__stdcall static ndis_status +ndis_register_miniport(handle, characteristics, len) + ndis_handle handle; + ndis_miniport_characteristics *characteristics; + int len; +{ + ndis_driver_object *drv; + + drv = handle; + bcopy((char *)characteristics, (char *)&drv->ndo_chars, + sizeof(ndis_miniport_characteristics)); + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +ndis_malloc_withtag(vaddr, len, tag) + void **vaddr; + uint32_t len; + uint32_t tag; +{ + void *mem; + + mem = malloc(len, M_DEVBUF, M_NOWAIT); + if (mem == NULL) + return(NDIS_STATUS_RESOURCES); + *vaddr = mem; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +ndis_malloc(vaddr, len, flags, highaddr) + void **vaddr; + uint32_t len; + uint32_t flags; + ndis_physaddr highaddr; +{ + void *mem; + + mem = malloc(len, M_DEVBUF, M_NOWAIT); + if (mem == NULL) + return(NDIS_STATUS_RESOURCES); + *vaddr = mem; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +ndis_free(vaddr, len, flags) + void *vaddr; + uint32_t len; + uint32_t flags; +{ + if (len == 0) + return; + free(vaddr, M_DEVBUF); + return; +} + +__stdcall static ndis_status +ndis_setattr_ex(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; + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +ndis_open_cfg(status, cfg, wrapctx) + ndis_status *status; + ndis_handle *cfg; + ndis_handle wrapctx; +{ + *cfg = wrapctx; + *status = NDIS_STATUS_SUCCESS; + 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; + + 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->nus_len = strlen((char *)oid->oid_arg1) * 2; + ustr->nus_buf = unicode; + break; + case ndis_parm_int: + (*parm)->ncp_type = ndis_parm_int; + (*parm)->ncp_parmdata.ncp_intdata = + strtol((char *)oid->oid_arg1, NULL, 10); + break; + case ndis_parm_hexint: + (*parm)->ncp_type = ndis_parm_hexint; + (*parm)->ncp_parmdata.ncp_intdata = + strtoul((char *)oid->oid_arg1, NULL, 16); + break; + default: + return(NDIS_STATUS_FAILURE); + break; + } + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +ndis_read_cfg(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 = (struct ndis_softc *)block->nmb_ifp; + + ndis_unicode_to_ascii(key->nus_buf, key->nus_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. + */ + TAILQ_FOREACH(e, &sc->ndis_ctx, link) { + oidp = e->entry; + if (strcmp(oidp->oid_name, keystr) == 0) { + *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, NULL, "0", CTLFLAG_RW); + else + ndis_add_sysctl(sc, keystr, NULL, "", CTLFLAG_RW); + + free(keystr, M_DEVBUF); + *status = NDIS_STATUS_FAILURE; + return; +} + +__stdcall static void +ndis_close_cfg(cfg) + ndis_handle cfg; +{ + return; +} + +__stdcall static void +ndis_create_lock(lock) + ndis_spin_lock *lock; +{ + struct mtx *mtx; + + mtx = malloc(sizeof(struct mtx), M_DEVBUF, M_NOWAIT|M_ZERO); + if (mtx == NULL) + return; + mtx_init(mtx, "ndislock", MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE | MTX_DUPOK); + lock->nsl_spinlock = (ndis_kspin_lock)mtx; + + return; +} + +__stdcall static void +ndis_destroy_lock(lock) + ndis_spin_lock *lock; +{ + struct mtx *ndis_mtx; + + ndis_mtx = (struct mtx *)lock->nsl_spinlock; + mtx_destroy(ndis_mtx); + free(ndis_mtx, M_DEVBUF); + + return; +} + +__stdcall static void +ndis_lock(lock) + ndis_spin_lock *lock; +{ + if (lock == NULL) + return; + mtx_lock((struct mtx *)lock->nsl_spinlock); + + return; +} + +__stdcall static void +ndis_unlock(lock) + ndis_spin_lock *lock; +{ + if (lock == NULL) + return; + mtx_unlock((struct mtx *)lock->nsl_spinlock); + + return; +} + +__stdcall static uint32_t +ndis_read_pci(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; + + block = (ndis_miniport_block *)adapter; + dest = buf; + if (block == NULL || block->nmb_dev == NULL) + return(0); + + for (i = 0; i < len; i++) + dest[i] = pci_read_config(block->nmb_dev, i + offset, 1); + + return(len); +} + +__stdcall static uint32_t +ndis_write_pci(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; + + block = (ndis_miniport_block *)adapter; + dest = buf; + + if (block == NULL || block->nmb_dev == NULL) + return(0); + + for (i = 0; i < len; i++) + pci_write_config(block->nmb_dev, i + offset, dest[i], 1); + + return(len); +} + +/* + * The errorlog routine uses a variable argument list, so we + * have to declare it this way. + */ +static void +ndis_syslog(ndis_handle adapter, ndis_error_code code, + uint32_t numerrors, ...) +{ + ndis_miniport_block *block; + va_list ap; + int i; + + block = (ndis_miniport_block *)adapter; + + printf ("NDIS ERROR: %x\n", code); + printf ("NDIS NUMERRORS: %x\n", numerrors); + + va_start(ap, numerrors); + for (i = 0; i < numerrors; i++) + printf ("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 +ndis_vtophys_load(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 = (struct ndis_softc *)(block->nmb_ifp); + + if (mapreg > sc->ndis_mmapcnt) + return; + + map = sc->ndis_mmaps[mapreg]; + nma.nma_fraglist = addrarray; + + error = bus_dmamap_load(sc->ndis_mtag, map, + buf->nb_mappedsystemva, buf->nb_bytecount, 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 +ndis_vtophys_unload(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 = (struct ndis_softc *)(block->nmb_ifp); + + 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; +} + +__stdcall static void +ndis_create_timer(timer, handle, func, ctx) + ndis_miniport_timer *timer; + ndis_handle *handle; + ndis_timer_function func; + void *ctx; +{ + struct callout_handle *ch; + + ch = (struct callout_handle *)&timer->nmt_dpc; + callout_handle_init(ch); + timer->nmt_timerfunc = func; + timer->nmt_timerctx = ctx; + + return; +} + +/* + * The driver's timer callout is __stdcall function, so we need this + * intermediate step. + */ + +static void +ndis_timercall(arg) + void *arg; +{ + ndis_miniport_timer *timer; + __stdcall ndis_timer_function timerfunc; + + timer = arg; + + timerfunc = timer->nmt_timerfunc; + timerfunc(NULL, timer->nmt_timerctx, NULL, NULL); + + return; +} + +/* + * Windows specifies timeouts in milliseconds. We specify timeouts + * in hz. Trying to compute a tenth of a second based on hz is tricky. + * so we approximate. Note that we abuse the dpc portion of the + * miniport timer structure to hold the UNIX callout handle. + */ +__stdcall static void +ndis_set_timer(timer, msecs) + ndis_miniport_timer *timer; + uint32_t msecs; +{ + struct callout_handle *ch; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = msecs * 1000; + + ch = (struct callout_handle *)&timer->nmt_dpc; + timer->nmt_dpc.nk_sysarg2 = ndis_timercall; + *ch = timeout((timeout_t *)timer->nmt_dpc.nk_sysarg2, (void *)timer, + tvtohz(&tv)); + + return; +} + +static void +ndis_tick(arg) + void *arg; +{ + ndis_miniport_timer *timer; + struct callout_handle *ch; + __stdcall ndis_timer_function timerfunc; + struct timeval tv; + + timer = arg; + + timerfunc = timer->nmt_timerfunc; + timerfunc(NULL, timer->nmt_timerctx, NULL, NULL); + + /* Automatically reload timer. */ + + tv.tv_sec = 0; + tv.tv_usec = timer->nmt_ktimer.nk_period * 1000; + ch = (struct callout_handle *)&timer->nmt_dpc; + timer->nmt_dpc.nk_sysarg2 = ndis_tick; + *ch = timeout((timeout_t *)timer->nmt_dpc.nk_sysarg2, timer, + tvtohz(&tv)); + + return; +} + +__stdcall static void +ndis_set_periodic_timer(timer, msecs) + ndis_miniport_timer *timer; + uint32_t msecs; +{ + struct callout_handle *ch; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = msecs * 1000; + + timer->nmt_ktimer.nk_period = msecs; + ch = (struct callout_handle *)&timer->nmt_dpc; + timer->nmt_dpc.nk_sysarg2 = ndis_tick; + *ch = timeout((timeout_t *)timer->nmt_dpc.nk_sysarg2, timer, + tvtohz(&tv)); + + return; +} + +__stdcall static void +ndis_cancel_timer(timer, cancelled) + ndis_miniport_timer *timer; + uint8_t *cancelled; +{ + struct callout_handle *ch; + + ch = (struct callout_handle *)&timer->nmt_dpc; + untimeout((timeout_t *)timer->nmt_dpc.nk_sysarg2, timer, *ch); + + return; +} + +__stdcall static void +ndis_query_resources(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; + + block = (ndis_miniport_block *)adapter; + sc = (struct ndis_softc *)block->nmb_ifp; + + *buflen = sizeof(ndis_resource_list) + + (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)); + + bcopy((char *)block->nmb_rlist, (char *)list, *buflen); + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall static ndis_status +ndis_register_ioport(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 = (struct ndis_softc *)(block->nmb_ifp); + + if (sc->ndis_res_io == NULL) + return(NDIS_STATUS_FAILURE); + + 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 +ndis_deregister_ioport(adapter, port, numports, offset) + ndis_handle adapter; + uint32_t port; + uint32_t numports; + void *offset; +{ + return; +} + +__stdcall static void +ndis_read_netaddr(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 = (struct ndis_softc *)block->nmb_ifp; + + 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 +ndis_alloc_mapreg(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 = (struct ndis_softc *)block->nmb_ifp; + + 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 +ndis_free_mapreg(adapter) + ndis_handle adapter; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + int i; + + block = (ndis_miniport_block *)adapter; + sc = (struct ndis_softc *)block->nmb_ifp; + + 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 +ndis_alloc_sharedmem(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 = (struct ndis_softc *)(block->nmb_ifp); + + sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO); + if (sh == NULL) + return; + + error = bus_dma_tag_create(sc->ndis_parent_tag, 64, + 0, BUS_SPACE_MAXADDR_32BIT, 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; +} + +__stdcall static void +ndis_alloc_sharedmem_async(adapter, len, cached, ctx) + ndis_handle adapter; + uint32_t len; + uint8_t cached; + void *ctx; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + void *vaddr; + ndis_physaddr paddr; + __stdcall ndis_allocdone_handler donefunc; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = (struct ndis_softc *)(block->nmb_ifp); + donefunc = sc->ndis_chars.nmc_allocate_complete_func; + + ndis_alloc_sharedmem(adapter, len, cached, &vaddr, &paddr); + donefunc(adapter, vaddr, &paddr, len, ctx); + + return; +} + +__stdcall static void +ndis_free_sharedmem(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 = (struct ndis_softc *)(block->nmb_ifp); + sh = prev = sc->ndis_shlist; + + 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 +ndis_map_iospace(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 = (struct ndis_softc *)(block->nmb_ifp); + + if (sc->ndis_res_mem == NULL) + return(NDIS_STATUS_FAILURE); + + *vaddr = (void *)rman_get_virtual(sc->ndis_res_mem); + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +ndis_unmap_iospace(adapter, vaddr, len) + ndis_handle adapter; + void *vaddr; + uint32_t len; +{ + return; +} + +__stdcall static uint32_t +ndis_cachefill(void) +{ + return(128); +} + +__stdcall static uint32_t +ndis_dma_align(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 +ndis_init_sc_dma(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 = (struct ndis_softc *)block->nmb_ifp; + + /* 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 static void +ndis_alloc_packetpool(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) * (descnum + 1), + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (pool == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + cur = (ndis_packet *)*pool; + cur->np_private.npp_flags = 0x1; /* mark the head of the list */ + for (i = 0; i < descnum; i++) { + cur->np_private.npp_head = (ndis_handle)(cur + 1); + cur++; + } + + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall static void +ndis_ex_alloc_packetpool(status, pool, descnum, oflowdescnum, protrsvdlen) + ndis_status *status; + ndis_handle *pool; + uint32_t descnum; + uint32_t oflowdescnum; + uint32_t protrsvdlen; +{ + return(ndis_alloc_packetpool(status, pool, + descnum + oflowdescnum, protrsvdlen)); +} + +__stdcall static uint32_t +ndis_packetpool_use(pool) + ndis_handle pool; +{ + ndis_packet *head; + + head = (ndis_packet *)pool; + + return(head->np_private.npp_count); +} + +__stdcall static void +ndis_free_packetpool(pool) + ndis_handle pool; +{ + free(pool, M_DEVBUF); + return; +} + +__stdcall static void +ndis_alloc_packet(status, packet, pool) + ndis_status *status; + ndis_packet **packet; + ndis_handle pool; +{ + ndis_packet *head, *pkt; + + head = (ndis_packet *)pool; + + if (head->np_private.npp_flags != 0x1) { + *status = NDIS_STATUS_FAILURE; + return; + } + + pkt = (ndis_packet *)head->np_private.npp_head; + + if (pkt == NULL) { + *status = NDIS_STATUS_RESOURCES; + 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); + + *packet = pkt; + + head->np_private.npp_count++; + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall static void +ndis_release_packet(packet) + ndis_packet *packet; +{ + ndis_packet *head; + + if (packet == NULL || packet->np_private.npp_pool == NULL) + return; + + head = packet->np_private.npp_pool; + if (head->np_private.npp_flags != 0x1) + return; + + packet->np_private.npp_head = head->np_private.npp_head; + head->np_private.npp_head = (ndis_buffer *)packet; + head->np_private.npp_count--; + + return; +} + +__stdcall static void +ndis_unchain_headbuf(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)->nb_next; + } + + return; +} + +/* + * The NDIS "buffer" manipulation functions are somewhat misnamed. + * They don't really allocate buffers: they allocate buffer mappings. + * The idea is you reserve a chunk of DMA-able memory using + * NdisMAllocateSharedMemory() and then use NdisAllocateBuffer() + * to obtain the virtual address of the DMA-able region. + * ndis_alloc_bufpool() is analagous to bus_dma_tag_create(). + */ + +__stdcall static void +ndis_alloc_bufpool(status, pool, descnum) + ndis_status *status; + ndis_handle *pool; + uint32_t descnum; +{ + ndis_buffer *cur; + int i; + + *pool = malloc(sizeof(ndis_buffer) * (descnum + 1), + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (pool == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + cur = (ndis_buffer *)*pool; + cur->nb_flags = 0x1; /* mark the head of the list */ + for (i = 0; i < descnum; i++) { + cur->nb_next = cur + 1; + cur++; + } + + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall static void +ndis_free_bufpool(pool) + ndis_handle pool; +{ + free(pool, M_DEVBUF); + return; +} + +/* + * This maps to a bus_dmamap_create() and bus_dmamap_load(). + */ +__stdcall static void +ndis_alloc_buf(status, buffer, pool, vaddr, len) + ndis_status *status; + ndis_buffer **buffer; + ndis_handle pool; + void *vaddr; + uint32_t len; +{ + ndis_buffer *head, *buf; + + head = (ndis_buffer *)pool; + if (head->nb_flags != 0x1) { + *status = NDIS_STATUS_FAILURE; + return; + } + + buf = head->nb_next; + + if (buf == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + head->nb_next = buf->nb_next; + + /* Save pointer to the pool. */ + buf->nb_process = head; + + buf->nb_mappedsystemva = vaddr; + buf->nb_size = len; + buf->nb_next = NULL; + + *buffer = buf; + + *status = NDIS_STATUS_SUCCESS; + return; +} + +__stdcall static void +ndis_release_buf(buf) + ndis_buffer *buf; +{ + ndis_buffer *head; + + if (buf == NULL || buf->nb_process == NULL) + return; + + head = buf->nb_process; + + if (head->nb_flags != 0x1) + return; + + buf->nb_next = head->nb_next; + head->nb_next = buf; + + return; +} + +/* Get the virtual address and length of a buffer */ + +__stdcall static void +ndis_query_buf(buf, vaddr, len) + ndis_buffer *buf; + void **vaddr; + uint32_t *len; +{ + *vaddr = buf->nb_mappedsystemva; + *len = buf->nb_bytecount; + + return; +} + +/* Same as above -- we don't care about the priority. */ + +__stdcall static void +ndis_query_buf_safe(buf, vaddr, len, prio) + ndis_buffer *buf; + void **vaddr; + uint32_t *len; + uint32_t prio; +{ + *vaddr = buf->nb_mappedsystemva; + *len = buf->nb_bytecount; + + return; +} + +__stdcall static void +ndis_adjust_buflen(buf, len) + ndis_buffer *buf; + int len; +{ + if (buf->nb_bytecount > len) + return; + buf->nb_bytecount = len; + + return; +} + +__stdcall static uint32_t +ndis_interlock_inc(addend) + uint32_t *addend; +{ + mtx_lock(&ndis_interlock); + *addend++; + mtx_unlock(&ndis_interlock); + return(*addend); +} + +__stdcall static uint32_t +ndis_interlock_dec(addend) + uint32_t *addend; +{ + mtx_lock(&ndis_interlock); + *addend--; + mtx_unlock(&ndis_interlock); + return(*addend); +} + +__stdcall static void +ndis_init_event(event) + ndis_event *event; +{ + event->ne_event.nk_header.dh_sigstate = FALSE; + return; +} + +__stdcall static void +ndis_set_event(event) + ndis_event *event; +{ + event->ne_event.nk_header.dh_sigstate = TRUE; + wakeup(event); + return; +} + +__stdcall static void +ndis_reset_event(event) + ndis_event *event; +{ + event->ne_event.nk_header.dh_sigstate = FALSE; + wakeup(event); + return; +} + +__stdcall static uint8_t +ndis_wait_event(event, msecs) + ndis_event *event; + uint32_t msecs; +{ + int error; + struct timeval tv; + + if (event->ne_event.nk_header.dh_sigstate == TRUE) + return(TRUE); + + tv.tv_sec = 0; + tv.tv_usec = msecs * 1000; + + error = tsleep(event, PPAUSE|PCATCH, "ndis", tvtohz(&tv)); + + return(event->ne_event.nk_header.dh_sigstate); +} + +__stdcall static ndis_status +ndis_unicode2ansi(dstr, sstr) + ndis_ansi_string *dstr; + ndis_unicode_string *sstr; +{ + ndis_unicode_to_ascii(sstr->nus_buf, sstr->nus_len, &dstr->nas_buf); + dstr->nas_len = strlen(dstr->nas_buf); + printf ("unicode 2 ansi...\n"); + return (NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +ndis_assign_pcirsrc(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; + + printf ("assign PCI resources...\n"); + return (NDIS_STATUS_SUCCESS); +} + +__stdcall static ndis_status +ndis_register_intr(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; +{ + + return(NDIS_STATUS_SUCCESS); +} + +__stdcall static void +ndis_deregister_intr(intr) + ndis_miniport_interrupt *intr; +{ + return; +} + +__stdcall static void +ndis_register_shutdown(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 = (struct ndis_softc *)block->nmb_ifp; + chars = &sc->ndis_chars; + + chars->nmc_shutdown_handler = shutdownfunc; + chars->nmc_rsvd0 = shutdownctx; + + return; +} + +__stdcall static void +ndis_deregister_shutdown(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 = (struct ndis_softc *)block->nmb_ifp; + chars = &sc->ndis_chars; + + chars->nmc_shutdown_handler = NULL; + chars->nmc_rsvd0 = NULL; + + return; +} + +__stdcall static uint32_t +ndis_numpages(buf) + ndis_buffer *buf; +{ + return(howmany(buf->nb_bytecount, PAGE_SIZE)); +} + +__stdcall static void +ndis_query_bufoffset(buf, off, len) + ndis_buffer *buf; + uint32_t *off; + uint32_t *len; +{ + *off = (uint32_t)buf->nb_mappedsystemva & (PAGE_SIZE - 1); + *len = buf->nb_bytecount; + + return; +} + +__stdcall static void +ndis_sleep(usecs) + uint32_t usecs; +{ + struct timeval tv; + uint32_t dummy; + + tv.tv_sec = 0; + tv.tv_usec = usecs; + + tsleep(&dummy, PPAUSE|PCATCH, "ndis", tvtohz(&tv)); + return; +} + +__stdcall static uint32_t +ndis_read_pccard_amem(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 = (struct ndis_softc *)block->nmb_ifp; + 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 * 2) + (i * 2)); + + return(i); +} + +__stdcall static uint32_t +ndis_write_pccard_amem(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 = (struct ndis_softc *)block->nmb_ifp; + 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 * 2) + (i * 2), src[i]); + + return(i); +} + +__stdcall static ndis_list_entry * +ndis_insert_head(head, entry, lock) + ndis_list_entry *head; + ndis_list_entry *entry; + ndis_spin_lock *lock; +{ + ndis_list_entry *flink; + + mtx_lock_spin((struct mtx *)lock->nsl_spinlock); + flink = head->nle_flink; + entry->nle_flink = flink; + entry->nle_blink = head; + flink->nle_blink = entry; + head->nle_flink = entry; + mtx_unlock_spin((struct mtx *)lock->nsl_spinlock); + + return(flink); +} + +__stdcall static ndis_list_entry * +ndis_remove_head(head, lock) + ndis_list_entry *head; + ndis_spin_lock *lock; +{ + ndis_list_entry *flink; + ndis_list_entry *entry; + + mtx_lock_spin((struct mtx *)lock->nsl_spinlock); + entry = head->nle_flink; + flink = entry->nle_flink; + head->nle_flink = flink; + flink->nle_blink = head; + mtx_unlock_spin((struct mtx *)lock->nsl_spinlock); + + return(entry); +} + +__stdcall static ndis_list_entry * +ndis_insert_tail(head, entry, lock) + ndis_list_entry *head; + ndis_list_entry *entry; + ndis_spin_lock *lock; +{ + ndis_list_entry *blink; + + mtx_lock_spin((struct mtx *)lock->nsl_spinlock); + blink = head->nle_blink; + entry->nle_flink = head; + entry->nle_blink = blink; + blink->nle_flink = entry; + head->nle_blink = entry; + mtx_unlock_spin((struct mtx *)lock->nsl_spinlock); + + return(blink); +} + +__stdcall static uint8_t +ndis_sync_with_intr(intr, syncfunc, syncctx) + ndis_miniport_interrupt *intr; + void *syncfunc; + void *syncctx; +{ + __stdcall uint8_t (*sync)(void *); + + if (syncfunc == NULL || syncctx == NULL) + return(0); + + sync = syncfunc; + return(sync(syncctx)); +} + +__stdcall static void +dummy() +{ + printf ("NDIS dummy called...\n"); + return; +} + +image_patch_table ndis_functbl[] = { + { "NdisMSynchronizeWithInterrupt", (FUNC)ndis_sync_with_intr }, + { "NdisMAllocateSharedMemoryAsync", (FUNC)ndis_alloc_sharedmem_async }, + { "NdisInterlockedInsertHeadList", (FUNC)ndis_insert_head }, + { "NdisInterlockedInsertTailList", (FUNC)ndis_insert_tail }, + { "NdisInterlockedRemoveHeadList", (FUNC)ndis_remove_head }, + { "NdisInitializeWrapper", (FUNC)ndis_initwrap }, + { "NdisMRegisterMiniport", (FUNC)ndis_register_miniport }, + { "NdisAllocateMemoryWithTag", (FUNC)ndis_malloc_withtag }, + { "NdisAllocateMemory", (FUNC)ndis_malloc }, + { "NdisMSetAttributesEx", (FUNC)ndis_setattr_ex }, + { "NdisCloseConfiguration", (FUNC)ndis_close_cfg }, + { "NdisReadConfiguration", (FUNC)ndis_read_cfg }, + { "NdisOpenConfiguration", (FUNC)ndis_open_cfg }, + { "NdisReleaseSpinLock", (FUNC)ndis_unlock }, + { "NdisDprAcquireSpinLock", (FUNC)ndis_lock }, + { "NdisDprReleaseSpinLock", (FUNC)ndis_unlock }, + { "NdisAcquireSpinLock", (FUNC)ndis_lock }, + { "NdisAllocateSpinLock", (FUNC)ndis_create_lock }, + { "NdisFreeSpinLock", (FUNC)ndis_destroy_lock }, + { "NdisFreeMemory", (FUNC)ndis_free }, + { "NdisReadPciSlotInformation", (FUNC)ndis_read_pci }, + { "NdisWritePciSlotInformation",(FUNC)ndis_write_pci }, + { "NdisWriteErrorLogEntry", (FUNC)ndis_syslog }, + { "NdisMStartBufferPhysicalMapping", (FUNC)ndis_vtophys_load }, + { "NdisMCompleteBufferPhysicalMapping", (FUNC)ndis_vtophys_unload }, + { "NdisMInitializeTimer", (FUNC)ndis_create_timer }, + { "NdisSetTimer", (FUNC)ndis_set_timer }, + { "NdisMCancelTimer", (FUNC)ndis_cancel_timer }, + { "NdisMSetPeriodicTimer", (FUNC)ndis_set_periodic_timer }, + { "NdisMQueryAdapterResources", (FUNC)ndis_query_resources }, + { "NdisMRegisterIoPortRange", (FUNC)ndis_register_ioport }, + { "NdisMDeregisterIoPortRange", (FUNC)ndis_deregister_ioport }, + { "NdisReadNetworkAddress", (FUNC)ndis_read_netaddr }, + { "NdisMAllocateMapRegisters", (FUNC)ndis_alloc_mapreg }, + { "NdisMFreeMapRegisters", (FUNC)ndis_free_mapreg }, + { "NdisMAllocateSharedMemory", (FUNC)ndis_alloc_sharedmem }, + { "NdisMMapIoSpace", (FUNC)ndis_map_iospace }, + { "NdisMUnmapIoSpace", (FUNC)ndis_unmap_iospace }, + { "NdisGetCacheFillSize", (FUNC)ndis_cachefill }, + { "NdisMGetDmaAlignment", (FUNC)ndis_dma_align }, + { "NdisMInitializeScatterGatherDma", (FUNC)ndis_init_sc_dma }, + { "NdisAllocatePacketPool", (FUNC)ndis_alloc_packetpool }, + { "NdisAllocatePacketPoolEx", (FUNC)ndis_ex_alloc_packetpool }, + { "NdisAllocatePacket", (FUNC)ndis_alloc_packet }, + { "NdisFreePacket", (FUNC)ndis_release_packet }, + { "NdisFreePacketPool", (FUNC)ndis_free_packetpool }, + { "NdisAllocateBufferPool", (FUNC)ndis_alloc_bufpool }, + { "NdisAllocateBuffer", (FUNC)ndis_alloc_buf }, + { "NdisQueryBuffer", (FUNC)ndis_query_buf }, + { "NdisQueryBufferSafe", (FUNC)ndis_query_buf_safe }, + { "NdisFreeBuffer", (FUNC)ndis_release_buf }, + { "NdisFreeBufferPool", (FUNC)ndis_free_bufpool }, + { "NdisInterlockedIncrement", (FUNC)ndis_interlock_inc }, + { "NdisInterlockedDecrement", (FUNC)ndis_interlock_dec }, + { "NdisInitializeEvent", (FUNC)ndis_init_event }, + { "NdisSetEvent", (FUNC)ndis_set_event }, + { "NdisResetEvent", (FUNC)ndis_reset_event }, + { "NdisWaitEvent", (FUNC)ndis_wait_event }, + { "NdisUnicodeStringToAnsiString", (FUNC)ndis_unicode2ansi }, + { "NdisMPciAssignResources", (FUNC)ndis_assign_pcirsrc }, + { "NdisMFreeSharedMemory", (FUNC)ndis_free_sharedmem }, + { "NdisMRegisterInterrupt", (FUNC)ndis_register_intr }, + { "NdisMDeregisterInterrupt", (FUNC)ndis_deregister_intr }, + { "NdisMRegisterAdapterShutdownHandler", (FUNC)ndis_register_shutdown }, + { "NdisMDeregisterAdapterShutdownHandler", (FUNC)ndis_deregister_shutdown }, + { "NDIS_BUFFER_TO_SPAN_PAGES", (FUNC)ndis_numpages }, + { "NdisQueryBufferOffset", (FUNC)ndis_query_bufoffset }, + { "NdisAdjustBufferLength", (FUNC)ndis_adjust_buflen }, + { "NdisPacketPoolUsage", (FUNC)ndis_packetpool_use }, + { "NdisMSleep", (FUNC)ndis_sleep }, + { "NdisUnchainBufferAtFront", (FUNC)ndis_unchain_headbuf }, + { "NdisReadPcmciaAttributeMemory", (FUNC)ndis_read_pccard_amem }, + { "NdisWritePcmciaAttributeMemory", (FUNC)ndis_write_pccard_amem }, + + /* + * 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 }, + + /* End of list. */ + + { NULL, NULL }, +}; + diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c new file mode 100644 index 000000000000..04399c750fd9 --- /dev/null +++ b/sys/compat/ndis/subr_ntoskrnl.c @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> + +#include <sys/callout.h> +#include <sys/kernel.h> + +#include <machine/clock.h> +#include <machine/bus_memio.h> +#include <machine/bus_pio.h> +#include <machine/bus.h> +#include <machine/stdarg.h> + +#include <sys/bus.h> +#include <sys/rman.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ndis_var.h> +#include <compat/ndis/ntoskrnl_var.h> + +#define __stdcall __attribute__((__stdcall__)) +#define FUNC void(*)(void) + +__stdcall static uint32_t ntoskrnl_unicode_equal(ndis_unicode_string *, + ndis_unicode_string *, uint32_t); +__stdcall static void *ntoskrnl_iobuildsynchfsdreq(uint32_t, void *, + void *, uint32_t, uint32_t *, void *, void *); +__stdcall static uint32_t ntoskrnl_iofcalldriver(void *, void *); +__stdcall static uint32_t ntoskrnl_waitforobj(void *, uint32_t, + uint32_t, uint8_t, void *); +__stdcall static void ntoskrnl_initevent(void *, uint32_t, uint8_t); +__stdcall static void ntoskrnl_writereg_ushort(uint16_t *, uint16_t); +__stdcall static uint16_t ntoskrnl_readreg_ushort(uint16_t *); +__stdcall static void ntoskrnl_writereg_ulong(uint32_t *, uint32_t); +__stdcall static uint32_t ntoskrnl_readreg_ulong(uint32_t *); +__stdcall static void ntoskrnl_writereg_uchar(uint8_t *, uint8_t); +__stdcall static uint8_t ntoskrnl_readreg_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); +__stdcall static int64_t _allshr(int64_t, int); +__stdcall static int64_t _allshl(int64_t, int); +__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); +__stdcall static uint64_t _aullshr(uint64_t, int); +__stdcall static uint64_t _aullshl(uint64_t, int); +__stdcall static void *ntoskrnl_allocfunc(uint32_t, size_t, uint32_t); +__stdcall static void ntoskrnl_freefunc(void *); +__stdcall static void ntoskrnl_init_lookaside(paged_lookaside_list *, + lookaside_alloc_func *, lookaside_free_func *, + uint32_t, size_t, uint32_t, uint16_t); +__stdcall static void ntoskrnl_delete_lookaside(paged_lookaside_list *); +__stdcall static void ntoskrnl_init_nplookaside(npaged_lookaside_list *, + lookaside_alloc_func *, lookaside_free_func *, + uint32_t, size_t, uint32_t, uint16_t); +__stdcall static void ntoskrnl_delete_nplookaside(npaged_lookaside_list *); +static slist_entry *ntoskrnl_push_slist(slist_entry *, slist_entry *); +static slist_entry *ntoskrnl_pop_slist(slist_entry *); +__stdcall static void dummy(void); + +static struct mtx ntoskrnl_interlock; +static int ntoskrnl_inits = 0; + +int +ntoskrnl_libinit() +{ + if (ntoskrnl_inits) { + ntoskrnl_inits++; + return(0); + } + + mtx_init(&ntoskrnl_interlock, "ntoskrnllock", MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE); + + ntoskrnl_inits++; + return(0); +} + +int +ntoskrnl_libfini() +{ + if (ntoskrnl_inits != 1) { + ntoskrnl_inits--; + return(0); + } + + mtx_destroy(&ntoskrnl_interlock); + ntoskrnl_inits--; + + return(0); +} + +__stdcall static uint32_t +ntoskrnl_unicode_equal(str1, str2, casesensitive) + ndis_unicode_string *str1; + ndis_unicode_string *str2; + uint32_t casesensitive; +{ + char *astr1 = NULL, *astr2 = NULL; + int rval = 1; + + ndis_unicode_to_ascii(str1->nus_buf, str2->nus_len, &astr1); + ndis_unicode_to_ascii(str2->nus_buf, str2->nus_len, &astr2); + + if (casesensitive) + rval = strcmp(astr1, astr2); +#ifdef notdef + else + rval = strcasecmp(astr1, astr2); +#endif + + free(astr1, M_DEVBUF); + free(astr2, M_DEVBUF); + + return(rval); +} + +__stdcall static void * +ntoskrnl_iobuildsynchfsdreq(func, dobj, buf, len, off, event, status) + uint32_t func; + void *dobj; + void *buf; + uint32_t len; + uint32_t *off; + void *event; + void *status; +{ + return(NULL); +} + +__stdcall static uint32_t +ntoskrnl_iofcalldriver(dobj, irp) + void *dobj; + void *irp; +{ + return(0); +} + +__stdcall static uint32_t +ntoskrnl_waitforobj(obj, reason, mode, alertable, timeout) + void *obj; + uint32_t reason; + uint32_t mode; + uint8_t alertable; + void *timeout; +{ + return(0); +} + +__stdcall static void +ntoskrnl_initevent(event, type, state) + void *event; + uint32_t type; + uint8_t state; +{ + return; +} + +__stdcall static void +ntoskrnl_writereg_ushort(reg, val) + uint16_t *reg; + uint16_t val; +{ + bus_space_write_2(I386_BUS_SPACE_MEM, 0x0, (uint32_t)reg, val); + return; +} + +__stdcall static uint16_t +ntoskrnl_readreg_ushort(reg) + uint16_t *reg; +{ + return(bus_space_read_2(I386_BUS_SPACE_MEM, 0x0, (uint32_t)reg)); +} + +__stdcall static void +ntoskrnl_writereg_ulong(reg, val) + uint32_t *reg; + uint32_t val; +{ + bus_space_write_4(I386_BUS_SPACE_MEM, 0x0, (uint32_t)reg, val); + return; +} + +__stdcall static uint32_t +ntoskrnl_readreg_ulong(reg) + uint32_t *reg; +{ + return(bus_space_read_4(I386_BUS_SPACE_MEM, 0x0, (uint32_t)reg)); +} + +__stdcall static uint8_t +ntoskrnl_readreg_uchar(reg) + uint8_t *reg; +{ + return(bus_space_read_1(I386_BUS_SPACE_MEM, 0x0, (uint32_t)reg)); +} + +__stdcall static void +ntoskrnl_writereg_uchar(reg, val) + uint8_t *reg; + uint8_t val; +{ + bus_space_write_1(I386_BUS_SPACE_MEM, 0x0, (uint32_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); +} + +__stdcall static int64_t +_allshl(a, b) + int64_t a; + int b; +{ + return (a << b); +} + +__stdcall static uint64_t +_aullshl(a, b) + uint64_t a; + int b; +{ + return (a << b); +} + +__stdcall static int64_t +_allshr(a, b) + int64_t a; + int b; +{ + return (a >> b); +} + +__stdcall static uint64_t +_aullshr(a, b) + uint64_t a; + int b; +{ + return (a >> b); +} + +__stdcall static void * +ntoskrnl_allocfunc(pooltype, size, tag) + uint32_t pooltype; + size_t size; + uint32_t tag; +{ + return(malloc(size, M_DEVBUF, M_NOWAIT)); +} + +__stdcall static void +ntoskrnl_freefunc(buf) + void *buf; +{ + free(buf, M_DEVBUF); +} + +__stdcall static void +ntoskrnl_init_lookaside(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; +{ + lookaside->nll_l.gl_size = size; + lookaside->nll_l.gl_tag = tag; + if (allocfunc == NULL) + lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc; + else + lookaside->nll_l.gl_allocfunc = allocfunc; + + if (freefunc == NULL) + lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc; + else + lookaside->nll_l.gl_freefunc = freefunc; + + return; +} + +__stdcall static void +ntoskrnl_delete_lookaside(lookaside) + paged_lookaside_list *lookaside; +{ + return; +} + +__stdcall static void +ntoskrnl_init_nplookaside(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; +{ + lookaside->nll_l.gl_size = size; + lookaside->nll_l.gl_tag = tag; + if (allocfunc == NULL) + lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc; + else + lookaside->nll_l.gl_allocfunc = allocfunc; + + if (freefunc == NULL) + lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc; + else + lookaside->nll_l.gl_freefunc = freefunc; + + return; +} + +__stdcall static void +ntoskrnl_delete_nplookaside(lookaside) + npaged_lookaside_list *lookaside; +{ + return; +} + +/* + * Note: the interlocked slist push and pop routines are + * declared to be _fastcall in Windows, which means they + * use the _cdecl calling convention here. + */ +static slist_entry * +ntoskrnl_push_slist(head, entry) + slist_entry *head; + slist_entry *entry; +{ + slist_entry *oldhead; + mtx_lock(&ntoskrnl_interlock); + oldhead = head->sl_next; + entry->sl_next = head->sl_next; + head->sl_next = entry; + mtx_unlock(&ntoskrnl_interlock); + return(oldhead); +} + +static slist_entry * +ntoskrnl_pop_slist(head) + slist_entry *head; +{ + slist_entry *first; + mtx_lock(&ntoskrnl_interlock); + first = head->sl_next; + if (first != NULL) + head->sl_next = first->sl_next; + mtx_unlock(&ntoskrnl_interlock); + return(first); +} + +__stdcall static void +dummy() +{ + printf ("ntoskrnl dummy called...\n"); + return; +} + + +image_patch_table ntoskrnl_functbl[] = { + { "RtlEqualUnicodeString", (FUNC)ntoskrnl_unicode_equal }, + { "sprintf", (FUNC)sprintf }, + { "DbgPrint", (FUNC)printf }, + { "strncmp", (FUNC)strncmp }, + { "strcmp", (FUNC)strcmp }, + { "strncpy", (FUNC)strncpy }, + { "strcpy", (FUNC)strcpy }, + { "IofCallDriver", (FUNC)ntoskrnl_iofcalldriver }, + { "IoBuildSynchronousFsdRequest", (FUNC)ntoskrnl_iobuildsynchfsdreq }, + { "KeWaitForSingleObject", (FUNC)ntoskrnl_waitforobj }, + { "KeInitializeEvent", (FUNC)ntoskrnl_initevent }, + { "_allmul", (FUNC)_allmul }, + { "_alldiv", (FUNC)_alldiv }, + { "_allrem", (FUNC)_allrem }, + { "_allshr", (FUNC)_allshr }, + { "_allshl", (FUNC)_allshl }, + { "_aullmul", (FUNC)_aullmul }, + { "_aulldiv", (FUNC)_aulldiv }, + { "_aullrem", (FUNC)_aullrem }, + { "_aullushr", (FUNC)_aullshr }, + { "_aullshl", (FUNC)_aullshl }, + { "WRITE_REGISTER_USHORT", (FUNC)ntoskrnl_writereg_ushort }, + { "READ_REGISTER_USHORT", (FUNC)ntoskrnl_readreg_ushort }, + { "WRITE_REGISTER_ULONG", (FUNC)ntoskrnl_writereg_ulong }, + { "READ_REGISTER_ULONG", (FUNC)ntoskrnl_readreg_ulong }, + { "READ_REGISTER_UCHAR", (FUNC)ntoskrnl_readreg_uchar }, + { "WRITE_REGISTER_UCHAR", (FUNC)ntoskrnl_writereg_uchar }, + { "ExInitializePagedLookasideList", (FUNC)ntoskrnl_init_lookaside }, + { "ExDeletePagedLookasideList", (FUNC)ntoskrnl_delete_lookaside }, + { "ExInitializeNPagedLookasideList", (FUNC)ntoskrnl_init_nplookaside }, + { "ExDeleteNPagedLookasideList", (FUNC)ntoskrnl_delete_nplookaside }, + { "InterlockedPopEntrySList", (FUNC)ntoskrnl_pop_slist }, + { "InterlockedPushEntrySList", (FUNC)ntoskrnl_push_slist }, + + /* + * 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 }, + + /* End of list. */ + + { NULL, NULL }, +}; diff --git a/sys/compat/ndis/subr_pe.c b/sys/compat/ndis/subr_pe.c new file mode 100644 index 000000000000..8a2ae5b8b52b --- /dev/null +++ b/sys/compat/ndis/subr_pe.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * 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 <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> +#ifdef _KERNEL +#include <sys/systm.h> +#else +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#endif + +#include <compat/ndis/pe_var.h> + +static u_int32_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 == NULL || 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 == NULL) + 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 == NULL || 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 == NULL || 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 == NULL || 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; + uint32_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 <= (u_int32_t)rva && + (sect_hdr->ish_vaddr + fixedlen) > + (u_int32_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 == NULL || 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; + uint32_t base, delta, *lloc; + 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; + 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. + */ + +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 == NULL || 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 (!strncmp(module, modname, strlen(module))) { + bcopy((char *)imp_desc, (char *)desc, + sizeof(image_import_descriptor)); + return(0); + } + imp_desc++; + } + + 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((uint32_t)p->ipt_func); + p++; + } + printf ("no match for %s\n", name); + return((vm_offset_t)p->ipt_func); +} + +/* + * 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. + * + * 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. + */ + +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 == NULL || 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) != NULL) { + 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/conf/files.i386 b/sys/conf/files.i386 index 34168ac5aeae..d46ce901295e 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -74,6 +74,11 @@ compat/linux/linux_stats.c optional compat_linux compat/linux/linux_sysctl.c optional compat_linux compat/linux/linux_uid16.c optional compat_linux compat/linux/linux_util.c optional compat_linux +compat/ndis/kern_ndis.c optional ndisapi pci pccard +compat/ndis/subr_hal.c optional ndisapi pci pccard +compat/ndis/subr_ndis.c optional ndisapi pci pccard +compat/ndis/subr_ntoskrnl.c optional ndisapi pci pccard +compat/ndis/subr_pe.c optional ndisapi pci pccard compat/pecoff/imgact_pecoff.c optional pecoff_support compat/svr4/imgact_svr4.c optional compat_svr4 compat/svr4/svr4_fcntl.c optional compat_svr4 @@ -127,6 +132,7 @@ dev/fb/fb.c optional vga dev/fb/splash.c optional splash dev/fb/vga.c optional vga dev/fe/if_fe_isa.c optional fe isa +dev/if_ndis/if_ndis.c optional ndis pci pccard dev/kbd/atkbd.c optional atkbd dev/kbd/atkbdc.c optional atkbdc dev/kbd/kbd.c optional atkbd diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c new file mode 100644 index 000000000000..7a6b56a4ee01 --- /dev/null +++ b/sys/dev/if_ndis/if_ndis.c @@ -0,0 +1,961 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_bdg.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <net/bpf.h> + +#include <vm/vm.h> /* for vtophys */ +#include <vm/pmap.h> /* for vtophys */ +#include <machine/bus_memio.h> +#include <machine/bus_pio.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ndis_var.h> +#include <compat/ndis/cfg_var.h> +#include <dev/if_ndis/if_ndisvar.h> + +#include "ndis_driver_data.h" + +MODULE_DEPEND(ndis, pci, 1, 1, 1); +MODULE_DEPEND(ndis, ether, 1, 1, 1); +MODULE_DEPEND(ndis, ndisapi, 1, 1, 1); + +/* + * Various supported device vendors/types and their names. + * These are defined in the ndis_driver_data.h file. + */ +static struct ndis_type ndis_devs[] = { +#ifdef NDIS_DEV_TABLE + NDIS_DEV_TABLE +#endif + { 0, 0, NULL } +}; + +#define __stdcall __attribute__((__stdcall__)) + +static int ndis_probe (device_t); +static int ndis_attach (device_t); +static int ndis_detach (device_t); + +static __stdcall void ndis_txeof (ndis_handle, + ndis_packet *, ndis_status); +static __stdcall void ndis_rxeof (ndis_handle, + ndis_packet **, uint32_t); +static void ndis_intr (void *); +static void ndis_tick (void *); +static void ndis_start (struct ifnet *); +static int ndis_ioctl (struct ifnet *, u_long, caddr_t); +static void ndis_init (void *); +static void ndis_stop (struct ndis_softc *); +static void ndis_watchdog (struct ifnet *); +static void ndis_shutdown (device_t); +static int ndis_ifmedia_upd (struct ifnet *); +static void ndis_ifmedia_sts (struct ifnet *, struct ifmediareq *); + +static void ndis_reset (struct ndis_softc *); +static void ndis_setmulti (struct ndis_softc *); +static void ndis_map_sclist (void *, bus_dma_segment_t *, + int, bus_size_t, int); + +#ifdef NDIS_USEIOSPACE +#define NDIS_RES SYS_RES_IOPORT +#define NDIS_RID NDIS_PCI_LOIO +#else +#define NDIS_RES SYS_RES_MEMORY +#define NDIS_RID NDIS_PCI_LOMEM +#endif + +static device_method_t ndis_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ndis_probe), + DEVMETHOD(device_attach, ndis_attach), + DEVMETHOD(device_detach, ndis_detach), + DEVMETHOD(device_shutdown, ndis_shutdown), + + { 0, 0 } +}; + +static driver_t ndis_driver = { + "ndis", + ndis_methods, + sizeof(struct ndis_softc) +}; + +static devclass_t ndis_devclass; + +DRIVER_MODULE(ndis, pci, ndis_driver, ndis_devclass, 0, 0); + +/* + * Program the 64-bit multicast hash filter. + */ +static void +ndis_setmulti(sc) + struct ndis_softc *sc; +{ +#ifdef notyet + uint32_t ndis_filter; + int len; +#endif + return; +} + +static void +ndis_reset(sc) + struct ndis_softc *sc; +{ + ndis_reset_nic(sc); + return; +} + +/* + * Probe for an NDIS device. Check the PCI vendor and device + * IDs against our list and return a device name if we find a match. + */ +static int +ndis_probe(dev) + device_t dev; +{ + struct ndis_type *t; + + t = ndis_devs; + + while(t->ndis_name != NULL) { + if ((pci_get_vendor(dev) == t->ndis_vid) && + (pci_get_device(dev) == t->ndis_did)) { + device_set_desc(dev, t->ndis_name); + return(0); + } + t++; + } + + return(ENXIO); +} + +/* + * Attach the interface. Allocate softc structures, do ifmedia + * setup and ethernet/BPF attach. + */ +static int +ndis_attach(dev) + device_t dev; +{ + u_char eaddr[ETHER_ADDR_LEN]; + struct ndis_softc *sc; + struct ifnet *ifp; + int unit, error = 0, rid, len; + void *img; + + sc = device_get_softc(dev); + unit = device_get_unit(dev); + + mtx_init(&sc->ndis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE); + + /* + * Map control/status registers. + */ + pci_enable_busmaster(dev); + + /* Try to map iospace */ + + sc->ndis_io_rid = NDIS_PCI_LOIO; + sc->ndis_res_io = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->ndis_io_rid, 0, ~0, 1, RF_ACTIVE); + + /* + * Sometimes the iospace and memspace BARs are swapped. + * Make one more try to map I/O space using a different + * RID. + */ + if (sc->ndis_res_io == NULL) { + sc->ndis_io_rid = NDIS_PCI_LOMEM; + sc->ndis_res_io = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->ndis_io_rid, 0, ~0, 1, RF_ACTIVE); + } + + if (sc->ndis_res_io != NULL) + sc->ndis_rescnt++; + + /* Now try to mem memory space */ + sc->ndis_mem_rid = NDIS_PCI_LOMEM; + sc->ndis_res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, + &sc->ndis_mem_rid, 0, ~0, 1, RF_ACTIVE); + + /* + * If the first attempt fails, try again with another + * BAR. + */ + if (sc->ndis_res_mem == NULL) { + sc->ndis_mem_rid = NDIS_PCI_LOIO; + sc->ndis_res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, + &sc->ndis_mem_rid, 0, ~0, 1, RF_ACTIVE); + } + + if (sc->ndis_res_mem != NULL) + sc->ndis_rescnt++; + + if (!sc->ndis_rescnt) { + printf("ndis%d: couldn't map ports/memory\n", unit); + error = ENXIO; + goto fail; + } +#ifdef notdef + sc->ndis_btag = rman_get_bustag(sc->ndis_res); + sc->ndis_bhandle = rman_get_bushandle(sc->ndis_res); +#endif + + /* Allocate interrupt */ + rid = 0; + sc->ndis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, + RF_SHAREABLE | RF_ACTIVE); + + if (sc->ndis_irq == NULL) { + printf("ndis%d: couldn't map interrupt\n", unit); + error = ENXIO; + goto fail; + } + + sc->ndis_rescnt++; + + /* + * Allocate the parent bus DMA tag appropriate for PCI. + */ +#define NDIS_NSEG_NEW 32 + error = bus_dma_tag_create(NULL, /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MAXBSIZE, NDIS_NSEG_NEW,/* maxsize, nsegments */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->ndis_parent_tag); + + if (error) + goto fail; + + img = drv_data; + sc->ndis_dev = dev; + sc->ndis_regvals = ndis_regvals; + sc->ndis_iftype = PCIBus; + + sysctl_ctx_init(&sc->ndis_ctx); + + /* Create sysctl registry nodes */ + ndis_create_sysctls(sc); + + /* Set up driver image in memory. */ + ndis_load_driver((vm_offset_t)img, sc); + + /* Do resource conversion. */ + ndis_convert_res(sc); + + /* Install our RX and TX interrupt handlers. */ + sc->ndis_block.nmb_senddone_func = ndis_txeof; + sc->ndis_block.nmb_pktind_func = ndis_rxeof; + + /* Call driver's init routine. */ + if (ndis_init_nic(sc)) { + printf ("ndis%d: init handler failed\n", sc->ndis_unit); + error = ENXIO; + goto fail; + } + + /* Reset the adapter. */ + ndis_reset(sc); + + /* + * Get station address from the driver. + */ + len = sizeof(eaddr); + ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len); + + /* + * An NDIS device was detected. Inform the world. + */ + printf("ndis%d: Ethernet address: %6D\n", unit, eaddr, ":"); + + sc->ndis_unit = unit; + bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); + + /* + * Figure out of we're allowed to use multipacket sends + * with this driver, and if so, how many. + */ + + if (sc->ndis_chars.nmc_sendsingle_func) + sc->ndis_maxpkts = 1; + else { + len = sizeof(sc->ndis_maxpkts); + ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS, + &sc->ndis_maxpkts, &len); + sc->ndis_txarray = malloc(sizeof(ndis_packet *) * + sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT); + bzero((char *)sc->ndis_txarray, sizeof(ndis_packet *) * + sc->ndis_maxpkts); + } + + sc->ndis_txpending = sc->ndis_maxpkts; + sc->ndis_mbufs = malloc(sizeof(struct mbuf) * sc->ndis_maxpkts, + M_DEVBUF, M_NOWAIT); + + if (sc->ndis_mbufs == NULL) + goto fail; + + sc->ndis_oidcnt = 0; + /* Get supported oid list. */ + ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt); + + /* If the NDIS module requested scatter/gather, init maps. */ + if (sc->ndis_sc) + ndis_init_dma(sc); + + ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd, + ndis_ifmedia_sts); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); + ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO); + + ifp = &sc->arpcom.ac_if; + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_mtu = ETHERMTU; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = ndis_ioctl; + ifp->if_output = ether_output; + ifp->if_start = ndis_start; + ifp->if_watchdog = ndis_watchdog; + ifp->if_init = ndis_init; + ifp->if_baudrate = 10000000; + ifp->if_snd.ifq_maxlen = 50; + + /* + * Call MI attach routine. + */ + ether_ifattach(ifp, eaddr); + + /* Hook interrupt last to avoid having to lock softc */ + error = bus_setup_intr(dev, sc->ndis_irq, INTR_TYPE_NET, + ndis_intr, sc, &sc->ndis_intrhand); + + if (error) { + printf("ndis%d: couldn't set up irq\n", unit); + ether_ifdetach(ifp); + goto fail; + } + +fail: + if (error) + ndis_detach(dev); + + return(error); +} + +/* + * Shutdown hardware and free up resources. This can be called any + * time after the mutex has been initialized. It is called in both + * the error case in attach and the normal detach case so it needs + * to be careful about only freeing resources that have actually been + * allocated. + */ +static int +ndis_detach(dev) + device_t dev; +{ + struct ndis_softc *sc; + struct ifnet *ifp; + + sc = device_get_softc(dev); + KASSERT(mtx_initialized(&sc->ndis_mtx), ("ndis mutex not initialized")); + NDIS_LOCK(sc); + ifp = &sc->arpcom.ac_if; + + if (device_is_attached(dev)) { + NDIS_UNLOCK(sc); + ndis_stop(sc); + ether_ifdetach(ifp); + NDIS_LOCK(sc); + } + + bus_generic_detach(dev); + + if (sc->ndis_intrhand) + bus_teardown_intr(dev, sc->ndis_irq, sc->ndis_intrhand); + if (sc->ndis_irq) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq); + if (sc->ndis_res_io) + bus_release_resource(dev, SYS_RES_IOPORT, + sc->ndis_io_rid, sc->ndis_res_io); + if (sc->ndis_res_mem) + bus_release_resource(dev, SYS_RES_MEMORY, + sc->ndis_mem_rid, sc->ndis_res_mem); + + if (sc->ndis_sc) + ndis_destroy_dma(sc); + + ndis_unload_driver((void *)ifp); + + bus_dma_tag_destroy(sc->ndis_parent_tag); + + sysctl_ctx_free(&sc->ndis_ctx); + + NDIS_UNLOCK(sc); + mtx_destroy(&sc->ndis_mtx); + + return(0); +} + +/* + * A frame has been uploaded: pass the resulting mbuf chain up to + * the higher level protocols. + */ +__stdcall static void +ndis_rxeof(adapter, packets, pktcnt) + ndis_handle adapter; + ndis_packet **packets; + uint32_t pktcnt; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + ndis_packet *p; + struct ifnet *ifp; + struct mbuf *m0; + int i; + + block = (ndis_miniport_block *)adapter; + sc = (struct ndis_softc *)(block->nmb_ifp); + ifp = block->nmb_ifp; + + for (i = 0; i < pktcnt; i++) { + p = packets[i]; + if (ndis_ptom(&m0, p)) { + printf ("ndis%d: ptom failed\n", sc->ndis_unit); + ndis_return_packet(sc, p); + } else { + MEXTADD(m0, m0->m_data, m0->m_pkthdr.len, + ndis_return_packet, sc, 0, EXT_NET_DRV); + m0->m_ext.ext_buf = (void *)p; /* XXX */ + m0->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + (*ifp->if_input)(ifp, m0); + } + } + + return; +} + +/* + * A frame was downloaded to the chip. It's safe for us to clean up + * the list buffers. + */ +__stdcall static void +ndis_txeof(adapter, packet, status) + ndis_handle adapter; + ndis_packet *packet; + ndis_status status; + +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + struct ifnet *ifp; + int idx; + + block = (ndis_miniport_block *)adapter; + sc = (struct ndis_softc *)block->nmb_ifp; + ifp = block->nmb_ifp; + + if (packet->np_rsvd[1] != NULL) { + idx = (int)packet->np_rsvd[1]; + ifp->if_opackets++; + if (sc->ndis_mbufs[idx] != NULL) { + m_freem(sc->ndis_mbufs[idx]); + sc->ndis_mbufs[idx] = NULL; + } + if (sc->ndis_sc) + bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]); + } + + ndis_free_packet(packet); + sc->ndis_txpending++; + + ifp->if_timer = 0; + ifp->if_flags &= ~IFF_OACTIVE; + + if (ifp->if_snd.ifq_head != NULL) + ndis_start(ifp); + + return; +} + +static void +ndis_intr(arg) + void *arg; +{ + struct ndis_softc *sc; + struct ifnet *ifp; + int is_our_intr = 0; + int call_isr = 0; + + sc = arg; + /*NDIS_LOCK(sc);*/ + ifp = &sc->arpcom.ac_if; + +/* + if (!(ifp->if_flags & IFF_UP)) { + NDIS_UNLOCK(sc); + return; + } +*/ + ndis_isr(sc, &is_our_intr, &call_isr); + + if (is_our_intr || call_isr) + ndis_intrhand(sc); + + if (ifp->if_snd.ifq_head != NULL) + ndis_start(ifp); + + /*NDIS_UNLOCK(sc);*/ + + return; +} + +static void +ndis_tick(xsc) + void *xsc; +{ + struct ndis_softc *sc; + __stdcall ndis_checkforhang_handler hangfunc; + uint8_t rval; + + sc = xsc; + NDIS_LOCK(sc); + + hangfunc = sc->ndis_chars.nmc_checkhang_func; + + if (hangfunc != NULL) { + rval = hangfunc(sc->ndis_block.nmb_miniportadapterctx); + if (rval == TRUE) + ndis_reset_nic(sc); + } + + sc->ndis_stat_ch = timeout(ndis_tick, sc, hz * + sc->ndis_block.nmb_checkforhangsecs); + + NDIS_UNLOCK(sc); + + return; +} + +static void +ndis_map_sclist(arg, segs, nseg, mapsize, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + bus_size_t mapsize; + int error; + +{ + struct ndis_sc_list *sclist; + int i; + + if (error || arg == NULL) + return; + + sclist = arg; + + sclist->nsl_frags = nseg; + + for (i = 0; i < nseg; i++) { + sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr; + sclist->nsl_elements[i].nse_len = segs[i].ds_len; + } + + return; +} + +/* + * Main transmit routine. To make NDIS drivers happy, we need to + * transform mbuf chains into NDIS packets and feed them to the + * send packet routines. Most drivers allow you to send several + * packets at once (up to the maxpkts limit). Unfortunately, rather + * that accepting them in the form of a linked list, they expect + * a contiguous array of pointers to packets. + * + * For those drivers which use the NDIS scatter/gather DMA mechanism, + * we need to perform busdma work here. Those that use map registers + * will do the mapping themselves on a buffer by buffer basis. + */ + +static void +ndis_start(ifp) + struct ifnet *ifp; +{ + struct ndis_softc *sc; + struct mbuf *m = NULL; + ndis_packet **p0 = NULL, *p = NULL; + int pcnt = 0; + + sc = ifp->if_softc; + + p0 = &sc->ndis_txarray[sc->ndis_txidx]; + + while(sc->ndis_txpending) { + IF_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + + NDIS_LOCK(sc); + sc->ndis_txarray[sc->ndis_txidx] = NULL; + if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) { + NDIS_UNLOCK(sc); + IF_PREPEND(&ifp->if_snd, m); + return; + } + + /* + * Save pointer to original mbuf + * so we can free it later. + */ + + sc->ndis_mbufs[sc->ndis_txidx] = m; + (sc->ndis_txarray[sc->ndis_txidx])->np_rsvd[1] = + (uint32_t *)sc->ndis_txidx; + + /* + * Do scatter/gather processing, if driver requested it. + */ + if (sc->ndis_sc) { + p = sc->ndis_txarray[sc->ndis_txidx]; + bus_dmamap_load_mbuf(sc->ndis_ttag, + sc->ndis_tmaps[sc->ndis_txidx], m, + ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT); + bus_dmamap_sync(sc->ndis_ttag, + sc->ndis_tmaps[sc->ndis_txidx], + BUS_DMASYNC_PREREAD); + p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist; + } + + NDIS_INC(sc); + sc->ndis_txpending--; + NDIS_UNLOCK(sc); + + pcnt++; + + /* + * If there's a BPF listener, bounce a copy of this frame + * to him. + */ + + BPF_MTAP(ifp, m); + + /* + * The array that p0 points to must appear contiguous, + * so we must not wrap past the end of sc->ndis_txarray[]. + * If it looks like we're about to wrap, break out here + * so the this batch of packets can be transmitted, then + * wait for txeof to ask us to send the rest. + */ + + if (sc->ndis_txidx == 0) + break; + } + + if (sc->ndis_txpending == 0) + ifp->if_flags |= IFF_OACTIVE; + + ndis_send_packets(sc, p0, pcnt); + + /* + * Set a timeout in case the chip goes out to lunch. + */ + ifp->if_timer = 5; + + return; +} + +static void +ndis_init(xsc) + void *xsc; +{ + struct ndis_softc *sc = xsc; + struct ifnet *ifp = &sc->arpcom.ac_if; + int i, error; + uint32_t ndis_filter = 0; + + /*NDIS_LOCK(sc);*/ + + /* + * Cancel pending I/O and free all RX/TX buffers. + */ + ndis_reset(sc); + ndis_stop(sc); + ndis_init_nic(sc); + + /* Init our MAC address */ +#ifdef notdef + /* + * Program the multicast filter, if necessary. + */ + ndis_setmulti(sc); +#endif + + /* Program the packet filter */ + + ndis_filter = NDIS_PACKET_TYPE_DIRECTED; + + if (ifp->if_flags & IFF_BROADCAST) + ndis_filter |= NDIS_PACKET_TYPE_BROADCAST; + + if (ifp->if_flags & IFF_PROMISC) + ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; + + if (ifp->if_flags & IFF_MULTICAST) + ndis_filter |= NDIS_PACKET_TYPE_MULTICAST; + + i = sizeof(ndis_filter); + + error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, + &ndis_filter, &i); + + if (error) + printf ("set filter failed: %d\n", error); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + if (sc->ndis_chars.nmc_checkhang_func != NULL) + sc->ndis_stat_ch = timeout(ndis_tick, sc, + hz * sc->ndis_block.nmb_checkforhangsecs); + + /*NDIS_UNLOCK(sc);*/ + + return; +} + +/* + * Set media options. + */ +static int +ndis_ifmedia_upd(ifp) + struct ifnet *ifp; +{ + struct ndis_softc *sc; + + sc = ifp->if_softc; + + if (ifp->if_flags & IFF_UP) + ndis_init(sc); + + return(0); +} + +/* + * Report current media status. + */ +static void +ndis_ifmedia_sts(ifp, ifmr) + struct ifnet *ifp; + struct ifmediareq *ifmr; +{ + struct ndis_softc *sc; + uint32_t media_info; + ndis_media_state linkstate; + int error, len; + + sc = ifp->if_softc; + + len = sizeof(linkstate); + error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS, + (void *)&linkstate, &len); + + len = sizeof(media_info); + error = ndis_get_info(sc, OID_GEN_LINK_SPEED, + (void *)&media_info, &len); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (linkstate == nmc_connected) + ifmr->ifm_status |= IFM_ACTIVE; + + switch(media_info) { + case 100000: + ifmr->ifm_active |= IFM_10_T; + break; + case 1000000: + ifmr->ifm_active |= IFM_100_TX; + break; + case 10000000: + ifmr->ifm_active |= IFM_1000_T; + break; + default: + printf("ndis%d: unknown speed: %d\n", + sc->ndis_unit, media_info); + break; + } + + return; +} + +static int +ndis_ioctl(ifp, command, data) + struct ifnet *ifp; + u_long command; + caddr_t data; +{ + struct ndis_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0; + + /*NDIS_LOCK(sc);*/ + + switch(command) { + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + ndis_init(sc); + } else { + if (ifp->if_flags & IFF_RUNNING) + ndis_stop(sc); + } + error = 0; + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + ndis_setmulti(sc); + error = 0; + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); + break; + default: + error = ether_ioctl(ifp, command, data); + break; + } + + /*NDIS_UNLOCK(sc);*/ + + return(error); +} + +static void +ndis_watchdog(ifp) + struct ifnet *ifp; +{ + struct ndis_softc *sc; + + sc = ifp->if_softc; + + NDIS_LOCK(sc); + ifp->if_oerrors++; + printf("ndis%d: watchdog timeout\n", sc->ndis_unit); + + ndis_reset(sc); + + if (ifp->if_snd.ifq_head != NULL) + ndis_start(ifp); + NDIS_UNLOCK(sc); + + return; +} + +/* + * Stop the adapter and free any mbufs allocated to the + * RX and TX lists. + */ +static void +ndis_stop(sc) + struct ndis_softc *sc; +{ + struct ifnet *ifp; + +/* NDIS_LOCK(sc);*/ + ifp = &sc->arpcom.ac_if; + ifp->if_timer = 0; + + untimeout(ndis_tick, sc, sc->ndis_stat_ch); + + ndis_halt_nic(sc); + + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + /*NDIS_UNLOCK(sc);*/ + + return; +} + +/* + * Stop all chip I/O so that the kernel's probe routines don't + * get confused by errant DMAs when rebooting. + */ +static void +ndis_shutdown(dev) + device_t dev; +{ + struct ndis_softc *sc; + + sc = device_get_softc(dev); +/* ndis_shutdown_nic(sc); */ + + return; +} diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h new file mode 100644 index 000000000000..7a762174ffe4 --- /dev/null +++ b/sys/dev/if_ndis/if_ndisvar.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define NDIS_PCI_LOIO 0x10 +#define NDIS_PCI_LOMEM 0x14 + + +struct ndis_chain_onefrag { + void *dummy; +}; + +struct ndis_chain { + void *dummy; +}; + +struct ndis_type { + uint16_t ndis_vid; + uint16_t ndis_did; + char *ndis_name; +}; + +struct ndis_shmem { + bus_dma_tag_t ndis_stag; + bus_dmamap_t ndis_smap; + void *ndis_saddr; + struct ndis_shmem *ndis_next; +}; + +struct ndis_cfglist { + ndis_cfg ndis_cfg; + TAILQ_ENTRY(ndis_cfglist) link; +}; + +TAILQ_HEAD(nch, ndis_cfglist); + +#define NDIS_INC(x) \ + (x)->ndis_txidx = ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts + +struct ndis_softc { + struct arpcom arpcom; /* interface info */ + struct ifmedia ifmedia; /* media info */ + bus_space_handle_t ndis_bhandle; + bus_space_tag_t ndis_btag; + void *ndis_intrhand; + struct resource *ndis_irq; + struct resource *ndis_res; + struct resource *ndis_res_io; + int ndis_io_rid; + struct resource *ndis_res_mem; + int ndis_mem_rid; + struct resource *ndis_res_altmem; + int ndis_altmem_rid; + struct resource *ndis_res_am; /* attribute mem (pccard) */ + struct resource *ndis_res_cm; /* common mem (pccard) */ + int ndis_rescnt; + struct mtx ndis_mtx; + device_t ndis_dev; + int ndis_unit; + ndis_miniport_block ndis_block; + ndis_miniport_characteristics ndis_chars; + interface_type ndis_type; + struct callout_handle ndis_stat_ch; + int ndis_maxpkts; + ndis_oid *ndis_oids; + int ndis_oidcnt; + int ndis_txidx; + int ndis_txpending; + ndis_packet **ndis_txarray; + int ndis_sc; + ndis_cfg *ndis_regvals; + struct nch ndis_cfglist_head; + + struct sysctl_ctx_list ndis_ctx; + struct sysctl_oid *ndis_tree; + interface_type ndis_iftype; + + bus_dma_tag_t ndis_parent_tag; + struct ndis_shmem *ndis_shlist; + bus_dma_tag_t ndis_mtag; + bus_dma_tag_t ndis_ttag; + bus_dmamap_t *ndis_mmaps; + bus_dmamap_t *ndis_tmaps; + struct mbuf **ndis_mbufs; + int ndis_mmapcnt; + +}; + +#define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx) +#define NDIS_UNLOCK(_sc) mtx_unlock(&(_sc)->ndis_mtx) + diff --git a/sys/modules/Makefile b/sys/modules/Makefile index d1ae6fe385f8..7d7db3f63397 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -53,6 +53,7 @@ SUBDIR= accf_data \ if_faith \ if_gif \ if_gre \ + if_ndis \ if_ppp \ if_sl \ if_stf \ @@ -90,6 +91,7 @@ SUBDIR= accf_data \ msdosfs \ msdosfs_iconv \ my \ + ndis \ nfsclient \ nfsserver \ nge \ diff --git a/sys/modules/if_ndis/Makefile b/sys/modules/if_ndis/Makefile new file mode 100644 index 000000000000..c2cd0c6f380b --- /dev/null +++ b/sys/modules/if_ndis/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../compat/ndis + +KMOD= if_ndis +SRCS= if_ndis.c +SRCS+= opt_bdg.h device_if.h bus_if.h pci_if.h card_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ndis/Makefile b/sys/modules/ndis/Makefile new file mode 100644 index 000000000000..acb5d1bdf0ee --- /dev/null +++ b/sys/modules/ndis/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/if_ndis + +KMOD= ndis +SRCS= subr_pe.c subr_ndis.c subr_hal.c subr_ntoskrnl.c kern_ndis.c +SRCS+= opt_bdg.h device_if.h bus_if.h pci_if.h card_if.h + +.include <bsd.kmod.mk> |