1/*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 2003 5 * Bill Paul <wpaul@windriver.com>. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD$"); 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/unistd.h> 41#include <sys/types.h> 42#include <sys/errno.h> 43#include <sys/callout.h> 44#include <sys/socket.h> 45#include <sys/queue.h> 46#include <sys/sysctl.h> 47#include <sys/proc.h> 48#include <sys/malloc.h> 49#include <sys/lock.h> 50#include <sys/mutex.h> 51#include <sys/conf.h> 52 53#include <sys/kernel.h> 54#include <sys/module.h> 55#include <sys/kthread.h> 56#include <machine/bus.h> 57#include <machine/resource.h> 58#include <sys/bus.h> 59#include <sys/rman.h> 60 61#include <net/if.h> 62#include <net/if_var.h> 63#include <net/if_arp.h> 64#include <net/ethernet.h> 65#include <net/if_dl.h> 66#include <net/if_media.h> 67 68#include <net80211/ieee80211_var.h> 69#include <net80211/ieee80211_ioctl.h> 70 71#include <dev/usb/usb.h> 72#include <dev/usb/usbdi.h> 73 74#include <compat/ndis/pe_var.h> 75#include <compat/ndis/cfg_var.h> 76#include <compat/ndis/resource_var.h> 77#include <compat/ndis/ntoskrnl_var.h> 78#include <compat/ndis/ndis_var.h> 79#include <compat/ndis/hal_var.h> 80#include <compat/ndis/usbd_var.h> 81#include <dev/if_ndis/if_ndisvar.h> 82 83#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 84#define NDIS_FLAG_RDONLY 1 85 86static void ndis_status_func(ndis_handle, ndis_status, void *, uint32_t); 87static void ndis_statusdone_func(ndis_handle); 88static void ndis_setdone_func(ndis_handle, ndis_status); 89static void ndis_getdone_func(ndis_handle, ndis_status); 90static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 91static void ndis_sendrsrcavail_func(ndis_handle); 92static void ndis_intrsetup(kdpc *, device_object *, 93 irp *, struct ndis_softc *); 94static void ndis_return(device_object *, void *); 95 96static image_patch_table kernndis_functbl[] = { 97 IMPORT_SFUNC(ndis_status_func, 4), 98 IMPORT_SFUNC(ndis_statusdone_func, 1), 99 IMPORT_SFUNC(ndis_setdone_func, 2), 100 IMPORT_SFUNC(ndis_getdone_func, 2), 101 IMPORT_SFUNC(ndis_resetdone_func, 3), 102 IMPORT_SFUNC(ndis_sendrsrcavail_func, 1), 103 IMPORT_SFUNC(ndis_intrsetup, 4), 104 IMPORT_SFUNC(ndis_return, 1), 105 106 { NULL, NULL, NULL } 107}; 108 109static struct nd_head ndis_devhead; 110 111/* 112 * This allows us to export our symbols to other modules. 113 * Note that we call ourselves 'ndisapi' to avoid a namespace 114 * collision with if_ndis.ko, which internally calls itself 115 * 'ndis.' 116 * 117 * Note: some of the subsystems depend on each other, so the 118 * order in which they're started is important. The order of 119 * importance is: 120 * 121 * HAL - spinlocks and IRQL manipulation 122 * ntoskrnl - DPC and workitem threads, object waiting 123 * windrv - driver/device registration 124 * 125 * The HAL should also be the last thing shut down, since 126 * the ntoskrnl subsystem will use spinlocks right up until 127 * the DPC and workitem threads are terminated. 128 */ 129 130static int 131ndis_modevent(module_t mod, int cmd, void *arg) 132{ 133 int error = 0; 134 image_patch_table *patch; 135 136 switch (cmd) { 137 case MOD_LOAD: 138 /* Initialize subsystems */ 139 hal_libinit(); 140 ntoskrnl_libinit(); 141 windrv_libinit(); 142 ndis_libinit(); 143 usbd_libinit(); 144 145 patch = kernndis_functbl; 146 while (patch->ipt_func != NULL) { 147 windrv_wrap((funcptr)patch->ipt_func, 148 (funcptr *)&patch->ipt_wrap, 149 patch->ipt_argcnt, patch->ipt_ftype); 150 patch++; 151 } 152 153 TAILQ_INIT(&ndis_devhead); 154 break; 155 case MOD_SHUTDOWN: 156 if (TAILQ_FIRST(&ndis_devhead) == NULL) { 157 /* Shut down subsystems */ 158 ndis_libfini(); 159 usbd_libfini(); 160 windrv_libfini(); 161 ntoskrnl_libfini(); 162 hal_libfini(); 163 164 patch = kernndis_functbl; 165 while (patch->ipt_func != NULL) { 166 windrv_unwrap(patch->ipt_wrap); 167 patch++; 168 } 169 } 170 break; 171 case MOD_UNLOAD: 172 /* Shut down subsystems */ 173 ndis_libfini(); 174 usbd_libfini(); 175 windrv_libfini(); 176 ntoskrnl_libfini(); 177 hal_libfini(); 178 179 patch = kernndis_functbl; 180 while (patch->ipt_func != NULL) { 181 windrv_unwrap(patch->ipt_wrap); 182 patch++; 183 } 184 185 break; 186 default: 187 error = EINVAL; 188 break; 189 } 190 191 return (error); 192} 193DEV_MODULE(ndisapi, ndis_modevent, NULL); 194MODULE_VERSION(ndisapi, 1); 195 196static void 197ndis_sendrsrcavail_func(adapter) 198 ndis_handle adapter; 199{ 200} 201 202static void 203ndis_status_func(adapter, status, sbuf, slen) 204 ndis_handle adapter; 205 ndis_status status; 206 void *sbuf; 207 uint32_t slen; 208{ 209 ndis_miniport_block *block; 210 struct ndis_softc *sc; 211 struct ifnet *ifp; 212 213 block = adapter; 214 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 215 ifp = NDISUSB_GET_IFNET(sc); 216 if ( ifp && ifp->if_flags & IFF_DEBUG) 217 device_printf(sc->ndis_dev, "status: %x\n", status); 218} 219 220static void 221ndis_statusdone_func(adapter) 222 ndis_handle adapter; 223{ 224 ndis_miniport_block *block; 225 struct ndis_softc *sc; 226 struct ifnet *ifp; 227 228 block = adapter; 229 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 230 ifp = NDISUSB_GET_IFNET(sc); 231 if (ifp && ifp->if_flags & IFF_DEBUG) 232 device_printf(sc->ndis_dev, "status complete\n"); 233} 234 235static void 236ndis_setdone_func(adapter, status) 237 ndis_handle adapter; 238 ndis_status status; 239{ 240 ndis_miniport_block *block; 241 block = adapter; 242 243 block->nmb_setstat = status; 244 KeSetEvent(&block->nmb_setevent, IO_NO_INCREMENT, FALSE); 245} 246 247static void 248ndis_getdone_func(adapter, status) 249 ndis_handle adapter; 250 ndis_status status; 251{ 252 ndis_miniport_block *block; 253 block = adapter; 254 255 block->nmb_getstat = status; 256 KeSetEvent(&block->nmb_getevent, IO_NO_INCREMENT, FALSE); 257} 258 259static void 260ndis_resetdone_func(ndis_handle adapter, ndis_status status, 261 uint8_t addressingreset) 262{ 263 ndis_miniport_block *block; 264 struct ndis_softc *sc; 265 struct ifnet *ifp; 266 267 block = adapter; 268 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 269 ifp = NDISUSB_GET_IFNET(sc); 270 271 if (ifp && ifp->if_flags & IFF_DEBUG) 272 device_printf(sc->ndis_dev, "reset done...\n"); 273 KeSetEvent(&block->nmb_resetevent, IO_NO_INCREMENT, FALSE); 274} 275 276int 277ndis_create_sysctls(arg) 278 void *arg; 279{ 280 struct ndis_softc *sc; 281 ndis_cfg *vals; 282 char buf[256]; 283 struct sysctl_oid *oidp; 284 struct sysctl_ctx_entry *e; 285 286 if (arg == NULL) 287 return (EINVAL); 288 289 sc = arg; 290 /* 291 device_printf(sc->ndis_dev, "ndis_create_sysctls() sc=%p\n", sc); 292 */ 293 vals = sc->ndis_regvals; 294 295 TAILQ_INIT(&sc->ndis_cfglist_head); 296 297 /* Add the driver-specific registry keys. */ 298 299 while(1) { 300 if (vals->nc_cfgkey == NULL) 301 break; 302 303 if (vals->nc_idx != sc->ndis_devidx) { 304 vals++; 305 continue; 306 } 307 308 /* See if we already have a sysctl with this name */ 309 310 oidp = NULL; 311 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 312 oidp = e->entry; 313 if (strcasecmp(oidp->oid_name, vals->nc_cfgkey) == 0) 314 break; 315 oidp = NULL; 316 } 317 318 if (oidp != NULL) { 319 vals++; 320 continue; 321 } 322 323 ndis_add_sysctl(sc, vals->nc_cfgkey, vals->nc_cfgdesc, 324 vals->nc_val, CTLFLAG_RW); 325 vals++; 326 } 327 328 /* Now add a couple of builtin keys. */ 329 330 /* 331 * Environment can be either Windows (0) or WindowsNT (1). 332 * We qualify as the latter. 333 */ 334 ndis_add_sysctl(sc, "Environment", 335 "Windows environment", "1", NDIS_FLAG_RDONLY); 336 337 /* NDIS version should be 5.1. */ 338 ndis_add_sysctl(sc, "NdisVersion", 339 "NDIS API Version", "0x00050001", NDIS_FLAG_RDONLY); 340 341 /* 342 * Some miniport drivers rely on the existence of the SlotNumber, 343 * NetCfgInstanceId and DriverDesc keys. 344 */ 345 ndis_add_sysctl(sc, "SlotNumber", "Slot Numer", "01", NDIS_FLAG_RDONLY); 346 ndis_add_sysctl(sc, "NetCfgInstanceId", "NetCfgInstanceId", 347 "{12345678-1234-5678-CAFE0-123456789ABC}", NDIS_FLAG_RDONLY); 348 ndis_add_sysctl(sc, "DriverDesc", "Driver Description", 349 "NDIS Network Adapter", NDIS_FLAG_RDONLY); 350 351 /* Bus type (PCI, PCMCIA, etc...) */ 352 sprintf(buf, "%d", (int)sc->ndis_iftype); 353 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, NDIS_FLAG_RDONLY); 354 355 if (sc->ndis_res_io != NULL) { 356 sprintf(buf, "0x%jx", rman_get_start(sc->ndis_res_io)); 357 ndis_add_sysctl(sc, "IOBaseAddress", 358 "Base I/O Address", buf, NDIS_FLAG_RDONLY); 359 } 360 361 if (sc->ndis_irq != NULL) { 362 sprintf(buf, "%ju", rman_get_start(sc->ndis_irq)); 363 ndis_add_sysctl(sc, "InterruptNumber", 364 "Interrupt Number", buf, NDIS_FLAG_RDONLY); 365 } 366 367 return (0); 368} 369 370int 371ndis_add_sysctl(arg, key, desc, val, flag_rdonly) 372 void *arg; 373 char *key; 374 char *desc; 375 char *val; 376 int flag_rdonly; 377{ 378 struct ndis_softc *sc; 379 struct ndis_cfglist *cfg; 380 char descstr[256]; 381 382 sc = arg; 383 384 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 385 386 if (cfg == NULL) { 387 printf("failed for %s\n", key); 388 return (ENOMEM); 389 } 390 391 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 392 if (desc == NULL) { 393 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 394 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 395 } else 396 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 397 strcpy(cfg->ndis_cfg.nc_val, val); 398 399 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 400 401 if (flag_rdonly != 0) { 402 cfg->ndis_oid = 403 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 404 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 405 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, CTLFLAG_RD, 406 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 407 cfg->ndis_cfg.nc_cfgdesc); 408 } else { 409 cfg->ndis_oid = 410 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 411 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 412 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, CTLFLAG_RW, 413 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 414 cfg->ndis_cfg.nc_cfgdesc); 415 } 416 return (0); 417} 418 419/* 420 * Somewhere, somebody decided "hey, let's automatically create 421 * a sysctl tree for each device instance as it's created -- it'll 422 * make life so much easier!" Lies. Why must they turn the kernel 423 * into a house of lies? 424 */ 425 426int 427ndis_flush_sysctls(arg) 428 void *arg; 429{ 430 struct ndis_softc *sc; 431 struct ndis_cfglist *cfg; 432 struct sysctl_ctx_list *clist; 433 434 sc = arg; 435 436 clist = device_get_sysctl_ctx(sc->ndis_dev); 437 438 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 439 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 440 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 441 sysctl_ctx_entry_del(clist, cfg->ndis_oid); 442 sysctl_remove_oid(cfg->ndis_oid, 1, 0); 443 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 444 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 445 free(cfg, M_DEVBUF); 446 } 447 448 return (0); 449} 450 451void * 452ndis_get_routine_address(functbl, name) 453 struct image_patch_table *functbl; 454 char *name; 455{ 456 int i; 457 458 for (i = 0; functbl[i].ipt_name != NULL; i++) 459 if (strcmp(name, functbl[i].ipt_name) == 0) 460 return (functbl[i].ipt_wrap); 461 return (NULL); 462} 463 464static void 465ndis_return(dobj, arg) 466 device_object *dobj; 467 void *arg; 468{ 469 ndis_miniport_block *block; 470 ndis_miniport_characteristics *ch; 471 ndis_return_handler returnfunc; 472 ndis_handle adapter; 473 ndis_packet *p; 474 uint8_t irql; 475 list_entry *l; 476 477 block = arg; 478 ch = IoGetDriverObjectExtension(dobj->do_drvobj, (void *)1); 479 480 p = arg; 481 adapter = block->nmb_miniportadapterctx; 482 483 if (adapter == NULL) 484 return; 485 486 returnfunc = ch->nmc_return_packet_func; 487 488 KeAcquireSpinLock(&block->nmb_returnlock, &irql); 489 while (!IsListEmpty(&block->nmb_returnlist)) { 490 l = RemoveHeadList((&block->nmb_returnlist)); 491 p = CONTAINING_RECORD(l, ndis_packet, np_list); 492 InitializeListHead((&p->np_list)); 493 KeReleaseSpinLock(&block->nmb_returnlock, irql); 494 MSCALL2(returnfunc, adapter, p); 495 KeAcquireSpinLock(&block->nmb_returnlock, &irql); 496 } 497 KeReleaseSpinLock(&block->nmb_returnlock, irql); 498} 499 500static void 501ndis_ext_free(struct mbuf *m) 502{ 503 504 return (ndis_return_packet(m->m_ext.ext_arg1)); 505} 506 507void 508ndis_return_packet(ndis_packet *p) 509{ 510 ndis_miniport_block *block; 511 512 if (p == NULL) 513 return; 514 515 /* Decrement refcount. */ 516 p->np_refcnt--; 517 518 /* Release packet when refcount hits zero, otherwise return. */ 519 if (p->np_refcnt) 520 return; 521 522 block = ((struct ndis_softc *)p->np_softc)->ndis_block; 523 524 KeAcquireSpinLockAtDpcLevel(&block->nmb_returnlock); 525 InitializeListHead((&p->np_list)); 526 InsertHeadList((&block->nmb_returnlist), (&p->np_list)); 527 KeReleaseSpinLockFromDpcLevel(&block->nmb_returnlock); 528 529 IoQueueWorkItem(block->nmb_returnitem, 530 (io_workitem_func)kernndis_functbl[7].ipt_wrap, 531 WORKQUEUE_CRITICAL, block); 532} 533 534void 535ndis_free_bufs(b0) 536 ndis_buffer *b0; 537{ 538 ndis_buffer *next; 539 540 if (b0 == NULL) 541 return; 542 543 while(b0 != NULL) { 544 next = b0->mdl_next; 545 IoFreeMdl(b0); 546 b0 = next; 547 } 548} 549 550void 551ndis_free_packet(p) 552 ndis_packet *p; 553{ 554 if (p == NULL) 555 return; 556 557 ndis_free_bufs(p->np_private.npp_head); 558 NdisFreePacket(p); 559} 560 561int 562ndis_convert_res(arg) 563 void *arg; 564{ 565 struct ndis_softc *sc; 566 ndis_resource_list *rl = NULL; 567 cm_partial_resource_desc *prd = NULL; 568 ndis_miniport_block *block; 569 device_t dev; 570 struct resource_list *brl; 571 struct resource_list_entry *brle; 572 int error = 0; 573 574 sc = arg; 575 block = sc->ndis_block; 576 dev = sc->ndis_dev; 577 578 rl = malloc(sizeof(ndis_resource_list) + 579 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 580 M_DEVBUF, M_NOWAIT|M_ZERO); 581 582 if (rl == NULL) 583 return (ENOMEM); 584 585 rl->cprl_version = 5; 586 rl->cprl_revision = 1; 587 rl->cprl_count = sc->ndis_rescnt; 588 prd = rl->cprl_partial_descs; 589 590 brl = BUS_GET_RESOURCE_LIST(dev, dev); 591 592 if (brl != NULL) { 593 594 STAILQ_FOREACH(brle, brl, link) { 595 switch (brle->type) { 596 case SYS_RES_IOPORT: 597 prd->cprd_type = CmResourceTypePort; 598 prd->cprd_flags = CM_RESOURCE_PORT_IO; 599 prd->cprd_sharedisp = 600 CmResourceShareDeviceExclusive; 601 prd->u.cprd_port.cprd_start.np_quad = 602 brle->start; 603 prd->u.cprd_port.cprd_len = brle->count; 604 break; 605 case SYS_RES_MEMORY: 606 prd->cprd_type = CmResourceTypeMemory; 607 prd->cprd_flags = 608 CM_RESOURCE_MEMORY_READ_WRITE; 609 prd->cprd_sharedisp = 610 CmResourceShareDeviceExclusive; 611 prd->u.cprd_mem.cprd_start.np_quad = 612 brle->start; 613 prd->u.cprd_mem.cprd_len = brle->count; 614 break; 615 case SYS_RES_IRQ: 616 prd->cprd_type = CmResourceTypeInterrupt; 617 prd->cprd_flags = 0; 618 /* 619 * Always mark interrupt resources as 620 * shared, since in our implementation, 621 * they will be. 622 */ 623 prd->cprd_sharedisp = 624 CmResourceShareShared; 625 prd->u.cprd_intr.cprd_level = brle->start; 626 prd->u.cprd_intr.cprd_vector = brle->start; 627 prd->u.cprd_intr.cprd_affinity = 0; 628 break; 629 default: 630 break; 631 } 632 prd++; 633 } 634 } 635 636 block->nmb_rlist = rl; 637 638 return (error); 639} 640 641/* 642 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 643 * packet, it will hand it to us in the form of an ndis_packet, 644 * which we need to convert to an mbuf that is then handed off 645 * to the stack. Note: we configure the mbuf list so that it uses 646 * the memory regions specified by the ndis_buffer structures in 647 * the ndis_packet as external storage. In most cases, this will 648 * point to a memory region allocated by the driver (either by 649 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 650 * the driver to handle free()ing this region for is, so we set up 651 * a dummy no-op free handler for it. 652 */ 653 654int 655ndis_ptom(m0, p) 656 struct mbuf **m0; 657 ndis_packet *p; 658{ 659 struct mbuf *m = NULL, *prev = NULL; 660 ndis_buffer *buf; 661 ndis_packet_private *priv; 662 uint32_t totlen = 0; 663 struct ifnet *ifp; 664 struct ether_header *eh; 665 int diff; 666 667 if (p == NULL || m0 == NULL) 668 return (EINVAL); 669 670 priv = &p->np_private; 671 buf = priv->npp_head; 672 p->np_refcnt = 0; 673 674 for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { 675 if (buf == priv->npp_head) 676 m = m_gethdr(M_NOWAIT, MT_DATA); 677 else 678 m = m_get(M_NOWAIT, MT_DATA); 679 if (m == NULL) { 680 m_freem(*m0); 681 *m0 = NULL; 682 return (ENOBUFS); 683 } 684 m->m_len = MmGetMdlByteCount(buf); 685 m_extadd(m, MmGetMdlVirtualAddress(buf), m->m_len, 686 ndis_ext_free, p, NULL, 0, EXT_NDIS); 687 p->np_refcnt++; 688 689 totlen += m->m_len; 690 if (m->m_flags & M_PKTHDR) 691 *m0 = m; 692 else 693 prev->m_next = m; 694 prev = m; 695 } 696 697 /* 698 * This is a hack to deal with the Marvell 8335 driver 699 * which, when associated with an AP in WPA-PSK mode, 700 * seems to overpad its frames by 8 bytes. I don't know 701 * that the extra 8 bytes are for, and they're not there 702 * in open mode, so for now clamp the frame size at 1514 703 * until I can figure out how to deal with this properly, 704 * otherwise if_ethersubr() will spank us by discarding 705 * the 'oversize' frames. 706 */ 707 708 eh = mtod((*m0), struct ether_header *); 709 ifp = NDISUSB_GET_IFNET((struct ndis_softc *)p->np_softc); 710 if (ifp && totlen > ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE)) { 711 diff = totlen - ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE); 712 totlen -= diff; 713 m->m_len -= diff; 714 } 715 (*m0)->m_pkthdr.len = totlen; 716 717 return (0); 718} 719 720/* 721 * Create an NDIS packet from an mbuf chain. 722 * This is used mainly when transmitting packets, where we need 723 * to turn an mbuf off an interface's send queue and transform it 724 * into an NDIS packet which will be fed into the NDIS driver's 725 * send routine. 726 * 727 * NDIS packets consist of two parts: an ndis_packet structure, 728 * which is vaguely analogous to the pkthdr portion of an mbuf, 729 * and one or more ndis_buffer structures, which define the 730 * actual memory segments in which the packet data resides. 731 * We need to allocate one ndis_buffer for each mbuf in a chain, 732 * plus one ndis_packet as the header. 733 */ 734 735int 736ndis_mtop(m0, p) 737 struct mbuf *m0; 738 ndis_packet **p; 739{ 740 struct mbuf *m; 741 ndis_buffer *buf = NULL, *prev = NULL; 742 ndis_packet_private *priv; 743 744 if (p == NULL || *p == NULL || m0 == NULL) 745 return (EINVAL); 746 747 priv = &(*p)->np_private; 748 priv->npp_totlen = m0->m_pkthdr.len; 749 750 for (m = m0; m != NULL; m = m->m_next) { 751 if (m->m_len == 0) 752 continue; 753 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); 754 if (buf == NULL) { 755 ndis_free_packet(*p); 756 *p = NULL; 757 return (ENOMEM); 758 } 759 MmBuildMdlForNonPagedPool(buf); 760 761 if (priv->npp_head == NULL) 762 priv->npp_head = buf; 763 else 764 prev->mdl_next = buf; 765 prev = buf; 766 } 767 768 priv->npp_tail = buf; 769 770 return (0); 771} 772 773int 774ndis_get_supported_oids(arg, oids, oidcnt) 775 void *arg; 776 ndis_oid **oids; 777 int *oidcnt; 778{ 779 int len, rval; 780 ndis_oid *o; 781 782 if (arg == NULL || oids == NULL || oidcnt == NULL) 783 return (EINVAL); 784 len = 0; 785 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 786 787 o = malloc(len, M_DEVBUF, M_NOWAIT); 788 if (o == NULL) 789 return (ENOMEM); 790 791 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 792 793 if (rval) { 794 free(o, M_DEVBUF); 795 return (rval); 796 } 797 798 *oids = o; 799 *oidcnt = len / 4; 800 801 return (0); 802} 803 804int 805ndis_set_info(arg, oid, buf, buflen) 806 void *arg; 807 ndis_oid oid; 808 void *buf; 809 int *buflen; 810{ 811 struct ndis_softc *sc; 812 ndis_status rval; 813 ndis_handle adapter; 814 ndis_setinfo_handler setfunc; 815 uint32_t byteswritten = 0, bytesneeded = 0; 816 uint8_t irql; 817 uint64_t duetime; 818 819 /* 820 * According to the NDIS spec, MiniportQueryInformation() 821 * and MiniportSetInformation() requests are handled serially: 822 * once one request has been issued, we must wait for it to 823 * finish before allowing another request to proceed. 824 */ 825 826 sc = arg; 827 828 KeResetEvent(&sc->ndis_block->nmb_setevent); 829 830 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 831 832 if (sc->ndis_block->nmb_pendingreq != NULL) { 833 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 834 panic("ndis_set_info() called while other request pending"); 835 } else 836 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 837 838 setfunc = sc->ndis_chars->nmc_setinfo_func; 839 adapter = sc->ndis_block->nmb_miniportadapterctx; 840 841 if (adapter == NULL || setfunc == NULL || 842 sc->ndis_block->nmb_devicectx == NULL) { 843 sc->ndis_block->nmb_pendingreq = NULL; 844 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 845 return (ENXIO); 846 } 847 848 rval = MSCALL6(setfunc, adapter, oid, buf, *buflen, 849 &byteswritten, &bytesneeded); 850 851 sc->ndis_block->nmb_pendingreq = NULL; 852 853 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 854 855 if (rval == NDIS_STATUS_PENDING) { 856 /* Wait up to 5 seconds. */ 857 duetime = (5 * 1000000) * -10; 858 KeWaitForSingleObject(&sc->ndis_block->nmb_setevent, 859 0, 0, FALSE, &duetime); 860 rval = sc->ndis_block->nmb_setstat; 861 } 862 863 if (byteswritten) 864 *buflen = byteswritten; 865 if (bytesneeded) 866 *buflen = bytesneeded; 867 868 if (rval == NDIS_STATUS_INVALID_LENGTH) 869 return (ENOSPC); 870 871 if (rval == NDIS_STATUS_INVALID_OID) 872 return (EINVAL); 873 874 if (rval == NDIS_STATUS_NOT_SUPPORTED || 875 rval == NDIS_STATUS_NOT_ACCEPTED) 876 return (ENOTSUP); 877 878 if (rval != NDIS_STATUS_SUCCESS) 879 return (ENODEV); 880 881 return (0); 882} 883 884typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 885 886int 887ndis_send_packets(arg, packets, cnt) 888 void *arg; 889 ndis_packet **packets; 890 int cnt; 891{ 892 struct ndis_softc *sc; 893 ndis_handle adapter; 894 ndis_sendmulti_handler sendfunc; 895 ndis_senddone_func senddonefunc; 896 int i; 897 ndis_packet *p; 898 uint8_t irql = 0; 899 900 sc = arg; 901 adapter = sc->ndis_block->nmb_miniportadapterctx; 902 if (adapter == NULL) 903 return (ENXIO); 904 sendfunc = sc->ndis_chars->nmc_sendmulti_func; 905 senddonefunc = sc->ndis_block->nmb_senddone_func; 906 907 if (NDIS_SERIALIZED(sc->ndis_block)) 908 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 909 910 MSCALL3(sendfunc, adapter, packets, cnt); 911 912 for (i = 0; i < cnt; i++) { 913 p = packets[i]; 914 /* 915 * Either the driver already handed the packet to 916 * ndis_txeof() due to a failure, or it wants to keep 917 * it and release it asynchronously later. Skip to the 918 * next one. 919 */ 920 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 921 continue; 922 MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status); 923 } 924 925 if (NDIS_SERIALIZED(sc->ndis_block)) 926 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 927 928 return (0); 929} 930 931int 932ndis_send_packet(arg, packet) 933 void *arg; 934 ndis_packet *packet; 935{ 936 struct ndis_softc *sc; 937 ndis_handle adapter; 938 ndis_status status; 939 ndis_sendsingle_handler sendfunc; 940 ndis_senddone_func senddonefunc; 941 uint8_t irql = 0; 942 943 sc = arg; 944 adapter = sc->ndis_block->nmb_miniportadapterctx; 945 if (adapter == NULL) 946 return (ENXIO); 947 sendfunc = sc->ndis_chars->nmc_sendsingle_func; 948 senddonefunc = sc->ndis_block->nmb_senddone_func; 949 950 if (NDIS_SERIALIZED(sc->ndis_block)) 951 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 952 status = MSCALL3(sendfunc, adapter, packet, 953 packet->np_private.npp_flags); 954 955 if (status == NDIS_STATUS_PENDING) { 956 if (NDIS_SERIALIZED(sc->ndis_block)) 957 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 958 return (0); 959 } 960 961 MSCALL3(senddonefunc, sc->ndis_block, packet, status); 962 963 if (NDIS_SERIALIZED(sc->ndis_block)) 964 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 965 966 return (0); 967} 968 969int 970ndis_init_dma(arg) 971 void *arg; 972{ 973 struct ndis_softc *sc; 974 int i, error; 975 976 sc = arg; 977 978 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 979 M_DEVBUF, M_NOWAIT|M_ZERO); 980 981 if (sc->ndis_tmaps == NULL) 982 return (ENOMEM); 983 984 for (i = 0; i < sc->ndis_maxpkts; i++) { 985 error = bus_dmamap_create(sc->ndis_ttag, 0, 986 &sc->ndis_tmaps[i]); 987 if (error) { 988 free(sc->ndis_tmaps, M_DEVBUF); 989 return (ENODEV); 990 } 991 } 992 993 return (0); 994} 995 996int 997ndis_destroy_dma(arg) 998 void *arg; 999{ 1000 struct ndis_softc *sc; 1001 struct mbuf *m; 1002 ndis_packet *p = NULL; 1003 int i; 1004 1005 sc = arg; 1006 1007 for (i = 0; i < sc->ndis_maxpkts; i++) { 1008 if (sc->ndis_txarray[i] != NULL) { 1009 p = sc->ndis_txarray[i]; 1010 m = (struct mbuf *)p->np_rsvd[1]; 1011 if (m != NULL) 1012 m_freem(m); 1013 ndis_free_packet(sc->ndis_txarray[i]); 1014 } 1015 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1016 } 1017 1018 free(sc->ndis_tmaps, M_DEVBUF); 1019 1020 bus_dma_tag_destroy(sc->ndis_ttag); 1021 1022 return (0); 1023} 1024 1025int 1026ndis_reset_nic(arg) 1027 void *arg; 1028{ 1029 struct ndis_softc *sc; 1030 ndis_handle adapter; 1031 ndis_reset_handler resetfunc; 1032 uint8_t addressing_reset; 1033 int rval; 1034 uint8_t irql = 0; 1035 1036 sc = arg; 1037 1038 NDIS_LOCK(sc); 1039 adapter = sc->ndis_block->nmb_miniportadapterctx; 1040 resetfunc = sc->ndis_chars->nmc_reset_func; 1041 1042 if (adapter == NULL || resetfunc == NULL || 1043 sc->ndis_block->nmb_devicectx == NULL) { 1044 NDIS_UNLOCK(sc); 1045 return (EIO); 1046 } 1047 1048 NDIS_UNLOCK(sc); 1049 1050 KeResetEvent(&sc->ndis_block->nmb_resetevent); 1051 1052 if (NDIS_SERIALIZED(sc->ndis_block)) 1053 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1054 1055 rval = MSCALL2(resetfunc, &addressing_reset, adapter); 1056 1057 if (NDIS_SERIALIZED(sc->ndis_block)) 1058 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1059 1060 if (rval == NDIS_STATUS_PENDING) 1061 KeWaitForSingleObject(&sc->ndis_block->nmb_resetevent, 1062 0, 0, FALSE, NULL); 1063 1064 return (0); 1065} 1066 1067int 1068ndis_halt_nic(arg) 1069 void *arg; 1070{ 1071 struct ndis_softc *sc; 1072 ndis_handle adapter; 1073 ndis_halt_handler haltfunc; 1074 ndis_miniport_block *block; 1075 int empty = 0; 1076 uint8_t irql; 1077 1078 sc = arg; 1079 block = sc->ndis_block; 1080 1081 if (!cold) 1082 KeFlushQueuedDpcs(); 1083 1084 /* 1085 * Wait for all packets to be returned. 1086 */ 1087 1088 while (1) { 1089 KeAcquireSpinLock(&block->nmb_returnlock, &irql); 1090 empty = IsListEmpty(&block->nmb_returnlist); 1091 KeReleaseSpinLock(&block->nmb_returnlock, irql); 1092 if (empty) 1093 break; 1094 NdisMSleep(1000); 1095 } 1096 1097 NDIS_LOCK(sc); 1098 adapter = sc->ndis_block->nmb_miniportadapterctx; 1099 if (adapter == NULL) { 1100 NDIS_UNLOCK(sc); 1101 return (EIO); 1102 } 1103 1104 sc->ndis_block->nmb_devicectx = NULL; 1105 1106 /* 1107 * The adapter context is only valid after the init 1108 * handler has been called, and is invalid once the 1109 * halt handler has been called. 1110 */ 1111 1112 haltfunc = sc->ndis_chars->nmc_halt_func; 1113 NDIS_UNLOCK(sc); 1114 1115 MSCALL1(haltfunc, adapter); 1116 1117 NDIS_LOCK(sc); 1118 sc->ndis_block->nmb_miniportadapterctx = NULL; 1119 NDIS_UNLOCK(sc); 1120 1121 return (0); 1122} 1123 1124int 1125ndis_shutdown_nic(arg) 1126 void *arg; 1127{ 1128 struct ndis_softc *sc; 1129 ndis_handle adapter; 1130 ndis_shutdown_handler shutdownfunc; 1131 1132 sc = arg; 1133 NDIS_LOCK(sc); 1134 adapter = sc->ndis_block->nmb_miniportadapterctx; 1135 shutdownfunc = sc->ndis_chars->nmc_shutdown_handler; 1136 NDIS_UNLOCK(sc); 1137 if (adapter == NULL || shutdownfunc == NULL) 1138 return (EIO); 1139 1140 if (sc->ndis_chars->nmc_rsvd0 == NULL) 1141 MSCALL1(shutdownfunc, adapter); 1142 else 1143 MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0); 1144 1145 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1146 1147 return (0); 1148} 1149 1150int 1151ndis_pnpevent_nic(arg, type) 1152 void *arg; 1153 int type; 1154{ 1155 device_t dev; 1156 struct ndis_softc *sc; 1157 ndis_handle adapter; 1158 ndis_pnpevent_handler pnpeventfunc; 1159 1160 dev = arg; 1161 sc = device_get_softc(arg); 1162 NDIS_LOCK(sc); 1163 adapter = sc->ndis_block->nmb_miniportadapterctx; 1164 pnpeventfunc = sc->ndis_chars->nmc_pnpevent_handler; 1165 NDIS_UNLOCK(sc); 1166 if (adapter == NULL || pnpeventfunc == NULL) 1167 return (EIO); 1168 1169 if (sc->ndis_chars->nmc_rsvd0 == NULL) 1170 MSCALL4(pnpeventfunc, adapter, type, NULL, 0); 1171 else 1172 MSCALL4(pnpeventfunc, sc->ndis_chars->nmc_rsvd0, type, NULL, 0); 1173 1174 return (0); 1175} 1176 1177int 1178ndis_init_nic(arg) 1179 void *arg; 1180{ 1181 struct ndis_softc *sc; 1182 ndis_miniport_block *block; 1183 ndis_init_handler initfunc; 1184 ndis_status status, openstatus = 0; 1185 ndis_medium mediumarray[NdisMediumMax]; 1186 uint32_t chosenmedium, i; 1187 1188 if (arg == NULL) 1189 return (EINVAL); 1190 1191 sc = arg; 1192 NDIS_LOCK(sc); 1193 block = sc->ndis_block; 1194 initfunc = sc->ndis_chars->nmc_init_func; 1195 NDIS_UNLOCK(sc); 1196 1197 sc->ndis_block->nmb_timerlist = NULL; 1198 1199 for (i = 0; i < NdisMediumMax; i++) 1200 mediumarray[i] = i; 1201 1202 status = MSCALL6(initfunc, &openstatus, &chosenmedium, 1203 mediumarray, NdisMediumMax, block, block); 1204 1205 /* 1206 * If the init fails, blow away the other exported routines 1207 * we obtained from the driver so we can't call them later. 1208 * If the init failed, none of these will work. 1209 */ 1210 if (status != NDIS_STATUS_SUCCESS) { 1211 NDIS_LOCK(sc); 1212 sc->ndis_block->nmb_miniportadapterctx = NULL; 1213 NDIS_UNLOCK(sc); 1214 return (ENXIO); 1215 } 1216 1217 /* 1218 * This may look really goofy, but apparently it is possible 1219 * to halt a miniport too soon after it's been initialized. 1220 * After MiniportInitialize() finishes, pause for 1 second 1221 * to give the chip a chance to handle any short-lived timers 1222 * that were set in motion. If we call MiniportHalt() too soon, 1223 * some of the timers may not be cancelled, because the driver 1224 * expects them to fire before the halt is called. 1225 */ 1226 1227 pause("ndwait", hz); 1228 1229 NDIS_LOCK(sc); 1230 sc->ndis_block->nmb_devicectx = sc; 1231 NDIS_UNLOCK(sc); 1232 1233 return (0); 1234} 1235 1236static void 1237ndis_intrsetup(dpc, dobj, ip, sc) 1238 kdpc *dpc; 1239 device_object *dobj; 1240 irp *ip; 1241 struct ndis_softc *sc; 1242{ 1243 ndis_miniport_interrupt *intr; 1244 1245 intr = sc->ndis_block->nmb_interrupt; 1246 1247 /* Sanity check. */ 1248 1249 if (intr == NULL) 1250 return; 1251 1252 KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock); 1253 KeResetEvent(&intr->ni_dpcevt); 1254 if (KeInsertQueueDpc(&intr->ni_dpc, NULL, NULL) == TRUE) 1255 intr->ni_dpccnt++; 1256 KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock); 1257} 1258 1259int 1260ndis_get_info(arg, oid, buf, buflen) 1261 void *arg; 1262 ndis_oid oid; 1263 void *buf; 1264 int *buflen; 1265{ 1266 struct ndis_softc *sc; 1267 ndis_status rval; 1268 ndis_handle adapter; 1269 ndis_queryinfo_handler queryfunc; 1270 uint32_t byteswritten = 0, bytesneeded = 0; 1271 uint8_t irql; 1272 uint64_t duetime; 1273 1274 sc = arg; 1275 1276 KeResetEvent(&sc->ndis_block->nmb_getevent); 1277 1278 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1279 1280 if (sc->ndis_block->nmb_pendingreq != NULL) { 1281 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1282 panic("ndis_get_info() called while other request pending"); 1283 } else 1284 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 1285 1286 queryfunc = sc->ndis_chars->nmc_queryinfo_func; 1287 adapter = sc->ndis_block->nmb_miniportadapterctx; 1288 1289 if (adapter == NULL || queryfunc == NULL || 1290 sc->ndis_block->nmb_devicectx == NULL) { 1291 sc->ndis_block->nmb_pendingreq = NULL; 1292 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1293 return (ENXIO); 1294 } 1295 1296 rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, 1297 &byteswritten, &bytesneeded); 1298 1299 sc->ndis_block->nmb_pendingreq = NULL; 1300 1301 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1302 1303 /* Wait for requests that block. */ 1304 1305 if (rval == NDIS_STATUS_PENDING) { 1306 /* Wait up to 5 seconds. */ 1307 duetime = (5 * 1000000) * -10; 1308 KeWaitForSingleObject(&sc->ndis_block->nmb_getevent, 1309 0, 0, FALSE, &duetime); 1310 rval = sc->ndis_block->nmb_getstat; 1311 } 1312 1313 if (byteswritten) 1314 *buflen = byteswritten; 1315 if (bytesneeded) 1316 *buflen = bytesneeded; 1317 1318 if (rval == NDIS_STATUS_INVALID_LENGTH || 1319 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1320 return (ENOSPC); 1321 1322 if (rval == NDIS_STATUS_INVALID_OID) 1323 return (EINVAL); 1324 1325 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1326 rval == NDIS_STATUS_NOT_ACCEPTED) 1327 return (ENOTSUP); 1328 1329 if (rval != NDIS_STATUS_SUCCESS) 1330 return (ENODEV); 1331 1332 return (0); 1333} 1334 1335uint32_t 1336NdisAddDevice(drv, pdo) 1337 driver_object *drv; 1338 device_object *pdo; 1339{ 1340 device_object *fdo; 1341 ndis_miniport_block *block; 1342 struct ndis_softc *sc; 1343 uint32_t status; 1344 int error; 1345 1346 sc = device_get_softc(pdo->do_devext); 1347 1348 if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) { 1349 error = bus_setup_intr(sc->ndis_dev, sc->ndis_irq, 1350 INTR_TYPE_NET | INTR_MPSAFE, 1351 NULL, ntoskrnl_intr, NULL, &sc->ndis_intrhand); 1352 if (error) 1353 return (NDIS_STATUS_FAILURE); 1354 } 1355 1356 status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, 1357 FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); 1358 1359 if (status != STATUS_SUCCESS) 1360 return (status); 1361 1362 block = fdo->do_devext; 1363 1364 block->nmb_filterdbs.nf_ethdb = block; 1365 block->nmb_deviceobj = fdo; 1366 block->nmb_physdeviceobj = pdo; 1367 block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); 1368 KeInitializeSpinLock(&block->nmb_lock); 1369 KeInitializeSpinLock(&block->nmb_returnlock); 1370 KeInitializeEvent(&block->nmb_getevent, EVENT_TYPE_NOTIFY, TRUE); 1371 KeInitializeEvent(&block->nmb_setevent, EVENT_TYPE_NOTIFY, TRUE); 1372 KeInitializeEvent(&block->nmb_resetevent, EVENT_TYPE_NOTIFY, TRUE); 1373 InitializeListHead(&block->nmb_parmlist); 1374 InitializeListHead(&block->nmb_returnlist); 1375 block->nmb_returnitem = IoAllocateWorkItem(fdo); 1376 1377 /* 1378 * Stash pointers to the miniport block and miniport 1379 * characteristics info in the if_ndis softc so the 1380 * UNIX wrapper driver can get to them later. 1381 */ 1382 sc->ndis_block = block; 1383 sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); 1384 1385 /* 1386 * If the driver has a MiniportTransferData() function, 1387 * we should allocate a private RX packet pool. 1388 */ 1389 1390 if (sc->ndis_chars->nmc_transferdata_func != NULL) { 1391 NdisAllocatePacketPool(&status, &block->nmb_rxpool, 1392 32, PROTOCOL_RESERVED_SIZE_IN_PACKET); 1393 if (status != NDIS_STATUS_SUCCESS) { 1394 IoDetachDevice(block->nmb_nextdeviceobj); 1395 IoDeleteDevice(fdo); 1396 return (status); 1397 } 1398 InitializeListHead((&block->nmb_packetlist)); 1399 } 1400 1401 /* Give interrupt handling priority over timers. */ 1402 IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap); 1403 KeSetImportanceDpc(&fdo->do_dpc, KDPC_IMPORTANCE_HIGH); 1404 1405 /* Finish up BSD-specific setup. */ 1406 1407 block->nmb_signature = (void *)0xcafebabe; 1408 block->nmb_status_func = kernndis_functbl[0].ipt_wrap; 1409 block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap; 1410 block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap; 1411 block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; 1412 block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; 1413 block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; 1414 block->nmb_pendingreq = NULL; 1415 1416 TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1417 1418 return (STATUS_SUCCESS); 1419} 1420 1421int 1422ndis_unload_driver(arg) 1423 void *arg; 1424{ 1425 struct ndis_softc *sc; 1426 device_object *fdo; 1427 1428 sc = arg; 1429 1430 if (sc->ndis_intrhand) 1431 bus_teardown_intr(sc->ndis_dev, 1432 sc->ndis_irq, sc->ndis_intrhand); 1433 1434 if (sc->ndis_block->nmb_rlist != NULL) 1435 free(sc->ndis_block->nmb_rlist, M_DEVBUF); 1436 1437 ndis_flush_sysctls(sc); 1438 1439 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1440 1441 if (sc->ndis_chars->nmc_transferdata_func != NULL) 1442 NdisFreePacketPool(sc->ndis_block->nmb_rxpool); 1443 fdo = sc->ndis_block->nmb_deviceobj; 1444 IoFreeWorkItem(sc->ndis_block->nmb_returnitem); 1445 IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); 1446 IoDeleteDevice(fdo); 1447 1448 return (0); 1449} 1450