[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/ndis/subr_ndis.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (c) 2003
  3  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
  4  *
  5  * Redistribution and use in source and binary forms, with or without
  6  * modification, are permitted provided that the following conditions
  7  * are met:
  8  * 1. Redistributions of source code must retain the above copyright
  9  *    notice, this list of conditions and the following disclaimer.
 10  * 2. Redistributions in binary form must reproduce the above copyright
 11  *    notice, this list of conditions and the following disclaimer in the
 12  *    documentation and/or other materials provided with the distribution.
 13  * 3. All advertising materials mentioning features or use of this software
 14  *    must display the following acknowledgement:
 15  *      This product includes software developed by Bill Paul.
 16  * 4. Neither the name of the author nor the names of any co-contributors
 17  *    may be used to endorse or promote products derived from this software
 18  *    without specific prior written permission.
 19  *
 20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
 21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
 24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 30  * THE POSSIBILITY OF SUCH DAMAGE.
 31  */
 32 
 33 #include <sys/cdefs.h>
 34 __FBSDID("$FreeBSD: src/sys/compat/ndis/subr_ndis.c,v 1.115 2008/12/27 08:03:32 weongyo Exp $");
 35 
 36 /*
 37  * This file implements a translation layer between the BSD networking
 38  * infrasturcture and Windows(R) NDIS network driver modules. A Windows
 39  * NDIS driver calls into several functions in the NDIS.SYS Windows
 40  * kernel module and exports a table of functions designed to be called
 41  * by the NDIS subsystem. Using the PE loader, we can patch our own
 42  * versions of the NDIS routines into a given Windows driver module and
 43  * convince the driver that it is in fact running on Windows.
 44  *
 45  * We provide a table of all our implemented NDIS routines which is patched
 46  * into the driver object code. All our exported routines must use the
 47  * _stdcall calling convention, since that's what the Windows object code
 48  * expects.
 49  */
 50 
 51 
 52 #include <sys/ctype.h>
 53 #include <sys/param.h>
 54 #include <sys/types.h>
 55 #include <sys/errno.h>
 56 
 57 #include <sys/callout.h>
 58 #include <sys/kernel.h>
 59 #include <sys/systm.h>
 60 #include <sys/malloc.h>
 61 #include <sys/lock.h>
 62 #include <sys/mutex.h>
 63 #include <sys/socket.h>
 64 #include <sys/sysctl.h>
 65 #include <sys/timespec.h>
 66 #include <sys/smp.h>
 67 #include <sys/queue.h>
 68 #include <sys/proc.h>
 69 #include <sys/filedesc.h>
 70 #include <sys/namei.h>
 71 #include <sys/fcntl.h>
 72 #include <sys/vnode.h>
 73 #include <sys/kthread.h>
 74 #include <sys/linker.h>
 75 #include <sys/mount.h>
 76 #include <sys/sysproto.h>
 77 
 78 #include <net/if.h>
 79 #include <net/if_arp.h>
 80 #include <net/ethernet.h>
 81 #include <net/if_dl.h>
 82 #include <net/if_media.h>
 83 
 84 #include <machine/atomic.h>
 85 #include <machine/bus.h>
 86 #include <machine/resource.h>
 87 
 88 #include <sys/bus.h>
 89 #include <sys/rman.h>
 90 
 91 #include <machine/stdarg.h>
 92 
 93 #include <net80211/ieee80211_var.h>
 94 #include <net80211/ieee80211_ioctl.h>
 95 
 96 #include <dev/pci/pcireg.h>
 97 #include <dev/pci/pcivar.h>
 98 #include <dev/usb/usb.h>
 99 #include <dev/usb/usbdi.h>
100 
101 #include <compat/ndis/pe_var.h>
102 #include <compat/ndis/cfg_var.h>
103 #include <compat/ndis/resource_var.h>
104 #include <compat/ndis/ntoskrnl_var.h>
105 #include <compat/ndis/hal_var.h>
106 #include <compat/ndis/ndis_var.h>
107 #include <dev/if_ndis/if_ndisvar.h>
108 
109 #include <vm/vm.h>
110 #include <vm/vm_param.h>
111 #include <vm/pmap.h>
112 #include <vm/uma.h>
113 #include <vm/vm_kern.h>
114 #include <vm/vm_map.h>
115 
116 static char ndis_filepath[MAXPATHLEN];
117 
118 SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath,
119         MAXPATHLEN, "Path used by NdisOpenFile() to search for files");
120 
121 static void NdisInitializeWrapper(ndis_handle *,
122         driver_object *, void *, void *);
123 static ndis_status NdisMRegisterMiniport(ndis_handle,
124         ndis_miniport_characteristics *, int);
125 static ndis_status NdisAllocateMemoryWithTag(void **,
126         uint32_t, uint32_t);
127 static ndis_status NdisAllocateMemory(void **,
128         uint32_t, uint32_t, ndis_physaddr);
129 static void NdisFreeMemory(void *, uint32_t, uint32_t);
130 static ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle,
131         uint32_t, uint32_t, ndis_interface_type);
132 static void NdisOpenConfiguration(ndis_status *,
133         ndis_handle *, ndis_handle);
134 static void NdisOpenConfigurationKeyByIndex(ndis_status *,
135         ndis_handle, uint32_t, unicode_string *, ndis_handle *);
136 static void NdisOpenConfigurationKeyByName(ndis_status *,
137         ndis_handle, unicode_string *, ndis_handle *);
138 static ndis_status ndis_encode_parm(ndis_miniport_block *,
139         struct sysctl_oid *, ndis_parm_type, ndis_config_parm **);
140 static ndis_status ndis_decode_parm(ndis_miniport_block *,
141         ndis_config_parm *, char *);
142 static void NdisReadConfiguration(ndis_status *, ndis_config_parm **,
143         ndis_handle, unicode_string *, ndis_parm_type);
144 static void NdisWriteConfiguration(ndis_status *, ndis_handle,
145         unicode_string *, ndis_config_parm *);
146 static void NdisCloseConfiguration(ndis_handle);
147 static void NdisAllocateSpinLock(ndis_spin_lock *);
148 static void NdisFreeSpinLock(ndis_spin_lock *);
149 static void NdisAcquireSpinLock(ndis_spin_lock *);
150 static void NdisReleaseSpinLock(ndis_spin_lock *);
151 static void NdisDprAcquireSpinLock(ndis_spin_lock *);
152 static void NdisDprReleaseSpinLock(ndis_spin_lock *);
153 static void NdisInitializeReadWriteLock(ndis_rw_lock *);
154 static void NdisAcquireReadWriteLock(ndis_rw_lock *,
155         uint8_t, ndis_lock_state *);
156 static void NdisReleaseReadWriteLock(ndis_rw_lock *, ndis_lock_state *);
157 static uint32_t NdisReadPciSlotInformation(ndis_handle, uint32_t,
158         uint32_t, void *, uint32_t);
159 static uint32_t NdisWritePciSlotInformation(ndis_handle, uint32_t,
160         uint32_t, void *, uint32_t);
161 static void NdisWriteErrorLogEntry(ndis_handle, ndis_error_code, uint32_t, ...);
162 static void ndis_map_cb(void *, bus_dma_segment_t *, int, int);
163 static void NdisMStartBufferPhysicalMapping(ndis_handle,
164         ndis_buffer *, uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *);
165 static void NdisMCompleteBufferPhysicalMapping(ndis_handle,
166         ndis_buffer *, uint32_t);
167 static void NdisMInitializeTimer(ndis_miniport_timer *, ndis_handle,
168         ndis_timer_function, void *);
169 static void NdisInitializeTimer(ndis_timer *,
170         ndis_timer_function, void *);
171 static void NdisSetTimer(ndis_timer *, uint32_t);
172 static void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t);
173 static void NdisMCancelTimer(ndis_timer *, uint8_t *);
174 static void ndis_timercall(kdpc *, ndis_miniport_timer *,
175         void *, void *);
176 static void NdisMQueryAdapterResources(ndis_status *, ndis_handle,
177         ndis_resource_list *, uint32_t *);
178 static ndis_status NdisMRegisterIoPortRange(void **,
179         ndis_handle, uint32_t, uint32_t);
180 static void NdisMDeregisterIoPortRange(ndis_handle,
181         uint32_t, uint32_t, void *);
182 static void NdisReadNetworkAddress(ndis_status *, void **,
183         uint32_t *, ndis_handle);
184 static ndis_status NdisQueryMapRegisterCount(uint32_t, uint32_t *);
185 static ndis_status NdisMAllocateMapRegisters(ndis_handle,
186         uint32_t, uint8_t, uint32_t, uint32_t);
187 static void NdisMFreeMapRegisters(ndis_handle);
188 static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int);
189 static void NdisMAllocateSharedMemory(ndis_handle, uint32_t,
190         uint8_t, void **, ndis_physaddr *);
191 static void ndis_asyncmem_complete(device_object *, void *);
192 static ndis_status NdisMAllocateSharedMemoryAsync(ndis_handle,
193         uint32_t, uint8_t, void *);
194 static void NdisMFreeSharedMemory(ndis_handle, uint32_t,
195         uint8_t, void *, ndis_physaddr);
196 static ndis_status NdisMMapIoSpace(void **, ndis_handle,
197         ndis_physaddr, uint32_t);
198 static void NdisMUnmapIoSpace(ndis_handle, void *, uint32_t);
199 static uint32_t NdisGetCacheFillSize(void);
200 static uint32_t NdisMGetDmaAlignment(ndis_handle);
201 static ndis_status NdisMInitializeScatterGatherDma(ndis_handle,
202         uint8_t, uint32_t);
203 static void NdisUnchainBufferAtFront(ndis_packet *, ndis_buffer **);
204 static void NdisUnchainBufferAtBack(ndis_packet *, ndis_buffer **);
205 static void NdisAllocateBufferPool(ndis_status *,
206         ndis_handle *, uint32_t);
207 static void NdisFreeBufferPool(ndis_handle);
208 static void NdisAllocateBuffer(ndis_status *, ndis_buffer **,
209         ndis_handle, void *, uint32_t);
210 static void NdisFreeBuffer(ndis_buffer *);
211 static uint32_t NdisBufferLength(ndis_buffer *);
212 static void NdisQueryBuffer(ndis_buffer *, void **, uint32_t *);
213 static void NdisQueryBufferSafe(ndis_buffer *, void **,
214         uint32_t *, uint32_t);
215 static void *NdisBufferVirtualAddress(ndis_buffer *);
216 static void *NdisBufferVirtualAddressSafe(ndis_buffer *, uint32_t);
217 static void NdisAdjustBufferLength(ndis_buffer *, int);
218 static uint32_t NdisInterlockedIncrement(uint32_t *);
219 static uint32_t NdisInterlockedDecrement(uint32_t *);
220 static void NdisInitializeEvent(ndis_event *);
221 static void NdisSetEvent(ndis_event *);
222 static void NdisResetEvent(ndis_event *);
223 static uint8_t NdisWaitEvent(ndis_event *, uint32_t);
224 static ndis_status NdisUnicodeStringToAnsiString(ansi_string *,
225         unicode_string *);
226 static ndis_status
227         NdisAnsiStringToUnicodeString(unicode_string *, ansi_string *);
228 static ndis_status NdisMPciAssignResources(ndis_handle,
229         uint32_t, ndis_resource_list **);
230 static ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *,
231         ndis_handle, uint32_t, uint32_t, uint8_t,
232         uint8_t, ndis_interrupt_mode);
233 static void NdisMDeregisterInterrupt(ndis_miniport_interrupt *);
234 static void NdisMRegisterAdapterShutdownHandler(ndis_handle, void *,
235         ndis_shutdown_handler);
236 static void NdisMDeregisterAdapterShutdownHandler(ndis_handle);
237 static uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *);
238 static void NdisGetBufferPhysicalArraySize(ndis_buffer *,
239         uint32_t *);
240 static void NdisQueryBufferOffset(ndis_buffer *,
241         uint32_t *, uint32_t *);
242 static uint32_t NdisReadPcmciaAttributeMemory(ndis_handle,
243         uint32_t, void *, uint32_t);
244 static uint32_t NdisWritePcmciaAttributeMemory(ndis_handle,
245         uint32_t, void *, uint32_t);
246 static list_entry *NdisInterlockedInsertHeadList(list_entry *,
247         list_entry *, ndis_spin_lock *);
248 static list_entry *NdisInterlockedRemoveHeadList(list_entry *,
249         ndis_spin_lock *);
250 static list_entry *NdisInterlockedInsertTailList(list_entry *,
251         list_entry *, ndis_spin_lock *);
252 static uint8_t
253         NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *,
254         void *, void *);
255 static void NdisGetCurrentSystemTime(uint64_t *);
256 static void NdisGetSystemUpTime(uint32_t *);
257 static void NdisInitializeString(unicode_string *, char *);
258 static void NdisInitAnsiString(ansi_string *, char *);
259 static void NdisInitUnicodeString(unicode_string *, uint16_t *);
260 static void NdisFreeString(unicode_string *);
261 static ndis_status NdisMRemoveMiniport(ndis_handle *);
262 static void NdisTerminateWrapper(ndis_handle, void *);
263 static void NdisMGetDeviceProperty(ndis_handle, device_object **,
264         device_object **, device_object **, cm_resource_list *,
265         cm_resource_list *);
266 static void NdisGetFirstBufferFromPacket(ndis_packet *,
267         ndis_buffer **, void **, uint32_t *, uint32_t *);
268 static void NdisGetFirstBufferFromPacketSafe(ndis_packet *,
269         ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t);
270 static int ndis_find_sym(linker_file_t, char *, char *, caddr_t *);
271 static void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *,
272         unicode_string *, ndis_physaddr);
273 static void NdisMapFile(ndis_status *, void **, ndis_handle);
274 static void NdisUnmapFile(ndis_handle);
275 static void NdisCloseFile(ndis_handle);
276 static uint8_t NdisSystemProcessorCount(void);
277 static void NdisMIndicateStatusComplete(ndis_handle);
278 static void NdisMIndicateStatus(ndis_handle, ndis_status,
279         void *, uint32_t);
280 static uint8_t ndis_intr(kinterrupt *, void *);
281 static void ndis_intrhand(kdpc *, ndis_miniport_interrupt *, void *, void *);
282 static funcptr ndis_findwrap(funcptr);
283 static void NdisCopyFromPacketToPacket(ndis_packet *,
284         uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *);
285 static void NdisCopyFromPacketToPacketSafe(ndis_packet *,
286         uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t);
287 static void NdisIMCopySendPerPacketInfo(ndis_packet *, ndis_packet *);
288 static ndis_status NdisMRegisterDevice(ndis_handle,
289         unicode_string *, unicode_string *, driver_dispatch **,
290         void **, ndis_handle *);
291 static ndis_status NdisMDeregisterDevice(ndis_handle);
292 static ndis_status
293         NdisMQueryAdapterInstanceName(unicode_string *, ndis_handle);
294 static void NdisMRegisterUnloadHandler(ndis_handle, void *);
295 static void dummy(void);
296 
297 /*
298  * Some really old drivers do not properly check the return value
299  * from NdisAllocatePacket() and NdisAllocateBuffer() and will
300  * sometimes allocate few more buffers/packets that they originally
301  * requested when they created the pool. To prevent this from being
302  * a problem, we allocate a few extra buffers/packets beyond what
303  * the driver asks for. This #define controls how many.
304  */
305 #define NDIS_POOL_EXTRA         16
306 
307 struct ktimer_list {
308         ktimer                  *kl_timer;
309         list_entry              kl_next;
310 };
311 
312 static struct list_entry        ndis_timerlist;
313 static kspin_lock               ndis_timerlock;
314 static int                      ndis_isusbdev;
315 
316 int
317 ndis_libinit()
318 {
319         image_patch_table       *patch;
320 
321         strcpy(ndis_filepath, "/compat/ndis");
322 
323         patch = ndis_functbl;
324         while (patch->ipt_func != NULL) {
325                 windrv_wrap((funcptr)patch->ipt_func,
326                     (funcptr *)&patch->ipt_wrap,
327                     patch->ipt_argcnt, patch->ipt_ftype);
328                 patch++;
329         }
330 
331         KeInitializeSpinLock(&ndis_timerlock);
332         InitializeListHead(&ndis_timerlist);
333 
334         return(0);
335 }
336 
337 int
338 ndis_libfini()
339 {
340         image_patch_table       *patch;
341 
342         patch = ndis_functbl;
343         while (patch->ipt_func != NULL) {
344                 windrv_unwrap(patch->ipt_wrap);
345                 patch++;
346         }
347 
348         return(0);
349 }
350 
351 static funcptr
352 ndis_findwrap(func)
353         funcptr                 func;
354 {
355         image_patch_table       *patch;
356 
357         patch = ndis_functbl;
358         while (patch->ipt_func != NULL) {
359                 if ((funcptr)patch->ipt_func == func)
360                         return((funcptr)patch->ipt_wrap);
361                 patch++;
362         }
363 
364         return(NULL);
365 }
366 
367 /*
368  * This routine does the messy Windows Driver Model device attachment
369  * stuff on behalf of NDIS drivers. We register our own AddDevice
370  * routine here
371  */
372 static void
373 NdisInitializeWrapper(wrapper, drv, path, unused)
374         ndis_handle             *wrapper;
375         driver_object           *drv;
376         void                    *path;
377         void                    *unused;
378 {
379         /*
380          * As of yet, I haven't come up with a compelling
381          * reason to define a private NDIS wrapper structure,
382          * so we use a pointer to the driver object as the
383          * wrapper handle. The driver object has the miniport
384          * characteristics struct for this driver hung off it
385          * via IoAllocateDriverObjectExtension(), and that's
386          * really all the private data we need.
387          */
388 
389         *wrapper = drv;
390 
391         /*
392          * If this was really Windows, we'd be registering dispatch
393          * routines for the NDIS miniport module here, but we're
394          * not Windows so all we really need to do is set up an
395          * AddDevice function that'll be invoked when a new device
396          * instance appears.
397          */
398 
399         drv->dro_driverext->dre_adddevicefunc = NdisAddDevice;
400 
401         return;
402 }
403 
404 static void
405 NdisTerminateWrapper(handle, syspec)
406         ndis_handle             handle;
407         void                    *syspec;
408 {
409         /* Nothing to see here, move along. */
410         return;
411 }
412 
413 static ndis_status
414 NdisMRegisterMiniport(handle, characteristics, len)
415         ndis_handle             handle;
416         ndis_miniport_characteristics *characteristics;
417         int                     len;
418 {
419         ndis_miniport_characteristics   *ch = NULL;
420         driver_object           *drv;
421 
422         drv = (driver_object *)handle;
423 
424         /*
425          * We need to save the NDIS miniport characteristics
426          * somewhere. This data is per-driver, not per-device
427          * (all devices handled by the same driver have the
428          * same characteristics) so we hook it onto the driver
429          * object using IoAllocateDriverObjectExtension().
430          * The extra extension info is automagically deleted when
431          * the driver is unloaded (see windrv_unload()).
432          */
433 
434         if (IoAllocateDriverObjectExtension(drv, (void *)1,
435             sizeof(ndis_miniport_characteristics), (void **)&ch) !=
436             STATUS_SUCCESS) {
437                 return(NDIS_STATUS_RESOURCES);
438         }
439 
440         bzero((char *)ch, sizeof(ndis_miniport_characteristics));
441 
442         bcopy((char *)characteristics, (char *)ch, len);
443 
444         if (ch->nmc_version_major < 5 || ch->nmc_version_minor < 1) {
445                 ch->nmc_shutdown_handler = NULL;
446                 ch->nmc_canceltxpkts_handler = NULL;
447                 ch->nmc_pnpevent_handler = NULL;
448         }
449 
450         return(NDIS_STATUS_SUCCESS);
451 }
452 
453 static ndis_status
454 NdisAllocateMemoryWithTag(vaddr, len, tag)
455         void                    **vaddr;
456         uint32_t                len;
457         uint32_t                tag;
458 {
459         void                    *mem;
460 
461         mem = ExAllocatePoolWithTag(NonPagedPool, len, tag);
462         if (mem == NULL) {
463                 return(NDIS_STATUS_RESOURCES);
464         }
465         *vaddr = mem;
466 
467         return(NDIS_STATUS_SUCCESS);
468 }
469 
470 static ndis_status
471 NdisAllocateMemory(vaddr, len, flags, highaddr)
472         void                    **vaddr;
473         uint32_t                len;
474         uint32_t                flags;
475         ndis_physaddr           highaddr;
476 {
477         void                    *mem;
478 
479         mem = ExAllocatePoolWithTag(NonPagedPool, len, 0);
480         if (mem == NULL)
481                 return(NDIS_STATUS_RESOURCES);
482         *vaddr = mem;
483 
484         return(NDIS_STATUS_SUCCESS);
485 }
486 
487 static void
488 NdisFreeMemory(vaddr, len, flags)
489         void                    *vaddr;
490         uint32_t                len;
491         uint32_t                flags;
492 {
493         if (len == 0)
494                 return;
495 
496         ExFreePool(vaddr);
497 
498         return;
499 }
500 
501 static ndis_status
502 NdisMSetAttributesEx(adapter_handle, adapter_ctx, hangsecs,
503                         flags, iftype)
504         ndis_handle                     adapter_handle;
505         ndis_handle                     adapter_ctx;
506         uint32_t                        hangsecs;
507         uint32_t                        flags;
508         ndis_interface_type             iftype;
509 {
510         ndis_miniport_block             *block;
511 
512         /*
513          * Save the adapter context, we need it for calling
514          * the driver's internal functions.
515          */
516         block = (ndis_miniport_block *)adapter_handle;
517         block->nmb_miniportadapterctx = adapter_ctx;
518         block->nmb_checkforhangsecs = hangsecs;
519         block->nmb_flags = flags;
520 
521         return(NDIS_STATUS_SUCCESS);
522 }
523 
524 static void
525 NdisOpenConfiguration(status, cfg, wrapctx)
526         ndis_status             *status;
527         ndis_handle             *cfg;
528         ndis_handle             wrapctx;
529 {
530         *cfg = wrapctx;
531         *status = NDIS_STATUS_SUCCESS;
532 
533         return;
534 }
535 
536 static void
537 NdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle)
538         ndis_status             *status;
539         ndis_handle             cfg;
540         unicode_string          *subkey;
541         ndis_handle             *subhandle;
542 {
543         *subhandle = cfg;
544         *status = NDIS_STATUS_SUCCESS;
545 
546         return;
547 }
548 
549 static void
550 NdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle)
551         ndis_status             *status;
552         ndis_handle             cfg;
553         uint32_t                idx;
554         unicode_string          *subkey;
555         ndis_handle             *subhandle;
556 {
557         *status = NDIS_STATUS_FAILURE;
558 
559         return;
560 }
561 
562 static ndis_status
563 ndis_encode_parm(block, oid, type, parm)
564         ndis_miniport_block     *block;
565         struct sysctl_oid       *oid;
566         ndis_parm_type          type;
567         ndis_config_parm        **parm;
568 {
569         ndis_config_parm        *p;
570         ndis_parmlist_entry     *np;
571         unicode_string          *us;
572         ansi_string             as;
573         int                     base = 0;
574         uint32_t                val;
575         char                    tmp[32];
576 
577         np = ExAllocatePoolWithTag(NonPagedPool,
578             sizeof(ndis_parmlist_entry), 0);
579         if (np == NULL)
580                 return(NDIS_STATUS_RESOURCES);
581         InsertHeadList((&block->nmb_parmlist), (&np->np_list));
582         *parm = p = &np->np_parm;
583 
584         switch(type) {
585         case ndis_parm_string:
586                 /* See if this might be a number. */
587                 val = strtoul((char *)oid->oid_arg1, NULL, 10);
588                 us = &p->ncp_parmdata.ncp_stringdata;
589                 p->ncp_type = ndis_parm_string;
590                 if (val) {
591                         snprintf(tmp, 32, "%x", val);
592                         RtlInitAnsiString(&as, tmp);
593                 } else {
594                         RtlInitAnsiString(&as, (char *)oid->oid_arg1);
595                 }
596 
597                 if (RtlAnsiStringToUnicodeString(us, &as, TRUE)) {
598                         ExFreePool(np);
599                         return(NDIS_STATUS_RESOURCES);
600                 }
601                 break;
602         case ndis_parm_int:
603                 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
604                         base = 16;
605                 else
606                         base = 10;
607                 p->ncp_type = ndis_parm_int;
608                 p->ncp_parmdata.ncp_intdata =
609                     strtol((char *)oid->oid_arg1, NULL, base);
610                 break;
611         case ndis_parm_hexint:
612 #ifdef notdef
613                 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
614                         base = 16;
615                 else
616                         base = 10;
617 #endif
618                 base = 16;
619                 p->ncp_type = ndis_parm_hexint;
620                 p->ncp_parmdata.ncp_intdata =
621                     strtoul((char *)oid->oid_arg1, NULL, base);
622                 break;
623         default:
624                 return(NDIS_STATUS_FAILURE);
625                 break;
626         }
627 
628         return(NDIS_STATUS_SUCCESS);
629 }
630 
631 static void
632 NdisReadConfiguration(status, parm, cfg, key, type)
633         ndis_status             *status;
634         ndis_config_parm        **parm;
635         ndis_handle             cfg;
636         unicode_string          *key;
637         ndis_parm_type          type;
638 {
639         char                    *keystr = NULL;
640         ndis_miniport_block     *block;
641         struct ndis_softc       *sc;
642         struct sysctl_oid       *oidp;
643         struct sysctl_ctx_entry *e;
644         ansi_string             as;
645 
646         block = (ndis_miniport_block *)cfg;
647         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
648 
649         if (key->us_len == 0 || key->us_buf == NULL) {
650                 *status = NDIS_STATUS_FAILURE;
651                 return;
652         }
653 
654         if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
655                 *status = NDIS_STATUS_RESOURCES;
656                 return;
657         }
658 
659         keystr = as.as_buf;
660 
661         /*
662          * See if registry key is already in a list of known keys
663          * included with the driver.
664          */
665 #if __FreeBSD_version < 502113
666         TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
667 #else
668         TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
669 #endif
670                 oidp = e->entry;
671                 if (strcasecmp(oidp->oid_name, keystr) == 0) {
672                         if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) {
673                                 RtlFreeAnsiString(&as);
674                                 *status = NDIS_STATUS_FAILURE;
675                                 return;
676                         }
677 
678                         *status = ndis_encode_parm(block, oidp, type, parm);
679                         RtlFreeAnsiString(&as);
680                         return;
681                 }
682         }
683 
684         /*
685          * If the key didn't match, add it to the list of dynamically
686          * created ones. Sometimes, drivers refer to registry keys
687          * that aren't documented in their .INF files. These keys
688          * are supposed to be created by some sort of utility or
689          * control panel snap-in that comes with the driver software.
690          * Sometimes it's useful to be able to manipulate these.
691          * If the driver requests the key in the form of a string,
692          * make its default value an empty string, otherwise default
693          * it to "".
694          */
695 
696         if (type == ndis_parm_int || type == ndis_parm_hexint)
697                 ndis_add_sysctl(sc, keystr, "(dynamic integer key)",
698                     "UNSET", CTLFLAG_RW);
699         else
700                 ndis_add_sysctl(sc, keystr, "(dynamic string key)",
701                     "UNSET", CTLFLAG_RW);
702 
703         RtlFreeAnsiString(&as);
704         *status = NDIS_STATUS_FAILURE;
705 
706         return;
707 }
708 
709 static ndis_status
710 ndis_decode_parm(block, parm, val)
711         ndis_miniport_block     *block;
712         ndis_config_parm        *parm;
713         char                    *val;
714 {
715         unicode_string          *ustr;
716         ansi_string             as;
717 
718         switch(parm->ncp_type) {
719         case ndis_parm_string:
720                 ustr = &parm->ncp_parmdata.ncp_stringdata;
721                 if (RtlUnicodeStringToAnsiString(&as, ustr, TRUE))
722                         return(NDIS_STATUS_RESOURCES);
723                 bcopy(as.as_buf, val, as.as_len);
724                 RtlFreeAnsiString(&as);
725                 break;
726         case ndis_parm_int:
727                 sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata);
728                 break;
729         case ndis_parm_hexint:
730                 sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata);
731                 break;
732         default:
733                 return(NDIS_STATUS_FAILURE);
734                 break;
735         }
736         return(NDIS_STATUS_SUCCESS);
737 }
738 
739 static void
740 NdisWriteConfiguration(status, cfg, key, parm)
741         ndis_status             *status;
742         ndis_handle             cfg;
743         unicode_string          *key;
744         ndis_config_parm        *parm;
745 {
746         ansi_string             as;
747         char                    *keystr = NULL;
748         ndis_miniport_block     *block;
749         struct ndis_softc       *sc;
750         struct sysctl_oid       *oidp;
751         struct sysctl_ctx_entry *e;
752         char                    val[256];
753 
754         block = (ndis_miniport_block *)cfg;
755         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
756 
757         if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
758                 *status = NDIS_STATUS_RESOURCES;
759                 return;
760         }
761 
762         keystr = as.as_buf;
763 
764         /* Decode the parameter into a string. */
765         bzero(val, sizeof(val));
766         *status = ndis_decode_parm(block, parm, val);
767         if (*status != NDIS_STATUS_SUCCESS) {
768                 RtlFreeAnsiString(&as);
769                 return;
770         }
771 
772         /* See if the key already exists. */
773 
774 #if __FreeBSD_version < 502113
775         TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
776 #else
777         TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
778 #endif
779                 oidp = e->entry;
780                 if (strcasecmp(oidp->oid_name, keystr) == 0) {
781                         /* Found it, set the value. */
782                         strcpy((char *)oidp->oid_arg1, val);
783                         RtlFreeAnsiString(&as);
784                         return;
785                 }
786         }
787 
788         /* Not found, add a new key with the specified value. */
789         ndis_add_sysctl(sc, keystr, "(dynamically set key)",
790                     val, CTLFLAG_RW);
791 
792         RtlFreeAnsiString(&as);
793         *status = NDIS_STATUS_SUCCESS;
794         return;
795 }
796 
797 static void
798 NdisCloseConfiguration(cfg)
799         ndis_handle             cfg;
800 {
801         list_entry              *e;
802         ndis_parmlist_entry     *pe;
803         ndis_miniport_block     *block;
804         ndis_config_parm        *p;
805 
806         block = (ndis_miniport_block *)cfg;
807 
808         while (!IsListEmpty(&block->nmb_parmlist)) {
809                 e = RemoveHeadList(&block->nmb_parmlist);
810                 pe = CONTAINING_RECORD(e, ndis_parmlist_entry, np_list);
811                 p = &pe->np_parm;
812                 if (p->ncp_type == ndis_parm_string)
813                         RtlFreeUnicodeString(&p->ncp_parmdata.ncp_stringdata);
814                 ExFreePool(e);
815         }
816 
817         return;
818 }
819 
820 /*
821  * Initialize a Windows spinlock.
822  */
823 static void
824 NdisAllocateSpinLock(lock)
825         ndis_spin_lock          *lock;
826 {
827         KeInitializeSpinLock(&lock->nsl_spinlock);
828         lock->nsl_kirql = 0;
829 
830         return;
831 }
832 
833 /*
834  * Destroy a Windows spinlock. This is a no-op for now. There are two reasons
835  * for this. One is that it's sort of superfluous: we don't have to do anything
836  * special to deallocate the spinlock. The other is that there are some buggy
837  * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on
838  * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm
839  * talking to you.)
840  */
841 static void
842 NdisFreeSpinLock(lock)
843         ndis_spin_lock          *lock;
844 {
845 #ifdef notdef
846         KeInitializeSpinLock(&lock->nsl_spinlock);
847         lock->nsl_kirql = 0;
848 #endif
849         return;
850 }
851 
852 /*
853  * Acquire a spinlock from IRQL <= DISPATCH_LEVEL.
854  */
855 
856 static void
857 NdisAcquireSpinLock(lock)
858         ndis_spin_lock          *lock;
859 {
860         KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
861         return;
862 }
863 
864 /*
865  * Release a spinlock from IRQL == DISPATCH_LEVEL.
866  */
867 
868 static void
869 NdisReleaseSpinLock(lock)
870         ndis_spin_lock          *lock;
871 {
872         KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
873         return;
874 }
875 
876 /*
877  * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL.
878  */
879 static void
880 NdisDprAcquireSpinLock(lock)
881         ndis_spin_lock          *lock;
882 {
883         KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock);
884         return;
885 }
886 
887 /*
888  * Release a spinlock without leaving IRQL == DISPATCH_LEVEL.
889  */
890 static void
891 NdisDprReleaseSpinLock(lock)
892         ndis_spin_lock          *lock;
893 {
894         KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock);
895         return;
896 }
897 
898 static void
899 NdisInitializeReadWriteLock(lock)
900         ndis_rw_lock            *lock;
901 {
902         KeInitializeSpinLock(&lock->nrl_spinlock);
903         bzero((char *)&lock->nrl_rsvd, sizeof(lock->nrl_rsvd));
904         return;
905 }
906 
907 static void
908 NdisAcquireReadWriteLock(lock, writeacc, state)
909         ndis_rw_lock            *lock;
910         uint8_t                 writeacc;
911         ndis_lock_state         *state;
912 {
913         if (writeacc == TRUE) {
914                 KeAcquireSpinLock(&lock->nrl_spinlock, &state->nls_oldirql);
915                 lock->nrl_rsvd[0]++;
916         } else
917                 lock->nrl_rsvd[1]++;
918 
919         return;
920 }
921 
922 static void
923 NdisReleaseReadWriteLock(lock, state)
924         ndis_rw_lock            *lock;
925         ndis_lock_state         *<