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 *< |