diff options
author | wpaul <wpaul@FreeBSD.org> | 2003-12-11 22:34:37 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2003-12-11 22:34:37 +0000 |
commit | 7e1ac581496c0d5c9235e96f48e6664b7783122e (patch) | |
tree | c45ddc74a90d2271d53841e2eeeace32996042a6 /sys | |
parent | 97c86c25fc58e99a248a81ad3dc02a7e00dcaee4 (diff) | |
download | FreeBSD-src-7e1ac581496c0d5c9235e96f48e6664b7783122e.zip FreeBSD-src-7e1ac581496c0d5c9235e96f48e6664b7783122e.tar.gz |
Commit the first cut of Project Evil, also known as the NDISulator.
Yes, it's what you think it is. Yes, you should run away now.
This is a special compatibility module for allowing Windows NDIS
miniport network drivers to be used with FreeBSD/x86. This provides
_binary_ NDIS compatibility (not source): you can run NDIS driver
code, but you can't build it. There are three main parts:
sys/compat/ndis: the NDIS compat API, which provides binary
compatibility functions for many routines in NDIS.SYS, HAL.dll
and ntoskrnl.exe in Windows (these are the three modules that
most NDIS miniport drivers use). The compat module also contains
a small PE relocator/dynalinker which relocates the Windows .SYS
image and then patches in our native routines.
sys/dev/if_ndis: the if_ndis driver wrapper. This module makes
use of the ndis compat API and can be compiled with a specially
prepared binary image file (ndis_driver_data.h) containing the
Windows .SYS image and registry key information parsed out of the
accompanying .INF file. Once if_ndis.ko is built, it can be loaded
and unloaded just like a native FreeBSD kenrel module.
usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf
into an ndis_driver_data.h file that can be compiled into if_ndis.o.
Contains an .inf file parser graciously provided by Matt Dodd (and
mercilessly hacked upon by me) that strips out device ID info and
registry key info from a .INF file and packages it up with a binary
image array. The ndiscvt(8) utility also does some manipulation of
the segments within the .sys file to make life easier for the kernel
loader. (Doing the manipulation here saves the kernel code from having
to move things around later, which would waste memory.)
ndiscvt is only built for the i386 arch. Only files.i386 has been
updated, and none of this is turned on in GENERIC. It should probably
work on pc98. I have no idea about amd64 or ia64 at this point.
This is still a work in progress. I estimate it's about %85 done, but
I want it under CVS control so I can track subsequent changes. It has
been tested with exactly three drivers: the LinkSys LNE100TX v4 driver
(Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK
(e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It
still needs to have a net80211 stuff added to it. To use it, you would
do something like this:
# cd /sys/modules/ndis
# make; make load
# cd /sys/modules/if_ndis
# ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h
# make; make load
# sysctl -a | grep ndis
All registry keys are mapped to sysctl nodes. Sometimes drivers refer
to registry keys that aren't mentioned in foo.inf. If this happens,
the NDIS API module creates sysctl nodes for these keys on the fly so
you can tweak them.
An example usage of the Broadcom wireless driver would be:
# sysctl hw.ndis0.EnableAutoConnect=1
# sysctl hw.ndis0.SSID="MY_SSID"
# sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc)
# ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up
Things to be done:
- get rid of debug messages
- add in ndis80211 support
- defer transmissions until after a status update with
NDIS_STATUS_CONNECTED occurs
- Create smarter lookaside list support
- Split off if_ndis_pci.c and if_ndis_pccard.c attachments
- Make sure PCMCIA support works
- Fix ndiscvt to properly parse PCMCIA device IDs from INF files
- write ndisapi.9 man page
Diffstat (limited to 'sys')
-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 |
17 files changed, 7128 insertions, 0 deletions
diff --git a/sys/compat/ndis/cfg_var.h b/sys/compat/ndis/cfg_var.h new file mode 100644 index 0000000..831239c --- /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 0000000..d18ae3e --- /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 0000000..b36831f --- /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 0000000..78bcfd2 --- /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 0000000..236d6fd --- /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 0000000..a0a2cc9 --- /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 0000000..079193b --- /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 0000000..442b7ef --- /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 0000000..f45b602 --- /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 0000000..04399c7 --- /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 0000000..8a2ae5b8 --- /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 34168ac..d46ce90 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 0000000..7a6b56a --- /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 0000000..7a76217 --- /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 d1ae6fe..7d7db3f 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 0000000..c2cd0c6 --- /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 0000000..acb5d1b --- /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> |