##
##
##
+source "ubuntu/ndiswrapper/Kconfig"
+##
+##
+##
##
##
##
##
##
##
+obj-$(CONFIG_NDISWRAPPER) += ndiswrapper/
+##
+##
+##
##
##
##
--- /dev/null
+Downloaded from: http://sourceforge.net/project/showfiles.php?group_id=93482
+Current Version: 1.55
--- /dev/null
+config NDISWRAPPER
+ tristate "Wrapper for Windows NDIS network drivers"
+ depends on NET
+ default m
--- /dev/null
+ndiswrapper-objs := crt.o hal.o iw_ndis.o loader.o ndis.o ntoskernel.o ntoskernel_io.o \
+ pe_linker.o pnp.o proc.o rtl.o wrapmem.o wrapndis.o wrapper.o usb.o
+
+EXPORTS = crt_exports.h hal_exports.h ndis_exports.h ntoskernel_exports.h \
+ ntoskernel_io_exports.h rtl_exports.h usb_exports.h
+
+STUB_SRCS = crt.c hal.c ndis.c ntoskernel.c ntoskernel_io.c \
+ pnp.c rtl.c wrapndis.c usb.c
+
+
+EXTRA_CFLAGS += -DENABLE_USB -I$(obj)
+EXTRA_AFLAGS += -I$(obj)
+
+# generate exports symbol table from C files
+quiet_cmd_mkexport = MKEXPORT $@
+cmd_mkexport = $(SHELL) $(srctree)/$(src)/mkexport.sh $< $@
+
+%_exports.h: %.c $(srctree)/$(src)/mkexport.sh FORCE
+ $(call if_changed,mkexport)
+
+$(addprefix $(obj)/,$(EXPORTS:_exports.h=.o)): %.o: %_exports.h
+extra-y += $(EXPORTS)
+
+ifeq ($(CONFIG_X86_64),y)
+quiet_cmd_mkstubs = MKSTUBS $@
+cmd_mkstubs = $(SHELL) $(srctree)/$(src)/mkstubs.sh $(addprefix $(srctree)/$(src)/,$(STUB_SRCS)) >$@
+
+$(obj)/win2lin_stubs.h: $(addprefix $(srctree)/$(src)/,$(STUB_SRCS)) FORCE
+ $(call if_changed,mkstubs)
+
+$(obj)/win2lin_stubs.o: $(obj)/win2lin_stubs.h
+extra-y += win2lin_stubs.h
+ndiswrapper-objs += win2lin_stubs.o
+else
+ndiswrapper-objs += divdi3.o
+endif
+
+obj-$(CONFIG_NDISWRAPPER) := ndiswrapper.o
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ntoskernel.h"
+#include "crt_exports.h"
+
+#ifdef CONFIG_X86_64
+/* Windows long is 32-bit, so strip single 'l' in integer formats */
+static void strip_l_modifier(char *str)
+{
+ char *ptr = str;
+ int in_format = 0;
+ char *lptr = NULL;
+ char last = 0;
+ char *end_ptr;
+ char *wptr;
+
+ /* Replace single 'l' inside integer formats with '\0' */
+ for (ptr = str; *ptr; ptr++) {
+ if (!in_format) {
+ if (*ptr == '%')
+ in_format = 1;
+ last = *ptr;
+ continue;
+ }
+ switch (*ptr) {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'p':
+ case 'n':
+ case 'm':
+ if (lptr) {
+ *lptr = '\0';
+ lptr = NULL;
+ }
+ in_format = 0;
+ break;
+ case 'c':
+ case 'C':
+ case 's':
+ case 'S':
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ lptr = NULL;
+ in_format = 0;
+ break;
+ case '%':
+ lptr = NULL;
+ if (last == '%')
+ in_format = 0;
+ else
+ in_format = 1; /* ignore previous junk */
+ break;
+ case 'l':
+ if (last == 'l')
+ lptr = NULL;
+ else
+ lptr = ptr;
+ break;
+ default:
+ break;
+ }
+ last = *ptr;
+ }
+
+ /* Purge zeroes from the resulting string */
+ end_ptr = ptr;
+ wptr = str;
+ for (ptr = str; ptr < end_ptr; ptr++)
+ if (*ptr != 0)
+ *(wptr++) = *ptr;
+ *wptr = 0;
+}
+
+/*
+ * va_list on x86_64 Linux is designed to allow passing arguments in registers
+ * even to variadic functions. va_list is a structure holding pointers to the
+ * register save area, which holds the arguments passed in registers, and to
+ * the stack, which may have the arguments that did not fit the registers.
+ * va_list also holds offsets in the register save area for the next general
+ * purpose and floating point registers that the next va_arg() would fetch.
+ *
+ * Unlike Linux, the Windows va_list is just a pointer to the stack. No
+ * arguments are passed in the registers. That's why we construct the Linux
+ * va_list so that the register save area is never used. For that goal, we set
+ * the offsets to the maximal allowed values, meaning that the arguments passed
+ * in the registers have been exhausted. The values are 48 for general purpose
+ * registers (6 registers, 8 bytes each) and 304 for floating point registers
+ * (16 registers, 16 bytes each, on top of general purpose register).
+ */
+
+struct x86_64_va_list {
+ int gp_offset;
+ int fp_offset;
+ void *overflow_arg_area;
+ void *reg_save_area;
+};
+
+#define VA_LIST_DECL(_args) \
+ va_list _args##new; \
+ struct x86_64_va_list *_args##x;
+#define VA_LIST_PREP(_args) \
+do { \
+ _args##x = (struct x86_64_va_list *)&_args##new; \
+ _args##x->gp_offset = 6 * 8; /* GP registers exhausted */ \
+ _args##x->fp_offset = 6 * 8 + 16 * 16; /* FP registers exhausted */ \
+ _args##x->overflow_arg_area = (void *)_args; \
+ _args##x->reg_save_area = NULL; \
+} while (0)
+#define VA_LIST_CONV(_args) (_args##new)
+#define VA_LIST_FREE(_args)
+#define FMT_DECL(_fmt) \
+ char *_fmt##copy; \
+ int _fmt##len;
+#define FMT_PREP(_fmt) \
+do { \
+ _fmt##len = strlen(format) + 1; \
+ _fmt##copy = kmalloc(_fmt##len, GFP_KERNEL); \
+ if (_fmt##copy) { \
+ memcpy(_fmt##copy, format, _fmt##len); \
+ strip_l_modifier(_fmt##copy); \
+ } \
+} while (0)
+#define FMT_CONV(_fmt) (_fmt##copy ? _fmt##copy : format)
+#define FMT_FREE(_fmt) kfree(_fmt##copy)
+
+#else /* !CONFIG_X86_64 */
+
+#define VA_LIST_DECL(_args)
+#define VA_LIST_PREP(_args)
+#define VA_LIST_CONV(_args) (_args)
+#define VA_LIST_FREE(_args)
+#define FMT_DECL(_fmt)
+#define FMT_PREP(_fmt)
+#define FMT_CONV(_fmt) (format)
+#define FMT_FREE(_fmt)
+
+#endif /* !CONFIG_X86_64 */
+
+noregparm INT WIN_FUNC(_win_sprintf,12)
+ (char *buf, const char *format, ...)
+{
+ va_list args;
+ int res;
+ FMT_DECL(format)
+
+ FMT_PREP(format);
+ va_start(args, format);
+ res = vsprintf(buf, FMT_CONV(format), args);
+ va_end(args);
+ FMT_FREE(format);
+
+ TRACE2("buf: %p: %s", buf, buf);
+ return res;
+}
+
+noregparm INT WIN_FUNC(swprintf,12)
+ (wchar_t *buf, const wchar_t *format, ...)
+{
+ TODO();
+ EXIT2(return 0);
+}
+
+noregparm INT WIN_FUNC(_win_vsprintf,3)
+ (char *str, const char *format, va_list ap)
+{
+ INT i;
+ VA_LIST_DECL(ap)
+ FMT_DECL(format)
+
+ VA_LIST_PREP(ap);
+ FMT_PREP(format);
+
+ i = vsprintf(str, FMT_CONV(format), VA_LIST_CONV(ap));
+ TRACE2("str: %p: %s", str, str);
+
+ FMT_FREE(format);
+ VA_LIST_FREE(ap);
+ EXIT2(return i);
+}
+
+noregparm INT WIN_FUNC(_win_snprintf,12)
+ (char *buf, SIZE_T count, const char *format, ...)
+{
+ va_list args;
+ int res;
+ FMT_DECL(format)
+
+ FMT_PREP(format);
+ va_start(args, format);
+ res = vsnprintf(buf, count, FMT_CONV(format), args);
+ va_end(args);
+ TRACE2("buf: %p: %s", buf, buf);
+
+ FMT_FREE(format);
+ return res;
+}
+
+noregparm INT WIN_FUNC(_win__snprintf,12)
+ (char *buf, SIZE_T count, const char *format, ...)
+{
+ va_list args;
+ int res;
+ FMT_DECL(format)
+
+ FMT_PREP(format);
+ va_start(args, format);
+ res = vsnprintf(buf, count, FMT_CONV(format), args);
+ va_end(args);
+ TRACE2("buf: %p: %s", buf, buf);
+
+ FMT_FREE(format);
+ return res;
+}
+
+noregparm INT WIN_FUNC(_win_vsnprintf,4)
+ (char *str, SIZE_T size, const char *format, va_list ap)
+{
+ INT i;
+ VA_LIST_DECL(ap)
+ FMT_DECL(format)
+
+ VA_LIST_PREP(ap);
+ FMT_PREP(format);
+
+ i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap));
+ TRACE2("str: %p: %s", str, str);
+
+ FMT_FREE(format);
+ VA_LIST_FREE(ap);
+ EXIT2(return i);
+}
+
+noregparm INT WIN_FUNC(_win__vsnprintf,4)
+ (char *str, SIZE_T size, const char *format, va_list ap)
+{
+ INT i;
+ VA_LIST_DECL(ap)
+ FMT_DECL(format)
+
+ VA_LIST_PREP(ap);
+ FMT_PREP(format);
+
+ i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap));
+ TRACE2("str: %p: %s", str, str);
+
+ FMT_FREE(format);
+ VA_LIST_FREE(ap);
+ EXIT2(return i);
+}
+
+noregparm char *WIN_FUNC(_win_strncpy,3)
+ (char *dst, char *src, SIZE_T n)
+{
+ return strncpy(dst, src, n);
+}
+
+noregparm SIZE_T WIN_FUNC(_win_strlen,1)
+ (const char *s)
+{
+ return strlen(s);
+}
+
+noregparm INT WIN_FUNC(_win_strncmp,3)
+ (const char *s1, const char *s2, SIZE_T n)
+{
+ return strncmp(s1, s2, n);
+}
+
+noregparm INT WIN_FUNC(_win_strcmp,2)
+ (const char *s1, const char *s2)
+{
+ return strcmp(s1, s2);
+}
+
+noregparm INT WIN_FUNC(_win_stricmp,2)
+ (const char *s1, const char *s2)
+{
+ return stricmp(s1, s2);
+}
+
+noregparm char *WIN_FUNC(_win_strncat,3)
+ (char *dest, const char *src, SIZE_T n)
+{
+ return strncat(dest, src, n);
+}
+
+noregparm INT WIN_FUNC(_win_wcscmp,2)
+ (const wchar_t *s1, const wchar_t *s2)
+{
+ while (*s1 && *s1 == *s2) {
+ s1++;
+ s2++;
+ }
+ return *s1 - *s2;
+}
+
+noregparm INT WIN_FUNC(_win_wcsicmp,2)
+ (const wchar_t *s1, const wchar_t *s2)
+{
+ while (*s1 && tolower((char)*s1) == tolower((char)*s2)) {
+ s1++;
+ s2++;
+ }
+ return tolower((char)*s1) - tolower((char)*s2);
+}
+
+noregparm SIZE_T WIN_FUNC(_win_wcslen,1)
+ (const wchar_t *s)
+{
+ const wchar_t *t = s;
+ while (*t)
+ t++;
+ return t - s;
+}
+
+noregparm wchar_t *WIN_FUNC(_win_wcsncpy,3)
+ (wchar_t *dest, const wchar_t *src, SIZE_T n)
+{
+ const wchar_t *s;
+ wchar_t *d;
+ s = src + n;
+ d = dest;
+ while (src < s && (*d++ = *src++))
+ ;
+ if (s > src)
+ memset(d, 0, (s - src) * sizeof(wchar_t));
+ return dest;
+}
+
+noregparm wchar_t *WIN_FUNC(_win_wcscpy,2)
+ (wchar_t *dest, const wchar_t *src)
+{
+ wchar_t *d = dest;
+ while ((*d++ = *src++))
+ ;
+ return dest;
+}
+
+noregparm wchar_t *WIN_FUNC(_win_wcscat,2)
+ (wchar_t *dest, const wchar_t *src)
+{
+ wchar_t *d;
+ d = dest;
+ while (*d)
+ d++;
+ while ((*d++ = *src++))
+ ;
+ return dest;
+}
+
+noregparm INT WIN_FUNC(_win_towupper,1)
+ (wchar_t c)
+{
+ return toupper(c);
+}
+
+noregparm INT WIN_FUNC(_win_towlower,1)
+ (wchar_t c)
+{
+ return tolower(c);
+}
+
+noregparm INT WIN_FUNC(_win_tolower,1)
+ (INT c)
+{
+ return tolower(c);
+}
+
+noregparm INT WIN_FUNC(_win_toupper,1)
+ (INT c)
+{
+ return toupper(c);
+}
+
+noregparm void *WIN_FUNC(_win_strcpy,2)
+ (void *to, const void *from)
+{
+ return strcpy(to, from);
+}
+
+noregparm char *WIN_FUNC(_win_strstr,2)
+ (const char *s1, const char *s2)
+{
+ return strstr(s1, s2);
+}
+
+noregparm char *WIN_FUNC(_win_strchr,2)
+ (const char *s, int c)
+{
+ return strchr(s, c);
+}
+
+noregparm char *WIN_FUNC(_win_strrchr,2)
+ (const char *s, int c)
+{
+ return strrchr(s, c);
+}
+
+noregparm void *WIN_FUNC(_win_memmove,3)
+ (void *to, void *from, SIZE_T count)
+{
+ return memmove(to, from, count);
+}
+
+noregparm void *WIN_FUNC(_win_memchr,3)
+ (const void *s, INT c, SIZE_T n)
+{
+ return memchr(s, c, n);
+}
+
+noregparm void *WIN_FUNC(_win_memcpy,3)
+ (void *to, const void *from, SIZE_T n)
+{
+ return memcpy(to, from, n);
+}
+
+noregparm void *WIN_FUNC(_win_memset,3)
+ (void *s, char c, SIZE_T count)
+{
+ return memset(s, c, count);
+}
+
+noregparm int WIN_FUNC(_win_memcmp,3)
+ (void *s1, void *s2, SIZE_T n)
+{
+ return memcmp(s1, s2, n);
+}
+
+noregparm void WIN_FUNC(_win_srand,1)
+ (UINT seed)
+{
+ net_srandom(seed);
+}
+
+noregparm int WIN_FUNC(rand,0)
+ (void)
+{
+ char buf[6];
+ int i, n;
+
+ get_random_bytes(buf, sizeof(buf));
+ for (n = i = 0; i < sizeof(buf) ; i++)
+ n += buf[i];
+ return n;
+}
+
+noregparm int WIN_FUNC(_win_atoi,1)
+ (const char *ptr)
+{
+ int i = simple_strtol(ptr, NULL, 10);
+ return i;
+}
+
+noregparm int WIN_FUNC(_win_isprint,1)
+ (int c)
+{
+ return isprint(c);
+}
+
+wstdcall s64 WIN_FUNC(_alldiv,2)
+ (s64 a, s64 b)
+{
+ return a / b;
+}
+
+wstdcall u64 WIN_FUNC(_aulldiv,2)
+ (u64 a, u64 b)
+{
+ return a / b;
+}
+
+wstdcall s64 WIN_FUNC(_allmul,2)
+ (s64 a, s64 b)
+{
+ return a * b;
+}
+
+wstdcall u64 WIN_FUNC(_aullmul,2)
+ (u64 a, u64 b)
+{
+ return a * b;
+}
+
+wstdcall s64 WIN_FUNC(_allrem,2)
+ (s64 a, s64 b)
+{
+ return a % b;
+}
+
+wstdcall u64 WIN_FUNC(_aullrem,2)
+ (u64 a, u64 b)
+{
+ return a % b;
+}
+
+__attribute__((regparm(3))) s64 WIN_FUNC(_allshl,2)
+ (s64 a, u8 b)
+{
+ return a << b;
+}
+
+__attribute__((regparm(3))) u64 WIN_FUNC(_aullshl,2)
+ (u64 a, u8 b)
+{
+ return a << b;
+}
+
+__attribute__((regparm(3))) s64 WIN_FUNC(_allshr,2)
+ (s64 a, u8 b)
+{
+ return a >> b;
+}
+
+__attribute__((regparm(3))) u64 WIN_FUNC(_aullshr,2)
+ (u64 a, u8 b)
+{
+ return a >> b;
+}
+
+int stricmp(const char *s1, const char *s2)
+{
+ while (*s1 && tolower(*s1) == tolower(*s2)) {
+ s1++;
+ s2++;
+ }
+ return *s1 - *s2;
+}
+
+void dump_bytes(const char *ctx, const u8 *from, int len)
+{
+ int i, j;
+ u8 *buf;
+
+ buf = kmalloc(len * 3 + 1, irql_gfp());
+ if (!buf) {
+ ERROR("couldn't allocate memory");
+ return;
+ }
+ for (i = j = 0; i < len; i++, j += 3) {
+ sprintf(&buf[j], "%02x ", from[i]);
+ }
+ buf[j] = 0;
+ printk(KERN_DEBUG "%s: %p: %s\n", ctx, from, buf);
+ kfree(buf);
+}
+
+int crt_init(void)
+{
+ return 0;
+}
+
+/* called when module is being removed */
+void crt_exit(void)
+{
+ EXIT4(return);
+}
--- /dev/null
+/* 64-bit multiplication and division
+ Copyright (C) 1989, 1992-1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#if BITS_PER_LONG != 32
+#error This is for 32-bit targets only
+#endif
+
+typedef unsigned int UQItype __attribute__ ((mode (QI)));
+typedef int SItype __attribute__ ((mode (SI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+#define Wtype SItype
+#define HWtype SItype
+#define DWtype DItype
+#define UWtype USItype
+#define UHWtype USItype
+#define UDWtype UDItype
+#define W_TYPE_SIZE 32
+
+#include "longlong.h"
+
+#if defined(__BIG_ENDIAN)
+struct DWstruct { Wtype high, low;};
+#elif defined(__LITTLE_ENDIAN)
+struct DWstruct { Wtype low, high;};
+#else
+#error Unhandled endianity
+#endif
+typedef union { struct DWstruct s; DWtype ll; } DWunion;
+
+/* Prototypes of exported functions. */
+extern DWtype __divdi3 (DWtype u, DWtype v);
+extern DWtype __moddi3 (DWtype u, DWtype v);
+extern UDWtype __udivdi3 (UDWtype u, UDWtype v);
+extern UDWtype __umoddi3 (UDWtype u, UDWtype v);
+
+static UDWtype
+__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
+{
+ DWunion ww;
+ DWunion nn, dd;
+ DWunion rr;
+ UWtype d0, d1, n0, n1, n2;
+ UWtype q0, q1;
+ UWtype b, bm;
+
+ nn.ll = n;
+ dd.ll = d;
+
+ d0 = dd.s.low;
+ d1 = dd.s.high;
+ n0 = nn.s.low;
+ n1 = nn.s.high;
+
+#if !UDIV_NEEDS_NORMALIZATION
+ if (d1 == 0)
+ {
+ if (d0 > n1)
+ {
+ /* 0q = nn / 0D */
+
+ udiv_qrnnd (q0, n0, n1, n0, d0);
+ q1 = 0;
+
+ /* Remainder in n0. */
+ }
+ else
+ {
+ /* qq = NN / 0d */
+
+ if (d0 == 0)
+ d0 = 1 / d0; /* Divide intentionally by zero. */
+
+ udiv_qrnnd (q1, n1, 0, n1, d0);
+ udiv_qrnnd (q0, n0, n1, n0, d0);
+
+ /* Remainder in n0. */
+ }
+
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = 0;
+ *rp = rr.ll;
+ }
+ }
+
+#else /* UDIV_NEEDS_NORMALIZATION */
+
+ if (d1 == 0)
+ {
+ if (d0 > n1)
+ {
+ /* 0q = nn / 0D */
+
+ count_leading_zeros (bm, d0);
+
+ if (bm != 0)
+ {
+ /* Normalize, i.e. make the most significant bit of the
+ denominator set. */
+
+ d0 = d0 << bm;
+ n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
+ n0 = n0 << bm;
+ }
+
+ udiv_qrnnd (q0, n0, n1, n0, d0);
+ q1 = 0;
+
+ /* Remainder in n0 >> bm. */
+ }
+ else
+ {
+ /* qq = NN / 0d */
+
+ if (d0 == 0)
+ d0 = 1 / d0; /* Divide intentionally by zero. */
+
+ count_leading_zeros (bm, d0);
+
+ if (bm == 0)
+ {
+ /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
+ conclude (the most significant bit of n1 is set) /\ (the
+ leading quotient digit q1 = 1).
+
+ This special case is necessary, not an optimization.
+ (Shifts counts of W_TYPE_SIZE are undefined.) */
+
+ n1 -= d0;
+ q1 = 1;
+ }
+ else
+ {
+ /* Normalize. */
+
+ b = W_TYPE_SIZE - bm;
+
+ d0 = d0 << bm;
+ n2 = n1 >> b;
+ n1 = (n1 << bm) | (n0 >> b);
+ n0 = n0 << bm;
+
+ udiv_qrnnd (q1, n1, n2, n1, d0);
+ }
+
+ /* n1 != d0... */
+
+ udiv_qrnnd (q0, n0, n1, n0, d0);
+
+ /* Remainder in n0 >> bm. */
+ }
+
+ if (rp != 0)
+ {
+ rr.s.low = n0 >> bm;
+ rr.s.high = 0;
+ *rp = rr.ll;
+ }
+ }
+#endif /* UDIV_NEEDS_NORMALIZATION */
+
+ else
+ {
+ if (d1 > n1)
+ {
+ /* 00 = nn / DD */
+
+ q0 = 0;
+ q1 = 0;
+
+ /* Remainder in n1n0. */
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = n1;
+ *rp = rr.ll;
+ }
+ }
+ else
+ {
+ /* 0q = NN / dd */
+
+ count_leading_zeros (bm, d1);
+ if (bm == 0)
+ {
+ /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
+ conclude (the most significant bit of n1 is set) /\ (the
+ quotient digit q0 = 0 or 1).
+
+ This special case is necessary, not an optimization. */
+
+ /* The condition on the next line takes advantage of that
+ n1 >= d1 (true due to program flow). */
+ if (n1 > d1 || n0 >= d0)
+ {
+ q0 = 1;
+ sub_ddmmss (n1, n0, n1, n0, d1, d0);
+ }
+ else
+ q0 = 0;
+
+ q1 = 0;
+
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = n1;
+ *rp = rr.ll;
+ }
+ }
+ else
+ {
+ UWtype m1, m0;
+ /* Normalize. */
+
+ b = W_TYPE_SIZE - bm;
+
+ d1 = (d1 << bm) | (d0 >> b);
+ d0 = d0 << bm;
+ n2 = n1 >> b;
+ n1 = (n1 << bm) | (n0 >> b);
+ n0 = n0 << bm;
+
+ udiv_qrnnd (q0, n1, n2, n1, d1);
+ umul_ppmm (m1, m0, q0, d0);
+
+ if (m1 > n1 || (m1 == n1 && m0 > n0))
+ {
+ q0--;
+ sub_ddmmss (m1, m0, m1, m0, d1, d0);
+ }
+
+ q1 = 0;
+
+ /* Remainder in (n1n0 - m1m0) >> bm. */
+ if (rp != 0)
+ {
+ sub_ddmmss (n1, n0, n1, n0, m1, m0);
+ rr.s.low = (n1 << b) | (n0 >> bm);
+ rr.s.high = n1 >> bm;
+ *rp = rr.ll;
+ }
+ }
+ }
+ }
+
+ ww.s.low = q0;
+ ww.s.high = q1;
+ return ww.ll;
+}
+
+DWtype
+__divdi3 (DWtype u, DWtype v)
+{
+ Wtype c = 0;
+ DWtype w;
+
+ if (u < 0)
+ {
+ c = ~c;
+ u = -u;
+ }
+ if (v < 0)
+ {
+ c = ~c;
+ v = -v;
+ }
+ w = __udivmoddi4 (u, v, NULL);
+ if (c)
+ w = -w;
+ return w;
+}
+
+DWtype
+__moddi3 (DWtype u, DWtype v)
+{
+ Wtype c = 0;
+ DWtype w;
+
+ if (u < 0)
+ {
+ c = ~c;
+ u = -u;
+ }
+ if (v < 0)
+ v = -v;
+ __udivmoddi4 (u, v, &w);
+ if (c)
+ w = -w;
+ return w;
+}
+
+UDWtype
+__udivdi3 (UDWtype u, UDWtype v)
+{
+ return __udivmoddi4 (u, v, NULL);
+}
+
+UDWtype
+__umoddi3 (UDWtype u, UDWtype v)
+{
+ UDWtype w;
+
+ __udivmoddi4 (u, v, &w);
+ return w;
+}
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ntoskernel.h"
+#include "hal_exports.h"
+
+wstdcall void WIN_FUNC(WRITE_PORT_ULONG,2)
+ (ULONG_PTR port, ULONG value)
+{
+ outl(value, port);
+}
+
+wstdcall ULONG WIN_FUNC(READ_PORT_ULONG,1)
+ (ULONG_PTR port)
+{
+ return inl(port);
+}
+
+wstdcall void WIN_FUNC(WRITE_PORT_USHORT,2)
+ (ULONG_PTR port, USHORT value)
+{
+ outw(value, port);
+}
+
+wstdcall USHORT WIN_FUNC(READ_PORT_USHORT,1)
+ (ULONG_PTR port)
+{
+ return inw(port);
+}
+
+wstdcall void WIN_FUNC(WRITE_PORT_UCHAR,2)
+ (ULONG_PTR port, UCHAR value)
+{
+ outb(value, port);
+}
+
+wstdcall UCHAR WIN_FUNC(READ_PORT_UCHAR,1)
+ (ULONG_PTR port)
+{
+ return inb(port);
+}
+
+wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_USHORT,3)
+ (ULONG_PTR port, USHORT *buf, ULONG count)
+{
+ outsw(port, buf, count);
+}
+
+wstdcall void WIN_FUNC(READ_PORT_BUFFER_USHORT,3)
+ (ULONG_PTR port, USHORT *buf, ULONG count)
+{
+ insw(port, buf, count);
+}
+
+wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_ULONG,3)
+ (ULONG_PTR port, ULONG *buf, ULONG count)
+{
+ outsl(port, buf, count);
+}
+
+wstdcall void WIN_FUNC(READ_PORT_BUFFER_ULONG,3)
+ (ULONG_PTR port, ULONG *buf, ULONG count)
+{
+ insl(port, buf, count);
+}
+
+wstdcall USHORT WIN_FUNC(READ_REGISTER_USHORT,1)
+ (void __iomem *reg)
+{
+ return readw(reg);
+}
+
+wstdcall void WIN_FUNC(WRITE_REGISTER_ULONG,2)
+ (void __iomem *reg, UINT val)
+{
+ writel(val, reg);
+}
+
+wstdcall void WIN_FUNC(WRITE_REGISTER_USHORT,2)
+ (void __iomem *reg, USHORT val)
+{
+ writew(val, reg);
+}
+
+wstdcall void WIN_FUNC(WRITE_REGISTER_UCHAR,2)
+ (void __iomem *reg, UCHAR val)
+{
+ writeb(val, reg);
+}
+
+wstdcall void WIN_FUNC(KeStallExecutionProcessor,1)
+ (ULONG usecs)
+{
+ udelay(usecs);
+}
+
+wstdcall KIRQL WIN_FUNC(KeGetCurrentIrql,0)
+ (void)
+{
+ return current_irql();
+}
+
+wfastcall KIRQL WIN_FUNC(KfRaiseIrql,1)
+ (KIRQL newirql)
+{
+ return raise_irql(newirql);
+}
+
+wfastcall void WIN_FUNC(KfLowerIrql,1)
+ (KIRQL oldirql)
+{
+ lower_irql(oldirql);
+}
+
+wfastcall KIRQL WIN_FUNC(KfAcquireSpinLock,1)
+ (NT_SPIN_LOCK *lock)
+{
+ return nt_spin_lock_irql(lock, DISPATCH_LEVEL);
+}
+
+wfastcall void WIN_FUNC(KfReleaseSpinLock,2)
+ (NT_SPIN_LOCK *lock, KIRQL oldirql)
+{
+ nt_spin_unlock_irql(lock, oldirql);
+}
+
+wfastcall void WIN_FUNC(KefAcquireSpinLockAtDpcLevel,1)
+ (NT_SPIN_LOCK *lock)
+{
+#ifdef DEBUG_IRQL
+ if (current_irql() != DISPATCH_LEVEL)
+ ERROR("irql != DISPATCH_LEVEL");
+#endif
+ nt_spin_lock(lock);
+}
+
+wfastcall void WIN_FUNC(KefReleaseSpinLockFromDpcLevel,1)
+ (NT_SPIN_LOCK *lock)
+{
+#ifdef DEBUG_IRQL
+ if (current_irql() != DISPATCH_LEVEL)
+ ERROR("irql != DISPATCH_LEVEL");
+#endif
+ nt_spin_unlock(lock);
+}
--- /dev/null
+ /*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_arp.h>
+#include <linux/usb.h>
+#include <linux/random.h>
+
+#include <net/iw_handler.h>
+#include <linux/rtnetlink.h>
+#include <asm/uaccess.h>
+
+#include "iw_ndis.h"
+#include "wrapndis.h"
+
+static int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484 };
+
+static const char *network_names[] = {"IEEE 802.11FH", "IEEE 802.11b",
+ "IEEE 802.11a", "IEEE 802.11g", "Auto"};
+
+int set_essid(struct ndis_device *wnd, const char *ssid, int ssid_len)
+{
+ NDIS_STATUS res;
+ struct ndis_essid req;
+
+ if (ssid_len > NDIS_ESSID_MAX_SIZE)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ req.length = ssid_len;
+ if (ssid_len)
+ memcpy(&req.essid, ssid, ssid_len);
+
+ res = mp_set(wnd, OID_802_11_SSID, &req, sizeof(req));
+ if (res) {
+ WARNING("setting essid failed (%08X)", res);
+ EXIT2(return -EINVAL);
+ }
+ memcpy(&wnd->essid, &req, sizeof(req));
+ EXIT2(return 0);
+}
+
+static int set_assoc_params(struct ndis_device *wnd)
+{
+ TRACE2("wpa_version=0x%x auth_alg=0x%x key_mgmt=0x%x "
+ "cipher_pairwise=0x%x cipher_group=0x%x",
+ wnd->iw_auth_wpa_version, wnd->iw_auth_80211_alg,
+ wnd->iw_auth_key_mgmt, wnd->iw_auth_cipher_pairwise,
+ wnd->iw_auth_cipher_group);
+ set_auth_mode(wnd);
+ set_priv_filter(wnd);
+ set_encr_mode(wnd);
+ return 0;
+}
+
+static int iw_set_essid(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ char ssid[NDIS_ESSID_MAX_SIZE];
+ int length;
+
+ ENTER2("");
+ memset(ssid, 0, sizeof(ssid));
+ /* there is no way to turn off essid other than to set to
+ * random bytes; instead, we use off to mean any */
+ if (wrqu->essid.flags) {
+ /* wireless-tools prior to version 20 add extra 1, and
+ * later than 20 don't! Deal with that mess */
+ length = wrqu->essid.length - 1;
+ if (length > 0)
+ length--;
+ while (length < wrqu->essid.length && extra[length])
+ length++;
+ TRACE2("%d", length);
+ if (length <= 0 || length > NDIS_ESSID_MAX_SIZE)
+ EXIT2(return -EINVAL);
+ } else
+ length = 0;
+
+ set_assoc_params(wnd);
+
+ memcpy(ssid, extra, length);
+ if (set_essid(wnd, ssid, length))
+ EXIT2(return -EINVAL);
+
+ EXIT2(return 0);
+}
+
+static int iw_get_essid(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ struct ndis_essid req;
+
+ ENTER2("");
+ memset(&req, 0, sizeof(req));
+ res = mp_query(wnd, OID_802_11_SSID, &req, sizeof(req));
+ if (res) {
+ WARNING("getting essid failed (%08X)", res);
+ EXIT2(return -EOPNOTSUPP);
+ }
+ memcpy(extra, req.essid, req.length);
+ if (req.length > 0)
+ wrqu->essid.flags = 1;
+ else
+ wrqu->essid.flags = 0;
+ wrqu->essid.length = req.length;
+ EXIT2(return 0);
+}
+
+int set_infra_mode(struct ndis_device *wnd,
+ enum ndis_infrastructure_mode mode)
+{
+ NDIS_STATUS res;
+ unsigned int i;
+
+ ENTER2("%d", mode);
+ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE,
+ &wnd->infrastructure_mode);
+ if (res != NDIS_STATUS_SUCCESS) {
+ WARNING("getting operating mode to failed (%08X)", res);
+ EXIT2(return -EINVAL);
+ }
+ if (wnd->infrastructure_mode == mode)
+ EXIT2(return 0);
+ res = mp_set_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, mode);
+ if (res) {
+ WARNING("setting operating mode to %d failed (%08X)",
+ mode, res);
+ EXIT2(return -EINVAL);
+ }
+ /* NDIS drivers clear keys when infrastructure mode is
+ * changed. But Linux tools assume otherwise. So set the
+ * keys */
+ if (wnd->iw_auth_key_mgmt == 0 ||
+ wnd->iw_auth_key_mgmt == IW_AUTH_KEY_MGMT_802_1X) {
+ for (i = 0; i < MAX_ENCR_KEYS; i++) {
+ if (wnd->encr_info.keys[i].length > 0)
+ add_wep_key(wnd, wnd->encr_info.keys[i].key,
+ wnd->encr_info.keys[i].length, i);
+ }
+ }
+ wnd->infrastructure_mode = mode;
+ EXIT2(return 0);
+}
+
+static int iw_set_infra_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ enum ndis_infrastructure_mode ndis_mode;
+
+ ENTER2("%d", wrqu->mode);
+ switch (wrqu->mode) {
+ case IW_MODE_ADHOC:
+ ndis_mode = Ndis802_11IBSS;
+ break;
+ case IW_MODE_INFRA:
+ ndis_mode = Ndis802_11Infrastructure;
+ break;
+ case IW_MODE_AUTO:
+ ndis_mode = Ndis802_11AutoUnknown;
+ break;
+ default:
+ EXIT2(return -EINVAL);
+ }
+
+ if (set_infra_mode(wnd, ndis_mode))
+ EXIT2(return -EINVAL);
+
+ EXIT2(return 0);
+}
+
+static int iw_get_infra_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ int ndis_mode, iw_mode;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &ndis_mode);
+ if (res) {
+ WARNING("getting operating mode failed (%08X)", res);
+ EXIT2(return -EOPNOTSUPP);
+ }
+
+ switch(ndis_mode) {
+ case Ndis802_11IBSS:
+ iw_mode = IW_MODE_ADHOC;
+ break;
+ case Ndis802_11Infrastructure:
+ iw_mode = IW_MODE_INFRA;
+ break;
+ case Ndis802_11AutoUnknown:
+ iw_mode = IW_MODE_AUTO;
+ break;
+ default:
+ ERROR("invalid operating mode (%u)", ndis_mode);
+ EXIT2(return -EINVAL);
+ }
+ wrqu->mode = iw_mode;
+ EXIT2(return 0);
+}
+
+static const char *network_type_to_name(int net_type)
+{
+ if (net_type >= 0 &&
+ net_type < (sizeof(network_names)/sizeof(network_names[0])))
+ return network_names[net_type];
+ else
+ return network_names[sizeof(network_names) /
+ sizeof(network_names[0]) - 1];
+}
+
+static int iw_get_network_type(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ unsigned int network_type;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ res = mp_query_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE,
+ &network_type);
+ if (res) {
+ WARNING("getting network type failed: %08X", res);
+ network_type = -1;
+ }
+ strncpy(wrqu->name, network_type_to_name(network_type),
+ sizeof(wrqu->name) - 1);
+ wrqu->name[sizeof(wrqu->name)-1] = 0;
+ return 0;
+}
+
+static int iw_get_freq(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ struct ndis_configuration req;
+
+ ENTER2("");
+ memset(&req, 0, sizeof(req));
+ res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req));
+ if (res) {
+ WARNING("getting configuration failed (%08X)", res);
+ EXIT2(return -EOPNOTSUPP);
+ }
+
+ memset(&(wrqu->freq), 0, sizeof(struct iw_freq));
+
+ /* see comment in wireless.h above the "struct iw_freq"
+ definition for an explanation of this if
+ NOTE: 1000000 is due to the kHz
+ */
+ if (req.ds_config > 1000000) {
+ wrqu->freq.m = req.ds_config / 10;
+ wrqu->freq.e = 1;
+ }
+ else
+ wrqu->freq.m = req.ds_config;
+
+ /* convert from kHz to Hz */
+ wrqu->freq.e += 3;
+
+ return 0;
+}
+
+static int iw_set_freq(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ struct ndis_configuration req;
+
+ ENTER2("");
+ /* this OID is valid only when not associated */
+ if (netif_carrier_ok(wnd->net_dev))
+ EXIT2(return 0);
+ memset(&req, 0, sizeof(req));
+ res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req));
+ if (res) {
+ WARNING("getting configuration failed (%08X)", res);
+ EXIT2(return 0);
+ }
+
+ if (wrqu->freq.m < 1000 && wrqu->freq.e == 0) {
+ if (wrqu->freq.m >= 1 &&
+ wrqu->freq.m <= (sizeof(freq_chan) / sizeof(freq_chan[0])))
+ req.ds_config = freq_chan[wrqu->freq.m - 1] * 1000;
+ else
+ return -EINVAL;
+ } else {
+ int i;
+ req.ds_config = wrqu->freq.m;
+ for (i = wrqu->freq.e; i > 0; i--)
+ req.ds_config *= 10;
+ req.ds_config /= 1000;
+ }
+ res = mp_set(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req));
+ if (res)
+ WARNING("setting configuration failed (%08X)", res);
+ return 0;
+}
+
+static int iw_get_tx_power(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ ndis_tx_power_level ndis_power;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL,
+ &ndis_power, sizeof(ndis_power));
+ if (res)
+ return -EOPNOTSUPP;
+ wrqu->txpower.flags = IW_TXPOW_MWATT;
+ wrqu->txpower.disabled = 0;
+ wrqu->txpower.fixed = 0;
+ wrqu->txpower.value = ndis_power;
+ return 0;
+}
+
+static int iw_set_tx_power(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ ndis_tx_power_level ndis_power;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ if (wrqu->txpower.disabled)
+ ndis_power = 0;
+ else {
+ if (wrqu->txpower.flags == IW_TXPOW_MWATT)
+ ndis_power = wrqu->txpower.value;
+ else { // wrqu->txpower.flags == IW_TXPOW_DBM
+ if (wrqu->txpower.value > 20)
+ ndis_power = 128;
+ else if (wrqu->txpower.value < -43)
+ ndis_power = 127;
+ else {
+ signed char tmp;
+ tmp = wrqu->txpower.value;
+ tmp = -12 - tmp;
+ tmp <<= 2;
+ ndis_power = (unsigned char)tmp;
+ }
+ }
+ }
+ TRACE2("%d", ndis_power);
+ res = mp_set(wnd, OID_802_11_TX_POWER_LEVEL,
+ &ndis_power, sizeof(ndis_power));
+ if (res)
+ EXIT2(return -EOPNOTSUPP);
+ if (ndis_power == 0)
+ res = disassociate(wnd, 0);
+ EXIT2(return 0);
+}
+
+static int iw_get_bitrate(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ ULONG ndis_rate;
+ int res;
+
+ ENTER2("");
+ res = mp_query(wnd, OID_GEN_LINK_SPEED, &ndis_rate, sizeof(ndis_rate));
+ if (res) {
+ WARNING("getting bitrate failed (%08X)", res);
+ ndis_rate = 0;
+ }
+
+ wrqu->bitrate.value = ndis_rate * 100;
+ return 0;
+}
+
+static int iw_set_bitrate(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ int i, n;
+ NDIS_STATUS res;
+ ndis_rates_ex rates;
+
+ ENTER2("");
+ if (wrqu->bitrate.fixed == 0)
+ EXIT2(return 0);
+
+ res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, &rates,
+ sizeof(rates), &n, NULL);
+ if (res) {
+ WARNING("getting bit rate failed (%08X)", res);
+ EXIT2(return 0);
+ }
+ for (i = 0; i < n; i++) {
+ if (rates[i] & 0x80)
+ continue;
+ if ((rates[i] & 0x7f) * 500000 > wrqu->bitrate.value) {
+ TRACE2("setting rate %d to 0",
+ (rates[i] & 0x7f) * 500000);
+ rates[i] = 0;
+ }
+ }
+
+ res = mp_set(wnd, OID_802_11_DESIRED_RATES, &rates, n);
+ if (res) {
+ WARNING("setting bit rate failed (%08X)", res);
+ EXIT2(return 0);
+ }
+
+ return 0;
+}
+
+static int iw_set_dummy(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /* Do nothing. Used for ioctls that are not implemented. */
+ return 0;
+}
+
+static int iw_get_rts_threshold(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ ndis_rts_threshold threshold;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ res = mp_query(wnd, OID_802_11_RTS_THRESHOLD,
+ &threshold, sizeof(threshold));
+ if (res)
+ return -EOPNOTSUPP;
+
+ wrqu->rts.value = threshold;
+ return 0;
+}
+
+static int iw_set_rts_threshold(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ ndis_rts_threshold threshold;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ threshold = wrqu->rts.value;
+ res = mp_set(wnd, OID_802_11_RTS_THRESHOLD,
+ &threshold, sizeof(threshold));
+ if (res == NDIS_STATUS_INVALID_DATA)
+ return -EINVAL;
+ if (res)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int iw_get_frag_threshold(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ ndis_fragmentation_threshold frag_threshold;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD,
+ &frag_threshold, sizeof(frag_threshold));
+ if (res)
+ return -ENOTSUPP;
+
+ wrqu->frag.value = frag_threshold;
+ return 0;
+}
+
+static int iw_set_frag_threshold(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ ndis_rts_threshold threshold;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ threshold = wrqu->frag.value;
+ res = mp_set(wnd, OID_802_11_FRAGMENTATION_THRESHOLD,
+ &threshold, sizeof(threshold));
+ if (res == NDIS_STATUS_INVALID_DATA)
+ return -EINVAL;
+ if (res)
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+int get_ap_address(struct ndis_device *wnd, mac_address ap_addr)
+{
+ NDIS_STATUS res;
+
+ res = mp_query(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN);
+ TRACE2(MACSTRSEP, MAC2STR(ap_addr));
+ if (res) {
+ TRACE2("res: %08X", res);
+ memset(ap_addr, 0x0, ETH_ALEN);
+ EXIT2(return -EOPNOTSUPP);
+ }
+ EXIT2(return 0);
+}
+
+static int iw_get_ap_address(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ mac_address ap_addr;
+
+ ENTER2("");
+ get_ap_address(wnd, ap_addr);
+ memcpy(wrqu->ap_addr.sa_data, ap_addr, ETH_ALEN);
+ wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+ EXIT2(return 0);
+}
+
+static int iw_set_ap_address(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ mac_address ap_addr;
+
+ ENTER2("");
+ memcpy(ap_addr, wrqu->ap_addr.sa_data, ETH_ALEN);
+ TRACE2(MACSTRSEP, MAC2STR(ap_addr));
+ res = mp_set(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN);
+ /* user apps may set ap's mac address, which is not required;
+ * they may fail to work if this function fails, so return
+ * success */
+ if (res)
+ WARNING("setting AP mac address failed (%08X)", res);
+
+ EXIT2(return 0);
+}
+
+int set_iw_auth_mode(struct ndis_device *wnd, int wpa_version,
+ int auth_80211_alg)
+{
+ NDIS_STATUS res;
+ ULONG auth_mode;
+
+ ENTER2("%d, %d", wpa_version, auth_80211_alg);
+ if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) {
+ if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X)
+ auth_mode = Ndis802_11AuthModeWPA2;
+ else
+ auth_mode = Ndis802_11AuthModeWPA2PSK;
+ } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) {
+ if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X)
+ auth_mode = Ndis802_11AuthModeWPA;
+ else if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_PSK)
+ auth_mode = Ndis802_11AuthModeWPAPSK;
+ else
+ auth_mode = Ndis802_11AuthModeWPANone;
+ } else if (auth_80211_alg & IW_AUTH_ALG_SHARED_KEY) {
+ if (auth_80211_alg & IW_AUTH_ALG_OPEN_SYSTEM)
+ auth_mode = Ndis802_11AuthModeAutoSwitch;
+ else
+ auth_mode = Ndis802_11AuthModeShared;
+ } else
+ auth_mode = Ndis802_11AuthModeOpen;
+
+ res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode);
+ if (res) {
+ WARNING("setting auth mode to %u failed (%08X)",
+ auth_mode, res);
+ if (res == NDIS_STATUS_INVALID_DATA)
+ EXIT2(return -EINVAL);
+ return -EOPNOTSUPP;
+ }
+ wnd->iw_auth_wpa_version = wpa_version;
+ wnd->iw_auth_80211_alg = auth_80211_alg;
+ EXIT2(return 0);
+}
+
+int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode)
+{
+ NDIS_STATUS res;
+
+ ENTER2("%d", auth_mode);
+ res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode);
+ if (res) {
+ WARNING("setting auth mode to %u failed (%08X)",
+ auth_mode, res);
+ if (res == NDIS_STATUS_INVALID_DATA)
+ EXIT2(return -EINVAL);
+ return -EOPNOTSUPP;
+ }
+ switch (auth_mode) {
+ case Ndis802_11AuthModeWPA:
+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA;
+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X;
+ break;
+ case Ndis802_11AuthModeWPAPSK:
+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA;
+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK;
+ case Ndis802_11AuthModeWPANone:
+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED;
+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK;
+ break;
+ case Ndis802_11AuthModeWPA2:
+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2;
+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X;
+ break;
+ case Ndis802_11AuthModeWPA2PSK:
+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2;
+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK;
+ break;
+ case Ndis802_11AuthModeOpen:
+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED;
+ wnd->iw_auth_80211_alg = IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ case Ndis802_11AuthModeShared:
+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED;
+ wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY;
+ break;
+ case Ndis802_11AuthModeAutoSwitch:
+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED;
+ wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY;
+ wnd->iw_auth_80211_alg |= IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ default:
+ WARNING("invalid authentication algorithm: %d", auth_mode);
+ break;
+ }
+ EXIT2(return 0);
+}
+
+int set_auth_mode(struct ndis_device *wnd)
+{
+ return set_iw_auth_mode(wnd, wnd->iw_auth_wpa_version,
+ wnd->iw_auth_80211_alg);
+}
+
+int get_ndis_auth_mode(struct ndis_device *wnd)
+{
+ ULONG mode;
+ NDIS_STATUS res;
+
+ res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &mode);
+ if (res) {
+ WARNING("getting authentication mode failed (%08X)", res);
+ EXIT2(return -EOPNOTSUPP);
+ }
+ TRACE2("%d", mode);
+ return mode;
+}
+
+int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise,
+ int cipher_groupwise)
+{
+ NDIS_STATUS res;
+ ULONG ndis_mode;
+
+ ENTER2("%d, %d", cipher_pairwise, cipher_groupwise);
+ if (cipher_pairwise & IW_AUTH_CIPHER_CCMP)
+ ndis_mode = Ndis802_11Encryption3Enabled;
+ else if (cipher_pairwise & IW_AUTH_CIPHER_TKIP)
+ ndis_mode = Ndis802_11Encryption2Enabled;
+ else if (cipher_pairwise &
+ (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
+ ndis_mode = Ndis802_11Encryption1Enabled;
+ else if (cipher_groupwise & IW_AUTH_CIPHER_CCMP)
+ ndis_mode = Ndis802_11Encryption3Enabled;
+ else if (cipher_groupwise & IW_AUTH_CIPHER_TKIP)
+ ndis_mode = Ndis802_11Encryption2Enabled;
+ else
+ ndis_mode = Ndis802_11EncryptionDisabled;
+
+ res = mp_set_int(wnd, OID_802_11_ENCRYPTION_STATUS, ndis_mode);
+ if (res) {
+ WARNING("setting encryption mode to %u failed (%08X)",
+ ndis_mode, res);
+ if (res == NDIS_STATUS_INVALID_DATA)
+ EXIT2(return -EINVAL);
+ return -EOPNOTSUPP;
+ }
+ wnd->iw_auth_cipher_pairwise = cipher_pairwise;
+ wnd->iw_auth_cipher_group = cipher_groupwise;
+ EXIT2(return 0);
+}
+
+int set_encr_mode(struct ndis_device *wnd)
+{
+ return set_iw_encr_mode(wnd, wnd->iw_auth_cipher_pairwise,
+ wnd->iw_auth_cipher_group);
+}
+
+int get_ndis_encr_mode(struct ndis_device *wnd)
+{
+ ULONG mode;
+ NDIS_STATUS res;
+
+ ENTER2("");
+ res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &mode);
+ if (res) {
+ WARNING("getting encryption status failed (%08X)", res);
+ EXIT2(return -EOPNOTSUPP);
+ } else
+ EXIT2(return mode);
+}
+
+static int iw_get_encr(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ int index, mode;
+ struct encr_info *encr_info = &wnd->encr_info;
+
+ ENTER2("wnd = %p", wnd);
+ wrqu->data.length = 0;
+ extra[0] = 0;
+
+ index = (wrqu->encoding.flags & IW_ENCODE_INDEX);
+ TRACE2("index = %u", index);
+ if (index > 0)
+ index--;
+ else
+ index = encr_info->tx_key_index;
+
+ if (index < 0 || index >= MAX_ENCR_KEYS) {
+ WARNING("encryption index out of range (%u)", index);
+ EXIT2(return -EINVAL);
+ }
+
+ if (index != encr_info->tx_key_index) {
+ if (encr_info->keys[index].length > 0) {
+ wrqu->data.flags |= IW_ENCODE_ENABLED;
+ wrqu->data.length = encr_info->keys[index].length;
+ memcpy(extra, encr_info->keys[index].key,
+ encr_info->keys[index].length);
+ }
+ else
+ wrqu->data.flags |= IW_ENCODE_DISABLED;
+
+ EXIT2(return 0);
+ }
+
+ /* transmit key */
+ mode = get_ndis_encr_mode(wnd);
+ if (mode < 0)
+ EXIT2(return -EOPNOTSUPP);
+
+ if (mode == Ndis802_11EncryptionDisabled ||
+ mode == Ndis802_11EncryptionNotSupported)
+ wrqu->data.flags |= IW_ENCODE_DISABLED;
+ else {
+ if (mode == Ndis802_11Encryption1KeyAbsent ||
+ mode == Ndis802_11Encryption2KeyAbsent ||
+ mode == Ndis802_11Encryption3KeyAbsent)
+ wrqu->data.flags |= IW_ENCODE_NOKEY;
+ else {
+ wrqu->data.flags |= IW_ENCODE_ENABLED;
+ wrqu->encoding.flags |= index+1;
+ wrqu->data.length = encr_info->keys[index].length;
+ memcpy(extra, encr_info->keys[index].key,
+ encr_info->keys[index].length);
+ }
+ }
+ mode = get_ndis_auth_mode(wnd);
+ if (mode < 0)
+ EXIT2(return -EOPNOTSUPP);
+
+ if (mode == Ndis802_11AuthModeOpen)
+ wrqu->data.flags |= IW_ENCODE_OPEN;
+ else if (mode == Ndis802_11AuthModeAutoSwitch)
+ wrqu->data.flags |= IW_ENCODE_RESTRICTED;
+ else // Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA etc.
+ wrqu->data.flags |= IW_ENCODE_RESTRICTED;
+
+ EXIT2(return 0);
+}
+
+/* index must be 0 - N, as per NDIS */
+int add_wep_key(struct ndis_device *wnd, char *key, int key_len,
+ int index)
+{
+ struct ndis_encr_key ndis_key;
+ NDIS_STATUS res;
+
+ ENTER2("key index: %d, length: %d", index, key_len);
+ if (key_len <= 0 || key_len > NDIS_ENCODING_TOKEN_MAX) {
+ WARNING("invalid key length (%d)", key_len);
+ EXIT2(return -EINVAL);
+ }
+ if (index < 0 || index >= MAX_ENCR_KEYS) {
+ WARNING("invalid key index (%d)", index);
+ EXIT2(return -EINVAL);
+ }
+ ndis_key.struct_size = sizeof(ndis_key);
+ ndis_key.length = key_len;
+ memcpy(&ndis_key.key, key, key_len);
+ ndis_key.index = index;
+
+ if (index == wnd->encr_info.tx_key_index) {
+ ndis_key.index |= (1 << 31);
+ res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104,
+ IW_AUTH_CIPHER_NONE);
+ if (res)
+ WARNING("encryption couldn't be enabled (%08X)", res);
+ }
+ TRACE2("key %d: " MACSTRSEP, index, MAC2STR(key));
+ res = mp_set(wnd, OID_802_11_ADD_WEP, &ndis_key, sizeof(ndis_key));
+ if (res) {
+ WARNING("adding encryption key %d failed (%08X)",
+ index+1, res);
+ EXIT2(return -EINVAL);
+ }
+
+ /* Atheros driver messes up ndis_key during ADD_WEP, so
+ * don't rely on that; instead use info in key and key_len */
+ wnd->encr_info.keys[index].length = key_len;
+ memcpy(&wnd->encr_info.keys[index].key, key, key_len);
+
+ EXIT2(return 0);
+}
+
+/* remove_key is for both wep and wpa */
+static int remove_key(struct ndis_device *wnd, int index,
+ mac_address bssid)
+{
+ NDIS_STATUS res;
+ if (wnd->encr_info.keys[index].length == 0)
+ EXIT2(return 0);
+ wnd->encr_info.keys[index].length = 0;
+ memset(&wnd->encr_info.keys[index].key, 0,
+ sizeof(wnd->encr_info.keys[index].length));
+ if (wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_TKIP ||
+ wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_CCMP ||
+ wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_TKIP ||
+ wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_CCMP) {
+ struct ndis_remove_key remove_key;
+ remove_key.struct_size = sizeof(remove_key);
+ remove_key.index = index;
+ if (bssid) {
+ /* pairwise key */
+ if (memcmp(bssid, "\xff\xff\xff\xff\xff\xff",
+ ETH_ALEN) != 0)
+ remove_key.index |= (1 << 30);
+ memcpy(remove_key.bssid, bssid,
+ sizeof(remove_key.bssid));
+ } else
+ memset(remove_key.bssid, 0xff,
+ sizeof(remove_key.bssid));
+ if (mp_set(wnd, OID_802_11_REMOVE_KEY,
+ &remove_key, sizeof(remove_key)))
+ EXIT2(return -EINVAL);
+ } else {
+ ndis_key_index keyindex = index;
+ res = mp_set_int(wnd, OID_802_11_REMOVE_WEP, keyindex);
+ if (res) {
+ WARNING("removing encryption key %d failed (%08X)",
+ keyindex, res);
+ EXIT2(return -EINVAL);
+ }
+ }
+ /* if it is transmit key, disable encryption */
+ if (index == wnd->encr_info.tx_key_index) {
+ res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE,
+ IW_AUTH_CIPHER_NONE);
+ if (res)
+ WARNING("changing encr status failed (%08X)", res);
+ }
+ TRACE2("key %d removed", index);
+ EXIT2(return 0);
+}
+
+static int iw_set_wep(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ unsigned int index, key_len;
+ struct encr_info *encr_info = &wnd->encr_info;
+ unsigned char *key;
+
+ ENTER2("");
+ index = (wrqu->encoding.flags & IW_ENCODE_INDEX);
+ TRACE2("index = %u", index);
+
+ /* iwconfig gives index as 1 - N */
+ if (index > 0)
+ index--;
+ else
+ index = encr_info->tx_key_index;
+
+ if (index < 0 || index >= MAX_ENCR_KEYS) {
+ WARNING("encryption index out of range (%u)", index);
+ EXIT2(return -EINVAL);
+ }
+
+ /* remove key if disabled */
+ if (wrqu->data.flags & IW_ENCODE_DISABLED) {
+ if (remove_key(wnd, index, NULL))
+ EXIT2(return -EINVAL);
+ else
+ EXIT2(return 0);
+ }
+
+ /* global encryption state (for all keys) */
+ if (wrqu->data.flags & IW_ENCODE_OPEN)
+ res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen);
+ else // if (wrqu->data.flags & IW_ENCODE_RESTRICTED)
+ res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeShared);
+ if (res) {
+ WARNING("setting authentication mode failed (%08X)", res);
+ EXIT2(return -EINVAL);
+ }
+
+ TRACE2("key length: %d", wrqu->data.length);
+
+ if (wrqu->data.length > 0) {
+ key_len = wrqu->data.length;
+ key = extra;
+ } else { // must be set as tx key
+ if (encr_info->keys[index].length == 0) {
+ WARNING("key %d is not set", index+1);
+ EXIT2(return -EINVAL);
+ }
+ key_len = encr_info->keys[index].length;
+ key = encr_info->keys[index].key;
+ encr_info->tx_key_index = index;
+ }
+
+ if (add_wep_key(wnd, key, key_len, index))
+ EXIT2(return -EINVAL);
+
+ if (index == encr_info->tx_key_index) {
+ /* if transmit key is at index other than 0, some
+ * drivers, at least Atheros and TI, want another
+ * (global) non-transmit key to be set; don't know why */
+ if (index != 0) {
+ int i;
+ for (i = 0; i < MAX_ENCR_KEYS; i++)
+ if (i != index &&
+ encr_info->keys[i].length != 0)
+ break;
+ if (i == MAX_ENCR_KEYS) {
+ if (index == 0)
+ i = index + 1;
+ else
+ i = index - 1;
+ if (add_wep_key(wnd, key, key_len, i))
+ WARNING("couldn't add broadcast key"
+ " at %d", i);
+ }
+ }
+ /* ndis drivers want essid to be set after setting encr */
+ set_essid(wnd, wnd->essid.essid, wnd->essid.length);
+ }
+ EXIT2(return 0);
+}
+
+static int iw_set_nick(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ if (wrqu->data.length >= IW_ESSID_MAX_SIZE || wrqu->data.length <= 0)
+ return -EINVAL;
+ memcpy(wnd->nick, extra, wrqu->data.length);
+ wnd->nick[wrqu->data.length] = 0;
+ return 0;
+}
+
+static int iw_get_nick(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ wrqu->data.length = strlen(wnd->nick);
+ memcpy(extra, wnd->nick, wrqu->data.length);
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) && !defined(IW_REQUEST_FLAG_COMPAT)
+#define iwe_stream_add_event(a, b, c, d, e) iwe_stream_add_event(b, c, d, e)
+#define iwe_stream_add_point(a, b, c, d, e) iwe_stream_add_point(b, c, d, e)
+#define iwe_stream_add_value(a, b, c, d, e, f) \
+ iwe_stream_add_value(b, c, d, e, f)
+#define iwe_stream_lcp_len(a) IW_EV_LCP_LEN
+#endif
+
+static char *ndis_translate_scan(struct net_device *dev,
+ struct iw_request_info *info, char *event,
+ char *end_buf, void *item)
+{
+ struct iw_event iwe;
+ char *current_val;
+ int i, nrates;
+ unsigned char buf[MAX_WPA_IE_LEN * 2 + 30];
+ struct ndis_wlan_bssid *bssid;
+ struct ndis_wlan_bssid_ex *bssid_ex;
+
+ ENTER2("%p, %p", event, item);
+ bssid = item;
+ bssid_ex = item;
+ /* add mac address */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ iwe.len = IW_EV_ADDR_LEN;
+ memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN);
+ event = iwe_stream_add_event(info, event, end_buf, &iwe,
+ IW_EV_ADDR_LEN);
+
+ /* add essid */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.length = bssid->ssid.length;
+ if (iwe.u.data.length > IW_ESSID_MAX_SIZE)
+ iwe.u.data.length = IW_ESSID_MAX_SIZE;
+ iwe.u.data.flags = 1;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ event = iwe_stream_add_point(info, event, end_buf, &iwe,
+ bssid->ssid.essid);
+
+ /* add protocol name */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWNAME;
+ strncpy(iwe.u.name, network_type_to_name(bssid->net_type), IFNAMSIZ);
+ event = iwe_stream_add_event(info, event, end_buf, &iwe,
+ IW_EV_CHAR_LEN);
+
+ /* add mode */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWMODE;
+ if (bssid->mode == Ndis802_11IBSS)
+ iwe.u.mode = IW_MODE_ADHOC;
+ else if (bssid->mode == Ndis802_11Infrastructure)
+ iwe.u.mode = IW_MODE_INFRA;
+ else // if (bssid->mode == Ndis802_11AutoUnknown)
+ iwe.u.mode = IW_MODE_AUTO;
+ event = iwe_stream_add_event(info, event, end_buf, &iwe,
+ IW_EV_UINT_LEN);
+
+ /* add freq */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = bssid->config.ds_config;
+ if (bssid->config.ds_config > 1000000) {
+ iwe.u.freq.m = bssid->config.ds_config / 10;
+ iwe.u.freq.e = 1;
+ }
+ else
+ iwe.u.freq.m = bssid->config.ds_config;
+ /* convert from kHz to Hz */
+ iwe.u.freq.e += 3;
+ iwe.len = IW_EV_FREQ_LEN;
+ event = iwe_stream_add_event(info, event, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+
+ /* add qual */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVQUAL;
+ i = 100 * (bssid->rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE);
+ if (i < 0)
+ i = 0;
+ else if (i > 100)
+ i = 100;
+ iwe.u.qual.level = bssid->rssi;
+ iwe.u.qual.noise = WL_NOISE;
+ iwe.u.qual.qual = i;
+ iwe.len = IW_EV_QUAL_LEN;
+ event = iwe_stream_add_event(info, event, end_buf, &iwe,
+ IW_EV_QUAL_LEN);
+
+ /* add key info */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWENCODE;
+ if (bssid->privacy == Ndis802_11PrivFilterAcceptAll)
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ else
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ iwe.u.data.length = 0;
+ iwe.len = IW_EV_POINT_LEN;
+ event = iwe_stream_add_point(info, event, end_buf, &iwe,
+ bssid->ssid.essid);
+
+ /* add rate */
+ memset(&iwe, 0, sizeof(iwe));
+ current_val = event + iwe_stream_lcp_len(info);
+ iwe.cmd = SIOCGIWRATE;
+ if (bssid->length > sizeof(*bssid))
+ nrates = NDIS_MAX_RATES_EX;
+ else
+ nrates = NDIS_MAX_RATES;
+ for (i = 0 ; i < nrates ; i++) {
+ if (bssid->rates[i] & 0x7f) {
+ iwe.u.bitrate.value = ((bssid->rates[i] & 0x7f) *
+ 500000);
+ current_val = iwe_stream_add_value(info, event,
+ current_val,
+ end_buf, &iwe,
+ IW_EV_PARAM_LEN);
+ }
+ }
+
+ if ((current_val - event) > iwe_stream_lcp_len(info))
+ event = current_val;
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "bcn_int=%d", bssid->config.beacon_period);
+ iwe.u.data.length = strlen(buf);
+ event = iwe_stream_add_point(info, event, end_buf, &iwe, buf);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "atim=%u", bssid->config.atim_window);
+ iwe.u.data.length = strlen(buf);
+ event = iwe_stream_add_point(info, event, end_buf, &iwe, buf);
+
+ TRACE2("%d, %u", bssid->length, (unsigned int)sizeof(*bssid));
+ if (bssid->length > sizeof(*bssid)) {
+ unsigned char *iep = (unsigned char *)bssid_ex->ies +
+ sizeof(struct ndis_fixed_ies);
+ no_warn_unused unsigned char *end = iep + bssid_ex->ie_length;
+
+ while (iep + 1 < end && iep + 2 + iep[1] <= end) {
+ unsigned char ielen = 2 + iep[1];
+
+ if (ielen > SSID_MAX_WPA_IE_LEN) {
+ iep += ielen;
+ continue;
+ }
+ if ((iep[0] == WLAN_EID_GENERIC && iep[1] >= 4 &&
+ memcmp(iep + 2, "\x00\x50\xf2\x01", 4) == 0) ||
+ iep[0] == RSN_INFO_ELEM) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = ielen;
+ event = iwe_stream_add_point(info, event,
+ end_buf, &iwe,
+ iep);
+ }
+ iep += ielen;
+ }
+ }
+ TRACE2("event = %p, current_val = %p", event, current_val);
+ EXIT2(return event);
+}
+
+int set_scan(struct ndis_device *wnd)
+{
+ NDIS_STATUS res;
+
+ ENTER2("");
+ res = mp_set(wnd, OID_802_11_BSSID_LIST_SCAN, NULL, 0);
+ if (res) {
+ WARNING("scanning failed (%08X)", res);
+ EXIT2(return -EOPNOTSUPP);
+ }
+ wnd->scan_timestamp = jiffies;
+ EXIT2(return 0);
+}
+
+static int iw_set_scan(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ return set_scan(wnd);
+}
+
+static int iw_get_scan(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ unsigned int i, list_len, needed;
+ NDIS_STATUS res;
+ struct ndis_bssid_list *bssid_list = NULL;
+ char *event = extra;
+ struct ndis_wlan_bssid *cur_item ;
+
+ ENTER2("");
+ if (time_before(jiffies, wnd->scan_timestamp + 3 * HZ))
+ return -EAGAIN;
+ /* try with space for a few scan items */
+ list_len = sizeof(ULONG) + sizeof(struct ndis_wlan_bssid_ex) * 8;
+ bssid_list = kmalloc(list_len, GFP_KERNEL);
+ if (!bssid_list) {
+ ERROR("couldn't allocate memory");
+ return -ENOMEM;
+ }
+ /* some drivers don't set bssid_list->num_items to 0 if
+ OID_802_11_BSSID_LIST returns no items (prism54 driver, e.g.,) */
+ memset(bssid_list, 0, list_len);
+
+ needed = 0;
+ res = mp_query_info(wnd, OID_802_11_BSSID_LIST,
+ bssid_list, list_len, NULL, &needed);
+ if (res == NDIS_STATUS_INVALID_LENGTH ||
+ res == NDIS_STATUS_BUFFER_TOO_SHORT) {
+ /* now try with required space */
+ kfree(bssid_list);
+ list_len = needed;
+ bssid_list = kmalloc(list_len, GFP_KERNEL);
+ if (!bssid_list) {
+ ERROR("couldn't allocate memory");
+ return -ENOMEM;
+ }
+ memset(bssid_list, 0, list_len);
+
+ res = mp_query(wnd, OID_802_11_BSSID_LIST,
+ bssid_list, list_len);
+ }
+ if (res) {
+ WARNING("getting BSSID list failed (%08X)", res);
+ kfree(bssid_list);
+ EXIT2(return -EOPNOTSUPP);
+ }
+ TRACE2("%d", bssid_list->num_items);
+ cur_item = &bssid_list->bssid[0];
+ for (i = 0; i < bssid_list->num_items; i++) {
+ event = ndis_translate_scan(dev, info, event,
+ extra + IW_SCAN_MAX_DATA, cur_item);
+ cur_item = (struct ndis_wlan_bssid *)((char *)cur_item +
+ cur_item->length);
+ }
+ wrqu->data.length = event - extra;
+ wrqu->data.flags = 0;
+ kfree(bssid_list);
+ EXIT2(return 0);
+}
+
+static int iw_set_power_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ ULONG power_mode;
+
+ if (wrqu->power.disabled == 1)
+ power_mode = NDIS_POWER_OFF;
+ else if (wrqu->power.flags & IW_POWER_MIN)
+ power_mode = NDIS_POWER_MIN;
+ else // if (wrqu->power.flags & IW_POWER_MAX)
+ power_mode = NDIS_POWER_MAX;
+
+ TRACE2("%d", power_mode);
+ res = mp_set(wnd, OID_802_11_POWER_MODE,
+ &power_mode, sizeof(power_mode));
+ if (res)
+ WARNING("setting power mode failed (%08X)", res);
+ return 0;
+}
+
+static int iw_get_power_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ ULONG power_mode;
+
+ ENTER2("");
+ res = mp_query(wnd, OID_802_11_POWER_MODE,
+ &power_mode, sizeof(power_mode));
+ if (res)
+ return -ENOTSUPP;
+
+ if (power_mode == NDIS_POWER_OFF)
+ wrqu->power.disabled = 1;
+ else {
+ if (wrqu->power.flags != 0)
+ return 0;
+ wrqu->power.flags |= IW_POWER_ALL_R;
+ wrqu->power.flags |= IW_POWER_TIMEOUT;
+ wrqu->power.value = 0;
+ wrqu->power.disabled = 0;
+
+ if (power_mode == NDIS_POWER_MIN)
+ wrqu->power.flags |= IW_POWER_MIN;
+ else // if (power_mode == NDIS_POWER_MAX)
+ wrqu->power.flags |= IW_POWER_MAX;
+ }
+ return 0;
+}
+
+static int iw_get_sensitivity(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ ndis_rssi rssi_trigger;
+
+ ENTER2("");
+ res = mp_query(wnd, OID_802_11_RSSI_TRIGGER,
+ &rssi_trigger, sizeof(rssi_trigger));
+ if (res)
+ return -EOPNOTSUPP;
+ wrqu->param.value = rssi_trigger;
+ wrqu->param.disabled = (rssi_trigger == 0);
+ wrqu->param.fixed = 1;
+ return 0;
+}
+
+static int iw_set_sensitivity(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ ndis_rssi rssi_trigger;
+
+ ENTER2("");
+ if (wrqu->param.disabled)
+ rssi_trigger = 0;
+ else
+ rssi_trigger = wrqu->param.value;
+ res = mp_set(wnd, OID_802_11_RSSI_TRIGGER,
+ &rssi_trigger, sizeof(rssi_trigger));
+ if (res == NDIS_STATUS_INVALID_DATA)
+ return -EINVAL;
+ if (res)
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static int iw_get_ndis_stats(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ struct iw_statistics *stats = &wnd->iw_stats;
+ memcpy(&wrqu->qual, &stats->qual, sizeof(stats->qual));
+ return 0;
+}
+
+static int iw_get_range(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_range *range = (struct iw_range *)extra;
+ struct iw_point *data = &wrqu->data;
+ struct ndis_device *wnd = netdev_priv(dev);
+ unsigned int i, n;
+ NDIS_STATUS res;
+ ndis_rates_ex rates;
+ ndis_tx_power_level tx_power;
+
+ ENTER2("");
+ data->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->txpower_capa = IW_TXPOW_MWATT;
+ range->num_txpower = 0;
+
+ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL,
+ &tx_power, sizeof(tx_power));
+ if (!res) {
+ range->num_txpower = 1;
+ range->txpower[0] = tx_power;
+ }
+
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 18;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT;
+ range->min_retry = 0;
+ range->max_retry = 255;
+
+ range->num_channels = 1;
+
+ range->max_qual.qual = 100;
+ range->max_qual.level = 154;
+ range->max_qual.noise = 154;
+ range->sensitivity = 3;
+
+ range->max_encoding_tokens = 4;
+ range->num_encoding_sizes = 2;
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+
+ range->num_bitrates = 0;
+ memset(&rates, 0, sizeof(rates));
+ res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES,
+ &rates, sizeof(rates), &n, NULL);
+ if (res)
+ WARNING("getting bit rates failed: %08X", res);
+ else {
+ for (i = 0; i < n && range->num_bitrates < IW_MAX_BITRATES; i++)
+ if (rates[i] & 0x80)
+ continue;
+ else if (rates[i] & 0x7f) {
+ range->bitrate[range->num_bitrates] =
+ (rates[i] & 0x7f) * 500000;
+ range->num_bitrates++;
+ }
+ }
+
+ range->num_channels = (sizeof(freq_chan)/sizeof(freq_chan[0]));
+
+ for (i = 0; i < (sizeof(freq_chan)/sizeof(freq_chan[0])) &&
+ i < IW_MAX_FREQUENCIES; i++) {
+ range->freq[i].i = i + 1;
+ range->freq[i].m = freq_chan[i] * 100000;
+ range->freq[i].e = 1;
+ }
+ range->num_frequency = i;
+
+ range->min_rts = 0;
+ range->max_rts = 2347;
+ range->min_frag = 256;
+ range->max_frag = 2346;
+
+ /* Event capability (kernel + driver) */
+ range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+ IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+ IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+ IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
+ range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) |
+ IW_EVENT_CAPA_MASK(IWEVCUSTOM) |
+ IW_EVENT_CAPA_MASK(IWEVREGISTERED) |
+ IW_EVENT_CAPA_MASK(IWEVEXPIRED));
+
+ range->enc_capa = 0;
+
+ if (test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr))
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
+ if (test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr))
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
+
+ if (test_bit(Ndis802_11AuthModeWPA, &wnd->capa.auth) ||
+ test_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth))
+ range->enc_capa |= IW_ENC_CAPA_WPA;
+ if (test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ||
+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth))
+ range->enc_capa |= IW_ENC_CAPA_WPA2;
+
+ return 0;
+}
+
+void set_default_iw_params(struct ndis_device *wnd)
+{
+ wnd->iw_auth_key_mgmt = 0;
+ wnd->iw_auth_wpa_version = 0;
+ set_infra_mode(wnd, Ndis802_11Infrastructure);
+ set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen);
+ set_priv_filter(wnd);
+ set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE);
+}
+
+static int deauthenticate(struct ndis_device *wnd)
+{
+ int ret;
+
+ ENTER2("");
+ ret = disassociate(wnd, 1);
+ set_default_iw_params(wnd);
+ EXIT2(return ret);
+}
+
+NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid)
+{
+ NDIS_STATUS res;
+ u8 buf[NDIS_ESSID_MAX_SIZE];
+ int i;
+
+ TRACE2("");
+ res = mp_set(wnd, OID_802_11_DISASSOCIATE, NULL, 0);
+ /* disassociate causes radio to be turned off; if reset_ssid
+ * is given, set ssid to random to enable radio */
+ if (reset_ssid) {
+ get_random_bytes(buf, sizeof(buf));
+ for (i = 0; i < sizeof(buf); i++)
+ buf[i] = 'a' + (buf[i] % 26);
+ set_essid(wnd, buf, sizeof(buf));
+ }
+ return res;
+}
+
+static ULONG ndis_priv_mode(struct ndis_device *wnd)
+{
+ if (wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2 ||
+ wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA)
+ return Ndis802_11PrivFilter8021xWEP;
+ else
+ return Ndis802_11PrivFilterAcceptAll;
+}
+
+int set_priv_filter(struct ndis_device *wnd)
+{
+ NDIS_STATUS res;
+ ULONG flags;
+
+ flags = ndis_priv_mode(wnd);
+ ENTER2("filter: %d", flags);
+ res = mp_set_int(wnd, OID_802_11_PRIVACY_FILTER, flags);
+ if (res)
+ TRACE2("setting privacy filter to %d failed (%08X)",
+ flags, res);
+ EXIT2(return 0);
+}
+
+static int iw_set_mlme(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+
+ ENTER2("");
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ return deauthenticate(wnd);
+ case IW_MLME_DISASSOC:
+ TRACE2("cmd=%d reason_code=%d", mlme->cmd, mlme->reason_code);
+ return disassociate(wnd, 1);
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iw_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * NDIS drivers do not allow IEs to be configured; this is
+ * done by the driver based on other configuration. Return 0
+ * to avoid causing issues with user space programs that
+ * expect this function to succeed.
+ */
+ return 0;
+}
+
+static int iw_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ TRACE2("index=%d value=%d", wrqu->param.flags & IW_AUTH_INDEX,
+ wrqu->param.value);
+ switch (wrqu->param.flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ wnd->iw_auth_wpa_version = wrqu->param.value;
+ break;
+ case IW_AUTH_CIPHER_PAIRWISE:
+ wnd->iw_auth_cipher_pairwise = wrqu->param.value;
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ wnd->iw_auth_cipher_group = wrqu->param.value;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ wnd->iw_auth_key_mgmt = wrqu->param.value;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ wnd->iw_auth_80211_alg = wrqu->param.value;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (wrqu->param.value)
+ deauthenticate(wnd);
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ TRACE2("%d not implemented: %d",
+ wrqu->param.flags & IW_AUTH_INDEX, wrqu->param.value);
+ break;
+ default:
+ WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX);
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int iw_get_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ ENTER2("index=%d", wrqu->param.flags & IW_AUTH_INDEX);
+ switch (wrqu->param.flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ wrqu->param.value = wnd->iw_auth_wpa_version;
+ break;
+ case IW_AUTH_CIPHER_PAIRWISE:
+ wrqu->param.value = wnd->iw_auth_cipher_pairwise;
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ wrqu->param.value = wnd->iw_auth_cipher_group;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ wrqu->param.value = wnd->iw_auth_key_mgmt;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ wrqu->param.value = wnd->iw_auth_80211_alg;
+ break;
+ default:
+ WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX);
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int iw_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ struct ndis_device *wnd = netdev_priv(dev);
+ struct ndis_add_key ndis_key;
+ int i, keyidx;
+ NDIS_STATUS res;
+ u8 *addr;
+
+ keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
+ ENTER2("%d", keyidx);
+ if (keyidx)
+ keyidx--;
+ else
+ keyidx = wnd->encr_info.tx_key_index;
+
+ if (keyidx < 0 || keyidx >= MAX_ENCR_KEYS)
+ return -EINVAL;
+
+ if (ext->alg == WPA_ALG_WEP) {
+ if (!test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr))
+ EXIT2(return -1);
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ wnd->encr_info.tx_key_index = keyidx;
+ if (add_wep_key(wnd, ext->key, ext->key_len, keyidx))
+ EXIT2(return -1);
+ else
+ EXIT2(return 0);
+ }
+ if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) ||
+ ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0)
+ EXIT2(return remove_key(wnd, keyidx, ndis_key.bssid));
+
+ if (ext->key_len > sizeof(ndis_key.key)) {
+ TRACE2("incorrect key length (%u)", ext->key_len);
+ EXIT2(return -1);
+ }
+
+ memset(&ndis_key, 0, sizeof(ndis_key));
+
+ ndis_key.struct_size =
+ sizeof(ndis_key) - sizeof(ndis_key.key) + ext->key_len;
+ ndis_key.length = ext->key_len;
+ ndis_key.index = keyidx;
+
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ for (i = 0; i < 6 ; i++)
+ ndis_key.rsc |= (((u64)ext->rx_seq[i]) << (i * 8));
+ TRACE2("0x%Lx", ndis_key.rsc);
+ ndis_key.index |= 1 << 29;
+ }
+
+ addr = ext->addr.sa_data;
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+ /* group key */
+ if (wnd->infrastructure_mode == Ndis802_11IBSS)
+ memset(ndis_key.bssid, 0xff, ETH_ALEN);
+ else
+ get_ap_address(wnd, ndis_key.bssid);
+ } else {
+ /* pairwise key */
+ ndis_key.index |= (1 << 30);
+ memcpy(ndis_key.bssid, addr, ETH_ALEN);
+ }
+ TRACE2(MACSTRSEP, MAC2STR(ndis_key.bssid));
+
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ ndis_key.index |= (1 << 31);
+
+ if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) {
+ /* wpa_supplicant gives us the Michael MIC RX/TX keys in
+ * different order than NDIS spec, so swap the order here. */
+ memcpy(ndis_key.key, ext->key, 16);
+ memcpy(ndis_key.key + 16, ext->key + 24, 8);
+ memcpy(ndis_key.key + 24, ext->key + 16, 8);
+ } else
+ memcpy(ndis_key.key, ext->key, ext->key_len);
+
+ res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size);
+ if (res) {
+ TRACE2("adding key failed (%08X), %u",
+ res, ndis_key.struct_size);
+ EXIT2(return -1);
+ }
+ wnd->encr_info.keys[keyidx].length = ext->key_len;
+ memcpy(&wnd->encr_info.keys[keyidx].key, ndis_key.key, ext->key_len);
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ wnd->encr_info.tx_key_index = keyidx;
+ TRACE2("key %d added", keyidx);
+
+ EXIT2(return 0);
+}
+
+static int iw_get_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /* struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; */
+ /* TODO */
+ ENTER2("");
+ return 0;
+}
+
+static int iw_set_pmksa(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;
+ struct ndis_pmkid pmkid;
+ NDIS_STATUS res;
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ /* TODO: must keep local list of PMKIDs since NDIS drivers
+ * expect that all PMKID entries are included whenever a new
+ * one is added. */
+
+ ENTER2("%d", pmksa->cmd);
+ if ((pmksa->cmd == IW_PMKSA_ADD || pmksa->cmd == IW_PMKSA_REMOVE) &&
+ (!(wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2)))
+ EXIT2(return -EOPNOTSUPP);
+
+ memset(&pmkid, 0, sizeof(pmkid));
+ if (pmksa->cmd == IW_PMKSA_ADD) {
+ pmkid.bssid_info_count = 1;
+ memcpy(pmkid.bssid_info[0].bssid, pmksa->bssid.sa_data,
+ ETH_ALEN);
+ memcpy(pmkid.bssid_info[0].pmkid, pmksa->pmkid, IW_PMKID_LEN);
+ }
+ pmkid.length = sizeof(pmkid);
+
+ res = mp_set(wnd, OID_802_11_PMKID, &pmkid, pmkid.length);
+ if (res == NDIS_STATUS_FAILURE)
+ EXIT2(return -EOPNOTSUPP);
+ TRACE2("OID_802_11_PMKID -> %d", res);
+ if (res)
+ return -EINVAL;
+
+ return 0;
+}
+
+#define WEXT(id) [id - SIOCIWFIRST]
+
+static const iw_handler ndis_handler[] = {
+ WEXT(SIOCGIWNAME) = iw_get_network_type,
+ WEXT(SIOCSIWESSID) = iw_set_essid,
+ WEXT(SIOCGIWESSID) = iw_get_essid,
+ WEXT(SIOCSIWMODE) = iw_set_infra_mode,
+ WEXT(SIOCGIWMODE) = iw_get_infra_mode,
+ WEXT(SIOCGIWFREQ) = iw_get_freq,
+ WEXT(SIOCSIWFREQ) = iw_set_freq,
+ WEXT(SIOCGIWTXPOW) = iw_get_tx_power,
+ WEXT(SIOCSIWTXPOW) = iw_set_tx_power,
+ WEXT(SIOCGIWRATE) = iw_get_bitrate,
+ WEXT(SIOCSIWRATE) = iw_set_bitrate,
+ WEXT(SIOCGIWRTS) = iw_get_rts_threshold,
+ WEXT(SIOCSIWRTS) = iw_set_rts_threshold,
+ WEXT(SIOCGIWFRAG) = iw_get_frag_threshold,
+ WEXT(SIOCSIWFRAG) = iw_set_frag_threshold,
+ WEXT(SIOCGIWAP) = iw_get_ap_address,
+ WEXT(SIOCSIWAP) = iw_set_ap_address,
+ WEXT(SIOCSIWENCODE) = iw_set_wep,
+ WEXT(SIOCGIWENCODE) = iw_get_encr,
+ WEXT(SIOCSIWSCAN) = iw_set_scan,
+ WEXT(SIOCGIWSCAN) = iw_get_scan,
+ WEXT(SIOCGIWPOWER) = iw_get_power_mode,
+ WEXT(SIOCSIWPOWER) = iw_set_power_mode,
+ WEXT(SIOCGIWRANGE) = iw_get_range,
+ WEXT(SIOCGIWSTATS) = iw_get_ndis_stats,
+ WEXT(SIOCGIWSENS) = iw_get_sensitivity,
+ WEXT(SIOCSIWSENS) = iw_set_sensitivity,
+ WEXT(SIOCGIWNICKN) = iw_get_nick,
+ WEXT(SIOCSIWNICKN) = iw_set_nick,
+ WEXT(SIOCSIWCOMMIT) = iw_set_dummy,
+ WEXT(SIOCSIWMLME) = iw_set_mlme,
+ WEXT(SIOCSIWGENIE) = iw_set_genie,
+ WEXT(SIOCSIWAUTH) = iw_set_auth,
+ WEXT(SIOCGIWAUTH) = iw_get_auth,
+ WEXT(SIOCSIWENCODEEXT) = iw_set_encodeext,
+ WEXT(SIOCGIWENCODEEXT) = iw_get_encodeext,
+ WEXT(SIOCSIWPMKSA) = iw_set_pmksa,
+};
+
+/* private ioctl's */
+
+static int priv_reset(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int res;
+ ENTER2("");
+ res = mp_reset(netdev_priv(dev));
+ if (res) {
+ WARNING("reset failed: %08X", res);
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int priv_deauthenticate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int res;
+ ENTER2("");
+ res = deauthenticate(netdev_priv(dev));
+ return res;
+}
+
+static int priv_power_profile(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ struct miniport *mp;
+ ULONG profile_inf;
+
+ ENTER2("");
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ if (!mp->pnp_event_notify)
+ EXIT2(return -EOPNOTSUPP);
+
+ /* 1 for AC and 0 for Battery */
+ if (wrqu->param.value)
+ profile_inf = NdisPowerProfileAcOnLine;
+ else
+ profile_inf = NdisPowerProfileBattery;
+
+ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx,
+ NdisDevicePnPEventPowerProfileChanged,
+ &profile_inf, sizeof(profile_inf));
+ EXIT2(return 0);
+}
+
+static int priv_network_type(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ enum network_type network_type;
+ NDIS_STATUS res;
+ char type;
+
+ ENTER2("");
+ type = wrqu->param.value;
+ if (type == 'f')
+ network_type = Ndis802_11FH;
+ else if (type == 'b')
+ network_type = Ndis802_11DS;
+ else if (type == 'a')
+ network_type = Ndis802_11OFDM5;
+ else if (type == 'g' || type == 'n')
+ network_type = Ndis802_11OFDM24;
+ else
+ network_type = Ndis802_11Automode;
+
+ res = mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, network_type);
+ if (res) {
+ WARNING("setting network type to %d failed (%08X)",
+ network_type, res);
+ EXIT2(return -EINVAL);
+ }
+
+ EXIT2(return 0);
+}
+
+static int priv_media_stream_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ NDIS_STATUS res;
+ int mode;
+
+ ENTER2("");
+ if (wrqu->param.value > 0)
+ mode = Ndis802_11MediaStreamOn;
+ else
+ mode = Ndis802_11MediaStreamOff;
+ res = mp_set_int(wnd, OID_802_11_MEDIA_STREAM_MODE, mode);
+ if (res) {
+ WARNING("oid failed (%08X)", res);
+ EXIT2(return -EINVAL);
+ }
+ EXIT2(return 0);
+}
+
+static int priv_reload_defaults(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ int res;
+ ENTER2("");
+ res = mp_set_int(wnd, OID_802_11_RELOAD_DEFAULTS,
+ Ndis802_11ReloadWEPKeys);
+ if (res) {
+ WARNING("reloading defaults failed: %08X", res);
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static const struct iw_priv_args priv_args[] = {
+ {PRIV_RESET, 0, 0, "ndis_reset"},
+ {PRIV_POWER_PROFILE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+ "power_profile"},
+ {PRIV_DEAUTHENTICATE, 0, 0, "deauthenticate"},
+ {PRIV_NETWORK_TYPE, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0,
+ "network_type"},
+ {PRIV_MEDIA_STREAM_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+ "media_stream"},
+
+ {PRIV_RELOAD_DEFAULTS, 0, 0, "reload_defaults"},
+};
+
+#define WEPRIV(id) [id - SIOCIWFIRSTPRIV]
+
+static const iw_handler priv_handler[] = {
+ WEPRIV(PRIV_RESET) = priv_reset,
+ WEPRIV(PRIV_POWER_PROFILE) = priv_power_profile,
+ WEPRIV(PRIV_DEAUTHENTICATE) = priv_deauthenticate,
+ WEPRIV(PRIV_NETWORK_TYPE) = priv_network_type,
+ WEPRIV(PRIV_MEDIA_STREAM_MODE) = priv_media_stream_mode,
+ WEPRIV(PRIV_RELOAD_DEFAULTS) = priv_reload_defaults,
+};
+
+const struct iw_handler_def ndis_handler_def = {
+ .num_standard = sizeof(ndis_handler) / sizeof(ndis_handler[0]),
+ .num_private = sizeof(priv_handler) / sizeof(priv_handler[0]),
+ .num_private_args = sizeof(priv_args) / sizeof(priv_args[0]),
+
+ .standard = (iw_handler *)ndis_handler,
+ .private = (iw_handler *)priv_handler,
+ .private_args = (struct iw_priv_args *)priv_args,
+ .get_wireless_stats = get_iw_stats,
+};
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _IW_NDIS_H_
+#define _IW_NDIS_H_
+
+#include "ndis.h"
+
+#define WL_NOISE -96 /* typical noise level in dBm */
+#define WL_SIGMAX -32 /* typical maximum signal level in dBm */
+
+struct ndis_encr_key {
+ ULONG struct_size;
+ ULONG index;
+ ULONG length;
+ UCHAR key[NDIS_ENCODING_TOKEN_MAX];
+};
+
+struct ndis_add_key {
+ ULONG struct_size;
+ ndis_key_index index;
+ ULONG length;
+ mac_address bssid;
+ UCHAR pad[6];
+ ndis_key_rsc rsc;
+ UCHAR key[NDIS_ENCODING_TOKEN_MAX];
+};
+
+struct ndis_remove_key {
+ ULONG struct_size;
+ ndis_key_index index;
+ mac_address bssid;
+};
+
+struct ndis_fixed_ies {
+ UCHAR time_stamp[8];
+ USHORT beacon_interval;
+ USHORT capa;
+};
+
+struct ndis_variable_ies {
+ ULONG elem_id;
+ UCHAR length;
+ UCHAR data[1];
+};
+
+enum ndis_reload_defaults { Ndis802_11ReloadWEPKeys };
+
+struct ndis_assoc_info {
+ ULONG length;
+ USHORT req_ies;
+ struct req_ie {
+ USHORT capa;
+ USHORT listen_interval;
+ mac_address cur_ap_address;
+ } req_ie;
+ ULONG req_ie_length;
+ ULONG offset_req_ies;
+ USHORT resp_ies;
+ struct resp_ie {
+ USHORT capa;
+ USHORT status_code;
+ USHORT assoc_id;
+ } resp_ie;
+ ULONG resp_ie_length;
+ ULONG offset_resp_ies;
+};
+
+struct ndis_configuration_fh {
+ ULONG length;
+ ULONG hop_pattern;
+ ULONG hop_set;
+ ULONG dwell_time;
+};
+
+struct ndis_configuration {
+ ULONG length;
+ ULONG beacon_period;
+ ULONG atim_window;
+ ULONG ds_config;
+ struct ndis_configuration_fh fh_config;
+};
+
+struct ndis_wlan_bssid {
+ ULONG length;
+ mac_address mac;
+ UCHAR reserved[2];
+ struct ndis_essid ssid;
+ ULONG privacy;
+ ndis_rssi rssi;
+ UINT net_type;
+ struct ndis_configuration config;
+ UINT mode;
+ ndis_rates rates;
+};
+
+struct ndis_wlan_bssid_ex {
+ ULONG length;
+ mac_address mac;
+ UCHAR reserved[2];
+ struct ndis_essid ssid;
+ ULONG privacy;
+ ndis_rssi rssi;
+ UINT net_type;
+ struct ndis_configuration config;
+ UINT mode;
+ ndis_rates_ex rates_ex;
+ ULONG ie_length;
+ UCHAR ies[1];
+};
+
+/* we use bssid_list as bssid_list_ex also */
+struct ndis_bssid_list {
+ ULONG num_items;
+ struct ndis_wlan_bssid bssid[1];
+};
+
+enum ndis_priv_filter {
+ Ndis802_11PrivFilterAcceptAll, Ndis802_11PrivFilter8021xWEP
+};
+
+enum network_type {
+ Ndis802_11FH, Ndis802_11DS, Ndis802_11OFDM5, Ndis802_11OFDM24,
+ /* MSDN site uses Ndis802_11Automode, which is not mentioned
+ * in DDK, so add one and assign it to
+ * Ndis802_11NetworkTypeMax */
+ Ndis802_11Automode, Ndis802_11NetworkTypeMax = Ndis802_11Automode
+};
+
+struct network_type_list {
+ ULONG num;
+ enum network_type types[1];
+};
+
+enum ndis_power {
+ NDIS_POWER_OFF = 0, NDIS_POWER_MAX, NDIS_POWER_MIN,
+};
+
+struct ndis_auth_req {
+ ULONG length;
+ mac_address bssid;
+ ULONG flags;
+};
+
+struct ndis_bssid_info {
+ mac_address bssid;
+ ndis_pmkid_vavlue pmkid;
+};
+
+struct ndis_pmkid {
+ ULONG length;
+ ULONG bssid_info_count;
+ struct ndis_bssid_info bssid_info[1];
+};
+
+int add_wep_key(struct ndis_device *wnd, char *key, int key_len,
+ int index);
+int set_essid(struct ndis_device *wnd, const char *ssid, int ssid_len);
+int set_infra_mode(struct ndis_device *wnd,
+ enum ndis_infrastructure_mode mode);
+int get_ap_address(struct ndis_device *wnd, mac_address mac);
+int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode);
+int set_iw_auth_mode(struct ndis_device *wnd, int wpa_version,
+ int auth_80211_alg);
+int set_auth_mode(struct ndis_device *wnd);
+int set_ndis_encr_mode(struct ndis_device *wnd, int cipher_pairwise,
+ int cipher_groupwise);
+int get_ndis_encr_mode(struct ndis_device *wnd);
+int set_encr_mode(struct ndis_device *wnd);
+int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise,
+ int cipher_groupwise);
+int get_ndis_auth_mode(struct ndis_device *wnd);
+int set_priv_filter(struct ndis_device *wnd);
+int set_scan(struct ndis_device *wnd);
+NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid);
+void set_default_iw_params(struct ndis_device *wnd);
+extern const struct iw_handler_def ndis_handler_def;
+
+#define PRIV_RESET SIOCIWFIRSTPRIV+16
+#define PRIV_POWER_PROFILE SIOCIWFIRSTPRIV+17
+#define PRIV_NETWORK_TYPE SIOCIWFIRSTPRIV+18
+#define PRIV_DEAUTHENTICATE SIOCIWFIRSTPRIV+19
+#define PRIV_MEDIA_STREAM_MODE SIOCIWFIRSTPRIV+20
+#define PRIV_RELOAD_DEFAULTS SIOCIWFIRSTPRIV+23
+
+#define RSN_INFO_ELEM 0x30
+
+/* these have to match what is in wpa_supplicant */
+
+typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
+typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
+ CIPHER_WEP104 } wpa_cipher;
+typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
+ KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
+
+#endif // IW_NDIS_H
--- /dev/null
+/*
+ * Copyright (C) 2006 Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifdef CONFIG_X86_64
+
+/* Windows functions must have 32 bytes of shadow space for arguments
+ * above return address, irrespective of number of args. So argc >= 4
+ */
+
+#define alloc_win_stack_frame(argc) \
+ "sub $(" #argc "+1)*8, %%rsp\n\t"
+#define free_win_stack_frame(argc) \
+ "add $(" #argc "+1)*8, %%rsp\n\t"
+
+/* m is index of Windows arg required; Windows arg 1 should be at
+ * 0(%rsp), arg 2 at 8(%rsp) and so on after the frame is allocated.
+*/
+
+#define lin2win_win_arg(m) "(" #m "-1)*8(%%rsp)"
+
+/* args for Windows function must be in clobber / output list */
+
+#define outputs() \
+ "=a" (_ret), "=c" (_dummy), "=d" (_dummy), \
+ "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+
+#define clobbers() "cc"
+
+#define LIN2WIN0(func) \
+({ \
+ u64 _ret, _dummy; \
+ register u64 r8 __asm__("r8"); \
+ register u64 r9 __asm__("r9"); \
+ register u64 r10 __asm__("r10"); \
+ register u64 r11 __asm__("r11"); \
+ __asm__ __volatile__( \
+ alloc_win_stack_frame(4) \
+ "callq *%[fptr]\n\t" \
+ free_win_stack_frame(4) \
+ : outputs() \
+ : [fptr] "r" (func) \
+ : clobbers()); \
+ _ret; \
+})
+
+#define LIN2WIN1(func, arg1) \
+({ \
+ u64 _ret, _dummy; \
+ register u64 r8 __asm__("r8"); \
+ register u64 r9 __asm__("r9"); \
+ register u64 r10 __asm__("r10"); \
+ register u64 r11 __asm__("r11"); \
+ __asm__ __volatile__( \
+ alloc_win_stack_frame(4) \
+ "callq *%[fptr]\n\t" \
+ free_win_stack_frame(4) \
+ : outputs() \
+ : "c" (arg1), [fptr] "r" (func) \
+ : clobbers()); \
+ _ret; \
+})
+
+#define LIN2WIN2(func, arg1, arg2) \
+({ \
+ u64 _ret, _dummy; \
+ register u64 r8 __asm__("r8"); \
+ register u64 r9 __asm__("r9"); \
+ register u64 r10 __asm__("r10"); \
+ register u64 r11 __asm__("r11"); \
+ __asm__ __volatile__( \
+ alloc_win_stack_frame(4) \
+ "callq *%[fptr]\n\t" \
+ free_win_stack_frame(4) \
+ : outputs() \
+ : "c" (arg1), "d" (arg2), [fptr] "r" (func) \
+ : clobbers()); \
+ _ret; \
+})
+
+#define LIN2WIN3(func, arg1, arg2, arg3) \
+({ \
+ u64 _ret, _dummy; \
+ register u64 r8 __asm__("r8") = (u64)arg3; \
+ register u64 r9 __asm__("r9"); \
+ register u64 r10 __asm__("r10"); \
+ register u64 r11 __asm__("r11"); \
+ __asm__ __volatile__( \
+ alloc_win_stack_frame(4) \
+ "callq *%[fptr]\n\t" \
+ free_win_stack_frame(4) \
+ : outputs() \
+ : "c" (arg1), "d" (arg2), "r" (r8), \
+ [fptr] "r" (func) \
+ : clobbers()); \
+ _ret; \
+})
+
+#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \
+({ \
+ u64 _ret, _dummy; \
+ register u64 r8 __asm__("r8") = (u64)arg3; \
+ register u64 r9 __asm__("r9") = (u64)arg4; \
+ register u64 r10 __asm__("r10"); \
+ register u64 r11 __asm__("r11"); \
+ __asm__ __volatile__( \
+ alloc_win_stack_frame(4) \
+ "callq *%[fptr]\n\t" \
+ free_win_stack_frame(4) \
+ : outputs() \
+ : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9), \
+ [fptr] "r" (func) \
+ : clobbers()); \
+ _ret; \
+})
+
+#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \
+({ \
+ u64 _ret, _dummy; \
+ register u64 r8 __asm__("r8") = (u64)arg3; \
+ register u64 r9 __asm__("r9") = (u64)arg4; \
+ register u64 r10 __asm__("r10"); \
+ register u64 r11 __asm__("r11"); \
+ __asm__ __volatile__( \
+ alloc_win_stack_frame(5) \
+ "movq %[rarg5], " lin2win_win_arg(5) "\n\t" \
+ "callq *%[fptr]\n\t" \
+ free_win_stack_frame(5) \
+ : outputs() \
+ : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9), \
+ [rarg5] "ri" ((u64)arg5), \
+ [fptr] "r" (func) \
+ : clobbers()); \
+ _ret; \
+})
+
+#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \
+({ \
+ u64 _ret, _dummy; \
+ register u64 r8 __asm__("r8") = (u64)arg3; \
+ register u64 r9 __asm__("r9") = (u64)arg4; \
+ register u64 r10 __asm__("r10"); \
+ register u64 r11 __asm__("r11"); \
+ __asm__ __volatile__( \
+ alloc_win_stack_frame(6) \
+ "movq %[rarg5], " lin2win_win_arg(5) "\n\t" \
+ "movq %[rarg6], " lin2win_win_arg(6) "\n\t" \
+ "callq *%[fptr]\n\t" \
+ free_win_stack_frame(6) \
+ : outputs() \
+ : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9), \
+ [rarg5] "ri" ((u64)arg5), [rarg6] "ri" ((u64)arg6), \
+ [fptr] "r" (func) \
+ : clobbers()); \
+ _ret; \
+})
+
+#else // CONFIG_X86_64
+
+#define LIN2WIN1(func, arg1) \
+({ \
+ TRACE6("calling %p", func); \
+ func(arg1); \
+})
+#define LIN2WIN2(func, arg1, arg2) \
+({ \
+ TRACE6("calling %p", func); \
+ func(arg1, arg2); \
+})
+#define LIN2WIN3(func, arg1, arg2, arg3) \
+({ \
+ TRACE6("calling %p", func); \
+ func(arg1, arg2, arg3); \
+})
+#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \
+({ \
+ TRACE6("calling %p", func); \
+ func(arg1, arg2, arg3, arg4); \
+})
+#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \
+({ \
+ TRACE6("calling %p", func); \
+ func(arg1, arg2, arg3, arg4, arg5); \
+})
+#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \
+({ \
+ TRACE6("calling %p", func); \
+ func(arg1, arg2, arg3, arg4, arg5, arg6); \
+})
+
+#endif // CONFIG_X86_64
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ndis.h"
+#include "loader.h"
+#include "wrapndis.h"
+#include "pnp.h"
+
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+
+/*
+ Network adapter: ClassGuid = {4d36e972-e325-11ce-bfc1-08002be10318}
+ Network client: ClassGuid = {4d36e973-e325-11ce-bfc1-08002be10318}
+ PCMCIA adapter: ClassGuid = {4d36e977-e325-11ce-bfc1-08002be10318}
+ USB: ClassGuid = {36fc9e60-c465-11cf-8056-444553540000}
+*/
+
+/* the indices used here must match macros WRAP_NDIS_DEVICE etc. */
+static struct guid class_guids[] = {
+ /* Network */
+ {0x4d36e972, 0xe325, 0x11ce, },
+ /* USB WDM */
+ {0x36fc9e60, 0xc465, 0x11cf, },
+ /* Bluetooth */
+ {0xe0cbf06c, 0xcd8b, 0x4647, },
+ /* ivtcorporatino.com's bluetooth device claims this is
+ * bluetooth guid */
+ {0xf12d3cf8, 0xb11d, 0x457e, },
+};
+
+struct semaphore loader_mutex;
+static struct completion loader_complete;
+
+static struct nt_list wrap_devices;
+static struct nt_list wrap_drivers;
+
+static int wrap_device_type(int data1)
+{
+ int i;
+ for (i = 0; i < sizeof(class_guids) / sizeof(class_guids[0]); i++)
+ if (data1 == class_guids[i].data1)
+ return i;
+ ERROR("unknown device: 0x%x\n", data1);
+ return -1;
+}
+
+/* load driver for given device, if not already loaded */
+struct wrap_driver *load_wrap_driver(struct wrap_device *wd)
+{
+ int ret;
+ struct nt_list *cur;
+ struct wrap_driver *wrap_driver;
+
+ ENTER1("device: %04X:%04X:%04X:%04X", wd->vendor, wd->device,
+ wd->subvendor, wd->subdevice);
+ if (down_interruptible(&loader_mutex)) {
+ WARNING("couldn't obtain loader_mutex");
+ EXIT1(return NULL);
+ }
+ wrap_driver = NULL;
+ nt_list_for_each(cur, &wrap_drivers) {
+ wrap_driver = container_of(cur, struct wrap_driver, list);
+ if (!stricmp(wrap_driver->name, wd->driver_name)) {
+ TRACE1("driver %s already loaded", wrap_driver->name);
+ break;
+ } else
+ wrap_driver = NULL;
+ }
+ up(&loader_mutex);
+
+ if (!wrap_driver) {
+ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DRIVER,
+#if defined(DEBUG) && DEBUG >= 1
+ "1",
+#else
+ "0",
+#endif
+ UTILS_VERSION, wd->driver_name,
+ wd->conf_file_name, NULL};
+ char *env[] = {NULL};
+
+ TRACE1("loading driver %s", wd->driver_name);
+ if (down_interruptible(&loader_mutex)) {
+ WARNING("couldn't obtain loader_mutex");
+ EXIT1(return NULL);
+ }
+ INIT_COMPLETION(loader_complete);
+ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, 1);
+ if (ret) {
+ up(&loader_mutex);
+ ERROR("couldn't load driver %s; check system log "
+ "for messages from 'loadndisdriver'",
+ wd->driver_name);
+ EXIT1(return NULL);
+ }
+ wait_for_completion(&loader_complete);
+ TRACE1("%s", wd->driver_name);
+ wrap_driver = NULL;
+ nt_list_for_each(cur, &wrap_drivers) {
+ wrap_driver = container_of(cur, struct wrap_driver,
+ list);
+ if (!stricmp(wrap_driver->name, wd->driver_name)) {
+ wd->driver = wrap_driver;
+ break;
+ } else
+ wrap_driver = NULL;
+ }
+ up(&loader_mutex);
+ if (wrap_driver)
+ TRACE1("driver %s is loaded", wrap_driver->name);
+ else
+ ERROR("couldn't load driver '%s'", wd->driver_name);
+ }
+ EXIT1(return wrap_driver);
+}
+
+/* load the driver files from userspace. */
+static int load_sys_files(struct wrap_driver *driver,
+ struct load_driver *load_driver)
+{
+ int i, err;
+
+ TRACE1("num_pe_images = %d", load_driver->num_sys_files);
+ TRACE1("loading driver: %s", load_driver->name);
+ strncpy(driver->name, load_driver->name, sizeof(driver->name));
+ driver->name[sizeof(driver->name)-1] = 0;
+ TRACE1("driver: %s", driver->name);
+ err = 0;
+ driver->num_pe_images = 0;
+ for (i = 0; i < load_driver->num_sys_files; i++) {
+ struct pe_image *pe_image;
+ pe_image = &driver->pe_images[driver->num_pe_images];
+
+ strncpy(pe_image->name, load_driver->sys_files[i].name,
+ sizeof(pe_image->name));
+ pe_image->name[sizeof(pe_image->name)-1] = 0;
+ TRACE1("image size: %lu bytes",
+ (unsigned long)load_driver->sys_files[i].size);
+
+#ifdef CONFIG_X86_64
+#ifdef PAGE_KERNEL_EXECUTABLE
+ pe_image->image =
+ __vmalloc(load_driver->sys_files[i].size,
+ GFP_KERNEL | __GFP_HIGHMEM,
+ PAGE_KERNEL_EXECUTABLE);
+#elif defined PAGE_KERNEL_EXEC
+ pe_image->image =
+ __vmalloc(load_driver->sys_files[i].size,
+ GFP_KERNEL | __GFP_HIGHMEM,
+ PAGE_KERNEL_EXEC);
+#else
+#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC
+#endif
+#else
+ /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is
+ * not available to modules! */
+#ifdef cpu_has_nx
+ if (cpu_has_nx)
+ pe_image->image =
+ __vmalloc(load_driver->sys_files[i].size,
+ GFP_KERNEL | __GFP_HIGHMEM,
+ __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
+ else
+ pe_image->image =
+ vmalloc(load_driver->sys_files[i].size);
+#else
+ pe_image->image =
+ vmalloc(load_driver->sys_files[i].size);
+#endif
+#endif
+ if (!pe_image->image) {
+ ERROR("couldn't allocate memory");
+ err = -ENOMEM;
+ break;
+ }
+ TRACE1("image is at %p", pe_image->image);
+
+ if (copy_from_user(pe_image->image,
+ load_driver->sys_files[i].data,
+ load_driver->sys_files[i].size)) {
+ ERROR("couldn't load file %s",
+ load_driver->sys_files[i].name);
+ err = -EFAULT;
+ break;
+ }
+ pe_image->size = load_driver->sys_files[i].size;
+ driver->num_pe_images++;
+ }
+
+ if (!err && link_pe_images(driver->pe_images, driver->num_pe_images)) {
+ ERROR("couldn't prepare driver '%s'", load_driver->name);
+ err = -EINVAL;
+ }
+
+ if (driver->num_pe_images < load_driver->num_sys_files || err) {
+ for (i = 0; i < driver->num_pe_images; i++)
+ if (driver->pe_images[i].image)
+ vfree(driver->pe_images[i].image);
+ driver->num_pe_images = 0;
+ EXIT1(return err);
+ } else
+ EXIT1(return 0);
+}
+
+struct wrap_bin_file *get_bin_file(char *bin_file_name)
+{
+ int i = 0;
+ struct wrap_driver *driver, *cur;
+
+ ENTER1("%s", bin_file_name);
+ if (down_interruptible(&loader_mutex)) {
+ WARNING("couldn't obtain loader_mutex");
+ EXIT1(return NULL);
+ }
+ driver = NULL;
+ nt_list_for_each_entry(cur, &wrap_drivers, list) {
+ for (i = 0; i < cur->num_bin_files; i++)
+ if (!stricmp(cur->bin_files[i].name, bin_file_name)) {
+ driver = cur;
+ break;
+ }
+ if (driver)
+ break;
+ }
+ up(&loader_mutex);
+ if (!driver) {
+ TRACE1("coudln't find bin file '%s'", bin_file_name);
+ return NULL;
+ }
+
+ if (!driver->bin_files[i].data) {
+ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_BIN_FILE,
+#if defined(DEBUG) && DEBUG >= 1
+ "1",
+#else
+ "0",
+#endif
+ UTILS_VERSION, driver->name,
+ driver->bin_files[i].name, NULL};
+ char *env[] = {NULL};
+ int ret;
+
+ TRACE1("loading bin file %s/%s", driver->name,
+ driver->bin_files[i].name);
+ if (down_interruptible(&loader_mutex)) {
+ WARNING("couldn't obtain loader_mutex");
+ EXIT1(return NULL);
+ }
+ INIT_COMPLETION(loader_complete);
+ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, 1);
+ if (ret) {
+ up(&loader_mutex);
+ ERROR("couldn't load file %s/%s; check system log "
+ "for messages from 'loadndisdriver' (%d)",
+ driver->name, driver->bin_files[i].name, ret);
+ EXIT1(return NULL);
+ }
+ wait_for_completion(&loader_complete);
+ up(&loader_mutex);
+ if (!driver->bin_files[i].data) {
+ WARNING("couldn't load binary file %s",
+ driver->bin_files[i].name);
+ EXIT1(return NULL);
+ }
+ }
+ EXIT2(return &(driver->bin_files[i]));
+}
+
+/* called with loader_mutex down */
+static int add_bin_file(struct load_driver_file *driver_file)
+{
+ struct wrap_driver *driver, *cur;
+ struct wrap_bin_file *bin_file;
+ int i = 0;
+
+ driver = NULL;
+ nt_list_for_each_entry(cur, &wrap_drivers, list) {
+ for (i = 0; i < cur->num_bin_files; i++)
+ if (!stricmp(cur->bin_files[i].name,
+ driver_file->name)) {
+ driver = cur;
+ break;
+ }
+ if (driver)
+ break;
+ }
+ if (!driver) {
+ ERROR("couldn't find %s", driver_file->name);
+ return -EINVAL;
+ }
+ bin_file = &driver->bin_files[i];
+ strncpy(bin_file->name, driver_file->name, sizeof(bin_file->name));
+ bin_file->name[sizeof(bin_file->name)-1] = 0;
+ bin_file->data = vmalloc(driver_file->size);
+ if (!bin_file->data) {
+ ERROR("couldn't allocate memory");
+ return -ENOMEM;
+ }
+ bin_file->size = driver_file->size;
+ if (copy_from_user(bin_file->data, driver_file->data, bin_file->size)) {
+ ERROR("couldn't copy data");
+ free_bin_file(bin_file);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+void free_bin_file(struct wrap_bin_file *bin_file)
+{
+ TRACE2("unloading %s", bin_file->name);
+ if (bin_file->data)
+ vfree(bin_file->data);
+ bin_file->data = NULL;
+ bin_file->size = 0;
+ EXIT2(return);
+}
+
+/* load firmware files from userspace */
+static int load_bin_files_info(struct wrap_driver *driver,
+ struct load_driver *load_driver)
+{
+ struct wrap_bin_file *bin_files;
+ int i;
+
+ ENTER1("%s, %d", load_driver->name, load_driver->num_bin_files);
+ driver->num_bin_files = 0;
+ driver->bin_files = NULL;
+ if (load_driver->num_bin_files == 0)
+ EXIT1(return 0);
+ bin_files = kzalloc(load_driver->num_bin_files * sizeof(*bin_files),
+ GFP_KERNEL);
+ if (!bin_files) {
+ ERROR("couldn't allocate memory");
+ EXIT1(return -ENOMEM);
+ }
+
+ for (i = 0; i < load_driver->num_bin_files; i++) {
+ strncpy(bin_files[i].name, load_driver->bin_files[i].name,
+ sizeof(bin_files[i].name));
+ bin_files[i].name[sizeof(bin_files[i].name)-1] = 0;
+ TRACE2("loaded bin file %s", bin_files[i].name);
+ }
+ driver->num_bin_files = load_driver->num_bin_files;
+ driver->bin_files = bin_files;
+ EXIT1(return 0);
+}
+
+/* load settnigs for a device. called with loader_mutex down */
+static int load_settings(struct wrap_driver *wrap_driver,
+ struct load_driver *load_driver)
+{
+ int i, num_settings;
+
+ ENTER1("%p, %p", wrap_driver, load_driver);
+
+ num_settings = 0;
+ for (i = 0; i < load_driver->num_settings; i++) {
+ struct load_device_setting *load_setting =
+ &load_driver->settings[i];
+ struct wrap_device_setting *setting;
+ ULONG data1;
+
+ setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+ if (!setting) {
+ ERROR("couldn't allocate memory");
+ break;
+ }
+ strncpy(setting->name, load_setting->name,
+ sizeof(setting->name));
+ setting->name[sizeof(setting->name)-1] = 0;
+ strncpy(setting->value, load_setting->value,
+ sizeof(setting->value));
+ setting->value[sizeof(setting->value)-1] = 0;
+ TRACE2("%p: %s=%s", setting, setting->name, setting->value);
+
+ if (strcmp(setting->name, "driver_version") == 0) {
+ strncpy(wrap_driver->version, setting->value,
+ sizeof(wrap_driver->version));
+ wrap_driver->version[sizeof(wrap_driver->version)-1] = 0;
+ } else if (strcmp(setting->name, "class_guid") == 0 &&
+ sscanf(setting->value, "%x", &data1) == 1) {
+ wrap_driver->dev_type = wrap_device_type(data1);
+ if (wrap_driver->dev_type < 0) {
+ WARNING("unknown guid: %x", data1);
+ wrap_driver->dev_type = 0;
+ }
+ }
+ InsertTailList(&wrap_driver->settings, &setting->list);
+ num_settings++;
+ }
+ /* it is not a fatal error if some settings couldn't be loaded */
+ if (num_settings > 0)
+ EXIT1(return 0);
+ else
+ EXIT1(return -EINVAL);
+}
+
+void unload_wrap_device(struct wrap_device *wd)
+{
+ struct nt_list *cur;
+ ENTER1("unloading device %p (%04X:%04X:%04X:%04X), driver %s", wd,
+ wd->vendor, wd->device, wd->subvendor, wd->subdevice,
+ wd->driver_name);
+ if (down_interruptible(&loader_mutex))
+ WARNING("couldn't obtain loader_mutex");
+ while ((cur = RemoveHeadList(&wd->settings))) {
+ struct wrap_device_setting *setting;
+ setting = container_of(cur, struct wrap_device_setting, list);
+ kfree(setting);
+ }
+ RemoveEntryList(&wd->list);
+ up(&loader_mutex);
+ kfree(wd);
+ EXIT1(return);
+}
+
+/* should be called with loader_mutex down */
+void unload_wrap_driver(struct wrap_driver *driver)
+{
+ int i;
+ struct driver_object *drv_obj;
+ struct nt_list *cur, *next;
+
+ ENTER1("unloading driver: %s (%p)", driver->name, driver);
+ TRACE1("freeing %d images", driver->num_pe_images);
+ drv_obj = driver->drv_obj;
+ for (i = 0; i < driver->num_pe_images; i++)
+ if (driver->pe_images[i].image) {
+ TRACE1("freeing image at %p",
+ driver->pe_images[i].image);
+ vfree(driver->pe_images[i].image);
+ }
+
+ TRACE1("freeing %d bin files", driver->num_bin_files);
+ for (i = 0; i < driver->num_bin_files; i++) {
+ TRACE1("freeing image at %p", driver->bin_files[i].data);
+ if (driver->bin_files[i].data)
+ vfree(driver->bin_files[i].data);
+ }
+ if (driver->bin_files)
+ kfree(driver->bin_files);
+ RtlFreeUnicodeString(&drv_obj->name);
+ RemoveEntryList(&driver->list);
+ nt_list_for_each_safe(cur, next, &driver->settings) {
+ struct wrap_device_setting *setting;
+ struct ndis_configuration_parameter *param;
+
+ setting = container_of(cur, struct wrap_device_setting, list);
+ TRACE2("%p", setting);
+ param = setting->encoded;
+ if (param) {
+ TRACE2("%p", param);
+ if (param->type == NdisParameterString)
+ RtlFreeUnicodeString(¶m->data.string);
+ ExFreePool(param);
+ }
+ kfree(setting);
+ }
+ /* this frees driver */
+ free_custom_extensions(drv_obj->drv_ext);
+ kfree(drv_obj->drv_ext);
+ TRACE1("drv_obj: %p", drv_obj);
+
+ EXIT1(return);
+}
+
+/* call the entry point of the driver */
+static int start_wrap_driver(struct wrap_driver *driver)
+{
+ int i;
+ NTSTATUS ret, res;
+ struct driver_object *drv_obj;
+ typeof(driver->pe_images[0].entry) entry;
+
+ ENTER1("%s", driver->name);
+ drv_obj = driver->drv_obj;
+ for (ret = res = 0, i = 0; i < driver->num_pe_images; i++)
+ /* dlls are already started by loader */
+ if (driver->pe_images[i].type == IMAGE_FILE_EXECUTABLE_IMAGE) {
+ entry = driver->pe_images[i].entry;
+ drv_obj->start = driver->pe_images[i].entry;
+ drv_obj->driver_size = driver->pe_images[i].size;
+ TRACE1("entry: %p, %p, drv_obj: %p",
+ entry, *entry, drv_obj);
+ res = LIN2WIN2(entry, drv_obj, &drv_obj->name);
+ ret |= res;
+ TRACE1("entry returns %08X", res);
+ break;
+ }
+ if (ret) {
+ ERROR("driver initialization failed: %08X", ret);
+ RtlFreeUnicodeString(&drv_obj->name);
+ /* this frees ndis_driver */
+ free_custom_extensions(drv_obj->drv_ext);
+ kfree(drv_obj->drv_ext);
+ TRACE1("drv_obj: %p", drv_obj);
+ ObDereferenceObject(drv_obj);
+ EXIT1(return -EINVAL);
+ }
+ EXIT1(return 0);
+}
+
+/*
+ * add driver to list of loaded driver but make sure this driver is
+ * not loaded before. called with loader_mutex down
+ */
+static int add_wrap_driver(struct wrap_driver *driver)
+{
+ struct wrap_driver *tmp;
+
+ ENTER1("name: %s", driver->name);
+ nt_list_for_each_entry(tmp, &wrap_drivers, list) {
+ if (stricmp(tmp->name, driver->name) == 0) {
+ ERROR("cannot add duplicate driver");
+ EXIT1(return -EBUSY);
+ }
+ }
+ InsertHeadList(&wrap_drivers, &driver->list);
+ EXIT1(return 0);
+}
+
+/* load a driver from userspace and initialize it. called with
+ * loader_mutex down */
+static int load_user_space_driver(struct load_driver *load_driver)
+{
+ struct driver_object *drv_obj;
+ struct ansi_string ansi_reg;
+ struct wrap_driver *wrap_driver = NULL;
+
+ ENTER1("%p", load_driver);
+ drv_obj = allocate_object(sizeof(*drv_obj), OBJECT_TYPE_DRIVER, NULL);
+ if (!drv_obj) {
+ ERROR("couldn't allocate memory");
+ EXIT1(return -ENOMEM);
+ }
+ TRACE1("drv_obj: %p", drv_obj);
+ drv_obj->drv_ext = kzalloc(sizeof(*(drv_obj->drv_ext)), GFP_KERNEL);
+ if (!drv_obj->drv_ext) {
+ ERROR("couldn't allocate memory");
+ ObDereferenceObject(drv_obj);
+ EXIT1(return -ENOMEM);
+ }
+ InitializeListHead(&drv_obj->drv_ext->custom_ext);
+ if (IoAllocateDriverObjectExtension(drv_obj,
+ (void *)WRAP_DRIVER_CLIENT_ID,
+ sizeof(*wrap_driver),
+ (void **)&wrap_driver) !=
+ STATUS_SUCCESS)
+ EXIT1(return -ENOMEM);
+ TRACE1("driver: %p", wrap_driver);
+ memset(wrap_driver, 0, sizeof(*wrap_driver));
+ InitializeListHead(&wrap_driver->list);
+ InitializeListHead(&wrap_driver->settings);
+ InitializeListHead(&wrap_driver->wrap_devices);
+ wrap_driver->drv_obj = drv_obj;
+ RtlInitAnsiString(&ansi_reg, "/tmp");
+ if (RtlAnsiStringToUnicodeString(&drv_obj->name, &ansi_reg, TRUE) !=
+ STATUS_SUCCESS) {
+ ERROR("couldn't initialize registry path");
+ free_custom_extensions(drv_obj->drv_ext);
+ kfree(drv_obj->drv_ext);
+ TRACE1("drv_obj: %p", drv_obj);
+ ObDereferenceObject(drv_obj);
+ EXIT1(return -EINVAL);
+ }
+ strncpy(wrap_driver->name, load_driver->name, sizeof(wrap_driver->name));
+ wrap_driver->name[sizeof(wrap_driver->name)-1] = 0;
+ if (load_sys_files(wrap_driver, load_driver) ||
+ load_bin_files_info(wrap_driver, load_driver) ||
+ load_settings(wrap_driver, load_driver) ||
+ start_wrap_driver(wrap_driver) ||
+ add_wrap_driver(wrap_driver)) {
+ unload_wrap_driver(wrap_driver);
+ EXIT1(return -EINVAL);
+ } else {
+ printk(KERN_INFO "%s: driver %s (%s) loaded\n",
+ DRIVER_NAME, wrap_driver->name, wrap_driver->version);
+ add_taint(TAINT_PROPRIETARY_MODULE);
+ EXIT1(return 0);
+ }
+}
+
+static struct pci_device_id wrap_pci_id_table[] = {
+ {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID},
+};
+
+static struct pci_driver wrap_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = wrap_pci_id_table,
+ .probe = wrap_pnp_start_pci_device,
+ .remove = __devexit_p(wrap_pnp_remove_pci_device),
+ .suspend = wrap_pnp_suspend_pci_device,
+ .resume = wrap_pnp_resume_pci_device,
+};
+
+#ifdef ENABLE_USB
+static struct usb_device_id wrap_usb_id_table[] = {
+ {
+ .driver_info = 1
+ },
+};
+
+static struct usb_driver wrap_usb_driver = {
+ .name = DRIVER_NAME,
+ .id_table = wrap_usb_id_table,
+ .probe = wrap_pnp_start_usb_device,
+ .disconnect = __devexit_p(wrap_pnp_remove_usb_device),
+ .suspend = wrap_pnp_suspend_usb_device,
+ .resume = wrap_pnp_resume_usb_device,
+};
+#endif
+
+/* register drivers for pci and usb */
+static void register_devices(void)
+{
+ int res;
+
+ res = pci_register_driver(&wrap_pci_driver);
+ if (res < 0) {
+ ERROR("couldn't register pci driver: %d", res);
+ wrap_pci_driver.name = NULL;
+ }
+
+#ifdef ENABLE_USB
+ res = usb_register(&wrap_usb_driver);
+ if (res < 0) {
+ ERROR("couldn't register usb driver: %d", res);
+ wrap_usb_driver.name = NULL;
+ }
+#endif
+ EXIT1(return);
+}
+
+static void unregister_devices(void)
+{
+ struct nt_list *cur, *next;
+
+ if (down_interruptible(&loader_mutex))
+ WARNING("couldn't obtain loader_mutex");
+ nt_list_for_each_safe(cur, next, &wrap_devices) {
+ struct wrap_device *wd;
+ wd = container_of(cur, struct wrap_device, list);
+ set_bit(HW_PRESENT, &wd->hw_status);
+ }
+ up(&loader_mutex);
+
+ if (wrap_pci_driver.name)
+ pci_unregister_driver(&wrap_pci_driver);
+#ifdef ENABLE_USB
+ if (wrap_usb_driver.name)
+ usb_deregister(&wrap_usb_driver);
+#endif
+}
+
+struct wrap_device *load_wrap_device(struct load_device *load_device)
+{
+ int ret;
+ struct nt_list *cur;
+ struct wrap_device *wd = NULL;
+ char vendor[5], device[5], subvendor[5], subdevice[5], bus[5];
+
+ ENTER1("%04x, %04x, %04x, %04x", load_device->vendor,
+ load_device->device, load_device->subvendor,
+ load_device->subdevice);
+ if (sprintf(vendor, "%04x", load_device->vendor) == 4 &&
+ sprintf(device, "%04x", load_device->device) == 4 &&
+ sprintf(subvendor, "%04x", load_device->subvendor) == 4 &&
+ sprintf(subdevice, "%04x", load_device->subdevice) == 4 &&
+ sprintf(bus, "%04x", load_device->bus) == 4) {
+ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DEVICE,
+#if defined(DEBUG) && DEBUG >= 1
+ "1",
+#else
+ "0",
+#endif
+ UTILS_VERSION, vendor, device,
+ subvendor, subdevice, bus, NULL};
+ char *env[] = {NULL};
+ TRACE2("%s, %s, %s, %s, %s", vendor, device,
+ subvendor, subdevice, bus);
+ if (down_interruptible(&loader_mutex)) {
+ WARNING("couldn't obtain loader_mutex");
+ EXIT1(return NULL);
+ }
+ INIT_COMPLETION(loader_complete);
+ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, 1);
+ if (ret) {
+ up(&loader_mutex);
+ TRACE1("couldn't load device %04x:%04x; check system "
+ "log for messages from 'loadndisdriver'",
+ load_device->vendor, load_device->device);
+ EXIT1(return NULL);
+ }
+ wait_for_completion(&loader_complete);
+ wd = NULL;
+ nt_list_for_each(cur, &wrap_devices) {
+ wd = container_of(cur, struct wrap_device, list);
+ TRACE2("%p, %04x, %04x, %04x, %04x", wd, wd->vendor,
+ wd->device, wd->subvendor, wd->subdevice);
+ if (wd->vendor == load_device->vendor &&
+ wd->device == load_device->device)
+ break;
+ else
+ wd = NULL;
+ }
+ up(&loader_mutex);
+ } else
+ wd = NULL;
+ EXIT1(return wd);
+}
+
+struct wrap_device *get_wrap_device(void *dev, int bus)
+{
+ struct nt_list *cur;
+ struct wrap_device *wd;
+
+ if (down_interruptible(&loader_mutex)) {
+ WARNING("couldn't obtain loader_mutex");
+ return NULL;
+ }
+ wd = NULL;
+ nt_list_for_each(cur, &wrap_devices) {
+ wd = container_of(cur, struct wrap_device, list);
+ if (bus == WRAP_PCI_BUS &&
+ wrap_is_pci_bus(wd->dev_bus) && wd->pci.pdev == dev)
+ break;
+ else if (bus == WRAP_USB_BUS &&
+ wrap_is_usb_bus(wd->dev_bus) && wd->usb.udev == dev)
+ break;
+ else
+ wd = NULL;
+ }
+ up(&loader_mutex);
+ return wd;
+}
+
+/* called with loader_mutex is down */
+static int wrapper_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct load_driver *load_driver;
+ struct load_device load_device;
+ struct load_driver_file load_bin_file;
+ int ret;
+ void __user *addr = (void __user *)arg;
+
+ ENTER1("cmd: %u", cmd);
+
+ ret = 0;
+ switch (cmd) {
+ case WRAP_IOCTL_LOAD_DEVICE:
+ if (copy_from_user(&load_device, addr, sizeof(load_device))) {
+ ret = -EFAULT;
+ break;
+ }
+ TRACE2("%04x, %04x, %04x, %04x", load_device.vendor,
+ load_device.device, load_device.subvendor,
+ load_device.subdevice);
+ if (load_device.vendor) {
+ struct wrap_device *wd;
+ wd = kzalloc(sizeof(*wd), GFP_KERNEL);
+ if (!wd) {
+ ret = -ENOMEM;
+ break;
+ }
+ InitializeListHead(&wd->settings);
+ wd->dev_bus = WRAP_BUS(load_device.bus);
+ wd->vendor = load_device.vendor;
+ wd->device = load_device.device;
+ wd->subvendor = load_device.subvendor;
+ wd->subdevice = load_device.subdevice;
+ strncpy(wd->conf_file_name, load_device.conf_file_name,
+ sizeof(wd->conf_file_name));
+ wd->conf_file_name[sizeof(wd->conf_file_name)-1] = 0;
+ strncpy(wd->driver_name, load_device.driver_name,
+ sizeof(wd->driver_name));
+ wd->driver_name[sizeof(wd->driver_name)-1] = 0;
+ InsertHeadList(&wrap_devices, &wd->list);
+ ret = 0;
+ } else
+ ret = -EINVAL;
+ break;
+ case WRAP_IOCTL_LOAD_DRIVER:
+ TRACE1("loading driver at %p", addr);
+ load_driver = vmalloc(sizeof(*load_driver));
+ if (!load_driver) {
+ ret = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(load_driver, addr, sizeof(*load_driver)))
+ ret = -EFAULT;
+ else
+ ret = load_user_space_driver(load_driver);
+ vfree(load_driver);
+ break;
+ case WRAP_IOCTL_LOAD_BIN_FILE:
+ if (copy_from_user(&load_bin_file, addr, sizeof(load_bin_file)))
+ ret = -EFAULT;
+ else
+ ret = add_bin_file(&load_bin_file);
+ break;
+ default:
+ ERROR("unknown ioctl %u", cmd);
+ ret = -EINVAL;
+ break;
+ }
+ complete(&loader_complete);
+ EXIT1(return ret);
+}
+
+static int wrapper_ioctl_release(struct inode *inode, struct file *file)
+{
+ ENTER1("");
+ return 0;
+}
+
+static struct file_operations wrapper_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = wrapper_ioctl,
+ .release = wrapper_ioctl_release,
+};
+
+static struct miscdevice wrapper_misc = {
+ .name = DRIVER_NAME,
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &wrapper_fops
+};
+
+int loader_init(void)
+{
+ int err;
+
+ InitializeListHead(&wrap_drivers);
+ InitializeListHead(&wrap_devices);
+ init_MUTEX(&loader_mutex);
+ init_completion(&loader_complete);
+ if ((err = misc_register(&wrapper_misc)) < 0 ) {
+ ERROR("couldn't register module (%d)", err);
+ unregister_devices();
+ EXIT1(return err);
+ }
+ register_devices();
+ EXIT1(return 0);
+}
+
+void loader_exit(void)
+{
+ struct nt_list *cur, *next;
+
+ ENTER1("");
+ misc_deregister(&wrapper_misc);
+ unregister_devices();
+ if (down_interruptible(&loader_mutex))
+ WARNING("couldn't obtain loader_mutex");
+ nt_list_for_each_safe(cur, next, &wrap_drivers) {
+ struct wrap_driver *driver;
+ driver = container_of(cur, struct wrap_driver, list);
+ unload_wrap_driver(driver);
+ }
+ up(&loader_mutex);
+ EXIT1(return);
+}
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LOADER_H_
+#define _LOADER_H_
+
+#include "ndiswrapper.h"
+
+#ifndef __KERNEL__
+#define __user
+#endif
+
+struct load_driver_file {
+ char driver_name[MAX_DRIVER_NAME_LEN];
+ char name[MAX_DRIVER_NAME_LEN];
+ size_t size;
+ void __user *data;
+};
+
+struct load_device_setting {
+ char name[MAX_SETTING_NAME_LEN];
+ char value[MAX_SETTING_VALUE_LEN];
+};
+
+struct load_device {
+ int bus;
+ int vendor;
+ int device;
+ int subvendor;
+ int subdevice;
+ char conf_file_name[MAX_DRIVER_NAME_LEN];
+ char driver_name[MAX_DRIVER_NAME_LEN];
+};
+
+struct load_devices {
+ int count;
+ struct load_device *devices;
+};
+
+struct load_driver {
+ char name[MAX_DRIVER_NAME_LEN];
+ char conf_file_name[MAX_DRIVER_NAME_LEN];
+ unsigned int num_sys_files;
+ struct load_driver_file sys_files[MAX_DRIVER_PE_IMAGES];
+ unsigned int num_settings;
+ struct load_device_setting settings[MAX_DEVICE_SETTINGS];
+ unsigned int num_bin_files;
+ struct load_driver_file bin_files[MAX_DRIVER_BIN_FILES];
+};
+
+#define WRAP_IOCTL_LOAD_DEVICE _IOW(('N' + 'd' + 'i' + 'S'), 0, \
+ struct load_device *)
+#define WRAP_IOCTL_LOAD_DRIVER _IOW(('N' + 'd' + 'i' + 'S'), 1, \
+ struct load_driver *)
+#define WRAP_IOCTL_LOAD_BIN_FILE _IOW(('N' + 'd' + 'i' + 'S'), 2, \
+ struct load_driver_file *)
+
+#define WRAP_CMD_LOAD_DEVICE "load_device"
+#define WRAP_CMD_LOAD_DRIVER "load_driver"
+#define WRAP_CMD_LOAD_BIN_FILE "load_bin_file"
+
+int loader_init(void);
+void loader_exit(void);
+
+#ifdef __KERNEL__
+struct wrap_device *load_wrap_device(struct load_device *load_device);
+struct wrap_driver *load_wrap_driver(struct wrap_device *device);
+struct wrap_bin_file *get_bin_file(char *bin_file_name);
+void free_bin_file(struct wrap_bin_file *bin_file);
+void unload_wrap_driver(struct wrap_driver *driver);
+void unload_wrap_device(struct wrap_device *wd);
+struct wrap_device *get_wrap_device(void *dev, int bus_type);
+
+extern struct semaphore loader_mutex;
+#endif
+
+#endif /* LOADER_H */
+
--- /dev/null
+/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
+ Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+ Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* You have to define the following before including this file:
+
+ UWtype -- An unsigned type, default type for operations (typically a "word")
+ UHWtype -- An unsigned type, at least half the size of UWtype.
+ UDWtype -- An unsigned type, at least twice as large a UWtype
+ W_TYPE_SIZE -- size in bits of UWtype
+
+ UQItype -- Unsigned 8 bit type.
+ SItype, USItype -- Signed and unsigned 32 bit types.
+ DItype, UDItype -- Signed and unsigned 64 bit types.
+
+ On a 32 bit machine UWtype should typically be USItype;
+ on a 64 bit machine, UWtype should typically be UDItype.
+*/
+
+#define __BITS4 (W_TYPE_SIZE / 4)
+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
+
+#ifndef W_TYPE_SIZE
+#define W_TYPE_SIZE 32
+#define UWtype USItype
+#define UHWtype USItype
+#define UDWtype UDItype
+#endif
+
+/* Define auxiliary asm macros.
+
+ 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two
+ UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
+ word product in HIGH_PROD and LOW_PROD.
+
+ 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a
+ UDWtype product. This is just a variant of umul_ppmm.
+
+ 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+ denominator) divides a UDWtype, composed by the UWtype integers
+ HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
+ in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less
+ than DENOMINATOR for correct operation. If, in addition, the most
+ significant bit of DENOMINATOR must be 1, then the pre-processor symbol
+ UDIV_NEEDS_NORMALIZATION is defined to 1.
+
+ 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+ denominator). Like udiv_qrnnd but the numbers are signed. The quotient
+ is rounded towards 0.
+
+ 5) count_leading_zeros(count, x) counts the number of zero-bits from the
+ msb to the first nonzero bit in the UWtype X. This is the number of
+ steps X needs to be shifted left to set the msb. Undefined for X == 0,
+ unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value.
+
+ 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts
+ from the least significant end.
+
+ 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
+ high_addend_2, low_addend_2) adds two UWtype integers, composed by
+ HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
+ respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow
+ (i.e. carry out) is not stored anywhere, and is lost.
+
+ 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
+ high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
+ composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
+ LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE
+ and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere,
+ and is lost.
+
+ If any of these macros are left undefined for a particular CPU,
+ C macros are used. */
+
+/* The CPUs come in alphabetical order below.
+
+ Please add support for more CPUs here, or improve the current support
+ for the CPUs below!
+ (E.g. WE32100, IBM360.) */
+
+#if defined (__GNUC__) && !defined (NO_ASM)
+
+/* We sometimes need to clobber "cc" with gcc2, but that would not be
+ understood by gcc1. Use cpp to avoid major code duplication. */
+#if __GNUC__ < 2
+#define __CLOBBER_CC
+#define __AND_CLOBBER_CC
+#else /* __GNUC__ >= 2 */
+#define __CLOBBER_CC : "cc"
+#define __AND_CLOBBER_CC , "cc"
+#endif /* __GNUC__ < 2 */
+
+#if defined (__alpha) && W_TYPE_SIZE == 64
+#define umul_ppmm(ph, pl, m0, m1) \
+ do { \
+ UDItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("umulh %r1,%2,%0" \
+ : "=r" ((UDItype) ph) \
+ : "%rJ" (__m0), \
+ "rI" (__m1)); \
+ (pl) = __m0 * __m1; \
+ } while (0)
+#define UMUL_TIME 46
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ do { UDItype __r; \
+ (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \
+ (r) = __r; \
+ } while (0)
+extern UDItype __udiv_qrnnd (UDItype *, UDItype, UDItype, UDItype);
+#define UDIV_TIME 220
+#endif /* LONGLONG_STANDALONE */
+#ifdef __alpha_cix__
+#define count_leading_zeros(COUNT,X) \
+ __asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X))
+#define count_trailing_zeros(COUNT,X) \
+ __asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X))
+#define COUNT_LEADING_ZEROS_0 64
+#else
+extern const UQItype __clz_tab[];
+#define count_leading_zeros(COUNT,X) \
+ do { \
+ UDItype __xr = (X), __t, __a; \
+ __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \
+ __a = __clz_tab[__t ^ 0xff] - 1; \
+ __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \
+ (COUNT) = 64 - (__clz_tab[__t] + __a*8); \
+ } while (0)
+#define count_trailing_zeros(COUNT,X) \
+ do { \
+ UDItype __xr = (X), __t, __a; \
+ __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \
+ __t = ~__t & -~__t; \
+ __a = ((__t & 0xCC) != 0) * 2; \
+ __a += ((__t & 0xF0) != 0) * 4; \
+ __a += ((__t & 0xAA) != 0); \
+ __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \
+ __a <<= 3; \
+ __t &= -__t; \
+ __a += ((__t & 0xCC) != 0) * 2; \
+ __a += ((__t & 0xF0) != 0) * 4; \
+ __a += ((__t & 0xAA) != 0); \
+ (COUNT) = __a; \
+ } while (0)
+#endif /* __alpha_cix__ */
+#endif /* __alpha */
+
+#if defined (__arc__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add.f %1, %4, %5\n\tadc %0, %2, %3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%r" ((USItype) (ah)), \
+ "rIJ" ((USItype) (bh)), \
+ "%r" ((USItype) (al)), \
+ "rIJ" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub.f %1, %4, %5\n\tsbc %0, %2, %3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (ah)), \
+ "rIJ" ((USItype) (bh)), \
+ "r" ((USItype) (al)), \
+ "rIJ" ((USItype) (bl)))
+/* Call libgcc routine. */
+#define umul_ppmm(w1, w0, u, v) \
+do { \
+ DWunion __w; \
+ __w.ll = __umulsidi3 (u, v); \
+ w1 = __w.s.high; \
+ w0 = __w.s.low; \
+} while (0)
+#define __umulsidi3 __umulsidi3
+UDItype __umulsidi3 (USItype, USItype);
+#endif
+
+#if defined (__arm__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("adds %1, %4, %5\n\tadc %0, %2, %3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%r" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "%r" ((USItype) (al)), \
+ "rI" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "r" ((USItype) (al)), \
+ "rI" ((USItype) (bl)))
+#define umul_ppmm(xh, xl, a, b) \
+{register USItype __t0, __t1, __t2; \
+ __asm__ ("%@ Inlined umul_ppmm\n" \
+ " mov %2, %5, lsr #16\n" \
+ " mov %0, %6, lsr #16\n" \
+ " bic %3, %5, %2, lsl #16\n" \
+ " bic %4, %6, %0, lsl #16\n" \
+ " mul %1, %3, %4\n" \
+ " mul %4, %2, %4\n" \
+ " mul %3, %0, %3\n" \
+ " mul %0, %2, %0\n" \
+ " adds %3, %4, %3\n" \
+ " addcs %0, %0, #65536\n" \
+ " adds %1, %1, %3, lsl #16\n" \
+ " adc %0, %0, %3, lsr #16" \
+ : "=&r" ((USItype) (xh)), \
+ "=r" ((USItype) (xl)), \
+ "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \
+ : "r" ((USItype) (a)), \
+ "r" ((USItype) (b)));}
+#define UMUL_TIME 20
+#define UDIV_TIME 100
+#endif /* __arm__ */
+
+#if defined (__hppa) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add %4,%5,%1\n\taddc %2,%3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%rM" ((USItype) (ah)), \
+ "rM" ((USItype) (bh)), \
+ "%rM" ((USItype) (al)), \
+ "rM" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub %4,%5,%1\n\tsubb %2,%3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "rM" ((USItype) (ah)), \
+ "rM" ((USItype) (bh)), \
+ "rM" ((USItype) (al)), \
+ "rM" ((USItype) (bl)))
+#if defined (_PA_RISC1_1)
+#define umul_ppmm(w1, w0, u, v) \
+ do { \
+ union \
+ { \
+ UDItype __f; \
+ struct {USItype __w1, __w0;} __w1w0; \
+ } __t; \
+ __asm__ ("xmpyu %1,%2,%0" \
+ : "=x" (__t.__f) \
+ : "x" ((USItype) (u)), \
+ "x" ((USItype) (v))); \
+ (w1) = __t.__w1w0.__w1; \
+ (w0) = __t.__w1w0.__w0; \
+ } while (0)
+#define UMUL_TIME 8
+#else
+#define UMUL_TIME 30
+#endif
+#define UDIV_TIME 40
+#define count_leading_zeros(count, x) \
+ do { \
+ USItype __tmp; \
+ __asm__ ( \
+ "ldi 1,%0\n" \
+" extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \
+" extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n"\
+" ldo 16(%0),%0 ; Yes. Perform add.\n" \
+" extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \
+" extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n"\
+" ldo 8(%0),%0 ; Yes. Perform add.\n" \
+" extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \
+" extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n"\
+" ldo 4(%0),%0 ; Yes. Perform add.\n" \
+" extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \
+" extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n"\
+" ldo 2(%0),%0 ; Yes. Perform add.\n" \
+" extru %1,30,1,%1 ; Extract bit 1.\n" \
+" sub %0,%1,%0 ; Subtract it.\n" \
+ : "=r" (count), "=r" (__tmp) : "1" (x)); \
+ } while (0)
+#endif
+
+#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32
+#define umul_ppmm(xh, xl, m0, m1) \
+ do { \
+ union {UDItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mr %0,%3" \
+ : "=r" (__xx.__i.__h), \
+ "=r" (__xx.__i.__l) \
+ : "%1" (__m0), \
+ "r" (__m1)); \
+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+ (xh) += ((((SItype) __m0 >> 31) & __m1) \
+ + (((SItype) __m1 >> 31) & __m0)); \
+ } while (0)
+#define smul_ppmm(xh, xl, m0, m1) \
+ do { \
+ union {DItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ __asm__ ("mr %0,%3" \
+ : "=r" (__xx.__i.__h), \
+ "=r" (__xx.__i.__l) \
+ : "%1" (m0), \
+ "r" (m1)); \
+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+ } while (0)
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+ do { \
+ union {DItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ __xx.__i.__h = n1; __xx.__i.__l = n0; \
+ __asm__ ("dr %0,%2" \
+ : "=r" (__xx.__ll) \
+ : "0" (__xx.__ll), "r" (d)); \
+ (q) = __xx.__i.__l; (r) = __xx.__i.__h; \
+ } while (0)
+#endif
+
+#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addl %5,%1\n\tadcl %3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subl %5,%1\n\tsbbl %3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("mull %3" \
+ : "=a" ((USItype) (w0)), \
+ "=d" ((USItype) (w1)) \
+ : "%0" ((USItype) (u)), \
+ "rm" ((USItype) (v)))
+#define udiv_qrnnd(q, r, n1, n0, dv) \
+ __asm__ ("divl %4" \
+ : "=a" ((USItype) (q)), \
+ "=d" ((USItype) (r)) \
+ : "0" ((USItype) (n0)), \
+ "1" ((USItype) (n1)), \
+ "rm" ((USItype) (dv)))
+#define count_leading_zeros(count, x) \
+ do { \
+ USItype __cbtmp; \
+ __asm__ ("bsrl %1,%0" \
+ : "=r" (__cbtmp) : "rm" ((USItype) (x))); \
+ (count) = __cbtmp ^ 31; \
+ } while (0)
+#define count_trailing_zeros(count, x) \
+ __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
+#define UMUL_TIME 40
+#define UDIV_TIME 40
+#endif /* 80x86 */
+
+#if defined (__i960__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+ ({union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ __asm__ ("emul %2,%1,%0" \
+ : "=d" (__xx.__ll) \
+ : "%dI" ((USItype) (u)), \
+ "dI" ((USItype) (v))); \
+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
+#define __umulsidi3(u, v) \
+ ({UDItype __w; \
+ __asm__ ("emul %2,%1,%0" \
+ : "=d" (__w) \
+ : "%dI" ((USItype) (u)), \
+ "dI" ((USItype) (v))); \
+ __w; })
+#endif /* __i960__ */
+
+#if defined (__M32R__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ /* The cmp clears the condition bit. */ \
+ __asm__ ("cmp %0,%0\n\taddx %%5,%1\n\taddx %%3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "r" ((USItype) (bl)) \
+ : "cbit")
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ /* The cmp clears the condition bit. */ \
+ __asm__ ("cmp %0,%0\n\tsubx %5,%1\n\tsubx %3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "r" ((USItype) (bl)) \
+ : "cbit")
+#endif /* __M32R__ */
+
+#if defined (__mc68000__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \
+ : "=d" ((USItype) (sh)), \
+ "=&d" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "d" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0" \
+ : "=d" ((USItype) (sh)), \
+ "=&d" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "d" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
+
+/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r. */
+#if defined (__mc68020__) || defined(mc68020) \
+ || defined(__mc68030__) || defined(mc68030) \
+ || defined(__mc68040__) || defined(mc68040) \
+ || defined(__mcpu32__) || defined(mcpu32)
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("mulu%.l %3,%1:%0" \
+ : "=d" ((USItype) (w0)), \
+ "=d" ((USItype) (w1)) \
+ : "%0" ((USItype) (u)), \
+ "dmi" ((USItype) (v)))
+#define UMUL_TIME 45
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ __asm__ ("divu%.l %4,%1:%0" \
+ : "=d" ((USItype) (q)), \
+ "=d" ((USItype) (r)) \
+ : "0" ((USItype) (n0)), \
+ "1" ((USItype) (n1)), \
+ "dmi" ((USItype) (d)))
+#define UDIV_TIME 90
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+ __asm__ ("divs%.l %4,%1:%0" \
+ : "=d" ((USItype) (q)), \
+ "=d" ((USItype) (r)) \
+ : "0" ((USItype) (n0)), \
+ "1" ((USItype) (n1)), \
+ "dmi" ((USItype) (d)))
+
+#else /* not mc68020 */
+#if !defined(__mcf5200__)
+/* %/ inserts REGISTER_PREFIX, %# inserts IMMEDIATE_PREFIX. */
+#define umul_ppmm(xh, xl, a, b) \
+ __asm__ ("| Inlined umul_ppmm\n" \
+ " move%.l %2,%/d0\n" \
+ " move%.l %3,%/d1\n" \
+ " move%.l %/d0,%/d2\n" \
+ " swap %/d0\n" \
+ " move%.l %/d1,%/d3\n" \
+ " swap %/d1\n" \
+ " move%.w %/d2,%/d4\n" \
+ " mulu %/d3,%/d4\n" \
+ " mulu %/d1,%/d2\n" \
+ " mulu %/d0,%/d3\n" \
+ " mulu %/d0,%/d1\n" \
+ " move%.l %/d4,%/d0\n" \
+ " eor%.w %/d0,%/d0\n" \
+ " swap %/d0\n" \
+ " add%.l %/d0,%/d2\n" \
+ " add%.l %/d3,%/d2\n" \
+ " jcc 1f\n" \
+ " add%.l %#65536,%/d1\n" \
+ "1: swap %/d2\n" \
+ " moveq %#0,%/d0\n" \
+ " move%.w %/d2,%/d0\n" \
+ " move%.w %/d4,%/d2\n" \
+ " move%.l %/d2,%1\n" \
+ " add%.l %/d1,%/d0\n" \
+ " move%.l %/d0,%0" \
+ : "=g" ((USItype) (xh)), \
+ "=g" ((USItype) (xl)) \
+ : "g" ((USItype) (a)), \
+ "g" ((USItype) (b)) \
+ : "d0", "d1", "d2", "d3", "d4")
+#define UMUL_TIME 100
+#define UDIV_TIME 400
+#endif /* not mcf5200 */
+#endif /* not mc68020 */
+
+/* The '020, '030, '040 and '060 have bitfield insns. */
+#if defined (__mc68020__) || defined(mc68020) \
+ || defined(__mc68030__) || defined(mc68030) \
+ || defined(__mc68040__) || defined(mc68040) \
+ || defined(__mc68060__) || defined(mc68060)
+#define count_leading_zeros(count, x) \
+ __asm__ ("bfffo %1{%b2:%b2},%0" \
+ : "=d" ((USItype) (count)) \
+ : "od" ((USItype) (x)), "n" (0))
+#endif
+#endif /* mc68000 */
+
+#if defined (__m88000__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%rJ" ((USItype) (ah)), \
+ "rJ" ((USItype) (bh)), \
+ "%rJ" ((USItype) (al)), \
+ "rJ" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "rJ" ((USItype) (ah)), \
+ "rJ" ((USItype) (bh)), \
+ "rJ" ((USItype) (al)), \
+ "rJ" ((USItype) (bl)))
+#define count_leading_zeros(count, x) \
+ do { \
+ USItype __cbtmp; \
+ __asm__ ("ff1 %0,%1" \
+ : "=r" (__cbtmp) \
+ : "r" ((USItype) (x))); \
+ (count) = __cbtmp ^ 31; \
+ } while (0)
+#define COUNT_LEADING_ZEROS_0 63 /* sic */
+#if defined (__mc88110__)
+#define umul_ppmm(wh, wl, u, v) \
+ do { \
+ union {UDItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ __asm__ ("mulu.d %0,%1,%2" \
+ : "=r" (__xx.__ll) \
+ : "r" ((USItype) (u)), \
+ "r" ((USItype) (v))); \
+ (wh) = __xx.__i.__h; \
+ (wl) = __xx.__i.__l; \
+ } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ ({union {UDItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ USItype __q; \
+ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \
+ __asm__ ("divu.d %0,%1,%2" \
+ : "=r" (__q) \
+ : "r" (__xx.__ll), \
+ "r" ((USItype) (d))); \
+ (r) = (n0) - __q * (d); (q) = __q; })
+#define UMUL_TIME 5
+#define UDIV_TIME 25
+#else
+#define UMUL_TIME 17
+#define UDIV_TIME 150
+#endif /* __mc88110__ */
+#endif /* __m88000__ */
+
+#if defined (__mips__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("multu %2,%3" \
+ : "=l" ((USItype) (w0)), \
+ "=h" ((USItype) (w1)) \
+ : "d" ((USItype) (u)), \
+ "d" ((USItype) (v)))
+#define UMUL_TIME 10
+#define UDIV_TIME 100
+#endif /* __mips__ */
+
+#if defined (__ns32000__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+ ({union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ __asm__ ("meid %2,%0" \
+ : "=g" (__xx.__ll) \
+ : "%0" ((USItype) (u)), \
+ "g" ((USItype) (v))); \
+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
+#define __umulsidi3(u, v) \
+ ({UDItype __w; \
+ __asm__ ("meid %2,%0" \
+ : "=g" (__w) \
+ : "%0" ((USItype) (u)), \
+ "g" ((USItype) (v))); \
+ __w; })
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ ({union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \
+ __asm__ ("deid %2,%0" \
+ : "=g" (__xx.__ll) \
+ : "0" (__xx.__ll), \
+ "g" ((USItype) (d))); \
+ (r) = __xx.__i.__l; (q) = __xx.__i.__h; })
+#define count_trailing_zeros(count,x) \
+ do { \
+ __asm__ ("ffsd %2,%0" \
+ : "=r" ((USItype) (count)) \
+ : "0" ((USItype) 0), \
+ "r" ((USItype) (x))); \
+ } while (0)
+#endif /* __ns32000__ */
+
+/* FIXME: We should test _IBMR2 here when we add assembly support for the
+ system vendor compilers.
+ FIXME: What's needed for gcc PowerPC VxWorks? __vxworks__ is not good
+ enough, since that hits ARM and m68k too. */
+#if (defined (_ARCH_PPC) /* AIX */ \
+ || defined (_ARCH_PWR) /* AIX */ \
+ || defined (_ARCH_COM) /* AIX */ \
+ || defined (__powerpc__) /* gcc */ \
+ || defined (__POWERPC__) /* BEOS */ \
+ || defined (__ppc__) /* Darwin */ \
+ || defined (PPC) /* GNU/Linux, SysV */ \
+ ) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ if (__builtin_constant_p (bh) && (bh) == 0) \
+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
+ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \
+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
+ else \
+ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
+ : "=r" (sh), "=&r" (sl) \
+ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \
+ } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ if (__builtin_constant_p (ah) && (ah) == 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
+ else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
+ else if (__builtin_constant_p (bh) && (bh) == 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
+ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
+ else \
+ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
+ : "=r" (sh), "=&r" (sl) \
+ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \
+ } while (0)
+#define count_leading_zeros(count, x) \
+ __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x))
+#define COUNT_LEADING_ZEROS_0 32
+#if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \
+ || defined (__ppc__) || defined (PPC) || defined (__vxworks__)
+#define umul_ppmm(ph, pl, m0, m1) \
+ do { \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \
+ (pl) = __m0 * __m1; \
+ } while (0)
+#define UMUL_TIME 15
+#define smul_ppmm(ph, pl, m0, m1) \
+ do { \
+ SItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \
+ (pl) = __m0 * __m1; \
+ } while (0)
+#define SMUL_TIME 14
+#define UDIV_TIME 120
+#elif defined (_ARCH_PWR)
+#define UMUL_TIME 8
+#define smul_ppmm(xh, xl, m0, m1) \
+ __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1))
+#define SMUL_TIME 4
+#define sdiv_qrnnd(q, r, nh, nl, d) \
+ __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d))
+#define UDIV_TIME 100
+#endif
+#endif /* 32-bit POWER architecture variants. */
+
+/* We should test _IBMR2 here when we add assembly support for the system
+ vendor compilers. */
+#if (defined (_ARCH_PPC64) || defined (__powerpc64__)) && W_TYPE_SIZE == 64
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ if (__builtin_constant_p (bh) && (bh) == 0) \
+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
+ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \
+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
+ else \
+ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
+ : "=r" (sh), "=&r" (sl) \
+ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \
+ } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ if (__builtin_constant_p (ah) && (ah) == 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
+ else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
+ else if (__builtin_constant_p (bh) && (bh) == 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
+ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
+ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
+ else \
+ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
+ : "=r" (sh), "=&r" (sl) \
+ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \
+ } while (0)
+#define count_leading_zeros(count, x) \
+ __asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x))
+#define COUNT_LEADING_ZEROS_0 64
+#define umul_ppmm(ph, pl, m0, m1) \
+ do { \
+ UDItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \
+ (pl) = __m0 * __m1; \
+ } while (0)
+#define UMUL_TIME 15
+#define smul_ppmm(ph, pl, m0, m1) \
+ do { \
+ DItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \
+ (pl) = __m0 * __m1; \
+ } while (0)
+#define SMUL_TIME 14 /* ??? */
+#define UDIV_TIME 120 /* ??? */
+#endif /* 64-bit PowerPC. */
+
+#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("a %1,%5\n\tae %0,%3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "r" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("s %1,%5\n\tse %0,%3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "r" ((USItype) (bl)))
+#define umul_ppmm(ph, pl, m0, m1) \
+ do { \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ( \
+ "s r2,r2\n" \
+" mts r10,%2\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" m r2,%3\n" \
+" cas %0,r2,r0\n" \
+" mfs r10,%1" \
+ : "=r" ((USItype) (ph)), \
+ "=r" ((USItype) (pl)) \
+ : "%r" (__m0), \
+ "r" (__m1) \
+ : "r2"); \
+ (ph) += ((((SItype) __m0 >> 31) & __m1) \
+ + (((SItype) __m1 >> 31) & __m0)); \
+ } while (0)
+#define UMUL_TIME 20
+#define UDIV_TIME 200
+#define count_leading_zeros(count, x) \
+ do { \
+ if ((x) >= 0x10000) \
+ __asm__ ("clz %0,%1" \
+ : "=r" ((USItype) (count)) \
+ : "r" ((USItype) (x) >> 16)); \
+ else \
+ { \
+ __asm__ ("clz %0,%1" \
+ : "=r" ((USItype) (count)) \
+ : "r" ((USItype) (x))); \
+ (count) += 16; \
+ } \
+ } while (0)
+#endif
+
+#if defined (__sh2__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ( \
+ "dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \
+ : "=r" ((USItype)(w1)), \
+ "=r" ((USItype)(w0)) \
+ : "r" ((USItype)(u)), \
+ "r" ((USItype)(v)) \
+ : "macl", "mach")
+#define UMUL_TIME 5
+#endif
+
+#if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32
+#define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v)
+#define count_leading_zeros(count, x) \
+ do \
+ { \
+ UDItype x_ = (USItype)(x); \
+ SItype c_; \
+ \
+ __asm__ ("nsb %1, %0" : "=r" (c_) : "r" (x_)); \
+ (count) = c_ - 31; \
+ } \
+ while (0)
+#define COUNT_LEADING_ZEROS_0 32
+#endif
+
+#if defined (__sparc__) && !defined (__arch64__) && !defined (__sparcv9) \
+ && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%rJ" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "%rJ" ((USItype) (al)), \
+ "rI" ((USItype) (bl)) \
+ __CLOBBER_CC)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "rJ" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "rJ" ((USItype) (al)), \
+ "rI" ((USItype) (bl)) \
+ __CLOBBER_CC)
+#if defined (__sparc_v8__)
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("umul %2,%3,%1;rd %%y,%0" \
+ : "=r" ((USItype) (w1)), \
+ "=r" ((USItype) (w0)) \
+ : "r" ((USItype) (u)), \
+ "r" ((USItype) (v)))
+#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \
+ __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\
+ : "=&r" ((USItype) (__q)), \
+ "=&r" ((USItype) (__r)) \
+ : "r" ((USItype) (__n1)), \
+ "r" ((USItype) (__n0)), \
+ "r" ((USItype) (__d)))
+#else
+#if defined (__sparclite__)
+/* This has hardware multiply but not divide. It also has two additional
+ instructions scan (ffs from high bit) and divscc. */
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("umul %2,%3,%1;rd %%y,%0" \
+ : "=r" ((USItype) (w1)), \
+ "=r" ((USItype) (w0)) \
+ : "r" ((USItype) (u)), \
+ "r" ((USItype) (v)))
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ __asm__ ("! Inlined udiv_qrnnd\n" \
+" wr %%g0,%2,%%y ! Not a delayed write for sparclite\n" \
+" tst %%g0\n" \
+" divscc %3,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%%g1\n" \
+" divscc %%g1,%4,%0\n" \
+" rd %%y,%1\n" \
+" bl,a 1f\n" \
+" add %1,%4,%1\n" \
+"1: ! End of inline udiv_qrnnd" \
+ : "=r" ((USItype) (q)), \
+ "=r" ((USItype) (r)) \
+ : "r" ((USItype) (n1)), \
+ "r" ((USItype) (n0)), \
+ "rI" ((USItype) (d)) \
+ : "g1" __AND_CLOBBER_CC)
+#define UDIV_TIME 37
+#define count_leading_zeros(count, x) \
+ do { \
+ __asm__ ("scan %1,1,%0" \
+ : "=r" ((USItype) (count)) \
+ : "r" ((USItype) (x))); \
+ } while (0)
+/* Early sparclites return 63 for an argument of 0, but they warn that future
+ implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0
+ undefined. */
+#else
+/* SPARC without integer multiplication and divide instructions.
+ (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("! Inlined umul_ppmm\n" \
+" wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr\n"\
+" sra %3,31,%%o5 ! Don't move this insn\n" \
+" and %2,%%o5,%%o5 ! Don't move this insn\n" \
+" andcc %%g0,0,%%g1 ! Don't move this insn\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,%3,%%g1\n" \
+" mulscc %%g1,0,%%g1\n" \
+" add %%g1,%%o5,%0\n" \
+" rd %%y,%1" \
+ : "=r" ((USItype) (w1)), \
+ "=r" ((USItype) (w0)) \
+ : "%rI" ((USItype) (u)), \
+ "r" ((USItype) (v)) \
+ : "g1", "o5" __AND_CLOBBER_CC)
+#define UMUL_TIME 39 /* 39 instructions */
+/* It's quite necessary to add this much assembler for the sparc.
+ The default udiv_qrnnd (in C) is more than 10 times slower! */
+#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \
+ __asm__ ("! Inlined udiv_qrnnd\n" \
+" mov 32,%%g1\n" \
+" subcc %1,%2,%%g0\n" \
+"1: bcs 5f\n" \
+" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \
+" sub %1,%2,%1 ! this kills msb of n\n" \
+" addx %1,%1,%1 ! so this can't give carry\n" \
+" subcc %%g1,1,%%g1\n" \
+"2: bne 1b\n" \
+" subcc %1,%2,%%g0\n" \
+" bcs 3f\n" \
+" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \
+" b 3f\n" \
+" sub %1,%2,%1 ! this kills msb of n\n" \
+"4: sub %1,%2,%1\n" \
+"5: addxcc %1,%1,%1\n" \
+" bcc 2b\n" \
+" subcc %%g1,1,%%g1\n" \
+"! Got carry from n. Subtract next step to cancel this carry.\n" \
+" bne 4b\n" \
+" addcc %0,%0,%0 ! shift n1n0 and a 0-bit in lsb\n" \
+" sub %1,%2,%1\n" \
+"3: xnor %0,0,%0\n" \
+" ! End of inline udiv_qrnnd" \
+ : "=&r" ((USItype) (__q)), \
+ "=&r" ((USItype) (__r)) \
+ : "r" ((USItype) (__d)), \
+ "1" ((USItype) (__n1)), \
+ "0" ((USItype) (__n0)) : "g1" __AND_CLOBBER_CC)
+#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */
+#endif /* __sparclite__ */
+#endif /* __sparc_v8__ */
+#endif /* sparc32 */
+
+#if ((defined (__sparc__) && defined (__arch64__)) || defined (__sparcv9)) \
+ && W_TYPE_SIZE == 64
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addcc %r4,%5,%1\n\t" \
+ "add %r2,%3,%0\n\t" \
+ "bcs,a,pn %%xcc, 1f\n\t" \
+ "add %0, 1, %0\n" \
+ "1:" \
+ : "=r" ((UDItype)(sh)), \
+ "=&r" ((UDItype)(sl)) \
+ : "%rJ" ((UDItype)(ah)), \
+ "rI" ((UDItype)(bh)), \
+ "%rJ" ((UDItype)(al)), \
+ "rI" ((UDItype)(bl)) \
+ __CLOBBER_CC)
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subcc %r4,%5,%1\n\t" \
+ "sub %r2,%3,%0\n\t" \
+ "bcs,a,pn %%xcc, 1f\n\t" \
+ "sub %0, 1, %0\n\t" \
+ "1:" \
+ : "=r" ((UDItype)(sh)), \
+ "=&r" ((UDItype)(sl)) \
+ : "rJ" ((UDItype)(ah)), \
+ "rI" ((UDItype)(bh)), \
+ "rJ" ((UDItype)(al)), \
+ "rI" ((UDItype)(bl)) \
+ __CLOBBER_CC)
+
+#define umul_ppmm(wh, wl, u, v) \
+ do { \
+ UDItype tmp1, tmp2, tmp3, tmp4; \
+ __asm__ __volatile__ ( \
+ "srl %7,0,%3\n\t" \
+ "mulx %3,%6,%1\n\t" \
+ "srlx %6,32,%2\n\t" \
+ "mulx %2,%3,%4\n\t" \
+ "sllx %4,32,%5\n\t" \
+ "srl %6,0,%3\n\t" \
+ "sub %1,%5,%5\n\t" \
+ "srlx %5,32,%5\n\t" \
+ "addcc %4,%5,%4\n\t" \
+ "srlx %7,32,%5\n\t" \
+ "mulx %3,%5,%3\n\t" \
+ "mulx %2,%5,%5\n\t" \
+ "sethi %%hi(0x80000000),%2\n\t" \
+ "addcc %4,%3,%4\n\t" \
+ "srlx %4,32,%4\n\t" \
+ "add %2,%2,%2\n\t" \
+ "movcc %%xcc,%%g0,%2\n\t" \
+ "addcc %5,%4,%5\n\t" \
+ "sllx %3,32,%3\n\t" \
+ "add %1,%3,%1\n\t" \
+ "add %5,%2,%0" \
+ : "=r" ((UDItype)(wh)), \
+ "=&r" ((UDItype)(wl)), \
+ "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \
+ : "r" ((UDItype)(u)), \
+ "r" ((UDItype)(v)) \
+ __CLOBBER_CC); \
+ } while (0)
+#define UMUL_TIME 96
+#define UDIV_TIME 230
+#endif /* sparc64 */
+
+#if defined (__vax__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addl2 %5,%1\n\tadwc %3,%0" \
+ : "=g" ((USItype) (sh)), \
+ "=&g" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subl2 %5,%1\n\tsbwc %3,%0" \
+ : "=g" ((USItype) (sh)), \
+ "=&g" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+ do { \
+ union { \
+ UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("emul %1,%2,$0,%0" \
+ : "=r" (__xx.__ll) \
+ : "g" (__m0), \
+ "g" (__m1)); \
+ (xh) = __xx.__i.__h; \
+ (xl) = __xx.__i.__l; \
+ (xh) += ((((SItype) __m0 >> 31) & __m1) \
+ + (((SItype) __m1 >> 31) & __m0)); \
+ } while (0)
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+ do { \
+ union {DItype __ll; \
+ struct {SItype __l, __h;} __i; \
+ } __xx; \
+ __xx.__i.__h = n1; __xx.__i.__l = n0; \
+ __asm__ ("ediv %3,%2,%0,%1" \
+ : "=g" (q), "=g" (r) \
+ : "g" (__xx.__ll), "g" (d)); \
+ } while (0)
+#endif /* __vax__ */
+
+#if defined (__z8000__) && W_TYPE_SIZE == 16
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \
+ : "=r" ((unsigned int)(sh)), \
+ "=&r" ((unsigned int)(sl)) \
+ : "%0" ((unsigned int)(ah)), \
+ "r" ((unsigned int)(bh)), \
+ "%1" ((unsigned int)(al)), \
+ "rQR" ((unsigned int)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \
+ : "=r" ((unsigned int)(sh)), \
+ "=&r" ((unsigned int)(sl)) \
+ : "0" ((unsigned int)(ah)), \
+ "r" ((unsigned int)(bh)), \
+ "1" ((unsigned int)(al)), \
+ "rQR" ((unsigned int)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+ do { \
+ union {long int __ll; \
+ struct {unsigned int __h, __l;} __i; \
+ } __xx; \
+ unsigned int __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mult %S0,%H3" \
+ : "=r" (__xx.__i.__h), \
+ "=r" (__xx.__i.__l) \
+ : "%1" (__m0), \
+ "rQR" (__m1)); \
+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+ (xh) += ((((signed int) __m0 >> 15) & __m1) \
+ + (((signed int) __m1 >> 15) & __m0)); \
+ } while (0)
+#endif /* __z8000__ */
+
+#endif /* __GNUC__ */
+
+/* If this machine has no inline assembler, use C macros. */
+
+#if !defined (add_ssaaaa)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) + (bl); \
+ (sh) = (ah) + (bh) + (__x < (al)); \
+ (sl) = __x; \
+ } while (0)
+#endif
+
+#if !defined (sub_ddmmss)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) - (bl); \
+ (sh) = (ah) - (bh) - (__x > (al)); \
+ (sl) = __x; \
+ } while (0)
+#endif
+
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+ do { \
+ UWtype __x0, __x1, __x2, __x3; \
+ UHWtype __ul, __vl, __uh, __vh; \
+ \
+ __ul = __ll_lowpart (u); \
+ __uh = __ll_highpart (u); \
+ __vl = __ll_lowpart (v); \
+ __vh = __ll_highpart (v); \
+ \
+ __x0 = (UWtype) __ul * __vl; \
+ __x1 = (UWtype) __ul * __vh; \
+ __x2 = (UWtype) __uh * __vl; \
+ __x3 = (UWtype) __uh * __vh; \
+ \
+ __x1 += __ll_highpart (__x0);/* this can't give carry */ \
+ __x1 += __x2; /* but this indeed can */ \
+ if (__x1 < __x2) /* did we get it? */ \
+ __x3 += __ll_B; /* yes, add it in the proper pos. */ \
+ \
+ (w1) = __x3 + __ll_highpart (__x1); \
+ (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \
+ } while (0)
+#endif
+
+#if !defined (__umulsidi3)
+#define __umulsidi3(u, v) \
+ ({DWunion __w; \
+ umul_ppmm (__w.s.high, __w.s.low, u, v); \
+ __w.ll; })
+#endif
+
+/* Define this unconditionally, so it can be used for debugging. */
+#define __udiv_qrnnd_c(q, r, n1, n0, d) \
+ do { \
+ UWtype __d1, __d0, __q1, __q0; \
+ UWtype __r1, __r0, __m; \
+ __d1 = __ll_highpart (d); \
+ __d0 = __ll_lowpart (d); \
+ \
+ __r1 = (n1) % __d1; \
+ __q1 = (n1) / __d1; \
+ __m = (UWtype) __q1 * __d0; \
+ __r1 = __r1 * __ll_B | __ll_highpart (n0); \
+ if (__r1 < __m) \
+ { \
+ __q1--, __r1 += (d); \
+ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
+ if (__r1 < __m) \
+ __q1--, __r1 += (d); \
+ } \
+ __r1 -= __m; \
+ \
+ __r0 = __r1 % __d1; \
+ __q0 = __r1 / __d1; \
+ __m = (UWtype) __q0 * __d0; \
+ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \
+ if (__r0 < __m) \
+ { \
+ __q0--, __r0 += (d); \
+ if (__r0 >= (d)) \
+ if (__r0 < __m) \
+ __q0--, __r0 += (d); \
+ } \
+ __r0 -= __m; \
+ \
+ (q) = (UWtype) __q1 * __ll_B | __q0; \
+ (r) = __r0; \
+ } while (0)
+
+/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
+ __udiv_w_sdiv (defined in libgcc or elsewhere). */
+#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd)
+#define udiv_qrnnd(q, r, nh, nl, d) \
+ do { \
+ USItype __r; \
+ (q) = __udiv_w_sdiv (&__r, nh, nl, d); \
+ (r) = __r; \
+ } while (0)
+#endif
+
+/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */
+#if !defined (udiv_qrnnd)
+#define UDIV_NEEDS_NORMALIZATION 1
+#define udiv_qrnnd __udiv_qrnnd_c
+#endif
+
+#if !defined (count_leading_zeros)
+extern const UQItype __clz_tab[];
+#define count_leading_zeros(count, x) \
+ do { \
+ UWtype __xr = (x); \
+ UWtype __a; \
+ \
+ if (W_TYPE_SIZE <= 32) \
+ { \
+ __a = __xr < ((UWtype)1<<2*__BITS4) \
+ ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \
+ : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \
+ } \
+ else \
+ { \
+ for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \
+ if (((__xr >> __a) & 0xff) != 0) \
+ break; \
+ } \
+ \
+ (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
+ } while (0)
+#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
+#endif
+
+#if !defined (count_trailing_zeros)
+/* Define count_trailing_zeros using count_leading_zeros. The latter might be
+ defined in asm, but if it is not, the C version above is good enough. */
+#define count_trailing_zeros(count, x) \
+ do { \
+ UWtype __ctz_x = (x); \
+ UWtype __ctz_c; \
+ count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \
+ (count) = W_TYPE_SIZE - 1 - __ctz_c; \
+ } while (0)
+#endif
+
+#ifndef UDIV_NEEDS_NORMALIZATION
+#define UDIV_NEEDS_NORMALIZATION 0
+#endif
--- /dev/null
+#! /bin/sh
+
+# Generate exports symbol table from C files
+
+input="$1"
+output="$2"
+exports=$(basename "$output" .h)
+exec >"$output"
+
+echo "/* automatically generated from src */";
+
+sed -n -e '/^\(wstdcall\|wfastcall\|noregparm\|__attribute__\)/{
+:more
+N
+s/\([^{]\)$/\1/
+t more
+s/\n{$/;/
+p
+}' $input
+
+echo "#ifdef CONFIG_X86_64";
+
+sed -n \
+ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\
+'WIN_FUNC_DECL(\1, \2)/p' \
+ -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\
+'WIN_FUNC_DECL(\1, \2)/p' $input | sort -u
+
+echo "#endif"
+echo "extern struct wrap_export $exports[];"
+echo "struct wrap_export $exports[] = {"
+
+sed -n \
+ -e 's/.*WIN_FUNC(_win_\([^\,]\+\) *\, *\([0-9]\+\)).*/'\
+' WIN_WIN_SYMBOL(\1, \2),/p' \
+ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\
+' WIN_SYMBOL(\1, \2),/p' \
+ -e 's/.*WIN_SYMBOL_MAP(\("[^"]\+"\)[ ,\n]\+\([^)]\+\)).*/'\
+' {\1, (generic_func)\2},/p' $input | sort -u
+
+echo " {NULL, NULL}"
+echo "};"
--- /dev/null
+#! /bin/sh
+
+for file in "$@"; do
+ echo
+ echo "# automatically generated from $file"
+ sed -n \
+ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/\
+ win2lin(\1, \2)/p' \
+ -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/\
+ win2lin(\1, \2)/p' \
+ $file | sed -e 's/[ \t ]\+//' | sort -u; \
+done
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ndis.h"
+#include "iw_ndis.h"
+#include "wrapndis.h"
+#include "pnp.h"
+#include "loader.h"
+#include <linux/kernel_stat.h>
+#include <asm/dma.h>
+#include "ndis_exports.h"
+
+#define MAX_ALLOCATED_NDIS_PACKETS TX_RING_SIZE
+#define MAX_ALLOCATED_NDIS_BUFFERS TX_RING_SIZE
+
+static void ndis_worker(worker_param_t dummy);
+static work_struct_t ndis_work;
+static struct nt_list ndis_work_list;
+static spinlock_t ndis_work_list_lock;
+
+workqueue_struct_t *ndis_wq;
+static struct nt_thread *ndis_worker_thread;
+
+static void *ndis_get_routine_address(char *name);
+
+wstdcall void WIN_FUNC(NdisInitializeWrapper,4)
+ (void **driver_handle, struct driver_object *driver,
+ struct unicode_string *reg_path, void *unused)
+{
+ ENTER1("handle: %p, driver: %p", driver_handle, driver);
+ *driver_handle = driver;
+ EXIT1(return);
+}
+
+wstdcall void WIN_FUNC(NdisTerminateWrapper,2)
+ (struct device_object *dev_obj, void *system_specific)
+{
+ EXIT1(return);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterMiniport,3)
+ (struct driver_object *drv_obj, struct miniport *mp, UINT length)
+{
+ int min_length;
+ struct wrap_driver *wrap_driver;
+ struct ndis_driver *ndis_driver;
+
+ min_length = ((char *)&mp->co_create_vc) - ((char *)mp);
+
+ ENTER1("%p %p %d", drv_obj, mp, length);
+
+ if (mp->major_version < 4) {
+ ERROR("Driver is using ndis version %d which is too old.",
+ mp->major_version);
+ EXIT1(return NDIS_STATUS_BAD_VERSION);
+ }
+
+ if (length < min_length) {
+ ERROR("Characteristics length %d is too small", length);
+ EXIT1(return NDIS_STATUS_BAD_CHARACTERISTICS);
+ }
+
+ TRACE1("%d.%d, %d, %u", mp->major_version, mp->minor_version, length,
+ (u32)sizeof(struct miniport));
+ wrap_driver = IoGetDriverObjectExtension(drv_obj,
+ (void *)WRAP_DRIVER_CLIENT_ID);
+ if (!wrap_driver) {
+ ERROR("couldn't get wrap_driver");
+ EXIT1(return NDIS_STATUS_RESOURCES);
+ }
+ if (IoAllocateDriverObjectExtension(
+ drv_obj, (void *)NDIS_DRIVER_CLIENT_ID,
+ sizeof(*ndis_driver), (void **)&ndis_driver) !=
+ STATUS_SUCCESS)
+ EXIT1(return NDIS_STATUS_RESOURCES);
+ wrap_driver->ndis_driver = ndis_driver;
+ TRACE1("driver: %p", ndis_driver);
+ memcpy(&ndis_driver->mp, mp, min_t(int, sizeof(*mp), length));
+
+ DBG_BLOCK(2) {
+ int i;
+ void **func;
+ char *mp_funcs[] = {
+ "queryinfo", "reconfig", "reset", "send", "setinfo",
+ "tx_data", "return_packet", "send_packets",
+ "alloc_complete", "co_create_vc", "co_delete_vc",
+ "co_activate_vc", "co_deactivate_vc",
+ "co_send_packets", "co_request", "cancel_send_packets",
+ "pnp_event_notify", "shutdown",
+ };
+ func = (void **)&ndis_driver->mp.queryinfo;
+ for (i = 0; i < (sizeof(mp_funcs) / sizeof(mp_funcs[0])); i++)
+ TRACE2("function '%s' is at %p", mp_funcs[i], func[i]);
+ }
+ EXIT1(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterDevice,6)
+ (struct driver_object *drv_obj, struct unicode_string *dev_name,
+ struct unicode_string *link, void **funcs,
+ struct device_object **dev_obj, void **dev_obj_handle)
+{
+ NTSTATUS status;
+ struct device_object *tmp;
+ int i;
+
+ ENTER1("%p, %p, %p", drv_obj, dev_name, link);
+ status = IoCreateDevice(drv_obj, 0, dev_name, FILE_DEVICE_NETWORK, 0,
+ FALSE, &tmp);
+
+ if (status != STATUS_SUCCESS)
+ EXIT1(return NDIS_STATUS_RESOURCES);
+ if (link)
+ status = IoCreateSymbolicLink(link, dev_name);
+ if (status != STATUS_SUCCESS) {
+ IoDeleteDevice(tmp);
+ EXIT1(return NDIS_STATUS_RESOURCES);
+ }
+
+ *dev_obj = tmp;
+ *dev_obj_handle = *dev_obj;
+ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
+ if (funcs[i] && i != IRP_MJ_PNP && i != IRP_MJ_POWER) {
+ drv_obj->major_func[i] = funcs[i];
+ TRACE1("mj_fn for 0x%x is at %p", i, funcs[i]);
+ }
+ EXIT1(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMDeregisterDevice,1)
+ (struct device_object *dev_obj)
+{
+ ENTER2("%p", dev_obj);
+ IoDeleteDevice(dev_obj);
+ return NDIS_STATUS_SUCCESS;
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemoryWithTag,3)
+ (void **dest, UINT length, ULONG tag)
+{
+ void *addr;
+
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ addr = ExAllocatePoolWithTag(NonPagedPool, length, tag);
+ TRACE4("%p", addr);
+ if (addr) {
+ *dest = addr;
+ EXIT4(return NDIS_STATUS_SUCCESS);
+ } else
+ EXIT4(return NDIS_STATUS_FAILURE);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemory,4)
+ (void **dest, UINT length, UINT flags, NDIS_PHY_ADDRESS highest_address)
+{
+ return NdisAllocateMemoryWithTag(dest, length, 0);
+}
+
+/* length_tag is either length or tag, depending on if
+ * NdisAllocateMemory or NdisAllocateMemoryTag is used to allocate
+ * memory */
+wstdcall void WIN_FUNC(NdisFreeMemory,3)
+ (void *addr, UINT length_tag, UINT flags)
+{
+ TRACE4("%p", addr);
+ ExFreePool(addr);
+}
+
+noregparm void WIN_FUNC(NdisWriteErrorLogEntry,12)
+ (struct driver_object *drv_obj, ULONG error, ULONG count, ...)
+{
+ va_list args;
+ int i;
+ ULONG code;
+
+ va_start(args, count);
+ ERROR("log: %08X, count: %d, return_address: %p",
+ error, count, __builtin_return_address(0));
+ for (i = 0; i < count; i++) {
+ code = va_arg(args, ULONG);
+ ERROR("code: 0x%x", code);
+ }
+ va_end(args);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisOpenConfiguration,3)
+ (NDIS_STATUS *status, struct ndis_mp_block **conf_handle,
+ struct ndis_mp_block *handle)
+{
+ ENTER2("%p", conf_handle);
+ *conf_handle = handle;
+ *status = NDIS_STATUS_SUCCESS;
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisOpenProtocolConfiguration,3)
+ (NDIS_STATUS *status, void **confhandle,
+ struct unicode_string *section)
+{
+ ENTER2("%p", confhandle);
+ *status = NDIS_STATUS_SUCCESS;
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByName,4)
+ (NDIS_STATUS *status, void *handle,
+ struct unicode_string *key, void **subkeyhandle)
+{
+ struct ansi_string ansi;
+ ENTER2("");
+ if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE) == STATUS_SUCCESS) {
+ TRACE2("%s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ *subkeyhandle = handle;
+ *status = NDIS_STATUS_SUCCESS;
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByIndex,5)
+ (NDIS_STATUS *status, void *handle, ULONG index,
+ struct unicode_string *key, void **subkeyhandle)
+{
+ ENTER2("%u", index);
+// *subkeyhandle = handle;
+ *status = NDIS_STATUS_FAILURE;
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisCloseConfiguration,1)
+ (void *handle)
+{
+ /* instead of freeing all configuration parameters as we are
+ * supposed to do here, we free them when the device is
+ * removed */
+ ENTER2("%p", handle);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisOpenFile,5)
+ (NDIS_STATUS *status, struct wrap_bin_file **file,
+ UINT *filelength, struct unicode_string *filename,
+ NDIS_PHY_ADDRESS highest_address)
+{
+ struct ansi_string ansi;
+ struct wrap_bin_file *bin_file;
+
+ ENTER2("%p, %d, %llx, %p", status, *filelength, highest_address, *file);
+ if (RtlUnicodeStringToAnsiString(&ansi, filename, TRUE) !=
+ STATUS_SUCCESS) {
+ *status = NDIS_STATUS_RESOURCES;
+ EXIT2(return);
+ }
+ TRACE2("%s", ansi.buf);
+ bin_file = get_bin_file(ansi.buf);
+ if (bin_file) {
+ *file = bin_file;
+ *filelength = bin_file->size;
+ *status = NDIS_STATUS_SUCCESS;
+ } else
+ *status = NDIS_STATUS_FILE_NOT_FOUND;
+
+ RtlFreeAnsiString(&ansi);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisMapFile,3)
+ (NDIS_STATUS *status, void **mappedbuffer, struct wrap_bin_file *file)
+{
+ ENTER2("%p", file);
+
+ if (!file) {
+ *status = NDIS_STATUS_ALREADY_MAPPED;
+ EXIT2(return);
+ }
+
+ *status = NDIS_STATUS_SUCCESS;
+ *mappedbuffer = file->data;
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisUnmapFile,1)
+ (struct wrap_bin_file *file)
+{
+ ENTER2("%p", file);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisCloseFile,1)
+ (struct wrap_bin_file *file)
+{
+ ENTER2("%p", file);
+ free_bin_file(file);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisGetSystemUpTime,1)
+ (ULONG *ms)
+{
+ *ms = 1000 * jiffies / HZ;
+ EXIT5(return);
+}
+
+wstdcall ULONG WIN_FUNC(NDIS_BUFFER_TO_SPAN_PAGES,1)
+ (ndis_buffer *buffer)
+{
+ ULONG n, length;
+
+ if (buffer == NULL)
+ EXIT2(return 0);
+ if (MmGetMdlByteCount(buffer) == 0)
+ EXIT2(return 1);
+
+ length = MmGetMdlByteCount(buffer);
+ n = SPAN_PAGES(MmGetMdlVirtualAddress(buffer), length);
+ TRACE4("%p, %p, %d, %d", buffer->startva, buffer->mappedsystemva,
+ length, n);
+ EXIT3(return n);
+}
+
+wstdcall void WIN_FUNC(NdisGetBufferPhysicalArraySize,2)
+ (ndis_buffer *buffer, UINT *arraysize)
+{
+ ENTER3("%p", buffer);
+ *arraysize = NDIS_BUFFER_TO_SPAN_PAGES(buffer);
+ EXIT3(return);
+}
+
+static struct ndis_configuration_parameter *
+ndis_encode_setting(struct wrap_device_setting *setting,
+ enum ndis_parameter_type type)
+{
+ struct ansi_string ansi;
+ struct ndis_configuration_parameter *param;
+
+ param = setting->encoded;
+ if (param) {
+ if (param->type == type)
+ EXIT2(return param);
+ if (param->type == NdisParameterString)
+ RtlFreeUnicodeString(¶m->data.string);
+ setting->encoded = NULL;
+ } else
+ param = ExAllocatePoolWithTag(NonPagedPool, sizeof(*param), 0);
+ if (!param) {
+ ERROR("couldn't allocate memory");
+ return NULL;
+ }
+ switch(type) {
+ case NdisParameterInteger:
+ param->data.integer = simple_strtol(setting->value, NULL, 0);
+ TRACE2("0x%x", (ULONG)param->data.integer);
+ break;
+ case NdisParameterHexInteger:
+ param->data.integer = simple_strtol(setting->value, NULL, 16);
+ TRACE2("0x%x", (ULONG)param->data.integer);
+ break;
+ case NdisParameterString:
+ RtlInitAnsiString(&ansi, setting->value);
+ TRACE2("'%s'", ansi.buf);
+ if (RtlAnsiStringToUnicodeString(¶m->data.string,
+ &ansi, TRUE)) {
+ ExFreePool(param);
+ EXIT2(return NULL);
+ }
+ break;
+ case NdisParameterBinary:
+ param->data.integer = simple_strtol(setting->value, NULL, 2);
+ TRACE2("0x%x", (ULONG)param->data.integer);
+ break;
+ default:
+ ERROR("unknown type: %d", type);
+ ExFreePool(param);
+ return NULL;
+ }
+ param->type = type;
+ setting->encoded = param;
+ EXIT2(return param);
+}
+
+static int ndis_decode_setting(struct wrap_device_setting *setting,
+ struct ndis_configuration_parameter *param)
+{
+ struct ansi_string ansi;
+ struct ndis_configuration_parameter *prev;
+
+ ENTER2("%p, %p", setting, param);
+ prev = setting->encoded;
+ if (prev && prev->type == NdisParameterString) {
+ RtlFreeUnicodeString(&prev->data.string);
+ setting->encoded = NULL;
+ }
+ switch(param->type) {
+ case NdisParameterInteger:
+ snprintf(setting->value, sizeof(u32), "%u",
+ param->data.integer);
+ setting->value[sizeof(ULONG)] = 0;
+ break;
+ case NdisParameterHexInteger:
+ snprintf(setting->value, sizeof(u32), "%x",
+ param->data.integer);
+ setting->value[sizeof(ULONG)] = 0;
+ break;
+ case NdisParameterString:
+ ansi.buf = setting->value;
+ ansi.max_length = MAX_SETTING_VALUE_LEN;
+ if ((RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string,
+ FALSE) != STATUS_SUCCESS)
+ || ansi.length >= MAX_SETTING_VALUE_LEN) {
+ EXIT1(return -1);
+ }
+ if (ansi.length == ansi.max_length)
+ ansi.length--;
+ setting->value[ansi.length] = 0;
+ break;
+ case NdisParameterBinary:
+ snprintf(setting->value, sizeof(u32), "%u",
+ param->data.integer);
+ setting->value[sizeof(ULONG)] = 0;
+ break;
+ default:
+ TRACE2("unknown setting type: %d", param->type);
+ return -1;
+ }
+ TRACE2("setting changed %s='%s', %d", setting->name, setting->value,
+ ansi.length);
+ return 0;
+}
+
+static int read_setting(struct nt_list *setting_list, char *keyname, int length,
+ struct ndis_configuration_parameter **param,
+ enum ndis_parameter_type type)
+{
+ struct wrap_device_setting *setting;
+ if (down_interruptible(&loader_mutex))
+ WARNING("couldn't obtain loader_mutex");
+ nt_list_for_each_entry(setting, setting_list, list) {
+ if (strnicmp(keyname, setting->name, length) == 0) {
+ TRACE2("setting %s='%s'", keyname, setting->value);
+ up(&loader_mutex);
+ *param = ndis_encode_setting(setting, type);
+ if (*param)
+ EXIT2(return 0);
+ else
+ EXIT2(return -1);
+ }
+ }
+ up(&loader_mutex);
+ EXIT2(return -1);
+}
+
+wstdcall void WIN_FUNC(NdisReadConfiguration,5)
+ (NDIS_STATUS *status, struct ndis_configuration_parameter **param,
+ struct ndis_mp_block *nmb, struct unicode_string *key,
+ enum ndis_parameter_type type)
+{
+ struct ansi_string ansi;
+ int ret;
+
+ ENTER2("nmb: %p", nmb);
+ ret = RtlUnicodeStringToAnsiString(&ansi, key, TRUE);
+ if (ret != STATUS_SUCCESS || ansi.buf == NULL) {
+ *param = NULL;
+ *status = NDIS_STATUS_FAILURE;
+ RtlFreeAnsiString(&ansi);
+ EXIT2(return);
+ }
+ TRACE2("%d, %s", type, ansi.buf);
+
+ if (read_setting(&nmb->wnd->wd->settings, ansi.buf,
+ ansi.length, param, type) == 0 ||
+ read_setting(&nmb->wnd->wd->driver->settings, ansi.buf,
+ ansi.length, param, type) == 0)
+ *status = NDIS_STATUS_SUCCESS;
+ else {
+ TRACE2("setting %s not found (type:%d)", ansi.buf, type);
+ *status = NDIS_STATUS_FAILURE;
+ }
+ RtlFreeAnsiString(&ansi);
+ EXIT2(return);
+
+}
+
+wstdcall void WIN_FUNC(NdisWriteConfiguration,4)
+ (NDIS_STATUS *status, struct ndis_mp_block *nmb,
+ struct unicode_string *key, struct ndis_configuration_parameter *param)
+{
+ struct ansi_string ansi;
+ char *keyname;
+ struct wrap_device_setting *setting;
+
+ ENTER2("nmb: %p", nmb);
+ if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE)) {
+ *status = NDIS_STATUS_FAILURE;
+ EXIT2(return);
+ }
+ keyname = ansi.buf;
+ TRACE2("%s", keyname);
+
+ if (down_interruptible(&loader_mutex))
+ WARNING("couldn't obtain loader_mutex");
+ nt_list_for_each_entry(setting, &nmb->wnd->wd->settings, list) {
+ if (strnicmp(keyname, setting->name, ansi.length) == 0) {
+ up(&loader_mutex);
+ if (ndis_decode_setting(setting, param))
+ *status = NDIS_STATUS_FAILURE;
+ else
+ *status = NDIS_STATUS_SUCCESS;
+ RtlFreeAnsiString(&ansi);
+ EXIT2(return);
+ }
+ }
+ up(&loader_mutex);
+ setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+ if (setting) {
+ if (ansi.length == ansi.max_length)
+ ansi.length--;
+ memcpy(setting->name, keyname, ansi.length);
+ setting->name[ansi.length] = 0;
+ if (ndis_decode_setting(setting, param))
+ *status = NDIS_STATUS_FAILURE;
+ else {
+ *status = NDIS_STATUS_SUCCESS;
+ if (down_interruptible(&loader_mutex))
+ WARNING("couldn't obtain loader_mutex");
+ InsertTailList(&nmb->wnd->wd->settings, &setting->list);
+ up(&loader_mutex);
+ }
+ } else
+ *status = NDIS_STATUS_RESOURCES;
+
+ RtlFreeAnsiString(&ansi);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisReadNetworkAddress,4)
+ (NDIS_STATUS *status, void **addr, UINT *len,
+ struct ndis_mp_block *nmb)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ struct ndis_configuration_parameter *param;
+ struct unicode_string key;
+ struct ansi_string ansi;
+ typeof(wnd->mac) mac;
+ int i, ret;
+
+ ENTER2("%p", nmb);
+ RtlInitAnsiString(&ansi, "NetworkAddress");
+ *status = NDIS_STATUS_FAILURE;
+ if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS)
+ EXIT1(return);
+
+ NdisReadConfiguration(&ret, ¶m, nmb, &key, NdisParameterString);
+ RtlFreeUnicodeString(&key);
+ if (ret != NDIS_STATUS_SUCCESS)
+ EXIT1(return);
+ ret = RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, TRUE);
+ if (ret != STATUS_SUCCESS)
+ EXIT1(return);
+
+ i = 0;
+ if (ansi.length >= 2 * sizeof(mac)) {
+ for (i = 0; i < sizeof(mac); i++) {
+ char c[3];
+ int x;
+ c[0] = ansi.buf[i*2];
+ c[1] = ansi.buf[i*2+1];
+ c[2] = 0;
+ ret = sscanf(c, "%x", &x);
+ if (ret != 1)
+ break;
+ mac[i] = x;
+ }
+ }
+ TRACE2("%s, %d, " MACSTR, ansi.buf, i, MAC2STR(mac));
+ RtlFreeAnsiString(&ansi);
+ if (i == sizeof(mac)) {
+ memcpy(wnd->mac, mac, sizeof(wnd->mac));
+ *len = sizeof(mac);
+ *addr = wnd->mac;
+ *status = NDIS_STATUS_SUCCESS;
+ }
+ EXIT1(return);
+}
+
+wstdcall void WIN_FUNC(NdisInitializeString,2)
+ (struct unicode_string *dest, UCHAR *src)
+{
+ struct ansi_string ansi;
+
+ ENTER2("");
+ if (src == NULL) {
+ dest->length = dest->max_length = 0;
+ dest->buf = NULL;
+ } else {
+ RtlInitAnsiString(&ansi, src);
+ /* the string is freed with NdisFreeMemory */
+ RtlAnsiStringToUnicodeString(dest, &ansi, TRUE);
+ }
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisInitAnsiString,2)
+ (struct ansi_string *dst, CHAR *src)
+{
+ RtlInitAnsiString(dst, src);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisInitUnicodeString,2)
+ (struct unicode_string *dest, const wchar_t *src)
+{
+ RtlInitUnicodeString(dest, src);
+ return;
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisAnsiStringToUnicodeString,2)
+ (struct unicode_string *dst, struct ansi_string *src)
+{
+ ENTER2("");
+ if (dst == NULL || src == NULL)
+ EXIT2(return NDIS_STATUS_FAILURE);
+ if (RtlAnsiStringToUnicodeString(dst, src, FALSE) == STATUS_SUCCESS)
+ return NDIS_STATUS_SUCCESS;
+ else
+ return NDIS_STATUS_FAILURE;
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisUnicodeStringToAnsiString,2)
+ (struct ansi_string *dst, struct unicode_string *src)
+{
+ ENTER2("");
+ if (dst == NULL || src == NULL)
+ EXIT2(return NDIS_STATUS_FAILURE);
+ if (RtlUnicodeStringToAnsiString(dst, src, FALSE) == STATUS_SUCCESS)
+ return NDIS_STATUS_SUCCESS;
+ else
+ return NDIS_STATUS_FAILURE;
+}
+
+wstdcall NTSTATUS WIN_FUNC(NdisUpcaseUnicodeString,2)
+ (struct unicode_string *dst, struct unicode_string *src)
+{
+ EXIT2(return RtlUpcaseUnicodeString(dst, src, FALSE));
+}
+
+wstdcall void WIN_FUNC(NdisMSetAttributesEx,5)
+ (struct ndis_mp_block *nmb, void *mp_ctx,
+ UINT hangcheck_interval, UINT attributes, ULONG adaptertype)
+{
+ struct ndis_device *wnd;
+
+ ENTER1("%p, %p, %d, %08x, %d", nmb, mp_ctx, hangcheck_interval,
+ attributes, adaptertype);
+ wnd = nmb->wnd;
+ nmb->mp_ctx = mp_ctx;
+ wnd->attributes = attributes;
+
+ if ((attributes & NDIS_ATTRIBUTE_BUS_MASTER) &&
+ wrap_is_pci_bus(wnd->wd->dev_bus))
+ pci_set_master(wnd->wd->pci.pdev);
+
+ if (hangcheck_interval > 0)
+ wnd->hangcheck_interval = 2 * hangcheck_interval * HZ;
+ else
+ wnd->hangcheck_interval = 2 * HZ;
+
+ EXIT1(return);
+}
+
+wstdcall ULONG WIN_FUNC(NdisReadPciSlotInformation,5)
+ (struct ndis_mp_block *nmb, ULONG slot,
+ ULONG offset, char *buf, ULONG len)
+{
+ struct wrap_device *wd = nmb->wnd->wd;
+ ULONG i;
+ for (i = 0; i < len; i++)
+ if (pci_read_config_byte(wd->pci.pdev, offset + i, &buf[i]) !=
+ PCIBIOS_SUCCESSFUL)
+ break;
+ DBG_BLOCK(2) {
+ if (i != len)
+ WARNING("%u, %u", i, len);
+ }
+ return i;
+}
+
+wstdcall ULONG WIN_FUNC(NdisImmediateReadPciSlotInformation,5)
+ (struct ndis_mp_block *nmb, ULONG slot,
+ ULONG offset, char *buf, ULONG len)
+{
+ return NdisReadPciSlotInformation(nmb, slot, offset, buf, len);
+}
+
+wstdcall ULONG WIN_FUNC(NdisWritePciSlotInformation,5)
+ (struct ndis_mp_block *nmb, ULONG slot,
+ ULONG offset, char *buf, ULONG len)
+{
+ struct wrap_device *wd = nmb->wnd->wd;
+ ULONG i;
+ for (i = 0; i < len; i++)
+ if (pci_write_config_byte(wd->pci.pdev, offset + i, buf[i]) !=
+ PCIBIOS_SUCCESSFUL)
+ break;
+ DBG_BLOCK(2) {
+ if (i != len)
+ WARNING("%u, %u", i, len);
+ }
+ return i;
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterIoPortRange,4)
+ (void **virt, struct ndis_mp_block *nmb, UINT start, UINT len)
+{
+ ENTER3("%08x %08x", start, len);
+ *virt = (void *)(ULONG_PTR)start;
+ return NDIS_STATUS_SUCCESS;
+}
+
+wstdcall void WIN_FUNC(NdisMDeregisterIoPortRange,4)
+ (struct ndis_mp_block *nmb, UINT start, UINT len, void* virt)
+{
+ ENTER1("%08x %08x", start, len);
+}
+
+wstdcall void WIN_FUNC(NdisReadPortUchar,3)
+ (struct ndis_mp_block *nmb, ULONG port, char *data)
+{
+ *data = inb(port);
+}
+
+wstdcall void WIN_FUNC(NdisImmediateReadPortUchar,3)
+ (struct ndis_mp_block *nmb, ULONG port, char *data)
+{
+ *data = inb(port);
+}
+
+wstdcall void WIN_FUNC(NdisWritePortUchar,3)
+ (struct ndis_mp_block *nmb, ULONG port, char data)
+{
+ outb(data, port);
+}
+
+wstdcall void WIN_FUNC(NdisImmediateWritePortUchar,3)
+ (struct ndis_mp_block *nmb, ULONG port, char data)
+{
+ outb(data, port);
+}
+
+wstdcall void WIN_FUNC(NdisMQueryAdapterResources,4)
+ (NDIS_STATUS *status, struct ndis_mp_block *nmb,
+ NDIS_RESOURCE_LIST *resource_list, UINT *size)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ NDIS_RESOURCE_LIST *list;
+ UINT resource_length;
+
+ list = &wnd->wd->resource_list->list->partial_resource_list;
+ resource_length = sizeof(struct cm_partial_resource_list) +
+ sizeof(struct cm_partial_resource_descriptor) *
+ (list->count - 1);
+ TRACE2("%p, %p,%d (%d), %p %d %d", wnd, resource_list, *size,
+ resource_length, &list->partial_descriptors[list->count-1],
+ list->partial_descriptors[list->count-1].u.interrupt.level,
+ list->partial_descriptors[list->count-1].u.interrupt.vector);
+ if (*size < sizeof(*list)) {
+ *size = resource_length;
+ *status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ } else {
+ ULONG count;
+ if (*size >= resource_length) {
+ *size = resource_length;
+ count = list->count;
+ } else {
+ UINT n = sizeof(*list);
+ count = 1;
+ while (count++ < list->count && n < *size)
+ n += sizeof(list->partial_descriptors);
+ *size = n;
+ }
+ memcpy(resource_list, list, *size);
+ resource_list->count = count;
+ *status = NDIS_STATUS_SUCCESS;
+ }
+ EXIT2(return);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMPciAssignResources,3)
+ (struct ndis_mp_block *nmb, ULONG slot_number,
+ NDIS_RESOURCE_LIST **resources)
+{
+ struct ndis_device *wnd = nmb->wnd;
+
+ ENTER2("%p, %p", wnd, wnd->wd->resource_list);
+ *resources = &wnd->wd->resource_list->list->partial_resource_list;
+ EXIT2(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMMapIoSpace,4)
+ (void __iomem **virt, struct ndis_mp_block *nmb,
+ NDIS_PHY_ADDRESS phy_addr, UINT len)
+{
+ struct ndis_device *wnd = nmb->wnd;
+
+ ENTER2("%Lx, %d", phy_addr, len);
+ *virt = MmMapIoSpace(phy_addr, len, MmCached);
+ if (*virt == NULL) {
+ ERROR("ioremap failed");
+ EXIT2(return NDIS_STATUS_FAILURE);
+ }
+ wnd->mem_start = phy_addr;
+ wnd->mem_end = phy_addr + len;
+ TRACE2("%p", *virt);
+ EXIT2(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(NdisMUnmapIoSpace,3)
+ (struct ndis_mp_block *nmb, void __iomem *virt, UINT len)
+{
+ ENTER2("%p, %d", virt, len);
+ MmUnmapIoSpace(virt, len);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisAllocateSpinLock,1)
+ (struct ndis_spinlock *lock)
+{
+ TRACE4("lock %p, %p", lock, &lock->klock);
+ KeInitializeSpinLock(&lock->klock);
+ lock->irql = PASSIVE_LEVEL;
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisFreeSpinLock,1)
+ (struct ndis_spinlock *lock)
+{
+ TRACE4("lock %p, %p", lock, &lock->klock);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisAcquireSpinLock,1)
+ (struct ndis_spinlock *lock)
+{
+ ENTER6("lock %p, %p", lock, &lock->klock);
+// assert_irql(_irql_ <= DISPATCH_LEVEL);
+ lock->irql = nt_spin_lock_irql(&lock->klock, DISPATCH_LEVEL);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisReleaseSpinLock,1)
+ (struct ndis_spinlock *lock)
+{
+ ENTER6("lock %p, %p", lock, &lock->klock);
+// assert_irql(_irql_ == DISPATCH_LEVEL);
+ nt_spin_unlock_irql(&lock->klock, lock->irql);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisDprAcquireSpinLock,1)
+ (struct ndis_spinlock *lock)
+{
+ ENTER6("lock %p", &lock->klock);
+// assert_irql(_irql_ == DISPATCH_LEVEL);
+ nt_spin_lock(&lock->klock);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisDprReleaseSpinLock,1)
+ (struct ndis_spinlock *lock)
+{
+ ENTER6("lock %p", &lock->klock);
+// assert_irql(_irql_ == DISPATCH_LEVEL);
+ nt_spin_unlock(&lock->klock);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisInitializeReadWriteLock,1)
+ (struct ndis_rw_lock *rw_lock)
+{
+ ENTER3("%p", rw_lock);
+ memset(rw_lock, 0, sizeof(*rw_lock));
+ KeInitializeSpinLock(&rw_lock->klock);
+ return;
+}
+
+/* read/write locks are implemented in a rather simplisitic way - we
+ * should probably use Linux's rw_lock implementation */
+
+wstdcall void WIN_FUNC(NdisAcquireReadWriteLock,3)
+ (struct ndis_rw_lock *rw_lock, BOOLEAN write,
+ struct lock_state *lock_state)
+{
+ if (write) {
+ while (1) {
+ if (cmpxchg(&rw_lock->count, 0, -1) == 0)
+ return;
+ while (rw_lock->count)
+ cpu_relax();
+ }
+ return;
+ }
+ while (1) {
+ typeof(rw_lock->count) count;
+ while ((count = rw_lock->count) < 0)
+ cpu_relax();
+ if (cmpxchg(&rw_lock->count, count, count + 1) == count)
+ return;
+ }
+}
+
+wstdcall void WIN_FUNC(NdisReleaseReadWriteLock,2)
+ (struct ndis_rw_lock *rw_lock, struct lock_state *lock_state)
+{
+ if (rw_lock->count > 0)
+ pre_atomic_add(rw_lock->count, -1);
+ else if (rw_lock->count == -1)
+ rw_lock->count = 0;
+ else
+ WARNING("invalid state: %d", rw_lock->count);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateMapRegisters,5)
+ (struct ndis_mp_block *nmb, UINT dmachan,
+ NDIS_DMA_SIZE dmasize, ULONG basemap, ULONG max_buf_size)
+{
+ struct ndis_device *wnd = nmb->wnd;
+
+ ENTER2("%p, %d %d %d %d", wnd, dmachan, dmasize, basemap, max_buf_size);
+ if (wnd->dma_map_count > 0) {
+ WARNING("%s: map registers already allocated: %u",
+ wnd->net_dev->name, wnd->dma_map_count);
+ EXIT2(return NDIS_STATUS_RESOURCES);
+ }
+ if (dmasize == NDIS_DMA_24BITS) {
+ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(24)) ||
+ pci_set_consistent_dma_mask(wnd->wd->pci.pdev,
+ DMA_BIT_MASK(24)))
+ WARNING("setting dma mask failed");
+ } else if (dmasize == NDIS_DMA_32BITS) {
+ /* consistent dma is in low 32-bits by default */
+ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32)))
+ WARNING("setting dma mask failed");
+#ifdef CONFIG_X86_64
+ } else if (dmasize == NDIS_DMA_64BITS) {
+ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(64)) ||
+ pci_set_consistent_dma_mask(wnd->wd->pci.pdev,
+ DMA_BIT_MASK(64)))
+ WARNING("setting dma mask failed");
+ else
+ wnd->net_dev->features |= NETIF_F_HIGHDMA;
+#endif
+ }
+ /* since memory for buffer is allocated with kmalloc, buffer
+ * is physically contiguous, so entire map will fit in one
+ * register */
+ if (basemap > 64) {
+ WARNING("Windows driver %s requesting too many (%u) "
+ "map registers", wnd->wd->driver->name, basemap);
+ /* As per NDIS, NDIS_STATUS_RESOURCES should be
+ * returned, but with that Atheros PCI driver fails -
+ * for now tolerate it */
+// EXIT2(return NDIS_STATUS_RESOURCES);
+ }
+
+ wnd->dma_map_addr = kmalloc(basemap * sizeof(*(wnd->dma_map_addr)),
+ GFP_KERNEL);
+ if (!wnd->dma_map_addr)
+ EXIT2(return NDIS_STATUS_RESOURCES);
+ memset(wnd->dma_map_addr, 0, basemap * sizeof(*(wnd->dma_map_addr)));
+ wnd->dma_map_count = basemap;
+ TRACE2("%u", wnd->dma_map_count);
+ EXIT2(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(NdisMFreeMapRegisters,1)
+ (struct ndis_mp_block *nmb)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ int i;
+
+ ENTER2("wnd: %p", wnd);
+ if (wnd->dma_map_addr) {
+ for (i = 0; i < wnd->dma_map_count; i++) {
+ if (wnd->dma_map_addr[i])
+ WARNING("%s: dma addr %p not freed by "
+ "Windows driver", wnd->net_dev->name,
+ (void *)wnd->dma_map_addr[i]);
+ }
+ kfree(wnd->dma_map_addr);
+ wnd->dma_map_addr = NULL;
+ } else
+ WARNING("map registers already freed?");
+ wnd->dma_map_count = 0;
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisMStartBufferPhysicalMapping,6)
+ (struct ndis_mp_block *nmb, ndis_buffer *buf,
+ ULONG index, BOOLEAN write_to_dev,
+ struct ndis_phy_addr_unit *phy_addr_array, UINT *array_size)
+{
+ struct ndis_device *wnd = nmb->wnd;
+
+ ENTER3("%p, %p, %u, %u", wnd, buf, index, wnd->dma_map_count);
+ if (unlikely(wnd->sg_dma_size || !write_to_dev ||
+ index >= wnd->dma_map_count)) {
+ WARNING("invalid request: %d, %d, %d, %d", wnd->sg_dma_size,
+ write_to_dev, index, wnd->dma_map_count);
+ phy_addr_array[0].phy_addr = 0;
+ phy_addr_array[0].length = 0;
+ *array_size = 0;
+ return;
+ }
+ if (wnd->dma_map_addr[index]) {
+ TRACE2("buffer %p at %d is already mapped: %lx", buf, index,
+ (unsigned long)wnd->dma_map_addr[index]);
+// *array_size = 1;
+ return;
+ }
+ TRACE3("%p, %p, %u", buf, MmGetSystemAddressForMdl(buf),
+ MmGetMdlByteCount(buf));
+ DBG_BLOCK(4) {
+ dump_bytes(__func__, MmGetSystemAddressForMdl(buf),
+ MmGetMdlByteCount(buf));
+ }
+ wnd->dma_map_addr[index] =
+ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev,
+ MmGetSystemAddressForMdl(buf),
+ MmGetMdlByteCount(buf), PCI_DMA_TODEVICE);
+ phy_addr_array[0].phy_addr = wnd->dma_map_addr[index];
+ phy_addr_array[0].length = MmGetMdlByteCount(buf);
+ TRACE4("%Lx, %d, %d", phy_addr_array[0].phy_addr,
+ phy_addr_array[0].length, index);
+ *array_size = 1;
+}
+
+wstdcall void WIN_FUNC(NdisMCompleteBufferPhysicalMapping,3)
+ (struct ndis_mp_block *nmb, ndis_buffer *buf, ULONG index)
+{
+ struct ndis_device *wnd = nmb->wnd;
+
+ ENTER3("%p, %p %u (%u)", wnd, buf, index, wnd->dma_map_count);
+
+ if (unlikely(wnd->sg_dma_size))
+ WARNING("buffer %p may have been unmapped already", buf);
+ if (index >= wnd->dma_map_count) {
+ ERROR("invalid map register (%u >= %u)",
+ index, wnd->dma_map_count);
+ return;
+ }
+ TRACE4("%lx", (unsigned long)wnd->dma_map_addr[index]);
+ if (wnd->dma_map_addr[index]) {
+ PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, wnd->dma_map_addr[index],
+ MmGetMdlByteCount(buf), PCI_DMA_TODEVICE);
+ wnd->dma_map_addr[index] = 0;
+ } else
+ WARNING("map registers at %u not used", index);
+}
+
+wstdcall void WIN_FUNC(NdisMAllocateSharedMemory,5)
+ (struct ndis_mp_block *nmb, ULONG size,
+ BOOLEAN cached, void **virt, NDIS_PHY_ADDRESS *phys)
+{
+ dma_addr_t dma_addr;
+ struct wrap_device *wd = nmb->wnd->wd;
+
+ ENTER3("size: %u, cached: %d", size, cached);
+ *virt = PCI_DMA_ALLOC_COHERENT(wd->pci.pdev, size, &dma_addr);
+ if (*virt)
+ *phys = dma_addr;
+ else
+ WARNING("couldn't allocate %d bytes of %scached DMA memory",
+ size, cached ? "" : "un-");
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisMFreeSharedMemory,5)
+ (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached,
+ void *virt, NDIS_PHY_ADDRESS addr)
+{
+ struct wrap_device *wd = nmb->wnd->wd;
+ ENTER3("%p, %Lx, %u", virt, addr, size);
+ PCI_DMA_FREE_COHERENT(wd->pci.pdev, size, virt, addr);
+ EXIT3(return);
+}
+
+wstdcall void alloc_shared_memory_async(void *arg1, void *arg2)
+{
+ struct ndis_device *wnd;
+ struct alloc_shared_mem *alloc_shared_mem;
+ struct miniport *mp;
+ void *virt;
+ NDIS_PHY_ADDRESS phys;
+ KIRQL irql;
+
+ wnd = arg1;
+ alloc_shared_mem = arg2;
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ NdisMAllocateSharedMemory(wnd->nmb, alloc_shared_mem->size,
+ alloc_shared_mem->cached, &virt, &phys);
+ irql = serialize_lock_irql(wnd);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ LIN2WIN5(mp->alloc_complete, wnd->nmb, virt,
+ &phys, alloc_shared_mem->size, alloc_shared_mem->ctx);
+ serialize_unlock_irql(wnd, irql);
+ kfree(alloc_shared_mem);
+}
+WIN_FUNC_DECL(alloc_shared_memory_async,2)
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateSharedMemoryAsync,4)
+ (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void *ctx)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ struct alloc_shared_mem *alloc_shared_mem;
+
+ ENTER3("wnd: %p", wnd);
+ alloc_shared_mem = kmalloc(sizeof(*alloc_shared_mem), irql_gfp());
+ if (!alloc_shared_mem) {
+ WARNING("couldn't allocate memory");
+ return NDIS_STATUS_FAILURE;
+ }
+
+ alloc_shared_mem->size = size;
+ alloc_shared_mem->cached = cached;
+ alloc_shared_mem->ctx = ctx;
+ if (schedule_ntos_work_item(WIN_FUNC_PTR(alloc_shared_memory_async,2),
+ wnd, alloc_shared_mem))
+ EXIT3(return NDIS_STATUS_FAILURE);
+ EXIT3(return NDIS_STATUS_PENDING);
+}
+
+/* Some drivers allocate NDIS_BUFFER (aka MDL) very often; instead of
+ * allocating and freeing with kernel functions, we chain them into
+ * ndis_buffer_pool. When an MDL is freed, it is added to the list of
+ * free MDLs. When allocated, we first check if there is one in free
+ * list and if so just return it; otherwise, we allocate a new one and
+ * return that. This reduces memory fragmentation. Windows DDK says
+ * that the driver itself shouldn't check what is returned in
+ * pool_handle, presumably because buffer pools are not used in
+ * XP. However, as long as driver follows rest of the semantics - that
+ * it should indicate maximum number of MDLs used with num_descr and
+ * pass the same pool_handle in other buffer functions, this should
+ * work. Sadly, though, NdisFreeBuffer doesn't pass the pool_handle,
+ * so we use 'process' field of MDL to store pool_handle. */
+
+wstdcall void WIN_FUNC(NdisAllocateBufferPool,3)
+ (NDIS_STATUS *status, struct ndis_buffer_pool **pool_handle,
+ UINT num_descr)
+{
+ struct ndis_buffer_pool *pool;
+
+ ENTER1("buffers: %d", num_descr);
+ pool = kmalloc(sizeof(*pool), irql_gfp());
+ if (!pool) {
+ *status = NDIS_STATUS_RESOURCES;
+ EXIT3(return);
+ }
+ spin_lock_init(&pool->lock);
+ pool->max_descr = num_descr;
+ pool->num_allocated_descr = 0;
+ pool->free_descr = NULL;
+ *pool_handle = pool;
+ *status = NDIS_STATUS_SUCCESS;
+ TRACE1("pool: %p, num_descr: %d", pool, num_descr);
+ EXIT1(return);
+}
+
+wstdcall void WIN_FUNC(NdisAllocateBuffer,5)
+ (NDIS_STATUS *status, ndis_buffer **buffer,
+ struct ndis_buffer_pool *pool, void *virt, UINT length)
+{
+ ndis_buffer *descr;
+
+ ENTER4("pool: %p (%d)", pool, pool->num_allocated_descr);
+ /* NDIS drivers should call this at DISPATCH_LEVEL, but
+ * alloc_tx_packet calls at SOFT_IRQL */
+ assert_irql(_irql_ <= SOFT_LEVEL);
+ if (!pool) {
+ *status = NDIS_STATUS_FAILURE;
+ *buffer = NULL;
+ EXIT4(return);
+ }
+ spin_lock_bh(&pool->lock);
+ if ((descr = pool->free_descr))
+ pool->free_descr = descr->next;
+ spin_unlock_bh(&pool->lock);
+ if (descr) {
+ typeof(descr->flags) flags;
+ flags = descr->flags;
+ memset(descr, 0, sizeof(*descr));
+ MmInitializeMdl(descr, virt, length);
+ if (flags & MDL_CACHE_ALLOCATED)
+ descr->flags |= MDL_CACHE_ALLOCATED;
+ } else {
+ if (pool->num_allocated_descr > pool->max_descr) {
+ TRACE2("pool %p is full: %d(%d)", pool,
+ pool->num_allocated_descr, pool->max_descr);
+#ifndef ALLOW_POOL_OVERFLOW
+ *status = NDIS_STATUS_FAILURE;
+ *buffer = NULL;
+ return;
+#endif
+ }
+ descr = allocate_init_mdl(virt, length);
+ if (!descr) {
+ WARNING("couldn't allocate buffer");
+ *status = NDIS_STATUS_FAILURE;
+ *buffer = NULL;
+ EXIT4(return);
+ }
+ TRACE4("buffer %p for %p, %d", descr, virt, length);
+ atomic_inc_var(pool->num_allocated_descr);
+ }
+ /* TODO: make sure this mdl can map given buffer */
+ MmBuildMdlForNonPagedPool(descr);
+// descr->flags |= MDL_ALLOCATED_FIXED_SIZE |
+// MDL_MAPPED_TO_SYSTEM_VA | MDL_PAGES_LOCKED;
+ descr->pool = pool;
+ *buffer = descr;
+ *status = NDIS_STATUS_SUCCESS;
+ TRACE4("buffer: %p", descr);
+ EXIT4(return);
+}
+
+wstdcall void WIN_FUNC(NdisFreeBuffer,1)
+ (ndis_buffer *buffer)
+{
+ struct ndis_buffer_pool *pool;
+
+ ENTER4("%p", buffer);
+ if (!buffer || !buffer->pool) {
+ ERROR("invalid buffer");
+ EXIT4(return);
+ }
+ pool = buffer->pool;
+ if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_BUFFERS) {
+ /* NB NB NB: set mdl's 'pool' field to NULL before
+ * calling free_mdl; otherwise free_mdl calls
+ * NdisFreeBuffer back */
+ atomic_dec_var(pool->num_allocated_descr);
+ buffer->pool = NULL;
+ free_mdl(buffer);
+ } else {
+ spin_lock_bh(&pool->lock);
+ buffer->next = pool->free_descr;
+ pool->free_descr = buffer;
+ spin_unlock_bh(&pool->lock);
+ }
+ EXIT4(return);
+}
+
+wstdcall void WIN_FUNC(NdisFreeBufferPool,1)
+ (struct ndis_buffer_pool *pool)
+{
+ ndis_buffer *cur, *next;
+
+ TRACE3("pool: %p", pool);
+ if (!pool) {
+ WARNING("invalid pool");
+ EXIT3(return);
+ }
+ spin_lock_bh(&pool->lock);
+ cur = pool->free_descr;
+ while (cur) {
+ next = cur->next;
+ cur->pool = NULL;
+ free_mdl(cur);
+ cur = next;
+ }
+ spin_unlock_bh(&pool->lock);
+ kfree(pool);
+ pool = NULL;
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisAdjustBufferLength,2)
+ (ndis_buffer *buffer, UINT length)
+{
+ ENTER4("%p, %d", buffer, length);
+ buffer->bytecount = length;
+}
+
+wstdcall void WIN_FUNC(NdisQueryBuffer,3)
+ (ndis_buffer *buffer, void **virt, UINT *length)
+{
+ ENTER4("buffer: %p", buffer);
+ if (virt)
+ *virt = MmGetSystemAddressForMdl(buffer);
+ *length = MmGetMdlByteCount(buffer);
+ TRACE4("%p, %u", virt? *virt : NULL, *length);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisQueryBufferSafe,4)
+ (ndis_buffer *buffer, void **virt, UINT *length,
+ enum mm_page_priority priority)
+{
+ ENTER4("%p, %p, %p, %d", buffer, virt, length, priority);
+ if (virt)
+ *virt = MmGetSystemAddressForMdlSafe(buffer, priority);
+ *length = MmGetMdlByteCount(buffer);
+ TRACE4("%p, %u", virt? *virt : NULL, *length);
+}
+
+wstdcall void *WIN_FUNC(NdisBufferVirtualAddress,1)
+ (ndis_buffer *buffer)
+{
+ ENTER3("%p", buffer);
+ return MmGetSystemAddressForMdl(buffer);
+}
+
+wstdcall ULONG WIN_FUNC(NdisBufferLength,1)
+ (ndis_buffer *buffer)
+{
+ ENTER3("%p", buffer);
+ return MmGetMdlByteCount(buffer);
+}
+
+wstdcall void WIN_FUNC(NdisQueryBufferOffset,3)
+ (ndis_buffer *buffer, UINT *offset, UINT *length)
+{
+ ENTER3("%p", buffer);
+ *offset = MmGetMdlByteOffset(buffer);
+ *length = MmGetMdlByteCount(buffer);
+ TRACE3("%d, %d", *offset, *length);
+}
+
+wstdcall void WIN_FUNC(NdisUnchainBufferAtBack,2)
+ (struct ndis_packet *packet, ndis_buffer **buffer)
+{
+ ndis_buffer *b, *btail;
+
+ ENTER3("%p", packet);
+ b = packet->private.buffer_head;
+ if (!b) {
+ /* no buffer in packet */
+ *buffer = NULL;
+ EXIT3(return);
+ }
+ btail = packet->private.buffer_tail;
+ *buffer = btail;
+ if (b == btail) {
+ /* one buffer in packet */
+ packet->private.buffer_head = NULL;
+ packet->private.buffer_tail = NULL;
+ } else {
+ while (b->next != btail)
+ b = b->next;
+ packet->private.buffer_tail = b;
+ b->next = NULL;
+ }
+ packet->private.valid_counts = FALSE;
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisUnchainBufferAtFront,2)
+ (struct ndis_packet *packet, ndis_buffer **buffer)
+{
+ ENTER3("%p", packet);
+ if (packet->private.buffer_head == NULL) {
+ /* no buffer in packet */
+ *buffer = NULL;
+ EXIT3(return);
+ }
+
+ *buffer = packet->private.buffer_head;
+ if (packet->private.buffer_head == packet->private.buffer_tail) {
+ /* one buffer in packet */
+ packet->private.buffer_head = NULL;
+ packet->private.buffer_tail = NULL;
+ } else
+ packet->private.buffer_head = (*buffer)->next;
+
+ packet->private.valid_counts = FALSE;
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacketSafe,6)
+ (struct ndis_packet *packet, ndis_buffer **first_buffer,
+ void **first_buffer_va, UINT *first_buffer_length,
+ UINT *total_buffer_length, enum mm_page_priority priority)
+{
+ ndis_buffer *b = packet->private.buffer_head;
+
+ ENTER3("%p(%p)", packet, b);
+ *first_buffer = b;
+ if (b) {
+ *first_buffer_va = MmGetSystemAddressForMdlSafe(b, priority);
+ *first_buffer_length = *total_buffer_length =
+ MmGetMdlByteCount(b);
+ for (b = b->next; b; b = b->next)
+ *total_buffer_length += MmGetMdlByteCount(b);
+ } else {
+ *first_buffer_va = NULL;
+ *first_buffer_length = 0;
+ *total_buffer_length = 0;
+ }
+ TRACE3("%p, %d, %d", *first_buffer_va, *first_buffer_length,
+ *total_buffer_length);
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacket,6)
+ (struct ndis_packet *packet, ndis_buffer **first_buffer,
+ void **first_buffer_va, UINT *first_buffer_length,
+ UINT *total_buffer_length, enum mm_page_priority priority)
+{
+ NdisGetFirstBufferFromPacketSafe(packet, first_buffer,
+ first_buffer_va, first_buffer_length,
+ total_buffer_length,
+ NormalPagePriority);
+}
+
+wstdcall void WIN_FUNC(NdisAllocatePacketPoolEx,5)
+ (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle,
+ UINT num_descr, UINT overflowsize, UINT proto_rsvd_length)
+{
+ struct ndis_packet_pool *pool;
+
+ ENTER3("buffers: %d, length: %d", num_descr, proto_rsvd_length);
+ pool = kzalloc(sizeof(*pool), irql_gfp());
+ if (!pool) {
+ *status = NDIS_STATUS_RESOURCES;
+ EXIT3(return);
+ }
+ spin_lock_init(&pool->lock);
+ pool->max_descr = num_descr;
+ pool->num_allocated_descr = 0;
+ pool->num_used_descr = 0;
+ pool->free_descr = NULL;
+ pool->proto_rsvd_length = proto_rsvd_length;
+ *pool_handle = pool;
+ *status = NDIS_STATUS_SUCCESS;
+ TRACE3("pool: %p", pool);
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisAllocatePacketPool,4)
+ (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle,
+ UINT num_descr, UINT proto_rsvd_length)
+{
+ NdisAllocatePacketPoolEx(status, pool_handle, num_descr, 0,
+ proto_rsvd_length);
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisFreePacketPool,1)
+ (struct ndis_packet_pool *pool)
+{
+ struct ndis_packet *packet, *next;
+
+ ENTER3("pool: %p", pool);
+ if (!pool) {
+ WARNING("invalid pool");
+ EXIT3(return);
+ }
+ spin_lock_bh(&pool->lock);
+ packet = pool->free_descr;
+ while (packet) {
+ next = (struct ndis_packet *)packet->reserved[0];
+ kfree(packet);
+ packet = next;
+ }
+ pool->num_allocated_descr = 0;
+ pool->num_used_descr = 0;
+ pool->free_descr = NULL;
+ spin_unlock_bh(&pool->lock);
+ kfree(pool);
+ EXIT3(return);
+}
+
+wstdcall UINT WIN_FUNC(NdisPacketPoolUsage,1)
+ (struct ndis_packet_pool *pool)
+{
+ EXIT4(return pool->num_used_descr);
+}
+
+wstdcall void WIN_FUNC(NdisAllocatePacket,3)
+ (NDIS_STATUS *status, struct ndis_packet **ndis_packet,
+ struct ndis_packet_pool *pool)
+{
+ struct ndis_packet *packet;
+ int packet_length;
+
+ ENTER4("pool: %p", pool);
+ if (!pool) {
+ *status = NDIS_STATUS_RESOURCES;
+ *ndis_packet = NULL;
+ EXIT4(return);
+ }
+ assert_irql(_irql_ <= SOFT_LEVEL);
+ if (pool->num_used_descr > pool->max_descr) {
+ TRACE3("pool %p is full: %d(%d)", pool,
+ pool->num_used_descr, pool->max_descr);
+#ifndef ALLOW_POOL_OVERFLOW
+ *status = NDIS_STATUS_RESOURCES;
+ *ndis_packet = NULL;
+ return;
+#endif
+ }
+ /* packet has space for 1 byte in protocol_reserved field */
+ packet_length = sizeof(*packet) - 1 + pool->proto_rsvd_length +
+ sizeof(struct ndis_packet_oob_data);
+ spin_lock_bh(&pool->lock);
+ if ((packet = pool->free_descr))
+ pool->free_descr = (void *)packet->reserved[0];
+ spin_unlock_bh(&pool->lock);
+ if (!packet) {
+ packet = kmalloc(packet_length, irql_gfp());
+ if (!packet) {
+ WARNING("couldn't allocate packet");
+ *status = NDIS_STATUS_RESOURCES;
+ *ndis_packet = NULL;
+ return;
+ }
+ atomic_inc_var(pool->num_allocated_descr);
+ }
+ TRACE4("%p, %p", pool, packet);
+ atomic_inc_var(pool->num_used_descr);
+ memset(packet, 0, packet_length);
+ packet->private.oob_offset =
+ packet_length - sizeof(struct ndis_packet_oob_data);
+ packet->private.packet_flags = fPACKET_ALLOCATED_BY_NDIS;
+ packet->private.pool = pool;
+ *ndis_packet = packet;
+ *status = NDIS_STATUS_SUCCESS;
+ EXIT4(return);
+}
+
+wstdcall void WIN_FUNC(NdisDprAllocatePacket,3)
+ (NDIS_STATUS *status, struct ndis_packet **packet,
+ struct ndis_packet_pool *pool)
+{
+ NdisAllocatePacket(status, packet, pool);
+}
+
+wstdcall void WIN_FUNC(NdisFreePacket,1)
+ (struct ndis_packet *packet)
+{
+ struct ndis_packet_pool *pool;
+
+ ENTER4("%p, %p", packet, packet->private.pool);
+ pool = packet->private.pool;
+ if (!pool) {
+ ERROR("invalid pool %p", packet);
+ EXIT4(return);
+ }
+ assert((int)pool->num_used_descr > 0);
+ atomic_dec_var(pool->num_used_descr);
+ if (packet->reserved[1]) {
+ TRACE3("%p, %p", packet, (void *)packet->reserved[1]);
+ kfree((void *)packet->reserved[1]);
+ packet->reserved[1] = 0;
+ }
+ if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_PACKETS) {
+ TRACE3("%p", pool);
+ atomic_dec_var(pool->num_allocated_descr);
+ kfree(packet);
+ } else {
+ TRACE4("%p, %p, %p", pool, packet, pool->free_descr);
+ spin_lock_bh(&pool->lock);
+ packet->reserved[0] =
+ (typeof(packet->reserved[0]))pool->free_descr;
+ pool->free_descr = packet;
+ spin_unlock_bh(&pool->lock);
+ }
+ EXIT4(return);
+}
+
+wstdcall struct ndis_packet_stack *WIN_FUNC(NdisIMGetCurrentPacketStack,2)
+ (struct ndis_packet *packet, BOOLEAN *stacks_remain)
+{
+ struct ndis_packet_stack *stack;
+
+ if (!packet->reserved[1]) {
+ stack = kzalloc(2 * sizeof(*stack), irql_gfp());
+ TRACE3("%p, %p", packet, stack);
+ packet->reserved[1] = (typeof(packet->reserved[1]))stack;
+ } else {
+ stack = (void *)packet->reserved[1];;
+ if (xchg(&stack->ndis_reserved[0], 1)) {
+ stack++;
+ if (xchg(&stack->ndis_reserved[0], 1))
+ stack = NULL;
+ }
+ TRACE3("%p", stack);
+ }
+ if (stack)
+ *stacks_remain = TRUE;
+ else
+ *stacks_remain = FALSE;
+
+ EXIT3(return stack);
+}
+
+wstdcall void WIN_FUNC(NdisCopyFromPacketToPacketSafe,7)
+ (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy,
+ struct ndis_packet *src, UINT src_offset, UINT *num_copied,
+ enum mm_page_priority priority)
+{
+ UINT dst_n, src_n, n, left;
+ ndis_buffer *dst_buf;
+ ndis_buffer *src_buf;
+
+ ENTER4("");
+ if (!dst || !src) {
+ *num_copied = 0;
+ EXIT4(return);
+ }
+
+ dst_buf = dst->private.buffer_head;
+ src_buf = src->private.buffer_head;
+
+ if (!dst_buf || !src_buf) {
+ *num_copied = 0;
+ EXIT4(return);
+ }
+ dst_n = MmGetMdlByteCount(dst_buf) - dst_offset;
+ src_n = MmGetMdlByteCount(src_buf) - src_offset;
+
+ n = min(src_n, dst_n);
+ n = min(n, num_to_copy);
+ memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset,
+ MmGetSystemAddressForMdl(src_buf) + src_offset, n);
+
+ left = num_to_copy - n;
+ while (left > 0) {
+ src_offset += n;
+ dst_offset += n;
+ dst_n -= n;
+ src_n -= n;
+ if (dst_n == 0) {
+ dst_buf = dst_buf->next;
+ if (!dst_buf)
+ break;
+ dst_n = MmGetMdlByteCount(dst_buf);
+ dst_offset = 0;
+ }
+ if (src_n == 0) {
+ src_buf = src_buf->next;
+ if (!src_buf)
+ break;
+ src_n = MmGetMdlByteCount(src_buf);
+ src_offset = 0;
+ }
+
+ n = min(src_n, dst_n);
+ n = min(n, left);
+ memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset,
+ MmGetSystemAddressForMdl(src_buf) + src_offset, n);
+ left -= n;
+ }
+ *num_copied = num_to_copy - left;
+ EXIT4(return);
+}
+
+wstdcall void WIN_FUNC(NdisCopyFromPacketToPacket,6)
+ (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy,
+ struct ndis_packet *src, UINT src_offset, UINT *num_copied)
+{
+ NdisCopyFromPacketToPacketSafe(dst, dst_offset, num_to_copy,
+ src, src_offset, num_copied,
+ NormalPagePriority);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisIMCopySendPerPacketInfo,2)
+ (struct ndis_packet *dst, struct ndis_packet *src)
+{
+ struct ndis_packet_oob_data *dst_oob, *src_oob;
+ dst_oob = NDIS_PACKET_OOB_DATA(dst);
+ src_oob = NDIS_PACKET_OOB_DATA(src);
+ memcpy(&dst_oob->ext, &src_oob->ext, sizeof(dst_oob->ext));
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisSend,3)
+ (NDIS_STATUS *status, struct ndis_mp_block *nmb,
+ struct ndis_packet *packet)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ struct miniport *mp;
+ KIRQL irql;
+
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ if (mp->send_packets) {
+ irql = serialize_lock_irql(wnd);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, &packet, 1);
+ serialize_unlock_irql(wnd, irql);
+ if (deserialized_driver(wnd))
+ *status = NDIS_STATUS_PENDING;
+ else {
+ struct ndis_packet_oob_data *oob_data;
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ *status = oob_data->status;
+ switch (*status) {
+ case NDIS_STATUS_SUCCESS:
+ free_tx_packet(wnd, packet, *status);
+ break;
+ case NDIS_STATUS_PENDING:
+ break;
+ case NDIS_STATUS_RESOURCES:
+ wnd->tx_ok = 0;
+ break;
+ case NDIS_STATUS_FAILURE:
+ default:
+ free_tx_packet(wnd, packet, *status);
+ break;
+ }
+ }
+ } else {
+ irql = serialize_lock_irql(wnd);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ *status = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, packet, 0);
+ serialize_unlock_irql(wnd, irql);
+ switch (*status) {
+ case NDIS_STATUS_SUCCESS:
+ free_tx_packet(wnd, packet, *status);
+ break;
+ case NDIS_STATUS_PENDING:
+ break;
+ case NDIS_STATUS_RESOURCES:
+ wnd->tx_ok = 0;
+ break;
+ case NDIS_STATUS_FAILURE:
+ default:
+ free_tx_packet(wnd, packet, *status);
+ break;
+ }
+ }
+ EXIT3(return);
+}
+
+/* called for serialized drivers only */
+wstdcall void mp_timer_dpc(struct kdpc *kdpc, void *ctx, void *arg1, void *arg2)
+{
+ struct ndis_mp_timer *timer;
+ struct ndis_mp_block *nmb;
+
+ timer = ctx;
+ TIMERENTER("%p, %p, %p, %p", timer, timer->func, timer->ctx, timer->nmb);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ nmb = timer->nmb;
+ serialize_lock(nmb->wnd);
+ LIN2WIN4(timer->func, NULL, timer->ctx, NULL, NULL);
+ serialize_unlock(nmb->wnd);
+ TIMEREXIT(return);
+}
+WIN_FUNC_DECL(mp_timer_dpc,4)
+
+wstdcall void WIN_FUNC(NdisMInitializeTimer,4)
+ (struct ndis_mp_timer *timer, struct ndis_mp_block *nmb,
+ DPC func, void *ctx)
+{
+ TIMERENTER("%p, %p, %p, %p", timer, func, ctx, nmb);
+ assert_irql(_irql_ == PASSIVE_LEVEL);
+ timer->func = func;
+ timer->ctx = ctx;
+ timer->nmb = nmb;
+ if (deserialized_driver(nmb->wnd))
+ KeInitializeDpc(&timer->kdpc, func, ctx);
+ else
+ KeInitializeDpc(&timer->kdpc, WIN_FUNC_PTR(mp_timer_dpc,4),
+ timer);
+ wrap_init_timer(&timer->nt_timer, NotificationTimer, nmb);
+ TIMEREXIT(return);
+}
+
+wstdcall void WIN_FUNC(NdisMSetPeriodicTimer,2)
+ (struct ndis_mp_timer *timer, UINT period_ms)
+{
+ unsigned long expires = MSEC_TO_HZ(period_ms);
+
+ TIMERENTER("%p, %u, %ld", timer, period_ms, expires);
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ wrap_set_timer(&timer->nt_timer, expires, expires, &timer->kdpc);
+ TIMEREXIT(return);
+}
+
+wstdcall void WIN_FUNC(NdisMCancelTimer,2)
+ (struct ndis_mp_timer *timer, BOOLEAN *canceled)
+{
+ TIMERENTER("%p", timer);
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ *canceled = KeCancelTimer(&timer->nt_timer);
+ TIMERTRACE("%d", *canceled);
+ return;
+}
+
+wstdcall void WIN_FUNC(NdisInitializeTimer,3)
+ (struct ndis_timer *timer, void *func, void *ctx)
+{
+ TIMERENTER("%p, %p, %p", timer, func, ctx);
+ assert_irql(_irql_ == PASSIVE_LEVEL);
+ KeInitializeDpc(&timer->kdpc, func, ctx);
+ wrap_init_timer(&timer->nt_timer, NotificationTimer, NULL);
+ TIMEREXIT(return);
+}
+
+/* NdisMSetTimer is a macro that calls NdisSetTimer with
+ * ndis_mp_timer typecast to ndis_timer */
+
+wstdcall void WIN_FUNC(NdisSetTimer,2)
+ (struct ndis_timer *timer, UINT duetime_ms)
+{
+ unsigned long expires = MSEC_TO_HZ(duetime_ms);
+
+ TIMERENTER("%p, %p, %u, %ld", timer, timer->nt_timer.wrap_timer,
+ duetime_ms, expires);
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ wrap_set_timer(&timer->nt_timer, expires, 0, &timer->kdpc);
+ TIMEREXIT(return);
+}
+
+wstdcall void WIN_FUNC(NdisCancelTimer,2)
+ (struct ndis_timer *timer, BOOLEAN *canceled)
+{
+ TIMERENTER("%p", timer);
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ *canceled = KeCancelTimer(&timer->nt_timer);
+ TIMEREXIT(return);
+}
+
+wstdcall void WIN_FUNC(NdisMRegisterAdapterShutdownHandler,3)
+ (struct ndis_mp_block *nmb, void *ctx, void *func)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ ENTER1("%p", func);
+ wnd->wd->driver->ndis_driver->mp.shutdown = func;
+ wnd->shutdown_ctx = ctx;
+}
+
+wstdcall void WIN_FUNC(NdisMDeregisterAdapterShutdownHandler,1)
+ (struct ndis_mp_block *nmb)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ wnd->wd->driver->ndis_driver->mp.shutdown = NULL;
+ wnd->shutdown_ctx = NULL;
+}
+
+/* TODO: rt61 (serialized) driver doesn't want MiniportEnableInterrupt
+ * to be called in irq handler, but mrv800c (deserialized) driver
+ * wants. NDIS is confusing about when to call MiniportEnableInterrupt
+ * For now, handle these cases with two separate irq handlers based on
+ * observation of these two drivers. However, it is likely not
+ * correct. */
+wstdcall void deserialized_irq_handler(struct kdpc *kdpc, void *ctx,
+ void *arg1, void *arg2)
+{
+ struct ndis_device *wnd = ctx;
+ ndis_interrupt_handler irq_handler = arg1;
+ struct miniport *mp = arg2;
+
+ TRACE6("%p", irq_handler);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ LIN2WIN1(irq_handler, wnd->nmb->mp_ctx);
+ if (mp->enable_interrupt)
+ LIN2WIN1(mp->enable_interrupt, wnd->nmb->mp_ctx);
+ EXIT6(return);
+}
+WIN_FUNC_DECL(deserialized_irq_handler,4)
+
+wstdcall void serialized_irq_handler(struct kdpc *kdpc, void *ctx,
+ void *arg1, void *arg2)
+{
+ struct ndis_device *wnd = ctx;
+ ndis_interrupt_handler irq_handler = arg1;
+
+ TRACE6("%p, %p, %p", wnd, irq_handler, arg2);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ serialize_lock(wnd);
+ LIN2WIN1(irq_handler, arg2);
+ serialize_unlock(wnd);
+ EXIT6(return);
+}
+WIN_FUNC_DECL(serialized_irq_handler,4)
+
+wstdcall BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx)
+{
+ struct ndis_mp_interrupt *mp_interrupt = ctx;
+ struct ndis_device *wnd = mp_interrupt->nmb->wnd;
+ BOOLEAN recognized = TRUE, queue_handler = TRUE;
+
+ TRACE6("%p", wnd);
+ /* kernel may call ISR when registering interrupt, in
+ * the same context if DEBUG_SHIRQ is enabled */
+ assert_irql(_irql_ == DIRQL || _irql_ == PASSIVE_LEVEL);
+ if (mp_interrupt->shared)
+ LIN2WIN3(mp_interrupt->isr, &recognized, &queue_handler,
+ wnd->nmb->mp_ctx);
+ else {
+ struct miniport *mp;
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ LIN2WIN1(mp->disable_interrupt, wnd->nmb->mp_ctx);
+ /* it is not shared interrupt, so handler must be called */
+ recognized = queue_handler = TRUE;
+ }
+ if (recognized) {
+ if (queue_handler) {
+ TRACE5("%p", &wnd->irq_kdpc);
+ queue_kdpc(&wnd->irq_kdpc);
+ }
+ EXIT6(return TRUE);
+ }
+ EXIT6(return FALSE);
+}
+WIN_FUNC_DECL(ndis_isr,2)
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterInterrupt,7)
+ (struct ndis_mp_interrupt *mp_interrupt,
+ struct ndis_mp_block *nmb, UINT vector, UINT level,
+ BOOLEAN req_isr, BOOLEAN shared, enum kinterrupt_mode mode)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ struct miniport *mp;
+
+ ENTER1("%p, vector:%d, level:%d, req_isr:%d, shared:%d, mode:%d",
+ mp_interrupt, vector, level, req_isr, shared, mode);
+
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ nt_spin_lock_init(&mp_interrupt->lock);
+ mp_interrupt->irq = vector;
+ mp_interrupt->isr = mp->isr;
+ mp_interrupt->mp_dpc = mp->handle_interrupt;
+ mp_interrupt->nmb = nmb;
+ mp_interrupt->req_isr = req_isr;
+ if (shared && !req_isr)
+ WARNING("shared but dynamic interrupt!");
+ mp_interrupt->shared = shared;
+ wnd->mp_interrupt = mp_interrupt;
+ if (mp->enable_interrupt)
+ mp_interrupt->enable = TRUE;
+ else
+ mp_interrupt->enable = FALSE;
+
+ if (deserialized_driver(wnd)) {
+ KeInitializeDpc(&wnd->irq_kdpc,
+ WIN_FUNC_PTR(deserialized_irq_handler,4),
+ nmb->wnd);
+ wnd->irq_kdpc.arg1 = mp->handle_interrupt;
+ wnd->irq_kdpc.arg2 = mp;
+ TRACE2("%p, %p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2,
+ nmb->wnd, nmb->mp_ctx);
+ } else {
+ KeInitializeDpc(&wnd->irq_kdpc,
+ WIN_FUNC_PTR(serialized_irq_handler,4),
+ nmb->wnd);
+ wnd->irq_kdpc.arg1 = mp->handle_interrupt;
+ wnd->irq_kdpc.arg2 = nmb->mp_ctx;
+ TRACE2("%p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2,
+ nmb->wnd);
+ }
+
+ if (IoConnectInterrupt(&mp_interrupt->kinterrupt,
+ WIN_FUNC_PTR(ndis_isr,2), mp_interrupt, NULL,
+ vector, DIRQL, DIRQL, mode, shared, 0, FALSE) !=
+ STATUS_SUCCESS) {
+ printk(KERN_WARNING "%s: request for IRQ %d failed\n",
+ DRIVER_NAME, vector);
+ return NDIS_STATUS_RESOURCES;
+ }
+ printk(KERN_INFO "%s: using IRQ %d\n", DRIVER_NAME, vector);
+ EXIT1(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(NdisMDeregisterInterrupt,1)
+ (struct ndis_mp_interrupt *mp_interrupt)
+{
+ struct ndis_mp_block *nmb;
+
+ ENTER1("%p", mp_interrupt);
+ nmb = xchg(&mp_interrupt->nmb, NULL);
+ TRACE1("%p", nmb);
+ if (!nmb) {
+ WARNING("interrupt already freed?");
+ return;
+ }
+ nmb->wnd->mp_interrupt = NULL;
+ if (dequeue_kdpc(&nmb->wnd->irq_kdpc))
+ TRACE2("interrupt kdpc was pending");
+ flush_workqueue(wrapndis_wq);
+ IoDisconnectInterrupt(mp_interrupt->kinterrupt);
+ EXIT1(return);
+}
+
+wstdcall BOOLEAN WIN_FUNC(NdisMSynchronizeWithInterrupt,3)
+ (struct ndis_mp_interrupt *mp_interrupt,
+ PKSYNCHRONIZE_ROUTINE sync_func, void *ctx)
+{
+ return KeSynchronizeExecution(mp_interrupt->kinterrupt, sync_func, ctx);
+}
+
+/* called via function pointer; but 64-bit RNDIS driver calls directly */
+wstdcall void WIN_FUNC(NdisMIndicateStatus,4)
+ (struct ndis_mp_block *nmb, NDIS_STATUS status, void *buf, UINT len)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ struct ndis_status_indication *si;
+
+ ENTER2("status=0x%x len=%d", status, len);
+ switch (status) {
+ case NDIS_STATUS_MEDIA_CONNECT:
+ set_media_state(wnd, NdisMediaStateConnected);
+ break;
+ case NDIS_STATUS_MEDIA_DISCONNECT:
+ set_media_state(wnd, NdisMediaStateDisconnected);
+ break;
+ case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION:
+ if (!buf)
+ break;
+ si = buf;
+ TRACE2("status_type=%d", si->status_type);
+ switch (si->status_type) {
+ case Ndis802_11StatusType_MediaStreamMode:
+ break;
+#ifdef CONFIG_WIRELESS_EXT
+ case Ndis802_11StatusType_Authentication:
+ buf = (char *)buf + sizeof(*si);
+ len -= sizeof(*si);
+ while (len > 0) {
+ int pairwise_error = 0, group_error = 0;
+ struct ndis_auth_req *auth_req =
+ (struct ndis_auth_req *)buf;
+ TRACE1(MACSTRSEP, MAC2STR(auth_req->bssid));
+ if (auth_req->flags & 0x01)
+ TRACE2("reauth request");
+ if (auth_req->flags & 0x02)
+ TRACE2("key update request");
+ if (auth_req->flags & 0x06) {
+ pairwise_error = 1;
+ TRACE2("pairwise_error");
+ }
+ if (auth_req->flags & 0x0E) {
+ group_error = 1;
+ TRACE2("group_error");
+ }
+ if (pairwise_error || group_error) {
+ union iwreq_data wrqu;
+ struct iw_michaelmicfailure micfailure;
+
+ memset(&micfailure, 0, sizeof(micfailure));
+ if (pairwise_error)
+ micfailure.flags |=
+ IW_MICFAILURE_PAIRWISE;
+ if (group_error)
+ micfailure.flags |=
+ IW_MICFAILURE_GROUP;
+ memcpy(micfailure.src_addr.sa_data,
+ auth_req->bssid, ETH_ALEN);
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(micfailure);
+ wireless_send_event(wnd->net_dev,
+ IWEVMICHAELMICFAILURE,
+ &wrqu, (u8 *)&micfailure);
+ }
+ len -= auth_req->length;
+ buf = (char *)buf + auth_req->length;
+ }
+ break;
+ case Ndis802_11StatusType_PMKID_CandidateList:
+ {
+ u8 *end;
+ unsigned long i;
+ struct ndis_pmkid_candidate_list *cand;
+
+ cand = buf + sizeof(struct ndis_status_indication);
+ if (len < sizeof(struct ndis_status_indication) +
+ sizeof(struct ndis_pmkid_candidate_list) ||
+ cand->version != 1) {
+ WARNING("unrecognized PMKID ignored");
+ EXIT1(return);
+ }
+
+ end = (u8 *)buf + len;
+ TRACE2("PMKID ver %d num_cand %d",
+ cand->version, cand->num_candidates);
+ for (i = 0; i < cand->num_candidates; i++) {
+ struct iw_pmkid_cand pcand;
+ union iwreq_data wrqu;
+ struct ndis_pmkid_candidate *c =
+ &cand->candidates[i];
+ if ((u8 *)(c + 1) > end) {
+ TRACE2("truncated PMKID");
+ break;
+ }
+ TRACE2("%ld: " MACSTRSEP " 0x%x",
+ i, MAC2STR(c->bssid), c->flags);
+ memset(&pcand, 0, sizeof(pcand));
+ if (c->flags & 0x01)
+ pcand.flags |= IW_PMKID_CAND_PREAUTH;
+ pcand.index = i;
+ memcpy(pcand.bssid.sa_data, c->bssid, ETH_ALEN);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(pcand);
+ wireless_send_event(wnd->net_dev, IWEVPMKIDCAND,
+ &wrqu, (u8 *)&pcand);
+ }
+ break;
+ }
+ case Ndis802_11StatusType_RadioState:
+ {
+ struct ndis_radio_status_indication *radio_status = buf;
+ if (radio_status->radio_state ==
+ Ndis802_11RadioStatusOn)
+ INFO("radio is turned on");
+ else if (radio_status->radio_state ==
+ Ndis802_11RadioStatusHardwareOff)
+ INFO("radio is turned off by hardware");
+ else if (radio_status->radio_state ==
+ Ndis802_11RadioStatusSoftwareOff)
+ INFO("radio is turned off by software");
+ break;
+ }
+#endif
+ default:
+ /* is this RSSI indication? */
+ TRACE2("unknown indication: %x", si->status_type);
+ break;
+ }
+ break;
+ default:
+ TRACE2("unknown status: %08X", status);
+ break;
+ }
+
+ EXIT2(return);
+}
+
+/* called via function pointer; but 64-bit RNDIS driver calls directly */
+wstdcall void WIN_FUNC(NdisMIndicateStatusComplete,1)
+ (struct ndis_mp_block *nmb)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ ENTER2("%p", wnd);
+ if (wnd->tx_ok)
+ schedule_wrapndis_work(&wnd->tx_work);
+}
+
+/* called via function pointer */
+wstdcall void NdisMSendComplete(struct ndis_mp_block *nmb,
+ struct ndis_packet *packet, NDIS_STATUS status)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ ENTER4("%p, %08X", packet, status);
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ if (deserialized_driver(wnd))
+ free_tx_packet(wnd, packet, status);
+ else {
+ struct ndis_packet_oob_data *oob_data;
+ NDIS_STATUS pkt_status;
+ TRACE3("%p, %08x", packet, status);
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ switch ((pkt_status = xchg(&oob_data->status, status))) {
+ case NDIS_STATUS_NOT_RECOGNIZED:
+ free_tx_packet(wnd, packet, status);
+ break;
+ case NDIS_STATUS_PENDING:
+ case 0:
+ break;
+ default:
+ WARNING("%p: invalid status: %08X", packet, pkt_status);
+ break;
+ }
+ /* In case a serialized driver has earlier requested a
+ * pause by returning NDIS_STATUS_RESOURCES during
+ * MiniportSend(Packets), wakeup tx worker now.
+ */
+ if (xchg(&wnd->tx_ok, 1) == 0) {
+ TRACE3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end);
+ schedule_wrapndis_work(&wnd->tx_work);
+ }
+ }
+ EXIT3(return);
+}
+
+/* called via function pointer */
+wstdcall void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ ENTER3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end);
+ wnd->tx_ok = 1;
+ schedule_wrapndis_work(&wnd->tx_work);
+ EXIT3(return);
+}
+
+wstdcall void return_packet(void *arg1, void *arg2)
+{
+ struct ndis_device *wnd;
+ struct ndis_packet *packet;
+ struct miniport *mp;
+ KIRQL irql;
+
+ wnd = arg1;
+ packet = arg2;
+ ENTER4("%p, %p", wnd, packet);
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ irql = serialize_lock_irql(wnd);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ LIN2WIN2(mp->return_packet, wnd->nmb->mp_ctx, packet);
+ serialize_unlock_irql(wnd, irql);
+ EXIT4(return);
+}
+WIN_FUNC_DECL(return_packet,2)
+
+/* called via function pointer */
+wstdcall void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb,
+ struct ndis_packet **packets,
+ UINT nr_packets)
+{
+ struct ndis_device *wnd;
+ ndis_buffer *buffer;
+ struct ndis_packet *packet;
+ struct sk_buff *skb;
+ ULONG i, length, total_length;
+ struct ndis_packet_oob_data *oob_data;
+ void *virt;
+ struct ndis_tcp_ip_checksum_packet_info csum;
+
+ ENTER3("%p, %d", nmb, nr_packets);
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ wnd = nmb->wnd;
+ for (i = 0; i < nr_packets; i++) {
+ packet = packets[i];
+ if (!packet) {
+ WARNING("empty packet ignored");
+ continue;
+ }
+ wnd->net_dev->last_rx = jiffies;
+ /* get total number of bytes in packet */
+ NdisGetFirstBufferFromPacketSafe(packet, &buffer, &virt,
+ &length, &total_length,
+ NormalPagePriority);
+ TRACE3("%d, %d", length, total_length);
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ TRACE3("0x%x, 0x%x, %Lu", packet->private.flags,
+ packet->private.packet_flags, oob_data->time_rxed);
+ skb = dev_alloc_skb(total_length);
+ if (skb) {
+ while (buffer) {
+ memcpy_skb(skb, MmGetSystemAddressForMdl(buffer),
+ MmGetMdlByteCount(buffer));
+ buffer = buffer->next;
+ }
+ skb->dev = wnd->net_dev;
+ skb->protocol = eth_type_trans(skb, wnd->net_dev);
+ pre_atomic_add(wnd->net_stats.rx_bytes, total_length);
+ atomic_inc_var(wnd->net_stats.rx_packets);
+ csum.value = (typeof(csum.value))(ULONG_PTR)
+ oob_data->ext.info[TcpIpChecksumPacketInfo];
+ TRACE3("0x%05x", csum.value);
+ if (wnd->rx_csum.value &&
+ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded ||
+ csum.rx.ip_succeeded))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+ } else {
+ WARNING("couldn't allocate skb; packet dropped");
+ atomic_inc_var(wnd->net_stats.rx_dropped);
+ }
+
+ /* serialized drivers check the status upon return
+ * from this function */
+ if (!deserialized_driver(wnd)) {
+ oob_data->status = NDIS_STATUS_SUCCESS;
+ continue;
+ }
+
+ /* if a deserialized driver sets
+ * NDIS_STATUS_RESOURCES, then it reclaims the packet
+ * upon return from this function */
+ if (oob_data->status == NDIS_STATUS_RESOURCES)
+ continue;
+
+ assert(oob_data->status == NDIS_STATUS_SUCCESS);
+ /* deserialized driver doesn't check the status upon
+ * return from this function; we need to call
+ * MiniportReturnPacket later for this packet. Calling
+ * MiniportReturnPacket from here is not correct - the
+ * driver doesn't expect it (at least Centrino driver
+ * crashes) */
+ schedule_ntos_work_item(WIN_FUNC_PTR(return_packet,2),
+ wnd, packet);
+ }
+ EXIT3(return);
+}
+
+/* called via function pointer (by NdisMEthIndicateReceive macro); the
+ * first argument is nmb->eth_db */
+wstdcall void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx,
+ char *header1, char *header, UINT header_size,
+ void *look_ahead, UINT look_ahead_size,
+ UINT packet_size)
+{
+ struct sk_buff *skb = NULL;
+ struct ndis_device *wnd;
+ unsigned int skb_size = 0;
+ KIRQL irql;
+ struct ndis_packet_oob_data *oob_data;
+
+ ENTER3("nmb = %p, rx_ctx = %p, buf = %p, size = %d, buf = %p, "
+ "size = %d, packet = %d", nmb, rx_ctx, header, header_size,
+ look_ahead, look_ahead_size, packet_size);
+
+ wnd = nmb->wnd;
+ TRACE3("wnd = %p", wnd);
+ if (!wnd) {
+ ERROR("nmb is NULL");
+ EXIT3(return);
+ }
+ wnd->net_dev->last_rx = jiffies;
+
+ if (look_ahead_size < packet_size) {
+ struct ndis_packet *packet;
+ struct miniport *mp;
+ unsigned int bytes_txed;
+ NDIS_STATUS res;
+
+ NdisAllocatePacket(&res, &packet, wnd->tx_packet_pool);
+ if (res != NDIS_STATUS_SUCCESS) {
+ atomic_inc_var(wnd->net_stats.rx_dropped);
+ EXIT3(return);
+ }
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ irql = serialize_lock_irql(wnd);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ res = LIN2WIN6(mp->tx_data, packet, &bytes_txed, nmb,
+ rx_ctx, look_ahead_size, packet_size);
+ serialize_unlock_irql(wnd, irql);
+ TRACE3("%d, %d, %d", header_size, look_ahead_size, bytes_txed);
+ if (res == NDIS_STATUS_SUCCESS) {
+ ndis_buffer *buffer;
+ struct ndis_tcp_ip_checksum_packet_info csum;
+ skb = dev_alloc_skb(header_size + look_ahead_size +
+ bytes_txed);
+ if (!skb) {
+ ERROR("couldn't allocate skb; packet dropped");
+ atomic_inc_var(wnd->net_stats.rx_dropped);
+ NdisFreePacket(packet);
+ return;
+ }
+ memcpy_skb(skb, header, header_size);
+ memcpy_skb(skb, look_ahead, look_ahead_size);
+ buffer = packet->private.buffer_head;
+ while (buffer) {
+ memcpy_skb(skb,
+ MmGetSystemAddressForMdl(buffer),
+ MmGetMdlByteCount(buffer));
+ buffer = buffer->next;
+ }
+ skb_size = header_size + look_ahead_size + bytes_txed;
+ csum.value = (typeof(csum.value))(ULONG_PTR)
+ oob_data->ext.info[TcpIpChecksumPacketInfo];
+ TRACE3("0x%05x", csum.value);
+ if (wnd->rx_csum.value &&
+ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ NdisFreePacket(packet);
+ } else if (res == NDIS_STATUS_PENDING) {
+ /* driver will call td_complete */
+ oob_data->look_ahead = kmalloc(look_ahead_size,
+ GFP_ATOMIC);
+ if (!oob_data->look_ahead) {
+ NdisFreePacket(packet);
+ ERROR("packet dropped");
+ atomic_inc_var(wnd->net_stats.rx_dropped);
+ EXIT3(return);
+ }
+ assert(sizeof(oob_data->header) == header_size);
+ memcpy(oob_data->header, header,
+ sizeof(oob_data->header));
+ memcpy(oob_data->look_ahead, look_ahead,
+ look_ahead_size);
+ oob_data->look_ahead_size = look_ahead_size;
+ EXIT3(return);
+ } else {
+ WARNING("packet dropped: %08X", res);
+ atomic_inc_var(wnd->net_stats.rx_dropped);
+ NdisFreePacket(packet);
+ EXIT3(return);
+ }
+ } else {
+ skb_size = header_size + packet_size;
+ skb = dev_alloc_skb(skb_size);
+ if (skb) {
+ memcpy_skb(skb, header, header_size);
+ memcpy_skb(skb, look_ahead, packet_size);
+ }
+ }
+
+ if (skb) {
+ skb->dev = wnd->net_dev;
+ skb->protocol = eth_type_trans(skb, wnd->net_dev);
+ pre_atomic_add(wnd->net_stats.rx_bytes, skb_size);
+ atomic_inc_var(wnd->net_stats.rx_packets);
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+ }
+
+ EXIT3(return);
+}
+
+/* called via function pointer */
+wstdcall void NdisMTransferDataComplete(struct ndis_mp_block *nmb,
+ struct ndis_packet *packet,
+ NDIS_STATUS status, UINT bytes_txed)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ struct sk_buff *skb;
+ unsigned int skb_size;
+ struct ndis_packet_oob_data *oob_data;
+ ndis_buffer *buffer;
+ struct ndis_tcp_ip_checksum_packet_info csum;
+
+ ENTER3("wnd = %p, packet = %p, bytes_txed = %d",
+ wnd, packet, bytes_txed);
+ if (!packet) {
+ WARNING("illegal packet");
+ EXIT3(return);
+ }
+ wnd->net_dev->last_rx = jiffies;
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ skb_size = sizeof(oob_data->header) + oob_data->look_ahead_size +
+ bytes_txed;
+ skb = dev_alloc_skb(skb_size);
+ if (!skb) {
+ kfree(oob_data->look_ahead);
+ NdisFreePacket(packet);
+ ERROR("couldn't allocate skb; packet dropped");
+ atomic_inc_var(wnd->net_stats.rx_dropped);
+ EXIT3(return);
+ }
+ memcpy_skb(skb, oob_data->header, sizeof(oob_data->header));
+ memcpy_skb(skb, oob_data->look_ahead, oob_data->look_ahead_size);
+ buffer = packet->private.buffer_head;
+ while (buffer) {
+ memcpy_skb(skb, MmGetSystemAddressForMdl(buffer),
+ MmGetMdlByteCount(buffer));
+ buffer = buffer->next;
+ }
+ kfree(oob_data->look_ahead);
+ NdisFreePacket(packet);
+ skb->dev = wnd->net_dev;
+ skb->protocol = eth_type_trans(skb, wnd->net_dev);
+ pre_atomic_add(wnd->net_stats.rx_bytes, skb_size);
+ atomic_inc_var(wnd->net_stats.rx_packets);
+
+ csum.value = (typeof(csum.value))(ULONG_PTR)
+ oob_data->ext.info[TcpIpChecksumPacketInfo];
+ TRACE3("0x%05x", csum.value);
+ if (wnd->rx_csum.value &&
+ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+}
+
+/* called via function pointer */
+wstdcall void EthRxComplete(struct ndis_mp_block *nmb)
+{
+ TRACE3("");
+}
+
+/* called via function pointer */
+wstdcall void NdisMQueryInformationComplete(struct ndis_mp_block *nmb,
+ NDIS_STATUS status)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ typeof(wnd->ndis_req_task) task;
+
+ ENTER2("nmb: %p, wnd: %p, %08X", nmb, wnd, status);
+ wnd->ndis_req_status = status;
+ wnd->ndis_req_done = 1;
+ if ((task = xchg(&wnd->ndis_req_task, NULL)))
+ wake_up_process(task);
+ else
+ WARNING("invalid task");
+ EXIT2(return);
+}
+
+/* called via function pointer */
+wstdcall void NdisMSetInformationComplete(struct ndis_mp_block *nmb,
+ NDIS_STATUS status)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ typeof(wnd->ndis_req_task) task;
+
+ ENTER2("status = %08X", status);
+ wnd->ndis_req_status = status;
+ wnd->ndis_req_done = 1;
+ if ((task = xchg(&wnd->ndis_req_task, NULL)))
+ wake_up_process(task);
+ else
+ WARNING("invalid task");
+ EXIT2(return);
+}
+
+/* called via function pointer */
+wstdcall void NdisMResetComplete(struct ndis_mp_block *nmb,
+ NDIS_STATUS status, BOOLEAN address_reset)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ typeof(wnd->ndis_req_task) task;
+
+ ENTER2("status: %08X, %u", status, address_reset);
+ wnd->ndis_req_status = status;
+ wnd->ndis_req_done = address_reset + 1;
+ if ((task = xchg(&wnd->ndis_req_task, NULL)))
+ wake_up_process(task);
+ else
+ WARNING("invalid task");
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(NdisMSleep,1)
+ (ULONG us)
+{
+ unsigned long delay;
+
+ ENTER4("%p: us: %u", current, us);
+ delay = USEC_TO_HZ(us);
+ sleep_hz(delay);
+ TRACE4("%p: done", current);
+}
+
+wstdcall void WIN_FUNC(NdisGetCurrentSystemTime,1)
+ (LARGE_INTEGER *time)
+{
+ *time = ticks_1601();
+ TRACE5("%Lu, %lu", *time, jiffies);
+}
+
+wstdcall LONG WIN_FUNC(NdisInterlockedDecrement,1)
+ (LONG *val)
+{
+ return InterlockedDecrement(val);
+}
+
+wstdcall LONG WIN_FUNC(NdisInterlockedIncrement,1)
+ (LONG *val)
+{
+ return InterlockedIncrement(val);
+}
+
+wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertHeadList,3)
+ (struct nt_list *head, struct nt_list *entry,
+ struct ndis_spinlock *lock)
+{
+ return ExInterlockedInsertHeadList(head, entry, &lock->klock);
+}
+
+wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertTailList,3)
+ (struct nt_list *head, struct nt_list *entry,
+ struct ndis_spinlock *lock)
+{
+ return ExInterlockedInsertTailList(head, entry, &lock->klock);
+}
+
+wstdcall struct nt_list *WIN_FUNC(NdisInterlockedRemoveHeadList,2)
+ (struct nt_list *head, struct ndis_spinlock *lock)
+{
+ return ExInterlockedRemoveHeadList(head, &lock->klock);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMInitializeScatterGatherDma,3)
+ (struct ndis_mp_block *nmb, BOOLEAN dma_size, ULONG max_phy_map)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ ENTER2("dma_size=%d, maxtransfer=%u", dma_size, max_phy_map);
+#ifdef CONFIG_X86_64
+ if (dma_size != NDIS_DMA_64BITS) {
+ TRACE1("DMA size is not 64-bits");
+ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32)) ||
+ pci_set_consistent_dma_mask(wnd->wd->pci.pdev,
+ DMA_BIT_MASK(32)))
+ WARNING("setting dma mask failed");
+ }
+#endif
+ if ((wnd->attributes & NDIS_ATTRIBUTE_BUS_MASTER) &&
+ wrap_is_pci_bus(wnd->wd->dev_bus)) {
+ wnd->sg_dma_size = max_phy_map;
+ return NDIS_STATUS_SUCCESS;
+ } else
+ EXIT1(return NDIS_STATUS_NOT_SUPPORTED);
+}
+
+wstdcall ULONG WIN_FUNC(NdisMGetDmaAlignment,1)
+ (struct ndis_mp_block *nmb)
+{
+ ENTER3("");
+ return dma_get_cache_alignment();
+}
+
+wstdcall CHAR WIN_FUNC(NdisSystemProcessorCount,0)
+ (void)
+{
+ return (CHAR)NR_CPUS;
+}
+
+wstdcall void WIN_FUNC(NdisGetCurrentProcessorCounts,3)
+ (ULONG *idle, ULONG *kernel_user, ULONG *index)
+{
+ int cpu = smp_processor_id();
+ *idle = kstat_cpu(cpu).cpustat.idle;
+ *kernel_user = kstat_cpu(cpu).cpustat.system +
+ kstat_cpu(cpu).cpustat.user;
+ *index = cpu;
+}
+
+wstdcall void WIN_FUNC(NdisInitializeEvent,1)
+ (struct ndis_event *ndis_event)
+{
+ EVENTENTER("%p", ndis_event);
+ KeInitializeEvent(&ndis_event->nt_event, NotificationEvent, 0);
+}
+
+wstdcall BOOLEAN WIN_FUNC(NdisWaitEvent,2)
+ (struct ndis_event *ndis_event, UINT ms)
+{
+ LARGE_INTEGER ticks;
+ NTSTATUS res;
+
+ EVENTENTER("%p %u", ndis_event, ms);
+ ticks = -((LARGE_INTEGER)ms * TICKSPERMSEC);
+ res = KeWaitForSingleObject(&ndis_event->nt_event, 0, 0, TRUE,
+ ms == 0 ? NULL : &ticks);
+ if (res == STATUS_SUCCESS)
+ EXIT3(return TRUE);
+ else
+ EXIT3(return FALSE);
+}
+
+wstdcall void WIN_FUNC(NdisSetEvent,1)
+ (struct ndis_event *ndis_event)
+{
+ EVENTENTER("%p", ndis_event);
+ KeSetEvent(&ndis_event->nt_event, 0, 0);
+}
+
+wstdcall void WIN_FUNC(NdisResetEvent,1)
+ (struct ndis_event *ndis_event)
+{
+ EVENTENTER("%p", ndis_event);
+ KeResetEvent(&ndis_event->nt_event);
+}
+
+static void ndis_worker(worker_param_t dummy)
+{
+ struct nt_list *ent;
+ struct ndis_work_item *ndis_work_item;
+
+ WORKENTER("");
+ while (1) {
+ spin_lock_bh(&ndis_work_list_lock);
+ ent = RemoveHeadList(&ndis_work_list);
+ spin_unlock_bh(&ndis_work_list_lock);
+ if (!ent)
+ break;
+ ndis_work_item = container_of(ent, struct ndis_work_item, list);
+ WORKTRACE("%p: %p, %p", ndis_work_item,
+ ndis_work_item->func, ndis_work_item->ctx);
+ LIN2WIN2(ndis_work_item->func, ndis_work_item,
+ ndis_work_item->ctx);
+ WORKTRACE("%p done", ndis_work_item);
+ }
+ WORKEXIT(return);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisScheduleWorkItem,1)
+ (struct ndis_work_item *ndis_work_item)
+{
+ ENTER3("%p", ndis_work_item);
+ spin_lock_bh(&ndis_work_list_lock);
+ InsertTailList(&ndis_work_list, &ndis_work_item->list);
+ spin_unlock_bh(&ndis_work_list_lock);
+ WORKTRACE("scheduling %p", ndis_work_item);
+ schedule_ndis_work(&ndis_work);
+ EXIT3(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(NdisMGetDeviceProperty,6)
+ (struct ndis_mp_block *nmb, void **phy_dev, void **func_dev,
+ void **next_dev, void **alloc_res, void**trans_res)
+{
+ ENTER2("nmb: %p, phy_dev = %p, func_dev = %p, next_dev = %p, "
+ "alloc_res = %p, trans_res = %p", nmb, phy_dev, func_dev,
+ next_dev, alloc_res, trans_res);
+ if (phy_dev)
+ *phy_dev = nmb->pdo;
+ if (func_dev)
+ *func_dev = nmb->fdo;
+ if (next_dev)
+ *next_dev = nmb->next_device;
+}
+
+wstdcall void WIN_FUNC(NdisMRegisterUnloadHandler,2)
+ (struct driver_object *drv_obj, void *unload)
+{
+ if (drv_obj)
+ drv_obj->unload = unload;
+ return;
+}
+
+wstdcall UINT WIN_FUNC(NdisGetVersion,0)
+ (void)
+{
+ return 0x00050001;
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMQueryAdapterInstanceName,2)
+ (struct unicode_string *name, struct ndis_mp_block *nmb)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ struct ansi_string ansi;
+
+ if (wrap_is_pci_bus(wnd->wd->dev_bus))
+ RtlInitAnsiString(&ansi, "PCI Ethernet Adapter");
+ else
+ RtlInitAnsiString(&ansi, "USB Ethernet Adapter");
+
+ if (RtlAnsiStringToUnicodeString(name, &ansi, TRUE))
+ EXIT2(return NDIS_STATUS_RESOURCES);
+ else
+ EXIT2(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisWriteEventLogEntry,7)
+ (void *handle, NDIS_STATUS code, ULONG value, USHORT n,
+ void *strings, ULONG datasize, void *data)
+{
+ TRACE1("0x%x, 0x%x, %u, %u", code, value, n, datasize);
+ return NDIS_STATUS_SUCCESS;
+}
+
+wstdcall void *WIN_FUNC(NdisGetRoutineAddress,1)
+ (struct unicode_string *unicode_string)
+{
+ struct ansi_string ansi_string;
+ void *address;
+
+ if (RtlUnicodeStringToAnsiString(&ansi_string, unicode_string, TRUE) !=
+ STATUS_SUCCESS)
+ EXIT1(return NULL);
+ INFO("%s", ansi_string.buf);
+ address = ndis_get_routine_address(ansi_string.buf);
+ RtlFreeAnsiString(&ansi_string);
+ return address;
+}
+
+wstdcall ULONG WIN_FUNC(NdisReadPcmciaAttributeMemory,4)
+ (struct ndis_mp_block *nmb, ULONG offset, void *buffer,
+ ULONG length)
+{
+ TODO();
+ return 0;
+}
+
+wstdcall ULONG WIN_FUNC(NdisWritePcmciaAttributeMemory,4)
+ (struct ndis_mp_block *nmb, ULONG offset, void *buffer,
+ ULONG length)
+{
+ TODO();
+ return 0;
+}
+
+wstdcall void WIN_FUNC(NdisMCoIndicateReceivePacket,3)
+ (struct ndis_mp_block *nmb, struct ndis_packet **packets,
+ UINT nr_packets)
+{
+ ENTER3("nmb = %p", nmb);
+ NdisMIndicateReceivePacket(nmb, packets, nr_packets);
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisMCoSendComplete,3)
+ (NDIS_STATUS status, struct ndis_mp_block *nmb,
+ struct ndis_packet *packet)
+{
+ ENTER3("%08x", status);
+ NdisMSendComplete(nmb, packet, status);
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(NdisMCoRequestComplete,3)
+ (NDIS_STATUS status, struct ndis_mp_block *nmb,
+ struct ndis_request *ndis_request)
+{
+ struct ndis_device *wnd = nmb->wnd;
+ typeof(wnd->ndis_req_task) task;
+
+ ENTER3("%08X", status);
+ wnd->ndis_req_status = status;
+ wnd->ndis_req_done = 1;
+ if ((task = xchg(&wnd->ndis_req_task, NULL)))
+ wake_up_process(task);
+ else
+ WARNING("invalid task");
+ EXIT3(return);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisIMNotifiyPnPEvent,2)
+ (struct ndis_mp_block *nmb, struct net_pnp_event *event)
+{
+ ENTER2("%p, %d", nmb, event->code);
+ /* NdisWrapper never calls protocol's pnp event notifier, so
+ * nothing to do here */
+ EXIT2(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(NdisCompletePnPEvent,2)
+ (NDIS_STATUS status, void *handle, struct net_pnp_event *event)
+{
+ ENTER2("%d, %p, %d", status, handle, event->code);
+ /* NdisWrapper never calls protocol's pnp event notifier, so
+ * nothing to do here */
+ EXIT2(return);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMSetMiniportSecondary,2)
+ (struct ndis_mp_block *nmb2, struct ndis_mp_block *nmb1)
+{
+ ENTER3("%p, %p", nmb1, nmb2);
+ TODO();
+ EXIT3(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall NDIS_STATUS WIN_FUNC(NdisMPromoteMiniport,1)
+ (struct ndis_mp_block *nmb)
+{
+ ENTER3("%p", nmb);
+ TODO();
+ EXIT3(return NDIS_STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(NdisMCoActivateVcComplete,3)
+ (NDIS_STATUS status, void *handle, void *params)
+{
+ TODO();
+}
+
+wstdcall void WIN_FUNC(NdisMCoDeactivateVcComplete,2)
+ (NDIS_STATUS status, void *handle)
+{
+ TODO();
+}
+
+wstdcall void WIN_FUNC(NdisMRemoveMiniport,1)
+ (void *handle)
+{
+ TODO();
+}
+
+static void *ndis_get_routine_address(char *name)
+{
+ int i;
+ ENTER2("%p", name);
+ for (i = 0; i < sizeof(ndis_exports) / sizeof(ndis_exports[0]); i++) {
+ if (strcmp(name, ndis_exports[i].name) == 0) {
+ TRACE2("%p", ndis_exports[i].func);
+ return ndis_exports[i].func;
+ }
+ }
+ EXIT2(return NULL);
+}
+
+/* ndis_init_device is called for each device */
+int ndis_init_device(struct ndis_device *wnd)
+{
+ struct ndis_mp_block *nmb = wnd->nmb;
+
+ KeInitializeSpinLock(&nmb->lock);
+ wnd->mp_interrupt = NULL;
+ wnd->wrap_timer_slist.next = NULL;
+ if (wnd->wd->driver->ndis_driver)
+ wnd->wd->driver->ndis_driver->mp.shutdown = NULL;
+
+ nmb->filterdbs.eth_db = nmb;
+ nmb->filterdbs.tr_db = nmb;
+ nmb->filterdbs.fddi_db = nmb;
+ nmb->filterdbs.arc_db = nmb;
+
+ nmb->rx_packet = WIN_FUNC_PTR(NdisMIndicateReceivePacket,3);
+ nmb->send_complete = WIN_FUNC_PTR(NdisMSendComplete,3);
+ nmb->send_resource_avail = WIN_FUNC_PTR(NdisMSendResourcesAvailable,1);
+ nmb->status = WIN_FUNC_PTR(NdisMIndicateStatus,4);
+ nmb->status_complete = WIN_FUNC_PTR(NdisMIndicateStatusComplete,1);
+ nmb->queryinfo_complete = WIN_FUNC_PTR(NdisMQueryInformationComplete,2);
+ nmb->setinfo_complete = WIN_FUNC_PTR(NdisMSetInformationComplete,2);
+ nmb->reset_complete = WIN_FUNC_PTR(NdisMResetComplete,3);
+ nmb->eth_rx_indicate = WIN_FUNC_PTR(EthRxIndicateHandler,8);
+ nmb->eth_rx_complete = WIN_FUNC_PTR(EthRxComplete,1);
+ nmb->td_complete = WIN_FUNC_PTR(NdisMTransferDataComplete,4);
+ return 0;
+}
+
+/* ndis_exit_device is called for each device */
+void ndis_exit_device(struct ndis_device *wnd)
+{
+ struct wrap_device_setting *setting;
+ ENTER2("%p", wnd);
+ if (down_interruptible(&loader_mutex))
+ WARNING("couldn't obtain loader_mutex");
+ nt_list_for_each_entry(setting, &wnd->wd->settings, list) {
+ struct ndis_configuration_parameter *param;
+ param = setting->encoded;
+ if (param) {
+ if (param->type == NdisParameterString)
+ RtlFreeUnicodeString(¶m->data.string);
+ ExFreePool(param);
+ setting->encoded = NULL;
+ }
+ }
+ up(&loader_mutex);
+}
+
+/* ndis_init is called once when module is loaded */
+int ndis_init(void)
+{
+ InitializeListHead(&ndis_work_list);
+ spin_lock_init(&ndis_work_list_lock);
+ initialize_work(&ndis_work, ndis_worker, NULL);
+
+ ndis_wq = create_singlethread_workqueue("ndis_wq");
+ if (!ndis_wq) {
+ WARNING("couldn't create worker thread");
+ EXIT1(return -ENOMEM);
+ }
+
+ ndis_worker_thread = wrap_worker_init(ndis_wq);
+ TRACE1("%p", ndis_worker_thread);
+ return 0;
+}
+
+/* ndis_exit is called once when module is removed */
+void ndis_exit(void)
+{
+ ENTER1("");
+ if (ndis_wq)
+ destroy_workqueue(ndis_wq);
+ TRACE1("%p", ndis_worker_thread);
+ if (ndis_worker_thread)
+ ObDereferenceObject(ndis_worker_thread);
+ EXIT1(return);
+}
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _NDIS_H_
+#define _NDIS_H_
+
+#include "ntoskernel.h"
+
+//#define ALLOW_POOL_OVERFLOW 1
+
+#define NDIS_DMA_24BITS 0
+#define NDIS_DMA_32BITS 1
+#define NDIS_DMA_64BITS 2
+
+#ifdef CONFIG_X86_64
+#define MAXIMUM_PROCESSORS 64
+#else
+#define MAXIMUM_PROCESSORS 32
+#endif
+
+typedef UINT NDIS_STATUS;
+typedef UCHAR NDIS_DMA_SIZE;
+typedef LONG ndis_rssi;
+typedef ULONG ndis_key_index;
+typedef ULONG ndis_tx_power_level;
+typedef ULONGULONG ndis_key_rsc;
+typedef UCHAR ndis_rates[NDIS_MAX_RATES];
+typedef UCHAR ndis_rates_ex[NDIS_MAX_RATES_EX];
+typedef UCHAR mac_address[ETH_ALEN];
+typedef ULONG ndis_fragmentation_threshold;
+typedef ULONG ndis_rts_threshold;
+typedef ULONG ndis_antenna;
+typedef ULONG ndis_oid;
+
+typedef UCHAR ndis_pmkid_vavlue[16];
+
+typedef uint64_t NDIS_PHY_ADDRESS;
+
+struct ndis_sg_element {
+ PHYSICAL_ADDRESS address;
+ ULONG length;
+ ULONG_PTR reserved;
+};
+
+struct ndis_sg_list {
+ ULONG nent;
+ ULONG_PTR reserved;
+ struct ndis_sg_element elements[];
+};
+
+/* when sending packets, ndiswrapper associates exactly one sg element
+ * in sg list */
+struct wrap_tx_sg_list {
+ ULONG nent;
+ ULONG_PTR reserved;
+ struct ndis_sg_element elements[1];
+};
+
+struct ndis_phy_addr_unit {
+ NDIS_PHY_ADDRESS phy_addr;
+ UINT length;
+};
+
+typedef struct mdl ndis_buffer;
+
+struct ndis_buffer_pool {
+ ndis_buffer *free_descr;
+// NT_SPIN_LOCK lock;
+ spinlock_t lock;
+ UINT max_descr;
+ UINT num_allocated_descr;
+};
+
+#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
+
+#define fPACKET_WRAPPER_RESERVED 0x3F
+#define fPACKET_CONTAINS_MEDIA_SPECIFIC_INFO 0x40
+#define fPACKET_ALLOCATED_BY_NDIS 0x80
+
+#define PROTOCOL_RESERVED_SIZE_IN_PACKET (4 * sizeof(void *))
+
+struct transport_header_offset {
+ USHORT protocol_type;
+ USHORT header_offset;
+};
+
+struct ndis_network_address {
+ USHORT length;
+ USHORT type;
+ UCHAR address[1];
+};
+
+struct ndis_network_address_list {
+ LONG count;
+ USHORT type;
+ struct ndis_network_address address[1];
+};
+
+struct ndis_tcp_ip_checksum_packet_info {
+ union {
+ struct {
+ ULONG v4:1;
+ ULONG v6:1;
+ ULONG tcp:1;
+ ULONG udp:1;
+ ULONG ip:1;
+ } tx;
+ struct {
+ ULONG tcp_failed:1;
+ ULONG udp_failed:1;
+ ULONG ip_failed:1;
+ ULONG tcp_succeeded:1;
+ ULONG udp_succeeded:1;
+ ULONG ip_succeeded:1;
+ ULONG loopback:1;
+ } rx;
+ ULONG value;
+ };
+};
+
+enum ndis_task {
+ TcpIpChecksumNdisTask, IpSecNdisTask, TcpLargeSendNdisTask, MaxNdisTask
+};
+
+enum ndis_encapsulation {
+ UNSPECIFIED_Encapsulation, NULL_Encapsulation,
+ IEEE_802_3_Encapsulation, IEEE_802_5_Encapsulation,
+ LLC_SNAP_ROUTED_Encapsulation, LLC_SNAP_BRIDGED_Encapsulation
+};
+
+#define NDIS_TASK_OFFLOAD_VERSION 1
+
+struct ndis_encapsulation_format {
+ enum ndis_encapsulation encap;
+ struct {
+ ULONG fixed_header_size:1;
+ ULONG reserved:31;
+ } flags;
+ ULONG header_size;
+};
+
+struct ndis_task_offload_header {
+ ULONG version;
+ ULONG size;
+ ULONG reserved;
+ ULONG offset_first_task;
+ struct ndis_encapsulation_format encap_format;
+};
+
+struct ndis_task_offload {
+ ULONG version;
+ ULONG size;
+ enum ndis_task task;
+ ULONG offset_next_task;
+ ULONG task_buf_length;
+ UCHAR task_buf[1];
+};
+
+struct v4_checksum {
+ union {
+ struct {
+ ULONG ip_opts:1;
+ ULONG tcp_opts:1;
+ ULONG tcp_csum:1;
+ ULONG udp_csum:1;
+ ULONG ip_csum:1;
+ };
+ ULONG value;
+ };
+};
+
+struct v6_checksum {
+ ULONG ip_supported:1;
+ ULONG tcp_supported:1;
+ ULONG tcp_csum:1;
+ ULONG udp_csum:1;
+};
+
+struct ndis_task_tcp_ip_checksum {
+ struct v4_checksum v4_tx;
+ struct v4_checksum v4_rx;
+ struct v6_checksum v6_tx;
+ struct v6_checksum v6_rx;
+};
+
+struct ndis_task_tcp_large_send {
+ ULONG version;
+ ULONG max_size;
+ ULONG min_seg_count;
+ BOOLEAN tcp_opts;
+ BOOLEAN ip_opts;
+};
+
+struct ndis_packet;
+
+struct ndis_packet_pool {
+ struct ndis_packet *free_descr;
+// NT_SPIN_LOCK lock;
+ spinlock_t lock;
+ UINT max_descr;
+ UINT num_allocated_descr;
+ UINT num_used_descr;
+ UINT proto_rsvd_length;
+};
+
+struct ndis_packet_stack {
+ ULONG_PTR IM_reserved[2];
+ ULONG_PTR ndis_reserved[4];
+};
+
+enum ndis_per_packet_info {
+ TcpIpChecksumPacketInfo, IpSecPacketInfo, TcpLargeSendPacketInfo,
+ ClassificationHandlePacketInfo, NdisReserved,
+ ScatterGatherListPacketInfo, Ieee8021QInfo, OriginalPacketInfo,
+ PacketCancelId, MaxPerPacketInfo
+};
+
+struct ndis_packet_extension {
+ void *info[MaxPerPacketInfo];
+};
+
+struct ndis_packet_private {
+ UINT nr_pages;
+ UINT len;
+ ndis_buffer *buffer_head;
+ ndis_buffer *buffer_tail;
+ struct ndis_packet_pool *pool;
+ UINT count;
+ ULONG flags;
+ BOOLEAN valid_counts;
+ UCHAR packet_flags;
+ USHORT oob_offset;
+};
+
+struct ndis_packet {
+ struct ndis_packet_private private;
+ /* for use by miniport */
+ union {
+ /* for connectionless mininports */
+ struct {
+ UCHAR miniport_reserved[2 * sizeof(void *)];
+ UCHAR wrapper_reserved[2 * sizeof(void *)];
+ } cl_reserved;
+ /* for deserialized miniports */
+ struct {
+ UCHAR miniport_reserved_ex[3 * sizeof(void *)];
+ UCHAR wrapper_reserved_ex[sizeof(void *)];
+ } deserailized_reserved;
+ struct {
+ UCHAR mac_reserved[4 * sizeof(void *)];
+ } mac_reserved;
+ };
+ ULONG_PTR reserved[2];
+ UCHAR protocol_reserved[1];
+};
+
+/* OOB data */
+struct ndis_packet_oob_data {
+ union {
+ ULONGLONG time_to_tx;
+ ULONGLONG time_txed;
+ };
+ ULONGLONG time_rxed;
+ UINT header_size;
+ UINT media_size;
+ void *media;
+ NDIS_STATUS status;
+
+ /* ndiswrapper specific info; extension should be right after
+ * ndis's oob_data */
+ struct ndis_packet_extension ext;
+ union {
+ /* used for tx only */
+ struct {
+ struct sk_buff *tx_skb;
+ union {
+ struct wrap_tx_sg_list wrap_tx_sg_list;
+ struct ndis_sg_list *tx_sg_list;
+ };
+ };
+ /* used for rx only */
+ struct {
+ unsigned char header[ETH_HLEN];
+ unsigned char *look_ahead;
+ UINT look_ahead_size;
+ };
+ };
+};
+
+#define NDIS_PACKET_OOB_DATA(packet) \
+ (struct ndis_packet_oob_data *)(((void *)(packet)) + \
+ (packet)->private.oob_offset)
+
+enum ndis_device_pnp_event {
+ NdisDevicePnPEventQueryRemoved, NdisDevicePnPEventRemoved,
+ NdisDevicePnPEventSurpriseRemoved, NdisDevicePnPEventQueryStopped,
+ NdisDevicePnPEventStopped, NdisDevicePnPEventPowerProfileChanged,
+ NdisDevicePnPEventMaximum
+};
+
+enum ndis_request_type {
+ NdisRequestQueryInformation, NdisRequestSetInformation,
+ NdisRequestQueryStatistics, NdisRequestOpen, NdisRequestClose,
+ NdisRequestSend, NdisRequestTransferData, NdisRequestReset,
+ NdisRequestGeneric1, NdisRequestGeneric2, NdisRequestGeneric3,
+ NdisRequestGeneric4
+};
+
+struct ndis_request {
+ mac_address mac;
+ enum ndis_request_type request_type;
+ union data {
+ struct query_info {
+ UINT oid;
+ void *buf;
+ UINT buf_len;
+ UINT written;
+ UINT needed;
+ } query_info;
+ struct set_info {
+ UINT oid;
+ void *buf;
+ UINT buf_len;
+ UINT written;
+ UINT needed;
+ } set_info;
+ } data;
+};
+
+enum ndis_medium {
+ NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumWan,
+ NdisMediumLocalTalk, NdisMediumDix, NdisMediumArcnetRaw,
+ NdisMediumArcnet878_2, NdisMediumAtm, NdisMediumWirelessWan,
+ NdisMediumIrda, NdisMediumBpc, NdisMediumCoWan,
+ NdisMedium1394, NdisMediumMax
+};
+
+enum ndis_physical_medium {
+ NdisPhysicalMediumUnspecified, NdisPhysicalMediumWirelessLan,
+ NdisPhysicalMediumCableModem, NdisPhysicalMediumPhoneLine,
+ NdisPhysicalMediumPowerLine, NdisPhysicalMediumDSL,
+ NdisPhysicalMediumFibreChannel, NdisPhysicalMedium1394,
+ NdisPhysicalMediumWirelessWan, NdisPhysicalMediumMax
+};
+
+enum ndis_power_state {
+ NdisDeviceStateUnspecified = 0,
+ NdisDeviceStateD0, NdisDeviceStateD1, NdisDeviceStateD2,
+ NdisDeviceStateD3, NdisDeviceStateMaximum
+};
+
+enum ndis_power_profile {
+ NdisPowerProfileBattery, NdisPowerProfileAcOnLine
+};
+
+struct ndis_pm_wakeup_capabilities {
+ enum ndis_power_state min_magic_packet_wakeup;
+ enum ndis_power_state min_pattern_wakeup;
+ enum ndis_power_state min_link_change_wakeup;
+};
+
+#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001
+#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002
+#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004
+
+enum net_pnp_event_code {
+ NetEventSetPower, NetEventQueryPower, NetEventQueryRemoveDevice,
+ NetEventCancelRemoveDevice, NetEventReconfigure, NetEventBindList,
+ NetEventBindsComplete, NetEventPnPCapabilities, NetEventMaximum
+};
+
+struct net_pnp_event {
+ enum net_pnp_event_code code;
+ void *buf;
+ ULONG buf_length;
+ ULONG_PTR ndis_reserved[4];
+ ULONG_PTR transport_reserved[4];
+ ULONG_PTR tdi_reserved[4];
+ ULONG_PTR tdi_client_reserved[4];
+};
+
+struct ndis_pnp_capabilities {
+ ULONG flags;
+ struct ndis_pm_wakeup_capabilities wakeup;
+};
+
+typedef void (*ndis_isr_handler)(BOOLEAN *recognized, BOOLEAN *queue_handler,
+ void *handle) wstdcall;
+typedef void (*ndis_interrupt_handler)(void *ctx) wstdcall;
+
+struct miniport {
+ /* NDIS 3.0 */
+ UCHAR major_version;
+ UCHAR minor_version;
+ USHORT filler;
+ UINT reserved;
+ BOOLEAN (*hangcheck)(void *ctx) wstdcall;
+ void (*disable_interrupt)(void *ctx) wstdcall;
+ void (*enable_interrupt)(void *ctx) wstdcall;
+ void (*mp_halt)(void *ctx) wstdcall;
+ ndis_interrupt_handler handle_interrupt;
+ NDIS_STATUS (*init)(NDIS_STATUS *error_status, UINT *medium_index,
+ enum ndis_medium medium[], UINT medium_array_size,
+ void *handle, void *conf_handle) wstdcall;
+ ndis_isr_handler isr;
+ NDIS_STATUS (*queryinfo)(void *ctx, ndis_oid oid, void *buffer,
+ ULONG buflen, ULONG *written,
+ ULONG *needed) wstdcall;
+ void *reconfig;
+ NDIS_STATUS (*reset)(BOOLEAN *reset_address, void *ctx) wstdcall;
+ NDIS_STATUS (*send)(void *ctx, struct ndis_packet *packet,
+ UINT flags) wstdcall;
+ NDIS_STATUS (*setinfo)(void *ctx, ndis_oid oid, void *buffer,
+ ULONG buflen, ULONG *written,
+ ULONG *needed) wstdcall;
+ NDIS_STATUS (*tx_data)(struct ndis_packet *ndis_packet,
+ UINT *bytes_txed, void *mp_ctx, void *rx_ctx,
+ UINT offset, UINT bytes_to_tx) wstdcall;
+ /* NDIS 4.0 extensions */
+ void (*return_packet)(void *ctx, void *packet) wstdcall;
+ void (*send_packets)(void *ctx, struct ndis_packet **packets,
+ INT nr_of_packets) wstdcall;
+ void (*alloc_complete)(void *handle, void *virt,
+ NDIS_PHY_ADDRESS *phys,
+ ULONG size, void *ctx) wstdcall;
+ /* NDIS 5.0 extensions */
+ NDIS_STATUS (*co_create_vc)(void *ctx, void *vc_handle,
+ void *vc_ctx) wstdcall;
+ NDIS_STATUS (*co_delete_vc)(void *vc_ctx) wstdcall;
+ NDIS_STATUS (*co_activate_vc)(void *vc_ctx, void *call_params) wstdcall;
+ NDIS_STATUS (*co_deactivate_vc)(void *vc_ctx) wstdcall;
+ NDIS_STATUS (*co_send_packets)(void *vc_ctx, void **packets,
+ UINT nr_of_packets) wstdcall;
+ NDIS_STATUS (*co_request)(void *ctx, void *vc_ctx, UINT *req) wstdcall;
+ /* NDIS 5.1 extensions */
+ void (*cancel_send_packets)(void *ctx, void *id) wstdcall;
+ void (*pnp_event_notify)(void *ctx, enum ndis_device_pnp_event event,
+ void *inf_buf, ULONG inf_buf_len) wstdcall;
+ void (*shutdown)(void *ctx) wstdcall;
+ void *reserved1;
+ void *reserved2;
+ void *reserved3;
+ void *reserved4;
+};
+
+struct ndis_spinlock {
+ NT_SPIN_LOCK klock;
+ KIRQL irql;
+};
+
+union ndis_rw_lock_refcount {
+ UCHAR cache_line[16];
+};
+
+struct ndis_rw_lock {
+ union {
+ struct {
+ NT_SPIN_LOCK klock;
+ void *context;
+ };
+ UCHAR reserved[16];
+ };
+ union {
+ union ndis_rw_lock_refcount ref_count[MAXIMUM_PROCESSORS];
+ /* ndiswrapper specific */
+ volatile int count;
+ };
+};
+
+struct lock_state {
+ USHORT state;
+ KIRQL irql;
+};
+
+struct ndis_work_item;
+typedef void (*NDIS_PROC)(struct ndis_work_item *, void *) wstdcall;
+
+struct ndis_work_item {
+ void *ctx;
+ NDIS_PROC func;
+ union {
+ UCHAR reserved[8 * sizeof(void *)];
+ /* ndiswrapper specific */
+ struct nt_list list;
+ };
+};
+
+struct alloc_shared_mem {
+ void *ctx;
+ ULONG size;
+ BOOLEAN cached;
+};
+
+struct ndis_mp_block;
+
+/* this is opaque to drivers, so we can use it as we please */
+struct ndis_mp_interrupt {
+ struct kinterrupt *kinterrupt;
+ NT_SPIN_LOCK lock;
+ union {
+ void *reserved;
+ unsigned int irq;
+ };
+ ndis_isr_handler isr;
+ ndis_interrupt_handler mp_dpc;
+ struct kdpc intr_dpc;
+ struct ndis_mp_block *nmb;
+ UCHAR dpc_count;
+ BOOLEAN enable;
+ struct nt_event dpc_completed_event;
+ BOOLEAN shared;
+ BOOLEAN req_isr;
+};
+
+struct ndis_binary_data {
+ USHORT len;
+ void *buf;
+};
+
+enum ndis_parameter_type {
+ NdisParameterInteger, NdisParameterHexInteger,
+ NdisParameterString, NdisParameterMultiString, NdisParameterBinary,
+};
+
+typedef struct unicode_string NDIS_STRING;
+
+struct ndis_configuration_parameter {
+ enum ndis_parameter_type type;
+ union {
+ ULONG integer;
+ NDIS_STRING string;
+ } data;
+};
+
+struct ndis_driver {
+ struct miniport mp;
+};
+
+/* IDs used to store extensions in driver_object's custom extension */
+#define NDIS_DRIVER_CLIENT_ID 10
+
+struct ndis_wireless_stats {
+ ULONG length;
+ LARGE_INTEGER tx_frag;
+ LARGE_INTEGER tx_multi_frag;
+ LARGE_INTEGER failed;
+ LARGE_INTEGER retry;
+ LARGE_INTEGER multi_retry;
+ LARGE_INTEGER rtss_succ;
+ LARGE_INTEGER rtss_fail;
+ LARGE_INTEGER ack_fail;
+ LARGE_INTEGER frame_dup;
+ LARGE_INTEGER rx_frag;
+ LARGE_INTEGER rx_multi_frag;
+ LARGE_INTEGER fcs_err;
+ LARGE_INTEGER tkip_local_mic_failures;
+ LARGE_INTEGER tkip_icv_errors;
+ LARGE_INTEGER tkip_counter_measures_invoked;
+ LARGE_INTEGER tkip_replays;
+ LARGE_INTEGER ccmp_format_errors;
+ LARGE_INTEGER ccmp_replays;
+ LARGE_INTEGER ccmp_decrypt_errors;
+ LARGE_INTEGER fourway_handshake_failures;
+ LARGE_INTEGER wep_undecryptable_count;
+ LARGE_INTEGER wep_icv_errorcount;
+ LARGE_INTEGER decrypt_success_count;
+ LARGE_INTEGER decrypt_failure_count;
+};
+
+enum ndis_status_type {
+ Ndis802_11StatusType_Authentication,
+ Ndis802_11StatusType_MediaStreamMode,
+ Ndis802_11StatusType_PMKID_CandidateList,
+ Ndis802_11StatusType_RadioState,
+};
+
+struct ndis_status_indication {
+ enum ndis_status_type status_type;
+};
+
+enum ndis_radio_status {
+ Ndis802_11RadioStatusOn, Ndis802_11RadioStatusHardwareOff,
+ Ndis802_11RadioStatusSoftwareOff,
+};
+
+struct ndis_radio_status_indication
+{
+ enum ndis_status_type status_type;
+ enum ndis_radio_status radio_state;
+};
+
+enum ndis_media_state {
+ NdisMediaStateConnected,
+ NdisMediaStateDisconnected,
+};
+
+enum ndis_media_stream_mode {
+ Ndis802_11MediaStreamOff, Ndis802_11MediaStreamOn
+};
+
+enum wrapper_work {
+ LINK_STATUS_OFF, LINK_STATUS_ON, SET_MULTICAST_LIST, COLLECT_IW_STATS,
+ HANGCHECK, NETIF_WAKEQ,
+};
+
+struct encr_info {
+ struct encr_key {
+ ULONG length;
+ UCHAR key[NDIS_ENCODING_TOKEN_MAX];
+ } keys[MAX_ENCR_KEYS];
+ unsigned short tx_key_index;
+};
+
+struct ndis_essid {
+ ULONG length;
+ UCHAR essid[NDIS_ESSID_MAX_SIZE];
+};
+
+enum ndis_infrastructure_mode {
+ Ndis802_11IBSS, Ndis802_11Infrastructure, Ndis802_11AutoUnknown,
+ Ndis802_11InfrastructureMax
+};
+
+enum authentication_mode {
+ Ndis802_11AuthModeOpen, Ndis802_11AuthModeShared,
+ Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA,
+ Ndis802_11AuthModeWPAPSK, Ndis802_11AuthModeWPANone,
+ Ndis802_11AuthModeWPA2, Ndis802_11AuthModeWPA2PSK,
+ Ndis802_11AuthModeMax
+};
+
+enum encryption_status {
+ Ndis802_11WEPEnabled,
+ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+ Ndis802_11WEPDisabled,
+ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+ Ndis802_11WEPKeyAbsent,
+ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+ Ndis802_11WEPNotSupported,
+ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+ Ndis802_11Encryption2Enabled, Ndis802_11Encryption2KeyAbsent,
+ Ndis802_11Encryption3Enabled, Ndis802_11Encryption3KeyAbsent
+};
+
+struct ndis_auth_encr_pair {
+ enum authentication_mode auth_mode;
+ enum encryption_status encr_mode;
+};
+
+struct ndis_capability {
+ ULONG length;
+ ULONG version;
+ ULONG num_PMKIDs;
+ ULONG num_auth_encr_pair;
+ struct ndis_auth_encr_pair auth_encr_pair[1];
+};
+
+struct ndis_guid {
+ struct guid guid;
+ union {
+ ndis_oid oid;
+ NDIS_STATUS status;
+ };
+ ULONG size;
+ ULONG flags;
+};
+
+struct ndis_timer {
+ struct nt_timer nt_timer;
+ struct kdpc kdpc;
+};
+
+struct ndis_mp_timer {
+ struct nt_timer nt_timer;
+ struct kdpc kdpc;
+ DPC func;
+ void *ctx;
+ struct ndis_mp_block *nmb;
+ struct ndis_mp_timer *next;
+};
+
+typedef struct cm_partial_resource_list NDIS_RESOURCE_LIST;
+
+struct ndis_event {
+ struct nt_event nt_event;
+};
+
+struct ndis_bind_paths {
+ UINT number;
+ struct unicode_string paths[1];
+};
+
+struct ndis_reference {
+ NT_SPIN_LOCK lock;
+ USHORT ref_count;
+ BOOLEAN closing;
+};
+
+struct ndis_filterdbs {
+ union {
+ void *eth_db;
+ void *null_db;
+ };
+ void *tr_db;
+ void *fddi_db;
+ void *arc_db;
+};
+
+enum ndis_interface_type {
+ NdisInterfaceInternal, NdisInterfaceIsa, NdisInterfaceEisa,
+ NdisInterfaceMca, NdisInterfaceTurboChannel, NdisInterfacePci,
+ NdisInterfacePcMcia,
+};
+
+struct auth_encr_capa {
+ unsigned long auth;
+ unsigned long encr;
+};
+
+struct ndis_pmkid_candidate {
+ mac_address bssid;
+ DWORD flags;
+};
+
+struct ndis_pmkid_candidate_list {
+ ULONG version;
+ ULONG num_candidates;
+ struct ndis_pmkid_candidate candidates[1];
+};
+
+/*
+ * This struct contains function pointers that the drivers references
+ * directly via macros, so it's important that they are at the correct
+ * position.
+ */
+struct ndis_mp_block {
+ void *signature;
+ struct ndis_mp_block *next;
+ struct driver_object *drv_obj;
+ void *mp_ctx;
+ struct unicode_string name;
+ struct ndis_bind_paths *bindpaths;
+ void *openqueue;
+ struct ndis_reference reference;
+ void *device_ctx;
+ UCHAR padding;
+ UCHAR lock_acquired;
+ UCHAR pmode_opens;
+ UCHAR assigned_cpu;
+ NT_SPIN_LOCK lock;
+ enum ndis_request_type *mediarequest;
+ struct ndis_mp_interrupt *interrupt;
+ ULONG flags;
+ ULONG pnp_flags;
+ struct nt_list packet_list;
+ struct ndis_packet *first_pending_tx_packet;
+ struct ndis_packet *return_packet_queue;
+ ULONG request_buffer;
+ void *set_mcast_buffer;
+ struct ndis_mp_block *primary_mp;
+ void *wrapper_ctx;
+ void *bus_data_ctx;
+ ULONG pnp_capa;
+ void *resources;
+ struct ndis_timer wakeup_dpc_timer;
+ struct unicode_string basename;
+ struct unicode_string symlink_name;
+ ULONG ndis_hangcheck_interval;
+ USHORT hanghcheck_ticks;
+ USHORT hangcheck_tick;
+ NDIS_STATUS ndis_reset_status;
+ void *resetopen;
+ struct ndis_filterdbs filterdbs;
+ void *rx_packet;
+ void *send_complete;
+ void *send_resource_avail;
+ void *reset_complete;
+
+ enum ndis_medium media_type;
+ ULONG bus_number;
+ enum ndis_interface_type bus_type;
+ enum ndis_interface_type adapter_type;
+ struct device_object *fdo;
+ struct device_object *pdo;
+ struct device_object *next_device;
+ void *mapreg;
+ void *call_mgraflist;
+ void *mp_thread;
+ void *setinfobuf;
+ USHORT setinfo_buf_len;
+ USHORT max_send_pkts;
+ NDIS_STATUS fake_status;
+ void *lock_handler;
+ struct unicode_string *adapter_instance_name;
+ void *timer_queue;
+ UINT mac_options;
+ void *pending_req;
+ UINT max_long_addrs;
+ UINT max_short_addrs;
+ UINT cur_lookahead;
+ UINT max_lookahead;
+
+ ndis_interrupt_handler irq_bh;
+ void *disable_intr;
+ void *enable_intr;
+ void *send_pkts;
+ void *deferred_send;
+ void *eth_rx_indicate;
+ void *tr_rx_indicate;
+ void *fddi_rx_indicate;
+ void *eth_rx_complete;
+ void *tr_rx_complete;
+ void *fddi_rx_complete;
+
+ void *status;
+ void *status_complete;
+ void *td_complete;
+
+ void *queryinfo_complete;
+ void *setinfo_complete;
+ void *wan_tx_complete;
+ void *wan_rx;
+ void *wan_rx_complete;
+ /* ndiswrapper specific */
+ struct ndis_device *wnd;
+};
+
+struct ndis_device {
+ struct ndis_mp_block *nmb;
+ struct wrap_device *wd;
+ struct net_device *net_dev;
+ void *shutdown_ctx;
+ struct ndis_mp_interrupt *mp_interrupt;
+ struct kdpc irq_kdpc;
+ unsigned long mem_start;
+ unsigned long mem_end;
+
+ struct net_device_stats net_stats;
+ struct iw_statistics iw_stats;
+ BOOLEAN iw_stats_enabled;
+ struct ndis_wireless_stats ndis_stats;
+
+ work_struct_t tx_work;
+ struct ndis_packet *tx_ring[TX_RING_SIZE];
+ u8 tx_ring_start;
+ u8 tx_ring_end;
+ u8 is_tx_ring_full;
+ u8 tx_ok;
+ spinlock_t tx_ring_lock;
+ struct semaphore tx_ring_mutex;
+ unsigned int max_tx_packets;
+ struct semaphore ndis_req_mutex;
+ struct task_struct *ndis_req_task;
+ int ndis_req_done;
+ NDIS_STATUS ndis_req_status;
+ ULONG packet_filter;
+
+ ULONG sg_dma_size;
+ ULONG dma_map_count;
+ dma_addr_t *dma_map_addr;
+
+ int hangcheck_interval;
+ struct timer_list hangcheck_timer;
+ int iw_stats_interval;
+ struct timer_list iw_stats_timer;
+ unsigned long scan_timestamp;
+ struct encr_info encr_info;
+ char nick[IW_ESSID_MAX_SIZE + 1];
+ struct ndis_essid essid;
+ struct auth_encr_capa capa;
+ enum ndis_infrastructure_mode infrastructure_mode;
+ int max_pmkids;
+ int num_pmkids;
+ struct ndis_pmkid *pmkids;
+ mac_address mac;
+ struct proc_dir_entry *procfs_iface;
+
+ work_struct_t ndis_work;
+ unsigned long ndis_pending_work;
+ UINT attributes;
+ int iw_auth_wpa_version;
+ int iw_auth_cipher_pairwise;
+ int iw_auth_cipher_group;
+ int iw_auth_key_mgmt;
+ int iw_auth_80211_alg;
+ struct ndis_packet_pool *tx_packet_pool;
+ struct ndis_buffer_pool *tx_buffer_pool;
+ int multicast_size;
+ struct v4_checksum rx_csum;
+ struct v4_checksum tx_csum;
+ enum ndis_physical_medium physical_medium;
+ ULONG ndis_wolopts;
+ struct nt_slist wrap_timer_slist;
+ int drv_ndis_version;
+ struct ndis_pnp_capabilities pnp_capa;
+ char netdev_name[IFNAMSIZ];
+};
+
+BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) wstdcall;
+
+int ndis_init(void);
+void ndis_exit(void);
+int ndis_init_device(struct ndis_device *wnd);
+void ndis_exit_device(struct ndis_device *wnd);
+
+int wrap_procfs_add_ndis_device(struct ndis_device *wnd);
+void wrap_procfs_remove_ndis_device(struct ndis_device *wnd);
+
+void NdisAllocatePacketPoolEx(NDIS_STATUS *status,
+ struct ndis_packet_pool **pool_handle,
+ UINT num_descr, UINT overflowsize,
+ UINT proto_rsvd_length) wstdcall;
+void NdisFreePacketPool(struct ndis_packet_pool *pool) wstdcall;
+void NdisAllocatePacket(NDIS_STATUS *status, struct ndis_packet **packet,
+ struct ndis_packet_pool *pool) wstdcall;
+void NdisFreePacket(struct ndis_packet *descr) wstdcall;
+void NdisAllocateBufferPool(NDIS_STATUS *status,
+ struct ndis_buffer_pool **pool_handle,
+ UINT num_descr) wstdcall;
+void NdisFreeBufferPool(struct ndis_buffer_pool *pool) wstdcall;
+void NdisAllocateBuffer(NDIS_STATUS *status, ndis_buffer **buffer,
+ struct ndis_buffer_pool *pool, void *virt,
+ UINT length) wstdcall;
+void NdisFreeBuffer(ndis_buffer *descr) wstdcall;
+void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb,
+ struct ndis_packet **packets,
+ UINT nr_packets) wstdcall;
+void NdisMSendComplete(struct ndis_mp_block *nmb, struct ndis_packet *packet,
+ NDIS_STATUS status) wstdcall;
+void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) wstdcall;
+void NdisMIndicateStatus(struct ndis_mp_block *nmb,
+ NDIS_STATUS status, void *buf, UINT len) wstdcall;
+void NdisMIndicateStatusComplete(struct ndis_mp_block *nmb) wstdcall;
+void NdisMQueryInformationComplete(struct ndis_mp_block *nmb,
+ NDIS_STATUS status) wstdcall;
+void NdisMSetInformationComplete(struct ndis_mp_block *nmb,
+ NDIS_STATUS status) wstdcall;
+void NdisMResetComplete(struct ndis_mp_block *nmb, NDIS_STATUS status,
+ BOOLEAN address_reset) wstdcall;
+ULONG NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *buffer) wstdcall;
+BOOLEAN NdisWaitEvent(struct ndis_event *event, UINT timeout) wstdcall;
+void NdisSetEvent(struct ndis_event *event) wstdcall;
+void NdisMDeregisterInterrupt(struct ndis_mp_interrupt *mp_interrupt) wstdcall;
+void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx,
+ char *header1, char *header, UINT header_size,
+ void *look_ahead, UINT look_ahead_size,
+ UINT packet_size) wstdcall;
+void EthRxComplete(struct ndis_mp_block *nmb) wstdcall;
+void NdisMTransferDataComplete(struct ndis_mp_block *nmb,
+ struct ndis_packet *packet, NDIS_STATUS status,
+ UINT bytes_txed) wstdcall;
+void NdisWriteConfiguration(NDIS_STATUS *status, struct ndis_mp_block *nmb,
+ struct unicode_string *key,
+ struct ndis_configuration_parameter *param) wstdcall;
+void NdisReadConfiguration(NDIS_STATUS *status,
+ struct ndis_configuration_parameter **param,
+ struct ndis_mp_block *nmb,
+ struct unicode_string *key,
+ enum ndis_parameter_type type) wstdcall;
+
+/* Required OIDs */
+#define OID_GEN_SUPPORTED_LIST 0x00010101
+#define OID_GEN_HARDWARE_STATUS 0x00010102
+#define OID_GEN_MEDIA_SUPPORTED 0x00010103
+#define OID_GEN_MEDIA_IN_USE 0x00010104
+#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
+#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
+#define OID_GEN_LINK_SPEED 0x00010107
+#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
+#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
+#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
+#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
+#define OID_GEN_VENDOR_ID 0x0001010C
+#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
+#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
+#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
+#define OID_GEN_DRIVER_VERSION 0x00010110
+#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
+#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
+#define OID_GEN_MAC_OPTIONS 0x00010113
+#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
+#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
+#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
+#define OID_GEN_SUPPORTED_GUIDS 0x00010117
+#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 /* Set only */
+#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 /* Set only */
+#define OID_GEN_MACHINE_NAME 0x0001021A
+#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B /* Set only */
+#define OID_GEN_VLAN_ID 0x0001021C
+
+/* Optional OIDs. */
+#define OID_GEN_MEDIA_CAPABILITIES 0x00010201
+#define OID_GEN_PHYSICAL_MEDIUM 0x00010202
+
+/* Required statistics OIDs. */
+#define OID_GEN_XMIT_OK 0x00020101
+#define OID_GEN_RCV_OK 0x00020102
+#define OID_GEN_XMIT_ERROR 0x00020103
+#define OID_GEN_RCV_ERROR 0x00020104
+#define OID_GEN_RCV_NO_BUFFER 0x00020105
+
+/* Optional OID statistics */
+#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
+#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
+#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
+#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
+#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
+#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
+#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
+#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
+#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
+#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
+#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
+#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
+#define OID_GEN_RCV_CRC_ERROR 0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
+#define OID_GEN_GET_TIME_CAPS 0x0002020F
+#define OID_GEN_GET_NETCARD_TIME 0x00020210
+#define OID_GEN_NETCARD_LOAD 0x00020211
+#define OID_GEN_DEVICE_PROFILE 0x00020212
+
+/* 802.3 (ethernet) OIDs */
+#define OID_802_3_PERMANENT_ADDRESS 0x01010101
+#define OID_802_3_CURRENT_ADDRESS 0x01010102
+#define OID_802_3_MULTICAST_LIST 0x01010103
+#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104
+#define OID_802_3_MAC_OPTIONS 0x01010105
+#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001
+#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION 0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103
+#define OID_802_3_XMIT_DEFERRED 0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202
+#define OID_802_3_RCV_OVERRUN 0x01020203
+#define OID_802_3_XMIT_UNDERRUN 0x01020204
+#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205
+#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207
+
+/* PnP and power management OIDs */
+#define OID_PNP_CAPABILITIES 0xFD010100
+#define OID_PNP_SET_POWER 0xFD010101
+#define OID_PNP_QUERY_POWER 0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104
+#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105
+#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
+
+/* PnP/PM Statistics (Optional). */
+#define OID_PNP_WAKE_UP_OK 0xFD020200
+#define OID_PNP_WAKE_UP_ERROR 0xFD020201
+
+/* The following bits are defined for OID_PNP_ENABLE_WAKE_UP */
+#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001
+#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002
+#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004
+
+/* 802.11 OIDs */
+#define OID_802_11_BSSID 0x0D010101
+#define OID_802_11_SSID 0x0D010102
+#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0D010203
+#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204
+#define OID_802_11_TX_POWER_LEVEL 0x0D010205
+#define OID_802_11_RSSI 0x0D010206
+#define OID_802_11_RSSI_TRIGGER 0x0D010207
+#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108
+#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0D010209
+#define OID_802_11_RTS_THRESHOLD 0x0D01020A
+#define OID_802_11_NUMBER_OF_ANTENNAS 0x0D01020B
+#define OID_802_11_RX_ANTENNA_SELECTED 0x0D01020C
+#define OID_802_11_TX_ANTENNA_SELECTED 0x0D01020D
+#define OID_802_11_SUPPORTED_RATES 0x0D01020E
+#define OID_802_11_DESIRED_RATES 0x0D010210
+#define OID_802_11_CONFIGURATION 0x0D010211
+#define OID_802_11_STATISTICS 0x0D020212
+#define OID_802_11_ADD_WEP 0x0D010113
+#define OID_802_11_REMOVE_WEP 0x0D010114
+#define OID_802_11_DISASSOCIATE 0x0D010115
+#define OID_802_11_POWER_MODE 0x0D010216
+#define OID_802_11_BSSID_LIST 0x0D010217
+#define OID_802_11_AUTHENTICATION_MODE 0x0D010118
+#define OID_802_11_PRIVACY_FILTER 0x0D010119
+#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A
+#define OID_802_11_WEP_STATUS 0x0D01011B
+#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS
+#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C
+#define OID_802_11_ADD_KEY 0x0D01011D
+#define OID_802_11_REMOVE_KEY 0x0D01011E
+#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F
+#define OID_802_11_TEST 0x0D010120
+#define OID_802_11_MEDIA_STREAM_MODE 0x0D010121
+#define OID_802_11_CAPABILITY 0x0D010122
+#define OID_802_11_PMKID 0x0D010123
+
+#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_INVALID_PARAMETER 0xC000000D
+#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_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
+
+/* Event codes */
+
+#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
+
+/* packet filter bits used by NDIS_OID_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
+
+/* memory allocation flags */
+#define NDIS_MEMORY_CONTIGUOUS 0x00000001
+#define NDIS_MEMORY_NONCACHED 0x00000002
+
+/* Atrribute flags to NdisMSetAtrributesEx */
+#define NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT 0x00000001
+#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002
+#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004
+#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008
+#define NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER 0x00000010
+#define NDIS_ATTRIBUTE_DESERIALIZE 0x00000020
+#define NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND 0x00000040
+#define NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK 0x00000080
+#define NDIS_ATTRIBUTE_NOT_CO_NDIS 0x00000100
+#define NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS 0x00000200
+
+#define OID_TCP_TASK_OFFLOAD 0xFC010201
+
+#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 deserialized_driver(wnd) (wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE)
+
+static inline void serialize_lock(struct ndis_device *wnd)
+{
+ nt_spin_lock(&wnd->nmb->lock);
+}
+
+static inline void serialize_unlock(struct ndis_device *wnd)
+{
+ nt_spin_unlock(&wnd->nmb->lock);
+}
+
+static inline KIRQL serialize_lock_irql(struct ndis_device *wnd)
+{
+ if (deserialized_driver(wnd))
+ return raise_irql(DISPATCH_LEVEL);
+ else
+ return nt_spin_lock_irql(&wnd->nmb->lock, DISPATCH_LEVEL);
+}
+
+static inline void serialize_unlock_irql(struct ndis_device *wnd,
+ KIRQL irql)
+{
+ if (deserialized_driver(wnd))
+ lower_irql(irql);
+ else
+ nt_spin_unlock_irql(&wnd->nmb->lock, irql);
+}
+
+static inline void if_serialize_lock(struct ndis_device *wnd)
+{
+ if (!deserialized_driver(wnd))
+ nt_spin_lock(&wnd->nmb->lock);
+}
+
+static inline void if_serialize_unlock(struct ndis_device *wnd)
+{
+ if (!deserialized_driver(wnd))
+ nt_spin_unlock(&wnd->nmb->lock);
+}
+
+#endif /* NDIS_H */
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _NDISWRAPPER_H_
+#define _NDISWRAPPER_H_
+
+#define DRIVER_VERSION "1.55"
+#define UTILS_VERSION "1.9"
+
+#define DRIVER_NAME "ndiswrapper"
+#define DRIVER_CONFIG_DIR "/etc/ndiswrapper"
+
+#define SSID_MAX_WPA_IE_LEN 40
+#define NDIS_ESSID_MAX_SIZE 32
+#define NDIS_ENCODING_TOKEN_MAX 32
+#define MAX_ENCR_KEYS 4
+#define TX_RING_SIZE 16
+#define NDIS_MAX_RATES 8
+#define NDIS_MAX_RATES_EX 16
+#define WLAN_EID_GENERIC 221
+#define MAX_WPA_IE_LEN 64
+#define MAX_STR_LEN 512
+
+#define WRAP_PCI_BUS 5
+#define WRAP_PCMCIA_BUS 8
+/* some USB devices, e.g., DWL-G120 have BusType as 0 */
+#define WRAP_INTERNAL_BUS 0
+/* documentation at msdn says 15 is PNP bus, but inf files from all
+ * vendors say 15 is USB; which is correct? */
+#define WRAP_USB_BUS 15
+
+/* NDIS device must be 0, for compatability with old versions of
+ * ndiswrapper where device type for NDIS drivers is 0 */
+#define WRAP_NDIS_DEVICE 0
+#define WRAP_USB_DEVICE 1
+#define WRAP_BLUETOOTH_DEVICE1 2
+#define WRAP_BLUETOOTH_DEVICE2 3
+
+#define WRAP_DEVICE_BUS(dev, bus) ((dev) << 8 | (bus))
+#define WRAP_BUS(dev_bus) ((dev_bus) & 0x000FF)
+#define WRAP_DEVICE(dev_bus) ((dev_bus) >> 8)
+
+#define MAX_DRIVER_NAME_LEN 32
+#define MAX_VERSION_STRING_LEN 64
+#define MAX_SETTING_NAME_LEN 128
+#define MAX_SETTING_VALUE_LEN 256
+
+#define MAX_DRIVER_PE_IMAGES 4
+#define MAX_DRIVER_BIN_FILES 5
+#define MAX_DEVICE_SETTINGS 512
+
+#define MAX_ALLOCATED_URBS 15
+
+#define DEV_ANY_ID -1
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTRSEP "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MACSTR "%02x%02x%02x%02x%02x%02x"
+#define MACINTADR(a) (int*)&((a)[0]), (int*)&((a)[1]), (int*)&((a)[2]), \
+ (int*)&((a)[3]), (int*)&((a)[4]), (int*)&((a)[5])
+
+#ifdef __KERNEL__
+/* DEBUG macros */
+
+#define MSG(level, fmt, ...) \
+ printk(level "ndiswrapper (%s:%d): " fmt "\n", \
+ __func__, __LINE__ , ## __VA_ARGS__)
+
+#define WARNING(fmt, ...) MSG(KERN_WARNING, fmt, ## __VA_ARGS__)
+#define ERROR(fmt, ...) MSG(KERN_ERR, fmt , ## __VA_ARGS__)
+#define INFO(fmt, ...) MSG(KERN_INFO, fmt , ## __VA_ARGS__)
+#define TODO() WARNING("not fully implemented (yet)")
+
+#define TRACE(fmt, ...) do { } while (0)
+#define TRACE1(fmt, ...) do { } while (0)
+#define TRACE2(fmt, ...) do { } while (0)
+#define TRACE3(fmt, ...) do { } while (0)
+#define TRACE4(fmt, ...) do { } while (0)
+#define TRACE5(fmt, ...) do { } while (0)
+#define TRACE6(fmt, ...) do { } while (0)
+
+/* for a block of code */
+#define DBG_BLOCK(level) while (0)
+
+extern int debug;
+
+#if defined DEBUG
+#undef TRACE
+#define TRACE(level, fmt, ...) \
+do { \
+ if (debug >= level) \
+ printk(KERN_INFO "%s (%s:%d): " fmt "\n", DRIVER_NAME, \
+ __func__, __LINE__ , ## __VA_ARGS__); \
+} while (0)
+#undef DBG_BLOCK
+#define DBG_BLOCK(level) if (debug >= level)
+#endif
+
+#if defined(DEBUG) && DEBUG >= 1
+#undef TRACE1
+#define TRACE1(fmt, ...) TRACE(1, fmt , ## __VA_ARGS__)
+#endif
+
+#if defined(DEBUG) && DEBUG >= 2
+#undef TRACE2
+#define TRACE2(fmt, ...) TRACE(2, fmt , ## __VA_ARGS__)
+#endif
+
+#if defined(DEBUG) && DEBUG >= 3
+#undef TRACE3
+#define TRACE3(fmt, ...) TRACE(3, fmt , ## __VA_ARGS__)
+#endif
+
+#if defined(DEBUG) && DEBUG >= 4
+#undef TRACE4
+#define TRACE4(fmt, ...) TRACE(4, fmt , ## __VA_ARGS__)
+#endif
+
+#if defined(DEBUG) && DEBUG >= 5
+#undef TRACE5
+#define TRACE5(fmt, ...) TRACE(5, fmt , ## __VA_ARGS__)
+#endif
+
+#if defined(DEBUG) && DEBUG >= 6
+#undef TRACE6
+#define TRACE6(fmt, ...) TRACE(6, fmt , ## __VA_ARGS__)
+#endif
+
+#define ENTER1(fmt, ...) TRACE1("Enter " fmt , ## __VA_ARGS__)
+#define ENTER2(fmt, ...) TRACE2("Enter " fmt , ## __VA_ARGS__)
+#define ENTER3(fmt, ...) TRACE3("Enter " fmt , ## __VA_ARGS__)
+#define ENTER4(fmt, ...) TRACE4("Enter " fmt , ## __VA_ARGS__)
+#define ENTER5(fmt, ...) TRACE5("Enter " fmt , ## __VA_ARGS__)
+#define ENTER6(fmt, ...) TRACE6("Enter " fmt , ## __VA_ARGS__)
+
+#define EXIT1(stmt) do { TRACE1("Exit"); stmt; } while(0)
+#define EXIT2(stmt) do { TRACE2("Exit"); stmt; } while(0)
+#define EXIT3(stmt) do { TRACE3("Exit"); stmt; } while(0)
+#define EXIT4(stmt) do { TRACE4("Exit"); stmt; } while(0)
+#define EXIT5(stmt) do { TRACE5("Exit"); stmt; } while(0)
+#define EXIT6(stmt) do { TRACE6("Exit"); stmt; } while(0)
+
+#if defined(USB_DEBUG)
+#define USBTRACE TRACE1
+#define USBENTER ENTER1
+#define USBEXIT EXIT1
+#else
+#define USBTRACE(fmt, ...)
+#define USBENTER(fmt, ...)
+#define USBEXIT(stmt) stmt
+#endif
+
+#if defined(EVENT_DEBUG)
+#define EVENTTRACE TRACE1
+#define EVENTENTER ENTER1
+#define EVENTEXIT EXIT1
+#else
+#define EVENTTRACE(fmt, ...)
+#define EVENTENTER(fmt, ...)
+#define EVENTEXIT(stmt) stmt
+#endif
+
+#if defined(TIMER_DEBUG)
+#define TIMERTRACE TRACE1
+#define TIMERENTER ENTER1
+#define TIMEREXIT EXIT1
+#else
+#define TIMERTRACE(fmt, ...)
+#define TIMERENTER(fmt, ...)
+#define TIMEREXIT(stmt) stmt
+#endif
+
+#if defined(IO_DEBUG)
+#define IOTRACE TRACE1
+#define IOENTER ENTER1
+#define IOEXIT EXIT1
+#else
+#define IOTRACE(fmt, ...)
+#define IOENTER(fmt, ...)
+#define IOEXIT(stmt) stmt
+#endif
+
+#if defined(WORK_DEBUG)
+#define WORKTRACE TRACE1
+#define WORKENTER ENTER1
+#define WORKEXIT EXIT1
+#else
+#define WORKTRACE(fmt, ...)
+#define WORKENTER(fmt, ...)
+#define WORKEXIT(stmt) stmt
+#endif
+
+#ifdef DEBUG
+#define assert(expr) \
+do { \
+ if (!(expr)) { \
+ ERROR("assertion '%s' failed", #expr); \
+ dump_stack(); \
+ } \
+} while (0)
+#else
+#define assert(expr) do { } while (0)
+#endif
+
+#endif // __KERNEL__
+
+#endif // NDISWRAPPER_H
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ntoskernel.h"
+#include "ndis.h"
+#include "usb.h"
+#include "pnp.h"
+#include "loader.h"
+#include "ntoskernel_exports.h"
+
+/* MDLs describe a range of virtual address with an array of physical
+ * pages right after the header. For different ranges of virtual
+ * addresses, the number of entries of physical pages may be different
+ * (depending on number of entries required). If we want to allocate
+ * MDLs from a pool, the size has to be constant. So we assume that
+ * maximum range used by a driver is MDL_CACHE_PAGES; if a driver
+ * requests an MDL for a bigger region, we allocate it with kmalloc;
+ * otherwise, we allocate from the pool */
+
+#define MDL_CACHE_PAGES 3
+#define MDL_CACHE_SIZE (sizeof(struct mdl) + \
+ (sizeof(PFN_NUMBER) * MDL_CACHE_PAGES))
+struct wrap_mdl {
+ struct nt_list list;
+ struct mdl mdl[0];
+};
+
+/* everything here is for all drivers/devices - not per driver/device */
+static spinlock_t dispatcher_lock;
+spinlock_t ntoskernel_lock;
+static void *mdl_cache;
+static struct nt_list wrap_mdl_list;
+
+static work_struct_t kdpc_work;
+static void kdpc_worker(worker_param_t dummy);
+
+static struct nt_list kdpc_list;
+static spinlock_t kdpc_list_lock;
+
+static struct nt_list callback_objects;
+
+struct nt_list object_list;
+
+struct bus_driver {
+ struct nt_list list;
+ char name[MAX_DRIVER_NAME_LEN];
+ struct driver_object drv_obj;
+};
+
+static struct nt_list bus_driver_list;
+
+static work_struct_t ntos_work;
+static struct nt_list ntos_work_list;
+static spinlock_t ntos_work_lock;
+static void ntos_work_worker(worker_param_t dummy);
+static struct nt_thread *ntos_worker_thread;
+spinlock_t irp_cancel_lock;
+static NT_SPIN_LOCK nt_list_lock;
+static struct nt_slist wrap_timer_slist;
+
+/* compute ticks (100ns) since 1601 until when system booted into
+ * wrap_ticks_to_boot */
+u64 wrap_ticks_to_boot;
+
+#if defined(CONFIG_X86_64)
+static struct timer_list shared_data_timer;
+struct kuser_shared_data kuser_shared_data;
+static void update_user_shared_data_proc(unsigned long data);
+#endif
+
+WIN_SYMBOL_MAP("KeTickCount", &jiffies)
+
+WIN_SYMBOL_MAP("NlsMbCodePageTag", FALSE)
+
+workqueue_struct_t *ntos_wq;
+
+#ifdef WRAP_PREEMPT
+DEFINE_PER_CPU(irql_info_t, irql_info);
+#endif
+
+#if defined(CONFIG_X86_64)
+static void update_user_shared_data_proc(unsigned long data)
+{
+ /* timer is supposed to be scheduled every 10ms, but bigger
+ * intervals seem to work (tried upto 50ms) */
+ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601();
+ *((ULONG64 *)&kuser_shared_data.interrupt_time) =
+ jiffies * TICKSPERSEC / HZ;
+ *((ULONG64 *)&kuser_shared_data.tick) = jiffies;
+
+ mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30));
+}
+#endif
+
+void *allocate_object(ULONG size, enum common_object_type type,
+ struct unicode_string *name)
+{
+ struct common_object_header *hdr;
+ void *body;
+
+ /* we pad header as prefix to body */
+ hdr = ExAllocatePoolWithTag(NonPagedPool, OBJECT_SIZE(size), 0);
+ if (!hdr) {
+ WARNING("couldn't allocate memory");
+ return NULL;
+ }
+ memset(hdr, 0, OBJECT_SIZE(size));
+ if (name) {
+ hdr->name.buf = ExAllocatePoolWithTag(NonPagedPool,
+ name->max_length, 0);
+ if (!hdr->name.buf) {
+ ExFreePool(hdr);
+ return NULL;
+ }
+ memcpy(hdr->name.buf, name->buf, name->max_length);
+ hdr->name.length = name->length;
+ hdr->name.max_length = name->max_length;
+ }
+ hdr->type = type;
+ hdr->ref_count = 1;
+ spin_lock_bh(&ntoskernel_lock);
+ /* threads are looked up often (in KeWaitForXXX), so optimize
+ * for fast lookups of threads */
+ if (type == OBJECT_TYPE_NT_THREAD)
+ InsertHeadList(&object_list, &hdr->list);
+ else
+ InsertTailList(&object_list, &hdr->list);
+ spin_unlock_bh(&ntoskernel_lock);
+ body = HEADER_TO_OBJECT(hdr);
+ TRACE3("allocated hdr: %p, body: %p", hdr, body);
+ return body;
+}
+
+void free_object(void *object)
+{
+ struct common_object_header *hdr;
+
+ hdr = OBJECT_TO_HEADER(object);
+ spin_lock_bh(&ntoskernel_lock);
+ RemoveEntryList(&hdr->list);
+ spin_unlock_bh(&ntoskernel_lock);
+ TRACE3("freed hdr: %p, body: %p", hdr, object);
+ if (hdr->name.buf)
+ ExFreePool(hdr->name.buf);
+ ExFreePool(hdr);
+}
+
+static int add_bus_driver(const char *name)
+{
+ struct bus_driver *bus_driver;
+
+ bus_driver = kzalloc(sizeof(*bus_driver), GFP_KERNEL);
+ if (!bus_driver) {
+ ERROR("couldn't allocate memory");
+ return -ENOMEM;
+ }
+ strncpy(bus_driver->name, name, sizeof(bus_driver->name));
+ bus_driver->name[sizeof(bus_driver->name)-1] = 0;
+ spin_lock_bh(&ntoskernel_lock);
+ InsertTailList(&bus_driver_list, &bus_driver->list);
+ spin_unlock_bh(&ntoskernel_lock);
+ TRACE1("bus driver %s is at %p", name, &bus_driver->drv_obj);
+ return STATUS_SUCCESS;
+}
+
+struct driver_object *find_bus_driver(const char *name)
+{
+ struct bus_driver *bus_driver;
+ struct driver_object *drv_obj;
+
+ spin_lock_bh(&ntoskernel_lock);
+ drv_obj = NULL;
+ nt_list_for_each_entry(bus_driver, &bus_driver_list, list) {
+ if (strcmp(bus_driver->name, name) == 0) {
+ drv_obj = &bus_driver->drv_obj;
+ break;
+ }
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ return drv_obj;
+}
+
+wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertHeadList,3)
+ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock)
+{
+ struct nt_list *first;
+ unsigned long flags;
+
+ ENTER5("head = %p, entry = %p", head, entry);
+ nt_spin_lock_irqsave(lock, flags);
+ first = InsertHeadList(head, entry);
+ nt_spin_unlock_irqrestore(lock, flags);
+ TRACE5("head = %p, old = %p", head, first);
+ return first;
+}
+
+wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertHeadList,3)
+ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock)
+{
+ ENTER5("%p", head);
+ return ExfInterlockedInsertHeadList(head, entry, lock);
+}
+
+wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertTailList,3)
+ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock)
+{
+ struct nt_list *last;
+ unsigned long flags;
+
+ ENTER5("head = %p, entry = %p", head, entry);
+ nt_spin_lock_irqsave(lock, flags);
+ last = InsertTailList(head, entry);
+ nt_spin_unlock_irqrestore(lock, flags);
+ TRACE5("head = %p, old = %p", head, last);
+ return last;
+}
+
+wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertTailList,3)
+ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock)
+{
+ ENTER5("%p", head);
+ return ExfInterlockedInsertTailList(head, entry, lock);
+}
+
+wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveHeadList,2)
+ (struct nt_list *head, NT_SPIN_LOCK *lock)
+{
+ struct nt_list *ret;
+ unsigned long flags;
+
+ ENTER5("head = %p", head);
+ nt_spin_lock_irqsave(lock, flags);
+ ret = RemoveHeadList(head);
+ nt_spin_unlock_irqrestore(lock, flags);
+ TRACE5("head = %p, ret = %p", head, ret);
+ return ret;
+}
+
+wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveHeadList,2)
+ (struct nt_list *head, NT_SPIN_LOCK *lock)
+{
+ ENTER5("%p", head);
+ return ExfInterlockedRemoveHeadList(head, lock);
+}
+
+wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveTailList,2)
+ (struct nt_list *head, NT_SPIN_LOCK *lock)
+{
+ struct nt_list *ret;
+ unsigned long flags;
+
+ ENTER5("head = %p", head);
+ nt_spin_lock_irqsave(lock, flags);
+ ret = RemoveTailList(head);
+ nt_spin_unlock_irqrestore(lock, flags);
+ TRACE5("head = %p, ret = %p", head, ret);
+ return ret;
+}
+
+wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveTailList,2)
+ (struct nt_list *head, NT_SPIN_LOCK *lock)
+{
+ ENTER5("%p", head);
+ return ExfInterlockedRemoveTailList(head, lock);
+}
+
+wfastcall void WIN_FUNC(InitializeSListHead,1)
+ (nt_slist_header *head)
+{
+ memset(head, 0, sizeof(*head));
+}
+
+wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPushEntrySList,3)
+ (nt_slist_header *head, struct nt_slist *entry, NT_SPIN_LOCK *lock)
+{
+ struct nt_slist *ret;
+
+ ret = PushEntrySList(head, entry, lock);
+ return ret;
+}
+
+wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPushEntrySList,2)
+ (nt_slist_header *head, struct nt_slist *entry)
+{
+ struct nt_slist *ret;
+
+ ret = PushEntrySList(head, entry, &nt_list_lock);
+ return ret;
+}
+
+wfastcall struct nt_slist *WIN_FUNC(InterlockedPushEntrySList,2)
+ (nt_slist_header *head, struct nt_slist *entry)
+{
+ struct nt_slist *ret;
+
+ ret = PushEntrySList(head, entry, &nt_list_lock);
+ return ret;
+}
+
+wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPopEntrySList,2)
+ (nt_slist_header *head, NT_SPIN_LOCK *lock)
+{
+ struct nt_slist *ret;
+
+ ret = PopEntrySList(head, lock);
+ return ret;
+}
+
+wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPopEntrySList,1)
+ (nt_slist_header *head)
+{
+ struct nt_slist *ret;
+
+ ret = PopEntrySList(head, &nt_list_lock);
+ return ret;
+}
+
+wfastcall struct nt_slist *WIN_FUNC(InterlockedPopEntrySList,1)
+ (nt_slist_header *head)
+{
+ struct nt_slist *ret;
+
+ ret = PopEntrySList(head, &nt_list_lock);
+ return ret;
+}
+
+wstdcall USHORT WIN_FUNC(ExQueryDepthSList,1)
+ (nt_slist_header *head)
+{
+ USHORT depth;
+ ENTER5("%p", head);
+ depth = head->depth;
+ TRACE5("%d, %p", depth, head->next);
+ return depth;
+}
+
+wfastcall LONG WIN_FUNC(InterlockedIncrement,1)
+ (LONG volatile *val)
+{
+ return post_atomic_add(*val, 1);
+}
+
+wfastcall LONG WIN_FUNC(InterlockedDecrement,1)
+ (LONG volatile *val)
+{
+ return post_atomic_add(*val, -1);
+}
+
+wfastcall LONG WIN_FUNC(InterlockedExchange,2)
+ (LONG volatile *target, LONG val)
+{
+ return xchg(target, val);
+}
+
+wfastcall LONG WIN_FUNC(InterlockedCompareExchange,3)
+ (LONG volatile *dest, LONG new, LONG old)
+{
+ return cmpxchg(dest, old, new);
+}
+
+wfastcall void WIN_FUNC(ExInterlockedAddLargeStatistic,2)
+ (LARGE_INTEGER volatile *plint, ULONG n)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+#ifdef CONFIG_X86_64
+ __asm__ __volatile__(
+ "\n"
+ LOCK_PREFIX "add %1, %0\n\t"
+ : "+m" (*plint)
+ : "r" (n));
+#else
+ __asm__ __volatile__(
+ "1:\t"
+ " movl %1, %%ebx\n\t"
+ " movl %%edx, %%ecx\n\t"
+ " addl %%eax, %%ebx\n\t"
+ " adcl $0, %%ecx\n\t"
+ LOCK_PREFIX "cmpxchg8b %0\n\t"
+ " jnz 1b\n\t"
+ : "+m" (*plint)
+ : "m" (n), "A" (*plint)
+ : "ebx", "ecx");
+#endif
+ local_irq_restore(flags);
+}
+
+static void initialize_object(struct dispatcher_header *dh, enum dh_type type,
+ int state)
+{
+ memset(dh, 0, sizeof(*dh));
+ set_object_type(dh, type);
+ dh->signal_state = state;
+ InitializeListHead(&dh->wait_blocks);
+}
+
+static void timer_proc(unsigned long data)
+{
+ struct wrap_timer *wrap_timer = (struct wrap_timer *)data;
+ struct nt_timer *nt_timer;
+ struct kdpc *kdpc;
+
+ nt_timer = wrap_timer->nt_timer;
+ TIMERENTER("%p(%p), %lu", wrap_timer, nt_timer, jiffies);
+#ifdef TIMER_DEBUG
+ BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC);
+ BUG_ON(nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC);
+#endif
+ KeSetEvent((struct nt_event *)nt_timer, 0, FALSE);
+ if (wrap_timer->repeat)
+ mod_timer(&wrap_timer->timer, jiffies + wrap_timer->repeat);
+ kdpc = nt_timer->kdpc;
+ if (kdpc)
+ queue_kdpc(kdpc);
+ TIMEREXIT(return);
+}
+
+void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type,
+ struct ndis_mp_block *nmb)
+{
+ struct wrap_timer *wrap_timer;
+
+ /* TODO: if a timer is initialized more than once, we allocate
+ * memory for wrap_timer more than once for the same nt_timer,
+ * wasting memory. We can check if nt_timer->wrap_timer_magic is
+ * set and not allocate, but it is not guaranteed always to be
+ * safe */
+ TIMERENTER("%p", nt_timer);
+ /* we allocate memory for wrap_timer behind driver's back and
+ * there is no NDIS/DDK function where this memory can be
+ * freed, so we use slack_kmalloc so it gets freed when driver
+ * is unloaded */
+ if (nmb)
+ wrap_timer = kmalloc(sizeof(*wrap_timer), irql_gfp());
+ else
+ wrap_timer = slack_kmalloc(sizeof(*wrap_timer));
+ if (!wrap_timer) {
+ ERROR("couldn't allocate memory for timer");
+ return;
+ }
+
+ memset(wrap_timer, 0, sizeof(*wrap_timer));
+ init_timer(&wrap_timer->timer);
+ wrap_timer->timer.data = (unsigned long)wrap_timer;
+ wrap_timer->timer.function = timer_proc;
+ wrap_timer->nt_timer = nt_timer;
+#ifdef TIMER_DEBUG
+ wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC;
+#endif
+ nt_timer->wrap_timer = wrap_timer;
+ nt_timer->kdpc = NULL;
+ initialize_object(&nt_timer->dh, type, 0);
+ nt_timer->wrap_timer_magic = WRAP_TIMER_MAGIC;
+ TIMERTRACE("timer %p (%p)", wrap_timer, nt_timer);
+ spin_lock_bh(&ntoskernel_lock);
+ if (nmb) {
+ wrap_timer->slist.next = nmb->wnd->wrap_timer_slist.next;
+ nmb->wnd->wrap_timer_slist.next = &wrap_timer->slist;
+ } else {
+ wrap_timer->slist.next = wrap_timer_slist.next;
+ wrap_timer_slist.next = &wrap_timer->slist;
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ TIMEREXIT(return);
+}
+
+wstdcall void WIN_FUNC(KeInitializeTimerEx,2)
+ (struct nt_timer *nt_timer, enum timer_type type)
+{
+ TIMERENTER("%p", nt_timer);
+ wrap_init_timer(nt_timer, type, NULL);
+}
+
+wstdcall void WIN_FUNC(KeInitializeTimer,1)
+ (struct nt_timer *nt_timer)
+{
+ TIMERENTER("%p", nt_timer);
+ wrap_init_timer(nt_timer, NotificationTimer, NULL);
+}
+
+/* expires and repeat are in HZ */
+BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz,
+ unsigned long repeat_hz, struct kdpc *kdpc)
+{
+ struct wrap_timer *wrap_timer;
+
+ TIMERENTER("%p, %lu, %lu, %p, %lu",
+ nt_timer, expires_hz, repeat_hz, kdpc, jiffies);
+
+ wrap_timer = nt_timer->wrap_timer;
+ TIMERTRACE("%p", wrap_timer);
+#ifdef TIMER_DEBUG
+ if (wrap_timer->nt_timer != nt_timer)
+ WARNING("bad timers: %p, %p, %p", wrap_timer, nt_timer,
+ wrap_timer->nt_timer);
+ if (nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) {
+ WARNING("buggy Windows timer didn't initialize timer %p",
+ nt_timer);
+ return FALSE;
+ }
+ if (wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) {
+ WARNING("timer %p is not initialized (%lx)?",
+ wrap_timer, wrap_timer->wrap_timer_magic);
+ wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC;
+ }
+#endif
+ KeClearEvent((struct nt_event *)nt_timer);
+ nt_timer->kdpc = kdpc;
+ wrap_timer->repeat = repeat_hz;
+ if (mod_timer(&wrap_timer->timer, jiffies + expires_hz))
+ TIMEREXIT(return TRUE);
+ else
+ TIMEREXIT(return FALSE);
+}
+
+wstdcall BOOLEAN WIN_FUNC(KeSetTimerEx,4)
+ (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks,
+ LONG period_ms, struct kdpc *kdpc)
+{
+ unsigned long expires_hz, repeat_hz;
+
+ TIMERENTER("%p, %Ld, %d", nt_timer, duetime_ticks, period_ms);
+ expires_hz = SYSTEM_TIME_TO_HZ(duetime_ticks);
+ repeat_hz = MSEC_TO_HZ(period_ms);
+ return wrap_set_timer(nt_timer, expires_hz, repeat_hz, kdpc);
+}
+
+wstdcall BOOLEAN WIN_FUNC(KeSetTimer,3)
+ (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks,
+ struct kdpc *kdpc)
+{
+ TIMERENTER("%p, %Ld, %p", nt_timer, duetime_ticks, kdpc);
+ return KeSetTimerEx(nt_timer, duetime_ticks, 0, kdpc);
+}
+
+wstdcall BOOLEAN WIN_FUNC(KeCancelTimer,1)
+ (struct nt_timer *nt_timer)
+{
+ struct wrap_timer *wrap_timer;
+ int ret;
+
+ TIMERENTER("%p", nt_timer);
+ wrap_timer = nt_timer->wrap_timer;
+ if (!wrap_timer) {
+ ERROR("invalid wrap_timer");
+ return TRUE;
+ }
+#ifdef TIMER_DEBUG
+ BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC);
+#endif
+ /* disable timer before deleting so if it is periodic timer, it
+ * won't be re-armed after deleting */
+ wrap_timer->repeat = 0;
+ ret = del_timer_sync(&wrap_timer->timer);
+ /* the documentation for KeCancelTimer suggests the DPC is
+ * deqeued, but actually DPC is left to run */
+ if (ret)
+ TIMEREXIT(return TRUE);
+ else
+ TIMEREXIT(return FALSE);
+}
+
+wstdcall BOOLEAN WIN_FUNC(KeReadStateTimer,1)
+ (struct nt_timer *nt_timer)
+{
+ if (nt_timer->dh.signal_state)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+wstdcall void WIN_FUNC(KeInitializeDpc,3)
+ (struct kdpc *kdpc, void *func, void *ctx)
+{
+ ENTER3("%p, %p, %p", kdpc, func, ctx);
+ memset(kdpc, 0, sizeof(*kdpc));
+ kdpc->func = func;
+ kdpc->ctx = ctx;
+ InitializeListHead(&kdpc->list);
+}
+
+static void kdpc_worker(worker_param_t dummy)
+{
+ struct nt_list *entry;
+ struct kdpc *kdpc;
+ unsigned long flags;
+ KIRQL irql;
+
+ WORKENTER("");
+ irql = raise_irql(DISPATCH_LEVEL);
+ while (1) {
+ spin_lock_irqsave(&kdpc_list_lock, flags);
+ entry = RemoveHeadList(&kdpc_list);
+ if (entry) {
+ kdpc = container_of(entry, struct kdpc, list);
+ assert(kdpc->queued);
+ kdpc->queued = 0;
+ } else
+ kdpc = NULL;
+ spin_unlock_irqrestore(&kdpc_list_lock, flags);
+ if (!kdpc)
+ break;
+ WORKTRACE("%p, %p, %p, %p, %p", kdpc, kdpc->func, kdpc->ctx,
+ kdpc->arg1, kdpc->arg2);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ LIN2WIN4(kdpc->func, kdpc, kdpc->ctx, kdpc->arg1, kdpc->arg2);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ }
+ lower_irql(irql);
+ WORKEXIT(return);
+}
+
+wstdcall void WIN_FUNC(KeFlushQueuedDpcs,0)
+ (void)
+{
+ kdpc_worker(NULL);
+}
+
+BOOLEAN queue_kdpc(struct kdpc *kdpc)
+{
+ BOOLEAN ret;
+ unsigned long flags;
+
+ WORKENTER("%p", kdpc);
+ spin_lock_irqsave(&kdpc_list_lock, flags);
+ if (kdpc->queued)
+ ret = FALSE;
+ else {
+ if (unlikely(kdpc->importance == HighImportance))
+ InsertHeadList(&kdpc_list, &kdpc->list);
+ else
+ InsertTailList(&kdpc_list, &kdpc->list);
+ kdpc->queued = 1;
+ ret = TRUE;
+ }
+ spin_unlock_irqrestore(&kdpc_list_lock, flags);
+ if (ret == TRUE)
+ schedule_ntos_work(&kdpc_work);
+ WORKTRACE("%d", ret);
+ return ret;
+}
+
+BOOLEAN dequeue_kdpc(struct kdpc *kdpc)
+{
+ BOOLEAN ret;
+ unsigned long flags;
+
+ WORKENTER("%p", kdpc);
+ spin_lock_irqsave(&kdpc_list_lock, flags);
+ if (kdpc->queued) {
+ RemoveEntryList(&kdpc->list);
+ kdpc->queued = 0;
+ ret = TRUE;
+ } else
+ ret = FALSE;
+ spin_unlock_irqrestore(&kdpc_list_lock, flags);
+ WORKTRACE("%d", ret);
+ return ret;
+}
+
+wstdcall BOOLEAN WIN_FUNC(KeInsertQueueDpc,3)
+ (struct kdpc *kdpc, void *arg1, void *arg2)
+{
+ WORKENTER("%p, %p, %p", kdpc, arg1, arg2);
+ kdpc->arg1 = arg1;
+ kdpc->arg2 = arg2;
+ return queue_kdpc(kdpc);
+}
+
+wstdcall BOOLEAN WIN_FUNC(KeRemoveQueueDpc,1)
+ (struct kdpc *kdpc)
+{
+ return dequeue_kdpc(kdpc);
+}
+
+wstdcall void WIN_FUNC(KeSetImportanceDpc,2)
+ (struct kdpc *kdpc, enum kdpc_importance importance)
+{
+ kdpc->importance = importance;
+}
+
+static void ntos_work_worker(worker_param_t dummy)
+{
+ struct ntos_work_item *ntos_work_item;
+ struct nt_list *cur;
+
+ while (1) {
+ spin_lock_bh(&ntos_work_lock);
+ cur = RemoveHeadList(&ntos_work_list);
+ spin_unlock_bh(&ntos_work_lock);
+ if (!cur)
+ break;
+ ntos_work_item = container_of(cur, struct ntos_work_item, list);
+ WORKTRACE("%p: executing %p, %p, %p", current,
+ ntos_work_item->func, ntos_work_item->arg1,
+ ntos_work_item->arg2);
+ LIN2WIN2(ntos_work_item->func, ntos_work_item->arg1,
+ ntos_work_item->arg2);
+ kfree(ntos_work_item);
+ }
+ WORKEXIT(return);
+}
+
+int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2)
+{
+ struct ntos_work_item *ntos_work_item;
+
+ WORKENTER("adding work: %p, %p, %p", func, arg1, arg2);
+ ntos_work_item = kmalloc(sizeof(*ntos_work_item), irql_gfp());
+ if (!ntos_work_item) {
+ ERROR("couldn't allocate memory");
+ return -ENOMEM;
+ }
+ ntos_work_item->func = func;
+ ntos_work_item->arg1 = arg1;
+ ntos_work_item->arg2 = arg2;
+ spin_lock_bh(&ntos_work_lock);
+ InsertTailList(&ntos_work_list, &ntos_work_item->list);
+ spin_unlock_bh(&ntos_work_lock);
+ schedule_ntos_work(&ntos_work);
+ WORKEXIT(return 0);
+}
+
+wstdcall void WIN_FUNC(KeInitializeSpinLock,1)
+ (NT_SPIN_LOCK *lock)
+{
+ ENTER6("%p", lock);
+ nt_spin_lock_init(lock);
+}
+
+wstdcall void WIN_FUNC(KeAcquireSpinLock,2)
+ (NT_SPIN_LOCK *lock, KIRQL *irql)
+{
+ ENTER6("%p", lock);
+ *irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL);
+}
+
+wstdcall void WIN_FUNC(KeReleaseSpinLock,2)
+ (NT_SPIN_LOCK *lock, KIRQL oldirql)
+{
+ ENTER6("%p", lock);
+ nt_spin_unlock_irql(lock, oldirql);
+}
+
+wstdcall void WIN_FUNC(KeAcquireSpinLockAtDpcLevel,1)
+ (NT_SPIN_LOCK *lock)
+{
+ ENTER6("%p", lock);
+ nt_spin_lock(lock);
+}
+
+wstdcall void WIN_FUNC(KeReleaseSpinLockFromDpcLevel,1)
+ (NT_SPIN_LOCK *lock)
+{
+ ENTER6("%p", lock);
+ nt_spin_unlock(lock);
+}
+
+wstdcall void WIN_FUNC(KeRaiseIrql,2)
+ (KIRQL newirql, KIRQL *oldirql)
+{
+ ENTER6("%d", newirql);
+ *oldirql = raise_irql(newirql);
+}
+
+wstdcall KIRQL WIN_FUNC(KeRaiseIrqlToDpcLevel,0)
+ (void)
+{
+ return raise_irql(DISPATCH_LEVEL);
+}
+
+wstdcall void WIN_FUNC(KeLowerIrql,1)
+ (KIRQL irql)
+{
+ ENTER6("%d", irql);
+ lower_irql(irql);
+}
+
+wstdcall KIRQL WIN_FUNC(KeAcquireSpinLockRaiseToDpc,1)
+ (NT_SPIN_LOCK *lock)
+{
+ ENTER6("%p", lock);
+ return nt_spin_lock_irql(lock, DISPATCH_LEVEL);
+}
+
+#undef ExAllocatePoolWithTag
+
+wstdcall void *WIN_FUNC(ExAllocatePoolWithTag,3)
+ (enum pool_type pool_type, SIZE_T size, ULONG tag)
+{
+ void *addr;
+
+ ENTER4("pool_type: %d, size: %lu, tag: 0x%x", pool_type, size, tag);
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ if (size < PAGE_SIZE)
+ addr = kmalloc(size, irql_gfp());
+ else {
+ if (irql_gfp() & GFP_ATOMIC) {
+ addr = __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM,
+ PAGE_KERNEL);
+ TRACE1("%p, %lu", addr, size);
+ } else {
+ addr = vmalloc(size);
+ TRACE1("%p, %lu", addr, size);
+ }
+ }
+ DBG_BLOCK(1) {
+ if (addr)
+ TRACE4("addr: %p, %lu", addr, size);
+ else
+ TRACE1("failed: %lu", size);
+ }
+ return addr;
+}
+WIN_FUNC_DECL(ExAllocatePoolWithTag,3)
+
+wstdcall void WIN_FUNC(ExFreePoolWithTag,2)
+ (void *addr, ULONG tag)
+{
+ TRACE4("%p", addr);
+ if ((unsigned long)addr < VMALLOC_START ||
+ (unsigned long)addr >= VMALLOC_END)
+ kfree(addr);
+ else
+ vfree(addr);
+
+ EXIT4(return);
+}
+
+wstdcall void WIN_FUNC(ExFreePool,1)
+ (void *addr)
+{
+ ExFreePoolWithTag(addr, 0);
+}
+WIN_FUNC_DECL(ExFreePool,1)
+
+wstdcall void WIN_FUNC(ExInitializeNPagedLookasideList,7)
+ (struct npaged_lookaside_list *lookaside,
+ LOOKASIDE_ALLOC_FUNC *alloc_func, LOOKASIDE_FREE_FUNC *free_func,
+ ULONG flags, SIZE_T size, ULONG tag, USHORT depth)
+{
+ ENTER3("lookaside: %p, size: %lu, flags: %u, head: %p, "
+ "alloc: %p, free: %p", lookaside, size, flags,
+ lookaside, alloc_func, free_func);
+
+ memset(lookaside, 0, sizeof(*lookaside));
+
+ lookaside->size = size;
+ lookaside->tag = tag;
+ lookaside->depth = 4;
+ lookaside->maxdepth = 256;
+ lookaside->pool_type = NonPagedPool;
+
+ if (alloc_func)
+ lookaside->alloc_func = alloc_func;
+ else
+ lookaside->alloc_func = WIN_FUNC_PTR(ExAllocatePoolWithTag,3);
+ if (free_func)
+ lookaside->free_func = free_func;
+ else
+ lookaside->free_func = WIN_FUNC_PTR(ExFreePool,1);
+
+#ifndef CONFIG_X86_64
+ nt_spin_lock_init(&lookaside->obsolete);
+#endif
+ EXIT3(return);
+}
+
+wstdcall void WIN_FUNC(ExDeleteNPagedLookasideList,1)
+ (struct npaged_lookaside_list *lookaside)
+{
+ struct nt_slist *entry;
+
+ ENTER3("lookaside = %p", lookaside);
+ while ((entry = ExpInterlockedPopEntrySList(&lookaside->head)))
+ LIN2WIN1(lookaside->free_func, entry);
+ EXIT3(return);
+}
+
+#if defined(ALLOC_DEBUG) && ALLOC_DEBUG > 1
+#define ExAllocatePoolWithTag(pool_type, size, tag) \
+ wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__)
+#endif
+
+wstdcall NTSTATUS WIN_FUNC(ExCreateCallback,4)
+ (struct callback_object **object, struct object_attributes *attributes,
+ BOOLEAN create, BOOLEAN allow_multiple_callbacks)
+{
+ struct callback_object *obj;
+
+ ENTER2("");
+ spin_lock_bh(&ntoskernel_lock);
+ nt_list_for_each_entry(obj, &callback_objects, callback_funcs) {
+ if (obj->attributes == attributes) {
+ spin_unlock_bh(&ntoskernel_lock);
+ *object = obj;
+ return STATUS_SUCCESS;
+ }
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ obj = allocate_object(sizeof(struct callback_object),
+ OBJECT_TYPE_CALLBACK, NULL);
+ if (!obj)
+ EXIT2(return STATUS_INSUFFICIENT_RESOURCES);
+ InitializeListHead(&obj->callback_funcs);
+ nt_spin_lock_init(&obj->lock);
+ obj->allow_multiple_callbacks = allow_multiple_callbacks;
+ obj->attributes = attributes;
+ *object = obj;
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall void *WIN_FUNC(ExRegisterCallback,3)
+ (struct callback_object *object, PCALLBACK_FUNCTION func, void *context)
+{
+ struct callback_func *callback;
+ KIRQL irql;
+
+ ENTER2("");
+ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL);
+ if (object->allow_multiple_callbacks == FALSE &&
+ !IsListEmpty(&object->callback_funcs)) {
+ nt_spin_unlock_irql(&object->lock, irql);
+ EXIT2(return NULL);
+ }
+ nt_spin_unlock_irql(&object->lock, irql);
+ callback = kmalloc(sizeof(*callback), GFP_KERNEL);
+ if (!callback) {
+ ERROR("couldn't allocate memory");
+ return NULL;
+ }
+ callback->func = func;
+ callback->context = context;
+ callback->object = object;
+ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL);
+ InsertTailList(&object->callback_funcs, &callback->list);
+ nt_spin_unlock_irql(&object->lock, irql);
+ EXIT2(return callback);
+}
+
+wstdcall void WIN_FUNC(ExUnregisterCallback,1)
+ (struct callback_func *callback)
+{
+ struct callback_object *object;
+ KIRQL irql;
+
+ ENTER3("%p", callback);
+ if (!callback)
+ return;
+ object = callback->object;
+ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL);
+ RemoveEntryList(&callback->list);
+ nt_spin_unlock_irql(&object->lock, irql);
+ kfree(callback);
+ return;
+}
+
+wstdcall void WIN_FUNC(ExNotifyCallback,3)
+ (struct callback_object *object, void *arg1, void *arg2)
+{
+ struct callback_func *callback;
+ KIRQL irql;
+
+ ENTER3("%p", object);
+ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL);
+ nt_list_for_each_entry(callback, &object->callback_funcs, list) {
+ LIN2WIN3(callback->func, callback->context, arg1, arg2);
+ }
+ nt_spin_unlock_irql(&object->lock, irql);
+ return;
+}
+
+/* check and set signaled state; should be called with dispatcher_lock held */
+/* @grab indicates if the event should be grabbed or checked
+ * - note that a semaphore may stay in signaled state for multiple
+ * 'grabs' if the count is > 1 */
+static int grab_object(struct dispatcher_header *dh,
+ struct task_struct *thread, int grab)
+{
+ EVENTTRACE("%p, %p, %d, %d", dh, thread, grab, dh->signal_state);
+ if (unlikely(is_mutex_object(dh))) {
+ struct nt_mutex *nt_mutex;
+ nt_mutex = container_of(dh, struct nt_mutex, dh);
+ EVENTTRACE("%p, %p, %d, %p, %d", nt_mutex,
+ nt_mutex->owner_thread, dh->signal_state,
+ thread, grab);
+ /* either no thread owns the mutex or this thread owns
+ * it */
+ assert(dh->signal_state == 1 && nt_mutex->owner_thread == NULL);
+ assert(dh->signal_state < 1 && nt_mutex->owner_thread != NULL);
+ if ((dh->signal_state == 1 && nt_mutex->owner_thread == NULL) ||
+ nt_mutex->owner_thread == thread) {
+ if (grab) {
+ dh->signal_state--;
+ nt_mutex->owner_thread = thread;
+ }
+ EVENTEXIT(return 1);
+ }
+ } else if (dh->signal_state > 0) {
+ /* to grab, decrement signal_state for synchronization
+ * or semaphore objects */
+ if (grab && (is_synch_object(dh) || is_semaphore_object(dh)))
+ dh->signal_state--;
+ EVENTEXIT(return 1);
+ }
+ EVENTEXIT(return 0);
+}
+
+/* this function should be called holding dispatcher_lock */
+static void object_signalled(struct dispatcher_header *dh)
+{
+ struct nt_list *cur, *next;
+ struct wait_block *wb;
+
+ EVENTENTER("%p", dh);
+ nt_list_for_each_safe(cur, next, &dh->wait_blocks) {
+ wb = container_of(cur, struct wait_block, list);
+ assert(wb->thread != NULL);
+ assert(wb->object == NULL);
+ if (!grab_object(dh, wb->thread, 1))
+ continue;
+ EVENTTRACE("%p (%p): waking %p", dh, wb, wb->thread);
+ RemoveEntryList(cur);
+ wb->object = dh;
+ *(wb->wait_done) = 1;
+ wake_up_process(wb->thread);
+ }
+ EVENTEXIT(return);
+}
+
+wstdcall NTSTATUS WIN_FUNC(KeWaitForMultipleObjects,8)
+ (ULONG count, void *object[], enum wait_type wait_type,
+ KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode,
+ BOOLEAN alertable, LARGE_INTEGER *timeout,
+ struct wait_block *wait_block_array)
+{
+ int i, res = 0, wait_count, wait_done;
+ typeof(jiffies) wait_hz = 0;
+ struct wait_block *wb, wb_array[THREAD_WAIT_OBJECTS];
+ struct dispatcher_header *dh;
+
+ EVENTENTER("%p, %d, %u, %p", current, count, wait_type, timeout);
+
+ if (count > MAX_WAIT_OBJECTS ||
+ (count > THREAD_WAIT_OBJECTS && wait_block_array == NULL))
+ EVENTEXIT(return STATUS_INVALID_PARAMETER);
+
+ if (wait_block_array == NULL)
+ wb = wb_array;
+ else
+ wb = wait_block_array;
+
+ /* If *timeout == 0: In the case of WaitAny, if an object can
+ * be grabbed (object is in signaled state), grab and
+ * return. In the case of WaitAll, we have to first make sure
+ * all objects can be grabbed. If any/some of them can't be
+ * grabbed, either we return STATUS_TIMEOUT or wait for them,
+ * depending on how to satisfy wait. If all of them can be
+ * grabbed, we will grab them in the next loop below */
+
+ spin_lock_bh(&dispatcher_lock);
+ for (i = wait_count = 0; i < count; i++) {
+ dh = object[i];
+ EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state);
+ /* wait_type == 1 for WaitAny, 0 for WaitAll */
+ if (grab_object(dh, current, wait_type)) {
+ if (wait_type == WaitAny) {
+ spin_unlock_bh(&dispatcher_lock);
+ EVENTEXIT(return STATUS_WAIT_0 + i);
+ }
+ } else {
+ EVENTTRACE("%p: wait for %p", current, dh);
+ wait_count++;
+ }
+ }
+
+ if (timeout && *timeout == 0 && wait_count) {
+ spin_unlock_bh(&dispatcher_lock);
+ EVENTEXIT(return STATUS_TIMEOUT);
+ }
+
+ /* get the list of objects the thread needs to wait on and add
+ * the thread on the wait list for each such object */
+ /* if *timeout == 0, this step will grab all the objects */
+ wait_done = 0;
+ for (i = 0; i < count; i++) {
+ dh = object[i];
+ EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state);
+ wb[i].object = NULL;
+ if (grab_object(dh, current, 1)) {
+ EVENTTRACE("%p: no wait for %p (%d)",
+ current, dh, dh->signal_state);
+ /* mark that we are not waiting on this object */
+ wb[i].thread = NULL;
+ } else {
+ wb[i].wait_done = &wait_done;
+ wb[i].thread = current;
+ EVENTTRACE("%p: wait for %p", current, dh);
+ InsertTailList(&dh->wait_blocks, &wb[i].list);
+ }
+ }
+ spin_unlock_bh(&dispatcher_lock);
+ if (wait_count == 0)
+ EVENTEXIT(return STATUS_SUCCESS);
+
+ assert(timeout == NULL || *timeout != 0);
+ if (timeout == NULL)
+ wait_hz = 0;
+ else
+ wait_hz = SYSTEM_TIME_TO_HZ(*timeout);
+
+ DBG_BLOCK(2) {
+ KIRQL irql = current_irql();
+ if (irql >= DISPATCH_LEVEL) {
+ TRACE2("wait in atomic context: %lu, %d, %ld",
+ wait_hz, in_atomic(), in_interrupt());
+ }
+ }
+ assert_irql(_irql_ < DISPATCH_LEVEL);
+ EVENTTRACE("%p: sleep for %ld on %p", current, wait_hz, &wait_done);
+ /* we don't honor 'alertable' - according to decription for
+ * this, even if waiting in non-alertable state, thread may be
+ * alerted in some circumstances */
+ while (wait_count) {
+ res = wait_condition(wait_done, wait_hz, TASK_INTERRUPTIBLE);
+ spin_lock_bh(&dispatcher_lock);
+ EVENTTRACE("%p woke up: %d, %d", current, res, wait_done);
+ /* the event may have been set by the time
+ * wrap_wait_event returned and spinlock obtained, so
+ * don't rely on value of 'res' - check event status */
+ if (!wait_done) {
+ assert(res <= 0);
+ /* timed out or interrupted; remove from wait list */
+ for (i = 0; i < count; i++) {
+ if (!wb[i].thread)
+ continue;
+ EVENTTRACE("%p: timedout, dequeue %p (%p)",
+ current, object[i], wb[i].object);
+ assert(wb[i].object == NULL);
+ RemoveEntryList(&wb[i].list);
+ }
+ spin_unlock_bh(&dispatcher_lock);
+ if (res < 0)
+ EVENTEXIT(return STATUS_ALERTED);
+ else
+ EVENTEXIT(return STATUS_TIMEOUT);
+ }
+ assert(res > 0);
+ /* woken because object(s) signalled */
+ for (i = 0; wait_count && i < count; i++) {
+ if (!wb[i].thread || !wb[i].object)
+ continue;
+ DBG_BLOCK(1) {
+ if (wb[i].object != object[i]) {
+ EVENTTRACE("oops %p != %p",
+ wb[i].object, object[i]);
+ continue;
+ }
+ }
+ wait_count--;
+ if (wait_type == WaitAny) {
+ int j;
+ /* done; remove from rest of wait list */
+ for (j = i + 1; j < count; j++) {
+ if (wb[j].thread && !wb[j].object)
+ RemoveEntryList(&wb[j].list);
+ }
+ spin_unlock_bh(&dispatcher_lock);
+ EVENTEXIT(return STATUS_WAIT_0 + i);
+ }
+ }
+ wait_done = 0;
+ spin_unlock_bh(&dispatcher_lock);
+ if (wait_count == 0)
+ EVENTEXIT(return STATUS_SUCCESS);
+
+ /* this thread is still waiting for more objects, so
+ * let it wait for remaining time and those objects */
+ if (timeout)
+ wait_hz = res;
+ else
+ wait_hz = 0;
+ }
+ /* should never reach here, but compiler wants return value */
+ ERROR("%p: wait_hz: %ld", current, wait_hz);
+ EVENTEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(KeWaitForSingleObject,5)
+ (void *object, KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode,
+ BOOLEAN alertable, LARGE_INTEGER *timeout)
+{
+ return KeWaitForMultipleObjects(1, &object, WaitAny, wait_reason,
+ wait_mode, alertable, timeout, NULL);
+}
+
+wstdcall void WIN_FUNC(KeInitializeEvent,3)
+ (struct nt_event *nt_event, enum event_type type, BOOLEAN state)
+{
+ EVENTENTER("event = %p, type = %d, state = %d", nt_event, type, state);
+ initialize_object(&nt_event->dh, type, state);
+ EVENTEXIT(return);
+}
+
+wstdcall LONG WIN_FUNC(KeSetEvent,3)
+ (struct nt_event *nt_event, KPRIORITY incr, BOOLEAN wait)
+{
+ LONG old_state;
+
+ EVENTENTER("%p, %d", nt_event, nt_event->dh.type);
+ if (wait == TRUE)
+ WARNING("wait = %d, not yet implemented", wait);
+ spin_lock_bh(&dispatcher_lock);
+ old_state = nt_event->dh.signal_state;
+ nt_event->dh.signal_state = 1;
+ if (old_state == 0)
+ object_signalled(&nt_event->dh);
+ spin_unlock_bh(&dispatcher_lock);
+ EVENTEXIT(return old_state);
+}
+
+wstdcall void WIN_FUNC(KeClearEvent,1)
+ (struct nt_event *nt_event)
+{
+ EVENTENTER("%p", nt_event);
+ nt_event->dh.signal_state = 0;
+ EVENTEXIT(return);
+}
+
+wstdcall LONG WIN_FUNC(KeResetEvent,1)
+ (struct nt_event *nt_event)
+{
+ LONG old_state;
+
+ EVENTENTER("%p", nt_event);
+ old_state = xchg(&nt_event->dh.signal_state, 0);
+ EVENTEXIT(return old_state);
+}
+
+wstdcall LONG WIN_FUNC(KeReadStateEvent,1)
+ (struct nt_event *nt_event)
+{
+ LONG state;
+
+ state = nt_event->dh.signal_state;
+ EVENTTRACE("%d", state);
+ return state;
+}
+
+wstdcall void WIN_FUNC(KeInitializeMutex,2)
+ (struct nt_mutex *mutex, ULONG level)
+{
+ EVENTENTER("%p", mutex);
+ initialize_object(&mutex->dh, MutexObject, 1);
+ mutex->dh.size = sizeof(*mutex);
+ InitializeListHead(&mutex->list);
+ mutex->abandoned = FALSE;
+ mutex->apc_disable = 1;
+ mutex->owner_thread = NULL;
+ EVENTEXIT(return);
+}
+
+wstdcall LONG WIN_FUNC(KeReleaseMutex,2)
+ (struct nt_mutex *mutex, BOOLEAN wait)
+{
+ LONG ret;
+ struct task_struct *thread;
+
+ EVENTENTER("%p, %d, %p", mutex, wait, current);
+ if (wait == TRUE)
+ WARNING("wait: %d", wait);
+ thread = current;
+ spin_lock_bh(&dispatcher_lock);
+ EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread,
+ mutex->dh.signal_state);
+ if ((mutex->owner_thread == thread) && (mutex->dh.signal_state <= 0)) {
+ ret = mutex->dh.signal_state++;
+ if (ret == 0) {
+ mutex->owner_thread = NULL;
+ object_signalled(&mutex->dh);
+ }
+ } else {
+ ret = STATUS_MUTANT_NOT_OWNED;
+ WARNING("invalid mutex: %p, %p, %p", mutex, mutex->owner_thread,
+ thread);
+ }
+ EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread,
+ mutex->dh.signal_state);
+ spin_unlock_bh(&dispatcher_lock);
+ EVENTEXIT(return ret);
+}
+
+wstdcall void WIN_FUNC(KeInitializeSemaphore,3)
+ (struct nt_semaphore *semaphore, LONG count, LONG limit)
+{
+ EVENTENTER("%p: %d", semaphore, count);
+ /* if limit > 1, we need to satisfy as many waits (until count
+ * becomes 0); so we keep decrementing count everytime a wait
+ * is satisified */
+ initialize_object(&semaphore->dh, SemaphoreObject, count);
+ semaphore->dh.size = sizeof(*semaphore);
+ semaphore->limit = limit;
+ EVENTEXIT(return);
+}
+
+wstdcall LONG WIN_FUNC(KeReleaseSemaphore,4)
+ (struct nt_semaphore *semaphore, KPRIORITY incr, LONG adjustment,
+ BOOLEAN wait)
+{
+ LONG ret;
+
+ EVENTENTER("%p", semaphore);
+ spin_lock_bh(&dispatcher_lock);
+ ret = semaphore->dh.signal_state;
+ assert(ret >= 0);
+ if (semaphore->dh.signal_state + adjustment <= semaphore->limit)
+ semaphore->dh.signal_state += adjustment;
+ else {
+ WARNING("releasing %d over limit %d", adjustment,
+ semaphore->limit);
+ semaphore->dh.signal_state = semaphore->limit;
+ }
+ if (semaphore->dh.signal_state > 0)
+ object_signalled(&semaphore->dh);
+ spin_unlock_bh(&dispatcher_lock);
+ EVENTEXIT(return ret);
+}
+
+wstdcall NTSTATUS WIN_FUNC(KeDelayExecutionThread,3)
+ (KPROCESSOR_MODE wait_mode, BOOLEAN alertable, LARGE_INTEGER *interval)
+{
+ int res;
+ long timeout;
+
+ if (wait_mode != 0)
+ ERROR("invalid wait_mode %d", wait_mode);
+
+ timeout = SYSTEM_TIME_TO_HZ(*interval);
+ EVENTTRACE("%p, %Ld, %ld", current, *interval, timeout);
+ if (timeout <= 0)
+ EVENTEXIT(return STATUS_SUCCESS);
+
+ if (alertable)
+ set_current_state(TASK_INTERRUPTIBLE);
+ else
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ res = schedule_timeout(timeout);
+ EVENTTRACE("%p, %d", current, res);
+ if (res == 0)
+ EVENTEXIT(return STATUS_SUCCESS);
+ else
+ EVENTEXIT(return STATUS_ALERTED);
+}
+
+wstdcall ULONGLONG WIN_FUNC(KeQueryInterruptTime,0)
+ (void)
+{
+ EXIT5(return jiffies * TICKSPERJIFFY);
+}
+
+wstdcall ULONG WIN_FUNC(KeQueryTimeIncrement,0)
+ (void)
+{
+ EXIT5(return TICKSPERSEC / HZ);
+}
+
+wstdcall void WIN_FUNC(KeQuerySystemTime,1)
+ (LARGE_INTEGER *time)
+{
+ *time = ticks_1601();
+ TRACE5("%Lu, %lu", *time, jiffies);
+}
+
+wstdcall void WIN_FUNC(KeQueryTickCount,1)
+ (LARGE_INTEGER *count)
+{
+ *count = jiffies;
+}
+
+wstdcall LARGE_INTEGER WIN_FUNC(KeQueryPerformanceCounter,1)
+ (LARGE_INTEGER *counter)
+{
+ if (counter)
+ *counter = HZ;
+ return jiffies;
+}
+
+wstdcall KAFFINITY WIN_FUNC(KeQueryActiveProcessors,0)
+ (void)
+{
+ int i, n;
+ KAFFINITY bits = 0;
+#ifdef num_online_cpus
+ n = num_online_cpus();
+#else
+ n = NR_CPUS;
+#endif
+ for (i = 0; i < n; i++)
+ bits = (bits << 1) | 1;
+ return bits;
+}
+
+struct nt_thread *get_current_nt_thread(void)
+{
+ struct task_struct *task = current;
+ struct nt_thread *thread;
+ struct common_object_header *header;
+
+ TRACE6("task: %p", task);
+ thread = NULL;
+ spin_lock_bh(&ntoskernel_lock);
+ nt_list_for_each_entry(header, &object_list, list) {
+ TRACE6("%p, %d", header, header->type);
+ if (header->type != OBJECT_TYPE_NT_THREAD)
+ break;
+ thread = HEADER_TO_OBJECT(header);
+ TRACE6("%p, %p", thread, thread->task);
+ if (thread->task == task)
+ break;
+ else
+ thread = NULL;
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ if (thread == NULL)
+ TRACE4("couldn't find thread for task %p, %d", task, task->pid);
+ TRACE6("%p", thread);
+ return thread;
+}
+
+static struct task_struct *get_nt_thread_task(struct nt_thread *thread)
+{
+ struct task_struct *task;
+ struct common_object_header *header;
+
+ TRACE6("%p", thread);
+ task = NULL;
+ spin_lock_bh(&ntoskernel_lock);
+ nt_list_for_each_entry(header, &object_list, list) {
+ TRACE6("%p, %d", header, header->type);
+ if (header->type != OBJECT_TYPE_NT_THREAD)
+ break;
+ if (thread == HEADER_TO_OBJECT(header)) {
+ task = thread->task;
+ break;
+ }
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ if (task == NULL)
+ TRACE2("%p: couldn't find task for %p", current, thread);
+ return task;
+}
+
+static struct nt_thread *create_nt_thread(struct task_struct *task)
+{
+ struct nt_thread *thread;
+ thread = allocate_object(sizeof(*thread), OBJECT_TYPE_NT_THREAD, NULL);
+ if (!thread) {
+ ERROR("couldn't allocate thread object");
+ EXIT2(return NULL);
+ }
+ thread->task = task;
+ if (task)
+ thread->pid = task->pid;
+ else
+ thread->pid = 0;
+ nt_spin_lock_init(&thread->lock);
+ InitializeListHead(&thread->irps);
+ initialize_object(&thread->dh, ThreadObject, 0);
+ thread->dh.size = sizeof(*thread);
+ thread->prio = LOW_PRIORITY;
+ return thread;
+}
+
+wstdcall struct nt_thread *WIN_FUNC(KeGetCurrentThread,0)
+ (void)
+{
+ struct nt_thread *thread = get_current_nt_thread();
+ TRACE2("%p, %p", thread, current);
+ return thread;
+}
+
+wstdcall KPRIORITY WIN_FUNC(KeQueryPriorityThread,1)
+ (struct nt_thread *thread)
+{
+ KPRIORITY prio;
+ struct task_struct *task;
+
+ TRACE2("%p", thread);
+#ifdef CONFIG_X86_64
+ /* sis163u driver for amd64 passes 0x1f from thread created by
+ * PsCreateSystemThread - no idea what is 0x1f */
+ if (thread == (void *)0x1f)
+ thread = get_current_nt_thread();
+#endif
+ if (!thread) {
+ TRACE2("invalid thread");
+ EXIT2(return LOW_REALTIME_PRIORITY);
+ }
+ task = get_nt_thread_task(thread);
+ if (!task) {
+ TRACE2("couldn't find task for thread: %p", thread);
+ EXIT2(return LOW_REALTIME_PRIORITY);
+ }
+
+ prio = thread->prio;
+
+ TRACE2("%d", prio);
+ return prio;
+}
+
+wstdcall KPRIORITY WIN_FUNC(KeSetPriorityThread,2)
+ (struct nt_thread *thread, KPRIORITY prio)
+{
+ KPRIORITY old_prio;
+ struct task_struct *task;
+
+ TRACE2("thread: %p, priority = %u", thread, prio);
+#ifdef CONFIG_X86_64
+ if (thread == (void *)0x1f)
+ thread = get_current_nt_thread();
+#endif
+ if (!thread) {
+ TRACE2("invalid thread");
+ EXIT2(return LOW_REALTIME_PRIORITY);
+ }
+ task = get_nt_thread_task(thread);
+ if (!task) {
+ TRACE2("couldn't find task for thread: %p", thread);
+ EXIT2(return LOW_REALTIME_PRIORITY);
+ }
+
+ old_prio = thread->prio;
+ thread->prio = prio;
+
+ TRACE2("%d, %d", old_prio, thread->prio);
+ return old_prio;
+}
+
+struct thread_trampoline {
+ void (*func)(void *) wstdcall;
+ void *ctx;
+ struct nt_thread *thread;
+ struct completion started;
+};
+
+static int ntdriver_thread(void *data)
+{
+ struct thread_trampoline *thread_tramp = data;
+ /* yes, a tramp! */
+ typeof(thread_tramp->func) func = thread_tramp->func;
+ typeof(thread_tramp->ctx) ctx = thread_tramp->ctx;
+
+ thread_tramp->thread->task = current;
+ thread_tramp->thread->pid = current->pid;
+ TRACE2("thread: %p, task: %p (%d)", thread_tramp->thread,
+ current, current->pid);
+ complete(&thread_tramp->started);
+
+#ifdef PF_NOFREEZE
+ current->flags |= PF_NOFREEZE;
+#endif
+ strncpy(current->comm, "ntdriver", sizeof(current->comm));
+ current->comm[sizeof(current->comm)-1] = 0;
+ LIN2WIN1(func, ctx);
+ ERROR("task: %p", current);
+ return 0;
+}
+
+wstdcall NTSTATUS WIN_FUNC(PsCreateSystemThread,7)
+ (void **handle, ULONG access, void *obj_attr, void *process,
+ void *client_id, void (*func)(void *) wstdcall, void *ctx)
+{
+ struct thread_trampoline thread_tramp;
+
+ ENTER2("handle = %p, access = %u, obj_attr = %p, process = %p, "
+ "client_id = %p, func = %p, context = %p", handle, access,
+ obj_attr, process, client_id, func, ctx);
+
+ thread_tramp.thread = create_nt_thread(NULL);
+ if (!thread_tramp.thread) {
+ ERROR("couldn't allocate thread object");
+ EXIT2(return STATUS_RESOURCES);
+ }
+ TRACE2("thread: %p", thread_tramp.thread);
+ thread_tramp.func = func;
+ thread_tramp.ctx = ctx;
+ init_completion(&thread_tramp.started);
+
+ thread_tramp.thread->task = kthread_run(ntdriver_thread,
+ &thread_tramp, "ntdriver");
+ if (IS_ERR(thread_tramp.thread->task)) {
+ free_object(thread_tramp.thread);
+ EXIT2(return STATUS_FAILURE);
+ }
+ TRACE2("created task: %p", thread_tramp.thread->task);
+
+ wait_for_completion(&thread_tramp.started);
+ *handle = OBJECT_TO_HEADER(thread_tramp.thread);
+ TRACE2("created thread: %p, %p", thread_tramp.thread, *handle);
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(PsTerminateSystemThread,1)
+ (NTSTATUS status)
+{
+ struct nt_thread *thread;
+
+ TRACE2("%p, %08X", current, status);
+ thread = get_current_nt_thread();
+ TRACE2("%p", thread);
+ if (thread) {
+ KeSetEvent((struct nt_event *)&thread->dh, 0, FALSE);
+ while (1) {
+ struct nt_list *ent;
+ struct irp *irp;
+ KIRQL irql;
+ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL);
+ ent = RemoveHeadList(&thread->irps);
+ nt_spin_unlock_irql(&thread->lock, irql);
+ if (!ent)
+ break;
+ irp = container_of(ent, struct irp, thread_list);
+ IOTRACE("%p", irp);
+ IoCancelIrp(irp);
+ }
+ /* the driver may later query this status with
+ * ZwQueryInformationThread */
+ thread->status = status;
+ } else
+ ERROR("couldn't find thread for task: %p", current);
+
+ complete_and_exit(NULL, status);
+ ERROR("oops: %p, %d", thread->task, thread->pid);
+ return STATUS_FAILURE;
+}
+
+wstdcall BOOLEAN WIN_FUNC(KeRemoveEntryDeviceQueue,2)
+ (struct kdevice_queue *dev_queue, struct kdevice_queue_entry *entry)
+{
+ struct kdevice_queue_entry *e;
+ KIRQL irql;
+
+ irql = nt_spin_lock_irql(&dev_queue->lock, DISPATCH_LEVEL);
+ nt_list_for_each_entry(e, &dev_queue->list, list) {
+ if (e == entry) {
+ RemoveEntryList(&e->list);
+ nt_spin_unlock_irql(&dev_queue->lock, irql);
+ return TRUE;
+ }
+ }
+ nt_spin_unlock_irql(&dev_queue->lock, irql);
+ return FALSE;
+}
+
+wstdcall BOOLEAN WIN_FUNC(KeSynchronizeExecution,3)
+ (struct kinterrupt *interrupt, PKSYNCHRONIZE_ROUTINE synch_routine,
+ void *ctx)
+{
+ BOOLEAN ret;
+ unsigned long flags;
+
+ nt_spin_lock_irqsave(interrupt->actual_lock, flags);
+ ret = LIN2WIN1(synch_routine, ctx);
+ nt_spin_unlock_irqrestore(interrupt->actual_lock, flags);
+ TRACE6("%d", ret);
+ return ret;
+}
+
+wstdcall void *WIN_FUNC(MmAllocateContiguousMemorySpecifyCache,5)
+ (SIZE_T size, PHYSICAL_ADDRESS lowest, PHYSICAL_ADDRESS highest,
+ PHYSICAL_ADDRESS boundary, enum memory_caching_type cache_type)
+{
+ void *addr;
+ gfp_t flags;
+
+ ENTER2("%lu, 0x%lx, 0x%lx, 0x%lx, %d", size, (long)lowest,
+ (long)highest, (long)boundary, cache_type);
+ flags = irql_gfp();
+ addr = wrap_get_free_pages(flags, size);
+ TRACE2("%p, %lu, 0x%x", addr, size, flags);
+ if (addr && ((virt_to_phys(addr) + size) <= highest))
+ EXIT2(return addr);
+#ifdef CONFIG_X86_64
+ /* GFP_DMA is really only 16MB even on x86-64, but there is no
+ * other zone available */
+ if (highest <= DMA_BIT_MASK(31))
+ flags |= __GFP_DMA;
+ else if (highest <= DMA_BIT_MASK(32))
+ flags |= __GFP_DMA32;
+#else
+ if (highest <= DMA_BIT_MASK(24))
+ flags |= __GFP_DMA;
+ else if (highest > DMA_BIT_MASK(30))
+ flags |= __GFP_HIGHMEM;
+#endif
+ addr = wrap_get_free_pages(flags, size);
+ TRACE2("%p, %lu, 0x%x", addr, size, flags);
+ return addr;
+}
+
+wstdcall void WIN_FUNC(MmFreeContiguousMemorySpecifyCache,3)
+ (void *base, SIZE_T size, enum memory_caching_type cache_type)
+{
+ TRACE2("%p, %lu", base, size);
+ free_pages((unsigned long)base, get_order(size));
+}
+
+wstdcall PHYSICAL_ADDRESS WIN_FUNC(MmGetPhysicalAddress,1)
+ (void *base)
+{
+ unsigned long phy = virt_to_phys(base);
+ TRACE2("%p, %p", base, (void *)phy);
+ return phy;
+}
+
+/* Atheros card with pciid 168C:0014 calls this function with 0xf0000
+ * and 0xf6ef0 address, and then check for things that seem to be
+ * related to ACPI: "_SM_" and "_DMI_". This may be the hack they do
+ * to check if this card is installed in IBM thinkpads; we can
+ * probably get this device to work if we create a buffer with the
+ * strings as required by the driver and return virtual address for
+ * that address instead */
+wstdcall void __iomem *WIN_FUNC(MmMapIoSpace,3)
+ (PHYSICAL_ADDRESS phys_addr, SIZE_T size,
+ enum memory_caching_type cache)
+{
+ void __iomem *virt;
+ ENTER1("cache type: %d", cache);
+ if (cache == MmCached)
+ virt = ioremap(phys_addr, size);
+ else
+ virt = ioremap_nocache(phys_addr, size);
+ TRACE1("%Lx, %lu, %p", phys_addr, size, virt);
+ return virt;
+}
+
+wstdcall void WIN_FUNC(MmUnmapIoSpace,2)
+ (void __iomem *addr, SIZE_T size)
+{
+ ENTER1("%p, %lu", addr, size);
+ iounmap(addr);
+ return;
+}
+
+wstdcall ULONG WIN_FUNC(MmSizeOfMdl,2)
+ (void *base, ULONG length)
+{
+ return sizeof(struct mdl) +
+ (sizeof(PFN_NUMBER) * SPAN_PAGES(base, length));
+}
+
+struct mdl *allocate_init_mdl(void *virt, ULONG length)
+{
+ struct wrap_mdl *wrap_mdl;
+ struct mdl *mdl;
+ int mdl_size = MmSizeOfMdl(virt, length);
+
+ if (mdl_size <= MDL_CACHE_SIZE) {
+ wrap_mdl = kmem_cache_alloc(mdl_cache, irql_gfp());
+ if (!wrap_mdl)
+ return NULL;
+ spin_lock_bh(&dispatcher_lock);
+ InsertHeadList(&wrap_mdl_list, &wrap_mdl->list);
+ spin_unlock_bh(&dispatcher_lock);
+ mdl = wrap_mdl->mdl;
+ TRACE3("allocated mdl from cache: %p(%p), %p(%d)",
+ wrap_mdl, mdl, virt, length);
+ memset(mdl, 0, MDL_CACHE_SIZE);
+ MmInitializeMdl(mdl, virt, length);
+ /* mark the MDL as allocated from cache pool so when
+ * it is freed, we free it back to the pool */
+ mdl->flags = MDL_ALLOCATED_FIXED_SIZE | MDL_CACHE_ALLOCATED;
+ } else {
+ wrap_mdl =
+ kmalloc(sizeof(*wrap_mdl) + mdl_size, irql_gfp());
+ if (!wrap_mdl)
+ return NULL;
+ mdl = wrap_mdl->mdl;
+ TRACE3("allocated mdl from memory: %p(%p), %p(%d)",
+ wrap_mdl, mdl, virt, length);
+ spin_lock_bh(&dispatcher_lock);
+ InsertHeadList(&wrap_mdl_list, &wrap_mdl->list);
+ spin_unlock_bh(&dispatcher_lock);
+ memset(mdl, 0, mdl_size);
+ MmInitializeMdl(mdl, virt, length);
+ mdl->flags = MDL_ALLOCATED_FIXED_SIZE;
+ }
+ return mdl;
+}
+
+void free_mdl(struct mdl *mdl)
+{
+ /* A driver may allocate Mdl with NdisAllocateBuffer and free
+ * with IoFreeMdl (e.g., 64-bit Broadcom). Since we need to
+ * treat buffers allocated with Ndis calls differently, we
+ * must call NdisFreeBuffer if it is allocated with Ndis
+ * function. We set 'pool' field in Ndis functions. */
+ if (!mdl)
+ return;
+ if (mdl->pool)
+ NdisFreeBuffer(mdl);
+ else {
+ struct wrap_mdl *wrap_mdl = (struct wrap_mdl *)
+ ((char *)mdl - offsetof(struct wrap_mdl, mdl));
+ spin_lock_bh(&dispatcher_lock);
+ RemoveEntryList(&wrap_mdl->list);
+ spin_unlock_bh(&dispatcher_lock);
+
+ if (mdl->flags & MDL_CACHE_ALLOCATED) {
+ TRACE3("freeing mdl cache: %p, %p, %p",
+ wrap_mdl, mdl, mdl->mappedsystemva);
+ kmem_cache_free(mdl_cache, wrap_mdl);
+ } else {
+ TRACE3("freeing mdl: %p, %p, %p",
+ wrap_mdl, mdl, mdl->mappedsystemva);
+ kfree(wrap_mdl);
+ }
+ }
+ return;
+}
+
+wstdcall void WIN_FUNC(IoBuildPartialMdl,4)
+ (struct mdl *source, struct mdl *target, void *virt, ULONG length)
+{
+ MmInitializeMdl(target, virt, length);
+ target->flags |= MDL_PARTIAL;
+}
+
+wstdcall void WIN_FUNC(MmBuildMdlForNonPagedPool,1)
+ (struct mdl *mdl)
+{
+ PFN_NUMBER *mdl_pages;
+ int i, n;
+
+ ENTER4("%p", mdl);
+ /* already mapped */
+// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl);
+ mdl->flags |= MDL_SOURCE_IS_NONPAGED_POOL;
+ TRACE4("%p, %p, %p, %d, %d", mdl, mdl->mappedsystemva, mdl->startva,
+ mdl->byteoffset, mdl->bytecount);
+ n = SPAN_PAGES(MmGetSystemAddressForMdl(mdl), MmGetMdlByteCount(mdl));
+ if (n > MDL_CACHE_PAGES)
+ WARNING("%p, %d, %d", MmGetSystemAddressForMdl(mdl),
+ MmGetMdlByteCount(mdl), n);
+ mdl_pages = MmGetMdlPfnArray(mdl);
+ for (i = 0; i < n; i++)
+ mdl_pages[i] = (ULONG_PTR)mdl->startva + (i * PAGE_SIZE);
+ EXIT4(return);
+}
+
+wstdcall void *WIN_FUNC(MmMapLockedPages,2)
+ (struct mdl *mdl, KPROCESSOR_MODE access_mode)
+{
+ /* already mapped */
+// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl);
+ mdl->flags |= MDL_MAPPED_TO_SYSTEM_VA;
+ /* what is the need for MDL_PARTIAL_HAS_BEEN_MAPPED? */
+ if (mdl->flags & MDL_PARTIAL)
+ mdl->flags |= MDL_PARTIAL_HAS_BEEN_MAPPED;
+ return mdl->mappedsystemva;
+}
+
+wstdcall void *WIN_FUNC(MmMapLockedPagesSpecifyCache,6)
+ (struct mdl *mdl, KPROCESSOR_MODE access_mode,
+ enum memory_caching_type cache_type, void *base_address,
+ ULONG bug_check, enum mm_page_priority priority)
+{
+ return MmMapLockedPages(mdl, access_mode);
+}
+
+wstdcall void WIN_FUNC(MmUnmapLockedPages,2)
+ (void *base, struct mdl *mdl)
+{
+ mdl->flags &= ~MDL_MAPPED_TO_SYSTEM_VA;
+ return;
+}
+
+wstdcall void WIN_FUNC(MmProbeAndLockPages,3)
+ (struct mdl *mdl, KPROCESSOR_MODE access_mode,
+ enum lock_operation operation)
+{
+ /* already locked */
+ mdl->flags |= MDL_PAGES_LOCKED;
+ return;
+}
+
+wstdcall void WIN_FUNC(MmUnlockPages,1)
+ (struct mdl *mdl)
+{
+ mdl->flags &= ~MDL_PAGES_LOCKED;
+ return;
+}
+
+wstdcall BOOLEAN WIN_FUNC(MmIsAddressValid,1)
+ (void *virt_addr)
+{
+ if (virt_addr_valid(virt_addr))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+wstdcall void *WIN_FUNC(MmLockPagableDataSection,1)
+ (void *address)
+{
+ return address;
+}
+
+wstdcall void WIN_FUNC(MmUnlockPagableImageSection,1)
+ (void *handle)
+{
+ return;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ObReferenceObjectByHandle,6)
+ (void *handle, ACCESS_MASK desired_access, void *obj_type,
+ KPROCESSOR_MODE access_mode, void **object, void *handle_info)
+{
+ struct common_object_header *hdr;
+
+ TRACE2("%p", handle);
+ hdr = HANDLE_TO_HEADER(handle);
+ atomic_inc_var(hdr->ref_count);
+ *object = HEADER_TO_OBJECT(hdr);
+ TRACE2("%p, %p, %d, %p", hdr, object, hdr->ref_count, *object);
+ return STATUS_SUCCESS;
+}
+
+/* DDK doesn't say if return value should be before incrementing or
+ * after incrementing reference count, but according to #reactos
+ * devels, it should be return value after incrementing */
+wfastcall LONG WIN_FUNC(ObfReferenceObject,1)
+ (void *object)
+{
+ struct common_object_header *hdr;
+ LONG ret;
+
+ hdr = OBJECT_TO_HEADER(object);
+ ret = post_atomic_add(hdr->ref_count, 1);
+ TRACE2("%p, %d, %p", hdr, hdr->ref_count, object);
+ return ret;
+}
+
+static int dereference_object(void *object)
+{
+ struct common_object_header *hdr;
+ int ref_count;
+
+ ENTER2("object: %p", object);
+ hdr = OBJECT_TO_HEADER(object);
+ TRACE2("hdr: %p", hdr);
+ ref_count = post_atomic_add(hdr->ref_count, -1);
+ TRACE2("object: %p, %d", object, ref_count);
+ if (ref_count < 0)
+ ERROR("invalid object: %p (%d)", object, ref_count);
+ if (ref_count <= 0) {
+ free_object(object);
+ return 1;
+ } else
+ return 0;
+}
+
+wfastcall void WIN_FUNC(ObfDereferenceObject,1)
+ (void *object)
+{
+ TRACE2("%p", object);
+ dereference_object(object);
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwCreateFile,11)
+ (void **handle, ACCESS_MASK access_mask,
+ struct object_attributes *obj_attr, struct io_status_block *iosb,
+ LARGE_INTEGER *size, ULONG file_attr, ULONG share_access,
+ ULONG create_disposition, ULONG create_options, void *ea_buffer,
+ ULONG ea_length)
+{
+ struct common_object_header *coh;
+ struct file_object *fo;
+ struct ansi_string ansi;
+ struct wrap_bin_file *bin_file;
+ char *file_basename;
+ NTSTATUS status;
+
+ spin_lock_bh(&ntoskernel_lock);
+ nt_list_for_each_entry(coh, &object_list, list) {
+ if (coh->type != OBJECT_TYPE_FILE)
+ continue;
+ /* TODO: check if file is opened in shared mode */
+ if (!RtlCompareUnicodeString(&coh->name, obj_attr->name, TRUE)) {
+ fo = HEADER_TO_OBJECT(coh);
+ bin_file = fo->wrap_bin_file;
+ *handle = coh;
+ spin_unlock_bh(&ntoskernel_lock);
+ ObReferenceObject(fo);
+ iosb->status = FILE_OPENED;
+ iosb->info = bin_file->size;
+ EXIT2(return STATUS_SUCCESS);
+ }
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+
+ if (RtlUnicodeStringToAnsiString(&ansi, obj_attr->name, TRUE) !=
+ STATUS_SUCCESS)
+ EXIT2(return STATUS_INSUFFICIENT_RESOURCES);
+
+ file_basename = strrchr(ansi.buf, '\\');
+ if (file_basename)
+ file_basename++;
+ else
+ file_basename = ansi.buf;
+ TRACE2("file: '%s', '%s'", ansi.buf, file_basename);
+
+ fo = allocate_object(sizeof(struct file_object), OBJECT_TYPE_FILE,
+ obj_attr->name);
+ if (!fo) {
+ RtlFreeAnsiString(&ansi);
+ iosb->status = STATUS_INSUFFICIENT_RESOURCES;
+ iosb->info = 0;
+ EXIT2(return STATUS_FAILURE);
+ }
+ coh = OBJECT_TO_HEADER(fo);
+ bin_file = get_bin_file(file_basename);
+ if (bin_file) {
+ TRACE2("%s, %s", bin_file->name, file_basename);
+ fo->flags = FILE_OPENED;
+ } else if (access_mask & FILE_WRITE_DATA) {
+ bin_file = kzalloc(sizeof(*bin_file), GFP_KERNEL);
+ if (bin_file) {
+ strncpy(bin_file->name, file_basename,
+ sizeof(bin_file->name));
+ bin_file->name[sizeof(bin_file->name)-1] = 0;
+ bin_file->data = vmalloc(*size);
+ if (bin_file->data) {
+ memset(bin_file->data, 0, *size);
+ bin_file->size = *size;
+ fo->flags = FILE_CREATED;
+ } else {
+ kfree(bin_file);
+ bin_file = NULL;
+ }
+ }
+ } else
+ bin_file = NULL;
+
+ RtlFreeAnsiString(&ansi);
+ if (!bin_file) {
+ iosb->status = FILE_DOES_NOT_EXIST;
+ iosb->info = 0;
+ free_object(fo);
+ EXIT2(return STATUS_FAILURE);
+ }
+
+ fo->wrap_bin_file = bin_file;
+ fo->current_byte_offset = 0;
+ if (access_mask & FILE_READ_DATA)
+ fo->read_access = TRUE;
+ if (access_mask & FILE_WRITE_DATA)
+ fo->write_access = TRUE;
+ iosb->status = FILE_OPENED;
+ iosb->info = bin_file->size;
+ *handle = coh;
+ TRACE2("handle: %p", *handle);
+ status = STATUS_SUCCESS;
+ EXIT2(return status);
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwOpenFile,6)
+ (void **handle, ACCESS_MASK access_mask,
+ struct object_attributes *obj_attr, struct io_status_block *iosb,
+ ULONG share_access, ULONG open_options)
+{
+ LARGE_INTEGER size;
+ return ZwCreateFile(handle, access_mask, obj_attr, iosb, &size, 0,
+ share_access, 0, open_options, NULL, 0);
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwReadFile,9)
+ (void *handle, struct nt_event *event, void *apc_routine,
+ void *apc_context, struct io_status_block *iosb, void *buffer,
+ ULONG length, LARGE_INTEGER *byte_offset, ULONG *key)
+{
+ struct file_object *fo;
+ struct common_object_header *coh;
+ ULONG count;
+ size_t offset;
+ struct wrap_bin_file *file;
+
+ TRACE2("%p", handle);
+ coh = handle;
+ if (coh->type != OBJECT_TYPE_FILE) {
+ ERROR("handle %p is invalid: %d", handle, coh->type);
+ EXIT2(return STATUS_FAILURE);
+ }
+ fo = HANDLE_TO_OBJECT(coh);
+ file = fo->wrap_bin_file;
+ TRACE2("file: %s (%zu)", file->name, file->size);
+ spin_lock_bh(&ntoskernel_lock);
+ if (byte_offset)
+ offset = *byte_offset;
+ else
+ offset = fo->current_byte_offset;
+ count = min((size_t)length, file->size - offset);
+ TRACE2("count: %u, offset: %zu, length: %u", count, offset, length);
+ memcpy(buffer, ((void *)file->data) + offset, count);
+ fo->current_byte_offset = offset + count;
+ spin_unlock_bh(&ntoskernel_lock);
+ iosb->status = STATUS_SUCCESS;
+ iosb->info = count;
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwWriteFile,9)
+ (void *handle, struct nt_event *event, void *apc_routine,
+ void *apc_context, struct io_status_block *iosb, void *buffer,
+ ULONG length, LARGE_INTEGER *byte_offset, ULONG *key)
+{
+ struct file_object *fo;
+ struct common_object_header *coh;
+ struct wrap_bin_file *file;
+ unsigned long offset;
+
+ TRACE2("%p", handle);
+ coh = handle;
+ if (coh->type != OBJECT_TYPE_FILE) {
+ ERROR("handle %p is invalid: %d", handle, coh->type);
+ EXIT2(return STATUS_FAILURE);
+ }
+ fo = HANDLE_TO_OBJECT(coh);
+ file = fo->wrap_bin_file;
+ TRACE2("file: %zu, %u", file->size, length);
+ spin_lock_bh(&ntoskernel_lock);
+ if (byte_offset)
+ offset = *byte_offset;
+ else
+ offset = fo->current_byte_offset;
+ if (length + offset > file->size) {
+ WARNING("%lu, %u", length + offset, (unsigned int)file->size);
+ /* TODO: implement writing past end of current size */
+ iosb->status = STATUS_FAILURE;
+ iosb->info = 0;
+ } else {
+ memcpy(file->data + offset, buffer, length);
+ iosb->status = STATUS_SUCCESS;
+ iosb->info = length;
+ fo->current_byte_offset = offset + length;
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ EXIT2(return iosb->status);
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwClose,1)
+ (void *handle)
+{
+ struct common_object_header *coh;
+
+ TRACE2("%p", handle);
+ if (handle == NULL) {
+ TRACE1("");
+ EXIT2(return STATUS_SUCCESS);
+ }
+ coh = handle;
+ if (coh->type == OBJECT_TYPE_FILE) {
+ struct file_object *fo;
+ struct wrap_bin_file *bin_file;
+ typeof(fo->flags) flags;
+
+ fo = HANDLE_TO_OBJECT(handle);
+ flags = fo->flags;
+ bin_file = fo->wrap_bin_file;
+ if (dereference_object(fo)) {
+ if (flags == FILE_CREATED) {
+ vfree(bin_file->data);
+ kfree(bin_file);
+ } else
+ free_bin_file(bin_file);
+ }
+ } else if (coh->type == OBJECT_TYPE_NT_THREAD) {
+ struct nt_thread *thread = HANDLE_TO_OBJECT(handle);
+ TRACE2("thread: %p (%p)", thread, handle);
+ ObDereferenceObject(thread);
+ } else {
+ /* TODO: can we just dereference object here? */
+ WARNING("closing handle 0x%x not implemented", coh->type);
+ }
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwQueryInformationFile,5)
+ (void *handle, struct io_status_block *iosb, void *info,
+ ULONG length, enum file_info_class class)
+{
+ struct file_object *fo;
+ struct file_name_info *fni;
+ struct file_std_info *fsi;
+ struct wrap_bin_file *file;
+ struct common_object_header *coh;
+
+ ENTER2("%p", handle);
+ coh = handle;
+ if (coh->type != OBJECT_TYPE_FILE) {
+ ERROR("handle %p is invalid: %d", coh, coh->type);
+ EXIT2(return STATUS_FAILURE);
+ }
+ fo = HANDLE_TO_OBJECT(handle);
+ TRACE2("fo: %p, %d", fo, class);
+ switch (class) {
+ case FileNameInformation:
+ fni = info;
+ fni->length = min(length, (typeof(length))coh->name.length);
+ memcpy(fni->name, coh->name.buf, fni->length);
+ iosb->status = STATUS_SUCCESS;
+ iosb->info = fni->length;
+ break;
+ case FileStandardInformation:
+ fsi = info;
+ file = fo->wrap_bin_file;
+ fsi->alloc_size = file->size;
+ fsi->eof = file->size;
+ fsi->num_links = 1;
+ fsi->delete_pending = FALSE;
+ fsi->dir = FALSE;
+ iosb->status = STATUS_SUCCESS;
+ iosb->info = 0;
+ break;
+ default:
+ WARNING("type %d not implemented yet", class);
+ iosb->status = STATUS_FAILURE;
+ iosb->info = 0;
+ break;
+ }
+ EXIT2(return iosb->status);
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwOpenSection,3)
+ (void **handle, ACCESS_MASK access, struct object_attributes *obj_attrs)
+{
+ INFO("%p, 0x%x, %d", obj_attrs, obj_attrs->attributes, access);
+ TODO();
+ *handle = obj_attrs;
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwMapViewOfSection,10)
+ (void *secn_handle, void *process_handle, void **base_address,
+ ULONG zero_bits, LARGE_INTEGER *secn_offset, SIZE_T *view_size,
+ enum section_inherit inherit, ULONG alloc_type, ULONG protect)
+{
+ INFO("%p, %p, %p", secn_handle, process_handle, base_address);
+ TODO();
+ *base_address = (void *)0xdeadbeef;
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwUnmapViewOfSection,2)
+ (void *process_handle, void *base_address)
+{
+ INFO("%p, %p", process_handle, base_address);
+ TODO();
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwCreateKey,7)
+ (void **handle, ACCESS_MASK desired_access,
+ struct object_attributes *attr, ULONG title_index,
+ struct unicode_string *class, ULONG create_options,
+ ULONG *disposition)
+{
+ struct ansi_string ansi;
+ if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) ==
+ STATUS_SUCCESS) {
+ TRACE1("key: %s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ *handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwOpenKey,3)
+ (void **handle, ACCESS_MASK desired_access,
+ struct object_attributes *attr)
+{
+ struct ansi_string ansi;
+ if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) ==
+ STATUS_SUCCESS) {
+ TRACE1("key: %s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ *handle = NULL;
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwSetValueKey,6)
+ (void *handle, struct unicode_string *name, ULONG title_index,
+ ULONG type, void *data, ULONG data_size)
+{
+ struct ansi_string ansi;
+ if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) ==
+ STATUS_SUCCESS) {
+ TRACE1("key: %s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwQueryValueKey,6)
+ (void *handle, struct unicode_string *name,
+ enum key_value_information_class class, void *info,
+ ULONG length, ULONG *res_length)
+{
+ struct ansi_string ansi;
+ if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == STATUS_SUCCESS) {
+ TRACE1("key: %s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ TODO();
+ return STATUS_INVALID_PARAMETER;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwDeleteKey,1)
+ (void *handle)
+{
+ ENTER2("%p", handle);
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(ZwPowerInformation,4)
+ (INT info_level, void *in_buf, ULONG in_buf_len, void *out_buf,
+ ULONG out_buf_len)
+{
+ INFO("%d, %u, %u", info_level, in_buf_len, out_buf_len);
+ TODO();
+ return STATUS_ACCESS_DENIED;
+}
+
+wstdcall NTSTATUS WIN_FUNC(WmiSystemControl,4)
+ (struct wmilib_context *info, struct device_object *dev_obj,
+ struct irp *irp, void *irp_disposition)
+{
+ TODO();
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(WmiCompleteRequest,5)
+ (struct device_object *dev_obj, struct irp *irp, NTSTATUS status,
+ ULONG buffer_used, CCHAR priority_boost)
+{
+ TODO();
+ return STATUS_SUCCESS;
+}
+
+noregparm NTSTATUS WIN_FUNC(WmiTraceMessage,12)
+ (void *tracehandle, ULONG message_flags,
+ void *message_guid, USHORT message_no, ...)
+{
+ TODO();
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(WmiQueryTraceInformation,4)
+ (enum trace_information_class trace_info_class, void *trace_info,
+ ULONG *req_length, void *buf)
+{
+ TODO();
+ EXIT2(return STATUS_SUCCESS);
+}
+
+/* this function can't be wstdcall as it takes variable number of args */
+noregparm ULONG WIN_FUNC(DbgPrint,12)
+ (char *format, ...)
+{
+#ifdef DEBUG
+ va_list args;
+ static char buf[100];
+
+ va_start(args, format);
+ vsnprintf(buf, sizeof(buf), format, args);
+ printk(KERN_DEBUG "%s (%s): %s", DRIVER_NAME, __func__, buf);
+ va_end(args);
+#endif
+ return STATUS_SUCCESS;
+}
+
+wstdcall void WIN_FUNC(KeBugCheck,1)
+ (ULONG code)
+{
+ TODO();
+ return;
+}
+
+wstdcall void WIN_FUNC(KeBugCheckEx,5)
+ (ULONG code, ULONG_PTR param1, ULONG_PTR param2,
+ ULONG_PTR param3, ULONG_PTR param4)
+{
+ TODO();
+ return;
+}
+
+wstdcall void WIN_FUNC(ExSystemTimeToLocalTime,2)
+ (LARGE_INTEGER *system_time, LARGE_INTEGER *local_time)
+{
+ *local_time = *system_time;
+}
+
+wstdcall ULONG WIN_FUNC(ExSetTimerResolution,2)
+ (ULONG time, BOOLEAN set)
+{
+ /* why a driver should change system wide timer resolution is
+ * beyond me */
+ return time;
+}
+
+wstdcall void WIN_FUNC(DbgBreakPoint,0)
+ (void)
+{
+ TODO();
+}
+
+wstdcall void WIN_FUNC(_except_handler3,0)
+ (void)
+{
+ TODO();
+}
+
+wstdcall void WIN_FUNC(__C_specific_handler,0)
+ (void)
+{
+ TODO();
+}
+
+wstdcall void WIN_FUNC(_purecall,0)
+ (void)
+{
+ TODO();
+}
+
+wstdcall void WIN_FUNC(__chkstk,0)
+ (void)
+{
+ TODO();
+}
+
+struct worker_init_struct {
+ work_struct_t work;
+ struct completion completion;
+ struct nt_thread *nt_thread;
+};
+
+static void wrap_worker_init_func(worker_param_t param)
+{
+ struct worker_init_struct *worker_init_struct;
+
+ worker_init_struct =
+ worker_param_data(param, struct worker_init_struct, work);
+ TRACE1("%p", worker_init_struct);
+ worker_init_struct->nt_thread = create_nt_thread(current);
+ if (!worker_init_struct->nt_thread)
+ WARNING("couldn't create worker thread");
+ complete(&worker_init_struct->completion);
+}
+
+struct nt_thread *wrap_worker_init(workqueue_struct_t *wq)
+{
+ struct worker_init_struct worker_init_struct;
+
+ TRACE1("%p", &worker_init_struct);
+ init_completion(&worker_init_struct.completion);
+ initialize_work(&worker_init_struct.work, wrap_worker_init_func,
+ &worker_init_struct);
+ worker_init_struct.nt_thread = NULL;
+ if (wq)
+ queue_work(wq, &worker_init_struct.work);
+ else
+ schedule_work(&worker_init_struct.work);
+ wait_for_completion(&worker_init_struct.completion);
+ TRACE1("%p", worker_init_struct.nt_thread);
+ return worker_init_struct.nt_thread;
+}
+
+int ntoskernel_init(void)
+{
+ struct timeval now;
+
+ spin_lock_init(&dispatcher_lock);
+ spin_lock_init(&ntoskernel_lock);
+ spin_lock_init(&ntos_work_lock);
+ spin_lock_init(&kdpc_list_lock);
+ spin_lock_init(&irp_cancel_lock);
+ InitializeListHead(&wrap_mdl_list);
+ InitializeListHead(&kdpc_list);
+ InitializeListHead(&callback_objects);
+ InitializeListHead(&bus_driver_list);
+ InitializeListHead(&object_list);
+ InitializeListHead(&ntos_work_list);
+
+ nt_spin_lock_init(&nt_list_lock);
+
+ initialize_work(&kdpc_work, kdpc_worker, NULL);
+ initialize_work(&ntos_work, ntos_work_worker, NULL);
+ wrap_timer_slist.next = NULL;
+
+ do_gettimeofday(&now);
+ wrap_ticks_to_boot = TICKS_1601_TO_1970;
+ wrap_ticks_to_boot += (u64)now.tv_sec * TICKSPERSEC;
+ wrap_ticks_to_boot += now.tv_usec * 10;
+ wrap_ticks_to_boot -= jiffies * TICKSPERJIFFY;
+ TRACE2("%Lu", wrap_ticks_to_boot);
+
+#ifdef WRAP_PREEMPT
+ do {
+ int cpu;
+ for_each_possible_cpu(cpu) {
+ irql_info_t *info;
+ info = &per_cpu(irql_info, cpu);
+ mutex_init(&(info->lock));
+ info->task = NULL;
+ info->count = 0;
+ }
+ } while (0);
+#endif
+
+ ntos_wq = create_singlethread_workqueue("ntos_wq");
+ if (!ntos_wq) {
+ WARNING("couldn't create ntos_wq thread");
+ return -ENOMEM;
+ }
+ ntos_worker_thread = wrap_worker_init(ntos_wq);
+ TRACE1("%p", ntos_worker_thread);
+
+ if (add_bus_driver("PCI")
+#ifdef ENABLE_USB
+ || add_bus_driver("USB")
+#endif
+ ) {
+ ntoskernel_exit();
+ return -ENOMEM;
+ }
+ mdl_cache =
+ wrap_kmem_cache_create("wrap_mdl",
+ sizeof(struct wrap_mdl) + MDL_CACHE_SIZE,
+ 0, 0);
+ TRACE2("%p", mdl_cache);
+ if (!mdl_cache) {
+ ERROR("couldn't allocate MDL cache");
+ ntoskernel_exit();
+ return -ENOMEM;
+ }
+
+#if defined(CONFIG_X86_64)
+ memset(&kuser_shared_data, 0, sizeof(kuser_shared_data));
+ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601();
+ init_timer(&shared_data_timer);
+ shared_data_timer.function = update_user_shared_data_proc;
+ shared_data_timer.data = (unsigned long)0;
+#endif
+ return 0;
+}
+
+int ntoskernel_init_device(struct wrap_device *wd)
+{
+#if defined(CONFIG_X86_64)
+ if (kuser_shared_data.reserved1)
+ mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30));
+#endif
+ return 0;
+}
+
+void ntoskernel_exit_device(struct wrap_device *wd)
+{
+ ENTER2("");
+
+ KeFlushQueuedDpcs();
+ EXIT2(return);
+}
+
+void ntoskernel_exit(void)
+{
+ struct nt_list *cur;
+
+ ENTER2("");
+
+ /* free kernel (Ke) timers */
+ TRACE2("freeing timers");
+ while (1) {
+ struct wrap_timer *wrap_timer;
+ struct nt_slist *slist;
+
+ spin_lock_bh(&ntoskernel_lock);
+ if ((slist = wrap_timer_slist.next))
+ wrap_timer_slist.next = slist->next;
+ spin_unlock_bh(&ntoskernel_lock);
+ TIMERTRACE("%p", slist);
+ if (!slist)
+ break;
+ wrap_timer = container_of(slist, struct wrap_timer, slist);
+ if (del_timer_sync(&wrap_timer->timer))
+ WARNING("Buggy Windows driver left timer %p running",
+ wrap_timer->nt_timer);
+ memset(wrap_timer, 0, sizeof(*wrap_timer));
+ slack_kfree(wrap_timer);
+ }
+
+ TRACE2("freeing MDLs");
+ if (mdl_cache) {
+ spin_lock_bh(&ntoskernel_lock);
+ if (!IsListEmpty(&wrap_mdl_list))
+ ERROR("Windows driver didn't free all MDLs; "
+ "freeing them now");
+ while ((cur = RemoveHeadList(&wrap_mdl_list))) {
+ struct wrap_mdl *wrap_mdl;
+ wrap_mdl = container_of(cur, struct wrap_mdl, list);
+ if (wrap_mdl->mdl->flags & MDL_CACHE_ALLOCATED)
+ kmem_cache_free(mdl_cache, wrap_mdl);
+ else
+ kfree(wrap_mdl);
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ kmem_cache_destroy(mdl_cache);
+ mdl_cache = NULL;
+ }
+
+ TRACE2("freeing callbacks");
+ spin_lock_bh(&ntoskernel_lock);
+ while ((cur = RemoveHeadList(&callback_objects))) {
+ struct callback_object *object;
+ struct nt_list *ent;
+ object = container_of(cur, struct callback_object, list);
+ while ((ent = RemoveHeadList(&object->callback_funcs))) {
+ struct callback_func *f;
+ f = container_of(ent, struct callback_func, list);
+ kfree(f);
+ }
+ kfree(object);
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+
+ spin_lock_bh(&ntoskernel_lock);
+ while ((cur = RemoveHeadList(&bus_driver_list))) {
+ struct bus_driver *bus_driver;
+ bus_driver = container_of(cur, struct bus_driver, list);
+ /* TODO: make sure all all drivers are shutdown/removed */
+ kfree(bus_driver);
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+
+#if defined(CONFIG_X86_64)
+ del_timer_sync(&shared_data_timer);
+#endif
+ if (ntos_wq)
+ destroy_workqueue(ntos_wq);
+ TRACE1("%p", ntos_worker_thread);
+ if (ntos_worker_thread)
+ ObDereferenceObject(ntos_worker_thread);
+ ENTER2("freeing objects");
+ spin_lock_bh(&ntoskernel_lock);
+ while ((cur = RemoveHeadList(&object_list))) {
+ struct common_object_header *hdr;
+ hdr = container_of(cur, struct common_object_header, list);
+ if (hdr->type == OBJECT_TYPE_NT_THREAD)
+ TRACE1("object %p(%d) was not freed, freeing it now",
+ HEADER_TO_OBJECT(hdr), hdr->type);
+ else
+ WARNING("object %p(%d) was not freed, freeing it now",
+ HEADER_TO_OBJECT(hdr), hdr->type);
+ ExFreePool(hdr);
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+
+ EXIT2(return);
+}
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _NTOSKERNEL_H_
+#define _NTOSKERNEL_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/usb.h>
+#include <linux/spinlock.h>
+#include <asm/mman.h>
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <net/iw_handler.h>
+#include <linux/ethtool.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/highmem.h>
+#include <linux/percpu.h>
+#include <linux/kthread.h>
+#include <linux/workqueue.h>
+
+#if !defined(CONFIG_X86) && !defined(CONFIG_X86_64)
+#error "this module is for x86 or x86_64 architectures only"
+#endif
+
+/* Interrupt backwards compatibility stuff */
+#include <linux/interrupt.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+#ifndef IRQ_HANDLED
+#define IRQ_HANDLED
+#define IRQ_NONE
+#define irqreturn_t void
+#endif
+#endif /* Linux < 2.6.29 */
+
+/* pci functions in 2.6 kernels have problems allocating dma buffers,
+ * but seem to work fine with dma functions
+ */
+#include <asm/dma-mapping.h>
+
+#define PCI_DMA_ALLOC_COHERENT(pci_dev,size,dma_handle) \
+ dma_alloc_coherent(&pci_dev->dev,size,dma_handle, \
+ GFP_KERNEL | __GFP_REPEAT)
+#define PCI_DMA_FREE_COHERENT(pci_dev,size,cpu_addr,dma_handle) \
+ dma_free_coherent(&pci_dev->dev,size,cpu_addr,dma_handle)
+#define PCI_DMA_MAP_SINGLE(pci_dev,addr,size,direction) \
+ dma_map_single(&pci_dev->dev,addr,size,direction)
+#define PCI_DMA_UNMAP_SINGLE(pci_dev,dma_handle,size,direction) \
+ dma_unmap_single(&pci_dev->dev,dma_handle,size,direction)
+#define MAP_SG(pci_dev, sglist, nents, direction) \
+ dma_map_sg(&pci_dev->dev, sglist, nents, direction)
+#define UNMAP_SG(pci_dev, sglist, nents, direction) \
+ dma_unmap_sg(&pci_dev->dev, sglist, nents, direction)
+#define PCI_DMA_MAP_ERROR(dma_addr) dma_mapping_error(dma_addr)
+
+
+#if defined(CONFIG_NET_RADIO) && !defined(CONFIG_WIRELESS_EXT)
+#define CONFIG_WIRELESS_EXT
+#endif
+
+#define prepare_wait_condition(task, var, value) \
+do { \
+ var = value; \
+ task = current; \
+ barrier(); \
+} while (0)
+
+/* Wait in wait_state (e.g., TASK_INTERRUPTIBLE) for condition to
+ * become true; timeout is either jiffies (> 0) to wait or 0 to wait
+ * forever.
+ * When timeout == 0, return value is
+ * > 0 if condition becomes true, or
+ * < 0 if signal is pending on the thread.
+ * When timeout > 0, return value is
+ * > 0 if condition becomes true before timeout,
+ * < 0 if signal is pending on the thread before timeout, or
+ * 0 if timedout (condition may have become true at the same time)
+ */
+
+#define wait_condition(condition, timeout, wait_state) \
+({ \
+ long ret = timeout ? timeout : 1; \
+ while (1) { \
+ if (signal_pending(current)) { \
+ ret = -ERESTARTSYS; \
+ break; \
+ } \
+ set_current_state(wait_state); \
+ if (condition) { \
+ __set_current_state(TASK_RUNNING); \
+ break; \
+ } \
+ if (timeout) { \
+ ret = schedule_timeout(ret); \
+ if (!ret) \
+ break; \
+ } else \
+ schedule(); \
+ } \
+ ret; \
+})
+
+#ifdef WRAP_WQ
+
+struct workqueue_struct;
+
+struct workqueue_thread {
+ spinlock_t lock;
+ struct task_struct *task;
+ struct completion *completion;
+ char name[16];
+ int pid;
+ /* whether any work_structs pending? <0 implies quit */
+ s8 pending;
+ /* list of work_structs pending */
+ struct list_head work_list;
+};
+
+typedef struct workqueue_struct {
+ u8 singlethread;
+ u8 qon;
+ int num_cpus;
+ struct workqueue_thread threads[0];
+} workqueue_struct_t;
+
+typedef struct {
+ struct list_head list;
+ void (*func)(void *data);
+ void *data;
+ /* whether/on which thread scheduled */
+ struct workqueue_thread *thread;
+} work_struct_t;
+
+#define initialize_work(work, pfunc, pdata) \
+ do { \
+ (work)->func = (pfunc); \
+ (work)->data = (pdata); \
+ (work)->thread = NULL; \
+ } while (0)
+
+#undef create_singlethread_workqueue
+#define create_singlethread_workqueue(name) wrap_create_wq(name, 1, 0)
+#undef create_workqueue
+#define create_workqueue(name) wrap_create_wq(name, 0, 0)
+#undef destroy_workqueue
+#define destroy_workqueue wrap_destroy_wq
+#undef queue_work
+#define queue_work wrap_queue_work
+#undef flush_workqueue
+#define flush_workqueue wrap_flush_wq
+
+workqueue_struct_t *wrap_create_wq(const char *name, u8 singlethread, u8 freeze);
+void wrap_destroy_wq_on(workqueue_struct_t *workq, int cpu);
+void wrap_destroy_wq(workqueue_struct_t *workq);
+int wrap_queue_work_on(workqueue_struct_t *workq, work_struct_t *work,
+ int cpu);
+int wrap_queue_work(workqueue_struct_t *workq, work_struct_t *work);
+void wrap_cancel_work(work_struct_t *work);
+void wrap_flush_wq_on(workqueue_struct_t *workq, int cpu);
+void wrap_flush_wq(workqueue_struct_t *workq);
+typedef void *worker_param_t;
+#define worker_param_data(param, type, member) param
+
+#else // WRAP_WQ
+
+typedef struct workqueue_struct workqueue_struct_t;
+typedef struct work_struct work_struct_t;
+
+#if defined(INIT_WORK_NAR) || defined(INIT_DELAYED_WORK_DEFERRABLE)
+#define initialize_work(work, func, data) INIT_WORK(work, func)
+typedef struct work_struct *worker_param_t;
+#define worker_param_data(param, type, member) \
+ container_of(param, type, member)
+#else
+#define initialize_work(work, func, data) INIT_WORK(work, func, data)
+typedef void *worker_param_t;
+#define worker_param_data(param, type, member) param
+#endif // INIT_WORK_NAR
+
+#endif // WRAP_WQ
+
+struct nt_thread *wrap_worker_init(workqueue_struct_t *wq);
+
+#ifdef module_param
+#define WRAP_MODULE_PARM_INT(name, perm) module_param(name, int, perm)
+#define WRAP_MODULE_PARM_STRING(name, perm) module_param(name, charp, perm)
+#else
+#define WRAP_MODULE_PARM_INT(name, perm) MODULE_PARM(name, "i")
+#define WRAP_MODULE_PARM_STRING(name, perm) MODULE_PARM(name, "s")
+#endif
+
+#ifndef LOCK_PREFIX
+#ifdef LOCK
+#define LOCK_PREFIX LOCK
+#else
+#ifdef CONFIG_SMP
+#define LOCK_PREFIX "lock ; "
+#else
+#define LOCK_PREFIX ""
+#endif
+#endif
+#endif
+
+#ifndef NETDEV_TX_OK
+#define NETDEV_TX_OK 0
+#endif
+
+#ifndef NETDEV_TX_BUSY
+#define NETDEV_TX_BUSY 1
+#endif
+
+#ifndef CHECKSUM_HW
+#define CHECKSUM_HW CHECKSUM_PARTIAL
+#endif
+
+#ifndef offset_in_page
+#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
+#endif
+
+#ifndef PMSG_SUSPEND
+#ifdef PM_SUSPEND
+/* this is not correct - the value of PM_SUSPEND is different from
+ * PMSG_SUSPEND, but ndiswrapper doesn't care about the value when
+ * suspending */
+#define PMSG_SUSPEND PM_SUSPEND
+#define PSMG_ON PM_ON
+#else
+typedef u32 pm_message_t;
+#define PMSG_SUSPEND 2
+#define PMSG_ON 0
+#endif
+#endif
+
+#ifndef PCI_D0
+#define PCI_D0 0
+#endif
+
+#ifndef PCI_D3hot
+#define PCI_D3hot 3
+#endif
+
+#ifndef PCI_D3cold
+#define PCI_D3cold 3
+#endif
+
+#ifndef PM_EVENT_SUSPEND
+#define PM_EVENT_SUSPEND 2
+#endif
+
+#if !defined(HAVE_NETDEV_PRIV)
+#define netdev_priv(dev) ((dev)->priv)
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
+#define ISR_PT_REGS_PARAM_DECL
+#define ISR_PT_REGS_ARG
+#else
+#define ISR_PT_REGS_PARAM_DECL , struct pt_regs *regs
+#define ISR_PT_REGS_ARG , NULL
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+#define for_each_possible_cpu(_cpu) for_each_cpu(_cpu)
+#endif
+
+#ifndef flush_icache_range
+#define flush_icache_range(start, end) do { } while (0)
+#endif
+
+#ifndef CHECKSUM_PARTIAL
+#define CHECKSUM_PARTIAL CHECKSUM_HW
+#endif
+
+#ifndef IRQF_SHARED
+#define IRQF_SHARED SA_SHIRQ
+#endif
+
+#define memcpy_skb(skb, from, length) \
+ memcpy(skb_put(skb, length), from, length)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#ifndef DMA_BIT_MASK
+#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
+#endif
+#endif
+
+#ifndef __GFP_DMA32
+#define __GFP_DMA32 GFP_DMA
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
+#define wrap_kmem_cache_create(name, size, align, flags) \
+ kmem_cache_create(name, size, align, flags, NULL, NULL)
+#else
+#define wrap_kmem_cache_create(name, size, align, flags) \
+ kmem_cache_create(name, size, align, flags, NULL)
+#endif
+
+#include "winnt_types.h"
+#include "ndiswrapper.h"
+#include "pe_linker.h"
+#include "wrapmem.h"
+#include "lin2win.h"
+#include "loader.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+static inline void netif_tx_lock(struct net_device *dev)
+{
+ spin_lock(&dev->xmit_lock);
+}
+static inline void netif_tx_unlock(struct net_device *dev)
+{
+ spin_unlock(&dev->xmit_lock);
+}
+static inline void netif_tx_lock_bh(struct net_device *dev)
+{
+ spin_lock_bh(&dev->xmit_lock);
+}
+static inline void netif_tx_unlock_bh(struct net_device *dev)
+{
+ spin_unlock_bh(&dev->xmit_lock);
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+static inline void netif_poll_enable(struct net_device *dev)
+{
+}
+static inline void netif_poll_disable(struct net_device *dev)
+{
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#define proc_net_root init_net.proc_net
+#else
+#define proc_net_root proc_net
+#endif
+
+/* TICK is 100ns */
+#define TICKSPERSEC 10000000
+#define TICKSPERMSEC 10000
+#define SECSPERDAY 86400
+#define TICKSPERJIFFY ((TICKSPERSEC + HZ - 1) / HZ)
+
+#define int_div_round(x, y) (((x) + (y - 1)) / (y))
+
+/* 1601 to 1970 is 369 years plus 89 leap days */
+#define SECS_1601_TO_1970 ((369 * 365 + 89) * (u64)SECSPERDAY)
+#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
+
+/* 100ns units to HZ; if sys_time is negative, relative to current
+ * clock, otherwise from year 1601 */
+#define SYSTEM_TIME_TO_HZ(sys_time) \
+ (((sys_time) <= 0) ? \
+ int_div_round(((u64)HZ * (-(sys_time))), TICKSPERSEC) : \
+ int_div_round(((s64)HZ * ((sys_time) - ticks_1601())), TICKSPERSEC))
+
+#define MSEC_TO_HZ(ms) int_div_round((ms * HZ), 1000)
+#define USEC_TO_HZ(us) int_div_round((us * HZ), 1000000)
+
+extern u64 wrap_ticks_to_boot;
+
+static inline u64 ticks_1601(void)
+{
+ return wrap_ticks_to_boot + (u64)jiffies * TICKSPERJIFFY;
+}
+
+typedef void (*generic_func)(void);
+
+struct wrap_export {
+ const char *name;
+ generic_func func;
+};
+
+#ifdef CONFIG_X86_64
+
+#define WIN_SYMBOL(name, argc) \
+ {#name, (generic_func) win2lin_ ## name ## _ ## argc}
+#define WIN_WIN_SYMBOL(name, argc) \
+ {#name, (generic_func) win2lin__win_ ## name ## _ ## argc}
+#define WIN_FUNC_DECL(name, argc) \
+ extern typeof(name) win2lin_ ## name ## _ ## argc;
+#define WIN_FUNC_PTR(name, argc) win2lin_ ## name ## _ ## argc
+
+#else
+
+#define WIN_SYMBOL(name, argc) {#name, (generic_func)name}
+#define WIN_WIN_SYMBOL(name, argc) {#name, (generic_func)_win_ ## name}
+#define WIN_FUNC_DECL(name, argc)
+#define WIN_FUNC_PTR(name, argc) name
+
+#endif
+
+#define WIN_FUNC(name, argc) name
+/* map name s to f - if f is different from s */
+#define WIN_SYMBOL_MAP(s, f)
+
+#define POOL_TAG(A, B, C, D) \
+ ((ULONG)((A) + ((B) << 8) + ((C) << 16) + ((D) << 24)))
+
+struct pe_image {
+ char name[MAX_DRIVER_NAME_LEN];
+ UINT (*entry)(struct driver_object *, struct unicode_string *) wstdcall;
+ void *image;
+ int size;
+ int type;
+
+ IMAGE_NT_HEADERS *nt_hdr;
+ IMAGE_OPTIONAL_HEADER *opt_hdr;
+};
+
+struct ndis_mp_block;
+
+struct wrap_timer {
+ struct nt_slist slist;
+ struct timer_list timer;
+ struct nt_timer *nt_timer;
+ long repeat;
+#ifdef TIMER_DEBUG
+ unsigned long wrap_timer_magic;
+#endif
+};
+
+struct ntos_work_item {
+ struct nt_list list;
+ void *arg1;
+ void *arg2;
+ NTOS_WORK_FUNC func;
+};
+
+struct wrap_device_setting {
+ struct nt_list list;
+ char name[MAX_SETTING_NAME_LEN];
+ char value[MAX_SETTING_VALUE_LEN];
+ void *encoded;
+};
+
+struct wrap_bin_file {
+ char name[MAX_DRIVER_NAME_LEN];
+ size_t size;
+ void *data;
+};
+
+#define WRAP_DRIVER_CLIENT_ID 1
+
+struct wrap_driver {
+ struct nt_list list;
+ struct driver_object *drv_obj;
+ char name[MAX_DRIVER_NAME_LEN];
+ char version[MAX_SETTING_VALUE_LEN];
+ unsigned short num_pe_images;
+ struct pe_image pe_images[MAX_DRIVER_PE_IMAGES];
+ unsigned short num_bin_files;
+ struct wrap_bin_file *bin_files;
+ struct nt_list wrap_devices;
+ struct nt_list settings;
+ int dev_type;
+ struct ndis_driver *ndis_driver;
+};
+
+enum hw_status {
+ HW_INITIALIZED = 1, HW_SUSPENDED, HW_HALTED, HW_PRESENT,
+};
+
+struct wrap_device {
+ /* first part is (de)initialized once by loader */
+ struct nt_list list;
+ int dev_bus;
+ int vendor;
+ int device;
+ int subvendor;
+ int subdevice;
+ char conf_file_name[MAX_DRIVER_NAME_LEN];
+ char driver_name[MAX_DRIVER_NAME_LEN];
+ struct wrap_driver *driver;
+ struct nt_list settings;
+
+ /* rest should be (de)initialized when a device is
+ * (un)plugged */
+ struct cm_resource_list *resource_list;
+ unsigned long hw_status;
+ struct device_object *pdo;
+ union {
+ struct {
+ struct pci_dev *pdev;
+ enum device_power_state wake_state;
+ } pci;
+ struct {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ int num_alloc_urbs;
+ struct nt_list wrap_urb_list;
+ } usb;
+ };
+ union {
+ struct ndis_device *wnd;
+ };
+};
+
+#define wrap_is_pci_bus(dev_bus) \
+ (WRAP_BUS(dev_bus) == WRAP_PCI_BUS || \
+ WRAP_BUS(dev_bus) == WRAP_PCMCIA_BUS)
+#ifdef ENABLE_USB
+/* earlier versions of ndiswrapper used 0 as USB_BUS */
+#define wrap_is_usb_bus(dev_bus) \
+ (WRAP_BUS(dev_bus) == WRAP_USB_BUS || \
+ WRAP_BUS(dev_bus) == WRAP_INTERNAL_BUS)
+#else
+#define wrap_is_usb_bus(dev_bus) 0
+#endif
+#define wrap_is_bluetooth_device(dev_bus) \
+ (WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE1 || \
+ WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE2)
+
+extern workqueue_struct_t *ntos_wq;
+#define schedule_ntos_work(work_struct) queue_work(ntos_wq, work_struct)
+#define schedule_work(work_struct) queue_work(ntos_wq, work_struct)
+
+extern workqueue_struct_t *ndis_wq;
+#define schedule_ndis_work(work_struct) queue_work(ndis_wq, work_struct)
+
+extern workqueue_struct_t *wrapndis_wq;
+#define schedule_wrapndis_work(work_struct) queue_work(wrapndis_wq, work_struct)
+
+#define atomic_unary_op(var, size, oper) \
+do { \
+ if (size == 1) \
+ __asm__ __volatile__( \
+ LOCK_PREFIX oper "b %b0\n\t" : "+m" (var)); \
+ else if (size == 2) \
+ __asm__ __volatile__( \
+ LOCK_PREFIX oper "w %w0\n\t" : "+m" (var)); \
+ else if (size == 4) \
+ __asm__ __volatile__( \
+ LOCK_PREFIX oper "l %0\n\t" : "+m" (var)); \
+ else if (size == 8) \
+ __asm__ __volatile__( \
+ LOCK_PREFIX oper "q %q0\n\t" : "+m" (var)); \
+ else { \
+ extern void _invalid_op_size_(void); \
+ _invalid_op_size_(); \
+ } \
+} while (0)
+
+#define atomic_inc_var_size(var, size) atomic_unary_op(var, size, "inc")
+
+#define atomic_inc_var(var) atomic_inc_var_size(var, sizeof(var))
+
+#define atomic_dec_var_size(var, size) atomic_unary_op(var, size, "dec")
+
+#define atomic_dec_var(var) atomic_dec_var_size(var, sizeof(var))
+
+#define pre_atomic_add(var, i) \
+({ \
+ typeof(var) pre; \
+ __asm__ __volatile__( \
+ LOCK_PREFIX "xadd %0, %1\n\t" \
+ : "=r"(pre), "+m"(var) \
+ : "0"(i)); \
+ pre; \
+})
+
+#define post_atomic_add(var, i) (pre_atomic_add(var, i) + i)
+
+#ifndef in_atomic
+#define in_atomic() in_interrupt()
+#endif
+
+#ifndef preempt_enable_no_resched
+#define preempt_enable_no_resched() preempt_enable()
+#endif
+
+//#define DEBUG_IRQL 1
+
+#ifdef DEBUG_IRQL
+#define assert_irql(cond) \
+do { \
+ KIRQL _irql_ = current_irql(); \
+ if (!(cond)) { \
+ WARNING("assertion '%s' failed: %d", #cond, _irql_); \
+ DBG_BLOCK(4) { \
+ dump_stack(); \
+ } \
+ } \
+} while (0)
+#else
+#define assert_irql(cond) do { } while (0)
+#endif
+
+/* When preempt is enabled, we should preempt_disable to raise IRQL to
+ * DISPATCH_LEVEL, to be consistent with the semantics. However, using
+ * a mutex instead, so that only ndiswrapper threads run one at a time
+ * on a processor when at DISPATCH_LEVEL seems to be enough. So that
+ * is what we will use until we learn otherwise. If
+ * preempt_(en|dis)able is required for some reason, comment out
+ * following #define. */
+
+#define WRAP_PREEMPT 1
+
+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PREEMPT_RT)
+#ifndef WRAP_PREEMPT
+#define WRAP_PREEMPT 1
+#endif
+#endif
+
+//#undef WRAP_PREEMPT
+
+#ifdef WRAP_PREEMPT
+
+typedef struct {
+ int count;
+ struct mutex lock;
+#ifdef CONFIG_SMP
+ typeof(current->cpus_allowed) cpus_allowed;
+#endif
+ struct task_struct *task;
+} irql_info_t;
+
+DECLARE_PER_CPU(irql_info_t, irql_info);
+
+static inline KIRQL raise_irql(KIRQL newirql)
+{
+ irql_info_t *info;
+
+ assert(newirql == DISPATCH_LEVEL);
+ info = &get_cpu_var(irql_info);
+ if (info->task == current) {
+ assert(info->count > 0);
+ assert(mutex_is_locked(&info->lock));
+#if defined(CONFIG_SMP) && defined(DEBUG)
+ do {
+ cpumask_t cpumask;
+ cpumask = cpumask_of_cpu(smp_processor_id());
+ cpus_xor(cpumask, cpumask, current->cpus_allowed);
+ assert(cpus_empty(cpumask));
+ } while (0);
+#endif
+ info->count++;
+ put_cpu_var(irql_info);
+ return DISPATCH_LEVEL;
+ }
+ /* TODO: is this enough to pin down to current cpu? */
+#ifdef CONFIG_SMP
+ assert(task_cpu(current) == smp_processor_id());
+ info->cpus_allowed = current->cpus_allowed;
+ current->cpus_allowed = cpumask_of_cpu(smp_processor_id());
+#endif
+ put_cpu_var(irql_info);
+ mutex_lock(&info->lock);
+ assert(info->count == 0);
+ assert(info->task == NULL);
+ info->count = 1;
+ info->task = current;
+ return PASSIVE_LEVEL;
+}
+
+static inline void lower_irql(KIRQL oldirql)
+{
+ irql_info_t *info;
+
+ assert(oldirql <= DISPATCH_LEVEL);
+ info = &get_cpu_var(irql_info);
+ assert(info->task == current);
+ assert(mutex_is_locked(&info->lock));
+ assert(info->count > 0);
+ if (--info->count == 0) {
+ info->task = NULL;
+#ifdef CONFIG_SMP
+ current->cpus_allowed = info->cpus_allowed;
+#endif
+ mutex_unlock(&info->lock);
+ }
+ put_cpu_var(irql_info);
+}
+
+static inline KIRQL current_irql(void)
+{
+ int count;
+ if (in_irq() || irqs_disabled())
+ EXIT4(return DIRQL);
+ if (in_atomic() || in_interrupt())
+ EXIT4(return SOFT_IRQL);
+ count = get_cpu_var(irql_info).count;
+ put_cpu_var(irql_info);
+ if (count)
+ EXIT6(return DISPATCH_LEVEL);
+ else
+ EXIT6(return PASSIVE_LEVEL);
+}
+
+#else
+
+static inline KIRQL current_irql(void)
+{
+ if (in_irq() || irqs_disabled())
+ EXIT4(return DIRQL);
+ if (in_interrupt())
+ EXIT4(return SOFT_IRQL);
+ if (in_atomic())
+ EXIT6(return DISPATCH_LEVEL);
+ else
+ EXIT6(return PASSIVE_LEVEL);
+}
+
+static inline KIRQL raise_irql(KIRQL newirql)
+{
+ KIRQL ret = in_atomic() ? DISPATCH_LEVEL : PASSIVE_LEVEL;
+ assert(newirql == DISPATCH_LEVEL);
+ assert(current_irql() <= DISPATCH_LEVEL);
+ preempt_disable();
+ return ret;
+}
+
+static inline void lower_irql(KIRQL oldirql)
+{
+ assert(current_irql() == DISPATCH_LEVEL);
+ preempt_enable();
+}
+
+#endif
+
+#define irql_gfp() (in_atomic() ? GFP_ATOMIC : GFP_KERNEL)
+
+/* Windows spinlocks are of type ULONG_PTR which is not big enough to
+ * store Linux spinlocks; so we implement Windows spinlocks using
+ * ULONG_PTR space with our own functions/macros */
+
+/* Windows seems to use 0 for unlocked state of spinlock - if Linux
+ * convention of 1 for unlocked state is used, at least prism54 driver
+ * crashes */
+
+#define NT_SPIN_LOCK_UNLOCKED 0
+#define NT_SPIN_LOCK_LOCKED 1
+
+static inline void nt_spin_lock_init(NT_SPIN_LOCK *lock)
+{
+ *lock = NT_SPIN_LOCK_UNLOCKED;
+}
+
+#ifdef CONFIG_SMP
+
+static inline void nt_spin_lock(NT_SPIN_LOCK *lock)
+{
+ __asm__ __volatile__(
+ "1:\t"
+ " xchgl %1, %0\n\t"
+ " testl %1, %1\n\t"
+ " jz 3f\n"
+ "2:\t"
+ " rep; nop\n\t"
+ " cmpl %2, %0\n\t"
+ " je 1b\n\t"
+ " jmp 2b\n"
+ "3:\n\t"
+ : "+m" (*lock)
+ : "r" (NT_SPIN_LOCK_LOCKED), "i" (NT_SPIN_LOCK_UNLOCKED));
+}
+
+static inline void nt_spin_unlock(NT_SPIN_LOCK *lock)
+{
+ *lock = NT_SPIN_LOCK_UNLOCKED;
+}
+
+#else // CONFIG_SMP
+
+#define nt_spin_lock(lock) do { } while (0)
+
+#define nt_spin_unlock(lock) do { } while (0)
+
+#endif // CONFIG_SMP
+
+/* When kernel would've disabled preempt (e.g., in interrupt
+ * handlers), we need to fake preempt so driver thinks it is running
+ * at right IRQL */
+
+/* raise IRQL to given (higher) IRQL if necessary before locking */
+static inline KIRQL nt_spin_lock_irql(NT_SPIN_LOCK *lock, KIRQL newirql)
+{
+ KIRQL oldirql = raise_irql(newirql);
+ nt_spin_lock(lock);
+ return oldirql;
+}
+
+/* lower IRQL to given (lower) IRQL if necessary after unlocking */
+static inline void nt_spin_unlock_irql(NT_SPIN_LOCK *lock, KIRQL oldirql)
+{
+ nt_spin_unlock(lock);
+ lower_irql(oldirql);
+}
+
+#define nt_spin_lock_irqsave(lock, flags) \
+do { \
+ local_irq_save(flags); \
+ preempt_disable(); \
+ nt_spin_lock(lock); \
+} while (0)
+
+#define nt_spin_unlock_irqrestore(lock, flags) \
+do { \
+ nt_spin_unlock(lock); \
+ preempt_enable_no_resched(); \
+ local_irq_restore(flags); \
+ preempt_check_resched(); \
+} while (0)
+
+static inline ULONG SPAN_PAGES(void *ptr, SIZE_T length)
+{
+ return PAGE_ALIGN(((unsigned long)ptr & (PAGE_SIZE - 1)) + length)
+ >> PAGE_SHIFT;
+}
+
+#ifdef CONFIG_X86_64
+
+/* TODO: can these be implemented without using spinlock? */
+
+static inline struct nt_slist *PushEntrySList(nt_slist_header *head,
+ struct nt_slist *entry,
+ NT_SPIN_LOCK *lock)
+{
+ KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL);
+ entry->next = head->next;
+ head->next = entry;
+ head->depth++;
+ nt_spin_unlock_irql(lock, irql);
+ TRACE4("%p, %p, %p", head, entry, entry->next);
+ return entry->next;
+}
+
+static inline struct nt_slist *PopEntrySList(nt_slist_header *head,
+ NT_SPIN_LOCK *lock)
+{
+ struct nt_slist *entry;
+ KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL);
+ entry = head->next;
+ if (entry) {
+ head->next = entry->next;
+ head->depth--;
+ }
+ nt_spin_unlock_irql(lock, irql);
+ TRACE4("%p, %p", head, entry);
+ return entry;
+}
+
+#else
+
+#define u64_low_32(x) ((u32)x)
+#define u64_high_32(x) ((u32)(x >> 32))
+
+static inline u64 cmpxchg8b(volatile u64 *ptr, u64 old, u64 new)
+{
+ u64 prev;
+
+ __asm__ __volatile__(
+ "\n"
+ LOCK_PREFIX "cmpxchg8b %0\n"
+ : "+m" (*ptr), "=A" (prev)
+ : "A" (old), "b" (u64_low_32(new)), "c" (u64_high_32(new)));
+ return prev;
+}
+
+/* slist routines below update slist atomically - no need for
+ * spinlocks */
+
+static inline struct nt_slist *PushEntrySList(nt_slist_header *head,
+ struct nt_slist *entry,
+ NT_SPIN_LOCK *lock)
+{
+ nt_slist_header old, new;
+ do {
+ old.align = head->align;
+ entry->next = old.next;
+ new.next = entry;
+ new.depth = old.depth + 1;
+ } while (cmpxchg8b(&head->align, old.align, new.align) != old.align);
+ TRACE4("%p, %p, %p", head, entry, old.next);
+ return old.next;
+}
+
+static inline struct nt_slist *PopEntrySList(nt_slist_header *head,
+ NT_SPIN_LOCK *lock)
+{
+ struct nt_slist *entry;
+ nt_slist_header old, new;
+ do {
+ old.align = head->align;
+ entry = old.next;
+ if (!entry)
+ break;
+ new.next = entry->next;
+ new.depth = old.depth - 1;
+ } while (cmpxchg8b(&head->align, old.align, new.align) != old.align);
+ TRACE4("%p, %p", head, entry);
+ return entry;
+}
+
+#endif
+
+#define sleep_hz(n) \
+do { \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout(n); \
+} while (0)
+
+int ntoskernel_init(void);
+void ntoskernel_exit(void);
+int ntoskernel_init_device(struct wrap_device *wd);
+void ntoskernel_exit_device(struct wrap_device *wd);
+void *allocate_object(ULONG size, enum common_object_type type,
+ struct unicode_string *name);
+void free_object(void *object);
+
+int usb_init(void);
+void usb_exit(void);
+int usb_init_device(struct wrap_device *wd);
+void usb_exit_device(struct wrap_device *wd);
+void usb_cancel_pending_urbs(void);
+
+int crt_init(void);
+void crt_exit(void);
+int rtl_init(void);
+void rtl_exit(void);
+int wrap_procfs_init(void);
+void wrap_procfs_remove(void);
+
+int link_pe_images(struct pe_image *pe_image, unsigned short n);
+
+int stricmp(const char *s1, const char *s2);
+void dump_bytes(const char *name, const u8 *from, int len);
+struct mdl *allocate_init_mdl(void *virt, ULONG length);
+void free_mdl(struct mdl *mdl);
+struct driver_object *find_bus_driver(const char *name);
+void free_custom_extensions(struct driver_extension *drv_obj_ext);
+struct nt_thread *get_current_nt_thread(void);
+u64 ticks_1601(void);
+int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2);
+void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type,
+ struct ndis_mp_block *nmb);
+BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz,
+ unsigned long repeat_hz, struct kdpc *kdpc);
+
+LONG InterlockedDecrement(LONG volatile *val) wfastcall;
+LONG InterlockedIncrement(LONG volatile *val) wfastcall;
+struct nt_list *ExInterlockedInsertHeadList
+ (struct nt_list *head, struct nt_list *entry,
+ NT_SPIN_LOCK *lock) wfastcall;
+struct nt_list *ExInterlockedInsertTailList
+ (struct nt_list *head, struct nt_list *entry,
+ NT_SPIN_LOCK *lock) wfastcall;
+struct nt_list *ExInterlockedRemoveHeadList
+ (struct nt_list *head, NT_SPIN_LOCK *lock) wfastcall;
+NTSTATUS IofCallDriver(struct device_object *dev_obj, struct irp *irp) wfastcall;
+KIRQL KfRaiseIrql(KIRQL newirql) wfastcall;
+void KfLowerIrql(KIRQL oldirql) wfastcall;
+KIRQL KfAcquireSpinLock(NT_SPIN_LOCK *lock) wfastcall;
+void KfReleaseSpinLock(NT_SPIN_LOCK *lock, KIRQL oldirql) wfastcall;
+void IofCompleteRequest(struct irp *irp, CHAR prio_boost) wfastcall;
+void KefReleaseSpinLockFromDpcLevel(NT_SPIN_LOCK *lock) wfastcall;
+
+LONG ObfReferenceObject(void *object) wfastcall;
+void ObfDereferenceObject(void *object) wfastcall;
+
+#define ObReferenceObject(object) ObfReferenceObject(object)
+#define ObDereferenceObject(object) ObfDereferenceObject(object)
+
+void WRITE_PORT_UCHAR(ULONG_PTR port, UCHAR value) wstdcall;
+UCHAR READ_PORT_UCHAR(ULONG_PTR port) wstdcall;
+
+#undef ExAllocatePoolWithTag
+void *ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size,
+ ULONG tag) wstdcall;
+#if defined(ALLOC_DEBUG) && ALLOC_DEBUG > 1
+#define ExAllocatePoolWithTag(pool_type, size, tag) \
+ wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__)
+#endif
+
+void ExFreePool(void *p) wstdcall;
+ULONG MmSizeOfMdl(void *base, ULONG length) wstdcall;
+void __iomem *MmMapIoSpace(PHYSICAL_ADDRESS phys_addr, SIZE_T size,
+ enum memory_caching_type cache) wstdcall;
+void MmUnmapIoSpace(void __iomem *addr, SIZE_T size) wstdcall;
+void MmProbeAndLockPages(struct mdl *mdl, KPROCESSOR_MODE access_mode,
+ enum lock_operation operation) wstdcall;
+void MmUnlockPages(struct mdl *mdl) wstdcall;
+void KeInitializeEvent(struct nt_event *nt_event,
+ enum event_type type, BOOLEAN state) wstdcall;
+LONG KeSetEvent(struct nt_event *nt_event, KPRIORITY incr,
+ BOOLEAN wait) wstdcall;
+LONG KeResetEvent(struct nt_event *nt_event) wstdcall;
+void KeClearEvent(struct nt_event *nt_event) wstdcall;
+void KeInitializeDpc(struct kdpc *kdpc, void *func, void *ctx) wstdcall;
+BOOLEAN queue_kdpc(struct kdpc *kdpc);
+BOOLEAN dequeue_kdpc(struct kdpc *kdpc);
+
+void KeFlushQueuedDpcs(void) wstdcall;
+NTSTATUS IoConnectInterrupt(struct kinterrupt **kinterrupt,
+ PKSERVICE_ROUTINE service_routine,
+ void *service_context, NT_SPIN_LOCK *lock,
+ ULONG vector, KIRQL irql, KIRQL synch_irql,
+ enum kinterrupt_mode interrupt_mode,
+ BOOLEAN shareable, KAFFINITY processor_enable_mask,
+ BOOLEAN floating_save) wstdcall;
+void IoDisconnectInterrupt(struct kinterrupt *interrupt) wstdcall;
+BOOLEAN KeSynchronizeExecution(struct kinterrupt *interrupt,
+ PKSYNCHRONIZE_ROUTINE synch_routine,
+ void *ctx) wstdcall;
+
+NTSTATUS KeWaitForSingleObject(void *object, KWAIT_REASON reason,
+ KPROCESSOR_MODE waitmode, BOOLEAN alertable,
+ LARGE_INTEGER *timeout) wstdcall;
+struct mdl *IoAllocateMdl(void *virt, ULONG length, BOOLEAN second_buf,
+ BOOLEAN charge_quota, struct irp *irp) wstdcall;
+void MmBuildMdlForNonPagedPool(struct mdl *mdl) wstdcall;
+void IoFreeMdl(struct mdl *mdl) wstdcall;
+NTSTATUS IoCreateDevice(struct driver_object *driver, ULONG dev_ext_length,
+ struct unicode_string *dev_name, DEVICE_TYPE dev_type,
+ ULONG dev_chars, BOOLEAN exclusive,
+ struct device_object **dev_obj) wstdcall;
+NTSTATUS IoCreateSymbolicLink(struct unicode_string *link,
+ struct unicode_string *dev_name) wstdcall;
+void IoDeleteDevice(struct device_object *dev) wstdcall;
+void IoDetachDevice(struct device_object *topdev) wstdcall;
+struct device_object *IoGetAttachedDevice(struct device_object *dev) wstdcall;
+struct device_object *IoGetAttachedDeviceReference
+ (struct device_object *dev) wstdcall;
+NTSTATUS IoAllocateDriverObjectExtension
+ (struct driver_object *drv_obj, void *client_id, ULONG extlen,
+ void **ext) wstdcall;
+void *IoGetDriverObjectExtension(struct driver_object *drv,
+ void *client_id) wstdcall;
+struct device_object *IoAttachDeviceToDeviceStack
+ (struct device_object *src, struct device_object *dst) wstdcall;
+void KeInitializeEvent(struct nt_event *nt_event, enum event_type type,
+ BOOLEAN state) wstdcall;
+struct irp *IoAllocateIrp(char stack_count, BOOLEAN charge_quota) wstdcall;
+void IoFreeIrp(struct irp *irp) wstdcall;
+BOOLEAN IoCancelIrp(struct irp *irp) wstdcall;
+struct irp *IoBuildSynchronousFsdRequest
+ (ULONG major_func, struct device_object *dev_obj, void *buf,
+ ULONG length, LARGE_INTEGER *offset, struct nt_event *event,
+ struct io_status_block *status) wstdcall;
+struct irp *IoBuildAsynchronousFsdRequest
+ (ULONG major_func, struct device_object *dev_obj, void *buf,
+ ULONG length, LARGE_INTEGER *offset,
+ struct io_status_block *status) wstdcall;
+NTSTATUS PoCallDriver(struct device_object *dev_obj, struct irp *irp) wstdcall;
+
+NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) wstdcall;
+WIN_FUNC_DECL(IoPassIrpDown,2);
+NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj,
+ struct irp *irp) wstdcall;
+NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj,
+ struct irp *irp) wstdcall;
+NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj,
+ struct irp *irp) wstdcall;
+
+KIRQL KeGetCurrentIrql(void) wstdcall;
+void KeInitializeSpinLock(NT_SPIN_LOCK *lock) wstdcall;
+void KeAcquireSpinLock(NT_SPIN_LOCK *lock, KIRQL *irql) wstdcall;
+void KeReleaseSpinLock(NT_SPIN_LOCK *lock, KIRQL oldirql) wstdcall;
+KIRQL KeAcquireSpinLockRaiseToDpc(NT_SPIN_LOCK *lock) wstdcall;
+
+void IoAcquireCancelSpinLock(KIRQL *irql) wstdcall;
+void IoReleaseCancelSpinLock(KIRQL irql) wstdcall;
+
+void RtlCopyMemory(void *dst, const void *src, SIZE_T length) wstdcall;
+NTSTATUS RtlUnicodeStringToAnsiString
+ (struct ansi_string *dst, const struct unicode_string *src,
+ BOOLEAN dup) wstdcall;
+NTSTATUS RtlAnsiStringToUnicodeString
+ (struct unicode_string *dst, const struct ansi_string *src,
+ BOOLEAN dup) wstdcall;
+void RtlInitAnsiString(struct ansi_string *dst, const char *src) wstdcall;
+void RtlInitString(struct ansi_string *dst, const char *src) wstdcall;
+void RtlInitUnicodeString(struct unicode_string *dest,
+ const wchar_t *src) wstdcall;
+void RtlFreeUnicodeString(struct unicode_string *string) wstdcall;
+void RtlFreeAnsiString(struct ansi_string *string) wstdcall;
+LONG RtlCompareUnicodeString(const struct unicode_string *s1,
+ const struct unicode_string *s2,
+ BOOLEAN case_insensitive) wstdcall;
+void RtlCopyUnicodeString(struct unicode_string *dst,
+ struct unicode_string *src) wstdcall;
+NTSTATUS RtlUpcaseUnicodeString(struct unicode_string *dst,
+ struct unicode_string *src,
+ BOOLEAN alloc) wstdcall;
+void KeInitializeTimer(struct nt_timer *nt_timer) wstdcall;
+void KeInitializeTimerEx(struct nt_timer *nt_timer,
+ enum timer_type type) wstdcall;
+BOOLEAN KeSetTimerEx(struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks,
+ LONG period_ms, struct kdpc *kdpc) wstdcall;
+BOOLEAN KeSetTimer(struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks,
+ struct kdpc *kdpc) wstdcall;
+BOOLEAN KeCancelTimer(struct nt_timer *nt_timer) wstdcall;
+void KeInitializeDpc(struct kdpc *kdpc, void *func, void *ctx) wstdcall;
+struct nt_thread *KeGetCurrentThread(void) wstdcall;
+NTSTATUS ObReferenceObjectByHandle(void *handle, ACCESS_MASK desired_access,
+ void *obj_type, KPROCESSOR_MODE access_mode,
+ void **object, void *handle_info) wstdcall;
+
+void adjust_user_shared_data_addr(char *driver, unsigned long length);
+
+extern spinlock_t ntoskernel_lock;
+extern spinlock_t irp_cancel_lock;
+extern struct nt_list object_list;
+#ifdef CONFIG_X86_64
+extern struct kuser_shared_data kuser_shared_data;
+#endif
+
+#define IoCompleteRequest(irp, prio) IofCompleteRequest(irp, prio)
+#define IoCallDriver(dev, irp) IofCallDriver(dev, irp)
+
+#if defined(IO_DEBUG)
+#define DUMP_IRP(_irp) \
+do { \
+ struct io_stack_location *_irp_sl; \
+ _irp_sl = IoGetCurrentIrpStackLocation(_irp); \
+ IOTRACE("irp: %p, stack size: %d, cl: %d, sl: %p, dev_obj: %p, " \
+ "mj_fn: %d, minor_fn: %d, nt_urb: %p, event: %p", \
+ _irp, _irp->stack_count, (_irp)->current_location, \
+ _irp_sl, _irp_sl->dev_obj, _irp_sl->major_fn, \
+ _irp_sl->minor_fn, IRP_URB(_irp), \
+ (_irp)->user_event); \
+} while (0)
+#else
+#define DUMP_IRP(_irp) do { } while (0)
+#endif
+
+#endif // _NTOSKERNEL_H_
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ntoskernel.h"
+#include "ndis.h"
+#include "wrapndis.h"
+#include "usb.h"
+#include "loader.h"
+#include "ntoskernel_io_exports.h"
+
+wstdcall void WIN_FUNC(IoAcquireCancelSpinLock,1)
+ (KIRQL *irql) __acquires(irql)
+{
+ spin_lock_bh(&irp_cancel_lock);
+ *irql = 0;
+}
+
+wstdcall void WIN_FUNC(IoReleaseCancelSpinLock,1)
+ (KIRQL irql) __releases(irql)
+{
+ spin_unlock_bh(&irp_cancel_lock);
+}
+
+wstdcall int WIN_FUNC(IoIsWdmVersionAvailable,2)
+ (UCHAR major, UCHAR minor)
+{
+ IOENTER("%d, %x", major, minor);
+ if (major == 1 &&
+ (minor == 0x30 || // Windows 2003
+ minor == 0x20 || // Windows XP
+ minor == 0x10)) // Windows 2000
+ IOEXIT(return TRUE);
+ IOEXIT(return FALSE);
+}
+
+wstdcall BOOLEAN WIN_FUNC(IoIs32bitProcess,1)
+ (struct irp *irp)
+{
+#ifdef CONFIG_X86_64
+ return FALSE;
+#else
+ return TRUE;
+#endif
+}
+
+wstdcall void WIN_FUNC(IoInitializeIrp,3)
+ (struct irp *irp, USHORT size, CCHAR stack_count)
+{
+ IOENTER("irp: %p, %d, %d", irp, size, stack_count);
+
+ memset(irp, 0, size);
+ irp->size = size;
+ irp->stack_count = stack_count;
+ irp->current_location = stack_count;
+ IoGetCurrentIrpStackLocation(irp) = IRP_SL(irp, stack_count);
+ IOEXIT(return);
+}
+
+wstdcall void WIN_FUNC(IoReuseIrp,2)
+ (struct irp *irp, NTSTATUS status)
+{
+ IOENTER("%p, %d", irp, status);
+ if (irp) {
+ UCHAR alloc_flags;
+
+ alloc_flags = irp->alloc_flags;
+ IoInitializeIrp(irp, irp->size, irp->stack_count);
+ irp->alloc_flags = alloc_flags;
+ irp->io_status.status = status;
+ }
+ IOEXIT(return);
+}
+
+wstdcall struct irp *WIN_FUNC(IoAllocateIrp,2)
+ (char stack_count, BOOLEAN charge_quota)
+{
+ struct irp *irp;
+ int irp_size;
+
+ IOENTER("count: %d", stack_count);
+ stack_count++;
+ irp_size = IoSizeOfIrp(stack_count);
+ irp = kmalloc(irp_size, irql_gfp());
+ if (irp)
+ IoInitializeIrp(irp, irp_size, stack_count);
+ IOTRACE("irp %p", irp);
+ IOEXIT(return irp);
+}
+
+wstdcall BOOLEAN WIN_FUNC(IoCancelIrp,1)
+ (struct irp *irp)
+{
+ typeof(irp->cancel_routine) cancel_routine;
+
+ /* NB: this function may be called at DISPATCH_LEVEL */
+ IOTRACE("irp: %p", irp);
+ if (!irp)
+ return FALSE;
+ DUMP_IRP(irp);
+ IoAcquireCancelSpinLock(&irp->cancel_irql);
+ cancel_routine = xchg(&irp->cancel_routine, NULL);
+ IOTRACE("%p", cancel_routine);
+ irp->cancel = TRUE;
+ if (cancel_routine) {
+ struct io_stack_location *irp_sl;
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+ IOTRACE("%p, %p", irp_sl, irp_sl->dev_obj);
+ /* cancel_routine will release the spin lock */
+ __release(irp->cancel_irql);
+ LIN2WIN2(cancel_routine, irp_sl->dev_obj, irp);
+ /* in usb's cancel, irp->cancel is set to indicate
+ * status of cancel */
+ IOEXIT(return xchg(&irp->cancel, TRUE));
+ } else {
+ IOTRACE("irp %p already canceled", irp);
+ IoReleaseCancelSpinLock(irp->cancel_irql);
+ IOEXIT(return FALSE);
+ }
+}
+
+wstdcall void IoQueueThreadIrp(struct irp *irp)
+{
+ struct nt_thread *thread;
+ KIRQL irql;
+
+ thread = get_current_nt_thread();
+ if (thread) {
+ IOTRACE("thread: %p, task: %p", thread, thread->task);
+ irp->flags |= IRP_SYNCHRONOUS_API;
+ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL);
+ InsertTailList(&thread->irps, &irp->thread_list);
+ IoIrpThread(irp) = thread;
+ nt_spin_unlock_irql(&thread->lock, irql);
+ } else
+ IoIrpThread(irp) = NULL;
+}
+
+wstdcall void IoDequeueThreadIrp(struct irp *irp)
+{
+ struct nt_thread *thread;
+ KIRQL irql;
+
+ thread = IoIrpThread(irp);
+ if (thread) {
+ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL);
+ RemoveEntryList(&irp->thread_list);
+ nt_spin_unlock_irql(&thread->lock, irql);
+ }
+}
+
+wstdcall void WIN_FUNC(IoFreeIrp,1)
+ (struct irp *irp)
+{
+ IOENTER("irp = %p", irp);
+ if (irp->flags & IRP_SYNCHRONOUS_API)
+ IoDequeueThreadIrp(irp);
+ kfree(irp);
+
+ IOEXIT(return);
+}
+
+wstdcall struct irp *WIN_FUNC(IoBuildAsynchronousFsdRequest,6)
+ (ULONG major_fn, struct device_object *dev_obj, void *buffer,
+ ULONG length, LARGE_INTEGER *offset,
+ struct io_status_block *user_status)
+{
+ struct irp *irp;
+ struct io_stack_location *irp_sl;
+
+ IOENTER("%p", dev_obj);
+ if (!dev_obj)
+ IOEXIT(return NULL);
+ irp = IoAllocateIrp(dev_obj->stack_count, FALSE);
+ if (irp == NULL) {
+ WARNING("couldn't allocate irp");
+ IOEXIT(return NULL);
+ }
+
+ irp_sl = IoGetNextIrpStackLocation(irp);
+ irp_sl->major_fn = major_fn;
+ IOTRACE("major_fn: %d", major_fn);
+ irp_sl->minor_fn = 0;
+ irp_sl->flags = 0;
+ irp_sl->control = 0;
+ irp_sl->dev_obj = dev_obj;
+ irp_sl->file_obj = NULL;
+ irp_sl->completion_routine = NULL;
+
+ if (dev_obj->flags & DO_DIRECT_IO) {
+ irp->mdl = IoAllocateMdl(buffer, length, FALSE, FALSE, irp);
+ if (irp->mdl == NULL) {
+ IoFreeIrp(irp);
+ return NULL;
+ }
+ MmProbeAndLockPages(irp->mdl, KernelMode,
+ major_fn == IRP_MJ_WRITE ?
+ IoReadAccess : IoWriteAccess);
+ IOTRACE("mdl: %p", irp->mdl);
+ } else if (dev_obj->flags & DO_BUFFERED_IO) {
+ irp->associated_irp.system_buffer = buffer;
+ irp->flags = IRP_BUFFERED_IO;
+ irp->mdl = NULL;
+ IOTRACE("buffer: %p", buffer);
+ }
+ if (major_fn == IRP_MJ_READ) {
+ irp_sl->params.read.length = length;
+ irp_sl->params.read.byte_offset = *offset;
+ } else if (major_fn == IRP_MJ_WRITE) {
+ irp_sl->params.write.length = length;
+ irp_sl->params.write.byte_offset = *offset;
+ }
+ irp->user_status = user_status;
+ IOTRACE("irp: %p", irp);
+ return irp;
+}
+
+wstdcall struct irp *WIN_FUNC(IoBuildSynchronousFsdRequest,7)
+ (ULONG major_fn, struct device_object *dev_obj, void *buf,
+ ULONG length, LARGE_INTEGER *offset, struct nt_event *event,
+ struct io_status_block *user_status)
+{
+ struct irp *irp;
+
+ irp = IoBuildAsynchronousFsdRequest(major_fn, dev_obj, buf, length,
+ offset, user_status);
+ if (irp == NULL)
+ return NULL;
+ irp->user_event = event;
+ IoQueueThreadIrp(irp);
+ return irp;
+}
+
+wstdcall struct irp *WIN_FUNC(IoBuildDeviceIoControlRequest,9)
+ (ULONG ioctl, struct device_object *dev_obj,
+ void *input_buf, ULONG input_buf_len, void *output_buf,
+ ULONG output_buf_len, BOOLEAN internal_ioctl,
+ struct nt_event *event, struct io_status_block *io_status)
+{
+ struct irp *irp;
+ struct io_stack_location *irp_sl;
+ ULONG buf_len;
+
+ IOENTER("%p, 0x%08x, %d", dev_obj, ioctl, internal_ioctl);
+ if (!dev_obj)
+ IOEXIT(return NULL);
+ irp = IoAllocateIrp(dev_obj->stack_count, FALSE);
+ if (irp == NULL) {
+ WARNING("couldn't allocate irp");
+ return NULL;
+ }
+ irp_sl = IoGetNextIrpStackLocation(irp);
+ irp_sl->params.dev_ioctl.code = ioctl;
+ irp_sl->params.dev_ioctl.input_buf_len = input_buf_len;
+ irp_sl->params.dev_ioctl.output_buf_len = output_buf_len;
+ irp_sl->major_fn = (internal_ioctl) ?
+ IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL;
+ IOTRACE("%d", IO_METHOD_FROM_CTL_CODE(ioctl));
+
+ switch (IO_METHOD_FROM_CTL_CODE(ioctl)) {
+ case METHOD_BUFFERED:
+ buf_len = max(input_buf_len, output_buf_len);
+ if (buf_len) {
+ irp->associated_irp.system_buffer =
+ ExAllocatePoolWithTag(NonPagedPool, buf_len, 0);
+ if (!irp->associated_irp.system_buffer) {
+ IoFreeIrp(irp);
+ IOEXIT(return NULL);
+ }
+ irp->associated_irp.system_buffer = input_buf;
+ if (input_buf)
+ memcpy(irp->associated_irp.system_buffer,
+ input_buf, input_buf_len);
+ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
+ if (output_buf)
+ irp->flags = IRP_INPUT_OPERATION;
+ irp->user_buf = output_buf;
+ } else
+ irp->user_buf = NULL;
+ break;
+ case METHOD_IN_DIRECT:
+ case METHOD_OUT_DIRECT:
+ if (input_buf) {
+ irp->associated_irp.system_buffer =
+ ExAllocatePoolWithTag(NonPagedPool,
+ input_buf_len, 0);
+ if (!irp->associated_irp.system_buffer) {
+ IoFreeIrp(irp);
+ IOEXIT(return NULL);
+ }
+ memcpy(irp->associated_irp.system_buffer,
+ input_buf, input_buf_len);
+ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
+ }
+ /* TODO: we are supposed to setup MDL, but USB layer
+ * doesn't use MDLs. Moreover, USB layer mirrors
+ * non-DMAable buffers, so no need to allocate
+ * DMAable buffer here */
+ if (output_buf) {
+ irp->associated_irp.system_buffer =
+ ExAllocatePoolWithTag(NonPagedPool,
+ output_buf_len, 0);
+ if (!irp->associated_irp.system_buffer) {
+ IoFreeIrp(irp);
+ IOEXIT(return NULL);
+ }
+ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
+ }
+ break;
+ case METHOD_NEITHER:
+ irp->user_buf = output_buf;
+ irp_sl->params.dev_ioctl.type3_input_buf = input_buf;
+ break;
+ }
+
+ irp->user_status = io_status;
+ irp->user_event = event;
+ IoQueueThreadIrp(irp);
+
+ IOTRACE("irp: %p", irp);
+ IOEXIT(return irp);
+}
+
+wfastcall NTSTATUS WIN_FUNC(IofCallDriver,2)
+ (struct device_object *dev_obj, struct irp *irp)
+{
+ struct io_stack_location *irp_sl;
+ NTSTATUS status;
+ driver_dispatch_t *major_func;
+ struct driver_object *drv_obj;
+
+ if (irp->current_location <= 0) {
+ ERROR("invalid irp: %p, %d", irp, irp->current_location);
+ return STATUS_INVALID_PARAMETER;
+ }
+ IOTRACE("%p, %p, %p, %d, %d, %p", dev_obj, irp, dev_obj->drv_obj,
+ irp->current_location, irp->stack_count,
+ IoGetCurrentIrpStackLocation(irp));
+ IoSetNextIrpStackLocation(irp);
+ DUMP_IRP(irp);
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+ drv_obj = dev_obj->drv_obj;
+ irp_sl->dev_obj = dev_obj;
+ major_func = drv_obj->major_func[irp_sl->major_fn];
+ IOTRACE("major_func: %p, dev_obj: %p", major_func, dev_obj);
+ if (major_func)
+ status = LIN2WIN2(major_func, dev_obj, irp);
+ else {
+ ERROR("major_function %d is not implemented",
+ irp_sl->major_fn);
+ status = STATUS_NOT_SUPPORTED;
+ }
+ IOEXIT(return status);
+}
+
+wfastcall void WIN_FUNC(IofCompleteRequest,2)
+ (struct irp *irp, CHAR prio_boost)
+{
+ struct io_stack_location *irp_sl;
+
+#ifdef IO_DEBUG
+ DUMP_IRP(irp);
+ if (irp->io_status.status == STATUS_PENDING) {
+ ERROR("invalid irp: %p, STATUS_PENDING", irp);
+ return;
+ }
+ if (irp->current_location < 0 ||
+ irp->current_location >= irp->stack_count) {
+ ERROR("invalid irp: %p, %d", irp, irp->current_location);
+ return;
+ }
+#endif
+ for (irp_sl = IoGetCurrentIrpStackLocation(irp);
+ irp->current_location < irp->stack_count; irp_sl++) {
+ struct device_object *dev_obj;
+ NTSTATUS status;
+
+ DUMP_IRP(irp);
+ if (irp_sl->control & SL_PENDING_RETURNED)
+ irp->pending_returned = TRUE;
+
+ /* current_location and dev_obj must be same as when
+ * driver called IoSetCompletionRoutine, which sets
+ * completion routine at next (lower) location, which
+ * is what we are going to call below; so we set
+ * current_location and dev_obj for the previous
+ * (higher) location */
+ IoSkipCurrentIrpStackLocation(irp);
+ if (irp->current_location < irp->stack_count)
+ dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj;
+ else
+ dev_obj = NULL;
+
+ IOTRACE("%d, %d, %p", irp->current_location, irp->stack_count,
+ dev_obj);
+ if (irp_sl->completion_routine &&
+ ((irp->io_status.status == STATUS_SUCCESS &&
+ irp_sl->control & SL_INVOKE_ON_SUCCESS) ||
+ (irp->io_status.status != STATUS_SUCCESS &&
+ irp_sl->control & SL_INVOKE_ON_ERROR) ||
+ (irp->cancel == TRUE &&
+ irp_sl->control & SL_INVOKE_ON_CANCEL))) {
+ IOTRACE("calling completion_routine at: %p, %p",
+ irp_sl->completion_routine, irp_sl->context);
+ status = LIN2WIN3(irp_sl->completion_routine,
+ dev_obj, irp, irp_sl->context);
+ IOTRACE("status: %08X", status);
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ IOEXIT(return);
+ } else {
+ /* propagate pending status to next irp_sl */
+ if (irp->pending_returned &&
+ irp->current_location < irp->stack_count)
+ IoMarkIrpPending(irp);
+ }
+ }
+
+ if (irp->user_status) {
+ irp->user_status->status = irp->io_status.status;
+ irp->user_status->info = irp->io_status.info;
+ }
+
+ if (irp->user_event) {
+ IOTRACE("setting event %p", irp->user_event);
+ KeSetEvent(irp->user_event, prio_boost, FALSE);
+ }
+
+ if (irp->associated_irp.system_buffer &&
+ (irp->flags & IRP_DEALLOCATE_BUFFER))
+ ExFreePool(irp->associated_irp.system_buffer);
+ else {
+ struct mdl *mdl;
+ while ((mdl = irp->mdl)) {
+ irp->mdl = mdl->next;
+ MmUnlockPages(mdl);
+ IoFreeMdl(mdl);
+ }
+ }
+ IOTRACE("freeing irp %p", irp);
+ IoFreeIrp(irp);
+ IOEXIT(return);
+}
+
+wstdcall NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp)
+{
+ IoSkipCurrentIrpStackLocation(irp);
+ IOEXIT(return IoCallDriver(dev_obj, irp));
+}
+
+wstdcall NTSTATUS IoIrpSyncComplete(struct device_object *dev_obj,
+ struct irp *irp, void *context)
+{
+ if (irp->pending_returned == TRUE)
+ KeSetEvent(context, IO_NO_INCREMENT, FALSE);
+ IOEXIT(return STATUS_MORE_PROCESSING_REQUIRED);
+}
+WIN_FUNC_DECL(IoIrpSyncComplete,3)
+
+wstdcall NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj,
+ struct irp *irp)
+{
+ struct nt_event event;
+ NTSTATUS status;
+
+ IoCopyCurrentIrpStackLocationToNext(irp);
+ KeInitializeEvent(&event, SynchronizationEvent, FALSE);
+ /* completion function is called as Windows function */
+ IoSetCompletionRoutine(irp, WIN_FUNC_PTR(IoIrpSyncComplete,3), &event,
+ TRUE, TRUE, TRUE);
+ status = IoCallDriver(dev_obj, irp);
+ IOTRACE("%08X", status);
+ if (status == STATUS_PENDING) {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
+ NULL);
+ status = irp->io_status.status;
+ }
+ IOTRACE("%08X", status);
+ IOEXIT(return status);
+}
+WIN_FUNC_DECL(IoSyncForwardIrp,2)
+
+wstdcall NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj,
+ struct irp *irp)
+{
+ NTSTATUS status;
+
+ IoCopyCurrentIrpStackLocationToNext(irp);
+ status = IoCallDriver(dev_obj, irp);
+ IOEXIT(return status);
+}
+WIN_FUNC_DECL(IoAsyncForwardIrp,2)
+
+wstdcall NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj,
+ struct irp *irp)
+{
+ struct io_stack_location *irp_sl;
+ NTSTATUS status;
+
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+ WARNING("%d:%d not implemented", irp_sl->major_fn, irp_sl->minor_fn);
+ irp->io_status.status = STATUS_SUCCESS;
+ irp->io_status.info = 0;
+ status = irp->io_status.status;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ IOEXIT(return status);
+}
+WIN_FUNC_DECL(IoInvalidDeviceRequest,2)
+
+static irqreturn_t io_irq_isr(int irq, void *data ISR_PT_REGS_PARAM_DECL)
+{
+ struct kinterrupt *interrupt = data;
+ BOOLEAN ret;
+
+#ifdef CONFIG_DEBUG_SHIRQ
+ if (!interrupt->u.enabled)
+ EXIT1(return IRQ_NONE);
+#endif
+ TRACE6("%p", interrupt);
+ nt_spin_lock(interrupt->actual_lock);
+ ret = LIN2WIN2(interrupt->isr, interrupt, interrupt->isr_ctx);
+ nt_spin_unlock(interrupt->actual_lock);
+ if (ret == TRUE)
+ EXIT6(return IRQ_HANDLED);
+ else
+ EXIT6(return IRQ_NONE);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoConnectInterrupt,11)
+ (struct kinterrupt **kinterrupt, PKSERVICE_ROUTINE isr, void *isr_ctx,
+ NT_SPIN_LOCK *lock, ULONG vector, KIRQL irql, KIRQL synch_irql,
+ enum kinterrupt_mode mode, BOOLEAN shared, KAFFINITY cpu_mask,
+ BOOLEAN save_fp)
+{
+ struct kinterrupt *interrupt;
+ IOENTER("");
+ interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL);
+ if (!interrupt)
+ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES);
+ interrupt->vector = vector;
+ interrupt->cpu_mask = cpu_mask;
+ nt_spin_lock_init(&interrupt->lock);
+ if (lock)
+ interrupt->actual_lock = lock;
+ else
+ interrupt->actual_lock = &interrupt->lock;
+ interrupt->shared = shared;
+ interrupt->save_fp = save_fp;
+ interrupt->isr = isr;
+ interrupt->isr_ctx = isr_ctx;
+ InitializeListHead(&interrupt->list);
+ interrupt->irql = irql;
+ interrupt->synch_irql = synch_irql;
+ interrupt->mode = mode;
+ if (request_irq(vector, io_irq_isr, shared ? IRQF_SHARED : 0,
+ "ndiswrapper", interrupt)) {
+ WARNING("request for irq %d failed", vector);
+ kfree(interrupt);
+ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES);
+ }
+ *kinterrupt = interrupt;
+#ifdef CONFIG_DEBUG_SHIRQ
+ interrupt->u.enabled = 1;
+#endif
+ IOEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(IoDisconnectInterrupt,1)
+ (struct kinterrupt *interrupt)
+{
+#ifdef CONFIG_DEBUG_SHIRQ
+ interrupt->u.enabled = 0;
+#endif
+ free_irq(interrupt->vector, interrupt);
+ kfree(interrupt);
+}
+
+wstdcall struct mdl *WIN_FUNC(IoAllocateMdl,5)
+ (void *virt, ULONG length, BOOLEAN second_buf, BOOLEAN charge_quota,
+ struct irp *irp)
+{
+ struct mdl *mdl;
+ mdl = allocate_init_mdl(virt, length);
+ if (!mdl)
+ return NULL;
+ if (irp) {
+ if (second_buf == TRUE) {
+ struct mdl *last;
+
+ last = irp->mdl;
+ while (last->next)
+ last = last->next;
+ last->next = mdl;
+ } else
+ irp->mdl = mdl;
+ }
+ IOTRACE("%p", mdl);
+ return mdl;
+}
+
+wstdcall void WIN_FUNC(IoFreeMdl,1)
+ (struct mdl *mdl)
+{
+ IOTRACE("%p", mdl);
+ free_mdl(mdl);
+}
+
+wstdcall struct io_workitem *WIN_FUNC(IoAllocateWorkItem,1)
+ (struct device_object *dev_obj)
+{
+ struct io_workitem *io_workitem;
+
+ IOENTER("%p", dev_obj);
+ io_workitem = kmalloc(sizeof(*io_workitem), irql_gfp());
+ if (!io_workitem)
+ IOEXIT(return NULL);
+ io_workitem->dev_obj = dev_obj;
+ IOEXIT(return io_workitem);
+}
+
+wstdcall void WIN_FUNC(IoFreeWorkItem,1)
+ (struct io_workitem *io_workitem)
+{
+ kfree(io_workitem);
+ IOEXIT(return);
+}
+
+wstdcall void WIN_FUNC(IoQueueWorkItem,4)
+ (struct io_workitem *io_workitem, void *func,
+ enum work_queue_type queue_type, void *context)
+{
+ IOENTER("%p, %p", io_workitem, io_workitem->dev_obj);
+ io_workitem->worker_routine = func;
+ io_workitem->context = context;
+ schedule_ntos_work_item(func, io_workitem->dev_obj, context);
+ IOEXIT(return);
+}
+
+wstdcall void WIN_FUNC(ExQueueWorkItem,2)
+ (struct io_workitem *io_workitem, enum work_queue_type queue_type)
+{
+ IOENTER("%p", io_workitem);
+ schedule_ntos_work_item(io_workitem->worker_routine,
+ io_workitem->dev_obj, io_workitem->context);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoAllocateDriverObjectExtension,4)
+ (struct driver_object *drv_obj, void *client_id, ULONG extlen,
+ void **ext)
+{
+ struct custom_ext *ce;
+
+ IOENTER("%p, %p", drv_obj, client_id);
+ ce = kmalloc(sizeof(*ce) + extlen, irql_gfp());
+ if (ce == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ IOTRACE("custom_ext: %p", ce);
+ ce->client_id = client_id;
+ spin_lock_bh(&ntoskernel_lock);
+ InsertTailList(&drv_obj->drv_ext->custom_ext, &ce->list);
+ spin_unlock_bh(&ntoskernel_lock);
+
+ *ext = (void *)ce + sizeof(*ce);
+ IOTRACE("ext: %p", *ext);
+ IOEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall void *WIN_FUNC(IoGetDriverObjectExtension,2)
+ (struct driver_object *drv_obj, void *client_id)
+{
+ struct custom_ext *ce;
+ void *ret;
+
+ IOENTER("drv_obj: %p, client_id: %p", drv_obj, client_id);
+ ret = NULL;
+ spin_lock_bh(&ntoskernel_lock);
+ nt_list_for_each_entry(ce, &drv_obj->drv_ext->custom_ext, list) {
+ if (ce->client_id == client_id) {
+ ret = (void *)ce + sizeof(*ce);
+ break;
+ }
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ IOTRACE("ret: %p", ret);
+ return ret;
+}
+
+void free_custom_extensions(struct driver_extension *drv_ext)
+{
+ struct nt_list *ent;
+
+ IOENTER("%p", drv_ext);
+ spin_lock_bh(&ntoskernel_lock);
+ while ((ent = RemoveHeadList(&drv_ext->custom_ext)))
+ kfree(ent);
+ spin_unlock_bh(&ntoskernel_lock);
+ IOEXIT(return);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoCreateDevice,7)
+ (struct driver_object *drv_obj, ULONG dev_ext_length,
+ struct unicode_string *dev_name, DEVICE_TYPE dev_type,
+ ULONG dev_chars, BOOLEAN exclusive, struct device_object **newdev)
+{
+ struct device_object *dev;
+ struct dev_obj_ext *dev_obj_ext;
+ int size;
+
+ IOENTER("%p, %u, %p", drv_obj, dev_ext_length, dev_name);
+
+ size = sizeof(*dev) + dev_ext_length + sizeof(*dev_obj_ext);
+ dev = allocate_object(size, OBJECT_TYPE_DEVICE, dev_name);
+ if (!dev)
+ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES);
+ if (dev_ext_length)
+ dev->dev_ext = dev + 1;
+ else
+ dev->dev_ext = NULL;
+
+ dev_obj_ext = ((void *)(dev + 1)) + dev_ext_length;
+ dev_obj_ext->dev_obj = dev;
+ dev_obj_ext->size = 0;
+ dev_obj_ext->type = IO_TYPE_DEVICE;
+ dev->dev_obj_ext = dev_obj_ext;
+
+ dev->type = dev_type;
+ dev->flags = 0;
+ dev->size = sizeof(*dev) + dev_ext_length;
+ dev->ref_count = 1;
+ dev->attached = NULL;
+ dev->stack_count = 1;
+
+ dev->drv_obj = drv_obj;
+ dev->next = drv_obj->dev_obj;
+ drv_obj->dev_obj = dev;
+
+ dev->align_req = 1;
+ dev->characteristics = dev_chars;
+ dev->io_timer = NULL;
+ KeInitializeEvent(&dev->lock, SynchronizationEvent, TRUE);
+ dev->vpb = NULL;
+
+ IOTRACE("dev: %p, ext: %p", dev, dev->dev_ext);
+ *newdev = dev;
+ IOEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoCreateUnprotectedSymbolicLink,2)
+ (struct unicode_string *link, struct unicode_string *dev_name)
+{
+ struct ansi_string ansi;
+
+ IOENTER("%p, %p", dev_name, link);
+ if (dev_name && (RtlUnicodeStringToAnsiString(&ansi, dev_name, TRUE) ==
+ STATUS_SUCCESS)) {
+ IOTRACE("dev_name: %s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) ==
+ STATUS_SUCCESS)) {
+ IOTRACE("link: %s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+// TODO();
+ IOEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoCreateSymbolicLink,2)
+ (struct unicode_string *link, struct unicode_string *dev_name)
+{
+ IOEXIT(return IoCreateUnprotectedSymbolicLink(link, dev_name));
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoDeleteSymbolicLink,1)
+ (struct unicode_string *link)
+{
+ struct ansi_string ansi;
+
+ IOENTER("%p", link);
+ if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) ==
+ STATUS_SUCCESS)) {
+ IOTRACE("dev_name: %s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ IOEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(IoDeleteDevice,1)
+ (struct device_object *dev)
+{
+ IOENTER("%p", dev);
+ if (dev == NULL)
+ IOEXIT(return);
+ IOTRACE("drv_obj: %p", dev->drv_obj);
+ if (dev->drv_obj) {
+ struct device_object *prev;
+
+ prev = dev->drv_obj->dev_obj;
+ IOTRACE("dev_obj: %p", prev);
+ if (prev == dev)
+ dev->drv_obj->dev_obj = dev->next;
+ else if (prev) {
+ while (prev->next != dev)
+ prev = prev->next;
+ prev->next = dev->next;
+ }
+ }
+ ObDereferenceObject(dev);
+ IOEXIT(return);
+}
+
+wstdcall void WIN_FUNC(IoDetachDevice,1)
+ (struct device_object *tgt)
+{
+ struct device_object *tail;
+
+ IOENTER("%p", tgt);
+ if (!tgt)
+ IOEXIT(return);
+ tail = tgt->attached;
+ if (!tail)
+ IOEXIT(return);
+ IOTRACE("tail: %p", tail);
+
+ spin_lock_bh(&ntoskernel_lock);
+ tgt->attached = tail->attached;
+ IOTRACE("attached:%p", tgt->attached);
+ for ( ; tail; tail = tail->attached) {
+ IOTRACE("tail:%p", tail);
+ tail->stack_count--;
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ IOEXIT(return);
+}
+
+wstdcall struct device_object *WIN_FUNC(IoGetAttachedDevice,1)
+ (struct device_object *dev)
+{
+ IOENTER("%p", dev);
+ if (!dev)
+ IOEXIT(return NULL);
+ spin_lock_bh(&ntoskernel_lock);
+ while (dev->attached)
+ dev = dev->attached;
+ spin_unlock_bh(&ntoskernel_lock);
+ IOEXIT(return dev);
+}
+
+wstdcall struct device_object *WIN_FUNC(IoGetAttachedDeviceReference,1)
+ (struct device_object *dev)
+{
+ IOENTER("%p", dev);
+ if (!dev)
+ IOEXIT(return NULL);
+ dev = IoGetAttachedDevice(dev);
+ ObReferenceObject(dev);
+ IOEXIT(return dev);
+}
+
+wstdcall struct device_object *WIN_FUNC(IoAttachDeviceToDeviceStack,2)
+ (struct device_object *src, struct device_object *tgt)
+{
+ struct device_object *attached;
+ struct dev_obj_ext *src_dev_ext;
+
+ IOENTER("%p, %p", src, tgt);
+ attached = IoGetAttachedDevice(tgt);
+ IOTRACE("%p", attached);
+ src_dev_ext = src->dev_obj_ext;
+ spin_lock_bh(&ntoskernel_lock);
+ if (attached)
+ attached->attached = src;
+ src->attached = NULL;
+ src->stack_count = attached->stack_count + 1;
+ src_dev_ext->attached_to = attached;
+ spin_unlock_bh(&ntoskernel_lock);
+ IOTRACE("stack_count: %d -> %d", attached->stack_count,
+ src->stack_count);
+ IOEXIT(return attached);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoGetDeviceProperty,5)
+ (struct device_object *pdo, enum device_registry_property dev_property,
+ ULONG buffer_len, void *buffer, ULONG *result_len)
+{
+ struct ansi_string ansi;
+ struct unicode_string unicode;
+ struct wrap_device *wd;
+ ULONG need;
+
+ IOENTER("dev_obj = %p, dev_property = %d, buffer_len = %u, "
+ "buffer = %p, result_len = %p", pdo, dev_property,
+ buffer_len, buffer, result_len);
+
+ wd = pdo->reserved;
+ switch (dev_property) {
+ case DevicePropertyDeviceDescription:
+ case DevicePropertyFriendlyName:
+ case DevicePropertyDriverKeyName:
+ if (wrap_is_pci_bus(wd->dev_bus))
+ RtlInitAnsiString(&ansi, "PCI");
+ else // if (wrap_is_usb_bus(wd->dev_bus))
+ RtlInitAnsiString(&ansi, "USB");
+ need = sizeof(wchar_t) * (ansi.max_length + 1);
+ if (buffer_len < need) {
+ *result_len = need;
+ IOEXIT(return STATUS_BUFFER_TOO_SMALL);
+ }
+ unicode.max_length = buffer_len;
+ unicode.buf = buffer;
+ if (RtlAnsiStringToUnicodeString(&unicode, &ansi,
+ FALSE) != STATUS_SUCCESS) {
+ *result_len = unicode.length;
+ IOEXIT(return STATUS_BUFFER_TOO_SMALL);
+ }
+ IOEXIT(return STATUS_SUCCESS);
+ default:
+ WARNING("%d not implemented", dev_property);
+ IOEXIT(return STATUS_INVALID_PARAMETER_2);
+ }
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoGetDeviceObjectPointer,4)
+ (struct unicode_string *name, ACCESS_MASK desired_access,
+ void *file_obj, struct device_object *dev_obj)
+{
+ struct common_object_header *coh;
+
+ dev_obj = NULL;
+ /* TODO: access is not checked and file_obj is set to NULL */
+ file_obj = NULL;
+ spin_lock_bh(&ntoskernel_lock);
+ nt_list_for_each_entry(coh, &object_list, list) {
+ TRACE5("header: %p, type: %d", coh, coh->type);
+ if (coh->type != OBJECT_TYPE_DEVICE)
+ continue;
+ if (!RtlCompareUnicodeString(&coh->name, name, TRUE)) {
+ dev_obj = HEADER_TO_OBJECT(coh);
+ TRACE5("dev_obj: %p", dev_obj);
+ break;
+ }
+ }
+ spin_unlock_bh(&ntoskernel_lock);
+ if (dev_obj)
+ IOEXIT(return STATUS_SUCCESS);
+ else
+ IOEXIT(return STATUS_OBJECT_NAME_INVALID);
+}
+
+/* NOTE: Make sure to compile with -freg-struct-return, so gcc will
+ * return union in register, like Windows */
+wstdcall union power_state WIN_FUNC(PoSetPowerState,3)
+ (struct device_object *dev_obj, enum power_state_type type,
+ union power_state state)
+{
+ IOEXIT(return state);
+}
+
+wstdcall NTSTATUS WIN_FUNC(PoCallDriver,2)
+ (struct device_object *dev_obj, struct irp *irp)
+{
+ return IoCallDriver(dev_obj, irp);
+}
+
+wstdcall NTSTATUS WIN_FUNC(PoRequestPowerIrp,6)
+ (struct device_object *dev_obj, UCHAR minor_fn,
+ union power_state power_state, void *completion_func,
+ void *context, struct irp **pirp)
+{
+ struct irp *irp;
+ struct io_stack_location *irp_sl;
+
+ TRACE1("%p, %d, %p", dev_obj, dev_obj->stack_count, dev_obj->drv_obj);
+ irp = IoAllocateIrp(dev_obj->stack_count, FALSE);
+ if (!irp)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ irp_sl = IoGetNextIrpStackLocation(irp);
+ irp_sl->major_fn = IRP_MJ_POWER;
+ irp_sl->minor_fn = minor_fn;
+ if (minor_fn == IRP_MN_WAIT_WAKE)
+ irp_sl->params.power.type = SystemPowerState;
+ else
+ irp_sl->params.power.type = DevicePowerState;
+ irp_sl->params.power.state = power_state;
+ irp_sl->completion_routine = completion_func;
+ irp->io_status.status = STATUS_NOT_SUPPORTED;
+ *pirp = irp;
+ return PoCallDriver(dev_obj, irp);
+}
+
+wstdcall void WIN_FUNC(PoStartNextPowerIrp,1)
+ (struct irp *irp)
+{
+ IOENTER("irp = %p", irp);
+ IOEXIT(return);
+}
+
+wstdcall void WIN_FUNC(IoInitializeRemoveLockEx,5)
+ (struct io_remove_lock *lock, ULONG alloc_tag, ULONG max_locked_min,
+ ULONG high_mark, ULONG lock_size)
+{
+ TODO();
+}
+
+wstdcall void *WIN_FUNC(IoAllocateErrorLogEntry,2)
+ (void *io_object, UCHAR entry_size)
+{
+ /* not implemented fully */
+ void *ret = kmalloc(sizeof(struct io_error_log_packet) + entry_size,
+ irql_gfp());
+ TRACE2("%p", ret);
+ if (ret)
+ return ret + sizeof(struct io_error_log_packet);
+ else
+ return NULL;
+}
+
+wstdcall void WIN_FUNC(IoWriteErrorLogEntry,1)
+ (void *entry)
+{
+ /* TODO: log error with codes and message */
+ ERROR("");
+}
+
+wstdcall void WIN_FUNC(IoFreeErrorLogEntry,1)
+ (void *entry)
+{
+ TRACE2("%p", entry);
+ kfree(entry - sizeof(struct io_error_log_packet));
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoAcquireRemoveLockEx,5)
+ (struct io_remove_lock lock, void *tag, char *file, ULONG line,
+ ULONG lock_size)
+{
+ TODO();
+ IOEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoReleaseRemoveLockEx,3)
+ (struct io_remove_lock lock, void *tag, ULONG lock_size)
+{
+ TODO();
+ IOEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoRegisterDeviceInterface,4)
+ (struct device_object *pdo, struct guid *guid_class,
+ struct unicode_string *reference, struct unicode_string *link)
+{
+ struct ansi_string ansi;
+
+ /* TODO: check if pdo is valid */
+ RtlInitAnsiString(&ansi, "ndis");
+ ENTER1("pdo: %p, ref: %p, link: %p, %x, %x, %x", pdo, reference, link,
+ guid_class->data1, guid_class->data2, guid_class->data3);
+ return RtlAnsiStringToUnicodeString(link, &ansi, TRUE);
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoSetDeviceInterfaceState,2)
+ (struct unicode_string *link, BOOLEAN enable)
+{
+ ENTER1("link: %p, enable: %d", link, enable);
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoOpenDeviceRegistryKey,4)
+ (struct device_object *dev_obj, ULONG type, ACCESS_MASK mask,
+ void **handle)
+{
+ ENTER1("dev_obj: %p", dev_obj);
+ *handle = dev_obj;
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(IoWMIRegistrationControl,2)
+ (struct device_object *dev_obj, ULONG action)
+{
+ ENTER2("%p, %d", dev_obj, action);
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(IoInvalidateDeviceRelations,2)
+ (struct device_object *dev_obj, enum device_relation_type type)
+{
+ INFO("%p, %d", dev_obj, type);
+ TODO();
+}
+
+wstdcall void WIN_FUNC(IoInvalidateDeviceState,1)
+ (struct device_object *pdo)
+{
+ INFO("%p", pdo);
+ TODO();
+}
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifdef TEST_LOADER
+
+#include "usr_linker.h"
+
+#else
+
+#include <linux/types.h>
+#include <asm/errno.h>
+
+//#define DEBUGLINKER 2
+
+#include "ntoskernel.h"
+
+#endif
+
+struct pe_exports {
+ char *dll;
+ char *name;
+ generic_func addr;
+};
+
+static struct pe_exports pe_exports[40];
+static int num_pe_exports;
+
+#define RVA2VA(image, rva, type) (type)(ULONG_PTR)((void *)image + rva)
+#define CHECK_SZ(a,b) { if (sizeof(a) != b) { \
+ ERROR("%s is bad, got %zd, expected %d", \
+ #a , sizeof(a), (b)); return -EINVAL; } }
+
+#if defined(DEBUGLINKER) && DEBUGLINKER > 0
+#define DBGLINKER(fmt, ...) printk(KERN_INFO "%s (%s:%d): " fmt "\n", \
+ DRIVER_NAME, __func__, \
+ __LINE__ , ## __VA_ARGS__);
+static const char *image_directory_name[] = {
+ "EXPORT",
+ "IMPORT",
+ "RESOURCE",
+ "EXCEPTION",
+ "SECURITY",
+ "BASERELOC",
+ "DEBUG",
+ "COPYRIGHT",
+ "GLOBALPTR",
+ "TLS",
+ "LOAD_CONFIG",
+ "BOUND_IMPORT",
+ "IAT",
+ "DELAY_IMPORT",
+ "COM_DESCRIPTOR" };
+#else
+#define DBGLINKER(fmt, ...) do { } while (0)
+#endif
+
+#ifndef TEST_LOADER
+extern struct wrap_export ntoskernel_exports[], ntoskernel_io_exports[],
+ ndis_exports[], crt_exports[], hal_exports[], rtl_exports[];
+#ifdef ENABLE_USB
+extern struct wrap_export usb_exports[];
+#endif
+
+static char *get_export(char *name)
+{
+ int i;
+
+ for (i = 0 ; ntoskernel_exports[i].name != NULL; i++)
+ if (strcmp(ntoskernel_exports[i].name, name) == 0)
+ return (char *)ntoskernel_exports[i].func;
+
+ for (i = 0 ; ntoskernel_io_exports[i].name != NULL; i++)
+ if (strcmp(ntoskernel_io_exports[i].name, name) == 0)
+ return (char *)ntoskernel_io_exports[i].func;
+
+ for (i = 0 ; ndis_exports[i].name != NULL; i++)
+ if (strcmp(ndis_exports[i].name, name) == 0)
+ return (char *)ndis_exports[i].func;
+
+ for (i = 0 ; crt_exports[i].name != NULL; i++)
+ if (strcmp(crt_exports[i].name, name) == 0)
+ return (char *)crt_exports[i].func;
+
+ for (i = 0 ; hal_exports[i].name != NULL; i++)
+ if (strcmp(hal_exports[i].name, name) == 0)
+ return (char *)hal_exports[i].func;
+
+ for (i = 0 ; rtl_exports[i].name != NULL; i++)
+ if (strcmp(rtl_exports[i].name, name) == 0)
+ return (char *)rtl_exports[i].func;
+
+#ifdef ENABLE_USB
+ for (i = 0 ; usb_exports[i].name != NULL; i++)
+ if (strcmp(usb_exports[i].name, name) == 0)
+ return (char *)usb_exports[i].func;
+#endif
+
+ for (i = 0; i < num_pe_exports; i++)
+ if (strcmp(pe_exports[i].name, name) == 0)
+ return (char *)pe_exports[i].addr;
+
+ return NULL;
+}
+#endif // TEST_LOADER
+
+static void *get_dll_init(char *name)
+{
+ int i;
+ for (i = 0; i < num_pe_exports; i++)
+ if ((strcmp(pe_exports[i].dll, name) == 0) &&
+ (strcmp(pe_exports[i].name, "DllInitialize") == 0))
+ return (void *)pe_exports[i].addr;
+ return NULL;
+}
+
+/*
+ * Find and validate the coff header
+ *
+ */
+static int check_nt_hdr(IMAGE_NT_HEADERS *nt_hdr)
+{
+ int i;
+ WORD attr;
+ PIMAGE_OPTIONAL_HEADER opt_hdr;
+
+ /* Validate the "PE\0\0" signature */
+ if (nt_hdr->Signature != IMAGE_NT_SIGNATURE) {
+ ERROR("is this driver file? bad signature %08x",
+ nt_hdr->Signature);
+ return -EINVAL;
+ }
+
+ opt_hdr = &nt_hdr->OptionalHeader;
+ /* Make sure Image is PE32 or PE32+ */
+#ifdef CONFIG_X86_64
+ if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ ERROR("kernel is 64-bit, but Windows driver is not 64-bit;"
+ "bad magic: %04X", opt_hdr->Magic);
+ return -EINVAL;
+ }
+#else
+ if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ ERROR("kernel is 32-bit, but Windows driver is not 32-bit;"
+ "bad magic: %04X", opt_hdr->Magic);
+ return -EINVAL;
+ }
+#endif
+
+ /* Validate the image for the current architecture. */
+#ifdef CONFIG_X86_64
+ if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) {
+ ERROR("kernel is 64-bit, but Windows driver is not 64-bit;"
+ " (PE signature is %04X)", nt_hdr->FileHeader.Machine);
+ return -EINVAL;
+ }
+#else
+ if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) {
+ ERROR("kernel is 32-bit, but Windows driver is not 32-bit;"
+ " (PE signature is %04X)", nt_hdr->FileHeader.Machine);
+ return -EINVAL;
+ }
+#endif
+
+ /* Must have attributes */
+#ifdef CONFIG_X86_64
+ attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE;
+#else
+ attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE;
+#endif
+ if ((nt_hdr->FileHeader.Characteristics & attr) != attr)
+ return -EINVAL;
+
+ /* Must be relocatable */
+ attr = IMAGE_FILE_RELOCS_STRIPPED;
+ if ((nt_hdr->FileHeader.Characteristics & attr))
+ return -EINVAL;
+
+ /* Make sure we have at least one section */
+ if (nt_hdr->FileHeader.NumberOfSections == 0)
+ return -EINVAL;
+
+ if (opt_hdr->SectionAlignment < opt_hdr->FileAlignment) {
+ ERROR("alignment mismatch: secion: 0x%x, file: 0x%x",
+ opt_hdr->SectionAlignment, opt_hdr->FileAlignment);
+ return -EINVAL;
+ }
+
+ DBGLINKER("number of datadictionary entries %d",
+ opt_hdr->NumberOfRvaAndSizes);
+ for (i = 0; i < opt_hdr->NumberOfRvaAndSizes; i++) {
+ DBGLINKER("datadirectory %s RVA:%X Size:%d",
+ (i<=IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)?
+ image_directory_name[i] : "unknown",
+ opt_hdr->DataDirectory[i].VirtualAddress,
+ opt_hdr->DataDirectory[i].Size);
+ }
+
+ if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE))
+ return IMAGE_FILE_EXECUTABLE_IMAGE;
+ if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_DLL))
+ return IMAGE_FILE_DLL;
+ return -EINVAL;
+}
+
+static int import(void *image, IMAGE_IMPORT_DESCRIPTOR *dirent, char *dll)
+{
+ ULONG_PTR *lookup_tbl, *address_tbl;
+ char *symname = NULL;
+ int i;
+ int ret = 0;
+ void *adr;
+
+ lookup_tbl = RVA2VA(image, dirent->u.OriginalFirstThunk, ULONG_PTR *);
+ address_tbl = RVA2VA(image, dirent->FirstThunk, ULONG_PTR *);
+
+ for (i = 0; lookup_tbl[i]; i++) {
+ if (IMAGE_SNAP_BY_ORDINAL(lookup_tbl[i])) {
+ ERROR("ordinal import not supported: %Lu",
+ (uint64_t)lookup_tbl[i]);
+ return -1;
+ }
+ else {
+ symname = RVA2VA(image,
+ ((lookup_tbl[i] &
+ ~IMAGE_ORDINAL_FLAG) + 2), char *);
+ }
+
+ adr = get_export(symname);
+ if (adr == NULL) {
+ ERROR("unknown symbol: %s:'%s'", dll, symname);
+ ret = -1;
+ } else {
+ DBGLINKER("found symbol: %s:%s: addr: %p, rva = %Lu",
+ dll, symname, adr, (uint64_t)address_tbl[i]);
+ address_tbl[i] = (ULONG_PTR)adr;
+ }
+ }
+ return ret;
+}
+
+static int read_exports(struct pe_image *pe)
+{
+ IMAGE_EXPORT_DIRECTORY *export_dir_table;
+ uint32_t *export_addr_table;
+ int i;
+ uint32_t *name_table;
+ PIMAGE_OPTIONAL_HEADER opt_hdr;
+ IMAGE_DATA_DIRECTORY *export_data_dir;
+
+ opt_hdr = &pe->nt_hdr->OptionalHeader;
+ export_data_dir =
+ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+
+ if (export_data_dir->Size == 0) {
+ DBGLINKER("no exports");
+ return 0;
+ }
+
+ export_dir_table =
+ RVA2VA(pe->image, export_data_dir->VirtualAddress,
+ IMAGE_EXPORT_DIRECTORY *);
+
+ name_table = (unsigned int *)(pe->image +
+ export_dir_table->AddressOfNames);
+ export_addr_table = (uint32_t *)
+ (pe->image + export_dir_table->AddressOfFunctions);
+
+ for (i = 0; i < export_dir_table->NumberOfNames; i++) {
+
+ if (export_data_dir->VirtualAddress <= *export_addr_table ||
+ *export_addr_table >= (export_data_dir->VirtualAddress +
+ export_data_dir->Size))
+ DBGLINKER("forwarder rva");
+
+ DBGLINKER("export symbol: %s, at %p",
+ (char *)(pe->image + *name_table),
+ pe->image + *export_addr_table);
+
+ pe_exports[num_pe_exports].dll = pe->name;
+ pe_exports[num_pe_exports].name = pe->image + *name_table;
+ pe_exports[num_pe_exports].addr =
+ pe->image + *export_addr_table;
+
+ num_pe_exports++;
+ name_table++;
+ export_addr_table++;
+ }
+ return 0;
+}
+
+static int fixup_imports(void *image, IMAGE_NT_HEADERS *nt_hdr)
+{
+ int i;
+ char *name;
+ int ret = 0;
+ IMAGE_IMPORT_DESCRIPTOR *dirent;
+ IMAGE_DATA_DIRECTORY *import_data_dir;
+ PIMAGE_OPTIONAL_HEADER opt_hdr;
+
+ opt_hdr = &nt_hdr->OptionalHeader;
+ import_data_dir =
+ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
+ dirent = RVA2VA(image, import_data_dir->VirtualAddress,
+ IMAGE_IMPORT_DESCRIPTOR *);
+
+ for (i = 0; dirent[i].Name; i++) {
+ name = RVA2VA(image, dirent[i].Name, char*);
+
+ DBGLINKER("imports from dll: %s", name);
+ ret += import(image, &dirent[i], name);
+ }
+ return ret;
+}
+
+static int fixup_reloc(void *image, IMAGE_NT_HEADERS *nt_hdr)
+{
+ ULONG_PTR base;
+ ULONG_PTR size;
+ IMAGE_BASE_RELOCATION *fixup_block;
+ IMAGE_DATA_DIRECTORY *base_reloc_data_dir;
+ PIMAGE_OPTIONAL_HEADER opt_hdr;
+
+ opt_hdr = &nt_hdr->OptionalHeader;
+ base = opt_hdr->ImageBase;
+ base_reloc_data_dir =
+ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ if (base_reloc_data_dir->Size == 0)
+ return 0;
+
+ fixup_block = RVA2VA(image, base_reloc_data_dir->VirtualAddress,
+ IMAGE_BASE_RELOCATION *);
+ DBGLINKER("fixup_block=%p, image=%p", fixup_block, image);
+ DBGLINKER("fixup_block info: %x %d",
+ fixup_block->VirtualAddress, fixup_block->SizeOfBlock);
+
+ while (fixup_block->SizeOfBlock) {
+ int i;
+ WORD fixup, offset;
+
+ size = (fixup_block->SizeOfBlock -
+ sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
+ DBGLINKER("found %Lu relocations in this block",
+ (uint64_t)size);
+
+ for (i = 0; i < size; i++) {
+ fixup = fixup_block->TypeOffset[i];
+ offset = fixup & 0xfff;
+ switch ((fixup >> 12) & 0x0f) {
+ case IMAGE_REL_BASED_ABSOLUTE:
+ break;
+
+ case IMAGE_REL_BASED_HIGHLOW: {
+ uint32_t addr;
+ uint32_t *loc =
+ RVA2VA(image,
+ fixup_block->VirtualAddress +
+ offset, uint32_t *);
+ addr = RVA2VA(image, (*loc - base), uint32_t);
+ DBGLINKER("relocation: *%p (Val:%X)= %X",
+ loc, *loc, addr);
+ *loc = addr;
+ }
+ break;
+
+ case IMAGE_REL_BASED_DIR64: {
+ uint64_t addr;
+ uint64_t *loc =
+ RVA2VA(image,
+ fixup_block->VirtualAddress +
+ offset, uint64_t *);
+ addr = RVA2VA(image, (*loc - base), uint64_t);
+ DBGLINKER("relocation: *%p (Val:%llX)= %llx",
+ loc, *loc, addr);
+ *loc = addr;
+ }
+ break;
+
+ default:
+ ERROR("unknown fixup: %08X",
+ (fixup >> 12) & 0x0f);
+ return -EOPNOTSUPP;
+ break;
+ }
+ }
+ DBGLINKER("finished relocating block");
+
+ fixup_block = (IMAGE_BASE_RELOCATION *)
+ ((void *)fixup_block + fixup_block->SizeOfBlock);
+ };
+ DBGLINKER("done relocating all");
+
+ return 0;
+}
+
+/* Expand the image in memroy if necessary. The image on disk does not
+ * necessarily maps the image of the driver in memory, so we have to
+ * re-write it in order to fullfill the sections alignements. The
+ * advantage to do that is that rva_to_va becomes a simple
+ * addition. */
+static int fix_pe_image(struct pe_image *pe)
+{
+ void *image;
+ IMAGE_SECTION_HEADER *sect_hdr;
+ int i, sections;
+ int image_size;
+
+ if (pe->size == pe->opt_hdr->SizeOfImage) {
+ /* Nothing to do */
+ return 0;
+ }
+
+ image_size = pe->opt_hdr->SizeOfImage;
+#ifdef CONFIG_X86_64
+#ifdef PAGE_KERNEL_EXECUTABLE
+ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM,
+ PAGE_KERNEL_EXECUTABLE);
+#elif defined PAGE_KERNEL_EXEC
+ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM,
+ PAGE_KERNEL_EXEC);
+#else
+#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC
+#endif
+#else
+#ifdef cpu_has_nx
+ /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is
+ * not available to modules! */
+ if (cpu_has_nx)
+ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM,
+ __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
+ else
+ image = vmalloc(image_size);
+#else
+ image = vmalloc(image_size);
+#endif
+#endif
+ if (image == NULL) {
+ ERROR("failed to allocate enough space for new image:"
+ " %d bytes", image_size);
+ return -ENOMEM;
+ }
+
+ /* Copy all the headers, ie everything before the first section. */
+
+ sections = pe->nt_hdr->FileHeader.NumberOfSections;
+ sect_hdr = IMAGE_FIRST_SECTION(pe->nt_hdr);
+
+ DBGLINKER("copying headers: %u bytes", sect_hdr->PointerToRawData);
+
+ memcpy(image, pe->image, sect_hdr->PointerToRawData);
+
+ /* Copy all the sections */
+ for (i = 0; i < sections; i++) {
+ DBGLINKER("Copy section %s from %x to %x",
+ sect_hdr->Name, sect_hdr->PointerToRawData,
+ sect_hdr->VirtualAddress);
+ if (sect_hdr->VirtualAddress+sect_hdr->SizeOfRawData >
+ image_size) {
+ ERROR("Invalid section %s in driver", sect_hdr->Name);
+ vfree(image);
+ return -EINVAL;
+ }
+
+ memcpy(image+sect_hdr->VirtualAddress,
+ pe->image + sect_hdr->PointerToRawData,
+ sect_hdr->SizeOfRawData);
+ sect_hdr++;
+ }
+
+ vfree(pe->image);
+ pe->image = image;
+ pe->size = image_size;
+
+ /* Update our internal pointers */
+ pe->nt_hdr = (IMAGE_NT_HEADERS *)
+ (pe->image + ((IMAGE_DOS_HEADER *)pe->image)->e_lfanew);
+ pe->opt_hdr = &pe->nt_hdr->OptionalHeader;
+
+ DBGLINKER("set nt headers: nt_hdr=%p, opt_hdr=%p, image=%p",
+ pe->nt_hdr, pe->opt_hdr, pe->image);
+
+ return 0;
+}
+
+#if defined(CONFIG_X86_64)
+static void fix_user_shared_data_addr(char *driver, unsigned long length)
+{
+ unsigned long i, n, max_addr, *addr;
+
+ n = length - sizeof(unsigned long);
+ max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data);
+ for (i = 0; i < n; i++) {
+ addr = (unsigned long *)(driver + i);
+ if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) {
+ *addr -= KI_USER_SHARED_DATA;
+ *addr += (unsigned long)&kuser_shared_data;
+ kuser_shared_data.reserved1 = 1;
+ }
+ }
+}
+#endif
+
+int link_pe_images(struct pe_image *pe_image, unsigned short n)
+{
+ int i;
+ struct pe_image *pe;
+
+#ifdef DEBUG
+ /* Sanity checkings */
+ CHECK_SZ(IMAGE_SECTION_HEADER, IMAGE_SIZEOF_SECTION_HEADER);
+ CHECK_SZ(IMAGE_FILE_HEADER, IMAGE_SIZEOF_FILE_HEADER);
+ CHECK_SZ(IMAGE_OPTIONAL_HEADER, IMAGE_SIZEOF_NT_OPTIONAL_HEADER);
+ CHECK_SZ(IMAGE_NT_HEADERS, 4 + IMAGE_SIZEOF_FILE_HEADER +
+ IMAGE_SIZEOF_NT_OPTIONAL_HEADER);
+ CHECK_SZ(IMAGE_DOS_HEADER, 0x40);
+ CHECK_SZ(IMAGE_EXPORT_DIRECTORY, 40);
+ CHECK_SZ(IMAGE_BASE_RELOCATION, 8);
+ CHECK_SZ(IMAGE_IMPORT_DESCRIPTOR, 20);
+#endif
+
+ for (i = 0; i < n; i++) {
+ IMAGE_DOS_HEADER *dos_hdr;
+ pe = &pe_image[i];
+ dos_hdr = pe->image;
+
+ if (pe->size < sizeof(IMAGE_DOS_HEADER)) {
+ TRACE1("image too small: %d", pe->size);
+ return -EINVAL;
+ }
+
+ pe->nt_hdr =
+ (IMAGE_NT_HEADERS *)(pe->image + dos_hdr->e_lfanew);
+ pe->opt_hdr = &pe->nt_hdr->OptionalHeader;
+
+ pe->type = check_nt_hdr(pe->nt_hdr);
+ if (pe->type <= 0) {
+ TRACE1("type <= 0");
+ return -EINVAL;
+ }
+
+ if (fix_pe_image(pe)) {
+ TRACE1("bad PE image");
+ return -EINVAL;
+ }
+
+ if (read_exports(pe)) {
+ TRACE1("read exports failed");
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ pe = &pe_image[i];
+
+ if (fixup_reloc(pe->image, pe->nt_hdr)) {
+ TRACE1("fixup reloc failed");
+ return -EINVAL;
+ }
+ if (fixup_imports(pe->image, pe->nt_hdr)) {
+ TRACE1("fixup imports failed");
+ return -EINVAL;
+ }
+#if defined(CONFIG_X86_64)
+ INFO("fixing KI_USER_SHARED_DATA address in the driver");
+ fix_user_shared_data_addr(pe_image[i].image, pe_image[i].size);
+#endif
+ flush_icache_range(pe->image, pe->size);
+
+ pe->entry =
+ RVA2VA(pe->image,
+ pe->opt_hdr->AddressOfEntryPoint, void *);
+ TRACE1("entry is at %p, rva at %08X", pe->entry,
+ pe->opt_hdr->AddressOfEntryPoint);
+ }
+
+ for (i = 0; i < n; i++) {
+ pe = &pe_image[i];
+
+ if (pe->type == IMAGE_FILE_DLL) {
+ struct unicode_string ustring;
+ char *buf = "0/0t0m0p00";
+ int (*dll_entry)(struct unicode_string *ustring)
+ wstdcall;
+
+ memset(&ustring, 0, sizeof(ustring));
+ ustring.buf = (wchar_t *)buf;
+ dll_entry = (void *)get_dll_init(pe->name);
+
+ TRACE1("calling dll_init at %p", dll_entry);
+ if (!dll_entry || dll_entry(&ustring))
+ ERROR("DLL initialize failed for %s",
+ pe->name);
+ }
+ else if (pe->type != IMAGE_FILE_EXECUTABLE_IMAGE)
+ ERROR("illegal image type: %d", pe->type);
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * This file is an excerpt of winnt.h from WINE, which bears the
+ * following copyright:
+ *
+ * Win32 definitions for Windows NT
+ *
+ * Copyright 1996 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * File formats definitions
+ */
+typedef struct _IMAGE_DOS_HEADER {
+ WORD e_magic; /* 00: MZ Header signature */
+ WORD e_cblp; /* 02: Bytes on last page of file */
+ WORD e_cp; /* 04: Pages in file */
+ WORD e_crlc; /* 06: Relocations */
+ WORD e_cparhdr; /* 08: Size of header in paragraphs */
+ WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */
+ WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */
+ WORD e_ss; /* 0e: Initial (relative) SS value */
+ WORD e_sp; /* 10: Initial SP value */
+ WORD e_csum; /* 12: Checksum */
+ WORD e_ip; /* 14: Initial IP value */
+ WORD e_cs; /* 16: Initial (relative) CS value */
+ WORD e_lfarlc; /* 18: File address of relocation table */
+ WORD e_ovno; /* 1a: Overlay number */
+ WORD e_res[4]; /* 1c: Reserved words */
+ WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */
+ WORD e_oeminfo; /* 26: OEM information; e_oemid specific */
+ WORD e_res2[10]; /* 28: Reserved words */
+ DWORD e_lfanew; /* 3c: Offset to extended header */
+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
+#define IMAGE_OS2_SIGNATURE 0x454E /* NE */
+#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */
+#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */
+#define IMAGE_VXD_SIGNATURE 0x454C /* LE */
+#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
+
+/*
+ * This is the Windows executable (NE) header.
+ * the name IMAGE_OS2_HEADER is misleading, but in the SDK this way.
+ */
+typedef struct
+{
+ WORD ne_magic; /* 00 NE signature 'NE' */
+ BYTE ne_ver; /* 02 Linker version number */
+ BYTE ne_rev; /* 03 Linker revision number */
+ WORD ne_enttab; /* 04 Offset to entry table relative to NE */
+ WORD ne_cbenttab; /* 06 Length of entry table in bytes */
+ LONG ne_crc; /* 08 Checksum */
+ WORD ne_flags; /* 0c Flags about segments in this file */
+ WORD ne_autodata; /* 0e Automatic data segment number */
+ WORD ne_heap; /* 10 Initial size of local heap */
+ WORD ne_stack; /* 12 Initial size of stack */
+ DWORD ne_csip; /* 14 Initial CS:IP */
+ DWORD ne_sssp; /* 18 Initial SS:SP */
+ WORD ne_cseg; /* 1c # of entries in segment table */
+ WORD ne_cmod; /* 1e # of entries in module reference tab. */
+ WORD ne_cbnrestab; /* 20 Length of nonresident-name table */
+ WORD ne_segtab; /* 22 Offset to segment table */
+ WORD ne_rsrctab; /* 24 Offset to resource table */
+ WORD ne_restab; /* 26 Offset to resident-name table */
+ WORD ne_modtab; /* 28 Offset to module reference table */
+ WORD ne_imptab; /* 2a Offset to imported name table */
+ DWORD ne_nrestab; /* 2c Offset to nonresident-name table */
+ WORD ne_cmovent; /* 30 # of movable entry points */
+ WORD ne_align; /* 32 Logical sector alignment shift count */
+ WORD ne_cres; /* 34 # of resource segments */
+ BYTE ne_exetyp; /* 36 Flags indicating target OS */
+ BYTE ne_flagsothers; /* 37 Additional information flags */
+ WORD ne_pretthunks; /* 38 Offset to return thunks */
+ WORD ne_psegrefbytes; /* 3a Offset to segment ref. bytes */
+ WORD ne_swaparea; /* 3c Reserved by Microsoft */
+ WORD ne_expver; /* 3e Expected Windows version number */
+} IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER;
+
+typedef struct _IMAGE_VXD_HEADER {
+ WORD e32_magic;
+ BYTE e32_border;
+ BYTE e32_worder;
+ DWORD e32_level;
+ WORD e32_cpu;
+ WORD e32_os;
+ DWORD e32_ver;
+ DWORD e32_mflags;
+ DWORD e32_mpages;
+ DWORD e32_startobj;
+ DWORD e32_eip;
+ DWORD e32_stackobj;
+ DWORD e32_esp;
+ DWORD e32_pagesize;
+ DWORD e32_lastpagesize;
+ DWORD e32_fixupsize;
+ DWORD e32_fixupsum;
+ DWORD e32_ldrsize;
+ DWORD e32_ldrsum;
+ DWORD e32_objtab;
+ DWORD e32_objcnt;
+ DWORD e32_objmap;
+ DWORD e32_itermap;
+ DWORD e32_rsrctab;
+ DWORD e32_rsrccnt;
+ DWORD e32_restab;
+ DWORD e32_enttab;
+ DWORD e32_dirtab;
+ DWORD e32_dircnt;
+ DWORD e32_fpagetab;
+ DWORD e32_frectab;
+ DWORD e32_impmod;
+ DWORD e32_impmodcnt;
+ DWORD e32_impproc;
+ DWORD e32_pagesum;
+ DWORD e32_datapage;
+ DWORD e32_preload;
+ DWORD e32_nrestab;
+ DWORD e32_cbnrestab;
+ DWORD e32_nressum;
+ DWORD e32_autodata;
+ DWORD e32_debuginfo;
+ DWORD e32_debuglen;
+ DWORD e32_instpreload;
+ DWORD e32_instdemand;
+ DWORD e32_heapsize;
+ BYTE e32_res3[12];
+ DWORD e32_winresoff;
+ DWORD e32_winreslen;
+ WORD e32_devid;
+ WORD e32_ddkver;
+} IMAGE_VXD_HEADER, *PIMAGE_VXD_HEADER;
+
+/* These defines describe the meanings of the bits in the
+ Characteristics field */
+
+#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
+
+/* These are the settings of the Machine field. */
+#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
+
+#define IMAGE_SIZEOF_FILE_HEADER 20
+#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56
+#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28
+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 224
+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 240
+#define IMAGE_SIZEOF_SHORT_NAME 8
+#define IMAGE_SIZEOF_SECTION_HEADER 40
+#define IMAGE_SIZEOF_SYMBOL 18
+#define IMAGE_SIZEOF_AUX_SYMBOL 18
+#define IMAGE_SIZEOF_RELOCATION 10
+#define IMAGE_SIZEOF_BASE_RELOCATION 8
+#define IMAGE_SIZEOF_LINENUMBER 6
+#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+/* Possible Magic values */
+#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b
+#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b
+#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x0107
+
+#ifdef CONFIG_X86_64
+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER64
+#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC
+#else
+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER32
+#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC
+#endif
+
+/* These are indexes into the DataDirectory array */
+#define IMAGE_FILE_EXPORT_DIRECTORY 0
+#define IMAGE_FILE_IMPORT_DIRECTORY 1
+#define IMAGE_FILE_RESOURCE_DIRECTORY 2
+#define IMAGE_FILE_EXCEPTION_DIRECTORY 3
+#define IMAGE_FILE_SECURITY_DIRECTORY 4
+#define IMAGE_FILE_BASE_RELOCATION_TABLE 5
+#define IMAGE_FILE_DEBUG_DIRECTORY 6
+#define IMAGE_FILE_DESCRIPTION_STRING 7
+#define IMAGE_FILE_MACHINE_VALUE 8 /* Mips */
+#define IMAGE_FILE_THREAD_LOCAL_STORAGE 9
+#define IMAGE_FILE_CALLBACK_DIRECTORY 10
+
+/* Directory Entries, indices into the DataDirectory array */
+
+#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
+#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
+#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
+#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
+#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
+#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
+#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
+#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
+#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */
+#define IMAGE_DIRECTORY_ENTRY_TLS 9
+#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
+#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11
+#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */
+#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
+#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14
+
+/* Subsystem Values */
+
+#define IMAGE_SUBSYSTEM_UNKNOWN 0
+#define IMAGE_SUBSYSTEM_NATIVE 1
+#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */
+#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem */
+#define IMAGE_SUBSYSTEM_OS2_CUI 5
+#define IMAGE_SUBSYSTEM_POSIX_CUI 7
+#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 /* native Win9x driver */
+#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 /* Windows CE subsystem */
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
+#define IMAGE_SUBSYSTEM_EFI_ROM 13
+#define IMAGE_SUBSYSTEM_XBOX 14
+
+typedef struct _IMAGE_FILE_HEADER {
+ WORD Machine;
+ WORD NumberOfSections;
+ DWORD TimeDateStamp;
+ DWORD PointerToSymbolTable;
+ DWORD NumberOfSymbols;
+ WORD SizeOfOptionalHeader;
+ WORD Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+ DWORD VirtualAddress;
+ DWORD Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+
+typedef struct _IMAGE_OPTIONAL_HEADER32 {
+
+ /* Standard fields */
+
+ WORD Magic;
+ BYTE MajorLinkerVersion;
+ BYTE MinorLinkerVersion;
+ DWORD SizeOfCode;
+ DWORD SizeOfInitializedData;
+ DWORD SizeOfUninitializedData;
+ DWORD AddressOfEntryPoint;
+ DWORD BaseOfCode;
+ DWORD BaseOfData;
+
+ /* NT additional fields */
+ DWORD ImageBase;
+ DWORD SectionAlignment;
+ DWORD FileAlignment;
+ WORD MajorOperatingSystemVersion;
+ WORD MinorOperatingSystemVersion;
+ WORD MajorImageVersion;
+ WORD MinorImageVersion;
+ WORD MajorSubsystemVersion;
+ WORD MinorSubsystemVersion;
+ DWORD Win32VersionValue;
+ DWORD SizeOfImage;
+ DWORD SizeOfHeaders;
+ DWORD CheckSum;
+ WORD Subsystem;
+ WORD DllCharacteristics;
+ DWORD SizeOfStackReserve;
+ DWORD SizeOfStackCommit;
+ DWORD SizeOfHeapReserve;
+ DWORD SizeOfHeapCommit;
+ DWORD LoaderFlags;
+ DWORD NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
+
+typedef struct _IMAGE_OPTIONAL_HEADER64 {
+
+ /* Standard fields */
+
+ WORD Magic;
+ BYTE MajorLinkerVersion;
+ BYTE MinorLinkerVersion;
+ DWORD SizeOfCode;
+ DWORD SizeOfInitializedData;
+ DWORD SizeOfUninitializedData;
+ DWORD AddressOfEntryPoint;
+ DWORD BaseOfCode;
+
+ /* NT additional fields */
+ ULONGLONG ImageBase;
+ DWORD SectionAlignment;
+ DWORD FileAlignment;
+ WORD MajorOperatingSystemVersion;
+ WORD MinorOperatingSystemVersion;
+ WORD MajorImageVersion;
+ WORD MinorImageVersion;
+ WORD MajorSubsystemVersion;
+ WORD MinorSubsystemVersion;
+ DWORD Win32VersionValue;
+ DWORD SizeOfImage;
+ DWORD SizeOfHeaders;
+ DWORD CheckSum;
+ WORD Subsystem;
+ WORD DllCharacteristics;
+ ULONGLONG SizeOfStackReserve;
+ ULONGLONG SizeOfStackCommit;
+ ULONGLONG SizeOfHeapReserve;
+ ULONGLONG SizeOfHeapCommit;
+ DWORD LoaderFlags;
+ DWORD NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
+
+#ifdef CONFIG_X86_64
+typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
+typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
+#else
+typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
+typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
+#endif
+
+typedef struct _IMAGE_NT_HEADERS32 {
+ DWORD Signature; /* "PE"\0\0 */ /* 0x00 */
+ IMAGE_FILE_HEADER FileHeader; /* 0x04 */
+ IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */
+} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
+
+typedef struct _IMAGE_NT_HEADERS64 {
+ DWORD Signature; /* "PE"\0\0 */ /* 0x00 */
+ IMAGE_FILE_HEADER FileHeader; /* 0x04 */
+ IMAGE_OPTIONAL_HEADER64 OptionalHeader; /* 0x18 */
+} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
+
+#ifdef CONFIG_X86_64
+typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS;
+typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS;
+#else
+typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS;
+typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
+#endif
+
+#define IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct _IMAGE_SECTION_HEADER {
+ BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
+ union {
+ DWORD PhysicalAddress;
+ DWORD VirtualSize;
+ } Misc;
+ DWORD VirtualAddress;
+ DWORD SizeOfRawData;
+ DWORD PointerToRawData;
+ DWORD PointerToRelocations;
+ DWORD PointerToLinenumbers;
+ WORD NumberOfRelocations;
+ WORD NumberOfLinenumbers;
+ DWORD Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+#define IMAGE_SIZEOF_SECTION_HEADER 40
+
+#define IMAGE_FIRST_SECTION(ntheader) \
+((PIMAGE_SECTION_HEADER)((LPBYTE)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \
+((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader))
+
+/* These defines are for the Characteristics bitfield. */
+/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */
+/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */
+/* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */
+/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */
+#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved */
+/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
+
+#define IMAGE_SCN_LNK_OTHER 0x00000100
+#define IMAGE_SCN_LNK_INFO 0x00000200
+/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */
+#define IMAGE_SCN_LNK_REMOVE 0x00000800
+#define IMAGE_SCN_LNK_COMDAT 0x00001000
+
+/* 0x00002000 - Reserved */
+/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */
+#define IMAGE_SCN_MEM_FARDATA 0x00008000
+
+/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */
+#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
+#define IMAGE_SCN_MEM_16BIT 0x00020000
+#define IMAGE_SCN_MEM_LOCKED 0x00040000
+#define IMAGE_SCN_MEM_PRELOAD 0x00080000
+
+#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
+#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
+#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
+#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
+#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */
+#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
+#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
+#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
+#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
+#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000
+#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000
+#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000
+#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000
+#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000
+/* 0x00F00000 - Unused */
+#define IMAGE_SCN_ALIGN_MASK 0x00F00000
+
+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
+
+
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
+#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
+#define IMAGE_SCN_MEM_SHARED 0x10000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+#define IMAGE_SCN_MEM_WRITE 0x80000000
+
+typedef struct _IMAGE_SYMBOL {
+ union {
+ BYTE ShortName[8];
+ struct {
+ DWORD Short;
+ DWORD Long;
+ } Name;
+ DWORD LongName[2];
+ } N;
+ DWORD Value;
+ SHORT SectionNumber;
+ WORD Type;
+ BYTE StorageClass;
+ BYTE NumberOfAuxSymbols;
+} IMAGE_SYMBOL;
+typedef IMAGE_SYMBOL *PIMAGE_SYMBOL;
+
+#define IMAGE_SIZEOF_SYMBOL 18
+
+typedef struct _IMAGE_LINENUMBER {
+ union {
+ DWORD SymbolTableIndex;
+ DWORD VirtualAddress;
+ } Type;
+ WORD Linenumber;
+} IMAGE_LINENUMBER;
+typedef IMAGE_LINENUMBER *PIMAGE_LINENUMBER;
+
+#define IMAGE_SIZEOF_LINENUMBER 6
+
+typedef union _IMAGE_AUX_SYMBOL {
+ struct {
+ DWORD TagIndex;
+ union {
+ struct {
+ WORD Linenumber;
+ WORD Size;
+ } LnSz;
+ DWORD TotalSize;
+ } Misc;
+ union {
+ struct {
+ DWORD PointerToLinenumber;
+ DWORD PointerToNextFunction;
+ } Function;
+ struct {
+ WORD Dimension[4];
+ } Array;
+ } FcnAry;
+ WORD TvIndex;
+ } Sym;
+ struct {
+ BYTE Name[IMAGE_SIZEOF_SYMBOL];
+ } File;
+ struct {
+ DWORD Length;
+ WORD NumberOfRelocations;
+ WORD NumberOfLinenumbers;
+ DWORD CheckSum;
+ SHORT Number;
+ BYTE Selection;
+ } Section;
+} IMAGE_AUX_SYMBOL;
+typedef IMAGE_AUX_SYMBOL *PIMAGE_AUX_SYMBOL;
+
+#define IMAGE_SIZEOF_AUX_SYMBOL 18
+
+#define IMAGE_SYM_UNDEFINED (SHORT)0
+#define IMAGE_SYM_ABSOLUTE (SHORT)-1
+#define IMAGE_SYM_DEBUG (SHORT)-2
+
+#define IMAGE_SYM_TYPE_NULL 0x0000
+#define IMAGE_SYM_TYPE_VOID 0x0001
+#define IMAGE_SYM_TYPE_CHAR 0x0002
+#define IMAGE_SYM_TYPE_SHORT 0x0003
+#define IMAGE_SYM_TYPE_INT 0x0004
+#define IMAGE_SYM_TYPE_LONG 0x0005
+#define IMAGE_SYM_TYPE_FLOAT 0x0006
+#define IMAGE_SYM_TYPE_DOUBLE 0x0007
+#define IMAGE_SYM_TYPE_STRUCT 0x0008
+#define IMAGE_SYM_TYPE_UNION 0x0009
+#define IMAGE_SYM_TYPE_ENUM 0x000A
+#define IMAGE_SYM_TYPE_MOE 0x000B
+#define IMAGE_SYM_TYPE_BYTE 0x000C
+#define IMAGE_SYM_TYPE_WORD 0x000D
+#define IMAGE_SYM_TYPE_UINT 0x000E
+#define IMAGE_SYM_TYPE_DWORD 0x000F
+#define IMAGE_SYM_TYPE_PCODE 0x8000
+
+#define IMAGE_SYM_DTYPE_NULL 0
+#define IMAGE_SYM_DTYPE_POINTER 1
+#define IMAGE_SYM_DTYPE_FUNCTION 2
+#define IMAGE_SYM_DTYPE_ARRAY 3
+
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1
+#define IMAGE_SYM_CLASS_NULL 0x0000
+#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001
+#define IMAGE_SYM_CLASS_EXTERNAL 0x0002
+#define IMAGE_SYM_CLASS_STATIC 0x0003
+#define IMAGE_SYM_CLASS_REGISTER 0x0004
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005
+#define IMAGE_SYM_CLASS_LABEL 0x0006
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008
+#define IMAGE_SYM_CLASS_ARGUMENT 0x0009
+#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B
+#define IMAGE_SYM_CLASS_UNION_TAG 0x000C
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E
+#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011
+#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012
+
+#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044
+#define IMAGE_SYM_CLASS_BLOCK 0x0064
+#define IMAGE_SYM_CLASS_FUNCTION 0x0065
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066
+#define IMAGE_SYM_CLASS_FILE 0x0067
+#define IMAGE_SYM_CLASS_SECTION 0x0068
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069
+
+#define N_BTMASK 0x000F
+#define N_TMASK 0x0030
+#define N_TMASK1 0x00C0
+#define N_TMASK2 0x00F0
+#define N_BTSHFT 4
+#define N_TSHIFT 2
+
+#define BTYPE(x) ((x) & N_BTMASK)
+
+#ifndef ISPTR
+#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT))
+#endif
+
+#ifndef ISFCN
+#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT))
+#endif
+
+#ifndef ISARY
+#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT))
+#endif
+
+#ifndef ISTAG
+#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG)
+#endif
+
+#ifndef INCREF
+#define INCREF(x) ((((x)&~N_BTMASK)<<N_TSHIFT)|(IMAGE_SYM_DTYPE_POINTER<<N_BTSHFT)|((x)&N_BTMASK))
+#endif
+#ifndef DECREF
+#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
+#endif
+
+#define IMAGE_COMDAT_SELECT_NODUPLICATES 1
+#define IMAGE_COMDAT_SELECT_ANY 2
+#define IMAGE_COMDAT_SELECT_SAME_SIZE 3
+#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4
+#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
+#define IMAGE_COMDAT_SELECT_LARGEST 6
+#define IMAGE_COMDAT_SELECT_NEWEST 7
+
+#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
+#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
+#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
+
+/* Export module directory */
+
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+ DWORD Characteristics;
+ DWORD TimeDateStamp;
+ WORD MajorVersion;
+ WORD MinorVersion;
+ DWORD Name;
+ DWORD Base;
+ DWORD NumberOfFunctions;
+ DWORD NumberOfNames;
+ DWORD AddressOfFunctions;
+ DWORD AddressOfNames;
+ DWORD AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
+
+/* Import name entry */
+typedef struct _IMAGE_IMPORT_BY_NAME {
+ WORD Hint;
+ BYTE Name[1];
+} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;
+
+/* Import thunk */
+typedef struct _IMAGE_THUNK_DATA32 {
+ union {
+ DWORD ForwarderString;
+ DWORD Function;
+ DWORD Ordinal;
+ DWORD AddressOfData;
+ } u1;
+} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32;
+
+typedef struct _IMAGE_THUNK_DATA64 {
+ union {
+ ULONGLONG ForwarderString;
+ ULONGLONG Function;
+ ULONGLONG Ordinal;
+ ULONGLONG AddressOfData;
+ } u1;
+} IMAGE_THUNK_DATA64,*PIMAGE_THUNK_DATA64;
+
+#ifdef CONFIG_X86_64
+typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA;
+typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA;
+#else
+typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA;
+typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA;
+#endif
+
+/* Import module directory */
+
+typedef struct packed _IMAGE_IMPORT_DESCRIPTOR {
+ union {
+ DWORD Characteristics; /* 0 for terminating null
+ * import descriptor */
+ DWORD OriginalFirstThunk; /* RVA to original unbound
+ * IAT */
+ } u;
+ DWORD TimeDateStamp; /* 0 if not bound,
+ * -1 if bound, and real date\time stamp
+ * in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
+ * (new BIND)
+ * otherwise date/time stamp of DLL bound to
+ * (Old BIND)
+ */
+ DWORD ForwarderChain; /* -1 if no forwarders */
+ DWORD Name;
+ /* RVA to IAT (if bound this IAT has actual addresses) */
+ DWORD FirstThunk;
+} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
+
+#define IMAGE_ORDINAL_FLAG32 0x80000000
+#define IMAGE_ORDINAL_FLAG64 0x8000000000000000UL
+#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0)
+#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0)
+#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)
+
+#ifdef CONFIG_X86_64
+#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64
+#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL64
+#else
+#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32
+#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL32
+#endif
+
+typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR
+{
+ DWORD TimeDateStamp;
+ WORD OffsetModuleName;
+ WORD NumberOfModuleForwarderRefs;
+/* Array of zero or more IMAGE_BOUND_FORWARDER_REF follows */
+} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR;
+
+typedef struct _IMAGE_BOUND_FORWARDER_REF
+{
+ DWORD TimeDateStamp;
+ WORD OffsetModuleName;
+ WORD Reserved;
+} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;
+
+typedef struct _IMAGE_BASE_RELOCATION
+{
+ DWORD VirtualAddress;
+ DWORD SizeOfBlock;
+ WORD TypeOffset[0];
+} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
+
+typedef struct _IMAGE_RELOCATION
+{
+ union {
+ DWORD VirtualAddress;
+ DWORD RelocCount;
+ } DUMMYUNIONNAME;
+ DWORD SymbolTableIndex;
+ WORD Type;
+} IMAGE_RELOCATION, *PIMAGE_RELOCATION;
+
+#define IMAGE_SIZEOF_RELOCATION 10
+
+/* 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
+
+/* I386 relocation types */
+#define IMAGE_REL_I386_ABSOLUTE 0
+#define IMAGE_REL_I386_DIR16 1
+#define IMAGE_REL_I386_REL16 2
+#define IMAGE_REL_I386_DIR32 6
+#define IMAGE_REL_I386_DIR32NB 7
+#define IMAGE_REL_I386_SEG12 9
+#define IMAGE_REL_I386_SECTION 10
+#define IMAGE_REL_I386_SECREL 11
+#define IMAGE_REL_I386_REL32 20
+
+/* MIPS relocation types */
+#define IMAGE_REL_MIPS_ABSOLUTE 0x0000
+#define IMAGE_REL_MIPS_REFHALF 0x0001
+#define IMAGE_REL_MIPS_REFWORD 0x0002
+#define IMAGE_REL_MIPS_JMPADDR 0x0003
+#define IMAGE_REL_MIPS_REFHI 0x0004
+#define IMAGE_REL_MIPS_REFLO 0x0005
+#define IMAGE_REL_MIPS_GPREL 0x0006
+#define IMAGE_REL_MIPS_LITERAL 0x0007
+#define IMAGE_REL_MIPS_SECTION 0x000A
+#define IMAGE_REL_MIPS_SECREL 0x000B
+#define IMAGE_REL_MIPS_SECRELLO 0x000C
+#define IMAGE_REL_MIPS_SECRELHI 0x000D
+#define IMAGE_REL_MIPS_JMPADDR16 0x0010
+#define IMAGE_REL_MIPS_REFWORDNB 0x0022
+#define IMAGE_REL_MIPS_PAIR 0x0025
+
+/* ALPHA relocation types */
+#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000
+#define IMAGE_REL_ALPHA_REFLONG 0x0001
+#define IMAGE_REL_ALPHA_REFQUAD 0x0002
+#define IMAGE_REL_ALPHA_GPREL 0x0003
+#define IMAGE_REL_ALPHA_LITERAL 0x0004
+#define IMAGE_REL_ALPHA_LITUSE 0x0005
+#define IMAGE_REL_ALPHA_GPDISP 0x0006
+#define IMAGE_REL_ALPHA_BRADDR 0x0007
+#define IMAGE_REL_ALPHA_HINT 0x0008
+#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009
+#define IMAGE_REL_ALPHA_REFHI 0x000A
+#define IMAGE_REL_ALPHA_REFLO 0x000B
+#define IMAGE_REL_ALPHA_PAIR 0x000C
+#define IMAGE_REL_ALPHA_MATCH 0x000D
+#define IMAGE_REL_ALPHA_SECTION 0x000E
+#define IMAGE_REL_ALPHA_SECREL 0x000F
+#define IMAGE_REL_ALPHA_REFLONGNB 0x0010
+#define IMAGE_REL_ALPHA_SECRELLO 0x0011
+#define IMAGE_REL_ALPHA_SECRELHI 0x0012
+#define IMAGE_REL_ALPHA_REFQ3 0x0013
+#define IMAGE_REL_ALPHA_REFQ2 0x0014
+#define IMAGE_REL_ALPHA_REFQ1 0x0015
+#define IMAGE_REL_ALPHA_GPRELLO 0x0016
+#define IMAGE_REL_ALPHA_GPRELHI 0x0017
+
+/* PowerPC relocation types */
+#define IMAGE_REL_PPC_ABSOLUTE 0x0000
+#define IMAGE_REL_PPC_ADDR64 0x0001
+#define IMAGE_REL_PPC_ADDR 0x0002
+#define IMAGE_REL_PPC_ADDR24 0x0003
+#define IMAGE_REL_PPC_ADDR16 0x0004
+#define IMAGE_REL_PPC_ADDR14 0x0005
+#define IMAGE_REL_PPC_REL24 0x0006
+#define IMAGE_REL_PPC_REL14 0x0007
+#define IMAGE_REL_PPC_TOCREL16 0x0008
+#define IMAGE_REL_PPC_TOCREL14 0x0009
+#define IMAGE_REL_PPC_ADDR32NB 0x000A
+#define IMAGE_REL_PPC_SECREL 0x000B
+#define IMAGE_REL_PPC_SECTION 0x000C
+#define IMAGE_REL_PPC_IFGLUE 0x000D
+#define IMAGE_REL_PPC_IMGLUE 0x000E
+#define IMAGE_REL_PPC_SECREL16 0x000F
+#define IMAGE_REL_PPC_REFHI 0x0010
+#define IMAGE_REL_PPC_REFLO 0x0011
+#define IMAGE_REL_PPC_PAIR 0x0012
+#define IMAGE_REL_PPC_SECRELLO 0x0013
+#define IMAGE_REL_PPC_SECRELHI 0x0014
+#define IMAGE_REL_PPC_GPREL 0x0015
+#define IMAGE_REL_PPC_TYPEMASK 0x00FF
+/* modifier bits */
+#define IMAGE_REL_PPC_NEG 0x0100
+#define IMAGE_REL_PPC_BRTAKEN 0x0200
+#define IMAGE_REL_PPC_BRNTAKEN 0x0400
+#define IMAGE_REL_PPC_TOCDEFN 0x0800
+
+/* SH3 ? relocation type */
+#define IMAGE_REL_SH3_ABSOLUTE 0x0000
+#define IMAGE_REL_SH3_DIRECT16 0x0001
+#define IMAGE_REL_SH3_DIRECT 0x0002
+#define IMAGE_REL_SH3_DIRECT8 0x0003
+#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004
+#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005
+#define IMAGE_REL_SH3_DIRECT4 0x0006
+#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007
+#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008
+#define IMAGE_REL_SH3_PCREL8_WORD 0x0009
+#define IMAGE_REL_SH3_PCREL8_LONG 0x000A
+#define IMAGE_REL_SH3_PCREL12_WORD 0x000B
+#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C
+#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D
+#define IMAGE_REL_SH3_SECTION 0x000E
+#define IMAGE_REL_SH3_SECREL 0x000F
+#define IMAGE_REL_SH3_DIRECT32_NB 0x0010
+
+/* ARM (Archimedes?) relocation types */
+#define IMAGE_REL_ARM_ABSOLUTE 0x0000
+#define IMAGE_REL_ARM_ADDR 0x0001
+#define IMAGE_REL_ARM_ADDR32NB 0x0002
+#define IMAGE_REL_ARM_BRANCH24 0x0003
+#define IMAGE_REL_ARM_BRANCH11 0x0004
+#define IMAGE_REL_ARM_SECTION 0x000E
+#define IMAGE_REL_ARM_SECREL 0x000F
+
+/* IA64 relocation types */
+#define IMAGE_REL_IA64_ABSOLUTE 0x0000
+#define IMAGE_REL_IA64_IMM14 0x0001
+#define IMAGE_REL_IA64_IMM22 0x0002
+#define IMAGE_REL_IA64_IMM64 0x0003
+#define IMAGE_REL_IA64_DIR 0x0004
+#define IMAGE_REL_IA64_DIR64 0x0005
+#define IMAGE_REL_IA64_PCREL21B 0x0006
+#define IMAGE_REL_IA64_PCREL21M 0x0007
+#define IMAGE_REL_IA64_PCREL21F 0x0008
+#define IMAGE_REL_IA64_GPREL22 0x0009
+#define IMAGE_REL_IA64_LTOFF22 0x000A
+#define IMAGE_REL_IA64_SECTION 0x000B
+#define IMAGE_REL_IA64_SECREL22 0x000C
+#define IMAGE_REL_IA64_SECREL64I 0x000D
+#define IMAGE_REL_IA64_SECREL 0x000E
+#define IMAGE_REL_IA64_LTOFF64 0x000F
+#define IMAGE_REL_IA64_DIR32NB 0x0010
+#define IMAGE_REL_IA64_RESERVED_11 0x0011
+#define IMAGE_REL_IA64_RESERVED_12 0x0012
+#define IMAGE_REL_IA64_RESERVED_13 0x0013
+#define IMAGE_REL_IA64_RESERVED_14 0x0014
+#define IMAGE_REL_IA64_RESERVED_15 0x0015
+#define IMAGE_REL_IA64_RESERVED_16 0x0016
+#define IMAGE_REL_IA64_ADDEND 0x001F
+
+/* archive format */
+
+#define IMAGE_ARCHIVE_START_SIZE 8
+#define IMAGE_ARCHIVE_START "!<arch>\n"
+#define IMAGE_ARCHIVE_END "`\n"
+#define IMAGE_ARCHIVE_PAD "\n"
+#define IMAGE_ARCHIVE_LINKER_MEMBER "/ "
+#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// "
+
+typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER
+{
+ BYTE Name[16];
+ BYTE Date[12];
+ BYTE UserID[6];
+ BYTE GroupID[6];
+ BYTE Mode[8];
+ BYTE Size[10];
+ BYTE EndHeader[2];
+} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER;
+
+#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+/*
+ * Resource directory stuff
+ */
+typedef struct _IMAGE_RESOURCE_DIRECTORY {
+ DWORD Characteristics;
+ DWORD TimeDateStamp;
+ WORD MajorVersion;
+ WORD MinorVersion;
+ WORD NumberOfNamedEntries;
+ WORD NumberOfIdEntries;
+ /* IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; */
+} IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY;
+
+#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000
+#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000
+
+typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
+ union {
+ struct {
+#ifdef BITFIELDS_BIGENDIAN
+ unsigned NameIsString:1;
+ unsigned NameOffset:31;
+#else
+ unsigned NameOffset:31;
+ unsigned NameIsString:1;
+#endif
+ } DUMMYSTRUCTNAME1;
+ DWORD Name;
+ struct {
+#ifdef WORDS_BIGENDIAN
+ WORD __pad;
+ WORD Id;
+#else
+ WORD Id;
+ WORD __pad;
+#endif
+ } DUMMYSTRUCTNAME2;
+ } DUMMYUNIONNAME1;
+ union {
+ DWORD OffsetToData;
+ struct {
+#ifdef BITFIELDS_BIGENDIAN
+ unsigned DataIsDirectory:1;
+ unsigned OffsetToDirectory:31;
+#else
+ unsigned OffsetToDirectory:31;
+ unsigned DataIsDirectory:1;
+#endif
+ } DUMMYSTRUCTNAME3;
+ } DUMMYUNIONNAME2;
+} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY;
+
+
+typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING {
+ WORD Length;
+ CHAR NameString[ 1 ];
+} IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING;
+
--- /dev/null
+/*
+ * Copyright (C) 2005 Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "usb.h"
+#include "pnp.h"
+#include "wrapndis.h"
+#include "loader.h"
+
+/* Functions callable from the NDIS driver */
+wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo,
+ struct irp *irp);
+wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp);
+wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp);
+
+static NTSTATUS start_pdo(struct device_object *pdo)
+{
+ int i, ret, count, resources_size;
+ struct wrap_device *wd;
+ struct pci_dev *pdev;
+ struct cm_partial_resource_descriptor *entry;
+ struct cm_partial_resource_list *partial_resource_list;
+
+ ENTER1("%p, %p", pdo, pdo->reserved);
+ wd = pdo->reserved;
+ if (ntoskernel_init_device(wd))
+ EXIT1(return STATUS_FAILURE);
+ if (wrap_is_usb_bus(wd->dev_bus)) {
+#ifdef ENABLE_USB
+ if (usb_init_device(wd)) {
+ ntoskernel_exit_device(wd);
+ EXIT1(return STATUS_FAILURE);
+ }
+#endif
+ EXIT1(return STATUS_SUCCESS);
+ }
+ if (!wrap_is_pci_bus(wd->dev_bus))
+ EXIT1(return STATUS_SUCCESS);
+ pdev = wd->pci.pdev;
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ ERROR("couldn't enable PCI device: %x", ret);
+ return STATUS_FAILURE;
+ }
+ ret = pci_request_regions(pdev, DRIVER_NAME);
+ if (ret) {
+ ERROR("couldn't request PCI regions: %x", ret);
+ goto err_enable;
+ }
+ pci_set_power_state(pdev, PCI_D0);
+#ifdef CONFIG_X86_64
+ /* 64-bit broadcom driver doesn't work if DMA is allocated
+ * from over 1GB */
+ if (wd->vendor == 0x14e4) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(30)) ||
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(30)))
+ WARNING("couldn't set DMA mask; this driver "
+ "may not work with more than 1GB RAM");
+ }
+#endif
+ /* IRQ resource entry is filled in from pdev, instead of
+ * pci_resource macros */
+ for (i = count = 0; pci_resource_start(pdev, i); i++)
+ if ((pci_resource_flags(pdev, i) & IORESOURCE_MEM) ||
+ (pci_resource_flags(pdev, i) & IORESOURCE_IO))
+ count++;
+ /* space for entry for IRQ is already in
+ * cm_partial_resource_list */
+ resources_size = sizeof(struct cm_resource_list) +
+ sizeof(struct cm_partial_resource_descriptor) * count;
+ TRACE2("resources: %d, %d", count, resources_size);
+ wd->resource_list = kzalloc(resources_size, GFP_KERNEL);
+ if (!wd->resource_list) {
+ WARNING("couldn't allocate memory");
+ goto err_regions;
+ }
+ wd->resource_list->count = 1;
+ wd->resource_list->list[0].interface_type = PCIBus;
+ /* bus_number is not used by WDM drivers */
+ wd->resource_list->list[0].bus_number = pdev->bus->number;
+
+ partial_resource_list =
+ &wd->resource_list->list->partial_resource_list;
+ partial_resource_list->version = 1;
+ partial_resource_list->revision = 1;
+ partial_resource_list->count = count + 1;
+
+ for (i = count = 0; pci_resource_start(pdev, i); i++) {
+ entry = &partial_resource_list->partial_descriptors[count];
+ TRACE2("%d", count);
+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+ entry->type = CmResourceTypeMemory;
+ entry->flags = CM_RESOURCE_MEMORY_READ_WRITE;
+ entry->share = CmResourceShareDeviceExclusive;
+ } else if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
+ entry->type = CmResourceTypePort;
+ entry->flags = CM_RESOURCE_PORT_IO;
+ entry->share = CmResourceShareDeviceExclusive;
+#if 0
+ } else if (pci_resource_flags(pdev, i) & IORESOURCE_DMA) {
+ /* it looks like no driver uses this resource */
+ typeof(pci_resource_flags(pdev, 0)) flags;
+ entry->type = CmResourceTypeDma;
+ flags = pci_resource_flags(pdev, i);
+ if (flags & IORESOURCE_DMA_TYPEA)
+ entry->flags |= CM_RESOURCE_DMA_TYPE_A;
+ else if (flags & IORESOURCE_DMA_TYPEB)
+ entry->flags |= CM_RESOURCE_DMA_TYPE_B;
+ else if (flags & IORESOURCE_DMA_TYPEF)
+ entry->flags |= CM_RESOURCE_DMA_TYPE_F;
+ if (flags & IORESOURCE_DMA_8BIT)
+ entry->flags |= CM_RESOURCE_DMA_8;
+ else if (flags & IORESOURCE_DMA_16BIT)
+ entry->flags |= CM_RESOURCE_DMA_16;
+ /* what about 32bit DMA? */
+ else if (flags & IORESOURCE_DMA_8AND16BIT)
+ entry->flags |= CM_RESOURCE_DMA_8_AND_16;
+ if (flags & IORESOURCE_DMA_MASTER)
+ entry->flags |= CM_RESOURCE_DMA_BUS_MASTER;
+ entry->u.dma.channel = pci_resource_start(pdev, i);
+ /* what should this be? */
+ entry->u.dma.port = 1;
+#endif
+ } else
+ continue;
+ /* TODO: Add other resource types? */
+ entry->u.generic.start =
+ (ULONG_PTR)pci_resource_start(pdev, i);
+ entry->u.generic.length = pci_resource_len(pdev, i);
+ count++;
+ }
+
+ /* put IRQ resource at the end */
+ entry = &partial_resource_list->partial_descriptors[count++];
+ entry->type = CmResourceTypeInterrupt;
+ entry->flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ /* we assume all devices use shared IRQ */
+ entry->share = CmResourceShareShared;
+ /* as per documentation, interrupt level should be DIRQL, but
+ * examples from DDK as well some drivers, such as AR5211,
+ * RT8180L use interrupt level as interrupt vector also in
+ * NdisMRegisterInterrupt */
+ entry->u.interrupt.level = pdev->irq;
+ entry->u.interrupt.vector = pdev->irq;
+ entry->u.interrupt.affinity = -1;
+
+ TRACE2("resource list count %d, irq: %d",
+ partial_resource_list->count, pdev->irq);
+ pci_set_drvdata(pdev, wd);
+ EXIT1(return STATUS_SUCCESS);
+err_regions:
+ pci_release_regions(pdev);
+err_enable:
+ pci_disable_device(pdev);
+ wd->pci.pdev = NULL;
+ wd->pdo = NULL;
+ EXIT1(return STATUS_FAILURE);
+}
+
+static void remove_pdo(struct device_object *pdo)
+{
+ struct wrap_device *wd = pdo->reserved;
+
+ ntoskernel_exit_device(wd);
+ if (wrap_is_pci_bus(wd->dev_bus)) {
+ struct pci_dev *pdev = wd->pci.pdev;
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ wd->pci.pdev = NULL;
+ pci_set_drvdata(pdev, NULL);
+ } else if (wrap_is_usb_bus(wd->dev_bus)) {
+#ifdef ENABLE_USB
+ usb_exit_device(wd);
+#endif
+ }
+ if (wd->resource_list)
+ kfree(wd->resource_list);
+ wd->resource_list = NULL;
+ return;
+}
+
+static NTSTATUS IoSendIrpTopDev(struct device_object *dev_obj, ULONG major_fn,
+ ULONG minor_fn, struct io_stack_location *sl)
+{
+ NTSTATUS status;
+ struct nt_event event;
+ struct irp *irp;
+ struct io_stack_location *irp_sl;
+ struct device_object *top_dev = IoGetAttachedDeviceReference(dev_obj);
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+ irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, top_dev, NULL, 0, NULL,
+ &event, NULL);
+ irp->io_status.status = STATUS_NOT_IMPLEMENTED;
+ irp->io_status.info = 0;
+ irp_sl = IoGetNextIrpStackLocation(irp);
+ if (sl)
+ memcpy(irp_sl, sl, sizeof(*irp_sl));
+ irp_sl->major_fn = major_fn;
+ irp_sl->minor_fn = minor_fn;
+ status = IoCallDriver(top_dev, irp);
+ if (status == STATUS_PENDING) {
+ KeWaitForSingleObject(&event, Executive, KernelMode,
+ FALSE, NULL);
+ status = irp->io_status.status;
+ }
+ ObDereferenceObject(top_dev);
+ return status;
+}
+
+wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo,
+ struct irp *irp)
+{
+ struct io_stack_location *irp_sl;
+ NTSTATUS status;
+
+ DUMP_IRP(irp);
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+#ifdef ENABLE_USB
+ status = wrap_submit_irp(pdo, irp);
+ IOTRACE("status: %08X", status);
+ if (status != STATUS_PENDING)
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+#else
+ status = irp->io_status.status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+#endif
+ IOEXIT(return status);
+}
+WIN_FUNC_DECL(pdoDispatchDeviceControl,2)
+
+wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp)
+{
+ struct io_stack_location *irp_sl;
+ struct wrap_device *wd;
+ NTSTATUS status;
+#ifdef ENABLE_USB
+ struct usbd_bus_interface_usbdi *usb_intf;
+#endif
+
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+ TRACE2("%p %d:%d", pdo, irp_sl->major_fn, irp_sl->minor_fn);
+ wd = pdo->reserved;
+ switch (irp_sl->minor_fn) {
+ case IRP_MN_START_DEVICE:
+ status = start_pdo(pdo);
+ break;
+ case IRP_MN_QUERY_STOP_DEVICE:
+ case IRP_MN_STOP_DEVICE:
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ status = STATUS_SUCCESS;
+ break;
+ case IRP_MN_REMOVE_DEVICE:
+ remove_pdo(pdo);
+ status = STATUS_SUCCESS;
+ break;
+ case IRP_MN_QUERY_INTERFACE:
+#ifdef ENABLE_USB
+ if (!wrap_is_usb_bus(wd->dev_bus)) {
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+ TRACE2("type: %x, size: %d, version: %d",
+ irp_sl->params.query_intf.type->data1,
+ irp_sl->params.query_intf.size,
+ irp_sl->params.query_intf.version);
+ usb_intf = (struct usbd_bus_interface_usbdi *)
+ irp_sl->params.query_intf.intf;
+ usb_intf->Context = wd;
+ usb_intf->InterfaceReference = USBD_InterfaceReference;
+ usb_intf->InterfaceDereference = USBD_InterfaceDereference;
+ usb_intf->GetUSBDIVersion = USBD_InterfaceGetUSBDIVersion;
+ usb_intf->QueryBusTime = USBD_InterfaceQueryBusTime;
+ usb_intf->SubmitIsoOutUrb = USBD_InterfaceSubmitIsoOutUrb;
+ usb_intf->QueryBusInformation =
+ USBD_InterfaceQueryBusInformation;
+ if (irp_sl->params.query_intf.version >=
+ USB_BUSIF_USBDI_VERSION_1)
+ usb_intf->IsDeviceHighSpeed =
+ USBD_InterfaceIsDeviceHighSpeed;
+ if (irp_sl->params.query_intf.version >=
+ USB_BUSIF_USBDI_VERSION_2)
+ usb_intf->LogEntry = USBD_InterfaceLogEntry;
+ status = STATUS_SUCCESS;
+#else
+ status = STATUS_NOT_IMPLEMENTED;
+#endif
+ break;
+ default:
+ TRACE2("fn %d not implemented", irp_sl->minor_fn);
+ status = STATUS_SUCCESS;
+ break;
+ }
+ irp->io_status.status = status;
+ TRACE2("status: %08X", status);
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ IOEXIT(return status);
+}
+WIN_FUNC_DECL(pdoDispatchPnp,2)
+
+wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp)
+{
+ struct io_stack_location *irp_sl;
+ struct wrap_device *wd;
+ union power_state power_state;
+ struct pci_dev *pdev;
+ NTSTATUS status;
+
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+ wd = pdo->reserved;
+ TRACE2("pdo: %p, fn: %d:%d, wd: %p",
+ pdo, irp_sl->major_fn, irp_sl->minor_fn, wd);
+ switch (irp_sl->minor_fn) {
+ case IRP_MN_WAIT_WAKE:
+ /* TODO: this is not complete/correct */
+ TRACE2("state: %d, completion: %p",
+ irp_sl->params.power.state.system_state,
+ irp_sl->completion_routine);
+ IoMarkIrpPending(irp);
+ status = STATUS_PENDING;
+ break;
+ case IRP_MN_SET_POWER:
+ power_state = irp_sl->params.power.state;
+ if (power_state.device_state == PowerDeviceD0) {
+ TRACE2("resuming %p", wd);
+ if (wrap_is_pci_bus(wd->dev_bus)) {
+ pdev = wd->pci.pdev;
+ pci_restore_state(pdev);
+ if (wd->pci.wake_state == PowerDeviceD3) {
+ pci_enable_wake(wd->pci.pdev,
+ PCI_D3hot, 0);
+ pci_enable_wake(wd->pci.pdev,
+ PCI_D3cold, 0);
+ }
+ pci_set_power_state(pdev, PCI_D0);
+ } else { // usb device
+#ifdef ENABLE_USB
+ wrap_resume_urbs(wd);
+#endif
+ }
+ } else {
+ TRACE2("suspending device %p", wd);
+ if (wrap_is_pci_bus(wd->dev_bus)) {
+ pdev = wd->pci.pdev;
+ pci_save_state(pdev);
+ TRACE2("%d", wd->pci.wake_state);
+ if (wd->pci.wake_state == PowerDeviceD3) {
+ pci_enable_wake(wd->pci.pdev,
+ PCI_D3hot, 1);
+ pci_enable_wake(wd->pci.pdev,
+ PCI_D3cold, 1);
+ }
+ pci_set_power_state(pdev, PCI_D3hot);
+ } else { // usb device
+#ifdef ENABLE_USB
+ wrap_suspend_urbs(wd);
+#endif
+ }
+ }
+ status = STATUS_SUCCESS;
+ break;
+ case IRP_MN_QUERY_POWER:
+ status = STATUS_SUCCESS;
+ break;
+ default:
+ TRACE2("fn %d not implemented", irp_sl->minor_fn);
+ status = STATUS_SUCCESS;
+ break;
+ }
+ irp->io_status.status = status;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ return status;
+}
+WIN_FUNC_DECL(pdoDispatchPower,2)
+
+static NTSTATUS pnp_set_device_power_state(struct wrap_device *wd,
+ enum device_power_state state)
+{
+ NTSTATUS status;
+ struct device_object *pdo;
+ struct io_stack_location irp_sl;
+
+ pdo = wd->pdo;
+ IOTRACE("%p, %p", pdo, IoGetAttachedDevice(pdo));
+ memset(&irp_sl, 0, sizeof(irp_sl));
+ irp_sl.params.power.state.device_state = state;
+ irp_sl.params.power.type = DevicePowerState;
+ if (state > PowerDeviceD0) {
+ status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_QUERY_POWER,
+ &irp_sl);
+ if (status != STATUS_SUCCESS) {
+ TRACE1("query of power to %d returns %08X",
+ state, status);
+ EXIT1(return status);
+ }
+ }
+ status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_SET_POWER, &irp_sl);
+ if (status != STATUS_SUCCESS)
+ WARNING("setting power to %d failed: %08X", state, status);
+ EXIT1(return status);
+}
+
+NTSTATUS pnp_start_device(struct wrap_device *wd)
+{
+ struct device_object *fdo;
+ struct device_object *pdo;
+ struct io_stack_location irp_sl;
+ NTSTATUS status;
+
+ pdo = wd->pdo;
+ /* TODO: for now we use same resources for both translated
+ * resources and raw resources */
+ memset(&irp_sl, 0, sizeof(irp_sl));
+ irp_sl.params.start_device.allocated_resources =
+ wd->resource_list;
+ irp_sl.params.start_device.allocated_resources_translated =
+ wd->resource_list;
+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_START_DEVICE, &irp_sl);
+ fdo = IoGetAttachedDevice(pdo);
+ if (status == STATUS_SUCCESS)
+ fdo->drv_obj->drv_ext->count++;
+ else
+ WARNING("Windows driver couldn't initialize the device (%08X)",
+ status);
+ EXIT1(return status);
+}
+
+NTSTATUS pnp_stop_device(struct wrap_device *wd)
+{
+ struct device_object *pdo;
+ NTSTATUS status;
+
+ pdo = wd->pdo;
+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_STOP_DEVICE,
+ NULL);
+ if (status != STATUS_SUCCESS)
+ WARNING("status: %08X", status);
+ /* for now we ignore query status */
+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_STOP_DEVICE, NULL);
+ if (status != STATUS_SUCCESS)
+ WARNING("status: %08X", status);
+ if (status != STATUS_SUCCESS)
+ WARNING("status: %08X", status);
+ EXIT2(return status);
+}
+
+NTSTATUS pnp_remove_device(struct wrap_device *wd)
+{
+ struct device_object *pdo, *fdo;
+ struct driver_object *fdo_drv_obj;
+ NTSTATUS status;
+
+ pdo = wd->pdo;
+ fdo = IoGetAttachedDevice(pdo);
+ fdo_drv_obj = fdo->drv_obj;
+ TRACE2("%p, %p, %p", pdo, fdo, fdo_drv_obj);
+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_REMOVE_DEVICE,
+ NULL);
+ if (status != STATUS_SUCCESS)
+ WARNING("status: %08X", status);
+
+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE, NULL);
+ if (status != STATUS_SUCCESS)
+ WARNING("status: %08X", status);
+ /* TODO: should we use count in drv_ext or driver's Object
+ * header reference count to keep count of devices associated
+ * with a driver? */
+ if (status == STATUS_SUCCESS)
+ fdo_drv_obj->drv_ext->count--;
+ TRACE1("count: %d", fdo_drv_obj->drv_ext->count);
+ if (fdo_drv_obj->drv_ext->count < 0)
+ WARNING("wrong count: %d", fdo_drv_obj->drv_ext->count);
+ if (fdo_drv_obj->drv_ext->count == 0) {
+ struct wrap_driver *wrap_driver;
+ TRACE1("unloading driver: %p", fdo_drv_obj);
+ wrap_driver =
+ IoGetDriverObjectExtension(fdo_drv_obj,
+ (void *)WRAP_DRIVER_CLIENT_ID);
+ if (fdo_drv_obj->unload)
+ LIN2WIN1(fdo_drv_obj->unload, fdo_drv_obj);
+ if (wrap_driver) {
+ if (down_interruptible(&loader_mutex))
+ WARNING("couldn't obtain loader_mutex");
+ unload_wrap_driver(wrap_driver);
+ up(&loader_mutex);
+ } else
+ ERROR("couldn't get wrap_driver");
+ ObDereferenceObject(fdo_drv_obj);
+ }
+ IoDeleteDevice(pdo);
+ unload_wrap_device(wd);
+ EXIT1(return status);
+}
+
+WIN_FUNC_DECL(IoInvalidDeviceRequest,2)
+
+static struct device_object *alloc_pdo(struct driver_object *drv_obj)
+{
+ struct device_object *pdo;
+ NTSTATUS status ;
+ int i;
+ struct ansi_string ansi_name;
+ struct unicode_string unicode_name;
+
+ RtlInitAnsiString(&ansi_name, "NDISpdo");
+ if (RtlAnsiStringToUnicodeString(&unicode_name, &ansi_name, TRUE) ==
+ STATUS_SUCCESS) {
+ status = IoCreateDevice(drv_obj, 0, &unicode_name,
+ FILE_DEVICE_UNKNOWN,
+ FILE_AUTOGENERATED_DEVICE_NAME,
+ FALSE, &pdo);
+ RtlFreeUnicodeString(&unicode_name);
+ } else {
+ status = IoCreateDevice(drv_obj, 0, NULL,
+ FILE_DEVICE_UNKNOWN,
+ FILE_AUTOGENERATED_DEVICE_NAME,
+ FALSE, &pdo);
+ }
+ TRACE1("%p, %d, %p", drv_obj, status, pdo);
+ if (status != STATUS_SUCCESS)
+ return NULL;
+ /* dispatch routines are called as Windows functions */
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ drv_obj->major_func[i] = WIN_FUNC_PTR(IoInvalidDeviceRequest,2);
+ drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
+ WIN_FUNC_PTR(pdoDispatchDeviceControl,2);
+ drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] =
+ WIN_FUNC_PTR(pdoDispatchDeviceControl,2);
+ drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(pdoDispatchPower,2);
+ drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(pdoDispatchPnp,2);
+ return pdo;
+}
+
+static int wrap_pnp_start_device(struct wrap_device *wd)
+{
+ struct wrap_driver *driver;
+ struct device_object *pdo;
+ struct driver_object *pdo_drv_obj;
+
+ ENTER1("wd: %p", wd);
+
+ if (!((wrap_is_pci_bus(wd->dev_bus)) ||
+ (wrap_is_usb_bus(wd->dev_bus)))) {
+ ERROR("bus type %d (%d) not supported",
+ WRAP_BUS(wd->dev_bus), wd->dev_bus);
+ EXIT1(return -EINVAL);
+ }
+ driver = load_wrap_driver(wd);
+ if (!driver)
+ return -ENODEV;
+
+ wd->driver = driver;
+ wd->dev_bus = WRAP_DEVICE_BUS(driver->dev_type, WRAP_BUS(wd->dev_bus));
+ TRACE1("dev type: %d, bus type: %d, %d", WRAP_DEVICE(wd->dev_bus),
+ WRAP_BUS(wd->dev_bus), wd->dev_bus);
+ TRACE1("%d, %d", driver->dev_type, wrap_is_usb_bus(wd->dev_bus));
+ /* first create pdo */
+ if (wrap_is_pci_bus(wd->dev_bus))
+ pdo_drv_obj = find_bus_driver("PCI");
+ else // if (wrap_is_usb_bus(wd->dev_bus))
+ pdo_drv_obj = find_bus_driver("USB");
+ if (!pdo_drv_obj)
+ return -EINVAL;
+ pdo = alloc_pdo(pdo_drv_obj);
+ if (!pdo)
+ return -ENOMEM;
+ wd->pdo = pdo;
+ pdo->reserved = wd;
+ if (WRAP_DEVICE(wd->dev_bus) == WRAP_NDIS_DEVICE) {
+ if (init_ndis_driver(driver->drv_obj)) {
+ IoDeleteDevice(pdo);
+ return -EINVAL;
+ }
+ }
+ TRACE1("%p", driver->drv_obj->drv_ext->add_device);
+ if (driver->drv_obj->drv_ext->add_device(driver->drv_obj, pdo) !=
+ STATUS_SUCCESS) {
+ IoDeleteDevice(pdo);
+ return -ENOMEM;
+ }
+ if (pnp_start_device(wd) != STATUS_SUCCESS) {
+ /* TODO: we need proper cleanup, to deallocate memory,
+ * for example */
+ pnp_remove_device(wd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * This function should not be marked __devinit because PCI IDs are
+ * added dynamically.
+ */
+int wrap_pnp_start_pci_device(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct load_device load_device;
+ struct wrap_device *wd;
+
+ ENTER1("called for %04x:%04x:%04x:%04x", pdev->vendor, pdev->device,
+ pdev->subsystem_vendor, pdev->subsystem_device);
+
+ load_device.bus = WRAP_PCI_BUS;
+ load_device.vendor = pdev->vendor;
+ load_device.device = pdev->device;
+ load_device.subvendor = pdev->subsystem_vendor;
+ load_device.subdevice = pdev->subsystem_device;
+ wd = load_wrap_device(&load_device);
+ if (!wd)
+ EXIT1(return -ENODEV);
+ wd->pci.pdev = pdev;
+ return wrap_pnp_start_device(wd);
+}
+
+void wrap_pnp_remove_pci_device(struct pci_dev *pdev)
+{
+ struct wrap_device *wd;
+
+ wd = (struct wrap_device *)pci_get_drvdata(pdev);
+ ENTER1("%p, %p", pdev, wd);
+ if (!wd)
+ EXIT1(return);
+ pnp_remove_device(wd);
+}
+
+int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state)
+{
+ struct wrap_device *wd;
+
+ wd = (struct wrap_device *)pci_get_drvdata(pdev);
+ return pnp_set_device_power_state(wd, PowerDeviceD3);
+}
+
+int wrap_pnp_resume_pci_device(struct pci_dev *pdev)
+{
+ struct wrap_device *wd;
+
+ wd = (struct wrap_device *)pci_get_drvdata(pdev);
+ return pnp_set_device_power_state(wd, PowerDeviceD0);
+}
+
+#ifdef ENABLE_USB
+int wrap_pnp_start_usb_device(struct usb_interface *intf,
+ const struct usb_device_id *usb_id)
+{
+ struct wrap_device *wd;
+ int ret;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ ENTER1("%04x, %04x, %04x", udev->descriptor.idVendor,
+ udev->descriptor.idProduct, udev->descriptor.bDeviceClass);
+
+ /* USB device (e.g., RNDIS) may have multiple interfaces;
+ initialize one interface only (is there a way to know which
+ of these interfaces is for network?) */
+
+ if ((wd = get_wrap_device(udev, WRAP_USB_BUS))) {
+ TRACE1("device already initialized: %p", wd);
+ usb_set_intfdata(intf, NULL);
+ ret = 0;
+ } else {
+ struct load_device load_device;
+
+ load_device.bus = WRAP_USB_BUS;
+ load_device.vendor = le16_to_cpu(udev->descriptor.idVendor);
+ load_device.device = le16_to_cpu(udev->descriptor.idProduct);
+ load_device.subvendor = 0;
+ load_device.subdevice = 0;
+ wd = load_wrap_device(&load_device);
+ TRACE2("%p", wd);
+ if (wd) {
+ /* some devices (e.g., TI 4150, RNDIS) need
+ * full reset */
+ ret = usb_reset_device(udev);
+ if (ret)
+ WARNING("reset failed: %d", ret);
+ usb_set_intfdata(intf, wd);
+ wd->usb.intf = intf;
+ wd->usb.udev = udev;
+ ret = wrap_pnp_start_device(wd);
+ } else
+ ret = -ENODEV;
+ }
+
+ TRACE2("ret: %d", ret);
+ if (ret)
+ EXIT1(return ret);
+ else
+ return 0;
+}
+
+void __devexit wrap_pnp_remove_usb_device(struct usb_interface *intf)
+{
+ struct wrap_device *wd;
+
+ wd = (struct wrap_device *)usb_get_intfdata(intf);
+ TRACE1("%p, %p", intf, wd);
+ if (wd == NULL)
+ EXIT1(return);
+ usb_set_intfdata(intf, NULL);
+ wd->usb.intf = NULL;
+ pnp_remove_device(wd);
+}
+
+int wrap_pnp_suspend_usb_device(struct usb_interface *intf, pm_message_t state)
+{
+ struct wrap_device *wd;
+ struct device_object *pdo;
+
+ wd = usb_get_intfdata(intf);
+ ENTER1("%p, %p", intf, wd);
+ if (!wd)
+ EXIT1(return 0);
+ pdo = wd->pdo;
+ if (pnp_set_device_power_state(wd, PowerDeviceD3))
+ return -1;
+ return 0;
+}
+
+int wrap_pnp_resume_usb_device(struct usb_interface *intf)
+{
+ struct wrap_device *wd;
+ wd = usb_get_intfdata(intf);
+ ENTER1("%p, %p", intf, wd);
+ if (!wd)
+ EXIT1(return 0);
+ if (pnp_set_device_power_state(wd, PowerDeviceD0))
+ return -1;
+ return 0;
+}
+
+#endif // USB
--- /dev/null
+/*
+ * Copyright (C) 2005 Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _PNP_H_
+#define _PNP_H_
+
+#include "ntoskernel.h"
+#include "ndis.h"
+#include "wrapndis.h"
+
+NTSTATUS pnp_start_device(struct wrap_device *wd);
+NTSTATUS pnp_stop_device(struct wrap_device *wd);
+NTSTATUS pnp_remove_device(struct wrap_device *wd);
+
+int wrap_pnp_start_pci_device(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+void __devexit wrap_pnp_remove_pci_device(struct pci_dev *pdev);
+int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state);
+int wrap_pnp_resume_pci_device(struct pci_dev *pdev);
+
+#ifdef ENABLE_USB
+int wrap_pnp_start_usb_device(struct usb_interface *intf,
+ const struct usb_device_id *usb_id);
+void wrap_pnp_remove_usb_device(struct usb_interface *intf);
+int wrap_pnp_suspend_usb_device(struct usb_interface *intf,
+ pm_message_t state);
+int wrap_pnp_resume_usb_device(struct usb_interface *intf);
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+#include "ndis.h"
+#include "iw_ndis.h"
+#include "wrapndis.h"
+#include "pnp.h"
+#include "wrapper.h"
+
+#define MAX_PROC_STR_LEN 32
+
+static struct proc_dir_entry *wrap_procfs_entry;
+
+static int procfs_read_ndis_stats(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct ndis_device *wnd = (struct ndis_device *)data;
+ struct ndis_wireless_stats stats;
+ NDIS_STATUS res;
+ ndis_rssi rssi;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi));
+ if (!res)
+ p += sprintf(p, "signal_level=%d dBm\n", (s32)rssi);
+
+ res = mp_query(wnd, OID_802_11_STATISTICS, &stats, sizeof(stats));
+ if (!res) {
+
+ p += sprintf(p, "tx_frames=%Lu\n", stats.tx_frag);
+ p += sprintf(p, "tx_multicast_frames=%Lu\n",
+ stats.tx_multi_frag);
+ p += sprintf(p, "tx_failed=%Lu\n", stats.failed);
+ p += sprintf(p, "tx_retry=%Lu\n", stats.retry);
+ p += sprintf(p, "tx_multi_rerty=%Lu\n", stats.multi_retry);
+ p += sprintf(p, "tx_rtss_success=%Lu\n", stats.rtss_succ);
+ p += sprintf(p, "tx_rtss_fail=%Lu\n", stats.rtss_fail);
+ p += sprintf(p, "ack_fail=%Lu\n", stats.ack_fail);
+ p += sprintf(p, "frame_duplicates=%Lu\n", stats.frame_dup);
+ p += sprintf(p, "rx_frames=%Lu\n", stats.rx_frag);
+ p += sprintf(p, "rx_multicast_frames=%Lu\n",
+ stats.rx_multi_frag);
+ p += sprintf(p, "fcs_errors=%Lu\n", stats.fcs_err);
+ }
+
+ if (p - page > count) {
+ ERROR("wrote %lu bytes (limit is %u)\n",
+ (unsigned long)(p - page), count);
+ *eof = 1;
+ }
+
+ return p - page;
+}
+
+static int procfs_read_ndis_encr(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct ndis_device *wnd = (struct ndis_device *)data;
+ int i, encr_status, auth_mode, infra_mode;
+ NDIS_STATUS res;
+ struct ndis_essid essid;
+ mac_address ap_address;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ res = mp_query(wnd, OID_802_11_BSSID,
+ &ap_address, sizeof(ap_address));
+ if (res)
+ memset(ap_address, 0, ETH_ALEN);
+ p += sprintf(p, "ap_address=%2.2X", ap_address[0]);
+ for (i = 1 ; i < ETH_ALEN ; i++)
+ p += sprintf(p, ":%2.2X", ap_address[i]);
+ p += sprintf(p, "\n");
+
+ res = mp_query(wnd, OID_802_11_SSID, &essid, sizeof(essid));
+ if (!res)
+ p += sprintf(p, "essid=%.*s\n", essid.length, essid.essid);
+
+ res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &encr_status);
+ if (!res) {
+ typeof(&wnd->encr_info.keys[0]) tx_key;
+ p += sprintf(p, "tx_key=%u\n", wnd->encr_info.tx_key_index);
+ p += sprintf(p, "key=");
+ tx_key = &wnd->encr_info.keys[wnd->encr_info.tx_key_index];
+ if (tx_key->length > 0)
+ for (i = 0; i < tx_key->length; i++)
+ p += sprintf(p, "%2.2X", tx_key->key[i]);
+ else
+ p += sprintf(p, "off");
+ p += sprintf(p, "\n");
+ p += sprintf(p, "encr_mode=%d\n", encr_status);
+ }
+ res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &auth_mode);
+ if (!res)
+ p += sprintf(p, "auth_mode=%d\n", auth_mode);
+ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &infra_mode);
+ p += sprintf(p, "mode=%s\n", (infra_mode == Ndis802_11IBSS) ?
+ "adhoc" : (infra_mode == Ndis802_11Infrastructure) ?
+ "managed" : "auto");
+ if (p - page > count) {
+ WARNING("wrote %lu bytes (limit is %u)",
+ (unsigned long)(p - page), count);
+ *eof = 1;
+ }
+
+ return p - page;
+}
+
+static int procfs_read_ndis_hw(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct ndis_device *wnd = (struct ndis_device *)data;
+ struct ndis_configuration config;
+ unsigned int power_mode;
+ NDIS_STATUS res;
+ ndis_tx_power_level tx_power;
+ ULONG bit_rate;
+ ndis_rts_threshold rts_threshold;
+ ndis_fragmentation_threshold frag_threshold;
+ ndis_antenna antenna;
+ ULONG packet_filter;
+ int n;
+ mac_address mac;
+ char *hw_status[] = {"ready", "initializing", "resetting", "closing",
+ "not ready"};
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ res = mp_query_int(wnd, OID_GEN_HARDWARE_STATUS, &n);
+ if (res == NDIS_STATUS_SUCCESS &&
+ n >= 0 && n < sizeof(hw_status) / sizeof(hw_status[0]))
+ p += sprintf(p, "status=%s\n", hw_status[n]);
+
+ res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac));
+ if (!res)
+ p += sprintf(p, "mac: " MACSTRSEP "\n", MAC2STR(mac));
+ res = mp_query(wnd, OID_802_11_CONFIGURATION, &config, sizeof(config));
+ if (!res) {
+ p += sprintf(p, "beacon_period=%u msec\n",
+ config.beacon_period);
+ p += sprintf(p, "atim_window=%u msec\n", config.atim_window);
+ p += sprintf(p, "frequency=%u kHZ\n", config.ds_config);
+ p += sprintf(p, "hop_pattern=%u\n",
+ config.fh_config.hop_pattern);
+ p += sprintf(p, "hop_set=%u\n",
+ config.fh_config.hop_set);
+ p += sprintf(p, "dwell_time=%u msec\n",
+ config.fh_config.dwell_time);
+ }
+
+ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL,
+ &tx_power, sizeof(tx_power));
+ if (!res)
+ p += sprintf(p, "tx_power=%u mW\n", tx_power);
+
+ res = mp_query(wnd, OID_GEN_LINK_SPEED, &bit_rate, sizeof(bit_rate));
+ if (!res)
+ p += sprintf(p, "bit_rate=%u kBps\n", (u32)bit_rate / 10);
+
+ res = mp_query(wnd, OID_802_11_RTS_THRESHOLD,
+ &rts_threshold, sizeof(rts_threshold));
+ if (!res)
+ p += sprintf(p, "rts_threshold=%u bytes\n", rts_threshold);
+
+ res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD,
+ &frag_threshold, sizeof(frag_threshold));
+ if (!res)
+ p += sprintf(p, "frag_threshold=%u bytes\n", frag_threshold);
+
+ res = mp_query_int(wnd, OID_802_11_POWER_MODE, &power_mode);
+ if (!res)
+ p += sprintf(p, "power_mode=%s\n",
+ (power_mode == NDIS_POWER_OFF) ? "always_on" :
+ (power_mode == NDIS_POWER_MAX) ?
+ "max_savings" : "min_savings");
+
+ res = mp_query(wnd, OID_802_11_NUMBER_OF_ANTENNAS,
+ &antenna, sizeof(antenna));
+ if (!res)
+ p += sprintf(p, "num_antennas=%u\n", antenna);
+
+ res = mp_query(wnd, OID_802_11_TX_ANTENNA_SELECTED,
+ &antenna, sizeof(antenna));
+ if (!res)
+ p += sprintf(p, "tx_antenna=%u\n", antenna);
+
+ res = mp_query(wnd, OID_802_11_RX_ANTENNA_SELECTED,
+ &antenna, sizeof(antenna));
+ if (!res)
+ p += sprintf(p, "rx_antenna=%u\n", antenna);
+
+ p += sprintf(p, "encryption_modes=%s%s%s%s%s%s%s\n",
+ test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ?
+ "WEP" : "none",
+
+ test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ?
+ "; TKIP with WPA" : "",
+ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
+ ", WPA2" : "",
+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
+ ", WPA2PSK" : "",
+
+ test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ?
+ "; AES/CCMP with WPA" : "",
+ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
+ ", WPA2" : "",
+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
+ ", WPA2PSK" : "");
+
+ res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter);
+ if (!res) {
+ if (packet_filter != wnd->packet_filter)
+ WARNING("wrong packet_filter? 0x%08x, 0x%08x\n",
+ packet_filter, wnd->packet_filter);
+ p += sprintf(p, "packet_filter: 0x%08x\n", packet_filter);
+ }
+ if (p - page > count) {
+ WARNING("wrote %lu bytes (limit is %u)",
+ (unsigned long)(p - page), count);
+ *eof = 1;
+ }
+
+ return p - page;
+}
+
+static int procfs_read_ndis_settings(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct ndis_device *wnd = (struct ndis_device *)data;
+ struct wrap_device_setting *setting;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ p += sprintf(p, "hangcheck_interval=%d\n",
+ hangcheck_interval == 0 ?
+ (int)(wnd->hangcheck_interval / HZ) : -1);
+
+ list_for_each_entry(setting, &wnd->wd->settings, list) {
+ p += sprintf(p, "%s=%s\n", setting->name, setting->value);
+ }
+
+ list_for_each_entry(setting, &wnd->wd->driver->settings, list) {
+ p += sprintf(p, "%s=%s\n", setting->name, setting->value);
+ }
+
+ return p - page;
+}
+
+static int procfs_write_ndis_settings(struct file *file, const char __user *buf,
+ unsigned long count, void *data)
+{
+ struct ndis_device *wnd = (struct ndis_device *)data;
+ char setting[MAX_PROC_STR_LEN], *p;
+ unsigned int i;
+ NDIS_STATUS res;
+
+ if (count > MAX_PROC_STR_LEN)
+ return -EINVAL;
+
+ memset(setting, 0, sizeof(setting));
+ if (copy_from_user(setting, buf, count))
+ return -EFAULT;
+
+ if ((p = strchr(setting, '\n')))
+ *p = 0;
+
+ if ((p = strchr(setting, '=')))
+ *p = 0;
+
+ if (!strcmp(setting, "hangcheck_interval")) {
+ if (!p)
+ return -EINVAL;
+ p++;
+ i = simple_strtol(p, NULL, 10);
+ hangcheck_del(wnd);
+ if (i > 0) {
+ wnd->hangcheck_interval = i * HZ;
+ hangcheck_add(wnd);
+ }
+ } else if (!strcmp(setting, "suspend")) {
+ if (!p)
+ return -EINVAL;
+ p++;
+ i = simple_strtol(p, NULL, 10);
+ if (i <= 0 || i > 3)
+ return -EINVAL;
+ if (wrap_is_pci_bus(wnd->wd->dev_bus))
+ i = wrap_pnp_suspend_pci_device(wnd->wd->pci.pdev,
+ PMSG_SUSPEND);
+ else
+#ifdef ENABLE_USB
+ i = wrap_pnp_suspend_usb_device(wnd->wd->usb.intf,
+ PMSG_SUSPEND);
+#else
+ i = -1;
+#endif
+ if (i)
+ return -EINVAL;
+ } else if (!strcmp(setting, "resume")) {
+ if (wrap_is_pci_bus(wnd->wd->dev_bus))
+ i = wrap_pnp_resume_pci_device(wnd->wd->pci.pdev);
+ else
+#ifdef ENABLE_USB
+ i = wrap_pnp_resume_usb_device(wnd->wd->usb.intf);
+#else
+ i = -1;
+#endif
+ if (i)
+ return -EINVAL;
+ } else if (!strcmp(setting, "stats_enabled")) {
+ if (!p)
+ return -EINVAL;
+ p++;
+ i = simple_strtol(p, NULL, 10);
+ if (i > 0)
+ wnd->iw_stats_enabled = TRUE;
+ else
+ wnd->iw_stats_enabled = FALSE;
+ } else if (!strcmp(setting, "packet_filter")) {
+ if (!p)
+ return -EINVAL;
+ p++;
+ i = simple_strtol(p, NULL, 10);
+ res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, i);
+ if (res)
+ WARNING("setting packet_filter failed: %08X", res);
+ } else if (!strcmp(setting, "reinit")) {
+ if (ndis_reinit(wnd) != NDIS_STATUS_SUCCESS)
+ return -EFAULT;
+ } else {
+ struct ndis_configuration_parameter param;
+ struct unicode_string key;
+ struct ansi_string ansi;
+
+ if (!p)
+ return -EINVAL;
+ p++;
+ RtlInitAnsiString(&ansi, p);
+ if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi,
+ TRUE) != STATUS_SUCCESS)
+ EXIT1(return -EFAULT);
+ param.type = NdisParameterString;
+ RtlInitAnsiString(&ansi, setting);
+ if (RtlAnsiStringToUnicodeString(&key, &ansi,
+ TRUE) != STATUS_SUCCESS) {
+ RtlFreeUnicodeString(¶m.data.string);
+ EXIT1(return -EINVAL);
+ }
+ NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m);
+ RtlFreeUnicodeString(&key);
+ RtlFreeUnicodeString(¶m.data.string);
+ if (res != NDIS_STATUS_SUCCESS)
+ return -EFAULT;
+ }
+ return count;
+}
+
+int wrap_procfs_add_ndis_device(struct ndis_device *wnd)
+{
+ struct proc_dir_entry *procfs_entry;
+
+ if (wrap_procfs_entry == NULL)
+ return -ENOMEM;
+
+ if (wnd->procfs_iface) {
+ ERROR("%s already registered?", wnd->netdev_name);
+ return -EINVAL;
+ }
+ wnd->procfs_iface = proc_mkdir(wnd->netdev_name, wrap_procfs_entry);
+ if (wnd->procfs_iface == NULL) {
+ ERROR("couldn't create proc directory");
+ return -ENOMEM;
+ }
+ wnd->procfs_iface->uid = proc_uid;
+ wnd->procfs_iface->gid = proc_gid;
+
+ procfs_entry = create_proc_entry("hw", S_IFREG | S_IRUSR | S_IRGRP,
+ wnd->procfs_iface);
+ if (procfs_entry == NULL) {
+ ERROR("couldn't create proc entry for 'hw'");
+ goto err_hw;
+ } else {
+ procfs_entry->uid = proc_uid;
+ procfs_entry->gid = proc_gid;
+ procfs_entry->data = wnd;
+ procfs_entry->read_proc = procfs_read_ndis_hw;
+ }
+
+ procfs_entry = create_proc_entry("stats", S_IFREG | S_IRUSR | S_IRGRP,
+ wnd->procfs_iface);
+ if (procfs_entry == NULL) {
+ ERROR("couldn't create proc entry for 'stats'");
+ goto err_stats;
+ } else {
+ procfs_entry->uid = proc_uid;
+ procfs_entry->gid = proc_gid;
+ procfs_entry->data = wnd;
+ procfs_entry->read_proc = procfs_read_ndis_stats;
+ }
+
+ procfs_entry = create_proc_entry("encr", S_IFREG | S_IRUSR | S_IRGRP,
+ wnd->procfs_iface);
+ if (procfs_entry == NULL) {
+ ERROR("couldn't create proc entry for 'encr'");
+ goto err_encr;
+ } else {
+ procfs_entry->uid = proc_uid;
+ procfs_entry->gid = proc_gid;
+ procfs_entry->data = wnd;
+ procfs_entry->read_proc = procfs_read_ndis_encr;
+ }
+
+ procfs_entry = create_proc_entry("settings", S_IFREG |
+ S_IRUSR | S_IRGRP |
+ S_IWUSR | S_IWGRP, wnd->procfs_iface);
+ if (procfs_entry == NULL) {
+ ERROR("couldn't create proc entry for 'settings'");
+ goto err_settings;
+ } else {
+ procfs_entry->uid = proc_uid;
+ procfs_entry->gid = proc_gid;
+ procfs_entry->data = wnd;
+ procfs_entry->read_proc = procfs_read_ndis_settings;
+ procfs_entry->write_proc = procfs_write_ndis_settings;
+ }
+ return 0;
+
+err_settings:
+ remove_proc_entry("encr", wnd->procfs_iface);
+err_encr:
+ remove_proc_entry("stats", wnd->procfs_iface);
+err_stats:
+ remove_proc_entry("hw", wnd->procfs_iface);
+err_hw:
+ remove_proc_entry(wnd->netdev_name, wrap_procfs_entry);
+ wnd->procfs_iface = NULL;
+ return -ENOMEM;
+}
+
+void wrap_procfs_remove_ndis_device(struct ndis_device *wnd)
+{
+ struct proc_dir_entry *procfs_iface = xchg(&wnd->procfs_iface, NULL);
+
+ if (procfs_iface == NULL)
+ return;
+ remove_proc_entry("hw", procfs_iface);
+ remove_proc_entry("stats", procfs_iface);
+ remove_proc_entry("encr", procfs_iface);
+ remove_proc_entry("settings", procfs_iface);
+ if (wrap_procfs_entry)
+ remove_proc_entry(wnd->netdev_name, wrap_procfs_entry);
+}
+
+static int procfs_read_debug(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ enum alloc_type type;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+ p += sprintf(p, "%d\n", debug);
+ type = 0;
+#ifdef ALLOC_DEBUG
+ for (type = 0; type < ALLOC_TYPE_MAX; type++)
+ p += sprintf(p, "total size of allocations in %d: %d\n",
+ type, alloc_size(type));
+#endif
+ return p - page;
+}
+
+static int procfs_write_debug(struct file *file, const char __user *buf,
+ unsigned long count, void *data)
+{
+ int i;
+ char setting[MAX_PROC_STR_LEN], *p;
+
+ if (count > MAX_PROC_STR_LEN)
+ return -EINVAL;
+
+ memset(setting, 0, sizeof(setting));
+ if (copy_from_user(setting, buf, count))
+ return -EFAULT;
+
+ if ((p = strchr(setting, '\n')))
+ *p = 0;
+
+ if ((p = strchr(setting, '=')))
+ *p = 0;
+
+ i = simple_strtol(setting, NULL, 10);
+ if (i >= 0 && i < 10)
+ debug = i;
+ else
+ return -EINVAL;
+ return count;
+}
+
+int wrap_procfs_init(void)
+{
+ struct proc_dir_entry *procfs_entry;
+
+ wrap_procfs_entry = proc_mkdir(DRIVER_NAME, proc_net_root);
+ if (wrap_procfs_entry == NULL) {
+ ERROR("couldn't create procfs directory");
+ return -ENOMEM;
+ }
+ wrap_procfs_entry->uid = proc_uid;
+ wrap_procfs_entry->gid = proc_gid;
+
+ procfs_entry = create_proc_entry("debug", S_IFREG | S_IRUSR | S_IRGRP,
+ wrap_procfs_entry);
+ if (procfs_entry == NULL) {
+ ERROR("couldn't create proc entry for 'debug'");
+ return -ENOMEM;
+ } else {
+ procfs_entry->uid = proc_uid;
+ procfs_entry->gid = proc_gid;
+ procfs_entry->read_proc = procfs_read_debug;
+ procfs_entry->write_proc = procfs_write_debug;
+ }
+ return 0;
+}
+
+void wrap_procfs_remove(void)
+{
+ if (wrap_procfs_entry == NULL)
+ return;
+ remove_proc_entry("debug", wrap_procfs_entry);
+ remove_proc_entry(DRIVER_NAME, proc_net_root);
+}
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ntoskernel.h"
+#include "rtl_exports.h"
+
+wstdcall SIZE_T WIN_FUNC(RtlCompareMemory,3)
+ (const void *a, const void *b, SIZE_T len)
+{
+ size_t i;
+ char *x, *y;
+
+ x = (char *)a;
+ y = (char *)b;
+ /* MSDN says this should return number of bytes that compare as
+ * equal. This can be interpretted as either all bytes that are
+ * equal in 'len' bytes or that only until the bytes compare as
+ * not equal. Initially we had it the former way, but Realtek driver
+ * doesn't like it that way - it takes many attempts to associate
+ * with WPA. ReactOS returns the number of bytes that are equal
+ * upto when they compare as not equal.
+ * According to lords at #reactos, that is the way it should be
+ * and that msdn is wrong about it!
+ */
+ for (i = 0; i < len && x[i] == y[i]; i++)
+ ;
+ return i;
+}
+
+wstdcall void WIN_FUNC(RtlCopyMemory,3)
+ (void *dst, const void *src, SIZE_T length)
+{
+ memcpy(dst, src, length);
+}
+
+wstdcall void WIN_FUNC(RtlZeroMemory,2)
+ (void *dst, SIZE_T length)
+{
+ memset(dst, 0, length);
+}
+
+wstdcall void WIN_FUNC(RtlSecureZeroMemory,2)
+ (void *dst, SIZE_T length)
+{
+ memset(dst, 0, length);
+}
+
+wstdcall void WIN_FUNC(RtlFillMemory,3)
+ (void *dest, SIZE_T length, UCHAR fill)
+{
+ memset(dest, fill, length);
+}
+
+wstdcall void WIN_FUNC(RtlMoveMemory,3)
+ (void *dest, const void *src, SIZE_T length)
+{
+ memmove(dest, src, length);
+}
+
+wstdcall LONG WIN_FUNC(RtlCompareString,3)
+ (const struct ansi_string *s1, const struct ansi_string *s2,
+ BOOLEAN case_insensitive)
+{
+ unsigned int len;
+ LONG ret = 0;
+ const char *p1, *p2;
+
+ ENTER2("");
+ len = min(s1->length, s2->length);
+ p1 = s1->buf;
+ p2 = s2->buf;
+ if (case_insensitive)
+ while (!ret && len--)
+ ret = toupper(*p1++) - toupper(*p2++);
+ else
+ while (!ret && len--)
+ ret = *p1++ - *p2++;
+ if (!ret)
+ ret = s1->length - s2->length;
+ EXIT2(return ret);
+}
+
+wstdcall LONG WIN_FUNC(RtlCompareUnicodeString,3)
+ (const struct unicode_string *s1, const struct unicode_string *s2,
+ BOOLEAN case_insensitive)
+{
+ unsigned int len;
+ LONG ret = 0;
+ const wchar_t *p1, *p2;
+
+ ENTER2("");
+
+ len = min(s1->length, s2->length) / sizeof(wchar_t);
+ p1 = s1->buf;
+ p2 = s2->buf;
+ if (case_insensitive)
+ while (!ret && len--)
+ ret = toupper((u8)*p1++) - toupper((u8)*p2++);
+ else
+ while (!ret && len--)
+ ret = (u8)*p1++ - (u8)*p2++;
+ if (!ret)
+ ret = s1->length - s2->length;
+ TRACE2("len: %d, ret: %d", len, ret);
+ EXIT2(return ret);
+}
+
+wstdcall BOOLEAN WIN_FUNC(RtlEqualString,3)
+ (const struct ansi_string *s1, const struct ansi_string *s2,
+ BOOLEAN case_insensitive)
+{
+ ENTER1("");
+ if (s1->length != s2->length)
+ return FALSE;
+ return !RtlCompareString(s1, s2, case_insensitive);
+}
+
+wstdcall BOOLEAN WIN_FUNC(RtlEqualUnicodeString,3)
+ (const struct unicode_string *s1, const struct unicode_string *s2,
+ BOOLEAN case_insensitive)
+{
+ if (s1->length != s2->length)
+ return FALSE;
+ return !RtlCompareUnicodeString(s1, s2, case_insensitive);
+}
+
+wstdcall void WIN_FUNC(RtlCopyUnicodeString,2)
+ (struct unicode_string *dst, struct unicode_string *src)
+{
+ ENTER1("%p, %p", dst, src);
+ if (src && src->buf && dst->buf) {
+ dst->length = min(src->length, dst->max_length);
+ memcpy(dst->buf, src->buf, dst->length);
+ if (dst->length < dst->max_length)
+ dst->buf[dst->length / sizeof(dst->buf[0])] = 0;
+ } else
+ dst->length = 0;
+ EXIT1(return);
+}
+
+wstdcall void WIN_FUNC(RtlCopyString,2)
+ (struct ansi_string *dst, struct ansi_string *src)
+{
+ ENTER1("%p, %p", dst, src);
+ if (src && src->buf && dst->buf) {
+ dst->length = min(src->length, dst->max_length);
+ memcpy(dst->buf, src->buf, dst->length);
+ if (dst->length < dst->max_length)
+ dst->buf[dst->length] = 0;
+ } else
+ dst->length = 0;
+ EXIT1(return);
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeToString,2)
+ (struct unicode_string *dst, wchar_t *src)
+{
+ if (src) {
+ int len;
+ for (len = 0; src[len]; len++)
+ ;
+ if (dst->length + (len * sizeof(dst->buf[0])) > dst->max_length)
+ return STATUS_BUFFER_TOO_SMALL;
+ memcpy(&dst->buf[dst->length], src, len * sizeof(dst->buf[0]));
+ dst->length += len * sizeof(dst->buf[0]);
+ if (dst->max_length > dst->length)
+ dst->buf[dst->length / sizeof(dst->buf[0])] = 0;
+ }
+ return STATUS_SUCCESS;
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeStringToString,2)
+ (struct unicode_string *dst, struct unicode_string *src)
+{
+ if (dst->max_length < src->length + dst->length)
+ return STATUS_BUFFER_TOO_SMALL;
+ if (src->length) {
+ memcpy(&dst->buf[dst->length], src->buf, src->length);
+ dst->length += src->length;
+ if (dst->max_length > dst->length)
+ dst->buf[dst->length / sizeof(dst->buf[0])] = 0;
+ }
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall ULONG WIN_FUNC(RtlxAnsiStringToUnicodeSize,1)
+ (const struct ansi_string *string)
+{
+ int i;
+
+ for (i = 0; i < string->max_length && string->buf[i]; i++)
+ ;
+ return i * sizeof(wchar_t);
+}
+
+wstdcall ULONG WIN_FUNC(RtlxUnicodeStringToAnsiSize,1)
+ (const struct unicode_string *string)
+{
+ int i;
+
+ for (i = 0; i < string->max_length && string->buf[i]; i++)
+ ;
+ return i;
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlAnsiStringToUnicodeString,3)
+ (struct unicode_string *dst, const struct ansi_string *src,
+ BOOLEAN alloc)
+{
+ int i, n;
+
+ n = RtlxAnsiStringToUnicodeSize(src);
+ TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length,
+ src->max_length, src->buf);
+ if (alloc == TRUE) {
+#if 0
+ if (n == 0) {
+ dst->length = dst->max_length = 0;
+ dst->buf = NULL;
+ EXIT2(return STATUS_SUCCESS);
+ }
+#endif
+ dst->max_length = n + sizeof(dst->buf[0]);
+ dst->buf = ExAllocatePoolWithTag(NonPagedPool,
+ dst->max_length, 0);
+ if (!dst->buf) {
+ dst->max_length = dst->length = 0;
+ EXIT2(return STATUS_NO_MEMORY);
+ }
+ } else if (dst->max_length < n)
+ EXIT2(return STATUS_BUFFER_TOO_SMALL);
+
+ dst->length = n;
+ n /= sizeof(dst->buf[0]);
+ for (i = 0; i < n; i++)
+ dst->buf[i] = src->buf[i];
+ if (i * sizeof(dst->buf[0]) < dst->max_length)
+ dst->buf[i] = 0;
+ TRACE2("dst: length: %d, max_length: %d, string: %p",
+ dst->length, dst->max_length, src->buf);
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToAnsiString,3)
+ (struct ansi_string *dst, const struct unicode_string *src,
+ BOOLEAN alloc)
+{
+ int i, n;
+
+ n = RtlxUnicodeStringToAnsiSize(src);
+ TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length,
+ src->max_length, src->buf);
+ if (alloc == TRUE) {
+#if 0
+ if (n == 0) {
+ dst->length = dst->max_length = 0;
+ dst->buf = NULL;
+ EXIT2(return STATUS_SUCCESS);
+ }
+#endif
+ dst->max_length = n + sizeof(dst->buf[0]);
+ dst->buf = ExAllocatePoolWithTag(NonPagedPool,
+ dst->max_length, 0);
+ if (!dst->buf) {
+ dst->max_length = dst->length = 0;
+ EXIT1(return STATUS_NO_MEMORY);
+ }
+ } else if (dst->max_length < n)
+ EXIT2(return STATUS_BUFFER_TOO_SMALL);
+
+ dst->length = n;
+ for (i = 0; i < n; i++)
+ dst->buf[i] = src->buf[i];
+ if (i < dst->max_length)
+ dst->buf[i] = 0;
+ TRACE2("string: %p, len: %d(%d)", dst->buf, dst->length,
+ dst->max_length);
+ EXIT2(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToInteger,3)
+ (struct unicode_string *ustring, ULONG base, ULONG *value)
+{
+ int i, sign = 1;
+ ULONG res;
+ typeof(ustring->buf) string;
+
+ if (ustring->length == 0) {
+ *value = 0;
+ return STATUS_SUCCESS;
+ }
+
+ string = ustring->buf;
+ i = 0;
+ while (i < (ustring->length / sizeof(*string)) && string[i] == ' ')
+ i++;
+ if (string[i] == '+')
+ i++;
+ else if (string[i] == '-') {
+ i++;
+ sign = -1;
+ }
+ if (base == 0) {
+ base = 10;
+ if (i <= ((ustring->length / sizeof(*string)) - 2) &&
+ string[i] == '0') {
+ i++;
+ if (string[i] == 'b') {
+ base = 2;
+ i++;
+ } else if (string[i] == 'o') {
+ base = 8;
+ i++;
+ } else if (string[i] == 'x') {
+ base = 16;
+ i++;
+ }
+ }
+ }
+ if (!(base == 2 || base == 8 || base == 10 || base == 16))
+ EXIT2(return STATUS_INVALID_PARAMETER);
+
+ for (res = 0; i < (ustring->length / sizeof(*string)); i++) {
+ int v;
+ if (isdigit((char)string[i]))
+ v = string[i] - '0';
+ else if (isxdigit((char)string[i]))
+ v = tolower((char)string[i]) - 'a' + 10;
+ else
+ v = base;
+ if (v >= base)
+ EXIT2(return STATUS_INVALID_PARAMETER);
+ res = res * base + v;
+ }
+ *value = sign * res;
+ EXIT3(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlCharToInteger,3)
+ (const char *string, ULONG base, ULONG *value)
+{
+ int sign = 1;
+ ULONG res;
+
+ if (!string || !value)
+ EXIT2(return STATUS_INVALID_PARAMETER);
+ while (*string == ' ')
+ string++;
+ if (*string == '+')
+ string++;
+ else if (*string == '-') {
+ string++;
+ sign = -1;
+ }
+ if (base == 0) {
+ base = 10;
+ if (*string == '0') {
+ string++;
+ if (*string == 'b') {
+ base = 2;
+ string++;
+ } else if (*string == 'o') {
+ base = 8;
+ string++;
+ } else if (*string == 'x') {
+ base = 16;
+ string++;
+ }
+ }
+ }
+ if (!(base == 2 || base == 8 || base == 10 || base == 16))
+ EXIT2(return STATUS_INVALID_PARAMETER);
+
+ for (res = 0; *string; string++) {
+ int v;
+ if (isdigit(*string))
+ v = *string - '0';
+ else if (isxdigit(*string))
+ v = tolower(*string) - 'a' + 10;
+ else
+ v = base;
+ if (v >= base)
+ EXIT2(return STATUS_INVALID_PARAMETER);
+ res = res * base + v;
+ }
+ *value = sign * res;
+ EXIT3(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlIntegerToUnicodeString,3)
+ (ULONG value, ULONG base, struct unicode_string *ustring)
+{
+ typeof(ustring->buf) buf = ustring->buf;
+ int i;
+
+ if (base == 0)
+ base = 10;
+ if (!(base == 2 || base == 8 || base == 10 || base == 16))
+ return STATUS_INVALID_PARAMETER;
+ for (i = 0; value && i < ustring->max_length / sizeof(*buf); i++) {
+ int r;
+ r = value % base;
+ value /= base;
+ if (r < 10)
+ buf[i] = r + '0';
+ else
+ buf[i] = r + 'a' - 10;
+ }
+ if (value)
+ return STATUS_BUFFER_OVERFLOW;
+ ustring->length = i * sizeof(*buf);
+ return STATUS_SUCCESS;
+}
+
+wstdcall LARGE_INTEGER WIN_FUNC(RtlConvertUlongToLargeInteger,1)
+ (ULONG ul)
+{
+ LARGE_INTEGER li = ul;
+ return li;
+}
+
+wfastcall USHORT WIN_FUNC(RtlUshortByteSwap,1)
+ (USHORT src)
+{
+ return __swab16(src);
+}
+
+wfastcall ULONG WIN_FUNC(RtlUlongByteSwap,1)
+ (ULONG src)
+{
+ /* ULONG is 32 bits for both 32-bit and 64-bit architectures */
+ return __swab32(src);
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlUpcaseUnicodeString,3)
+ (struct unicode_string *dst, struct unicode_string *src, BOOLEAN alloc)
+{
+ USHORT i, n;
+
+ if (alloc) {
+ dst->buf = ExAllocatePoolWithTag(NonPagedPool, src->length, 0);
+ if (dst->buf)
+ dst->max_length = src->length;
+ else
+ EXIT2(return STATUS_NO_MEMORY);
+ } else {
+ if (dst->max_length < src->length)
+ EXIT2(return STATUS_BUFFER_OVERFLOW);
+ }
+
+ n = src->length / sizeof(src->buf[0]);
+ for (i = 0; i < n; i++)
+ dst->buf[i] = toupper(src->buf[i]);
+
+ dst->length = src->length;
+ EXIT3(return STATUS_SUCCESS);
+}
+
+wstdcall void WIN_FUNC(RtlInitUnicodeString,2)
+ (struct unicode_string *dst, const wchar_t *src)
+{
+ ENTER2("%p", dst);
+ if (dst == NULL)
+ EXIT1(return);
+ if (src == NULL) {
+ dst->max_length = dst->length = 0;
+ dst->buf = NULL;
+ } else {
+ int i;
+ for (i = 0; (char)src[i]; i++)
+ ;
+ dst->buf = (typeof(dst->buf))src;
+ dst->length = i * sizeof(dst->buf[0]);
+ dst->max_length = (i + 1) * sizeof(dst->buf[0]);
+ }
+ EXIT1(return);
+}
+
+wstdcall void WIN_FUNC(RtlInitAnsiString,2)
+ (struct ansi_string *dst, const char *src)
+{
+ ENTER2("%p", dst);
+ if (dst == NULL)
+ EXIT2(return);
+ if (src == NULL) {
+ dst->max_length = dst->length = 0;
+ dst->buf = NULL;
+ } else {
+ int i;
+ for (i = 0; src[i]; i++)
+ ;
+ dst->buf = (typeof(dst->buf))src;
+ dst->length = i;
+ dst->max_length = i + 1;
+ }
+ TRACE2("%p", dst->buf);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(RtlInitString,2)
+ (struct ansi_string *dst, const char *src)
+{
+ ENTER2("%p", dst);
+ RtlInitAnsiString(dst, src);
+ EXIT2(return);
+}
+
+wstdcall void WIN_FUNC(RtlFreeUnicodeString,1)
+ (struct unicode_string *string)
+{
+ ENTER2("%p", string);
+ if (string == NULL)
+ return;
+ if (string->buf)
+ ExFreePool(string->buf);
+ string->length = string->max_length = 0;
+ string->buf = NULL;
+ return;
+}
+
+wstdcall void WIN_FUNC(RtlFreeAnsiString,1)
+ (struct ansi_string *string)
+{
+ ENTER2("%p", string);
+ if (string == NULL)
+ return;
+ if (string->buf)
+ ExFreePool(string->buf);
+ string->length = string->max_length = 0;
+ string->buf = NULL;
+ return;
+}
+
+/* guid string is of the form: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
+wstdcall NTSTATUS WIN_FUNC(RtlGUIDFromString,2)
+ (struct unicode_string *guid_string, struct guid *guid)
+{
+ struct ansi_string ansi;
+ NTSTATUS ret;
+ int i, j, k, l, m;
+
+ ret = RtlUnicodeStringToAnsiString(&ansi, guid_string, TRUE);
+ if (ret != STATUS_SUCCESS)
+ return ret;
+ if (ansi.length != 37 || ansi.buf[0] != '{' ||
+ ansi.buf[36] != '}' || ansi.buf[9] != '-' ||
+ ansi.buf[14] != '-' || ansi.buf[19] != '-' ||
+ ansi.buf[24] != '-') {
+ RtlFreeAnsiString(&ansi);
+ EXIT2(return STATUS_INVALID_PARAMETER);
+ }
+ memcpy(&guid->data4, &ansi.buf[29], sizeof(guid->data3));
+ /* set end of data3 for scanf */
+ ansi.buf[29] = 0;
+ if (sscanf(&ansi.buf[1], "%x", &i) == 1 &&
+ sscanf(&ansi.buf[10], "%x", &j) == 1 &&
+ sscanf(&ansi.buf[15], "%x", &k) == 1 &&
+ sscanf(&ansi.buf[20], "%x", &l) == 1 &&
+ sscanf(&ansi.buf[25], "%x", &m) == 1) {
+ guid->data1 = (i << 16) | (j < 8) | k;
+ guid->data2 = l;
+ guid->data3 = m;
+ ret = STATUS_SUCCESS;
+ } else
+ ret = STATUS_INVALID_PARAMETER;
+ RtlFreeAnsiString(&ansi);
+ return ret;
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlQueryRegistryValues,5)
+ (ULONG relative, wchar_t *path, struct rtl_query_registry_table *tbl,
+ void *context, void *env)
+{
+ struct ansi_string ansi;
+ struct unicode_string unicode;
+ NTSTATUS status, ret;
+ static int i = 0;
+
+ ENTER3("%x, %p", relative, tbl);
+// TODO();
+
+ RtlInitUnicodeString(&unicode, path);
+ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) ==
+ STATUS_SUCCESS) {
+ TRACE2("%s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ ret = STATUS_SUCCESS;
+ for (; tbl->name; tbl++) {
+ RtlInitUnicodeString(&unicode, tbl->name);
+ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) ==
+ STATUS_SUCCESS) {
+ TRACE2("name: %s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ TRACE2("flags: %08X", tbl->flags);
+ if (tbl->flags == RTL_QUERY_REGISTRY_DIRECT) {
+ TRACE2("type: %08X", tbl->def_type);
+ if (tbl->def_type == REG_DWORD) {
+ /* Atheros USB driver needs this, but
+ * don't know where and how to get its
+ * value */
+ if (tbl->def_data) {
+ TRACE2("def_data: %x",
+ *(int *)tbl->def_data);
+ *(DWORD *)tbl->context = 0x5f292a + i++;
+// *(DWORD *)tbl->def_data;
+ } else
+ *(DWORD *)tbl->context = 0x2345dbe;
+ }
+ } else {
+ void *data;
+ ULONG type, length;
+
+ if (!tbl->query_func) {
+ ERROR("oops: no query_func");
+ ret = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ if (tbl->flags & RTL_QUERY_REGISTRY_NOVALUE) {
+ data = NULL;
+ type = REG_NONE;
+ length = 0;
+ } else {
+ data = tbl->def_data;
+ type = tbl->def_type;
+ length = tbl->def_length;;
+ }
+ TRACE2("calling query_func: %p", tbl->query_func);
+ status = LIN2WIN6(tbl->query_func, tbl->name, type,
+ data, length, context, env);
+ TRACE2("status: %08X", status);
+ if (status) {
+ if (status == STATUS_BUFFER_TOO_SMALL)
+ ret = STATUS_BUFFER_TOO_SMALL;
+ else
+ EXIT2(return STATUS_INVALID_PARAMETER);
+ }
+ }
+ }
+ EXIT3(return ret);
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlWriteRegistryValue,6)
+ (ULONG relative, wchar_t *path, wchar_t *name, ULONG type,
+ void *data, ULONG length)
+{
+ struct ansi_string ansi;
+ struct unicode_string unicode;
+
+ ENTER3("%d", relative);
+ TODO();
+
+ RtlInitUnicodeString(&unicode, path);
+ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) ==
+ STATUS_SUCCESS) {
+ TRACE2("%s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ RtlInitUnicodeString(&unicode, name);
+ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) ==
+ STATUS_SUCCESS) {
+ TRACE2("%s", ansi.buf);
+ RtlFreeAnsiString(&ansi);
+ }
+ EXIT5(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS WIN_FUNC(RtlDeleteRegistryValue,3)
+ (ULONG relative, wchar_t *path, wchar_t *name)
+{
+ return STATUS_SUCCESS;
+}
+
+wstdcall void WIN_FUNC(RtlAssert,4)
+ (char *failed_assertion, char *file_name, ULONG line_num, char *message)
+{
+ ERROR("assertion '%s' failed at %s line %d%s",
+ failed_assertion, file_name, line_num, message ? message : "");
+ return;
+}
+
+wstdcall void WIN_FUNC(RtlUnwind,0)
+ (void)
+{
+ TODO();
+}
+
+wstdcall void WIN_FUNC(RtlRaiseException,1)
+ (void *exception_record)
+{
+ TODO();
+}
+
+int rtl_init(void)
+{
+ return 0;
+}
+
+/* called when module is being removed */
+void rtl_exit(void)
+{
+ EXIT4(return);
+}
--- /dev/null
+/*
+ * Copyright (C) 2004 Jan Kiszka
+ * Copyright (C) 2005 Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ndis.h"
+#include "usb.h"
+#include "usb_exports.h"
+
+#ifdef USB_DEBUG
+static unsigned int urb_id = 0;
+
+#define DUMP_WRAP_URB(wrap_urb, dir) \
+ USBTRACE("urb %p (%d) %s: buf: %p, len: %d, pipe: 0x%x, %d", \
+ (wrap_urb)->urb, (wrap_urb)->id, \
+ (dir == USB_DIR_OUT) ? "going down" : "coming back", \
+ (wrap_urb)->urb->transfer_buffer, \
+ (wrap_urb)->urb->transfer_buffer_length, \
+ (wrap_urb)->urb->pipe, (wrap_urb)->urb->status)
+
+#define DUMP_URB_BUFFER(urb, dir) \
+ while (debug >= 2) { \
+ int i; \
+ char msg[20], *t; \
+ if (!urb->transfer_buffer) \
+ break; \
+ if (!((usb_pipein(urb->pipe) && dir == USB_DIR_IN) || \
+ (usb_pipeout(urb->pipe) && dir == USB_DIR_OUT))) \
+ break; \
+ t = msg; \
+ t += sprintf(t, "%d: ", (urb)->actual_length); \
+ for (i = 0; i < urb->actual_length && \
+ t < &msg[sizeof(msg) - 4]; i++) \
+ t += sprintf(t, "%02X ", \
+ ((char *)urb->transfer_buffer)[i]); \
+ *t = 0; \
+ USBTRACE("%s", msg); \
+ break; \
+ }
+
+#else
+
+#define DUMP_WRAP_URB(wrap_urb, dir) (void)0
+#define DUMP_URB_BUFFER(urb, dir) (void)0
+
+#endif
+
+#define CUR_ALT_SETTING(intf) (intf)->cur_altsetting
+
+#ifndef USB_CTRL_SET_TIMEOUT
+#define USB_CTRL_SET_TIMEOUT 5000
+#endif
+
+#ifndef USB_CTRL_GET_TIMEOUT
+#define USB_CTRL_GET_TIMEOUT 5000
+#endif
+
+#ifndef URB_NO_TRANSFER_DMA_MAP
+#define URB_NO_TRANSFER_DMA_MAP 0
+#endif
+
+/* wrap_urb->flags */
+/* transfer_buffer for urb is allocated; free it in wrap_free_urb */
+#define WRAP_URB_COPY_BUFFER 0x01
+
+static int inline wrap_cancel_urb(struct wrap_urb *wrap_urb)
+{
+ int ret;
+ USBTRACE("%p, %p, %d", wrap_urb, wrap_urb->urb, wrap_urb->state);
+ if (wrap_urb->state != URB_SUBMITTED)
+ USBEXIT(return -1);
+ ret = usb_unlink_urb(wrap_urb->urb);
+ USBTRACE("ret: %d", ret);
+ if (ret == -EINPROGRESS)
+ return 0;
+ else {
+ WARNING("unlink failed: %d", ret);
+ return ret;
+ }
+}
+
+#define URB_STATUS(wrap_urb) (wrap_urb->urb->status)
+
+static struct nt_list wrap_urb_complete_list;
+static spinlock_t wrap_urb_complete_list_lock;
+
+static work_struct_t wrap_urb_complete_work;
+static void wrap_urb_complete_worker(worker_param_t dummy);
+
+static void kill_all_urbs(struct wrap_device *wd, int complete)
+{
+ struct nt_list *ent;
+ struct wrap_urb *wrap_urb;
+ KIRQL irql;
+
+ USBTRACE("%d", wd->usb.num_alloc_urbs);
+ while (1) {
+ IoAcquireCancelSpinLock(&irql);
+ ent = RemoveHeadList(&wd->usb.wrap_urb_list);
+ IoReleaseCancelSpinLock(irql);
+ if (!ent)
+ break;
+ wrap_urb = container_of(ent, struct wrap_urb, list);
+ if (wrap_urb->state == URB_SUBMITTED) {
+ WARNING("Windows driver %s didn't free urb: %p",
+ wd->driver->name, wrap_urb->urb);
+ if (!complete)
+ wrap_urb->urb->complete = NULL;
+ usb_kill_urb(wrap_urb->urb);
+ }
+ USBTRACE("%p, %p", wrap_urb, wrap_urb->urb);
+ usb_free_urb(wrap_urb->urb);
+ kfree(wrap_urb);
+ }
+ wd->usb.num_alloc_urbs = 0;
+}
+
+/* for a given Linux urb status code, return corresponding NT urb status */
+static USBD_STATUS wrap_urb_status(int urb_status)
+{
+ switch (urb_status) {
+ case 0:
+ return USBD_STATUS_SUCCESS;
+ case -EPROTO:
+ return USBD_STATUS_TIMEOUT;
+ case -EILSEQ:
+ return USBD_STATUS_CRC;
+ case -EPIPE:
+ return USBD_STATUS_INVALID_PIPE_HANDLE;
+ case -ECOMM:
+ return USBD_STATUS_DATA_OVERRUN;
+ case -ENOSR:
+ return USBD_STATUS_DATA_UNDERRUN;
+ case -EOVERFLOW:
+ return USBD_STATUS_BABBLE_DETECTED;
+ case -EREMOTEIO:
+ return USBD_STATUS_ERROR_SHORT_TRANSFER;;
+ case -ENODEV:
+ case -ESHUTDOWN:
+ case -ENOENT:
+ return USBD_STATUS_DEVICE_GONE;
+ case -ENOMEM:
+ return USBD_STATUS_NO_MEMORY;
+ case -EINVAL:
+ return USBD_STATUS_REQUEST_FAILED;
+ default:
+ return USBD_STATUS_NOT_SUPPORTED;
+ }
+}
+
+/* for a given USBD_STATUS, return its corresponding NTSTATUS (for irp) */
+static NTSTATUS nt_urb_irp_status(USBD_STATUS nt_urb_status)
+{
+ switch (nt_urb_status) {
+ case USBD_STATUS_SUCCESS:
+ return STATUS_SUCCESS;
+ case USBD_STATUS_DEVICE_GONE:
+ return STATUS_DEVICE_REMOVED;
+ case USBD_STATUS_PENDING:
+ return STATUS_PENDING;
+ case USBD_STATUS_NOT_SUPPORTED:
+ return STATUS_NOT_IMPLEMENTED;
+ case USBD_STATUS_NO_MEMORY:
+ return STATUS_NO_MEMORY;
+ case USBD_STATUS_REQUEST_FAILED:
+ return STATUS_NOT_SUPPORTED;
+ default:
+ return STATUS_FAILURE;
+ }
+}
+
+static void wrap_free_urb(struct urb *urb)
+{
+ struct irp *irp;
+ struct wrap_urb *wrap_urb;
+
+ USBTRACE("freeing urb: %p", urb);
+ wrap_urb = urb->context;
+ irp = wrap_urb->irp;
+ if (wrap_urb->flags & WRAP_URB_COPY_BUFFER) {
+ USBTRACE("freeing DMA buffer for URB: %p %p",
+ urb, urb->transfer_buffer);
+ usb_buffer_free(IRP_WRAP_DEVICE(irp)->usb.udev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ }
+ if (urb->setup_packet)
+ kfree(urb->setup_packet);
+ if (IRP_WRAP_DEVICE(irp)->usb.num_alloc_urbs > MAX_ALLOCATED_URBS) {
+ IoAcquireCancelSpinLock(&irp->cancel_irql);
+ RemoveEntryList(&wrap_urb->list);
+ IRP_WRAP_DEVICE(irp)->usb.num_alloc_urbs--;
+ IoReleaseCancelSpinLock(irp->cancel_irql);
+ usb_free_urb(urb);
+ kfree(wrap_urb);
+ } else {
+ wrap_urb->state = URB_FREE;
+ wrap_urb->flags = 0;
+ wrap_urb->irp = NULL;
+ }
+ return;
+}
+
+void wrap_suspend_urbs(struct wrap_device *wd)
+{
+ /* TODO: do we need to cancel urbs? */
+ USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs);
+}
+
+void wrap_resume_urbs(struct wrap_device *wd)
+{
+ /* TODO: do we need to resubmit urbs? */
+ USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs);
+}
+
+wstdcall void wrap_cancel_irp(struct device_object *dev_obj, struct irp *irp)
+{
+ struct urb *urb;
+
+ /* NB: this function is called holding Cancel spinlock */
+ USBENTER("irp: %p", irp);
+ urb = IRP_WRAP_URB(irp)->urb;
+ USBTRACE("canceling urb %p", urb);
+ if (wrap_cancel_urb(IRP_WRAP_URB(irp))) {
+ irp->cancel = FALSE;
+ ERROR("urb %p can't be canceld: %d", urb,
+ IRP_WRAP_URB(irp)->state);
+ } else
+ USBTRACE("urb %p canceled", urb);
+ IoReleaseCancelSpinLock(irp->cancel_irql);
+ return;
+}
+WIN_FUNC_DECL(wrap_cancel_irp,2)
+
+static struct urb *wrap_alloc_urb(struct irp *irp, unsigned int pipe,
+ void *buf, unsigned int buf_len)
+{
+ struct urb *urb;
+ gfp_t alloc_flags;
+ struct wrap_urb *wrap_urb;
+ struct wrap_device *wd;
+
+ USBENTER("irp: %p", irp);
+ wd = IRP_WRAP_DEVICE(irp);
+ alloc_flags = irql_gfp();
+ IoAcquireCancelSpinLock(&irp->cancel_irql);
+ urb = NULL;
+ nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) {
+ if (cmpxchg(&wrap_urb->state, URB_FREE,
+ URB_ALLOCATED) == URB_FREE) {
+ urb = wrap_urb->urb;
+ usb_init_urb(urb);
+ break;
+ }
+ }
+ if (!urb) {
+ IoReleaseCancelSpinLock(irp->cancel_irql);
+ wrap_urb = kzalloc(sizeof(*wrap_urb), alloc_flags);
+ if (!wrap_urb) {
+ WARNING("couldn't allocate memory");
+ return NULL;
+ }
+ urb = usb_alloc_urb(0, alloc_flags);
+ if (!urb) {
+ WARNING("couldn't allocate urb");
+ kfree(wrap_urb);
+ return NULL;
+ }
+ IoAcquireCancelSpinLock(&irp->cancel_irql);
+ wrap_urb->urb = urb;
+ wrap_urb->state = URB_ALLOCATED;
+ InsertTailList(&wd->usb.wrap_urb_list, &wrap_urb->list);
+ wd->usb.num_alloc_urbs++;
+ }
+
+#ifdef URB_ASYNC_UNLINK
+ urb->transfer_flags |= URB_ASYNC_UNLINK;
+#elif defined(USB_ASYNC_UNLINK)
+ urb->transfer_flags |= USB_ASYNC_UNLINK;
+#endif
+ urb->context = wrap_urb;
+ wrap_urb->irp = irp;
+ IRP_WRAP_URB(irp) = wrap_urb;
+ /* called as Windows function */
+ irp->cancel_routine = WIN_FUNC_PTR(wrap_cancel_irp,2);
+ IoReleaseCancelSpinLock(irp->cancel_irql);
+ USBTRACE("urb: %p", urb);
+
+ urb->transfer_buffer_length = buf_len;
+ if (buf_len && buf && (!virt_addr_valid(buf)
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_HIGHMEM4G)
+ || PageHighMem(virt_to_page(buf))
+#endif
+ )) {
+ urb->transfer_buffer =
+ usb_buffer_alloc(wd->usb.udev, buf_len, alloc_flags,
+ &urb->transfer_dma);
+ if (!urb->transfer_buffer) {
+ WARNING("couldn't allocate dma buf");
+ IoAcquireCancelSpinLock(&irp->cancel_irql);
+ wrap_urb->state = URB_FREE;
+ wrap_urb->irp = NULL;
+ IRP_WRAP_URB(irp) = NULL;
+ IoReleaseCancelSpinLock(irp->cancel_irql);
+ return NULL;
+ }
+ if (urb->transfer_dma)
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ wrap_urb->flags |= WRAP_URB_COPY_BUFFER;
+ if (usb_pipeout(pipe))
+ memcpy(urb->transfer_buffer, buf, buf_len);
+ USBTRACE("DMA buf for urb %p: %p", urb, urb->transfer_buffer);
+ } else
+ urb->transfer_buffer = buf;
+ return urb;
+}
+
+static USBD_STATUS wrap_submit_urb(struct irp *irp)
+{
+ int ret;
+ struct urb *urb;
+ union nt_urb *nt_urb;
+
+ urb = IRP_WRAP_URB(irp)->urb;
+ nt_urb = IRP_URB(irp);
+#ifdef USB_DEBUG
+ if (IRP_WRAP_URB(irp)->state != URB_ALLOCATED) {
+ ERROR("urb %p is in wrong state: %d",
+ urb, IRP_WRAP_URB(irp)->state);
+ NT_URB_STATUS(nt_urb) = USBD_STATUS_REQUEST_FAILED;
+ return NT_URB_STATUS(nt_urb);
+ }
+ IRP_WRAP_URB(irp)->id = pre_atomic_add(urb_id, 1);
+#endif
+ DUMP_WRAP_URB(IRP_WRAP_URB(irp), USB_DIR_OUT);
+ irp->io_status.status = STATUS_PENDING;
+ irp->io_status.info = 0;
+ NT_URB_STATUS(nt_urb) = USBD_STATUS_PENDING;
+ IoMarkIrpPending(irp);
+ DUMP_URB_BUFFER(urb, USB_DIR_OUT);
+ USBTRACE("%p", urb);
+ IRP_WRAP_URB(irp)->state = URB_SUBMITTED;
+ ret = usb_submit_urb(urb, irql_gfp());
+ if (ret) {
+ USBTRACE("ret: %d", ret);
+ wrap_free_urb(urb);
+ /* we assume that IRP was not in pending state before */
+ IoUnmarkIrpPending(irp);
+ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret);
+ USBEXIT(return NT_URB_STATUS(nt_urb));
+ } else
+ USBEXIT(return USBD_STATUS_PENDING);
+}
+
+static void wrap_urb_complete(struct urb *urb ISR_PT_REGS_PARAM_DECL)
+{
+ struct irp *irp;
+ struct wrap_urb *wrap_urb;
+
+ wrap_urb = urb->context;
+ USBTRACE("%p (%p) completed", wrap_urb, urb);
+ irp = wrap_urb->irp;
+ DUMP_WRAP_URB(wrap_urb, USB_DIR_IN);
+ irp->cancel_routine = NULL;
+#ifdef USB_DEBUG
+ if (wrap_urb->state != URB_SUBMITTED) {
+ WARNING("urb %p in wrong state: %d (%d)", urb, wrap_urb->state,
+ urb->status);
+ return;
+ }
+#endif
+ wrap_urb->state = URB_COMPLETED;
+ spin_lock(&wrap_urb_complete_list_lock);
+ InsertTailList(&wrap_urb_complete_list, &wrap_urb->complete_list);
+ spin_unlock(&wrap_urb_complete_list_lock);
+ schedule_ntos_work(&wrap_urb_complete_work);
+}
+
+/* one worker for all devices */
+static void wrap_urb_complete_worker(worker_param_t dummy)
+{
+ struct irp *irp;
+ struct urb *urb;
+ struct usbd_bulk_or_intr_transfer *bulk_int_tx;
+ struct usbd_vendor_or_class_request *vc_req;
+ union nt_urb *nt_urb;
+ struct wrap_urb *wrap_urb;
+ struct nt_list *ent;
+ unsigned long flags;
+
+ USBENTER("");
+ while (1) {
+ spin_lock_irqsave(&wrap_urb_complete_list_lock, flags);
+ ent = RemoveHeadList(&wrap_urb_complete_list);
+ spin_unlock_irqrestore(&wrap_urb_complete_list_lock, flags);
+ if (!ent)
+ break;
+ wrap_urb = container_of(ent, struct wrap_urb, complete_list);
+ urb = wrap_urb->urb;
+#ifdef USB_DEBUG
+ if (wrap_urb->state != URB_COMPLETED &&
+ wrap_urb->state != URB_INT_UNLINKED)
+ WARNING("urb %p in wrong state: %d",
+ urb, wrap_urb->state);
+#endif
+ irp = wrap_urb->irp;
+ DUMP_IRP(irp);
+ nt_urb = IRP_URB(irp);
+ USBTRACE("urb: %p, nt_urb: %p, status: %d",
+ urb, nt_urb, urb->status);
+ switch (urb->status) {
+ case 0:
+ /* succesfully transferred */
+ irp->io_status.info = urb->actual_length;
+ if (nt_urb->header.function ==
+ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) {
+ bulk_int_tx = &nt_urb->bulk_int_transfer;
+ bulk_int_tx->transfer_buffer_length =
+ urb->actual_length;
+ DUMP_URB_BUFFER(urb, USB_DIR_IN);
+ if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) &&
+ usb_pipein(urb->pipe))
+ memcpy(bulk_int_tx->transfer_buffer,
+ urb->transfer_buffer,
+ urb->actual_length);
+ } else { // vendor or class request
+ vc_req = &nt_urb->vendor_class_request;
+ vc_req->transfer_buffer_length =
+ urb->actual_length;
+ DUMP_URB_BUFFER(urb, USB_DIR_IN);
+ if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) &&
+ usb_pipein(urb->pipe))
+ memcpy(vc_req->transfer_buffer,
+ urb->transfer_buffer,
+ urb->actual_length);
+ }
+ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS;
+ irp->io_status.status = STATUS_SUCCESS;
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ /* urb canceled */
+ irp->io_status.info = 0;
+ TRACE2("urb %p canceled", urb);
+ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS;
+ irp->io_status.status = STATUS_CANCELLED;
+ break;
+ default:
+ TRACE2("irp: %p, urb: %p, status: %d/%d",
+ irp, urb, urb->status, wrap_urb->state);
+ irp->io_status.info = 0;
+ NT_URB_STATUS(nt_urb) = wrap_urb_status(urb->status);
+ irp->io_status.status =
+ nt_urb_irp_status(NT_URB_STATUS(nt_urb));
+ break;
+ }
+ wrap_free_urb(urb);
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ }
+ USBEXIT(return);
+}
+
+static USBD_STATUS wrap_bulk_or_intr_trans(struct irp *irp)
+{
+ usbd_pipe_handle pipe_handle;
+ struct urb *urb;
+ unsigned int pipe;
+ struct usbd_bulk_or_intr_transfer *bulk_int_tx;
+ USBD_STATUS status;
+ struct usb_device *udev;
+ union nt_urb *nt_urb;
+
+ nt_urb = IRP_URB(irp);
+ udev = IRP_WRAP_DEVICE(irp)->usb.udev;
+ bulk_int_tx = &nt_urb->bulk_int_transfer;
+ pipe_handle = bulk_int_tx->pipe_handle;
+ USBTRACE("flags: 0x%x, length: %u, buffer: %p, handle: %p",
+ bulk_int_tx->transfer_flags,
+ bulk_int_tx->transfer_buffer_length,
+ bulk_int_tx->transfer_buffer, pipe_handle);
+
+ if (USBD_IS_BULK_PIPE(pipe_handle)) {
+ if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN)
+ pipe = usb_rcvbulkpipe(udev,
+ pipe_handle->bEndpointAddress);
+ else
+ pipe = usb_sndbulkpipe(udev,
+ pipe_handle->bEndpointAddress);
+ } else {
+ if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN)
+ pipe = usb_rcvintpipe(udev,
+ pipe_handle->bEndpointAddress);
+ else
+ pipe = usb_sndintpipe(udev,
+ pipe_handle->bEndpointAddress);
+ }
+
+ DUMP_IRP(irp);
+ urb = wrap_alloc_urb(irp, pipe, bulk_int_tx->transfer_buffer,
+ bulk_int_tx->transfer_buffer_length);
+ if (!urb) {
+ ERROR("couldn't allocate urb");
+ return USBD_STATUS_NO_MEMORY;
+ }
+ if (usb_pipein(pipe) &&
+ (!(bulk_int_tx->transfer_flags & USBD_SHORT_TRANSFER_OK))) {
+ USBTRACE("short not ok");
+ urb->transfer_flags |= URB_SHORT_NOT_OK;
+ }
+ if (usb_pipebulk(pipe)) {
+ usb_fill_bulk_urb(urb, udev, pipe, urb->transfer_buffer,
+ bulk_int_tx->transfer_buffer_length,
+ wrap_urb_complete, urb->context);
+ USBTRACE("submitting bulk urb %p on pipe 0x%x (ep 0x%x)",
+ urb, urb->pipe, pipe_handle->bEndpointAddress);
+ } else {
+ usb_fill_int_urb(urb, udev, pipe, urb->transfer_buffer,
+ bulk_int_tx->transfer_buffer_length,
+ wrap_urb_complete, urb->context,
+ pipe_handle->bInterval);
+ USBTRACE("submitting interrupt urb %p on pipe 0x%x (ep 0x%x), "
+ "intvl: %d", urb, urb->pipe,
+ pipe_handle->bEndpointAddress, pipe_handle->bInterval);
+ }
+ status = wrap_submit_urb(irp);
+ USBTRACE("status: %08X", status);
+ USBEXIT(return status);
+}
+
+static USBD_STATUS wrap_vendor_or_class_req(struct irp *irp)
+{
+ u8 req_type;
+ unsigned int pipe;
+ struct usbd_vendor_or_class_request *vc_req;
+ struct usb_device *udev;
+ union nt_urb *nt_urb;
+ USBD_STATUS status;
+ struct urb *urb;
+ struct usb_ctrlrequest *dr;
+
+ nt_urb = IRP_URB(irp);
+ udev = IRP_WRAP_DEVICE(irp)->usb.udev;
+ vc_req = &nt_urb->vendor_class_request;
+ USBTRACE("bits: %x, req: %x, val: %08x, index: %08x, flags: %x,"
+ "buf: %p, len: %d", vc_req->reserved_bits, vc_req->request,
+ vc_req->value, vc_req->index, vc_req->transfer_flags,
+ vc_req->transfer_buffer, vc_req->transfer_buffer_length);
+
+ USBTRACE("%x", nt_urb->header.function);
+ switch (nt_urb->header.function) {
+ case URB_FUNCTION_VENDOR_DEVICE:
+ req_type = USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ break;
+ case URB_FUNCTION_VENDOR_INTERFACE:
+ req_type = USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
+ break;
+ case URB_FUNCTION_VENDOR_ENDPOINT:
+ req_type = USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+ break;
+ case URB_FUNCTION_VENDOR_OTHER:
+ req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER;
+ break;
+ case URB_FUNCTION_CLASS_DEVICE:
+ req_type = USB_TYPE_CLASS | USB_RECIP_DEVICE;
+ break;
+ case URB_FUNCTION_CLASS_INTERFACE:
+ req_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ break;
+ case URB_FUNCTION_CLASS_ENDPOINT:
+ req_type = USB_TYPE_CLASS | USB_RECIP_ENDPOINT;
+ break;
+ case URB_FUNCTION_CLASS_OTHER:
+ req_type = USB_TYPE_CLASS | USB_RECIP_OTHER;
+ break;
+ default:
+ ERROR("unknown request type: %x", nt_urb->header.function);
+ req_type = 0;
+ break;
+ }
+
+ req_type |= vc_req->reserved_bits;
+ USBTRACE("req type: %08x", req_type);
+
+ if (vc_req->transfer_flags & USBD_TRANSFER_DIRECTION_IN) {
+ pipe = usb_rcvctrlpipe(udev, 0);
+ req_type |= USB_DIR_IN;
+ USBTRACE("pipe: %x, dir in", pipe);
+ } else {
+ pipe = usb_sndctrlpipe(udev, 0);
+ req_type |= USB_DIR_OUT;
+ USBTRACE("pipe: %x, dir out", pipe);
+ }
+ urb = wrap_alloc_urb(irp, pipe, vc_req->transfer_buffer,
+ vc_req->transfer_buffer_length);
+ if (!urb) {
+ ERROR("couldn't allocate urb");
+ return USBD_STATUS_NO_MEMORY;
+ }
+
+ if (usb_pipein(pipe) &&
+ (!(vc_req->transfer_flags & USBD_SHORT_TRANSFER_OK))) {
+ USBTRACE("short not ok");
+ urb->transfer_flags |= URB_SHORT_NOT_OK;
+ }
+
+ dr = kzalloc(sizeof(*dr), GFP_ATOMIC);
+ if (!dr) {
+ ERROR("couldn't allocate memory");
+ wrap_free_urb(urb);
+ return USBD_STATUS_NO_MEMORY;
+ }
+ dr->bRequestType = req_type;
+ dr->bRequest = vc_req->request;
+ dr->wValue = cpu_to_le16(vc_req->value);
+ dr->wIndex = cpu_to_le16((u16)vc_req->index);
+ dr->wLength = cpu_to_le16((u16)urb->transfer_buffer_length);
+
+ usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr,
+ urb->transfer_buffer, urb->transfer_buffer_length,
+ wrap_urb_complete, urb->context);
+ status = wrap_submit_urb(irp);
+ USBTRACE("status: %08X", status);
+ USBEXIT(return status);
+}
+
+static USBD_STATUS wrap_reset_pipe(struct usb_device *udev, struct irp *irp)
+{
+ int ret;
+ union nt_urb *nt_urb;
+ usbd_pipe_handle pipe_handle;
+ unsigned int pipe1, pipe2;
+
+ nt_urb = IRP_URB(irp);
+ pipe_handle = nt_urb->pipe_req.pipe_handle;
+ /* TODO: not clear if both directions should be cleared? */
+ if (USBD_IS_BULK_PIPE(pipe_handle)) {
+ pipe1 = usb_rcvbulkpipe(udev, pipe_handle->bEndpointAddress);
+ pipe2 = usb_sndbulkpipe(udev, pipe_handle->bEndpointAddress);
+ } else if (USBD_IS_INT_PIPE(pipe_handle)) {
+ pipe1 = usb_rcvintpipe(udev, pipe_handle->bEndpointAddress);
+ pipe2 = pipe1;
+ } else {
+ WARNING("invalid pipe %d", pipe_handle->bEndpointAddress);
+ return USBD_STATUS_INVALID_PIPE_HANDLE;
+ }
+ USBTRACE("ep: %d, pipe: 0x%x", pipe_handle->bEndpointAddress, pipe1);
+ ret = usb_clear_halt(udev, pipe1);
+ if (ret)
+ USBTRACE("resetting pipe %d failed: %d", pipe1, ret);
+ if (pipe2 != pipe1) {
+ ret = usb_clear_halt(udev, pipe2);
+ if (ret)
+ USBTRACE("resetting pipe %d failed: %d", pipe2, ret);
+ }
+// return wrap_urb_status(ret);
+ return USBD_STATUS_SUCCESS;
+}
+
+static USBD_STATUS wrap_abort_pipe(struct usb_device *udev, struct irp *irp)
+{
+ union nt_urb *nt_urb;
+ usbd_pipe_handle pipe_handle;
+ struct wrap_urb *wrap_urb;
+ struct wrap_device *wd;
+ KIRQL irql;
+
+ wd = IRP_WRAP_DEVICE(irp);
+ nt_urb = IRP_URB(irp);
+ pipe_handle = nt_urb->pipe_req.pipe_handle;
+ USBENTER("%p, %x", irp, pipe_handle->bEndpointAddress);
+ IoAcquireCancelSpinLock(&irql);
+ nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) {
+ USBTRACE("%p, %p, %d, %x, %x", wrap_urb, wrap_urb->urb,
+ wrap_urb->state, wrap_urb->urb->pipe,
+ usb_pipeendpoint(wrap_urb->urb->pipe));
+ /* for WG111T driver, urbs for endpoint 0 should also
+ * be canceled */
+ if ((usb_pipeendpoint(wrap_urb->urb->pipe) ==
+ pipe_handle->bEndpointAddress) ||
+ (usb_pipeendpoint(wrap_urb->urb->pipe) == 0)) {
+ if (wrap_cancel_urb(wrap_urb) == 0)
+ USBTRACE("canceled wrap_urb: %p", wrap_urb);
+ }
+ }
+ IoReleaseCancelSpinLock(irql);
+ NT_URB_STATUS(nt_urb) = USBD_STATUS_CANCELED;
+ USBEXIT(return USBD_STATUS_SUCCESS);
+}
+
+static USBD_STATUS wrap_set_clear_feature(struct usb_device *udev,
+ struct irp *irp)
+{
+ union nt_urb *nt_urb;
+ struct urb_control_feature_request *feat_req;
+ int ret = 0;
+ __u8 request, type;
+ __u16 feature;
+
+ nt_urb = IRP_URB(irp);
+ feat_req = &nt_urb->feat_req;
+ feature = feat_req->feature_selector;
+ switch (nt_urb->header.function) {
+ case URB_FUNCTION_SET_FEATURE_TO_DEVICE:
+ request = USB_REQ_SET_FEATURE;
+ type = USB_DT_DEVICE;
+ break;
+ case URB_FUNCTION_SET_FEATURE_TO_INTERFACE:
+ request = USB_REQ_SET_FEATURE;
+ type = USB_DT_INTERFACE;
+ break;
+ case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT:
+ request = USB_REQ_SET_FEATURE;
+ type = USB_DT_ENDPOINT;
+ break;
+ case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE:
+ request = USB_REQ_CLEAR_FEATURE;
+ type = USB_DT_DEVICE;
+ break;
+ case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE:
+ request = USB_REQ_CLEAR_FEATURE;
+ type = USB_DT_INTERFACE;
+ break;
+ case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT:
+ request = USB_REQ_CLEAR_FEATURE;
+ type = USB_DT_ENDPOINT;
+ break;
+ default:
+ WARNING("invalid function: %x", nt_urb->header.function);
+ NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED;
+ return NT_URB_STATUS(nt_urb);
+ }
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, type,
+ feature, feat_req->index, NULL, 0, 1000);
+ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret);
+ USBEXIT(return NT_URB_STATUS(nt_urb));
+}
+
+static USBD_STATUS wrap_get_status_request(struct usb_device *udev,
+ struct irp *irp)
+{
+ union nt_urb *nt_urb;
+ struct urb_control_get_status_request *status_req;
+ int ret = 0;
+ __u8 type;
+
+ nt_urb = IRP_URB(irp);
+ status_req = &nt_urb->status_req;
+ switch (nt_urb->header.function) {
+ case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
+ type = USB_RECIP_DEVICE;
+ break;
+ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE:
+ type = USB_RECIP_INTERFACE;
+ break;
+ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT:
+ type = USB_RECIP_ENDPOINT;
+ break;
+ default:
+ WARNING("invalid function: %x", nt_urb->header.function);
+ NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED;
+ return NT_URB_STATUS(nt_urb);
+ }
+ assert(status_req->transfer_buffer_length == sizeof(u16));
+ ret = usb_get_status(udev, type, status_req->index,
+ status_req->transfer_buffer);
+ if (ret >= 0) {
+ assert(ret <= status_req->transfer_buffer_length);
+ status_req->transfer_buffer_length = ret;
+ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS;
+ } else
+ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret);
+ USBEXIT(return NT_URB_STATUS(nt_urb));
+}
+
+static void set_intf_pipe_info(struct wrap_device *wd,
+ struct usb_interface *usb_intf,
+ struct usbd_interface_information *intf)
+{
+ int i;
+ struct usb_endpoint_descriptor *ep;
+ struct usbd_pipe_information *pipe;
+
+ for (i = 0; i < CUR_ALT_SETTING(usb_intf)->desc.bNumEndpoints; i++) {
+ ep = &(CUR_ALT_SETTING(usb_intf)->endpoint[i]).desc;
+ if (i >= intf->bNumEndpoints) {
+ ERROR("intf %p has only %d endpoints, "
+ "ignoring endpoints above %d",
+ intf, intf->bNumEndpoints, i);
+ break;
+ }
+ pipe = &intf->pipes[i];
+
+ if (pipe->flags & USBD_PF_CHANGE_MAX_PACKET)
+ USBTRACE("pkt_sz: %d: %d", pipe->wMaxPacketSize,
+ pipe->max_tx_size);
+ USBTRACE("driver wants max_tx_size to %d",
+ pipe->max_tx_size);
+
+ pipe->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
+ pipe->bEndpointAddress = ep->bEndpointAddress;
+ pipe->type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (pipe->type == UsbdPipeTypeInterrupt) {
+ /* Windows and Linux differ in how the
+ * bInterval is interpretted */
+ /* for low speed:
+ interval (Windows) -> frames per ms (Linux)
+ 0 to 15 -> 8
+ 16 to 35 -> 16
+ 36 to 255 -> 32
+
+ for full speed: interval -> frames per ms
+ 1 -> 1
+ 2 to 3 -> 2
+ 4 to 7 -> 4
+ 8 to 15 -> 8
+ 16 to 31 -> 16
+ 32 to 255 -> 32
+
+ for high speed: interval -> microframes
+ 1 -> 1
+ 2 -> 2
+ 3 -> 4
+ 4 -> 8
+ 5 -> 16
+ 6 -> 32
+ 7 to 255 -> 32
+ */
+ if (wd->usb.udev->speed == USB_SPEED_LOW)
+ pipe->bInterval = ep->bInterval + 5;
+ else if (wd->usb.udev->speed == USB_SPEED_FULL)
+ pipe->bInterval = ep->bInterval;
+ else {
+ int j, k;
+ for (j = k = 1; j < ep->bInterval; k++)
+ j *= 2;
+ pipe->bInterval = k;
+ }
+ }
+ pipe->handle = ep;
+ USBTRACE("%d: ep 0x%x, type %d, pkt_sz %d, intv %d (%d),"
+ "type: %d, handle %p", i, ep->bEndpointAddress,
+ ep->bmAttributes, pipe->wMaxPacketSize, ep->bInterval,
+ pipe->bInterval, pipe->type, pipe->handle);
+ }
+}
+
+static USBD_STATUS wrap_select_configuration(struct wrap_device *wd,
+ union nt_urb *nt_urb,
+ struct irp *irp)
+{
+ int i, ret;
+ struct usbd_select_configuration *sel_conf;
+ struct usb_device *udev;
+ struct usbd_interface_information *intf;
+ struct usb_config_descriptor *config;
+ struct usb_interface *usb_intf;
+
+ udev = wd->usb.udev;
+ sel_conf = &nt_urb->select_conf;
+ config = sel_conf->config;
+ USBTRACE("%p", config);
+ if (config == NULL) {
+ kill_all_urbs(wd, 1);
+ ret = usb_reset_configuration(udev);
+ return wrap_urb_status(ret);
+ }
+
+ USBTRACE("conf: %d, type: %d, length: %d, numif: %d, attr: %08x",
+ config->bConfigurationValue, config->bDescriptorType,
+ config->wTotalLength, config->bNumInterfaces,
+ config->bmAttributes);
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_CONFIGURATION, 0,
+ config->bConfigurationValue, 0,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (ret < 0) {
+ ERROR("ret: %d", ret);
+ return wrap_urb_status(ret);
+ }
+ sel_conf->handle = udev->actconfig;
+ intf = &sel_conf->intf;
+ for (i = 0; i < config->bNumInterfaces && intf->bLength > 0;
+ i++, intf = (((void *)intf) + intf->bLength)) {
+
+ USBTRACE("intf: %d, alt setting: %d",
+ intf->bInterfaceNumber, intf->bAlternateSetting);
+ ret = usb_set_interface(udev, intf->bInterfaceNumber,
+ intf->bAlternateSetting);
+ if (ret < 0) {
+ ERROR("failed with %d", ret);
+ return wrap_urb_status(ret);
+ }
+ usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber);
+ if (!usb_intf) {
+ ERROR("couldn't obtain ifnum");
+ return USBD_STATUS_REQUEST_FAILED;
+ }
+ USBTRACE("intf: %p, num ep: %d", intf, intf->bNumEndpoints);
+ set_intf_pipe_info(wd, usb_intf, intf);
+ }
+ return USBD_STATUS_SUCCESS;
+}
+
+static USBD_STATUS wrap_select_interface(struct wrap_device *wd,
+ union nt_urb *nt_urb,
+ struct irp *irp)
+{
+ int ret;
+ struct usbd_select_interface *sel_intf;
+ struct usb_device *udev;
+ struct usbd_interface_information *intf;
+ struct usb_interface *usb_intf;
+
+ udev = wd->usb.udev;
+ sel_intf = &nt_urb->select_intf;
+ intf = &sel_intf->intf;
+
+ ret = usb_set_interface(udev, intf->bInterfaceNumber,
+ intf->bAlternateSetting);
+ if (ret < 0) {
+ ERROR("failed with %d", ret);
+ return wrap_urb_status(ret);
+ }
+ usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber);
+ if (!usb_intf) {
+ ERROR("couldn't get interface information");
+ return USBD_STATUS_REQUEST_FAILED;
+ }
+ USBTRACE("intf: %p, num ep: %d", usb_intf, intf->bNumEndpoints);
+ set_intf_pipe_info(wd, usb_intf, intf);
+ return USBD_STATUS_SUCCESS;
+}
+
+static int wrap_usb_get_string(struct usb_device *udev, unsigned short langid,
+ unsigned char index, void *buf, int size)
+{
+ int i, ret;
+ /* if langid is 0, return array of langauges supported in
+ * buf */
+ for (i = 0; i < 3; i++) {
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (USB_DT_STRING << 8) + index, langid,
+ buf, size, USB_CTRL_GET_TIMEOUT);
+ if (ret > 0 || ret == -EPIPE)
+ break;
+ }
+ return ret;
+}
+
+static USBD_STATUS wrap_get_descriptor(struct wrap_device *wd,
+ union nt_urb *nt_urb, struct irp *irp)
+{
+ struct usbd_control_descriptor_request *control_desc;
+ int ret = 0;
+ struct usb_device *udev;
+
+ udev = wd->usb.udev;
+ control_desc = &nt_urb->control_desc;
+ USBTRACE("desctype = %d, descindex = %d, transfer_buffer = %p,"
+ "transfer_buffer_length = %d", control_desc->desc_type,
+ control_desc->index, control_desc->transfer_buffer,
+ control_desc->transfer_buffer_length);
+
+ if (control_desc->desc_type == USB_DT_STRING) {
+ USBTRACE("langid: %x", control_desc->language_id);
+ ret = wrap_usb_get_string(udev, control_desc->language_id,
+ control_desc->index,
+ control_desc->transfer_buffer,
+ control_desc->transfer_buffer_length);
+ } else {
+ ret = usb_get_descriptor(udev, control_desc->desc_type,
+ control_desc->index,
+ control_desc->transfer_buffer,
+ control_desc->transfer_buffer_length);
+ }
+ if (ret < 0) {
+ USBTRACE("request %d failed: %d", control_desc->desc_type, ret);
+ control_desc->transfer_buffer_length = 0;
+ return wrap_urb_status(ret);
+ } else {
+ USBTRACE("ret: %08x", ret);
+ control_desc->transfer_buffer_length = ret;
+ irp->io_status.info = ret;
+ return USBD_STATUS_SUCCESS;
+ }
+}
+
+static USBD_STATUS wrap_process_nt_urb(struct irp *irp)
+{
+ union nt_urb *nt_urb;
+ struct usb_device *udev;
+ USBD_STATUS status;
+ struct wrap_device *wd;
+
+ wd = IRP_WRAP_DEVICE(irp);
+ udev = wd->usb.udev;
+ nt_urb = IRP_URB(irp);
+ USBENTER("nt_urb = %p, irp = %p, length = %d, function = %x",
+ nt_urb, irp, nt_urb->header.length, nt_urb->header.function);
+
+ DUMP_IRP(irp);
+ switch (nt_urb->header.function) {
+ /* bulk/int and vendor/class urbs are submitted to
+ * Linux USB core; if the call is sucessful, urb's
+ * completion worker will return IRP later */
+ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
+ USBTRACE("submitting bulk/int irp: %p", irp);
+ status = wrap_bulk_or_intr_trans(irp);
+ break;
+
+ case URB_FUNCTION_VENDOR_DEVICE:
+ case URB_FUNCTION_VENDOR_INTERFACE:
+ case URB_FUNCTION_VENDOR_ENDPOINT:
+ case URB_FUNCTION_VENDOR_OTHER:
+ case URB_FUNCTION_CLASS_DEVICE:
+ case URB_FUNCTION_CLASS_INTERFACE:
+ case URB_FUNCTION_CLASS_ENDPOINT:
+ case URB_FUNCTION_CLASS_OTHER:
+ USBTRACE("submitting vendor/class irp: %p", irp);
+ status = wrap_vendor_or_class_req(irp);
+ break;
+
+ /* rest are synchronous */
+ case URB_FUNCTION_SELECT_CONFIGURATION:
+ status = wrap_select_configuration(wd, nt_urb, irp);
+ NT_URB_STATUS(nt_urb) = status;
+ break;
+
+ case URB_FUNCTION_SELECT_INTERFACE:
+ status = wrap_select_interface(wd, nt_urb, irp);
+ NT_URB_STATUS(nt_urb) = status;
+ break;
+
+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+ status = wrap_get_descriptor(wd, nt_urb, irp);
+ NT_URB_STATUS(nt_urb) = status;
+ break;
+
+ case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
+ status = wrap_reset_pipe(udev, irp);
+ NT_URB_STATUS(nt_urb) = status;
+ break;
+
+ case URB_FUNCTION_ABORT_PIPE:
+ status = wrap_abort_pipe(udev, irp);
+ break;
+
+ case URB_FUNCTION_SET_FEATURE_TO_DEVICE:
+ case URB_FUNCTION_SET_FEATURE_TO_INTERFACE:
+ case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT:
+ case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE:
+ case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE:
+ case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT:
+ status = wrap_set_clear_feature(udev, irp);
+ break;
+
+ case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
+ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE:
+ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT:
+ status = wrap_get_status_request(udev, irp);
+ break;
+
+ default:
+ ERROR("function %x not implemented", nt_urb->header.function);
+ status = NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ USBTRACE("status: %08X", status);
+ return status;
+}
+
+static USBD_STATUS wrap_reset_port(struct irp *irp)
+{
+ no_warn_unused int ret, lock = 0;
+ struct wrap_device *wd;
+
+ wd = IRP_WRAP_DEVICE(irp);
+ USBENTER("%p, %p", wd, wd->usb.udev);
+ lock = usb_lock_device_for_reset(wd->usb.udev, wd->usb.intf);
+ if (lock < 0) {
+ WARNING("locking failed: %d", lock);
+// return wrap_urb_status(lock);
+ return USBD_STATUS_SUCCESS;
+ }
+ ret = usb_reset_device(wd->usb.udev);
+ if (ret < 0)
+ USBTRACE("reset failed: %d", ret);
+ /* TODO: should reconfigure? */
+ if (lock)
+ usb_unlock_device(wd->usb.udev);
+// return wrap_urb_status(ret);
+ return USBD_STATUS_SUCCESS;
+}
+
+static USBD_STATUS wrap_get_port_status(struct irp *irp)
+{
+ struct wrap_device *wd;
+ ULONG *status;
+ enum usb_device_state state;
+
+ wd = IRP_WRAP_DEVICE(irp);
+ USBENTER("%p, %p", wd, wd->usb.udev);
+ status = IoGetCurrentIrpStackLocation(irp)->params.others.arg1;
+ state = wd->usb.udev->state;
+ if (state != USB_STATE_NOTATTACHED &&
+ state != USB_STATE_SUSPENDED) {
+ *status |= USBD_PORT_CONNECTED;
+ if (state == USB_STATE_CONFIGURED)
+ *status |= USBD_PORT_ENABLED;
+ }
+ USBTRACE("state: %d, *status: %08X", state, *status);
+ return USBD_STATUS_SUCCESS;
+}
+
+NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp)
+{
+ struct io_stack_location *irp_sl;
+ struct wrap_device *wd;
+ USBD_STATUS status;
+ struct usbd_idle_callback *idle_callback;
+
+ USBENTER("%p, %p", pdo, irp);
+ wd = pdo->reserved;
+ if (wd->usb.intf == NULL) {
+ USBTRACE("%p", irp);
+ irp->io_status.status = STATUS_DEVICE_REMOVED;
+ irp->io_status.info = 0;
+ USBEXIT(return STATUS_DEVICE_REMOVED);
+ }
+ IRP_WRAP_DEVICE(irp) = wd;
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+ switch (irp_sl->params.dev_ioctl.code) {
+ case IOCTL_INTERNAL_USB_SUBMIT_URB:
+ status = wrap_process_nt_urb(irp);
+ break;
+ case IOCTL_INTERNAL_USB_RESET_PORT:
+ status = wrap_reset_port(irp);
+ break;
+ case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
+ status = wrap_get_port_status(irp);
+ break;
+ case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
+ idle_callback = irp_sl->params.dev_ioctl.type3_input_buf;
+ USBTRACE("suspend function: %p", idle_callback->callback);
+ status = USBD_STATUS_NOT_SUPPORTED;
+ break;
+ default:
+ ERROR("ioctl %08X NOT IMPLEMENTED",
+ irp_sl->params.dev_ioctl.code);
+ status = USBD_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ USBTRACE("status: %08X", status);
+ if (status == USBD_STATUS_PENDING) {
+ /* don't touch this IRP - it may have been already
+ * completed/returned */
+ return STATUS_PENDING;
+ } else {
+ irp->io_status.status = nt_urb_irp_status(status);
+ if (status != USBD_STATUS_SUCCESS)
+ irp->io_status.info = 0;
+ USBEXIT(return irp->io_status.status);
+ }
+}
+
+/* TODO: The example on msdn in reference section suggests that second
+ * argument should be an array of usbd_interface_information, but
+ * description and examples elsewhere suggest that it should be
+ * usbd_interface_list_entry structre. Which is correct? */
+
+wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequestEx,2)
+ (struct usb_config_descriptor *config,
+ struct usbd_interface_list_entry *intf_list)
+{
+ int size, i, n;
+ struct usbd_interface_information *intf;
+ struct usbd_pipe_information *pipe;
+ struct usb_interface_descriptor *intf_desc;
+ struct usbd_select_configuration *select_conf;
+
+ USBENTER("config = %p, intf_list = %p", config, intf_list);
+
+ /* calculate size required; select_conf already has space for
+ * one intf structure */
+ size = sizeof(*select_conf) - sizeof(*intf);
+ for (n = 0; n < config->bNumInterfaces; n++) {
+ i = intf_list[n].intf_desc->bNumEndpoints;
+ /* intf already has space for one pipe */
+ size += sizeof(*intf) + (i - 1) * sizeof(*pipe);
+ }
+ /* don't use kmalloc - driver frees it with ExFreePool */
+ select_conf = ExAllocatePoolWithTag(NonPagedPool, size,
+ POOL_TAG('L', 'U', 'S', 'B'));
+ if (!select_conf) {
+ WARNING("couldn't allocate memory");
+ return NULL;
+ }
+ memset(select_conf, 0, size);
+ intf = &select_conf->intf;
+ select_conf->handle = config;
+ for (n = 0; n < config->bNumInterfaces && intf_list[n].intf_desc; n++) {
+ /* initialize 'intf' fields in intf_list so they point
+ * to appropriate entry; these may be read/written by
+ * driver after this function returns */
+ intf_list[n].intf = intf;
+ intf_desc = intf_list[n].intf_desc;
+
+ i = intf_desc->bNumEndpoints;
+ intf->bLength = sizeof(*intf) + (i - 1) * sizeof(*pipe);
+
+ intf->bInterfaceNumber = intf_desc->bInterfaceNumber;
+ intf->bAlternateSetting = intf_desc->bAlternateSetting;
+ intf->bInterfaceClass = intf_desc->bInterfaceClass;
+ intf->bInterfaceSubClass = intf_desc->bInterfaceSubClass;
+ intf->bInterfaceProtocol = intf_desc->bInterfaceProtocol;
+ intf->bNumEndpoints = intf_desc->bNumEndpoints;
+
+ pipe = &intf->pipes[0];
+ for (i = 0; i < intf->bNumEndpoints; i++) {
+ memset(&pipe[i], 0, sizeof(*pipe));
+ pipe[i].max_tx_size =
+ USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
+ }
+ intf->handle = intf_desc;
+ intf = (((void *)intf) + intf->bLength);
+ }
+ select_conf->header.function = URB_FUNCTION_SELECT_CONFIGURATION;
+ select_conf->header.length = size;
+ select_conf->config = config;
+ USBEXIT(return (union nt_urb *)select_conf);
+}
+
+WIN_SYMBOL_MAP("_USBD_CreateConfigurationRequestEx@8", USBD_CreateConfigurationRequestEx)
+
+wstdcall struct usb_interface_descriptor *
+WIN_FUNC(USBD_ParseConfigurationDescriptorEx,7)
+ (struct usb_config_descriptor *config, void *start,
+ LONG bInterfaceNumber, LONG bAlternateSetting, LONG bInterfaceClass,
+ LONG bInterfaceSubClass, LONG bInterfaceProtocol)
+{
+ void *pos;
+ struct usb_interface_descriptor *intf;
+
+ USBENTER("config = %p, start = %p, ifnum = %d, alt_setting = %d,"
+ " class = %d, subclass = %d, proto = %d", config, start,
+ bInterfaceNumber, bAlternateSetting, bInterfaceClass,
+ bInterfaceSubClass, bInterfaceProtocol);
+
+ for (pos = start;
+ pos < ((void *)config + le16_to_cpu(config->wTotalLength));
+ pos += intf->bLength) {
+
+ intf = pos;
+
+ if ((intf->bDescriptorType == USB_DT_INTERFACE) &&
+ ((bInterfaceNumber == -1) ||
+ (intf->bInterfaceNumber == bInterfaceNumber)) &&
+ ((bAlternateSetting == -1) ||
+ (intf->bAlternateSetting == bAlternateSetting)) &&
+ ((bInterfaceClass == -1) ||
+ (intf->bInterfaceClass == bInterfaceClass)) &&
+ ((bInterfaceSubClass == -1) ||
+ (intf->bInterfaceSubClass == bInterfaceSubClass)) &&
+ ((bInterfaceProtocol == -1) ||
+ (intf->bInterfaceProtocol == bInterfaceProtocol))) {
+ USBTRACE("selected interface = %p", intf);
+ USBEXIT(return intf);
+ }
+ }
+ USBEXIT(return NULL);
+}
+
+WIN_SYMBOL_MAP("_USBD_ParseConfigurationDescriptorEx@28", USBD_ParseConfigurationDescriptorEx)
+
+wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequest,2)
+ (struct usb_config_descriptor *config, USHORT *size)
+{
+ union nt_urb *nt_urb;
+ struct usbd_interface_list_entry intf_list[2];
+ struct usb_interface_descriptor *intf_desc;
+
+ USBENTER("config = %p, urb_size = %p", config, size);
+
+ intf_desc = USBD_ParseConfigurationDescriptorEx(config, config, -1, -1,
+ -1, -1, -1);
+ intf_list[0].intf_desc = intf_desc;
+ intf_list[0].intf = NULL;
+ intf_list[1].intf_desc = NULL;
+ intf_list[1].intf = NULL;
+ nt_urb = USBD_CreateConfigurationRequestEx(config, intf_list);
+ if (!nt_urb)
+ return NULL;
+
+ *size = nt_urb->select_conf.header.length;
+ USBEXIT(return nt_urb);
+}
+
+wstdcall struct usb_interface_descriptor *
+WIN_FUNC(USBD_ParseConfigurationDescriptor,3)
+ (struct usb_config_descriptor *config, UCHAR bInterfaceNumber,
+ UCHAR bAlternateSetting)
+{
+ return USBD_ParseConfigurationDescriptorEx(config, config,
+ bInterfaceNumber,
+ bAlternateSetting,
+ -1, -1, -1);
+}
+
+wstdcall usb_common_descriptor_t *WIN_FUNC(USBD_ParseDescriptors,4)
+ (void *buf, ULONG length, void *start, LONG type)
+{
+ usb_common_descriptor_t *descr = start;
+
+ while ((void *)descr < buf + length) {
+ if (descr->bDescriptorType == type)
+ return descr;
+ if (descr->bLength == 0)
+ break;
+ descr = (void *)descr + descr->bLength;
+ }
+ USBEXIT(return NULL);
+}
+
+WIN_SYMBOL_MAP("_USBD_ParseDescriptors@16", USBD_ParseDescriptors)
+
+wstdcall void WIN_FUNC(USBD_GetUSBDIVersion,1)
+ (struct usbd_version_info *version_info)
+{
+ /* this function is obsolete in Windows XP */
+ if (version_info) {
+ version_info->usbdi_version = USBDI_VERSION_XP;
+ /* TODO: how do we get this correctly? */
+ version_info->supported_usb_version = 0x110;
+ }
+ USBEXIT(return);
+}
+
+wstdcall void
+USBD_InterfaceGetUSBDIVersion(void *context,
+ struct usbd_version_info *version_info,
+ ULONG *hcd_capa)
+{
+ struct wrap_device *wd = context;
+
+ if (version_info) {
+ version_info->usbdi_version = USBDI_VERSION_XP;
+ if (wd->usb.udev->speed == USB_SPEED_HIGH)
+ version_info->supported_usb_version = 0x200;
+ else
+ version_info->supported_usb_version = 0x110;
+ }
+ *hcd_capa = USB_HCD_CAPS_SUPPORTS_RT_THREADS;
+ USBEXIT(return);
+}
+
+wstdcall BOOLEAN USBD_InterfaceIsDeviceHighSpeed(void *context)
+{
+ struct wrap_device *wd = context;
+
+ USBTRACE("wd: %p", wd);
+ if (wd->usb.udev->speed == USB_SPEED_HIGH)
+ USBEXIT(return TRUE);
+ else
+ USBEXIT(return FALSE);
+}
+
+wstdcall void USBD_InterfaceReference(void *context)
+{
+ USBTRACE("%p", context);
+ TODO();
+}
+
+wstdcall void USBD_InterfaceDereference(void *context)
+{
+ USBTRACE("%p", context);
+ TODO();
+}
+
+wstdcall NTSTATUS USBD_InterfaceQueryBusTime(void *context, ULONG *frame)
+{
+ struct wrap_device *wd = context;
+
+ *frame = usb_get_current_frame_number(wd->usb.udev);
+ USBEXIT(return STATUS_SUCCESS);
+}
+
+wstdcall NTSTATUS USBD_InterfaceSubmitIsoOutUrb(void *context,
+ union nt_urb *nt_urb)
+{
+ /* TODO: implement this */
+ TODO();
+ USBEXIT(return STATUS_NOT_IMPLEMENTED);
+}
+
+wstdcall NTSTATUS
+USBD_InterfaceQueryBusInformation(void *context, ULONG level, void *buf,
+ ULONG *buf_length, ULONG *buf_actual_length)
+{
+ struct wrap_device *wd = context;
+ struct usb_bus_information_level *bus_info;
+ struct usb_bus *bus;
+
+ bus = wd->usb.udev->bus;
+ bus_info = buf;
+ TODO();
+ USBEXIT(return STATUS_NOT_IMPLEMENTED);
+}
+
+wstdcall NTSTATUS
+USBD_InterfaceLogEntry(void *context, ULONG driver_tag, ULONG enum_tag,
+ ULONG p1, ULONG p2)
+{
+ ERROR("%p, %x, %x, %x, %x", context, driver_tag, enum_tag, p1, p2);
+ USBEXIT(return STATUS_SUCCESS);
+}
+
+int usb_init(void)
+{
+ InitializeListHead(&wrap_urb_complete_list);
+ spin_lock_init(&wrap_urb_complete_list_lock);
+ initialize_work(&wrap_urb_complete_work, wrap_urb_complete_worker, NULL);
+#ifdef USB_DEBUG
+ urb_id = 0;
+#endif
+ return 0;
+}
+
+void usb_exit(void)
+{
+ USBEXIT(return);
+}
+
+int usb_init_device(struct wrap_device *wd)
+{
+ InitializeListHead(&wd->usb.wrap_urb_list);
+ wd->usb.num_alloc_urbs = 0;
+ USBEXIT(return 0);
+}
+
+void usb_exit_device(struct wrap_device *wd)
+{
+ kill_all_urbs(wd, 0);
+ USBEXIT(return);
+}
--- /dev/null
+/*
+ * Copyright (C) 2004 Jan Kiszka
+ * Copyright (C) 2005 Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _USB_H_
+#define _USB_H_
+
+#include "ntoskernel.h"
+
+#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003
+#define IOCTL_INTERNAL_USB_RESET_PORT 0x00220007
+#define IOCTL_INTERNAL_USB_GET_PORT_STATUS 0x00220013
+#define IOCTL_INTERNAL_USB_CYCLE_PORT 0x0022001F
+#define IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION 0x00220027
+
+#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000
+#define URB_FUNCTION_SELECT_INTERFACE 0x0001
+#define URB_FUNCTION_ABORT_PIPE 0x0002
+#define URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003
+#define URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004
+#define URB_FUNCTION_GET_FRAME_LENGTH 0x0005
+#define URB_FUNCTION_SET_FRAME_LENGTH 0x0006
+#define URB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007
+#define URB_FUNCTION_CONTROL_TRANSFER 0x0008
+#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009
+#define URB_FUNCTION_ISOCH_TRANSFER 0x000A
+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B
+#define URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C
+#define URB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D
+#define URB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E
+#define URB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F
+#define URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010
+#define URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011
+#define URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012
+#define URB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013
+#define URB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014
+#define URB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015
+#define URB_FUNCTION_RESERVED_0X0016 0x0016
+#define URB_FUNCTION_VENDOR_DEVICE 0x0017
+#define URB_FUNCTION_VENDOR_INTERFACE 0x0018
+#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019
+#define URB_FUNCTION_CLASS_DEVICE 0x001A
+#define URB_FUNCTION_CLASS_INTERFACE 0x001B
+#define URB_FUNCTION_CLASS_ENDPOINT 0x001C
+#define URB_FUNCTION_RESERVE_0X001D 0x001D
+#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E
+#define URB_FUNCTION_CLASS_OTHER 0x001F
+#define URB_FUNCTION_VENDOR_OTHER 0x0020
+#define URB_FUNCTION_GET_STATUS_FROM_OTHER 0x0021
+#define URB_FUNCTION_CLEAR_FEATURE_TO_OTHER 0x0022
+#define URB_FUNCTION_SET_FEATURE_TO_OTHER 0x0023
+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024
+#define URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT 0x0025
+#define URB_FUNCTION_GET_CONFIGURATION 0x0026
+#define URB_FUNCTION_GET_INTERFACE 0x0027
+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028
+#define URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE 0x0029
+#define URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR 0x002A
+#define URB_FUNCTION_RESERVE_0X002B 0x002B
+#define URB_FUNCTION_RESERVE_0X002C 0x002C
+#define URB_FUNCTION_RESERVE_0X002D 0x002D
+#define URB_FUNCTION_RESERVE_0X002E 0x002E
+#define URB_FUNCTION_RESERVE_0X002F 0x002F
+// USB 2.0 calls start at 0x0030
+#define URB_FUNCTION_SYNC_RESET_PIPE 0x0030
+#define URB_FUNCTION_SYNC_CLEAR_STALL 0x0031
+#define URB_FUNCTION_CONTROL_TRANSFER_EX 0x0032
+
+#define USBD_PF_CHANGE_MAX_PACKET 0x00000001
+
+#define USBD_TRANSFER_DIRECTION_OUT 0
+#define USBD_TRANSFER_DIRECTION_IN 1
+
+#define USBD_SHORT_TRANSFER_OK 0x00000002
+#define USBD_START_ISO_TRANSFER_ASAP 0x00000004
+#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008
+
+#define USBD_TRANSFER_DIRECTION(flags) \
+ ((flags) & USBD_TRANSFER_DIRECTION_IN)
+
+enum pipe_type {UsbdPipeTypeControl = USB_ENDPOINT_XFER_CONTROL,
+ UsbdPipeTypeIsochronous = USB_ENDPOINT_XFER_ISOC,
+ UsbdPipeTypeBulk = USB_ENDPOINT_XFER_BULK,
+ UsbdPipeTypeInterrupt = USB_ENDPOINT_XFER_INT};
+
+#define USBD_IS_BULK_PIPE(pipe_handle) \
+ (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \
+ == USB_ENDPOINT_XFER_BULK)
+
+#define USBD_IS_INT_PIPE(pipe_handle) \
+ (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \
+ == USB_ENDPOINT_XFER_INT)
+
+#define USBD_PORT_ENABLED 0x00000001
+#define USBD_PORT_CONNECTED 0x00000002
+
+typedef LONG USBD_STATUS;
+
+#define USBD_STATUS_SUCCESS 0x0
+#define USBD_STATUS_PENDING 0x40000000
+#define USBD_STATUS_CANCELED 0x00010000
+
+#define USBD_STATUS_CRC 0xC0000001
+#define USBD_STATUS_BTSTUFF 0xC0000002
+#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003
+#define USBD_STATUS_STALL_PID 0xC0000004
+#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005
+#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006
+#define USBD_STATUS_UNEXPECTED_PID 0xC0000007
+#define USBD_STATUS_DATA_OVERRUN 0xC0000008
+#define USBD_STATUS_DATA_UNDERRUN 0xC0000009
+#define USBD_STATUS_RESERVED1 0xC000000A
+#define USBD_STATUS_RESERVED2 0xC000000B
+#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C
+#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D
+#define USBD_STATUS_NOT_ACCESSED 0xC000000F
+#define USBD_STATUS_FIFO 0xC0000010
+#define USBD_STATUS_XACT_ERROR 0xC0000011
+#define USBD_STATUS_BABBLE_DETECTED 0xC0000012
+#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013
+
+#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00
+#define USBD_STATUS_BUFFER_TOO_SMALL 0xC0003000
+#define USBD_STATUS_TIMEOUT 0xC0006000
+#define USBD_STATUS_DEVICE_GONE 0xC0007000
+
+#define USBD_STATUS_NO_MEMORY 0x80000100
+#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200
+#define USBD_STATUS_INVALID_PARAMETER 0x80000300
+#define USBD_STATUS_REQUEST_FAILED 0x80000500
+#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600
+#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900
+
+#define USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE PAGE_SIZE
+
+struct urb_hcd_area {
+ void *reserved8[8];
+};
+
+typedef struct usb_endpoint_descriptor *usbd_pipe_handle;
+typedef struct usb_descriptor_header usb_common_descriptor_t;
+
+struct usbd_pipe_information {
+ USHORT wMaxPacketSize;
+ UCHAR bEndpointAddress;
+ UCHAR bInterval;
+ enum pipe_type type;
+ usbd_pipe_handle handle;
+ ULONG max_tx_size;
+ ULONG flags;
+};
+
+struct usbd_interface_information {
+ USHORT bLength;
+ UCHAR bInterfaceNumber;
+ UCHAR bAlternateSetting;
+ UCHAR bInterfaceClass;
+ UCHAR bInterfaceSubClass;
+ UCHAR bInterfaceProtocol;
+ UCHAR reserved;
+ void *handle;
+ ULONG bNumEndpoints;
+ struct usbd_pipe_information pipes[1];
+};
+
+struct usbd_interface_list_entry {
+ struct usb_interface_descriptor *intf_desc;
+ struct usbd_interface_information *intf;
+};
+
+struct nt_urb_header {
+ USHORT length;
+ USHORT function;
+ USBD_STATUS status;
+ void *usbd_dev_handle;
+ ULONG usbd_flags;
+};
+
+struct usbd_select_interface {
+ struct nt_urb_header header;
+ void *handle;
+ struct usbd_interface_information intf;
+};
+
+struct usbd_select_configuration {
+ struct nt_urb_header header;
+ struct usb_config_descriptor *config;
+ void *handle;
+ struct usbd_interface_information intf;
+};
+
+struct usbd_control_descriptor_request {
+ struct nt_urb_header header;
+ void *reserved;
+ ULONG reserved0;
+ ULONG transfer_buffer_length;
+ void *transfer_buffer;
+ struct mdl *mdl;
+ union nt_urb *urb_link;
+ struct urb_hcd_area hca;
+ USHORT reserved1;
+ UCHAR index;
+ UCHAR desc_type;
+ USHORT language_id;
+ USHORT reserved2;
+};
+
+struct usbd_bulk_or_intr_transfer {
+ struct nt_urb_header header;
+ usbd_pipe_handle pipe_handle;
+ ULONG transfer_flags;
+ ULONG transfer_buffer_length;
+ void *transfer_buffer;
+ struct mdl *mdl;
+ union nt_urb *urb_link;
+ struct urb_hcd_area hca;
+};
+
+struct usbd_pipe_request {
+ struct nt_urb_header header;
+ usbd_pipe_handle pipe_handle;
+};
+
+struct usbd_vendor_or_class_request {
+ struct nt_urb_header header;
+ void *reserved;
+ ULONG transfer_flags;
+ ULONG transfer_buffer_length;
+ void *transfer_buffer;
+ struct mdl *mdl;
+ union nt_urb *link;
+ struct urb_hcd_area hca;
+ UCHAR reserved_bits;
+ UCHAR request;
+ USHORT value;
+ USHORT index;
+ USHORT reserved1;
+};
+
+struct urb_control_feature_request {
+ struct nt_urb_header header;
+ void *reserved;
+ ULONG reserved2;
+ ULONG reserved3;
+ void *reserved4;
+ struct mdl *reserved5;
+ union nt_urb *link;
+ struct urb_hcd_area hca;
+ USHORT reserved0;
+ USHORT feature_selector;
+ USHORT index;
+ USHORT reserved1;
+};
+
+struct urb_control_get_status_request {
+ struct nt_urb_header header;
+ void *reserved;
+ ULONG reserved0;
+ ULONG transfer_buffer_length;
+ void *transfer_buffer;
+ struct mdl *mdl;
+ union nt_urb *link;
+ struct urb_hcd_area hca;
+ UCHAR reserved1[4];
+ USHORT index;
+ USHORT reserved2;
+};
+
+struct usbd_iso_packet_desc {
+ ULONG offset;
+ ULONG length;
+ USBD_STATUS status;
+};
+
+struct usbd_isochronous_transfer {
+ struct nt_urb_header header;
+ usbd_pipe_handle pipe_handle;
+ ULONG transfer_flags;
+ ULONG transfer_buffer_length;
+ void *transfer_buffer;
+ struct mdl *mdl;
+ union nt_urb *urb_link;
+ struct urb_hcd_area hca;
+ ULONG start_frame;
+ ULONG number_of_packets;
+ ULONG error_count;
+ struct usbd_iso_packet_desc iso_packet[1];
+};
+
+union nt_urb {
+ struct nt_urb_header header;
+ struct usbd_select_interface select_intf;
+ struct usbd_select_configuration select_conf;
+ struct usbd_bulk_or_intr_transfer bulk_int_transfer;
+ struct usbd_control_descriptor_request control_desc;
+ struct usbd_vendor_or_class_request vendor_class_request;
+ struct usbd_isochronous_transfer isochronous;
+ struct usbd_pipe_request pipe_req;
+ struct urb_control_feature_request feat_req;
+ struct urb_control_get_status_request status_req;
+};
+
+struct usbd_bus_interface_usbdi {
+ USHORT Size;
+ USHORT Version;
+ void *Context;
+ void *InterfaceReference;
+ void *InterfaceDereference;
+ void *GetUSBDIVersion;
+ void *QueryBusTime;
+ void *SubmitIsoOutUrb;
+ void *QueryBusInformation;
+ /* version 1 and above have following field */
+ void *IsDeviceHighSpeed;
+ /* version 2 (and above) have following field */
+ void *LogEntry;
+};
+
+struct usbd_bus_information_level {
+ ULONG TotalBandwidth;
+ ULONG ConsumedBandwidth;
+ /* level 1 and above have following fields */
+ ULONG ControllerNameLength;
+ wchar_t ControllerName[1];
+};
+
+#define USBDI_VERSION_XP 0x00000500 // Windows XP
+#define USB_HCD_CAPS_SUPPORTS_RT_THREADS 0x00000001
+#define USB_BUSIF_USBDI_VERSION_0 0x0000
+#define USB_BUSIF_USBDI_VERSION_1 0x0001
+#define USB_BUSIF_USBDI_VERSION_2 0x0002
+
+struct usbd_version_info {
+ ULONG usbdi_version;
+ ULONG supported_usb_version;
+};
+
+struct usbd_idle_callback {
+ void *callback;
+ void *context;
+};
+
+#define NT_URB_STATUS(nt_urb) ((nt_urb)->header.status)
+
+NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp);
+void wrap_suspend_urbs(struct wrap_device *wd);
+void wrap_resume_urbs(struct wrap_device *wd);
+
+void USBD_InterfaceGetUSBDIVersion(void *context,
+ struct usbd_version_info *version_info,
+ ULONG *hcd_capa) wstdcall;
+BOOLEAN USBD_InterfaceIsDeviceHighSpeed(void *context) wstdcall;
+void USBD_InterfaceReference(void *context) wstdcall;
+void USBD_InterfaceDereference(void *context) wstdcall;
+NTSTATUS USBD_InterfaceQueryBusTime(void *context, ULONG *frame) wstdcall;
+NTSTATUS USBD_InterfaceSubmitIsoOutUrb(void *context,
+ union nt_urb *nt_urb) wstdcall;
+NTSTATUS USBD_InterfaceQueryBusInformation(void *context, ULONG level, void *buf,
+ ULONG *buf_length,
+ ULONG *buf_actual_length) wstdcall;
+NTSTATUS USBD_InterfaceLogEntry(void *context, ULONG driver_tag, ULONG enum_tag,
+ ULONG p1, ULONG p2) wstdcall;
+
+#endif /* USB_H */
--- /dev/null
+/*
+ * Copyright (C) 2005 Karl Vogel, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/linkage.h>
+
+#ifdef CONFIG_X86_64
+
+/*
+# Windows <---> Linux register usage conversion when calling functions
+# V = Volatile
+# NV = Non Volatile (needs to be saved)
+#
+# Win Lin
+# ---------------------------------------
+# Rax Return V Return V
+# Rbx NV NV
+# Rcx Arg1 V Arg4 V
+# Rdx Arg2 V Arg3 V
+# Rsi NV Arg2 V
+# Rdi NV Arg1 V
+# Rsp NV NV
+# Rbp NV NV
+# R8 Arg3 V Arg5 V
+# R9 Arg4 V Arg6 V
+# R10 V V
+# R11 V V
+# R12 NV NV
+# R13 NV NV
+# R14 NV NV
+# R15 NV NV
+#
+# In addition, Linux uses %rax to indicate number of SSE registers used
+# when variadic functions are called. Since there is no way to obtain this
+# from Windows, for now, we just assume this is 0 (hence %rax is cleared).
+#
+# Windows pushes arguments 5 and higher onto stack in case of integer
+# variables and 4 and higher in case of floating point variabes (passed
+# in SSE registers).
+
+In a windows function, the stackframe/registers look like this:
+
+# 0x0048 ....
+# 0x0040 arg8
+# 0x0038 arg7
+# 0x0030 arg6
+# 0x0028 arg5
+# 0x0020 shadow/spill space for arg4
+# 0x0018 shadow/spill space for arg3
+# 0x0010 shadow/spill space for arg2
+# 0x0008 shadow/spill space for arg1
+# 0x0000 ret
+
+# register spill space is same irrespective of number of arguments - even
+# if Windows function takes less than 4 arguments, 32 bytes above return
+# address is reserved for the function
+
+In Linux it should look like:
+
+# 0x0018 ....
+# 0x0010 arg8
+# 0x0008 arg7
+# 0x0000 ret
+
+*/
+
+#
+# setup for Windows to Linux function call
+#
+
+ .text
+
+.macro win2lin_prolog
+ push %rsi
+ push %rdi
+.endm
+
+.macro win2lin_epilog
+ pop %rdi
+ pop %rsi
+.endm
+
+# when Windows function calls Linux function, the function address is in %r10
+
+.macro call_lin_func
+ xor %rax, %rax # rax indicates number of SSE regs
+ call *%r10
+.endm
+
+# before prolog, 0(%rsp) is return address, 8(%rsp) would be arg1
+# (but it is in register) and so on, so n'th arg would be at n*8(%rsp)
+# for n > 4. But in prolog, we push 2 registers that are non-volaile in
+# Windows, but volatile in Linux. So after prolog, args are at (n+2)*8(%rsp)
+
+#define win2lin_win_arg(n) (n+2)*8(%rsp)
+
+#define win2lin_arg1 mov %rcx, %rdi
+#define win2lin_arg2 mov %rdx, %rsi
+#define win2lin_arg3 mov %r8, %rdx
+#define win2lin_arg4 mov %r9, %rcx
+#define win2lin_arg5 mov win2lin_win_arg(5), %r8
+#define win2lin_arg6 mov win2lin_win_arg(6), %r9
+
+ .type win2lin0, @function
+win2lin0:
+ win2lin_prolog
+ call_lin_func
+ win2lin_epilog
+ ret
+ .size win2lin0, .-win2lin0
+
+ .type win2lin1, @function
+win2lin1:
+ win2lin_prolog
+ win2lin_arg1
+ call_lin_func
+ win2lin_epilog
+ ret
+ .size win2lin1, .-win2lin1
+
+ .type win2lin2, @function
+win2lin2:
+ win2lin_prolog
+ win2lin_arg1
+ win2lin_arg2
+ call_lin_func
+ win2lin_epilog
+ ret
+ .size win2lin2, .-win2lin2
+
+ .type win2lin3, @function
+win2lin3:
+ win2lin_prolog
+ win2lin_arg1
+ win2lin_arg2
+ win2lin_arg3
+ call_lin_func
+ win2lin_epilog
+ ret
+ .size win2lin3, .-win2lin3
+
+ .type win2lin4, @function
+win2lin4:
+ win2lin_prolog
+ win2lin_arg1
+ win2lin_arg2
+ win2lin_arg3
+ win2lin_arg4
+ call_lin_func
+ win2lin_epilog
+ ret
+ .size win2lin4, .-win2lin4
+
+ .type win2lin5, @function
+win2lin5:
+ win2lin_prolog
+ win2lin_arg1
+ win2lin_arg2
+ win2lin_arg3
+ win2lin_arg4
+ win2lin_arg5
+ call_lin_func
+ win2lin_epilog
+ ret
+ .size win2lin5, .-win2lin5
+
+ .type win2lin6, @function
+win2lin6:
+ win2lin_prolog
+ win2lin_arg1
+ win2lin_arg2
+ win2lin_arg3
+ win2lin_arg4
+ win2lin_arg5
+ win2lin_arg6
+ call_lin_func
+ win2lin_epilog
+ ret
+ .size win2lin6, .-win2lin6
+
+# Allocate stack frame for Linux arguments before calling function.
+# First 6 args are passed through registers, so we need space for 7 and above.
+# The arguments should have been copied onto stack already.
+
+.macro call_lin_func_args n
+ sub $(\n-6)*8, %rsp
+ call_lin_func
+ add $(\n-6)*8, %rsp
+ .endm
+
+# m is index of Linux arg required, n is total number of args to function
+# After stack frame is allocated, Linux arg 7 should be at 0(%rsp),
+# arg 8 should be at 1*8(%rsp) and so on. So Linux arg m should be at (m-7)*8
+# Stack frame starts at -(n-6)*8(%rsp), so before stack frame is allocated
+# Linux arg m should be at (6-n+m-7)*8(%rsp)
+
+#define win2lin_lin_arg(m,n) (m-1-n)*8(%rsp)
+
+ .type win2lin7, @function
+win2lin7:
+ win2lin_prolog
+
+ win2lin_arg1
+ win2lin_arg2
+ win2lin_arg3
+ win2lin_arg4
+ win2lin_arg5
+ win2lin_arg6
+
+ # copy windows argument 7 onto stack for Linux function
+ mov win2lin_win_arg(7), %r11
+ mov %r11, win2lin_lin_arg(7,7)
+
+ call_lin_func_args(7)
+ win2lin_epilog
+ ret
+ .size win2lin7, .-win2lin7
+
+ .type win2lin8, @function
+win2lin8:
+ win2lin_prolog
+
+ win2lin_arg1
+ win2lin_arg2
+ win2lin_arg3
+ win2lin_arg4
+ win2lin_arg5
+ win2lin_arg6
+
+ # copy windows arguments 7 and 8 onto stack for Linux function
+ mov win2lin_win_arg(7), %r11
+ mov %r11, win2lin_lin_arg(7,8)
+ mov win2lin_win_arg(8), %r11
+ mov %r11, win2lin_lin_arg(8,8)
+
+ call_lin_func_args(8)
+ win2lin_epilog
+ ret
+ .size win2lin8, .-win2lin8
+
+ .type win2lin9, @function
+win2lin9:
+win2lin10:
+win2lin11:
+win2lin12:
+ win2lin_prolog
+
+ # since we destroy rsi and rdi here, first copy windows
+ # arguments 7 through 12 onto stack for Linux function
+ mov %rcx, %r11 # save rcx
+ lea win2lin_win_arg(7), %rsi # source (windows arg 7 and up)
+ lea win2lin_lin_arg(7,12), %rdi # = destination
+ mov $6, %rcx # 6 arguments
+ rep
+ movsq
+ mov %r11, %rcx # restore rcx
+
+ win2lin_arg1
+ win2lin_arg2
+ win2lin_arg3
+ win2lin_arg4
+ win2lin_arg5
+ win2lin_arg6
+
+ call_lin_func_args(12)
+ win2lin_epilog
+ ret
+ .size win2lin9, .-win2lin9
+
+#define win2lin(name, argc) \
+ENTRY(win2lin_ ## name ## _ ## argc) \
+ lea name(%rip), %r10 ; \
+ jmp win2lin ## argc
+
+#include "win2lin_stubs.h"
+
+#endif // CONFIG_X86_64
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _WINNT_TYPES_H_
+#define _WINNT_TYPES_H_
+
+#define TRUE 1
+#define FALSE 0
+
+#define PASSIVE_LEVEL 0
+#define APC_LEVEL 1
+#define DISPATCH_LEVEL 2
+#define DEVICE_LEVEL_BASE 4
+
+/* soft interrupts / bottom-half's are disabled at SOFT_IRQL */
+#define SOFT_IRQL (DEVICE_LEVEL_BASE + 1)
+#define DIRQL (DEVICE_LEVEL_BASE + 2)
+
+#define STATUS_WAIT_0 0
+#define STATUS_SUCCESS 0
+#define STATUS_ALERTED 0x00000101
+#define STATUS_TIMEOUT 0x00000102
+#define STATUS_PENDING 0x00000103
+#define STATUS_FAILURE 0xC0000001
+#define STATUS_NOT_IMPLEMENTED 0xC0000002
+#define STATUS_INVALID_PARAMETER 0xC000000D
+#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010
+#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
+#define STATUS_ACCESS_DENIED 0xC0000022
+#define STATUS_BUFFER_TOO_SMALL 0xC0000023
+#define STATUS_OBJECT_NAME_INVALID 0xC0000023
+#define STATUS_MUTANT_NOT_OWNED 0xC0000046
+#define STATUS_RESOURCES 0xC000009A
+#define STATUS_DELETE_PENDING 0xC0000056
+#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A
+#define STATUS_NOT_SUPPORTED 0xC00000BB
+#define STATUS_INVALID_PARAMETER_2 0xC00000F0
+#define STATUS_NO_MEMORY 0xC0000017
+#define STATUS_CANCELLED 0xC0000120
+#define STATUS_DEVICE_REMOVED 0xC00002B6
+#define STATUS_DEVICE_NOT_CONNECTED 0xC000009D
+
+#define STATUS_BUFFER_OVERFLOW 0x80000005
+
+#define SL_PENDING_RETURNED 0x01
+#define SL_INVOKE_ON_CANCEL 0x20
+#define SL_INVOKE_ON_SUCCESS 0x40
+#define SL_INVOKE_ON_ERROR 0x80
+
+#define IRP_MJ_CREATE 0x00
+#define IRP_MJ_CREATE_NAMED_PIPE 0x01
+#define IRP_MJ_CLOSE 0x02
+#define IRP_MJ_READ 0x03
+#define IRP_MJ_WRITE 0x04
+
+#define IRP_MJ_DEVICE_CONTROL 0x0E
+#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0F
+#define IRP_MJ_POWER 0x16
+#define IRP_MJ_SYSTEM_CONTROL 0x0E
+#define IRP_MJ_PNP 0x1b
+#define IRP_MJ_MAXIMUM_FUNCTION 0x1b
+
+#define IRP_MN_WAIT_WAKE 0x00
+#define IRP_MN_POWER_SEQUENCE 0x01
+#define IRP_MN_SET_POWER 0x02
+#define IRP_MN_QUERY_POWER 0x03
+
+#define IRP_MN_REGINFO 0x08
+#define IRP_MN_REGINFO_EX 0x0b
+
+#define IRP_MN_START_DEVICE 0x00
+#define IRP_MN_QUERY_REMOVE_DEVICE 0x01
+#define IRP_MN_REMOVE_DEVICE 0x02
+#define IRP_MN_CANCEL_REMOVE_DEVICE 0x03
+#define IRP_MN_STOP_DEVICE 0x04
+#define IRP_MN_QUERY_STOP_DEVICE 0x05
+#define IRP_MN_CANCEL_STOP_DEVICE 0x06
+#define IRP_MN_QUERY_DEVICE_RELATIONS 0x07
+#define IRP_MN_QUERY_INTERFACE 0x08
+
+#define IRP_BUFFERED_IO 0x00000010
+#define IRP_DEALLOCATE_BUFFER 0x00000020
+#define IRP_INPUT_OPERATION 0x00000040
+
+#define IRP_DEFFER_IO_COMPLETION 0x00000800
+
+#define THREAD_WAIT_OBJECTS 3
+#define MAX_WAIT_OBJECTS 64
+
+#define LOW_PRIORITY 0
+#define LOW_REALTIME_PRIORITY 16
+#define HIGH_PRIORITY 31
+#define MAXIMUM_PRIORITY 32
+
+#define PROCESSOR_FEATURE_MAX 64
+
+#define IO_NO_INCREMENT 0
+
+#define WMIREG_ACTION_REGISTER 1
+#define WMIREG_ACTION_DEREGISTER 2
+#define WMIREG_ACTION_REREGISTER 3
+#define WMIREG_ACTION_UPDATE_GUIDS 4
+
+#define WMIREGISTER 0
+#define WMIUPDATE 1
+
+#ifdef CONFIG_X86_64
+#define wstdcall
+#define wfastcall
+#define noregparm
+
+#define KI_USER_SHARED_DATA 0xfffff78000000000UL
+
+#else
+
+#define noregparm __attribute__((regparm(0)))
+#define wstdcall __attribute__((__stdcall__, regparm(0)))
+#if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ > 3) || __GNUC__ > 3)
+#undef fastcall
+#define wfastcall __attribute__((fastcall))
+#else
+#error "gcc 3.4 or newer should be used for compiling this module"
+#endif
+
+#define KI_USER_SHARED_DATA 0xffdf0000
+
+#endif
+
+#define packed __attribute__((packed))
+#define no_warn_unused __attribute__((unused))
+
+typedef u8 BOOLEAN;
+typedef u8 BYTE;
+typedef u8 *LPBYTE;
+typedef s8 CHAR;
+typedef u8 UCHAR;
+typedef s16 SHORT;
+typedef u16 USHORT;
+typedef u16 WORD;
+typedef s32 INT;
+typedef u32 UINT;
+typedef u32 DWORD;
+typedef s32 LONG;
+typedef u32 ULONG;
+typedef s64 LONGLONG;
+typedef u64 ULONGLONG;
+typedef u64 ULONGULONG;
+typedef u64 ULONG64;
+
+typedef CHAR CCHAR;
+typedef USHORT wchar_t;
+typedef SHORT CSHORT;
+typedef LONGLONG LARGE_INTEGER;
+
+typedef LONG NTSTATUS;
+
+typedef LONG KPRIORITY;
+typedef LARGE_INTEGER PHYSICAL_ADDRESS;
+typedef UCHAR KIRQL;
+typedef CHAR KPROCESSOR_MODE;
+
+/* ULONG_PTR is 32 bits on 32-bit platforms and 64 bits on 64-bit
+ * platform, which is same as 'unsigned long' in Linux */
+typedef unsigned long ULONG_PTR;
+
+typedef ULONG_PTR SIZE_T;
+typedef ULONG_PTR KAFFINITY;
+typedef ULONG ACCESS_MASK;
+
+typedef ULONG_PTR PFN_NUMBER;
+typedef ULONG SECURITY_INFORMATION;
+
+/* non-negative numbers indicate success */
+#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0)
+
+struct ansi_string {
+ USHORT length;
+ USHORT max_length;
+ char *buf;
+};
+
+struct unicode_string {
+ USHORT length;
+ USHORT max_length;
+ wchar_t *buf;
+};
+
+struct nt_slist {
+ struct nt_slist *next;
+};
+
+#ifdef CONFIG_X86_64
+/* it is not clear how nt_slist_head is used to store pointer to
+ * slists and depth; here we assume 'align' field is used to store
+ * depth and 'region' field is used to store slist pointers */
+struct nt_slist_head {
+ union {
+ USHORT depth;
+ ULONGLONG align;
+ };
+ union {
+ ULONGLONG region;
+ struct nt_slist *next;
+ };
+} __attribute__((aligned(16)));
+typedef struct nt_slist_head nt_slist_header;
+#else
+union nt_slist_head {
+ ULONGLONG align;
+ struct {
+ struct nt_slist *next;
+ USHORT depth;
+ USHORT sequence;
+ };
+};
+typedef union nt_slist_head nt_slist_header;
+#endif
+
+struct nt_list {
+ struct nt_list *next;
+ struct nt_list *prev;
+};
+
+typedef ULONG_PTR NT_SPIN_LOCK;
+
+enum kdpc_importance {LowImportance, MediumImportance, HighImportance};
+
+struct kdpc;
+typedef void (*DPC)(struct kdpc *kdpc, void *ctx, void *arg1,
+ void *arg2) wstdcall;
+struct kdpc {
+ SHORT type;
+ UCHAR nr_cpu;
+ UCHAR importance;
+ struct nt_list list;
+ DPC func;
+ void *ctx;
+ void *arg1;
+ void *arg2;
+ union {
+ NT_SPIN_LOCK *lock;
+ /* 'lock' is not used; 'queued' represents whether
+ * kdpc is queued or not */
+ int queued;
+ };
+};
+
+enum pool_type {
+ NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType,
+ NonPagedPoolCacheAligned, PagedPoolCacheAligned,
+ NonPagedPoolCacheAlignedMustS, MaxPoolType,
+ NonPagedPoolSession = 32,
+ PagedPoolSession = NonPagedPoolSession + 1,
+ NonPagedPoolMustSucceedSession = PagedPoolSession + 1,
+ DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1,
+ NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1,
+ PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1,
+ NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1
+};
+
+enum memory_caching_type_orig {
+ MmFrameBufferCached = 2
+};
+
+enum memory_caching_type {
+ MmNonCached = FALSE, MmCached = TRUE,
+ MmWriteCombined = MmFrameBufferCached, MmHardwareCoherentCached,
+ MmNonCachedUnordered, MmUSWCCached, MmMaximumCacheType
+};
+
+enum lock_operation {
+ IoReadAccess, IoWriteAccess, IoModifyAccess
+};
+
+enum mode {
+ KernelMode, UserMode, MaximumMode
+};
+
+struct mdl {
+ struct mdl *next;
+ CSHORT size;
+ CSHORT flags;
+ /* NdisFreeBuffer doesn't pass pool, so we store pool in
+ * unused field 'process' */
+ union {
+ void *process;
+ void *pool;
+ };
+ void *mappedsystemva;
+ void *startva;
+ ULONG bytecount;
+ ULONG byteoffset;
+};
+
+#define MDL_MAPPED_TO_SYSTEM_VA 0x0001
+#define MDL_PAGES_LOCKED 0x0002
+#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004
+#define MDL_ALLOCATED_FIXED_SIZE 0x0008
+#define MDL_PARTIAL 0x0010
+#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020
+#define MDL_IO_PAGE_READ 0x0040
+#define MDL_WRITE_OPERATION 0x0080
+#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100
+#define MDL_FREE_EXTRA_PTES 0x0200
+#define MDL_IO_SPACE 0x0800
+#define MDL_NETWORK_HEADER 0x1000
+#define MDL_MAPPING_CAN_FAIL 0x2000
+#define MDL_ALLOCATED_MUST_SUCCEED 0x4000
+
+#define MDL_POOL_ALLOCATED 0x0400
+#define MDL_CACHE_ALLOCATED 0x8000
+
+#define PAGE_START(ptr) ((void *)((ULONG_PTR)(ptr) & ~(PAGE_SIZE - 1)))
+#define BYTE_OFFSET(ptr) ((ULONG)((ULONG_PTR)(ptr) & (PAGE_SIZE - 1)))
+
+#define MmGetMdlByteCount(mdl) ((mdl)->bytecount)
+#define MmGetMdlVirtualAddress(mdl) ((mdl)->startva + (mdl)->byteoffset)
+#define MmGetMdlByteOffset(mdl) ((mdl)->byteoffset)
+#define MmGetSystemAddressForMdl(mdl) ((mdl)->mappedsystemva)
+#define MmGetSystemAddressForMdlSafe(mdl, priority) ((mdl)->mappedsystemva)
+#define MmGetMdlPfnArray(mdl) ((PFN_NUMBER *)(mdl + 1))
+#define MmInitializeMdl(mdl, baseva, length) \
+do { \
+ (mdl)->next = NULL; \
+ (mdl)->size = MmSizeOfMdl(baseva, length); \
+ (mdl)->flags = 0; \
+ (mdl)->startva = PAGE_START(baseva); \
+ (mdl)->byteoffset = BYTE_OFFSET(baseva); \
+ (mdl)->bytecount = length; \
+ (mdl)->mappedsystemva = baseva; \
+ TRACE4("%p %p %p %d %d", (mdl), baseva, (mdl)->startva, \
+ (mdl)->byteoffset, length); \
+} while (0)
+
+struct kdevice_queue_entry {
+ struct nt_list list;
+ ULONG sort_key;
+ BOOLEAN inserted;
+};
+
+struct kdevice_queue {
+ USHORT type;
+ USHORT size;
+ struct nt_list list;
+ NT_SPIN_LOCK lock;
+ BOOLEAN busy;
+};
+
+struct wait_context_block {
+ struct kdevice_queue_entry wait_queue_entry;
+ void *device_routine;
+ void *device_context;
+ ULONG num_regs;
+ void *device_object;
+ void *current_irp;
+ void *buffer_chaining_dpc;
+};
+
+struct wait_block {
+ struct nt_list list;
+ struct task_struct *thread;
+ void *object;
+ int *wait_done;
+ USHORT wait_key;
+ USHORT wait_type;
+};
+
+struct dispatcher_header {
+ UCHAR type;
+ UCHAR absolute;
+ UCHAR size;
+ UCHAR inserted;
+ LONG signal_state;
+ struct nt_list wait_blocks;
+};
+
+enum event_type {
+ NotificationEvent,
+ SynchronizationEvent,
+};
+
+enum timer_type {
+ NotificationTimer = NotificationEvent,
+ SynchronizationTimer = SynchronizationEvent,
+};
+
+enum dh_type {
+ NotificationObject = NotificationEvent,
+ SynchronizationObject = SynchronizationEvent,
+ MutexObject,
+ SemaphoreObject,
+ ThreadObject,
+};
+
+enum wait_type {
+ WaitAll, WaitAny
+};
+
+/* objects that use dispatcher_header have it as the first field, so
+ * whenever we need to initialize dispatcher_header, we can convert
+ * that object into a nt_event and access dispatcher_header */
+struct nt_event {
+ struct dispatcher_header dh;
+};
+
+struct wrap_timer;
+
+#define WRAP_TIMER_MAGIC 47697249
+
+struct nt_timer {
+ struct dispatcher_header dh;
+ /* We can't fit Linux timer in this structure. Instead of
+ * padding the nt_timer structure, we replace due_time field
+ * with *wrap_timer and allocate memory for it when nt_timer is
+ * initialized */
+ union {
+ ULONGLONG due_time;
+ struct wrap_timer *wrap_timer;
+ };
+ struct nt_list nt_timer_list;
+ struct kdpc *kdpc;
+ union {
+ LONG period;
+ LONG wrap_timer_magic;
+ };
+};
+
+struct nt_mutex {
+ struct dispatcher_header dh;
+ struct nt_list list;
+ struct task_struct *owner_thread;
+ BOOLEAN abandoned;
+ BOOLEAN apc_disable;
+};
+
+struct nt_semaphore {
+ struct dispatcher_header dh;
+ LONG limit;
+};
+
+struct nt_thread {
+ struct dispatcher_header dh;
+ /* the rest in Windows is a long structure; since this
+ * structure is opaque to drivers, we just define what we
+ * need */
+ int pid;
+ NTSTATUS status;
+ struct task_struct *task;
+ struct nt_list irps;
+ NT_SPIN_LOCK lock;
+ KPRIORITY prio;
+};
+
+#define set_object_type(dh, type) ((dh)->type = (type))
+#define is_notify_object(dh) ((dh)->type == NotificationObject)
+#define is_synch_object(dh) ((dh)->type == SynchronizationObject)
+#define is_mutex_object(dh) ((dh)->type == MutexObject)
+#define is_semaphore_object(dh) ((dh)->type == SemaphoreObject)
+#define is_nt_thread_object(dh) ((dh)->type == ThreadObject)
+
+#define IO_TYPE_ADAPTER 1
+#define IO_TYPE_CONTROLLER 2
+#define IO_TYPE_DEVICE 3
+#define IO_TYPE_DRIVER 4
+#define IO_TYPE_FILE 5
+#define IO_TYPE_IRP 6
+#define IO_TYPE_DEVICE_OBJECT_EXTENSION 13
+
+struct irp;
+struct dev_obj_ext;
+struct driver_object;
+
+struct device_object {
+ CSHORT type;
+ USHORT size;
+ LONG ref_count;
+ struct driver_object *drv_obj;
+ struct device_object *next;
+ struct device_object *attached;
+ struct irp *current_irp;
+ void *io_timer;
+ ULONG flags;
+ ULONG characteristics;
+ void *vpb;
+ void *dev_ext;
+ CCHAR stack_count;
+ union {
+ struct nt_list queue_list;
+ struct wait_context_block wcb;
+ } queue;
+ ULONG align_req;
+ struct kdevice_queue dev_queue;
+ struct kdpc dpc;
+ ULONG active_threads;
+ void *security_desc;
+ struct nt_event lock;
+ USHORT sector_size;
+ USHORT spare1;
+ struct dev_obj_ext *dev_obj_ext;
+ void *reserved;
+};
+
+struct dev_obj_ext {
+ CSHORT type;
+ CSHORT size;
+ struct device_object *dev_obj;
+ struct device_object *attached_to;
+};
+
+struct io_status_block {
+ union {
+ NTSTATUS status;
+ void *pointer;
+ };
+ ULONG_PTR info;
+};
+
+#ifdef CONFIG_X86_64
+struct io_status_block32 {
+ NTSTATUS status;
+ ULONG info;
+};
+#endif
+
+#define DEVICE_TYPE ULONG
+
+struct driver_extension;
+
+typedef NTSTATUS driver_dispatch_t(struct device_object *dev_obj,
+ struct irp *irp) wstdcall;
+
+struct driver_object {
+ CSHORT type;
+ CSHORT size;
+ struct device_object *dev_obj;
+ ULONG flags;
+ void *start;
+ ULONG driver_size;
+ void *section;
+ struct driver_extension *drv_ext;
+ struct unicode_string name;
+ struct unicode_string *hardware_database;
+ void *fast_io_dispatch;
+ void *init;
+ void *start_io;
+ void (*unload)(struct driver_object *driver) wstdcall;
+ driver_dispatch_t *major_func[IRP_MJ_MAXIMUM_FUNCTION + 1];
+};
+
+struct driver_extension {
+ struct driver_object *drv_obj;
+ NTSTATUS (*add_device)(struct driver_object *drv_obj,
+ struct device_object *dev_obj) wstdcall;
+ ULONG count;
+ struct unicode_string service_key_name;
+ struct nt_list custom_ext;
+};
+
+struct custom_ext {
+ struct nt_list list;
+ void *client_id;
+};
+
+struct wrap_bin_file;
+
+struct file_object {
+ CSHORT type;
+ CSHORT size;
+ struct device_object *dev_obj;
+ void *volume_parameter_block;
+ void *fs_context;
+ void *fs_context2;
+ void *section_object_pointer;
+ void *private_cache_map;
+ NTSTATUS final_status;
+ union {
+ struct file_object *related_file_object;
+ struct wrap_bin_file *wrap_bin_file;
+ };
+ BOOLEAN lock_operation;
+ BOOLEAN delete_pending;
+ BOOLEAN read_access;
+ BOOLEAN write_access;
+ BOOLEAN delete_access;
+ BOOLEAN shared_read;
+ BOOLEAN shared_write;
+ BOOLEAN shared_delete;
+ ULONG flags;
+ struct unicode_string _name_;
+ LARGE_INTEGER current_byte_offset;
+ ULONG waiters;
+ ULONG busy;
+ void *last_lock;
+ struct nt_event lock;
+ struct nt_event event;
+ void *completion_context;
+};
+
+#ifdef CONFIG_X86_64
+#define POINTER_ALIGN __attribute__((aligned(8)))
+#else
+#define POINTER_ALIGN
+#endif
+
+#define CACHE_ALIGN __attribute__((aligned(128)))
+
+enum system_power_state {
+ PowerSystemUnspecified = 0,
+ PowerSystemWorking, PowerSystemSleeping1, PowerSystemSleeping2,
+ PowerSystemSleeping3, PowerSystemHibernate, PowerSystemShutdown,
+ PowerSystemMaximum,
+};
+
+enum device_power_state {
+ PowerDeviceUnspecified = 0,
+ PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, PowerDeviceD3,
+ PowerDeviceMaximum,
+};
+
+union power_state {
+ enum system_power_state system_state;
+ enum device_power_state device_state;
+};
+
+enum power_state_type {
+ SystemPowerState = 0, DevicePowerState,
+};
+
+enum power_action {
+ PowerActionNone = 0,
+ PowerActionReserved, PowerActionSleep, PowerActionHibernate,
+ PowerActionShutdown, PowerActionShutdownReset, PowerActionShutdownOff,
+ PowerActionWarmEject,
+};
+
+struct guid {
+ ULONG data1;
+ USHORT data2;
+ USHORT data3;
+ UCHAR data4[8];
+};
+
+struct nt_interface {
+ USHORT size;
+ USHORT version;
+ void *context;
+ void (*reference)(void *context) wstdcall;
+ void (*dereference)(void *context) wstdcall;
+};
+
+enum interface_type {
+ InterfaceTypeUndefined = -1, Internal, Isa, Eisa, MicroChannel,
+ TurboChannel, PCIBus, VMEBus, NuBus, PCMCIABus, CBus, MPIBus,
+ MPSABus, ProcessorInternal, InternalPowerBus, PNPISABus,
+ PNPBus, MaximumInterfaceType,
+};
+
+#define CmResourceTypeNull 0
+#define CmResourceTypePort 1
+#define CmResourceTypeInterrupt 2
+#define CmResourceTypeMemory 3
+#define CmResourceTypeDma 4
+#define CmResourceTypeDeviceSpecific 5
+#define CmResourceTypeBusNumber 6
+#define CmResourceTypeMaximum 7
+
+#define CmResourceTypeNonArbitrated 128
+#define CmResourceTypeConfigData 128
+#define CmResourceTypeDevicePrivate 129
+#define CmResourceTypePcCardConfig 130
+#define CmResourceTypeMfCardConfig 131
+
+enum cm_share_disposition {
+ CmResourceShareUndetermined = 0, CmResourceShareDeviceExclusive,
+ CmResourceShareDriverExclusive, CmResourceShareShared
+};
+
+#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0
+#define CM_RESOURCE_INTERRUPT_LATCHED 1
+#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 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 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
+
+#define MAX_RESOURCES 20
+
+#pragma pack(push,4)
+struct cm_partial_resource_descriptor {
+ UCHAR type;
+ UCHAR share;
+ USHORT flags;
+ union {
+ struct {
+ PHYSICAL_ADDRESS start;
+ ULONG length;
+ } generic;
+ struct {
+ PHYSICAL_ADDRESS start;
+ ULONG length;
+ } port;
+ struct {
+ ULONG level;
+ ULONG vector;
+ KAFFINITY affinity;
+ } interrupt;
+ struct {
+ PHYSICAL_ADDRESS start;
+ ULONG length;
+ } memory;
+ struct {
+ ULONG channel;
+ ULONG port;
+ ULONG reserved1;
+ } dma;
+ struct {
+ ULONG data[3];
+ } device_private;
+ struct {
+ ULONG start;
+ ULONG length;
+ ULONG reserved;
+ } bus_number;
+ struct {
+ ULONG data_size;
+ ULONG reserved1;
+ ULONG reserved2;
+ } device_specific_data;
+ } u;
+};
+#pragma pack(pop)
+
+struct cm_partial_resource_list {
+ USHORT version;
+ USHORT revision;
+ ULONG count;
+ struct cm_partial_resource_descriptor partial_descriptors[1];
+};
+
+struct cm_full_resource_descriptor {
+ enum interface_type interface_type;
+ ULONG bus_number;
+ struct cm_partial_resource_list partial_resource_list;
+};
+
+struct cm_resource_list {
+ ULONG count;
+ struct cm_full_resource_descriptor list[1];
+};
+
+enum file_info_class {
+ FileDirectoryInformation = 1,
+ FileBasicInformation = 4,
+ FileStandardInformation = 5,
+ FileNameInformation = 9,
+ FilePositionInformation = 14,
+ FileAlignmentInformation = 17,
+ FileNetworkOpenInformation = 34,
+ FileAttributeTagInformation = 35,
+ FileMaximumInformation = 41,
+};
+
+enum fs_info_class {
+ FileFsVolumeInformation = 1,
+ /* ... */
+ FileFsMaximumInformation = 9,
+};
+
+enum device_relation_type {
+ BusRelations, EjectionRelations, PowerRelations, RemovalRelations,
+ TargetDeviceRelation, SingleBusRelations,
+};
+
+enum bus_query_id_type {
+ BusQueryDeviceID = 0, BusQueryHardwareIDs = 1,
+ BusQueryCompatibleIDs = 2, BusQueryInstanceID = 3,
+ BusQueryDeviceSerialNumber = 4,
+};
+
+enum device_text_type {
+ DeviceTextDescription = 0, DeviceTextLocationInformation = 1,
+};
+
+enum device_usage_notification_type {
+ DeviceUsageTypeUndefined, DeviceUsageTypePaging,
+ DeviceUsageTypeHibernation, DevbiceUsageTypeDumpFile,
+};
+
+#define METHOD_BUFFERED 0
+#define METHOD_IN_DIRECT 1
+#define METHOD_OUT_DIRECT 2
+#define METHOD_NEITHER 3
+
+#define CTL_CODE(dev_type, func, method, access) \
+ (((dev_type) << 16) | ((access) << 14) | ((func) << 2) | (method))
+
+#define IO_METHOD_FROM_CTL_CODE(code) (code & 0x3)
+
+#ifndef CONFIG_X86_64
+#pragma pack(push,4)
+#endif
+struct io_stack_location {
+ UCHAR major_fn;
+ UCHAR minor_fn;
+ UCHAR flags;
+ UCHAR control;
+ union {
+ struct {
+ void *security_context;
+ ULONG options;
+ USHORT POINTER_ALIGN file_attributes;
+ USHORT share_access;
+ ULONG POINTER_ALIGN ea_length;
+ } create;
+ struct {
+ ULONG length;
+ ULONG POINTER_ALIGN key;
+ LARGE_INTEGER byte_offset;
+ } read;
+ struct {
+ ULONG length;
+ ULONG POINTER_ALIGN key;
+ LARGE_INTEGER byte_offset;
+ } write;
+ struct {
+ ULONG length;
+ enum file_info_class POINTER_ALIGN file_info_class;
+ } query_file;
+ struct {
+ ULONG length;
+ enum file_info_class POINTER_ALIGN file_info_class;
+ struct file_object *file_object;
+ union {
+ struct {
+ BOOLEAN replace_if_exists;
+ BOOLEAN advance_only;
+ };
+ ULONG cluster_count;
+ void *delete_handle;
+ };
+ } set_file;
+ struct {
+ ULONG length;
+ enum fs_info_class POINTER_ALIGN fs_info_class;
+ } query_volume;
+ struct {
+ ULONG output_buf_len;
+ ULONG POINTER_ALIGN input_buf_len;
+ ULONG POINTER_ALIGN code;
+ void *type3_input_buf;
+ } dev_ioctl;
+ struct {
+ SECURITY_INFORMATION security_info;
+ ULONG POINTER_ALIGN length;
+ } query_security;
+ struct {
+ SECURITY_INFORMATION security_info;
+ void *security_descriptor;
+ } set_security;
+ struct {
+ void *vpb;
+ struct device_object *device_object;
+ } mount_volume;
+ struct {
+ void *vpb;
+ struct device_object *device_object;
+ } verify_volume;
+ struct {
+ void *srb;
+ } scsi;
+ struct {
+ enum device_relation_type type;
+ } query_device_relations;
+ struct {
+ const struct guid *type;
+ USHORT size;
+ USHORT version;
+ struct nt_interface *intf;
+ void *intf_data;
+ } query_intf;
+ struct {
+ void *capabilities;
+ } device_capabilities;
+ struct {
+ void *io_resource_requirement_list;
+ } filter_resource_requirements;
+ struct {
+ ULONG which_space;
+ void *buffer;
+ ULONG offset;
+ ULONG POINTER_ALIGN length;
+ } read_write_config;
+ struct {
+ BOOLEAN lock;
+ } set_lock;
+ struct {
+ enum bus_query_id_type id_type;
+ } query_id;
+ struct {
+ enum device_text_type device_text_type;
+ ULONG POINTER_ALIGN locale_id;
+ } query_device_text;
+ struct {
+ BOOLEAN in_path;
+ BOOLEAN reserved[3];
+ enum device_usage_notification_type POINTER_ALIGN type;
+ } usage_notification;
+ struct {
+ enum system_power_state power_state;
+ } wait_wake;
+ struct {
+ void *power_sequence;
+ } power_sequence;
+ struct {
+ ULONG sys_context;
+ enum power_state_type POINTER_ALIGN type;
+ union power_state POINTER_ALIGN state;
+ enum power_action POINTER_ALIGN shutdown_type;
+ } power;
+ struct {
+ struct cm_resource_list *allocated_resources;
+ struct cm_resource_list *allocated_resources_translated;
+ } start_device;
+ struct {
+ ULONG_PTR provider_id;
+ void *data_path;
+ ULONG buf_len;
+ void *buf;
+ } wmi;
+ struct {
+ void *arg1;
+ void *arg2;
+ void *arg3;
+ void *arg4;
+ } others;
+ } params;
+ struct device_object *dev_obj;
+ struct file_object *file_obj;
+ NTSTATUS (*completion_routine)(struct device_object *,
+ struct irp *, void *) wstdcall;
+ void *context;
+};
+#ifndef CONFIG_X86_64
+#pragma pack(pop)
+#endif
+
+struct kapc {
+ CSHORT type;
+ CSHORT size;
+ ULONG spare0;
+ struct nt_thread *thread;
+ struct nt_list list;
+ void *kernele_routine;
+ void *rundown_routine;
+ void *normal_routine;
+ void *normal_context;
+ void *sys_arg1;
+ void *sys_arg2;
+ CCHAR apc_state_index;
+ KPROCESSOR_MODE apc_mode;
+ BOOLEAN inserted;
+};
+
+#define IRP_NOCACHE 0x00000001
+#define IRP_SYNCHRONOUS_API 0x00000004
+#define IRP_ASSOCIATED_IRP 0x00000008
+
+enum urb_state {
+ URB_INVALID = 1, URB_ALLOCATED, URB_SUBMITTED,
+ URB_COMPLETED, URB_FREE, URB_SUSPEND, URB_INT_UNLINKED };
+
+struct wrap_urb {
+ struct nt_list list;
+ enum urb_state state;
+ struct nt_list complete_list;
+ unsigned int flags;
+ struct urb *urb;
+ struct irp *irp;
+#ifdef USB_DEBUG
+ unsigned int id;
+#endif
+};
+
+struct irp {
+ SHORT type;
+ USHORT size;
+ struct mdl *mdl;
+ ULONG flags;
+ union {
+ struct irp *master_irp;
+ LONG irp_count;
+ void *system_buffer;
+ } associated_irp;
+ struct nt_list thread_list;
+ struct io_status_block io_status;
+ KPROCESSOR_MODE requestor_mode;
+ BOOLEAN pending_returned;
+ CHAR stack_count;
+ CHAR current_location;
+ BOOLEAN cancel;
+ KIRQL cancel_irql;
+ CCHAR apc_env;
+ UCHAR alloc_flags;
+ struct io_status_block *user_status;
+ struct nt_event *user_event;
+ union {
+ struct {
+ void *user_apc_routine;
+ void *user_apc_context;
+ } async_params;
+ LARGE_INTEGER alloc_size;
+ } overlay;
+ void (*cancel_routine)(struct device_object *, struct irp *) wstdcall;
+ void *user_buf;
+ union {
+ struct {
+ union {
+ struct kdevice_queue_entry dev_q_entry;
+ struct {
+ void *driver_context[4];
+ };
+ };
+ void *thread;
+ char *aux_buf;
+ struct {
+ struct nt_list list;
+ union {
+ struct io_stack_location *csl;
+ ULONG packet_type;
+ };
+ };
+ struct file_object *file_object;
+ } overlay;
+ union {
+ struct kapc apc;
+ /* space for apc is used for ndiswrapper
+ * specific fields */
+ struct {
+ struct wrap_urb *wrap_urb;
+ struct wrap_device *wrap_device;
+ };
+ };
+ void *completion_key;
+ } tail;
+};
+
+#define IoSizeOfIrp(stack_count) \
+ ((USHORT)(sizeof(struct irp) + \
+ ((stack_count) * sizeof(struct io_stack_location))))
+#define IoGetCurrentIrpStackLocation(irp) \
+ (irp)->tail.overlay.csl
+#define IoGetNextIrpStackLocation(irp) \
+ (IoGetCurrentIrpStackLocation(irp) - 1)
+#define IoGetPreviousIrpStackLocation(irp) \
+ (IoGetCurrentIrpStackLocation(irp) + 1)
+
+#define IoSetNextIrpStackLocation(irp) \
+do { \
+ KIRQL _irql_; \
+ IoAcquireCancelSpinLock(&_irql_); \
+ (irp)->current_location--; \
+ IoGetCurrentIrpStackLocation(irp)--; \
+ IoReleaseCancelSpinLock(_irql_); \
+} while (0)
+
+#define IoSkipCurrentIrpStackLocation(irp) \
+do { \
+ KIRQL _irql_; \
+ IoAcquireCancelSpinLock(&_irql_); \
+ (irp)->current_location++; \
+ IoGetCurrentIrpStackLocation(irp)++; \
+ IoReleaseCancelSpinLock(_irql_); \
+} while (0)
+
+static inline void
+IoCopyCurrentIrpStackLocationToNext(struct irp *irp)
+{
+ struct io_stack_location *next;
+ next = IoGetNextIrpStackLocation(irp);
+ memcpy(next, IoGetCurrentIrpStackLocation(irp),
+ offsetof(struct io_stack_location, completion_routine));
+ next->control = 0;
+}
+
+static inline void
+IoSetCompletionRoutine(struct irp *irp, void *routine, void *context,
+ BOOLEAN success, BOOLEAN error, BOOLEAN cancel)
+{
+ struct io_stack_location *irp_sl = IoGetNextIrpStackLocation(irp);
+ irp_sl->completion_routine = routine;
+ irp_sl->context = context;
+ irp_sl->control = 0;
+ if (success)
+ irp_sl->control |= SL_INVOKE_ON_SUCCESS;
+ if (error)
+ irp_sl->control |= SL_INVOKE_ON_ERROR;
+ if (cancel)
+ irp_sl->control |= SL_INVOKE_ON_CANCEL;
+}
+
+#define IoMarkIrpPending(irp) \
+ (IoGetCurrentIrpStackLocation((irp))->control |= SL_PENDING_RETURNED)
+#define IoUnmarkIrpPending(irp) \
+ (IoGetCurrentIrpStackLocation((irp))->control &= ~SL_PENDING_RETURNED)
+
+#define IRP_SL(irp, n) (((struct io_stack_location *)((irp) + 1)) + (n))
+#define IRP_DRIVER_CONTEXT(irp) (irp)->tail.overlay.driver_context
+#define IoIrpThread(irp) ((irp)->tail.overlay.thread)
+
+#define IRP_URB(irp) \
+ (union nt_urb *)(IoGetCurrentIrpStackLocation(irp)->params.others.arg1)
+
+#define IRP_WRAP_DEVICE(irp) (irp)->tail.wrap_device
+#define IRP_WRAP_URB(irp) (irp)->tail.wrap_urb
+
+struct wmi_guid_reg_info {
+ struct guid *guid;
+ ULONG instance_count;
+ ULONG flags;
+};
+
+struct wmilib_context {
+ ULONG guid_count;
+ struct wmi_guid_reg_info *guid_list;
+ void *query_wmi_reg_info;
+ void *query_wmi_data_block;
+ void *set_wmi_data_block;
+ void *set_wmi_data_item;
+ void *execute_wmi_method;
+ void *wmi_function_control;
+};
+
+enum key_value_information_class {
+ KeyValueBasicInformation, KeyValueFullInformation,
+ KeyValuePartialInformation, KeyValueFullInformationAlign64,
+ KeyValuePartialInformationAlign64
+};
+
+struct file_name_info {
+ ULONG length;
+ wchar_t *name;
+};
+
+struct file_std_info {
+ LARGE_INTEGER alloc_size;
+ LARGE_INTEGER eof;
+ ULONG num_links;
+ BOOLEAN delete_pending;
+ BOOLEAN dir;
+};
+
+enum nt_obj_type {
+ NT_OBJ_EVENT = 10, NT_OBJ_MUTEX, NT_OBJ_THREAD, NT_OBJ_TIMER,
+ NT_OBJ_SEMAPHORE,
+};
+
+enum common_object_type {
+ OBJECT_TYPE_NONE, OBJECT_TYPE_DEVICE, OBJECT_TYPE_DRIVER,
+ OBJECT_TYPE_NT_THREAD, OBJECT_TYPE_FILE, OBJECT_TYPE_CALLBACK,
+};
+
+struct common_object_header {
+ struct nt_list list;
+ enum common_object_type type;
+ UINT size;
+ UINT ref_count;
+ BOOLEAN close_in_process;
+ BOOLEAN permanent;
+ struct unicode_string name;
+};
+
+#define OBJECT_TO_HEADER(object) \
+ (struct common_object_header *)((void *)(object) - \
+ sizeof(struct common_object_header))
+#define OBJECT_SIZE(size) \
+ ((size) + sizeof(struct common_object_header))
+#define HEADER_TO_OBJECT(hdr) \
+ ((void *)(hdr) + sizeof(struct common_object_header))
+#define HANDLE_TO_OBJECT(handle) HEADER_TO_OBJECT(handle)
+#define HANDLE_TO_HEADER(handle) (handle)
+
+enum work_queue_type {
+ CriticalWorkQueue, DelayedWorkQueue, HyperCriticalWorkQueue,
+ MaximumWorkQueue
+};
+
+typedef void (*NTOS_WORK_FUNC)(void *arg1, void *arg2) wstdcall;
+
+struct io_workitem {
+ enum work_queue_type type;
+ struct device_object *dev_obj;
+ NTOS_WORK_FUNC worker_routine;
+ void *context;
+};
+
+struct io_workitem_entry {
+ struct nt_list list;
+ struct io_workitem *io_workitem;
+};
+
+enum mm_page_priority {
+ LowPagePriority, NormalPagePriority = 16, HighPagePriority = 32
+};
+
+enum kinterrupt_mode {
+ LevelSensitive, Latched
+};
+
+enum ntos_wait_reason {
+ Executive, FreePage, PageIn, PoolAllocation, DelayExecution,
+ Suspended, UserRequest, WrExecutive, WrFreePage, WrPageIn,
+ WrPoolAllocation, WrDelayExecution, WrSuspended, WrUserRequest,
+ WrEventPair, WrQueue, WrLpcReceive, WrLpcReply, WrVirtualMemory,
+ WrPageOut, WrRendezvous, Spare2, Spare3, Spare4, Spare5, Spare6,
+ WrKernel, MaximumWaitReason
+};
+
+typedef enum ntos_wait_reason KWAIT_REASON;
+
+typedef void *LOOKASIDE_ALLOC_FUNC(enum pool_type pool_type,
+ SIZE_T size, ULONG tag) wstdcall;
+typedef void LOOKASIDE_FREE_FUNC(void *) wstdcall;
+
+struct npaged_lookaside_list {
+ nt_slist_header head;
+ USHORT depth;
+ USHORT maxdepth;
+ ULONG totalallocs;
+ union {
+ ULONG allocmisses;
+ ULONG allochits;
+ } u1;
+ ULONG totalfrees;
+ union {
+ ULONG freemisses;
+ ULONG freehits;
+ } u2;
+ enum pool_type pool_type;
+ ULONG tag;
+ ULONG size;
+ LOOKASIDE_ALLOC_FUNC *alloc_func;
+ LOOKASIDE_FREE_FUNC *free_func;
+ struct nt_list list;
+ ULONG lasttotallocs;
+ union {
+ ULONG lastallocmisses;
+ ULONG lastallochits;
+ } u3;
+ ULONG pad[2];
+#ifndef CONFIG_X86_64
+ NT_SPIN_LOCK obsolete;
+#endif
+}
+#ifdef CONFIG_X86_64
+CACHE_ALIGN
+#endif
+;
+
+enum device_registry_property {
+ DevicePropertyDeviceDescription, DevicePropertyHardwareID,
+ DevicePropertyCompatibleIDs, DevicePropertyBootConfiguration,
+ DevicePropertyBootConfigurationTranslated,
+ DevicePropertyClassName, DevicePropertyClassGuid,
+ DevicePropertyDriverKeyName, DevicePropertyManufacturer,
+ DevicePropertyFriendlyName, DevicePropertyLocationInformation,
+ DevicePropertyPhysicalDeviceObjectName, DevicePropertyBusTypeGuid,
+ DevicePropertyLegacyBusType, DevicePropertyBusNumber,
+ DevicePropertyEnumeratorName, DevicePropertyAddress,
+ DevicePropertyUINumber, DevicePropertyInstallState,
+ DevicePropertyRemovalPolicy
+};
+
+enum trace_information_class {
+ TraceIdClass, TraceHandleClass, TraceEnableFlagsClass,
+ TraceEnableLevelClass, GlobalLoggerHandleClass, EventLoggerHandleClass,
+ AllLoggerHandlesClass, TraceHandleByNameClass
+};
+
+struct kinterrupt;
+typedef BOOLEAN (*PKSERVICE_ROUTINE)(struct kinterrupt *interrupt,
+ void *context) wstdcall;
+typedef BOOLEAN (*PKSYNCHRONIZE_ROUTINE)(void *context) wstdcall;
+
+struct kinterrupt {
+ ULONG vector;
+ KAFFINITY cpu_mask;
+ NT_SPIN_LOCK lock;
+ NT_SPIN_LOCK *actual_lock;
+ BOOLEAN shared;
+ BOOLEAN save_fp;
+ union {
+ CHAR processor_number;
+#ifdef CONFIG_DEBUG_SHIRQ
+ CHAR enabled;
+#endif
+ } u;
+ PKSERVICE_ROUTINE isr;
+ void *isr_ctx;
+ struct nt_list list;
+ KIRQL irql;
+ KIRQL synch_irql;
+ enum kinterrupt_mode mode;
+};
+
+struct time_fields {
+ CSHORT year;
+ CSHORT month;
+ CSHORT day;
+ CSHORT hour;
+ CSHORT minute;
+ CSHORT second;
+ CSHORT milliseconds;
+ CSHORT weekday;
+};
+
+struct object_attributes {
+ ULONG length;
+ void *root_dir;
+ struct unicode_string *name;
+ ULONG attributes;
+ void *security_descr;
+ void *security_qos;
+};
+
+typedef void (*PCALLBACK_FUNCTION)(void *context, void *arg1,
+ void *arg2) wstdcall;
+
+struct callback_object;
+struct callback_func {
+ PCALLBACK_FUNCTION func;
+ void *context;
+ struct nt_list list;
+ struct callback_object *object;
+};
+
+struct callback_object {
+ NT_SPIN_LOCK lock;
+ struct nt_list list;
+ struct nt_list callback_funcs;
+ BOOLEAN allow_multiple_callbacks;
+ struct object_attributes *attributes;
+};
+
+enum section_inherit {
+ ViewShare = 1, ViewUnmap = 2
+};
+
+struct ksystem_time {
+ ULONG low_part;
+ LONG high1_time;
+ LONG high2_time;
+};
+
+enum nt_product_type {
+ nt_product_win_nt = 1, nt_product_lan_man_nt, nt_product_server
+};
+
+enum alt_arch_type {
+ arch_type_standard, arch_type_nex98x86, end_alternatives
+};
+
+struct kuser_shared_data {
+ ULONG tick_count;
+ ULONG tick_count_multiplier;
+ volatile struct ksystem_time interrupt_time;
+ volatile struct ksystem_time system_time;
+ volatile struct ksystem_time time_zone_bias;
+ USHORT image_number_low;
+ USHORT image_number_high;
+ wchar_t nt_system_root[260];
+ ULONG max_stack_trace_depth;
+ ULONG crypto_exponent;
+ ULONG time_zone_id;
+ ULONG large_page_min;
+ ULONG reserved2[7];
+ enum nt_product_type nt_product_type;
+ BOOLEAN product_type_is_valid;
+ ULONG nt_major_version;
+ ULONG nt_minor_version;
+ BOOLEAN processor_features[PROCESSOR_FEATURE_MAX];
+ ULONG reserved1;
+ ULONG reserved3;
+ volatile LONG time_slip;
+ enum alt_arch_type alt_arch_type;
+ LARGE_INTEGER system_expiration_date;
+ ULONG suite_mask;
+ BOOLEAN kdbg_enabled;
+ volatile ULONG active_console;
+ volatile ULONG dismount_count;
+ ULONG com_plus_package;
+ ULONG last_system_rite_event_tick_count;
+ ULONG num_phys_pages;
+ BOOLEAN safe_boot_mode;
+ ULONG trace_log;
+ ULONGLONG fill0;
+ ULONGLONG sys_call[4];
+ union {
+ volatile struct ksystem_time tick_count;
+ volatile ULONG64 tick_count_quad;
+ } tick;
+};
+
+#define REG_NONE (0)
+#define REG_SZ (1)
+#define REG_EXPAND_SZ (2)
+#define REG_BINARY (3)
+#define REG_DWORD (4)
+
+#define RTL_REGISTRY_ABSOLUTE 0
+#define RTL_REGISTRY_SERVICES 1
+#define RTL_REGISTRY_CONTROL 2
+#define RTL_REGISTRY_WINDOWS_NT 3
+#define RTL_REGISTRY_DEVICEMAP 4
+#define RTL_REGISTRY_USER 5
+#define RTL_REGISTRY_MAXIMUM 6
+#define RTL_REGISTRY_HANDLE 0x40000000
+#define RTL_REGISTRY_OPTIONAL 0x80000000
+
+#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001
+#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002
+#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004
+#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008
+#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010
+#define RTL_QUERY_REGISTRY_DIRECT 0x00000020
+#define RTL_QUERY_REGISTRY_DELETE 0x00000040
+
+typedef NTSTATUS (*PRTL_QUERY_REGISTRY_ROUTINE)(wchar_t *name, ULONG type,
+ void *data, ULONG length,
+ void *context,
+ void *entry) wstdcall;
+
+struct rtl_query_registry_table {
+ PRTL_QUERY_REGISTRY_ROUTINE query_func;
+ ULONG flags;
+ wchar_t *name;
+ void *context;
+ ULONG def_type;
+ void *def_data;
+ ULONG def_length;
+};
+
+struct io_remove_lock {
+ BOOLEAN removed;
+ BOOLEAN reserved[3];
+ LONG io_count;
+ struct nt_event remove_event;
+};
+
+struct io_error_log_packet {
+ UCHAR major_fn_code;
+ UCHAR retry_count;
+ USHORT dump_data_size;
+ USHORT nr_of_strings;
+ USHORT string_offset;
+ USHORT event_category;
+ NTSTATUS error_code;
+ ULONG unique_error_value;
+ NTSTATUS final_status;
+ ULONG sequence_number;
+ ULONG io_control_code;
+ LARGE_INTEGER device_offset;
+ ULONG dump_data[1];
+};
+
+/* some of the functions below are slightly different from DDK's
+ * implementation; e.g., Insert functions return appropriate
+ * pointer */
+
+/* instead of using Linux's lists, we implement list manipulation
+ * functions because nt_list is used by drivers and we don't want to
+ * worry about Linux's list being different from nt_list (right now
+ * they are same, but in future they could be different) */
+
+static inline void InitializeListHead(struct nt_list *head)
+{
+ head->next = head->prev = head;
+}
+
+static inline BOOLEAN IsListEmpty(struct nt_list *head)
+{
+ if (head == head->next)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static inline void RemoveEntryList(struct nt_list *entry)
+{
+ entry->prev->next = entry->next;
+ entry->next->prev = entry->prev;
+}
+
+static inline struct nt_list *RemoveHeadList(struct nt_list *head)
+{
+ struct nt_list *entry;
+
+ entry = head->next;
+ if (entry == head)
+ return NULL;
+ else {
+ RemoveEntryList(entry);
+ return entry;
+ }
+}
+
+static inline struct nt_list *RemoveTailList(struct nt_list *head)
+{
+ struct nt_list *entry;
+
+ entry = head->prev;
+ if (entry == head)
+ return NULL;
+ else {
+ RemoveEntryList(entry);
+ return entry;
+ }
+}
+
+static inline void InsertListEntry(struct nt_list *entry, struct nt_list *prev,
+ struct nt_list *next)
+{
+ next->prev = entry;
+ entry->next = next;
+ entry->prev = prev;
+ prev->next = entry;
+}
+
+static inline struct nt_list *InsertHeadList(struct nt_list *head,
+ struct nt_list *entry)
+{
+ struct nt_list *ret;
+
+ if (IsListEmpty(head))
+ ret = NULL;
+ else
+ ret = head->next;
+
+ InsertListEntry(entry, head, head->next);
+ return ret;
+}
+
+static inline struct nt_list *InsertTailList(struct nt_list *head,
+ struct nt_list *entry)
+{
+ struct nt_list *ret;
+
+ if (IsListEmpty(head))
+ ret = NULL;
+ else
+ ret = head->prev;
+
+ InsertListEntry(entry, head->prev, head);
+ return ret;
+}
+
+#define nt_list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define nt_list_for_each_entry(pos, head, member) \
+ for (pos = container_of((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = container_of(pos->member.next, typeof(*pos), member))
+
+#define nt_list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/* device object flags */
+#define DO_VERIFY_VOLUME 0x00000002
+#define DO_BUFFERED_IO 0x00000004
+#define DO_EXCLUSIVE 0x00000008
+#define DO_DIRECT_IO 0x00000010
+#define DO_MAP_IO_BUFFER 0x00000020
+#define DO_DEVICE_HAS_NAME 0x00000040
+#define DO_DEVICE_INITIALIZING 0x00000080
+#define DO_SYSTEM_BOOT_PARTITION 0x00000100
+#define DO_LONG_TERM_REQUESTS 0x00000200
+#define DO_NEVER_LAST_DEVICE 0x00000400
+#define DO_SHUTDOWN_REGISTERED 0x00000800
+#define DO_BUS_ENUMERATED_DEVICE 0x00001000
+#define DO_POWER_PAGABLE 0x00002000
+#define DO_POWER_INRUSH 0x00004000
+#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000
+
+/* Various supported device types (used with IoCreateDevice()) */
+
+#define FILE_DEVICE_BEEP 0x00000001
+#define FILE_DEVICE_CD_ROM 0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
+#define FILE_DEVICE_CONTROLLER 0x00000004
+#define FILE_DEVICE_DATALINK 0x00000005
+#define FILE_DEVICE_DFS 0x00000006
+#define FILE_DEVICE_DISK 0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define FILE_DEVICE_INPORT_PORT 0x0000000A
+#define FILE_DEVICE_KEYBOARD 0x0000000B
+#define FILE_DEVICE_MAILSLOT 0x0000000C
+#define FILE_DEVICE_MIDI_IN 0x0000000D
+#define FILE_DEVICE_MIDI_OUT 0x0000000E
+#define FILE_DEVICE_MOUSE 0x0000000F
+#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010
+#define FILE_DEVICE_NAMED_PIPE 0x00000011
+#define FILE_DEVICE_NETWORK 0x00000012
+#define FILE_DEVICE_NETWORK_BROWSER 0x00000013
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL 0x00000015
+#define FILE_DEVICE_PARALLEL_PORT 0x00000016
+#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
+#define FILE_DEVICE_PRINTER 0x00000018
+#define FILE_DEVICE_SCANNER 0x00000019
+#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001A
+#define FILE_DEVICE_SERIAL_PORT 0x0000001B
+#define FILE_DEVICE_SCREEN 0x0000001C
+#define FILE_DEVICE_SOUND 0x0000001D
+#define FILE_DEVICE_STREAMS 0x0000001E
+#define FILE_DEVICE_TAPE 0x0000001F
+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+#define FILE_DEVICE_TRANSPORT 0x00000021
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#define FILE_DEVICE_VIDEO 0x00000023
+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
+#define FILE_DEVICE_WAVE_IN 0x00000025
+#define FILE_DEVICE_WAVE_OUT 0x00000026
+#define FILE_DEVICE_8042_PORT 0x00000027
+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
+#define FILE_DEVICE_BATTERY 0x00000029
+#define FILE_DEVICE_BUS_EXTENDER 0x0000002A
+#define FILE_DEVICE_MODEM 0x0000002B
+#define FILE_DEVICE_VDM 0x0000002C
+#define FILE_DEVICE_MASS_STORAGE 0x0000002D
+#define FILE_DEVICE_SMB 0x0000002E
+#define FILE_DEVICE_KS 0x0000002F
+#define FILE_DEVICE_CHANGER 0x00000030
+#define FILE_DEVICE_SMARTCARD 0x00000031
+#define FILE_DEVICE_ACPI 0x00000032
+#define FILE_DEVICE_DVD 0x00000033
+#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034
+#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035
+#define FILE_DEVICE_DFS_VOLUME 0x00000036
+#define FILE_DEVICE_SERENUM 0x00000037
+#define FILE_DEVICE_TERMSRV 0x00000038
+#define FILE_DEVICE_KSEC 0x00000039
+#define FILE_DEVICE_FIPS 0x0000003A
+
+/* Device characteristics */
+
+#define FILE_REMOVABLE_MEDIA 0x00000001
+#define FILE_READ_ONLY_DEVICE 0x00000002
+#define FILE_FLOPPY_DISKETTE 0x00000004
+#define FILE_WRITE_ONCE_MEDIA 0x00000008
+#define FILE_REMOTE_DEVICE 0x00000010
+#define FILE_DEVICE_IS_MOUNTED 0x00000020
+#define FILE_VIRTUAL_VOLUME 0x00000040
+#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080
+#define FILE_DEVICE_SECURE_OPEN 0x00000100
+
+#define FILE_READ_DATA 0x0001
+#define FILE_WRITE_DATA 0x0002
+
+#define FILE_SUPERSEDED 0x00000000
+#define FILE_OPENED 0x00000001
+#define FILE_CREATED 0x00000002
+#define FILE_OVERWRITTEN 0x00000003
+#define FILE_EXISTS 0x00000004
+#define FILE_DOES_NOT_EXIST 0x00000005
+
+
+#endif /* WINNT_TYPES_H */
--- /dev/null
+/*
+ * Copyright (C) 2006 Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define _WRAPMEM_C_
+
+#include "ntoskernel.h"
+
+struct slack_alloc_info {
+ struct nt_list list;
+ size_t size;
+};
+
+static struct nt_list allocs;
+static struct nt_list slack_allocs;
+static spinlock_t alloc_lock;
+
+struct vmem_block {
+ struct nt_list list;
+ int size;
+};
+
+static struct nt_list vmem_list;
+
+#if defined(ALLOC_DEBUG)
+struct alloc_info {
+ enum alloc_type type;
+ size_t size;
+#if ALLOC_DEBUG > 1
+ struct nt_list list;
+ const char *file;
+ int line;
+ ULONG tag;
+#endif
+};
+
+static atomic_t alloc_sizes[ALLOC_TYPE_MAX];
+#endif
+
+void wrapmem_info(void)
+{
+#ifdef ALLOC_DEBUG
+ enum alloc_type type;
+ for (type = 0; type < ALLOC_TYPE_MAX; type++)
+ INFO("total size of allocations in %d: %d",
+ type, atomic_read(&alloc_sizes[type]));
+#endif
+}
+
+/* allocate memory and add it to list of allocated pointers; if a
+ * driver doesn't free this memory for any reason (buggy driver or we
+ * allocate space behind driver's back since we need more space than
+ * corresponding Windows structure provides etc.), this gets freed
+ * automatically when module is unloaded
+ */
+void *slack_kmalloc(size_t size)
+{
+ struct slack_alloc_info *info;
+ gfp_t flags;
+
+ ENTER4("size = %lu", (unsigned long)size);
+
+ if (irql_gfp() & GFP_ATOMIC)
+ flags = GFP_ATOMIC;
+ else
+ flags = GFP_KERNEL;
+ info = kmalloc(size + sizeof(*info), flags);
+ if (!info)
+ return NULL;
+ info->size = size;
+ spin_lock_bh(&alloc_lock);
+ InsertTailList(&slack_allocs, &info->list);
+ spin_unlock_bh(&alloc_lock);
+#ifdef ALLOC_DEBUG
+ atomic_add(size, &alloc_sizes[ALLOC_TYPE_SLACK]);
+#endif
+ TRACE4("%p, %p", info, info + 1);
+ EXIT4(return info + 1);
+}
+
+/* free pointer and remove from list of allocated pointers */
+void slack_kfree(void *ptr)
+{
+ struct slack_alloc_info *info;
+
+ ENTER4("%p", ptr);
+ info = ptr - sizeof(*info);
+ spin_lock_bh(&alloc_lock);
+ RemoveEntryList(&info->list);
+ spin_unlock_bh(&alloc_lock);
+#ifdef ALLOC_DEBUG
+ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
+#endif
+ kfree(info);
+ EXIT4(return);
+}
+
+#if defined(ALLOC_DEBUG)
+void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line)
+{
+ struct alloc_info *info;
+
+ info = kmalloc(size + sizeof(*info), flags);
+ if (!info)
+ return NULL;
+ if (flags & GFP_ATOMIC)
+ info->type = ALLOC_TYPE_KMALLOC_ATOMIC;
+ else
+ info->type = ALLOC_TYPE_KMALLOC_NON_ATOMIC;
+ info->size = size;
+ atomic_add(size, &alloc_sizes[info->type]);
+#if ALLOC_DEBUG > 1
+ info->file = file;
+ info->line = line;
+ info->tag = 0;
+ spin_lock_bh(&alloc_lock);
+ InsertTailList(&allocs, &info->list);
+ spin_unlock_bh(&alloc_lock);
+#endif
+ TRACE4("%p", info + 1);
+ return info + 1;
+}
+
+void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line)
+{
+ void *ptr = wrap_kmalloc(size, flags, file, line);
+ if (ptr)
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void wrap_kfree(void *ptr)
+{
+ struct alloc_info *info;
+
+ TRACE4("%p", ptr);
+ if (!ptr)
+ return;
+ info = ptr - sizeof(*info);
+ atomic_sub(info->size, &alloc_sizes[info->type]);
+#if ALLOC_DEBUG > 1
+ spin_lock_bh(&alloc_lock);
+ RemoveEntryList(&info->list);
+ spin_unlock_bh(&alloc_lock);
+ if (!(info->type == ALLOC_TYPE_KMALLOC_ATOMIC ||
+ info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC))
+ WARNING("invliad type: %d", info->type);
+#endif
+ kfree(info);
+}
+
+void *wrap_vmalloc(unsigned long size, const char *file, int line)
+{
+ struct alloc_info *info;
+
+ info = vmalloc(size + sizeof(*info));
+ if (!info)
+ return NULL;
+ info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC;
+ info->size = size;
+ atomic_add(size, &alloc_sizes[info->type]);
+#if ALLOC_DEBUG > 1
+ info->file = file;
+ info->line = line;
+ info->tag = 0;
+ spin_lock_bh(&alloc_lock);
+ InsertTailList(&allocs, &info->list);
+ spin_unlock_bh(&alloc_lock);
+#endif
+ return info + 1;
+}
+
+void *wrap__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
+ const char *file, int line)
+{
+ struct alloc_info *info;
+
+ info = __vmalloc(size + sizeof(*info), gfp_mask, prot);
+ if (!info)
+ return NULL;
+ if (gfp_mask & GFP_ATOMIC)
+ info->type = ALLOC_TYPE_VMALLOC_ATOMIC;
+ else
+ info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC;
+ info->size = size;
+ atomic_add(size, &alloc_sizes[info->type]);
+#if ALLOC_DEBUG > 1
+ info->file = file;
+ info->line = line;
+ info->tag = 0;
+ spin_lock_bh(&alloc_lock);
+ InsertTailList(&allocs, &info->list);
+ spin_unlock_bh(&alloc_lock);
+#endif
+ return info + 1;
+}
+
+void wrap_vfree(void *ptr)
+{
+ struct alloc_info *info;
+
+ info = ptr - sizeof(*info);
+ atomic_sub(info->size, &alloc_sizes[info->type]);
+#if ALLOC_DEBUG > 1
+ spin_lock_bh(&alloc_lock);
+ RemoveEntryList(&info->list);
+ spin_unlock_bh(&alloc_lock);
+ if (!(info->type == ALLOC_TYPE_VMALLOC_ATOMIC ||
+ info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC))
+ WARNING("invliad type: %d", info->type);
+#endif
+ vfree(info);
+}
+
+void *wrap_alloc_pages(gfp_t flags, unsigned int size,
+ const char *file, int line)
+{
+ struct alloc_info *info;
+
+ size += sizeof(*info);
+ info = (struct alloc_info *)__get_free_pages(flags, get_order(size));
+ if (!info)
+ return NULL;
+ info->type = ALLOC_TYPE_PAGES;
+ info->size = size;
+ atomic_add(size, &alloc_sizes[info->type]);
+#if ALLOC_DEBUG > 1
+ info->file = file;
+ info->line = line;
+ info->tag = 0;
+ spin_lock_bh(&alloc_lock);
+ InsertTailList(&allocs, &info->list);
+ spin_unlock_bh(&alloc_lock);
+#endif
+ return info + 1;
+}
+
+void wrap_free_pages(unsigned long ptr, int order)
+{
+ struct alloc_info *info;
+
+ info = (void *)ptr - sizeof(*info);
+ atomic_sub(info->size, &alloc_sizes[info->type]);
+#if ALLOC_DEBUG > 1
+ spin_lock_bh(&alloc_lock);
+ RemoveEntryList(&info->list);
+ spin_unlock_bh(&alloc_lock);
+ if (info->type != ALLOC_TYPE_PAGES)
+ WARNING("invliad type: %d", info->type);
+#endif
+ free_pages((unsigned long)info, get_order(info->size));
+}
+
+#if ALLOC_DEBUG > 1
+#undef ExAllocatePoolWithTag
+void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size,
+ ULONG tag, const char *file, int line)
+{
+ void *addr;
+ struct alloc_info *info;
+
+ ENTER4("pool_type: %d, size: %lu, tag: %u", pool_type, size, tag);
+ addr = ExAllocatePoolWithTag(pool_type, size, tag);
+ if (!addr)
+ return NULL;
+ info = addr - sizeof(*info);
+ info->file = file;
+ info->line = line;
+ info->tag = tag;
+ EXIT4(return addr);
+}
+#endif
+
+int alloc_size(enum alloc_type type)
+{
+ if (type >= 0 && type < ALLOC_TYPE_MAX)
+ return atomic_read(&alloc_sizes[type]);
+ else
+ return -EINVAL;
+}
+
+#endif // ALLOC_DEBUG
+
+int wrapmem_init(void)
+{
+ InitializeListHead(&allocs);
+ InitializeListHead(&slack_allocs);
+ InitializeListHead(&vmem_list);
+ spin_lock_init(&alloc_lock);
+ return 0;
+}
+
+void wrapmem_exit(void)
+{
+ enum alloc_type type;
+ struct nt_list *ent;
+
+ /* free all pointers on the slack list */
+ while (1) {
+ struct slack_alloc_info *info;
+ spin_lock_bh(&alloc_lock);
+ ent = RemoveHeadList(&slack_allocs);
+ spin_unlock_bh(&alloc_lock);
+ if (!ent)
+ break;
+ info = container_of(ent, struct slack_alloc_info, list);
+#ifdef ALLOC_DEBUG
+ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
+#endif
+ kfree(info);
+ }
+ type = 0;
+#ifdef ALLOC_DEBUG
+ for (type = 0; type < ALLOC_TYPE_MAX; type++) {
+ int n = atomic_read(&alloc_sizes[type]);
+ if (n)
+ WARNING("%d bytes of memory in %d leaking", n, type);
+ }
+
+#if ALLOC_DEBUG > 1
+ while (1) {
+ struct alloc_info *info;
+
+ spin_lock_bh(&alloc_lock);
+ ent = RemoveHeadList(&allocs);
+ spin_unlock_bh(&alloc_lock);
+ if (!ent)
+ break;
+ info = container_of(ent, struct alloc_info, list);
+ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
+ WARNING("%p in %d of size %zu allocated at %s(%d) "
+ "with tag 0x%08X leaking; freeing it now",
+ info + 1, info->type, info->size, info->file,
+ info->line, info->tag);
+ if (info->type == ALLOC_TYPE_KMALLOC_ATOMIC ||
+ info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC)
+ kfree(info);
+ else if (info->type == ALLOC_TYPE_VMALLOC_ATOMIC ||
+ info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC)
+ vfree(info);
+ else if (info->type == ALLOC_TYPE_PAGES)
+ free_pages((unsigned long)info, get_order(info->size));
+ else
+ WARNING("invalid type: %d; not freed", info->type);
+ }
+#endif
+#endif
+ return;
+}
--- /dev/null
+/*
+ * Copyright (C) 2006 Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _WRAPMEM_H_
+
+/* set ALLOC_DEBUG to 1 to get information about memory used by both
+ * ndiswrapper and Windows driver by reading
+ * /proc/net/ndiswrapper/debug; this will also show memory leaks
+ * (memory allocated but not freed) when ndiswrapper module is
+ * unloaded.
+
+ * ALLOC_DEBUG=2: details about individual allocations leaking is printed
+ * ALLOC_DEBUG=3: tags in ExAllocatePoolWithTag leaking printed
+*/
+
+//#ifndef ALLOC_DEBUG
+//#define ALLOC_DEBUG 1
+//#endif
+
+enum alloc_type { ALLOC_TYPE_KMALLOC_ATOMIC, ALLOC_TYPE_KMALLOC_NON_ATOMIC,
+ ALLOC_TYPE_VMALLOC_ATOMIC, ALLOC_TYPE_VMALLOC_NON_ATOMIC,
+ ALLOC_TYPE_SLACK, ALLOC_TYPE_PAGES, ALLOC_TYPE_MAX };
+
+int wrapmem_init(void);
+void wrapmem_exit(void);
+void *slack_kmalloc(size_t size);
+void slack_kfree(void *ptr);
+void wrapmem_info(void);
+
+#ifdef ALLOC_DEBUG
+void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line);
+void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line);
+void wrap_kfree(void *ptr);
+void *wrap_vmalloc(unsigned long size, const char *file, int line);
+void *wrap__vmalloc(unsigned long size, gfp_t flags, pgprot_t prot,
+ const char *file, int line);
+void wrap_vfree(void *ptr);
+void *wrap_alloc_pages(gfp_t flags, unsigned int size,
+ const char *file, int line);
+void wrap_free_pages(unsigned long ptr, int order);
+int alloc_size(enum alloc_type type);
+
+#ifndef _WRAPMEM_C_
+#undef kmalloc
+#undef kzalloc
+#undef kfree
+#undef vmalloc
+#undef __vmalloc
+#undef vfree
+#define kmalloc(size, flags) \
+ wrap_kmalloc(size, flags, __FILE__, __LINE__)
+#define kzalloc(size, flags) \
+ wrap_kzalloc(size, flags, __FILE__, __LINE__)
+#define vmalloc(size) \
+ wrap_vmalloc(size, __FILE__, __LINE__)
+#define __vmalloc(size, flags, prot) \
+ wrap__vmalloc(size, flags, prot, __FILE__, __LINE__)
+#define kfree(ptr) wrap_kfree(ptr)
+#define vfree(ptr) wrap_vfree(ptr)
+
+#define wrap_get_free_pages(flags, size) \
+ wrap_alloc_pages(flags, size, __FILE__, __LINE__)
+#undef free_pages
+#define free_pages(ptr, order) wrap_free_pages(ptr, order)
+
+#if ALLOC_DEBUG > 1
+void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size,
+ ULONG tag, const char *file, int line);
+#define ExAllocatePoolWithTag(pool_type, size, tag) \
+ wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__)
+#endif
+
+#endif // _WRAPMEM_C_
+
+#else
+
+#define wrap_get_free_pages(flags, size) \
+ (void *)__get_free_pages(flags, get_order(size))
+
+#endif // ALLOC_DEBUG
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ndis.h"
+#include "iw_ndis.h"
+#include "pnp.h"
+#include "loader.h"
+#include "wrapndis.h"
+#include <linux/inetdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include "wrapper.h"
+
+/* Functions callable from the NDIS driver */
+wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo,
+ struct irp *irp);
+wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp);
+wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp);
+
+workqueue_struct_t *wrapndis_wq;
+static struct nt_thread *wrapndis_worker_thread;
+
+static int set_packet_filter(struct ndis_device *wnd,
+ ULONG packet_filter);
+static void add_iw_stats_timer(struct ndis_device *wnd);
+static void del_iw_stats_timer(struct ndis_device *wnd);
+static NDIS_STATUS ndis_start_device(struct ndis_device *wnd);
+static int ndis_remove_device(struct ndis_device *wnd);
+static void set_multicast_list(struct ndis_device *wnd);
+static int ndis_net_dev_open(struct net_device *net_dev);
+static int ndis_net_dev_close(struct net_device *net_dev);
+
+/* MiniportReset */
+NDIS_STATUS mp_reset(struct ndis_device *wnd)
+{
+ NDIS_STATUS res;
+ struct miniport *mp;
+ BOOLEAN reset_address;
+ KIRQL irql;
+
+ ENTER2("wnd: %p", wnd);
+ if (down_interruptible(&wnd->tx_ring_mutex))
+ EXIT3(return NDIS_STATUS_FAILURE);
+ if (down_interruptible(&wnd->ndis_req_mutex)) {
+ up(&wnd->tx_ring_mutex);
+ EXIT3(return NDIS_STATUS_FAILURE);
+ }
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0);
+ WARNING("%s is being reset", wnd->net_dev->name);
+ irql = serialize_lock_irql(wnd);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ res = LIN2WIN2(mp->reset, &reset_address, wnd->nmb->mp_ctx);
+ serialize_unlock_irql(wnd, irql);
+
+ TRACE2("%08X, %08X", res, reset_address);
+ if (res == NDIS_STATUS_PENDING) {
+ /* wait for NdisMResetComplete */
+ if (wait_condition((wnd->ndis_req_done > 0), 0,
+ TASK_INTERRUPTIBLE) < 0)
+ res = NDIS_STATUS_FAILURE;
+ else {
+ res = wnd->ndis_req_status;
+ reset_address = wnd->ndis_req_done - 1;
+ }
+ TRACE2("%08X, %08X", res, reset_address);
+ }
+ up(&wnd->ndis_req_mutex);
+ if (res == NDIS_STATUS_SUCCESS && reset_address) {
+ set_packet_filter(wnd, wnd->packet_filter);
+ set_multicast_list(wnd);
+ }
+ up(&wnd->tx_ring_mutex);
+ EXIT3(return res);
+}
+
+/* MiniportRequest(Query/Set)Information */
+NDIS_STATUS mp_request(enum ndis_request_type request,
+ struct ndis_device *wnd, ndis_oid oid,
+ void *buf, ULONG buflen, ULONG *written, ULONG *needed)
+{
+ NDIS_STATUS res;
+ ULONG w, n;
+ struct miniport *mp;
+ KIRQL irql;
+
+ if (down_interruptible(&wnd->ndis_req_mutex))
+ EXIT3(return NDIS_STATUS_FAILURE);
+ if (!written)
+ written = &w;
+ if (!needed)
+ needed = &n;
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0);
+ irql = serialize_lock_irql(wnd);
+ assert_irql(_irql_ == DISPATCH_LEVEL);
+ switch (request) {
+ case NdisRequestQueryInformation:
+ TRACE2("%p, %08X, %p", mp->queryinfo, oid, wnd->nmb->mp_ctx);
+ res = LIN2WIN6(mp->queryinfo, wnd->nmb->mp_ctx, oid, buf,
+ buflen, written, needed);
+ break;
+ case NdisRequestSetInformation:
+ TRACE2("%p, %08X, %p", mp->setinfo, oid, wnd->nmb->mp_ctx);
+ res = LIN2WIN6(mp->setinfo, wnd->nmb->mp_ctx, oid, buf,
+ buflen, written, needed);
+ break;
+ default:
+ WARNING("invalid request %d, %08X", request, oid);
+ res = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ serialize_unlock_irql(wnd, irql);
+ TRACE2("%08X, %08X", res, oid);
+ if (res == NDIS_STATUS_PENDING) {
+ /* wait for NdisMQueryInformationComplete */
+ if (wait_condition((wnd->ndis_req_done > 0), 0,
+ TASK_INTERRUPTIBLE) < 0)
+ res = NDIS_STATUS_FAILURE;
+ else
+ res = wnd->ndis_req_status;
+ TRACE2("%08X, %08X", res, oid);
+ }
+ up(&wnd->ndis_req_mutex);
+ DBG_BLOCK(2) {
+ if (res || needed)
+ TRACE2("%08X, %d, %d, %d", res, buflen, *written,
+ *needed);
+ }
+ EXIT3(return res);
+}
+
+/* MiniportPnPEventNotify */
+static NDIS_STATUS mp_pnp_event(struct ndis_device *wnd,
+ enum ndis_device_pnp_event event,
+ ULONG power_profile)
+{
+ struct miniport *mp;
+
+ ENTER1("%p, %d", wnd, event);
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ if (!mp->pnp_event_notify) {
+ TRACE1("Windows driver %s doesn't support "
+ "MiniportPnpEventNotify", wnd->wd->driver->name);
+ return NDIS_STATUS_FAILURE;
+ }
+ /* RNDIS driver doesn't like to be notified if device is
+ * already halted */
+ if (!test_bit(HW_INITIALIZED, &wnd->wd->hw_status))
+ EXIT1(return NDIS_STATUS_SUCCESS);
+ switch (event) {
+ case NdisDevicePnPEventSurpriseRemoved:
+ TRACE1("%u, %p",
+ (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK),
+ mp->pnp_event_notify);
+ if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) &&
+ !test_bit(HW_PRESENT, &wnd->wd->hw_status) &&
+ mp->pnp_event_notify) {
+ TRACE1("calling surprise_removed");
+ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx,
+ NdisDevicePnPEventSurpriseRemoved, NULL, 0);
+ } else
+ TRACE1("Windows driver %s doesn't support "
+ "MiniportPnpEventNotify for safe unplugging",
+ wnd->wd->driver->name);
+ return NDIS_STATUS_SUCCESS;
+ case NdisDevicePnPEventPowerProfileChanged:
+ if (power_profile)
+ power_profile = NdisPowerProfileAcOnLine;
+ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx,
+ NdisDevicePnPEventPowerProfileChanged,
+ &power_profile, (ULONG)sizeof(power_profile));
+ return NDIS_STATUS_SUCCESS;
+ default:
+ WARNING("event %d not yet implemented", event);
+ return NDIS_STATUS_SUCCESS;
+ }
+}
+
+/* MiniportInitialize */
+static NDIS_STATUS mp_init(struct ndis_device *wnd)
+{
+ NDIS_STATUS error_status, status;
+ UINT medium_index;
+ enum ndis_medium medium_array[] = {NdisMedium802_3};
+ struct miniport *mp;
+
+ ENTER1("irql: %d", current_irql());
+ if (test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {
+ WARNING("device %p already initialized!", wnd);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (!wnd->wd->driver->ndis_driver ||
+ !wnd->wd->driver->ndis_driver->mp.init) {
+ WARNING("assuming WDM (non-NDIS) driver");
+ EXIT1(return NDIS_STATUS_NOT_RECOGNIZED);
+ }
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ status = LIN2WIN6(mp->init, &error_status, &medium_index, medium_array,
+ sizeof(medium_array) / sizeof(medium_array[0]),
+ wnd->nmb, wnd->nmb);
+ TRACE1("init returns: %08X, irql: %d", status, current_irql());
+ if (status != NDIS_STATUS_SUCCESS) {
+ WARNING("couldn't initialize device: %08X", status);
+ EXIT1(return NDIS_STATUS_FAILURE);
+ }
+
+ /* Wait a little to let card power up otherwise ifup might
+ * fail after boot */
+ sleep_hz(HZ / 5);
+ status = mp_pnp_event(wnd, NdisDevicePnPEventPowerProfileChanged,
+ NdisPowerProfileAcOnLine);
+ if (status != NDIS_STATUS_SUCCESS)
+ TRACE1("setting power failed: %08X", status);
+ set_bit(HW_INITIALIZED, &wnd->wd->hw_status);
+ /* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is
+ * misleading/confusing */
+ status = mp_query(wnd, OID_PNP_CAPABILITIES,
+ &wnd->pnp_capa, sizeof(wnd->pnp_capa));
+ if (status == NDIS_STATUS_SUCCESS) {
+ TRACE1("%d, %d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup,
+ wnd->pnp_capa.wakeup.min_pattern_wakeup);
+ wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
+ status = mp_query_int(wnd, OID_PNP_ENABLE_WAKE_UP,
+ &wnd->ndis_wolopts);
+ TRACE1("%08X, %x", status, wnd->ndis_wolopts);
+ } else if (status == NDIS_STATUS_NOT_SUPPORTED)
+ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
+ TRACE1("%d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup);
+ /* although some NDIS drivers support suspend, Linux kernel
+ * has issues with suspending USB devices */
+ if (wrap_is_usb_bus(wnd->wd->dev_bus)) {
+ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
+ wnd->ndis_wolopts = 0;
+ }
+ mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);
+ EXIT1(return NDIS_STATUS_SUCCESS);
+}
+
+/* MiniportHalt */
+static void mp_halt(struct ndis_device *wnd)
+{
+ struct miniport *mp;
+
+ ENTER1("%p", wnd);
+ if (!test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {
+ WARNING("device %p is not initialized - not halting", wnd);
+ return;
+ }
+ hangcheck_del(wnd);
+ del_iw_stats_timer(wnd);
+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan &&
+ wrap_is_pci_bus(wnd->wd->dev_bus)) {
+ up(&wnd->ndis_req_mutex);
+ disassociate(wnd, 0);
+ if (down_interruptible(&wnd->ndis_req_mutex))
+ WARNING("couldn't obtain ndis_req_mutex");
+ }
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ TRACE1("halt: %p", mp->mp_halt);
+ LIN2WIN1(mp->mp_halt, wnd->nmb->mp_ctx);
+ /* if a driver doesn't call NdisMDeregisterInterrupt during
+ * halt, deregister it now */
+ if (wnd->mp_interrupt)
+ NdisMDeregisterInterrupt(wnd->mp_interrupt);
+ /* cancel any timers left by bugyy windows driver; also free
+ * the memory for timers */
+ while (1) {
+ struct nt_slist *slist;
+ struct wrap_timer *wrap_timer;
+
+ spin_lock_bh(&ntoskernel_lock);
+ if ((slist = wnd->wrap_timer_slist.next))
+ wnd->wrap_timer_slist.next = slist->next;
+ spin_unlock_bh(&ntoskernel_lock);
+ TIMERTRACE("%p", slist);
+ if (!slist)
+ break;
+ wrap_timer = container_of(slist, struct wrap_timer, slist);
+ wrap_timer->repeat = 0;
+ /* ktimer that this wrap_timer is associated to can't
+ * be touched, as it may have been freed by the driver
+ * already */
+ if (del_timer_sync(&wrap_timer->timer))
+ WARNING("Buggy Windows driver left timer %p "
+ "running", wrap_timer->nt_timer);
+ memset(wrap_timer, 0, sizeof(*wrap_timer));
+ kfree(wrap_timer);
+ }
+ EXIT1(return);
+}
+
+static NDIS_STATUS mp_set_power_state(struct ndis_device *wnd,
+ enum ndis_power_state state)
+{
+ NDIS_STATUS status;
+
+ TRACE1("%d", state);
+ if (state == NdisDeviceStateD0) {
+ status = NDIS_STATUS_SUCCESS;
+ up(&wnd->ndis_req_mutex);
+ if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) {
+ status = mp_init(wnd);
+ if (status == NDIS_STATUS_SUCCESS) {
+ set_packet_filter(wnd, wnd->packet_filter);
+ set_multicast_list(wnd);
+ }
+ } else if (test_and_clear_bit(HW_SUSPENDED,
+ &wnd->wd->hw_status)) {
+ status = mp_set_int(wnd, OID_PNP_SET_POWER, state);
+ if (status != NDIS_STATUS_SUCCESS)
+ WARNING("%s: setting power to state %d failed? "
+ "%08X", wnd->net_dev->name, state,
+ status);
+ } else
+ return NDIS_STATUS_FAILURE;
+
+ if (wrap_is_pci_bus(wnd->wd->dev_bus)) {
+ pci_enable_wake(wnd->wd->pci.pdev, PCI_D3hot, 0);
+ pci_enable_wake(wnd->wd->pci.pdev, PCI_D3cold, 0);
+ }
+ if (status == NDIS_STATUS_SUCCESS) {
+ up(&wnd->tx_ring_mutex);
+ netif_device_attach(wnd->net_dev);
+ hangcheck_add(wnd);
+ add_iw_stats_timer(wnd);
+ } else
+ WARNING("%s: couldn't set power to state %d; device not"
+ " resumed", wnd->net_dev->name, state);
+ EXIT1(return status);
+ } else {
+ if (down_interruptible(&wnd->tx_ring_mutex))
+ EXIT1(return NDIS_STATUS_FAILURE);
+ netif_device_detach(wnd->net_dev);
+ hangcheck_del(wnd);
+ del_iw_stats_timer(wnd);
+ status = NDIS_STATUS_NOT_SUPPORTED;
+ if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) {
+ status = mp_set_int(wnd, OID_PNP_ENABLE_WAKE_UP,
+ wnd->ndis_wolopts);
+ TRACE2("0x%x, 0x%x", status, wnd->ndis_wolopts);
+ if (status == NDIS_STATUS_SUCCESS) {
+ if (wnd->ndis_wolopts)
+ wnd->wd->pci.wake_state =
+ PowerDeviceD3;
+ else
+ wnd->wd->pci.wake_state =
+ PowerDeviceUnspecified;
+ } else
+ WARNING("couldn't set wake-on-lan options: "
+ "0x%x, %08X", wnd->ndis_wolopts, status);
+ status = mp_set_int(wnd, OID_PNP_SET_POWER, state);
+ if (status == NDIS_STATUS_SUCCESS)
+ set_bit(HW_SUSPENDED, &wnd->wd->hw_status);
+ else
+ WARNING("suspend failed: %08X", status);
+ }
+ if (status != NDIS_STATUS_SUCCESS) {
+ WARNING("%s does not support power management; "
+ "halting the device", wnd->net_dev->name);
+ mp_halt(wnd);
+ set_bit(HW_HALTED, &wnd->wd->hw_status);
+ status = STATUS_SUCCESS;
+ }
+ if (down_interruptible(&wnd->ndis_req_mutex))
+ WARNING("couldn't lock ndis_req_mutex");
+ EXIT1(return status);
+ }
+}
+
+static int ndis_set_mac_address(struct net_device *dev, void *p)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ struct sockaddr *addr = p;
+ struct ndis_configuration_parameter param;
+ struct unicode_string key;
+ struct ansi_string ansi;
+ NDIS_STATUS res;
+ unsigned char mac_string[2 * ETH_ALEN + 1];
+ mac_address mac;
+
+ memcpy(mac, addr->sa_data, sizeof(mac));
+ memset(mac_string, 0, sizeof(mac_string));
+ res = snprintf(mac_string, sizeof(mac_string), MACSTR, MAC2STR(mac));
+ if (res != (sizeof(mac_string) - 1))
+ EXIT1(return -EINVAL);
+ TRACE1("new mac: %s", mac_string);
+
+ RtlInitAnsiString(&ansi, mac_string);
+ if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi,
+ TRUE) != STATUS_SUCCESS)
+ EXIT1(return -EINVAL);
+
+ param.type = NdisParameterString;
+ RtlInitAnsiString(&ansi, "NetworkAddress");
+ if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) {
+ RtlFreeUnicodeString(¶m.data.string);
+ EXIT1(return -EINVAL);
+ }
+ NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m);
+ RtlFreeUnicodeString(&key);
+ RtlFreeUnicodeString(¶m.data.string);
+
+ if (res != NDIS_STATUS_SUCCESS)
+ EXIT1(return -EFAULT);
+ if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) {
+ res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS,
+ mac, sizeof(mac));
+ if (res == NDIS_STATUS_SUCCESS) {
+ TRACE1("mac:" MACSTRSEP, MAC2STR(mac));
+ memcpy(dev->dev_addr, mac, sizeof(mac));
+ } else
+ ERROR("couldn't get mac address: %08X", res);
+ }
+ EXIT1(return 0);
+}
+
+static int setup_tx_sg_list(struct ndis_device *wnd, struct sk_buff *skb,
+ struct ndis_packet_oob_data *oob_data)
+{
+ struct ndis_sg_element *sg_element;
+ struct ndis_sg_list *sg_list;
+ int i;
+
+ ENTER3("%p, %d", skb, skb_shinfo(skb)->nr_frags);
+ if (skb_shinfo(skb)->nr_frags <= 1) {
+ sg_element = &oob_data->wrap_tx_sg_list.elements[0];
+ sg_element->address =
+ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,
+ skb->len, PCI_DMA_TODEVICE);
+ sg_element->length = skb->len;
+ oob_data->wrap_tx_sg_list.nent = 1;
+ oob_data->ext.info[ScatterGatherListPacketInfo] =
+ &oob_data->wrap_tx_sg_list;
+ TRACE3("%Lx, %u", sg_element->address, sg_element->length);
+ return 0;
+ }
+ sg_list = kmalloc(sizeof(*sg_list) +
+ (skb_shinfo(skb)->nr_frags + 1) * sizeof(*sg_element),
+ GFP_ATOMIC);
+ if (!sg_list)
+ return -ENOMEM;
+ sg_list->nent = skb_shinfo(skb)->nr_frags + 1;
+ TRACE3("%p, %d", sg_list, sg_list->nent);
+ sg_element = sg_list->elements;
+ sg_element->length = skb_headlen(skb);
+ sg_element->address =
+ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,
+ skb_headlen(skb), PCI_DMA_TODEVICE);
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ sg_element++;
+ sg_element->length = frag->size;
+ sg_element->address =
+ pci_map_page(wnd->wd->pci.pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+ TRACE3("%Lx, %u", sg_element->address, sg_element->length);
+ }
+ oob_data->ext.info[ScatterGatherListPacketInfo] = sg_list;
+ return 0;
+}
+
+static void free_tx_sg_list(struct ndis_device *wnd,
+ struct ndis_packet_oob_data *oob_data)
+{
+ int i;
+ struct ndis_sg_element *sg_element;
+ struct ndis_sg_list *sg_list =
+ oob_data->ext.info[ScatterGatherListPacketInfo];
+ sg_element = sg_list->elements;
+ TRACE3("%p, %d", sg_list, sg_list->nent);
+ PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, sg_element->address,
+ sg_element->length, PCI_DMA_TODEVICE);
+ if (sg_list->nent == 1)
+ EXIT3(return);
+ for (i = 1; i < sg_list->nent; i++, sg_element++) {
+ TRACE3("%Lx, %u", sg_element->address, sg_element->length);
+ pci_unmap_page(wnd->wd->pci.pdev, sg_element->address,
+ sg_element->length, PCI_DMA_TODEVICE);
+ }
+ TRACE3("%p", sg_list);
+ kfree(sg_list);
+}
+
+static struct ndis_packet *alloc_tx_packet(struct ndis_device *wnd,
+ struct sk_buff *skb)
+{
+ struct ndis_packet *packet;
+ ndis_buffer *buffer;
+ struct ndis_packet_oob_data *oob_data;
+ NDIS_STATUS status;
+
+ NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool);
+ if (status != NDIS_STATUS_SUCCESS)
+ return NULL;
+ NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool,
+ skb->data, skb->len);
+ if (status != NDIS_STATUS_SUCCESS) {
+ NdisFreePacket(packet);
+ return NULL;
+ }
+ packet->private.buffer_head = buffer;
+ packet->private.buffer_tail = buffer;
+
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ oob_data->tx_skb = skb;
+ if (wnd->sg_dma_size) {
+ if (setup_tx_sg_list(wnd, skb, oob_data)) {
+ NdisFreeBuffer(buffer);
+ NdisFreePacket(packet);
+ return NULL;
+ }
+ }
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ struct ndis_tcp_ip_checksum_packet_info csum;
+ int protocol;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)
+ protocol = ntohs(skb->protocol);
+#else
+ protocol = skb->nh.iph->protocol;
+#endif
+ csum.value = 0;
+ csum.tx.v4 = 1;
+ if (protocol == IPPROTO_TCP)
+ csum.tx.tcp = 1;
+ else if (protocol == IPPROTO_UDP)
+ csum.tx.udp = 1;
+// csum->tx.ip = 1;
+ packet->private.flags |= NDIS_PROTOCOL_ID_TCP_IP;
+ oob_data->ext.info[TcpIpChecksumPacketInfo] =
+ (void *)(ULONG_PTR)csum.value;
+ }
+ DBG_BLOCK(4) {
+ dump_bytes(__func__, skb->data, skb->len);
+ }
+ TRACE4("%p, %p, %p", packet, buffer, skb);
+ return packet;
+}
+
+void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet,
+ NDIS_STATUS status)
+{
+ ndis_buffer *buffer;
+ struct ndis_packet_oob_data *oob_data;
+ struct sk_buff *skb;
+ struct ndis_packet_pool *pool;
+
+ assert_irql(_irql_ <= DISPATCH_LEVEL);
+ assert(packet->private.packet_flags);
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ skb = oob_data->tx_skb;
+ buffer = packet->private.buffer_head;
+ TRACE4("%p, %p, %p, %08X", packet, buffer, skb, status);
+ if (status == NDIS_STATUS_SUCCESS) {
+ pre_atomic_add(wnd->net_stats.tx_bytes, packet->private.len);
+ atomic_inc_var(wnd->net_stats.tx_packets);
+ } else {
+ TRACE1("packet dropped: %08X", status);
+ atomic_inc_var(wnd->net_stats.tx_dropped);
+ }
+ if (wnd->sg_dma_size)
+ free_tx_sg_list(wnd, oob_data);
+ NdisFreeBuffer(buffer);
+ dev_kfree_skb_any(skb);
+ pool = packet->private.pool;
+ NdisFreePacket(packet);
+ if (netif_queue_stopped(wnd->net_dev) &&
+ ((pool->max_descr - pool->num_used_descr) >=
+ (wnd->max_tx_packets / 4))) {
+ set_bit(NETIF_WAKEQ, &wnd->ndis_pending_work);
+ schedule_wrapndis_work(&wnd->ndis_work);
+ }
+ EXIT4(return);
+}
+
+/* MiniportSend and MiniportSendPackets */
+/* this function is called holding tx_ring_mutex. start and n are such
+ * that start + n < TX_RING_SIZE; i.e., packets don't wrap around
+ * ring */
+static u8 mp_tx_packets(struct ndis_device *wnd, u8 start, u8 n)
+{
+ NDIS_STATUS res;
+ struct miniport *mp;
+ struct ndis_packet *packet;
+ u8 sent;
+ KIRQL irql;
+
+ ENTER3("%d, %d", start, n);
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ if (mp->send_packets) {
+ if (deserialized_driver(wnd)) {
+ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx,
+ &wnd->tx_ring[start], n);
+ sent = n;
+ } else {
+ irql = serialize_lock_irql(wnd);
+ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx,
+ &wnd->tx_ring[start], n);
+ serialize_unlock_irql(wnd, irql);
+ for (sent = 0; sent < n && wnd->tx_ok; sent++) {
+ struct ndis_packet_oob_data *oob_data;
+ packet = wnd->tx_ring[start + sent];
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ switch ((res =
+ xchg(&oob_data->status,
+ NDIS_STATUS_NOT_RECOGNIZED))) {
+ case NDIS_STATUS_SUCCESS:
+ free_tx_packet(wnd, packet,
+ NDIS_STATUS_SUCCESS);
+ break;
+ case NDIS_STATUS_PENDING:
+ break;
+ case NDIS_STATUS_RESOURCES:
+ wnd->tx_ok = 0;
+ /* resubmit this packet and
+ * the rest when resources
+ * become available */
+ sent--;
+ break;
+ case NDIS_STATUS_FAILURE:
+ free_tx_packet(wnd, packet,
+ NDIS_STATUS_FAILURE);
+ break;
+ default:
+ ERROR("%p: invalid status: %08X",
+ packet, res);
+ free_tx_packet(wnd, packet,
+ oob_data->status);
+ break;
+ }
+ TRACE3("%p, %d", packet, res);
+ }
+ }
+ TRACE3("sent: %d(%d)", sent, n);
+ } else {
+ for (sent = 0; sent < n && wnd->tx_ok; sent++) {
+ struct ndis_packet_oob_data *oob_data;
+ packet = wnd->tx_ring[start + sent];
+ oob_data = NDIS_PACKET_OOB_DATA(packet);
+ oob_data->status = NDIS_STATUS_NOT_RECOGNIZED;
+ irql = serialize_lock_irql(wnd);
+ res = LIN2WIN3(mp->send, wnd->nmb->mp_ctx,
+ packet, packet->private.flags);
+ serialize_unlock_irql(wnd, irql);
+ switch (res) {
+ case NDIS_STATUS_SUCCESS:
+ free_tx_packet(wnd, packet, res);
+ break;
+ case NDIS_STATUS_PENDING:
+ break;
+ case NDIS_STATUS_RESOURCES:
+ wnd->tx_ok = 0;
+ /* resend this packet when resources
+ * become available */
+ sent--;
+ break;
+ case NDIS_STATUS_FAILURE:
+ free_tx_packet(wnd, packet, res);
+ break;
+ default:
+ ERROR("packet %p: invalid status: %08X",
+ packet, res);
+ break;
+ }
+ }
+ }
+ EXIT3(return sent);
+}
+
+static void tx_worker(worker_param_t param)
+{
+ struct ndis_device *wnd;
+ s8 n;
+
+ wnd = worker_param_data(param, struct ndis_device, tx_work);
+ ENTER3("tx_ok %d", wnd->tx_ok);
+ while (wnd->tx_ok) {
+ if (down_interruptible(&wnd->tx_ring_mutex))
+ break;
+ spin_lock_bh(&wnd->tx_ring_lock);
+ n = wnd->tx_ring_end - wnd->tx_ring_start;
+ TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n);
+ /* end == start if either ring is empty or full; in
+ * the latter case is_tx_ring_full is set */
+ if (n == 0) {
+ if (wnd->is_tx_ring_full)
+ n = TX_RING_SIZE - wnd->tx_ring_start;
+ else {
+ spin_unlock_bh(&wnd->tx_ring_lock);
+ up(&wnd->tx_ring_mutex);
+ break;
+ }
+ } else if (n < 0)
+ n = TX_RING_SIZE - wnd->tx_ring_start;
+ spin_unlock_bh(&wnd->tx_ring_lock);
+ if (unlikely(n > wnd->max_tx_packets))
+ n = wnd->max_tx_packets;
+ n = mp_tx_packets(wnd, wnd->tx_ring_start, n);
+ if (n) {
+ wnd->net_dev->trans_start = jiffies;
+ wnd->tx_ring_start =
+ (wnd->tx_ring_start + n) % TX_RING_SIZE;
+ wnd->is_tx_ring_full = 0;
+ }
+ up(&wnd->tx_ring_mutex);
+ TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n);
+ }
+ EXIT3(return);
+}
+
+static int tx_skbuff(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ struct ndis_packet *packet;
+
+ packet = alloc_tx_packet(wnd, skb);
+ if (!packet) {
+ TRACE2("couldn't allocate packet");
+ netif_tx_lock(dev);
+ netif_stop_queue(dev);
+ netif_tx_unlock(dev);
+ return NETDEV_TX_BUSY;
+ }
+ spin_lock(&wnd->tx_ring_lock);
+ wnd->tx_ring[wnd->tx_ring_end++] = packet;
+ if (wnd->tx_ring_end == TX_RING_SIZE)
+ wnd->tx_ring_end = 0;
+ if (wnd->tx_ring_end == wnd->tx_ring_start) {
+ netif_tx_lock(dev);
+ wnd->is_tx_ring_full = 1;
+ netif_stop_queue(dev);
+ netif_tx_unlock(dev);
+ }
+ spin_unlock(&wnd->tx_ring_lock);
+ TRACE4("ring: %d, %d", wnd->tx_ring_start, wnd->tx_ring_end);
+ schedule_wrapndis_work(&wnd->tx_work);
+ return NETDEV_TX_OK;
+}
+
+static int set_packet_filter(struct ndis_device *wnd, ULONG packet_filter)
+{
+ NDIS_STATUS res;
+
+ while (1) {
+ res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER,
+ packet_filter);
+ if (res == NDIS_STATUS_SUCCESS)
+ break;
+ TRACE2("couldn't set filter 0x%08x", packet_filter);
+ /* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */
+ if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+ packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
+ continue;
+ }
+ if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) {
+ packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL;
+ continue;
+ }
+ if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) {
+ packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL;
+ continue;
+ }
+ if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) {
+ packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
+ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
+ continue;
+ }
+ if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) {
+ packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST;
+ continue;
+ }
+ break;
+ }
+
+ wnd->packet_filter = packet_filter;
+ res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter);
+ if (packet_filter != wnd->packet_filter) {
+ WARNING("filter not set: 0x%08x, 0x%08x",
+ packet_filter, wnd->packet_filter);
+ wnd->packet_filter = packet_filter;
+ }
+ if (wnd->packet_filter)
+ EXIT3(return 0);
+ else
+ EXIT3(return -1);
+}
+
+void set_media_state(struct ndis_device *wnd, enum ndis_media_state state)
+{
+ ENTER2("state: 0x%x", state);
+ if (state == NdisMediaStateConnected) {
+ netif_carrier_on(wnd->net_dev);
+ wnd->tx_ok = 1;
+ if (netif_queue_stopped(wnd->net_dev))
+ netif_wake_queue(wnd->net_dev);
+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
+ set_bit(LINK_STATUS_ON, &wnd->ndis_pending_work);
+ schedule_wrapndis_work(&wnd->ndis_work);
+ }
+ } else if (state == NdisMediaStateDisconnected) {
+ netif_carrier_off(wnd->net_dev);
+ netif_stop_queue(wnd->net_dev);
+ wnd->tx_ok = 0;
+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
+ memset(&wnd->essid, 0, sizeof(wnd->essid));
+ set_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work);
+ schedule_wrapndis_work(&wnd->ndis_work);
+ }
+ } else {
+ WARNING("invalid media state: 0x%x", state);
+ }
+}
+
+static int ndis_net_dev_open(struct net_device *net_dev)
+{
+ ENTER1("%p", netdev_priv(net_dev));
+ netif_start_queue(net_dev);
+ netif_poll_enable(net_dev);
+ EXIT1(return 0);
+}
+
+static int ndis_net_dev_close(struct net_device *net_dev)
+{
+ ENTER1("%p", netdev_priv(net_dev));
+ netif_poll_disable(net_dev);
+ netif_tx_disable(net_dev);
+ EXIT1(return 0);
+}
+
+static int ndis_change_mtu(struct net_device *net_dev, int mtu)
+{
+ struct ndis_device *wnd = netdev_priv(net_dev);
+ int max;
+
+ if (mtu < ETH_ZLEN)
+ return -EINVAL;
+ if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &max) !=
+ NDIS_STATUS_SUCCESS)
+ return -EOPNOTSUPP;
+ TRACE1("%d", max);
+ max -= ETH_HLEN;
+ if (max <= ETH_ZLEN)
+ return -EINVAL;
+ if (mtu + ETH_HLEN > max)
+ return -EINVAL;
+ net_dev->mtu = mtu;
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ndis_poll_controller(struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ disable_irq(dev->irq);
+ ndis_isr(wnd->mp_interrupt->kinterrupt, wnd->mp_interrupt);
+ enable_irq(dev->irq);
+}
+#endif
+
+/* called from BH context */
+static struct net_device_stats *ndis_get_stats(struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ return &wnd->net_stats;
+}
+
+/* called from BH context */
+static void ndis_set_multicast_list(struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ set_bit(SET_MULTICAST_LIST, &wnd->ndis_pending_work);
+ schedule_wrapndis_work(&wnd->ndis_work);
+}
+
+/* called from BH context */
+struct iw_statistics *get_iw_stats(struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ return &wnd->iw_stats;
+}
+
+static void update_iw_stats(struct ndis_device *wnd)
+{
+ struct iw_statistics *iw_stats = &wnd->iw_stats;
+ struct ndis_wireless_stats ndis_stats;
+ NDIS_STATUS res;
+ ndis_rssi rssi;
+ int qual;
+
+ ENTER2("%p", wnd);
+ if (wnd->iw_stats_enabled == FALSE || !netif_carrier_ok(wnd->net_dev)) {
+ memset(iw_stats, 0, sizeof(*iw_stats));
+ EXIT2(return);
+ }
+ res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi));
+ if (res == NDIS_STATUS_SUCCESS)
+ iw_stats->qual.level = rssi;
+
+ qual = 100 * (rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE);
+ if (qual < 0)
+ qual = 0;
+ else if (qual > 100)
+ qual = 100;
+
+ iw_stats->qual.noise = WL_NOISE;
+ iw_stats->qual.qual = qual;
+
+ res = mp_query(wnd, OID_802_11_STATISTICS,
+ &ndis_stats, sizeof(ndis_stats));
+ if (res != NDIS_STATUS_SUCCESS)
+ EXIT2(return);
+ iw_stats->discard.retries = (unsigned long)ndis_stats.retry +
+ (unsigned long)ndis_stats.multi_retry;
+ iw_stats->discard.misc = (unsigned long)ndis_stats.fcs_err +
+ (unsigned long)ndis_stats.rtss_fail +
+ (unsigned long)ndis_stats.ack_fail +
+ (unsigned long)ndis_stats.frame_dup;
+
+ EXIT2(return);
+}
+
+static void set_multicast_list(struct ndis_device *wnd)
+{
+ struct net_device *net_dev;
+ ULONG packet_filter;
+ NDIS_STATUS res;
+
+ net_dev = wnd->net_dev;
+ packet_filter = wnd->packet_filter;
+
+ TRACE2("0x%08x", packet_filter);
+ if (net_dev->flags & IFF_PROMISC) {
+ packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL;
+ } else if (net_dev->flags & IFF_ALLMULTI ||
+ net_dev->mc_count > wnd->multicast_size) {
+ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
+ TRACE2("0x%08x", packet_filter);
+ } else if (net_dev->mc_count > 0) {
+ int i, size;
+ char *buf;
+ struct dev_mc_list *mclist;
+ size = min(wnd->multicast_size, net_dev->mc_count);
+ TRACE2("%d, %d", wnd->multicast_size, net_dev->mc_count);
+ buf = kmalloc(size * ETH_ALEN, GFP_KERNEL);
+ if (!buf) {
+ WARNING("couldn't allocate memory");
+ EXIT2(return);
+ }
+ mclist = net_dev->mc_list;
+ for (i = 0; i < size && mclist; mclist = mclist->next) {
+ if (mclist->dmi_addrlen != ETH_ALEN)
+ continue;
+ memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN);
+ TRACE2(MACSTRSEP, MAC2STR(mclist->dmi_addr));
+ i++;
+ }
+ res = mp_set(wnd, OID_802_3_MULTICAST_LIST, buf, i * ETH_ALEN);
+ if (res == NDIS_STATUS_SUCCESS && i > 0)
+ packet_filter |= NDIS_PACKET_TYPE_MULTICAST;
+ else
+ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
+ kfree(buf);
+ }
+ TRACE2("0x%08x", packet_filter);
+ res = set_packet_filter(wnd, packet_filter);
+ if (res)
+ TRACE1("couldn't set packet filter (%08X)", res);
+ EXIT2(return);
+}
+
+static void link_status_off(struct ndis_device *wnd)
+{
+#ifdef CONFIG_WIRELESS_EXT
+ union iwreq_data wrqu;
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL);
+#endif
+ EXIT2(return);
+}
+
+static void link_status_on(struct ndis_device *wnd)
+{
+#ifdef CONFIG_WIRELESS_EXT
+ struct ndis_assoc_info *ndis_assoc_info;
+ union iwreq_data wrqu;
+ NDIS_STATUS res;
+ const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX + 32;
+#endif
+
+ ENTER2("");
+#ifdef CONFIG_WIRELESS_EXT
+ memset(&wrqu, 0, sizeof(wrqu));
+ ndis_assoc_info = kzalloc(assoc_size, GFP_KERNEL);
+ if (!ndis_assoc_info) {
+ ERROR("couldn't allocate memory");
+ goto send_assoc_event;
+ }
+ res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION,
+ ndis_assoc_info, assoc_size);
+ if (res) {
+ TRACE2("query assoc_info failed (%08X)", res);
+ kfree(ndis_assoc_info);
+ goto send_assoc_event;
+ }
+ TRACE2("%u, 0x%x, %u, 0x%x, %u", ndis_assoc_info->length,
+ ndis_assoc_info->req_ies, ndis_assoc_info->req_ie_length,
+ ndis_assoc_info->resp_ies, ndis_assoc_info->resp_ie_length);
+ if (ndis_assoc_info->req_ie_length > 0) {
+ wrqu.data.length = ndis_assoc_info->req_ie_length;
+ wireless_send_event(wnd->net_dev, IWEVASSOCREQIE, &wrqu,
+ ((char *)ndis_assoc_info) +
+ ndis_assoc_info->offset_req_ies);
+ }
+ if (ndis_assoc_info->resp_ie_length > 0) {
+ wrqu.data.length = ndis_assoc_info->resp_ie_length;
+ wireless_send_event(wnd->net_dev, IWEVASSOCRESPIE, &wrqu,
+ ((char *)ndis_assoc_info) +
+ ndis_assoc_info->offset_resp_ies);
+ }
+ kfree(ndis_assoc_info);
+
+send_assoc_event:
+ get_ap_address(wnd, wrqu.ap_addr.sa_data);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ TRACE2(MACSTRSEP, MAC2STR(wrqu.ap_addr.sa_data));
+ wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL);
+#endif
+ EXIT2(return);
+}
+
+static void iw_stats_timer_proc(unsigned long data)
+{
+ struct ndis_device *wnd = (struct ndis_device *)data;
+
+ ENTER2("%d", wnd->iw_stats_interval);
+ if (wnd->iw_stats_interval > 0) {
+ set_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work);
+ schedule_wrapndis_work(&wnd->ndis_work);
+ }
+ mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval);
+}
+
+static void add_iw_stats_timer(struct ndis_device *wnd)
+{
+ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan)
+ return;
+ if (wnd->iw_stats_interval < 0)
+ wnd->iw_stats_interval *= -1;
+ wnd->iw_stats_timer.data = (unsigned long)wnd;
+ wnd->iw_stats_timer.function = iw_stats_timer_proc;
+ mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval);
+}
+
+static void del_iw_stats_timer(struct ndis_device *wnd)
+{
+ ENTER2("%d", wnd->iw_stats_interval);
+ wnd->iw_stats_interval *= -1;
+ del_timer_sync(&wnd->iw_stats_timer);
+ EXIT2(return);
+}
+
+static void hangcheck_proc(unsigned long data)
+{
+ struct ndis_device *wnd = (struct ndis_device *)data;
+
+ ENTER3("%d", wnd->hangcheck_interval);
+ if (wnd->hangcheck_interval > 0) {
+ set_bit(HANGCHECK, &wnd->ndis_pending_work);
+ schedule_wrapndis_work(&wnd->ndis_work);
+ }
+ mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval);
+ EXIT3(return);
+}
+
+void hangcheck_add(struct ndis_device *wnd)
+{
+ if (!wnd->wd->driver->ndis_driver->mp.hangcheck ||
+ hangcheck_interval < 0)
+ EXIT2(return);
+
+ if (hangcheck_interval > 0)
+ wnd->hangcheck_interval = hangcheck_interval * HZ;
+ if (wnd->hangcheck_interval < 0)
+ wnd->hangcheck_interval *= -1;
+ wnd->hangcheck_timer.data = (unsigned long)wnd;
+ wnd->hangcheck_timer.function = hangcheck_proc;
+ mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval);
+ EXIT2(return);
+}
+
+void hangcheck_del(struct ndis_device *wnd)
+{
+ ENTER2("%d", wnd->hangcheck_interval);
+ if (wnd->hangcheck_interval > 0)
+ wnd->hangcheck_interval *= -1;
+ del_timer_sync(&wnd->hangcheck_timer);
+ EXIT2(return);
+}
+
+/* worker procedure to take care of setting/checking various states */
+static void ndis_worker(worker_param_t param)
+{
+ struct ndis_device *wnd;
+
+ wnd = worker_param_data(param, struct ndis_device, ndis_work);
+ WORKTRACE("0x%lx", wnd->ndis_pending_work);
+
+ if (test_and_clear_bit(NETIF_WAKEQ, &wnd->ndis_pending_work)) {
+ netif_tx_lock_bh(wnd->net_dev);
+ netif_wake_queue(wnd->net_dev);
+ netif_tx_unlock_bh(wnd->net_dev);
+ }
+
+ if (test_and_clear_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work))
+ link_status_off(wnd);
+
+ if (test_and_clear_bit(LINK_STATUS_ON, &wnd->ndis_pending_work))
+ link_status_on(wnd);
+
+ if (test_and_clear_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work))
+ update_iw_stats(wnd);
+
+ if (test_and_clear_bit(SET_MULTICAST_LIST,
+ &wnd->ndis_pending_work))
+ set_multicast_list(wnd);
+
+ if (test_and_clear_bit(HANGCHECK, &wnd->ndis_pending_work)) {
+ struct miniport *mp;
+ BOOLEAN reset;
+ KIRQL irql;
+
+ mp = &wnd->wd->driver->ndis_driver->mp;
+ irql = serialize_lock_irql(wnd);
+ reset = LIN2WIN1(mp->hangcheck, wnd->nmb->mp_ctx);
+ serialize_unlock_irql(wnd, irql);
+ if (reset) {
+ TRACE2("%s needs reset", wnd->net_dev->name);
+ mp_reset(wnd);
+ }
+ }
+ WORKEXIT(return);
+}
+
+NDIS_STATUS ndis_reinit(struct ndis_device *wnd)
+{
+ NDIS_STATUS status;
+
+ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
+ status = mp_set_power_state(wnd, NdisDeviceStateD3);
+ if (status != NDIS_STATUS_SUCCESS) {
+ ERROR("halting device %s failed: %08X", wnd->net_dev->name,
+ status);
+ return status;
+ }
+ status = mp_set_power_state(wnd, NdisDeviceStateD0);
+ if (status != NDIS_STATUS_SUCCESS)
+ ERROR("starting device %s failed: %08X", wnd->net_dev->name,
+ status);
+ return status;
+}
+
+static void get_encryption_capa(struct ndis_device *wnd, char *buf,
+ const int buf_len)
+{
+ int i, mode;
+ NDIS_STATUS res;
+ struct ndis_assoc_info ndis_assoc_info;
+ struct ndis_add_key ndis_key;
+ struct ndis_capability *c;
+
+ ENTER1("%p", wnd);
+ /* set network type to g, b, or a, in that order */
+ res = mp_query(wnd, OID_802_11_NETWORK_TYPES_SUPPORTED, buf, buf_len);
+ if (res == NDIS_STATUS_SUCCESS) {
+ struct network_type_list *net_types;
+ unsigned long types = 0;
+ net_types = (typeof(net_types))buf;
+ for (i = 0; i < net_types->num; i++) {
+ TRACE2("%d", net_types->types[i]);
+ set_bit(net_types->types[i], &types);
+ }
+ if (types & Ndis802_11OFDM24)
+ mode = Ndis802_11OFDM24;
+ else if (types & Ndis802_11DS)
+ mode = Ndis802_11DS;
+ else if (types & Ndis802_11OFDM5)
+ mode = Ndis802_11OFDM5;
+ else
+ mode = Ndis802_11DS;
+ mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, mode);
+ }
+ /* check if WEP is supported */
+ if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104,
+ IW_AUTH_CIPHER_NONE) == 0 &&
+ get_ndis_encr_mode(wnd) == Ndis802_11Encryption1KeyAbsent)
+ set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr);
+
+ /* check if WPA is supported */
+ if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPA) == 0 &&
+ get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPA)
+ set_bit(Ndis802_11AuthModeWPA, &wnd->capa.encr);
+ else
+ EXIT1(return);
+
+ if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPAPSK) == 0 &&
+ get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPAPSK)
+ set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.encr);
+
+ /* check for highest encryption */
+ mode = 0;
+ if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_CCMP,
+ IW_AUTH_CIPHER_NONE) == 0 &&
+ (i = get_ndis_encr_mode(wnd)) > 0 &&
+ (i == Ndis802_11Encryption3KeyAbsent ||
+ i == Ndis802_11Encryption3Enabled))
+ mode = Ndis802_11Encryption3Enabled;
+ else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_TKIP,
+ IW_AUTH_CIPHER_NONE) == 0 &&
+ (i = get_ndis_encr_mode(wnd)) > 0 &&
+ (i == Ndis802_11Encryption2KeyAbsent ||
+ i == Ndis802_11Encryption2Enabled))
+ mode = Ndis802_11Encryption2Enabled;
+ else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104,
+ IW_AUTH_CIPHER_NONE) == 0 &&
+ (i = get_ndis_encr_mode(wnd)) > 0 &&
+ (i == Ndis802_11Encryption1KeyAbsent ||
+ i == Ndis802_11Encryption1Enabled))
+ mode = Ndis802_11Encryption1Enabled;
+
+ TRACE1("mode: %d", mode);
+ if (mode == 0)
+ EXIT1(return);
+ set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr);
+ if (mode == Ndis802_11Encryption1Enabled)
+ EXIT1(return);
+
+ ndis_key.length = 32;
+ ndis_key.index = 0xC0000001;
+ ndis_key.struct_size = sizeof(ndis_key);
+ res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size);
+ TRACE2("%08X, %lu", res, (unsigned long)sizeof(ndis_key));
+ if (res && res != NDIS_STATUS_INVALID_DATA)
+ EXIT1(return);
+ res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION,
+ &ndis_assoc_info, sizeof(ndis_assoc_info));
+ TRACE1("%08X", res);
+ if (res == NDIS_STATUS_NOT_SUPPORTED)
+ EXIT1(return);
+
+ set_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr);
+ if (mode == Ndis802_11Encryption3Enabled)
+ set_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr);
+ /* not all drivers support OID_802_11_CAPABILITY, so we don't
+ * know for sure if driver support WPA or WPAPSK; assume
+ * WPAPSK */
+ set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth);
+ wnd->max_pmkids = 1;
+
+ memset(buf, 0, buf_len);
+ c = (struct ndis_capability *)buf;
+ res = mp_query(wnd, OID_802_11_CAPABILITY, buf, buf_len);
+ if (!(res == NDIS_STATUS_SUCCESS && c->version == 2))
+ EXIT1(return);
+ wnd->max_pmkids = c->num_PMKIDs;
+
+ for (i = 0; i < c->num_auth_encr_pair; i++) {
+ struct ndis_auth_encr_pair *ae;
+
+ ae = &c->auth_encr_pair[i];
+ if ((char *)(ae + 1) > buf + buf_len)
+ break;
+ switch (ae->auth_mode) {
+ case Ndis802_11AuthModeOpen:
+ case Ndis802_11AuthModeShared:
+ case Ndis802_11AuthModeWPA:
+ case Ndis802_11AuthModeWPAPSK:
+ case Ndis802_11AuthModeWPANone:
+ case Ndis802_11AuthModeWPA2:
+ case Ndis802_11AuthModeWPA2PSK:
+ set_bit(ae->auth_mode, &wnd->capa.auth);
+ break;
+ default:
+ WARNING("unknown auth_mode: %d", ae->auth_mode);
+ break;
+ }
+ switch (ae->encr_mode) {
+ case Ndis802_11EncryptionDisabled:
+ case Ndis802_11Encryption1Enabled:
+ case Ndis802_11Encryption2Enabled:
+ case Ndis802_11Encryption3Enabled:
+ set_bit(ae->encr_mode, &wnd->capa.encr);
+ break;
+ default:
+ WARNING("unknown encr_mode: %d", ae->encr_mode);
+ break;
+ }
+ }
+ EXIT1(return);
+}
+
+wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo,
+ struct irp *irp)
+{
+ struct ndis_device *wnd;
+
+ TRACE3("fdo: %p", fdo);
+ /* for now, we don't have anything intresting here, so pass it
+ * down to bus driver */
+ wnd = fdo->reserved;
+ return IoPassIrpDown(wnd->nmb->pdo, irp);
+}
+WIN_FUNC_DECL(NdisDispatchDeviceControl,2)
+
+wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp)
+{
+ struct io_stack_location *irp_sl;
+ struct ndis_device *wnd;
+ enum ndis_power_state state;
+ NTSTATUS status;
+ NDIS_STATUS ndis_status;
+
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+ wnd = fdo->reserved;
+ IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn,
+ irp_sl->minor_fn, wnd);
+ if ((irp_sl->params.power.type == SystemPowerState &&
+ irp_sl->params.power.state.system_state > PowerSystemWorking) ||
+ (irp_sl->params.power.type == DevicePowerState &&
+ irp_sl->params.power.state.device_state > PowerDeviceD0))
+ state = NdisDeviceStateD3;
+ else
+ state = NdisDeviceStateD0;
+ switch (irp_sl->minor_fn) {
+ case IRP_MN_SET_POWER:
+ if (state == NdisDeviceStateD0) {
+ status = IoSyncForwardIrp(wnd->nmb->pdo, irp);
+ if (status != STATUS_SUCCESS)
+ break;
+ ndis_status = mp_set_power_state(wnd, state);
+ if (ndis_status != NDIS_STATUS_SUCCESS)
+ WARNING("couldn't set power to %d: %08X",
+ state, ndis_status);
+ TRACE2("%s: device resumed", wnd->net_dev->name);
+ irp->io_status.status = status = STATUS_SUCCESS;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ break;
+ } else {
+ ndis_status = mp_set_power_state(wnd, state);
+ /* TODO: handle error case */
+ if (ndis_status != NDIS_STATUS_SUCCESS)
+ WARNING("setting power to %d failed: %08X",
+ state, ndis_status);
+ status = IoAsyncForwardIrp(wnd->nmb->pdo, irp);
+ }
+ break;
+ case IRP_MN_QUERY_POWER:
+ if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) {
+ ndis_status = mp_query(wnd, OID_PNP_QUERY_POWER,
+ &state, sizeof(state));
+ TRACE2("%d, %08X", state, ndis_status);
+ /* this OID must always succeed */
+ if (ndis_status != NDIS_STATUS_SUCCESS)
+ TRACE1("query power returns %08X", ndis_status);
+ irp->io_status.status = STATUS_SUCCESS;
+ } else
+ irp->io_status.status = STATUS_SUCCESS;
+ status = IoPassIrpDown(wnd->nmb->pdo, irp);
+ break;
+ case IRP_MN_WAIT_WAKE:
+ case IRP_MN_POWER_SEQUENCE:
+ /* TODO: implement WAIT_WAKE */
+ status = IoPassIrpDown(wnd->nmb->pdo, irp);
+ break;
+ default:
+ status = IoPassIrpDown(wnd->nmb->pdo, irp);
+ break;
+ }
+ IOEXIT(return status);
+}
+WIN_FUNC_DECL(NdisDispatchPower,2)
+
+wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp)
+{
+ struct io_stack_location *irp_sl;
+ struct ndis_device *wnd;
+ struct device_object *pdo;
+ NTSTATUS status;
+
+ IOTRACE("fdo: %p, irp: %p", fdo, irp);
+ irp_sl = IoGetCurrentIrpStackLocation(irp);
+ wnd = fdo->reserved;
+ pdo = wnd->nmb->pdo;
+ switch (irp_sl->minor_fn) {
+ case IRP_MN_START_DEVICE:
+ status = IoSyncForwardIrp(pdo, irp);
+ if (status != STATUS_SUCCESS)
+ break;
+ if (ndis_start_device(wnd) == NDIS_STATUS_SUCCESS)
+ status = STATUS_SUCCESS;
+ else
+ status = STATUS_FAILURE;
+ irp->io_status.status = status;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ break;
+ case IRP_MN_QUERY_STOP_DEVICE:
+ /* TODO: implement in NDIS */
+ status = IoPassIrpDown(wnd->nmb->pdo, irp);
+ break;
+ case IRP_MN_STOP_DEVICE:
+ mp_halt(wnd);
+ irp->io_status.status = STATUS_SUCCESS;
+ status = IoAsyncForwardIrp(pdo, irp);
+ break;
+ case IRP_MN_REMOVE_DEVICE:
+ TRACE1("%s", wnd->net_dev->name);
+ mp_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved, 0);
+ if (ndis_remove_device(wnd)) {
+ status = STATUS_FAILURE;
+ break;
+ }
+ /* wnd is already freed */
+ status = IoAsyncForwardIrp(pdo, irp);
+ IoDetachDevice(fdo);
+ IoDeleteDevice(fdo);
+ break;
+ default:
+ status = IoAsyncForwardIrp(pdo, irp);
+ break;
+ }
+ IOTRACE("status: %08X", status);
+ IOEXIT(return status);
+}
+WIN_FUNC_DECL(NdisDispatchPnp,2)
+
+static void set_task_offload(struct ndis_device *wnd, void *buf,
+ const int buf_size)
+{
+ struct ndis_task_offload_header *task_offload_header;
+ struct ndis_task_offload *task_offload;
+ struct ndis_task_tcp_ip_checksum *csum = NULL;
+ struct ndis_task_tcp_large_send *tso = NULL;
+ NDIS_STATUS status;
+
+ memset(buf, 0, buf_size);
+ task_offload_header = buf;
+ task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION;
+ task_offload_header->size = sizeof(*task_offload_header);
+ task_offload_header->encap_format.flags.fixed_header_size = 1;
+ task_offload_header->encap_format.header_size = sizeof(struct ethhdr);
+ task_offload_header->encap_format.encap = IEEE_802_3_Encapsulation;
+ status = mp_query(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size);
+ TRACE1("%08X", status);
+ if (status != NDIS_STATUS_SUCCESS)
+ EXIT1(return);
+ if (task_offload_header->offset_first_task == 0)
+ EXIT1(return);
+ task_offload = ((void *)task_offload_header +
+ task_offload_header->offset_first_task);
+ while (1) {
+ TRACE1("%d, %d", task_offload->version, task_offload->task);
+ switch(task_offload->task) {
+ case TcpIpChecksumNdisTask:
+ csum = (void *)task_offload->task_buf;
+ break;
+ case TcpLargeSendNdisTask:
+ tso = (void *)task_offload->task_buf;
+ break;
+ default:
+ TRACE1("%d", task_offload->task);
+ break;
+ }
+ if (task_offload->offset_next_task == 0)
+ break;
+ task_offload = (void *)task_offload +
+ task_offload->offset_next_task;
+ }
+ if (tso)
+ TRACE1("%u, %u, %d, %d", tso->max_size, tso->min_seg_count,
+ tso->tcp_opts, tso->ip_opts);
+ if (!csum)
+ EXIT1(return);
+ TRACE1("%08x, %08x", csum->v4_tx.value, csum->v4_rx.value);
+ task_offload_header->encap_format.flags.fixed_header_size = 1;
+ task_offload_header->encap_format.header_size = sizeof(struct ethhdr);
+ task_offload_header->offset_first_task = sizeof(*task_offload_header);
+ task_offload = ((void *)task_offload_header +
+ task_offload_header->offset_first_task);
+ task_offload->offset_next_task = 0;
+ task_offload->size = sizeof(*task_offload);
+ task_offload->task = TcpIpChecksumNdisTask;
+ memcpy(task_offload->task_buf, csum, sizeof(*csum));
+ task_offload->task_buf_length = sizeof(*csum);
+ status = mp_set(wnd, OID_TCP_TASK_OFFLOAD, task_offload_header,
+ sizeof(*task_offload_header) +
+ sizeof(*task_offload) + sizeof(*csum));
+ TRACE1("%08X", status);
+ if (status != NDIS_STATUS_SUCCESS)
+ EXIT2(return);
+ wnd->tx_csum = csum->v4_tx;
+ if (csum->v4_tx.tcp_csum && csum->v4_tx.udp_csum) {
+ if (csum->v4_tx.ip_csum) {
+ wnd->net_dev->features |= NETIF_F_HW_CSUM;
+ TRACE1("hw checksum enabled");
+ } else {
+ wnd->net_dev->features |= NETIF_F_IP_CSUM;
+ TRACE1("IP checksum enabled");
+ }
+ if (wnd->sg_dma_size)
+ wnd->net_dev->features |= NETIF_F_SG;
+ }
+ wnd->rx_csum = csum->v4_rx;
+ EXIT1(return);
+}
+
+static void get_supported_oids(struct ndis_device *wnd)
+{
+ NDIS_STATUS res;
+ int i, n, needed;
+ ndis_oid *oids;
+
+ res = mp_query_info(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0, NULL,
+ &needed);
+ if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT ||
+ res == NDIS_STATUS_INVALID_LENGTH))
+ EXIT1(return);
+ oids = kmalloc(needed, GFP_KERNEL);
+ if (!oids) {
+ TRACE1("couldn't allocate memory");
+ EXIT1(return);
+ }
+ res = mp_query(wnd, OID_GEN_SUPPORTED_LIST, oids, needed);
+ if (res) {
+ TRACE1("failed: %08X", res);
+ kfree(oids);
+ EXIT1(return);
+ }
+ for (i = 0, n = needed / sizeof(*oids); i < n; i++) {
+ TRACE1("oid: %08X", oids[i]);
+ /* if a wireless device didn't say so for
+ * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */
+ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan &&
+ oids[i] == OID_802_11_SSID)
+ wnd->physical_medium = NdisPhysicalMediumWirelessLan;
+ }
+ kfree(oids);
+ EXIT1(return);
+}
+
+static void ndis_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 2);
+ strcat(info->driver, "+");
+ strncat(info->driver, wnd->wd->driver->name,
+ sizeof(info->driver) - strlen(DRIVER_NAME) - 1);
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 2);
+ strcat(info->version, "+");
+ strncat(info->version, wnd->wd->driver->version,
+ sizeof(info->version) - strlen(DRIVER_VERSION) - 1);
+ if (wrap_is_pci_bus(wnd->wd->dev_bus))
+ strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev),
+ sizeof(info->bus_info) - 1);
+#ifdef ENABLE_USB
+ else
+ usb_make_path(wnd->wd->usb.udev, info->bus_info,
+ sizeof(info->bus_info) - 1);
+#endif
+ return;
+}
+
+static u32 ndis_get_link(struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ return netif_carrier_ok(wnd->net_dev);
+}
+
+static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ wol->supported = 0;
+ wol->wolopts = 0;
+ if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND))
+ EXIT2(return);
+ if (!wrap_is_pci_bus(wnd->wd->dev_bus))
+ EXIT2(return);
+ /* we always suspend to D3 */
+ if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3)
+ return;
+ wol->supported |= WAKE_MAGIC;
+ if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET)
+ wol->wolopts |= WAKE_MAGIC;
+ return;
+}
+
+static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND))
+ return -EOPNOTSUPP;
+ if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3)
+ EXIT2(return -EOPNOTSUPP);
+ TRACE2("0x%x", wol->wolopts);
+ if (wol->wolopts & WAKE_MAGIC) {
+ wnd->ndis_wolopts |= NDIS_PNP_WAKE_UP_MAGIC_PACKET;
+ if (wol->wolopts != WAKE_MAGIC)
+ WARNING("ignored wake-on-lan options: 0x%x",
+ wol->wolopts & ~WAKE_MAGIC);
+ } else if (!wol->wolopts)
+ wnd->ndis_wolopts = 0;
+ else
+ return -EOPNOTSUPP;
+ TRACE2("0x%x", wnd->ndis_wolopts);
+ return 0;
+}
+
+static u32 ndis_get_tx_csum(struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ if (wnd->tx_csum.tcp_csum && wnd->tx_csum.udp_csum)
+ return 1;
+ else
+ return 0;
+}
+
+static u32 ndis_get_rx_csum(struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ if (wnd->rx_csum.value)
+ return 1;
+ else
+ return 0;
+}
+
+static int ndis_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ if (data && (wnd->tx_csum.value == 0))
+ return -EOPNOTSUPP;
+
+ if (wnd->tx_csum.ip_csum)
+ ethtool_op_set_tx_hw_csum(dev, data);
+ else
+ ethtool_op_set_tx_csum(dev, data);
+ return 0;
+}
+
+static int ndis_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+
+ if (data && (wnd->tx_csum.value == 0))
+ return -EOPNOTSUPP;
+
+ /* TODO: enable/disable rx csum through NDIS */
+ return 0;
+}
+
+static u32 ndis_get_sg(struct net_device *dev)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ if (wnd->sg_dma_size)
+ return ethtool_op_get_sg(dev);
+ else
+ return 0;
+}
+
+static int ndis_set_sg(struct net_device *dev, u32 data)
+{
+ struct ndis_device *wnd = netdev_priv(dev);
+ if (wnd->sg_dma_size)
+ return ethtool_op_set_sg(dev, data);
+ else
+ return -EOPNOTSUPP;
+}
+
+static struct ethtool_ops ndis_ethtool_ops = {
+ .get_drvinfo = ndis_get_drvinfo,
+ .get_link = ndis_get_link,
+ .get_wol = ndis_get_wol,
+ .set_wol = ndis_set_wol,
+ .get_tx_csum = ndis_get_tx_csum,
+ .get_rx_csum = ndis_get_rx_csum,
+ .set_tx_csum = ndis_set_tx_csum,
+ .set_rx_csum = ndis_set_rx_csum,
+ .get_sg = ndis_get_sg,
+ .set_sg = ndis_set_sg,
+};
+
+static int notifier_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr)
+{
+ struct net_device *net_dev = ptr;
+
+ ENTER2("0x%lx", event);
+ if (net_dev->ethtool_ops == &ndis_ethtool_ops
+ && event == NETDEV_CHANGENAME) {
+ struct ndis_device *wnd = netdev_priv(net_dev);
+ /* called with rtnl lock held, so no need to lock */
+ wrap_procfs_remove_ndis_device(wnd);
+ printk(KERN_INFO "%s: changing interface name from '%s' to "
+ "'%s'\n", DRIVER_NAME, wnd->netdev_name, net_dev->name);
+ memcpy(wnd->netdev_name, net_dev->name,
+ sizeof(wnd->netdev_name));
+ wrap_procfs_add_ndis_device(wnd);
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block netdev_notifier = {
+ .notifier_call = notifier_event,
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+static const struct net_device_ops ndis_netdev_ops = {
+ .ndo_open = ndis_net_dev_open,
+ .ndo_stop = ndis_net_dev_close,
+ .ndo_start_xmit = tx_skbuff,
+ .ndo_change_mtu = ndis_change_mtu,
+ .ndo_set_multicast_list = ndis_set_multicast_list,
+ .ndo_set_mac_address = ndis_set_mac_address,
+ .ndo_get_stats = ndis_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ndis_poll_controller,
+#endif
+};
+#endif
+
+static NDIS_STATUS ndis_start_device(struct ndis_device *wnd)
+{
+ struct wrap_device *wd;
+ struct net_device *net_dev;
+ NDIS_STATUS status;
+ char *buf;
+ const int buf_len = 256;
+ mac_address mac;
+ struct transport_header_offset *tx_header_offset;
+ int n;
+
+ ENTER2("%d", in_atomic());
+ status = mp_init(wnd);
+ if (status == NDIS_STATUS_NOT_RECOGNIZED)
+ EXIT1(return NDIS_STATUS_SUCCESS);
+ if (status != NDIS_STATUS_SUCCESS)
+ EXIT1(return status);
+ wd = wnd->wd;
+ net_dev = wnd->net_dev;
+
+ get_supported_oids(wnd);
+ memset(mac, 0, sizeof(mac));
+ status = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac));
+ if (memcmp(mac, "\x00\x00\x00\x00\x00\x00", sizeof(mac)) == 0) {
+ status = mp_query(wnd, OID_802_3_PERMANENT_ADDRESS, mac,
+ sizeof(mac));
+ if (status != NDIS_STATUS_SUCCESS) {
+ ERROR("couldn't get mac address: %08X", status);
+ goto err_start;
+ }
+ }
+ TRACE1("mac:" MACSTRSEP, MAC2STR(mac));
+ memcpy(net_dev->dev_addr, mac, ETH_ALEN);
+
+ strncpy(net_dev->name, if_name, IFNAMSIZ - 1);
+ net_dev->name[IFNAMSIZ - 1] = 0;
+
+ wnd->packet_filter = NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_MULTICAST;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+ net_dev->netdev_ops = &ndis_netdev_ops;
+#else
+ net_dev->open = ndis_net_dev_open;
+ net_dev->hard_start_xmit = tx_skbuff;
+ net_dev->stop = ndis_net_dev_close;
+ net_dev->get_stats = ndis_get_stats;
+ net_dev->change_mtu = ndis_change_mtu;
+ net_dev->set_multicast_list = ndis_set_multicast_list;
+ net_dev->set_mac_address = ndis_set_mac_address;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ net_dev->poll_controller = ndis_poll_controller;
+#endif
+#endif
+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
+ net_dev->wireless_handlers = &ndis_handler_def;
+ }
+ net_dev->ethtool_ops = &ndis_ethtool_ops;
+ if (wnd->mp_interrupt)
+ net_dev->irq = wnd->mp_interrupt->irq;
+ net_dev->mem_start = wnd->mem_start;
+ net_dev->mem_end = wnd->mem_end;
+ status = mp_query_int(wnd, OID_802_3_MAXIMUM_LIST_SIZE,
+ &wnd->multicast_size);
+ if (status != NDIS_STATUS_SUCCESS || wnd->multicast_size < 0)
+ wnd->multicast_size = 0;
+ if (wnd->multicast_size > 0)
+ net_dev->flags |= IFF_MULTICAST;
+ else
+ net_dev->flags &= ~IFF_MULTICAST;
+
+ buf = kmalloc(buf_len, GFP_KERNEL);
+ if (!buf) {
+ WARNING("couldn't allocate memory");
+ goto err_start;
+ }
+
+ set_task_offload(wnd, buf, buf_len);
+#ifdef NETIF_F_LLTX
+ net_dev->features |= NETIF_F_LLTX;
+#endif
+
+ if (register_netdev(net_dev)) {
+ ERROR("cannot register net device %s", net_dev->name);
+ goto err_register;
+ }
+ memcpy(wnd->netdev_name, net_dev->name, sizeof(wnd->netdev_name));
+ memset(buf, 0, buf_len);
+ status = mp_query(wnd, OID_GEN_VENDOR_DESCRIPTION, buf, buf_len);
+ if (status != NDIS_STATUS_SUCCESS) {
+ WARNING("couldn't get vendor information: 0x%x", status);
+ buf[0] = 0;
+ }
+ wnd->drv_ndis_version = n = 0;
+ mp_query_int(wnd, OID_GEN_DRIVER_VERSION, &wnd->drv_ndis_version);
+ mp_query_int(wnd, OID_GEN_VENDOR_DRIVER_VERSION, &n);
+
+ printk(KERN_INFO "%s: ethernet device " MACSTRSEP " using %sNDIS "
+ "driver: %s, version: 0x%x, NDIS version: 0x%x, vendor: '%s', "
+ "%s\n", net_dev->name, MAC2STR(net_dev->dev_addr),
+ deserialized_driver(wnd) ? "" : "serialized ",
+ wnd->wd->driver->name, n, wnd->drv_ndis_version, buf,
+ wnd->wd->conf_file_name);
+
+ if (deserialized_driver(wnd)) {
+ /* deserialized drivers don't have a limit, but we
+ * keep max at TX_RING_SIZE */
+ wnd->max_tx_packets = TX_RING_SIZE;
+ } else {
+ status = mp_query_int(wnd, OID_GEN_MAXIMUM_SEND_PACKETS,
+ &wnd->max_tx_packets);
+ if (status != NDIS_STATUS_SUCCESS)
+ wnd->max_tx_packets = 1;
+ if (wnd->max_tx_packets > TX_RING_SIZE)
+ wnd->max_tx_packets = TX_RING_SIZE;
+ }
+ TRACE2("maximum send packets: %d", wnd->max_tx_packets);
+ NdisAllocatePacketPoolEx(&status, &wnd->tx_packet_pool,
+ wnd->max_tx_packets, 0,
+ PROTOCOL_RESERVED_SIZE_IN_PACKET);
+ if (status != NDIS_STATUS_SUCCESS) {
+ ERROR("couldn't allocate packet pool");
+ goto packet_pool_err;
+ }
+ NdisAllocateBufferPool(&status, &wnd->tx_buffer_pool,
+ wnd->max_tx_packets + 4);
+ if (status != NDIS_STATUS_SUCCESS) {
+ ERROR("couldn't allocate buffer pool");
+ goto buffer_pool_err;
+ }
+ TRACE1("pool: %p", wnd->tx_buffer_pool);
+
+ if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &n) ==
+ NDIS_STATUS_SUCCESS && n > ETH_HLEN)
+ ndis_change_mtu(wnd->net_dev, n - ETH_HLEN);
+
+ if (mp_query_int(wnd, OID_GEN_MAC_OPTIONS, &n) == NDIS_STATUS_SUCCESS)
+ TRACE2("mac options supported: 0x%x", n);
+
+ tx_header_offset = (typeof(tx_header_offset))buf;
+ tx_header_offset->protocol_type = NDIS_PROTOCOL_ID_TCP_IP;
+ tx_header_offset->header_offset = sizeof(ETH_HLEN);
+ status = mp_set(wnd, OID_GEN_TRANSPORT_HEADER_OFFSET,
+ tx_header_offset, sizeof(*tx_header_offset));
+ TRACE2("%08X", status);
+
+ status = mp_query_int(wnd, OID_GEN_PHYSICAL_MEDIUM,
+ &wnd->physical_medium);
+ if (status != NDIS_STATUS_SUCCESS)
+ wnd->physical_medium = NdisPhysicalMediumUnspecified;
+
+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
+ mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);
+ get_encryption_capa(wnd, buf, buf_len);
+ TRACE1("capbilities = %ld", wnd->capa.encr);
+ printk(KERN_INFO "%s: encryption modes supported: "
+ "%s%s%s%s%s%s%s\n", net_dev->name,
+ test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ?
+ "WEP" : "none",
+
+ test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ?
+ "; TKIP with WPA" : "",
+ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
+ ", WPA2" : "",
+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
+ ", WPA2PSK" : "",
+
+ test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ?
+ "; AES/CCMP with WPA" : "",
+ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
+ ", WPA2" : "",
+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
+ ", WPA2PSK" : "");
+
+ set_default_iw_params(wnd);
+ }
+ status = mp_query_int(wnd, OID_GEN_MEDIA_CONNECT_STATUS, (int *)buf);
+ if (status == NDIS_STATUS_SUCCESS)
+ set_media_state(wnd, *((int *)buf));
+ kfree(buf);
+ wrap_procfs_add_ndis_device(wnd);
+ hangcheck_add(wnd);
+ add_iw_stats_timer(wnd);
+ EXIT1(return NDIS_STATUS_SUCCESS);
+
+buffer_pool_err:
+ wnd->tx_buffer_pool = NULL;
+ if (wnd->tx_packet_pool) {
+ NdisFreePacketPool(wnd->tx_packet_pool);
+ wnd->tx_packet_pool = NULL;
+ }
+packet_pool_err:
+err_register:
+ kfree(buf);
+err_start:
+ ndis_remove_device(wnd);
+ EXIT1(return NDIS_STATUS_FAILURE);
+}
+
+static int ndis_remove_device(struct ndis_device *wnd)
+{
+ s8 tx_pending;
+
+ /* prevent setting essid during disassociation */
+ memset(&wnd->essid, 0, sizeof(wnd->essid));
+ wnd->tx_ok = 0;
+ if (wnd->max_tx_packets)
+ unregister_netdev(wnd->net_dev);
+ netif_carrier_off(wnd->net_dev);
+ /* if device is suspended, but resume failed, tx_ring_mutex
+ * may already be locked */
+ if (down_trylock(&wnd->tx_ring_mutex))
+ WARNING("couldn't obtain tx_ring_mutex");
+ spin_lock_bh(&wnd->tx_ring_lock);
+ tx_pending = wnd->tx_ring_end - wnd->tx_ring_start;
+ if (tx_pending < 0)
+ tx_pending += TX_RING_SIZE;
+ else if (tx_pending == 0 && wnd->is_tx_ring_full)
+ tx_pending = TX_RING_SIZE - 1;
+ wnd->is_tx_ring_full = 0;
+ /* throw away pending packets */
+ while (tx_pending-- > 0) {
+ struct ndis_packet *packet;
+
+ packet = wnd->tx_ring[wnd->tx_ring_start];
+ free_tx_packet(wnd, packet, NDIS_STATUS_CLOSING);
+ wnd->tx_ring_start = (wnd->tx_ring_start + 1) % TX_RING_SIZE;
+ }
+ spin_unlock_bh(&wnd->tx_ring_lock);
+ up(&wnd->tx_ring_mutex);
+ wrap_procfs_remove_ndis_device(wnd);
+ mp_halt(wnd);
+ ndis_exit_device(wnd);
+
+ if (wnd->tx_packet_pool) {
+ NdisFreePacketPool(wnd->tx_packet_pool);
+ wnd->tx_packet_pool = NULL;
+ }
+ if (wnd->tx_buffer_pool) {
+ NdisFreeBufferPool(wnd->tx_buffer_pool);
+ wnd->tx_buffer_pool = NULL;
+ }
+ if (wnd->pmkids)
+ kfree(wnd->pmkids);
+ printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME,
+ wnd->net_dev->name);
+ kfree(wnd->nmb);
+ free_netdev(wnd->net_dev);
+ EXIT2(return 0);
+}
+
+static wstdcall NTSTATUS NdisAddDevice(struct driver_object *drv_obj,
+ struct device_object *pdo)
+{
+ struct device_object *fdo;
+ struct ndis_mp_block *nmb;
+ NTSTATUS status;
+ struct ndis_device *wnd;
+ struct net_device *net_dev;
+ struct wrap_device *wd;
+ unsigned long i;
+
+ ENTER2("%p, %p", drv_obj, pdo);
+ if (strlen(if_name) >= IFNAMSIZ) {
+ ERROR("interface name '%s' is too long", if_name);
+ return STATUS_INVALID_PARAMETER;
+ }
+ net_dev = alloc_etherdev(sizeof(*wnd));
+ if (!net_dev) {
+ ERROR("couldn't allocate device");
+ return STATUS_RESOURCES;
+ }
+ wd = pdo->reserved;
+ if (wrap_is_pci_bus(wd->dev_bus))
+ SET_NETDEV_DEV(net_dev, &wd->pci.pdev->dev);
+ if (wrap_is_usb_bus(wd->dev_bus))
+ SET_NETDEV_DEV(net_dev, &wd->usb.intf->dev);
+ status = IoCreateDevice(drv_obj, 0, NULL, FILE_DEVICE_UNKNOWN, 0,
+ FALSE, &fdo);
+ if (status != STATUS_SUCCESS) {
+ free_netdev(net_dev);
+ EXIT2(return status);
+ }
+ wnd = netdev_priv(net_dev);
+ TRACE1("wnd: %p", wnd);
+
+ nmb = kmalloc(sizeof(*nmb), GFP_KERNEL);
+ if (!nmb) {
+ WARNING("couldn't allocate memory");
+ IoDeleteDevice(fdo);
+ free_netdev(net_dev);
+ return STATUS_RESOURCES;
+ }
+#if defined(DEBUG) && DEBUG >= 6
+ /* poison nmb so if a driver accesses uninitialized pointers, we
+ * know what it is */
+ for (i = 0; i < sizeof(*nmb) / sizeof(unsigned long); i++)
+ ((unsigned long *)nmb)[i] = i + 0x8a3fc1;
+#endif
+
+ wnd->nmb = nmb;
+ nmb->wnd = wnd;
+ nmb->pdo = pdo;
+ wd->wnd = wnd;
+ wnd->wd = wd;
+ wnd->net_dev = net_dev;
+ fdo->reserved = wnd;
+ nmb->fdo = fdo;
+ if (ndis_init_device(wnd)) {
+ IoDeleteDevice(fdo);
+ kfree(nmb);
+ free_netdev(net_dev);
+ EXIT1(return STATUS_RESOURCES);
+ }
+ nmb->next_device = IoAttachDeviceToDeviceStack(fdo, pdo);
+ spin_lock_init(&wnd->tx_ring_lock);
+ init_MUTEX(&wnd->tx_ring_mutex);
+ init_MUTEX(&wnd->ndis_req_mutex);
+ wnd->ndis_req_done = 0;
+ initialize_work(&wnd->tx_work, tx_worker, wnd);
+ wnd->tx_ring_start = 0;
+ wnd->tx_ring_end = 0;
+ wnd->is_tx_ring_full = 0;
+ wnd->capa.encr = 0;
+ wnd->capa.auth = 0;
+ wnd->attributes = 0;
+ wnd->dma_map_count = 0;
+ wnd->dma_map_addr = NULL;
+ wnd->nick[0] = 0;
+ init_timer(&wnd->hangcheck_timer);
+ wnd->scan_timestamp = 0;
+ init_timer(&wnd->iw_stats_timer);
+ wnd->iw_stats_interval = 10 * HZ;
+ wnd->ndis_pending_work = 0;
+ memset(&wnd->essid, 0, sizeof(wnd->essid));
+ memset(&wnd->encr_info, 0, sizeof(wnd->encr_info));
+ wnd->infrastructure_mode = Ndis802_11Infrastructure;
+ initialize_work(&wnd->ndis_work, ndis_worker, wnd);
+ wnd->iw_stats_enabled = TRUE;
+
+ TRACE1("nmb: %p, pdo: %p, fdo: %p, attached: %p, next: %p",
+ nmb, pdo, fdo, fdo->attached, nmb->next_device);
+
+ /* dispatch routines are called as Windows functions */
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ drv_obj->major_func[i] = WIN_FUNC_PTR(IoPassIrpDown,2);
+
+ drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(NdisDispatchPnp,2);
+ drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(NdisDispatchPower,2);
+ drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
+ WIN_FUNC_PTR(NdisDispatchDeviceControl,2);
+// drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] =
+// WIN_FUNC_PTR(NdisDispatchDeviceControl,2);
+ EXIT2(return STATUS_SUCCESS);
+}
+
+int init_ndis_driver(struct driver_object *drv_obj)
+{
+ ENTER1("%p", drv_obj);
+ drv_obj->drv_ext->add_device = NdisAddDevice;
+ return 0;
+}
+
+int wrapndis_init(void)
+{
+ wrapndis_wq = create_singlethread_workqueue("wrapndis_wq");
+ if (!wrapndis_wq)
+ EXIT1(return -ENOMEM);
+ wrapndis_worker_thread = wrap_worker_init(wrapndis_wq);
+ TRACE1("%p", wrapndis_worker_thread);
+ register_netdevice_notifier(&netdev_notifier);
+ return 0;
+}
+
+void wrapndis_exit(void)
+{
+ unregister_netdevice_notifier(&netdev_notifier);
+ if (wrapndis_wq)
+ destroy_workqueue(wrapndis_wq);
+ TRACE1("%p", wrapndis_worker_thread);
+ if (wrapndis_worker_thread)
+ ObDereferenceObject(wrapndis_worker_thread);
+}
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _WRAPNDIS_H_
+#define _WRAPNDIS_H_
+
+#include "ndis.h"
+#include "pnp.h"
+
+int wrapndis_init(void);
+void wrapndis_exit(void);
+
+NDIS_STATUS mp_reset(struct ndis_device *wnd);
+
+NDIS_STATUS mp_request(enum ndis_request_type request,
+ struct ndis_device *wnd, ndis_oid oid,
+ void *buf, ULONG buflen, ULONG *written, ULONG *needed);
+
+static inline NDIS_STATUS mp_query_info(struct ndis_device *wnd,
+ ndis_oid oid, void *buf, ULONG buflen,
+ ULONG *written, ULONG *needed)
+{
+ return mp_request(NdisRequestQueryInformation, wnd, oid,
+ buf, buflen, written, needed);
+}
+
+static inline NDIS_STATUS mp_set_info(struct ndis_device *wnd,
+ ndis_oid oid, void *buf, ULONG buflen,
+ ULONG *written, ULONG *needed)
+{
+ return mp_request(NdisRequestSetInformation, wnd, oid,
+ buf, buflen, written, needed);
+}
+
+static inline NDIS_STATUS mp_query(struct ndis_device *wnd, ndis_oid oid,
+ void *buf, ULONG buflen)
+{
+ return mp_request(NdisRequestQueryInformation, wnd, oid,
+ buf, buflen, NULL, NULL);
+}
+
+static inline NDIS_STATUS mp_query_int(struct ndis_device *wnd,
+ ndis_oid oid, ULONG *data)
+{
+ return mp_request(NdisRequestQueryInformation, wnd, oid,
+ data, sizeof(ULONG), NULL, NULL);
+}
+
+static inline NDIS_STATUS mp_set(struct ndis_device *wnd, ndis_oid oid,
+ void *buf, ULONG buflen)
+{
+ return mp_request(NdisRequestSetInformation, wnd, oid,
+ buf, buflen, NULL, NULL);
+}
+
+static inline NDIS_STATUS mp_set_int(struct ndis_device *wnd,
+ ndis_oid oid, ULONG data)
+{
+ return mp_request(NdisRequestSetInformation, wnd, oid,
+ &data, sizeof(ULONG), NULL, NULL);
+}
+
+void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet,
+ NDIS_STATUS status);
+int init_ndis_driver(struct driver_object *drv_obj);
+NDIS_STATUS ndis_reinit(struct ndis_device *wnd);
+void set_media_state(struct ndis_device *wnd, enum ndis_media_state state);
+
+void hangcheck_add(struct ndis_device *wnd);
+void hangcheck_del(struct ndis_device *wnd);
+
+driver_dispatch_t winNdisDispatchPnp;
+driver_dispatch_t winNdisDispatchPower;
+driver_dispatch_t winNdisDispatchDeviceControl;
+
+struct iw_statistics *get_iw_stats(struct net_device *dev);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ndis.h"
+#include "iw_ndis.h"
+#include "loader.h"
+#include "pnp.h"
+#include "wrapper.h"
+
+char *if_name = "wlan%d";
+int proc_uid, proc_gid;
+int hangcheck_interval;
+static char *utils_version = UTILS_VERSION;
+
+#if defined(DEBUG) && (DEBUG > 0)
+int debug = DEBUG;
+#else
+int debug = 0;
+#endif
+
+WRAP_MODULE_PARM_STRING(if_name, 0400);
+MODULE_PARM_DESC(if_name, "Network interface name or template "
+ "(default: wlan%d)");
+WRAP_MODULE_PARM_INT(proc_uid, 0600);
+MODULE_PARM_DESC(proc_uid, "The uid of the files created in /proc "
+ "(default: 0).");
+WRAP_MODULE_PARM_INT(proc_gid, 0600);
+MODULE_PARM_DESC(proc_gid, "The gid of the files created in /proc "
+ "(default: 0).");
+WRAP_MODULE_PARM_INT(debug, 0600);
+MODULE_PARM_DESC(debug, "debug level");
+
+/* 0 - default value provided by NDIS driver,
+ * positive value - force hangcheck interval to that many seconds
+ * negative value - disable hangcheck
+ */
+WRAP_MODULE_PARM_INT(hangcheck_interval, 0600);
+MODULE_PARM_DESC(hangcheck_interval, "The interval, in seconds, for checking"
+ " if driver is hung. (default: 0)");
+
+WRAP_MODULE_PARM_STRING(utils_version, 0400);
+MODULE_PARM_DESC(utils_version, "Compatible version of utils "
+ "(read only: " UTILS_VERSION ")");
+
+MODULE_AUTHOR("ndiswrapper team <ndiswrapper-general@lists.sourceforge.net>");
+#ifdef MODULE_DESCRIPTION
+MODULE_DESCRIPTION("NDIS wrapper driver");
+#endif
+#ifdef MODULE_VERSION
+MODULE_VERSION(DRIVER_VERSION);
+#endif
+MODULE_LICENSE("GPL");
+
+static void module_cleanup(void)
+{
+ loader_exit();
+#ifdef ENABLE_USB
+ usb_exit();
+#endif
+
+ wrap_procfs_remove();
+ wrapndis_exit();
+ ndis_exit();
+ rtl_exit();
+ crt_exit();
+ ntoskernel_exit();
+ wrapmem_exit();
+}
+
+static int __init wrapper_init(void)
+{
+ printk(KERN_INFO "%s version %s loaded (smp=%s, preempt=%s)\n",
+ DRIVER_NAME, DRIVER_VERSION,
+#ifdef CONFIG_SMP
+ "yes"
+#else
+ "no"
+#endif
+ ,
+#ifdef CONFIG_PREEMPT_RT
+ "rt"
+#elif defined(CONFIG_PREEMPT)
+ "yes"
+#else
+ "no"
+#endif
+ );
+
+ if (wrapmem_init() || ntoskernel_init() || crt_init() ||
+ rtl_init() || ndis_init() || wrapndis_init() ||
+#ifdef ENABLE_USB
+ usb_init() ||
+#endif
+ wrap_procfs_init() || loader_init()) {
+ module_cleanup();
+ ERROR("%s: initialization failed", DRIVER_NAME);
+ return -EINVAL;
+ }
+ EXIT1(return 0);
+}
+
+static void __exit wrapper_exit(void)
+{
+ ENTER1("");
+ module_cleanup();
+}
+
+module_init(wrapper_init);
+module_exit(wrapper_exit);
--- /dev/null
+/*
+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef WRAPPER_H
+#define WRAPPER_H
+
+extern char *if_name;
+extern int proc_uid;
+extern int proc_gid;
+extern int hangcheck_interval;
+
+#endif /* WRAPPER_H */