35 36#include <sys/param.h> 37#include <sys/types.h> 38#include <sys/errno.h> 39#include <sys/callout.h> 40#include <sys/socket.h> 41#include <sys/queue.h> 42#include <sys/sysctl.h> 43#include <sys/systm.h> 44#include <sys/malloc.h> 45#include <sys/lock.h> 46#include <sys/mutex.h> 47#include <sys/conf.h> 48#include <sys/taskqueue.h> 49 50#include <sys/kernel.h> 51#include <machine/bus.h> 52#include <machine/resource.h> 53#include <sys/bus.h> 54#include <sys/rman.h> 55 56#include <vm/uma.h> 57 58#include <net/if.h> 59#include <net/if_arp.h> 60#include <net/ethernet.h> 61#include <net/if_dl.h> 62#include <net/if_media.h> 63 64#include <net80211/ieee80211_var.h> 65#include <net80211/ieee80211_ioctl.h> 66 67#include <dev/pccard/pccardvar.h> 68#include "card_if.h" 69 70#include <compat/ndis/pe_var.h> 71#include <compat/ndis/resource_var.h> 72#include <compat/ndis/ndis_var.h> 73#include <compat/ndis/hal_var.h> 74#include <compat/ndis/ntoskrnl_var.h> 75#include <compat/ndis/cfg_var.h> 76#include <dev/if_ndis/if_ndisvar.h> 77 78#define __stdcall __attribute__((__stdcall__)) 79#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 80 81__stdcall static void ndis_status_func(ndis_handle, ndis_status, 82 void *, uint32_t); 83__stdcall static void ndis_statusdone_func(ndis_handle); 84__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); 85__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); 86__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 87__stdcall static void ndis_sendrsrcavail_func(ndis_handle); 88 89static uma_zone_t ndis_packet_zone, ndis_buffer_zone; 90 91/* 92 * This allows us to export our symbols to other modules. 93 * Note that we call ourselves 'ndisapi' to avoid a namespace 94 * collision with if_ndis.ko, which internally calls itself 95 * 'ndis.' 96 */ 97static int 98ndis_modevent(module_t mod, int cmd, void *arg) 99{ 100 int error = 0; 101 102 switch (cmd) { 103 case MOD_LOAD: 104 /* Initialize subsystems */ 105 ndis_libinit(); 106 ntoskrnl_libinit(); 107 108 /* Initialize TX buffer UMA zone. */ 109 ndis_packet_zone = uma_zcreate("NDIS packet", 110 sizeof(ndis_packet), NULL, NULL, NULL, 111 NULL, UMA_ALIGN_PTR, 0); 112 ndis_buffer_zone = uma_zcreate("NDIS buffer", 113 sizeof(ndis_buffer), NULL, NULL, NULL, 114 NULL, UMA_ALIGN_PTR, 0); 115 break; 116 case MOD_UNLOAD: 117 case MOD_SHUTDOWN: 118 /* Shut down subsystems */ 119 ndis_libfini(); 120 ntoskrnl_libfini(); 121 122 /* Remove zones */ 123 uma_zdestroy(ndis_packet_zone); 124 uma_zdestroy(ndis_buffer_zone); 125 break; 126 default: 127 error = EINVAL; 128 break; 129 } 130 131 return(error); 132} 133DEV_MODULE(ndisapi, ndis_modevent, NULL); 134MODULE_VERSION(ndisapi, 1); 135 136 137__stdcall static void 138ndis_sendrsrcavail_func(adapter) 139 ndis_handle adapter; 140{ 141 return; 142} 143 144__stdcall static void 145ndis_status_func(adapter, status, sbuf, slen) 146 ndis_handle adapter; 147 ndis_status status; 148 void *sbuf; 149 uint32_t slen; 150{ 151 ndis_miniport_block *block; 152 block = adapter; 153 154 device_printf (block->nmb_dev, "status: %x\n", status); 155 return; 156} 157 158__stdcall static void 159ndis_statusdone_func(adapter) 160 ndis_handle adapter; 161{ 162 ndis_miniport_block *block; 163 block = adapter; 164 165 device_printf (block->nmb_dev, "status complete\n"); 166 return; 167} 168 169__stdcall static void 170ndis_setdone_func(adapter, status) 171 ndis_handle adapter; 172 ndis_status status; 173{ 174 ndis_miniport_block *block; 175 block = adapter; 176 177 block->nmb_setstat = status; 178 wakeup(&block->nmb_wkupdpctimer); 179 return; 180} 181 182__stdcall static void 183ndis_getdone_func(adapter, status) 184 ndis_handle adapter; 185 ndis_status status; 186{ 187 ndis_miniport_block *block; 188 block = adapter; 189 190 block->nmb_getstat = status; 191 wakeup(&block->nmb_wkupdpctimer); 192 return; 193} 194 195__stdcall static void 196ndis_resetdone_func(adapter, status, addressingreset) 197 ndis_handle adapter; 198 ndis_status status; 199 uint8_t addressingreset; 200{ 201 ndis_miniport_block *block; 202 block = adapter; 203 204 device_printf (block->nmb_dev, "reset done...\n"); 205 return; 206} 207 208#define NDIS_AM_RID 3 209 210int 211ndis_alloc_amem(arg) 212 void *arg; 213{ 214 struct ndis_softc *sc; 215 int error, rid; 216 217 if (arg == NULL) 218 return(EINVAL); 219 220 sc = arg; 221 rid = NDIS_AM_RID; 222 sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, 223 &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); 224 225 if (sc->ndis_res_am == NULL) { 226 device_printf(sc->ndis_dev, 227 "failed to allocate attribute memory\n"); 228 return(ENXIO); 229 } 230 231 error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), 232 sc->ndis_dev, rid, 0, NULL); 233 234 if (error) { 235 device_printf(sc->ndis_dev, 236 "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error); 237 return(error); 238 } 239 240 error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), 241 sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 242 243 if (error) { 244 device_printf(sc->ndis_dev, 245 "CARD_SET_RES_FLAGS() returned 0x%x\n", error); 246 return(error); 247 } 248 249 return(0); 250} 251 252int 253ndis_create_sysctls(arg) 254 void *arg; 255{ 256 struct ndis_softc *sc; 257 ndis_cfg *vals; 258 char buf[256]; 259 260 if (arg == NULL) 261 return(EINVAL); 262 263 sc = arg; 264 vals = sc->ndis_regvals; 265 266 TAILQ_INIT(&sc->ndis_cfglist_head); 267 268 /* Create the sysctl tree. */ 269 270 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 271 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 272 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 273 device_get_desc(sc->ndis_dev)); 274 275 /* Add the driver-specific registry keys. */ 276 277 vals = sc->ndis_regvals; 278 while(1) { 279 if (vals->nc_cfgkey == NULL) 280 break; 281 if (vals->nc_idx != sc->ndis_devidx) { 282 vals++; 283 continue; 284 } 285 SYSCTL_ADD_STRING(&sc->ndis_ctx, 286 SYSCTL_CHILDREN(sc->ndis_tree), 287 OID_AUTO, vals->nc_cfgkey, 288 CTLFLAG_RW, vals->nc_val, 289 sizeof(vals->nc_val), 290 vals->nc_cfgdesc); 291 vals++; 292 } 293 294 /* Now add a couple of builtin keys. */ 295 296 /* 297 * Environment can be either Windows (0) or WindowsNT (1). 298 * We qualify as the latter. 299 */ 300 ndis_add_sysctl(sc, "Environment", 301 "Windows environment", "1", CTLFLAG_RD); 302 303 /* NDIS version should be 5.1. */ 304 ndis_add_sysctl(sc, "NdisVersion", 305 "NDIS API Version", "0x00050001", CTLFLAG_RD); 306 307 /* Bus type (PCI, PCMCIA, etc...) */ 308 sprintf(buf, "%d\n", (int)sc->ndis_iftype); 309 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 310 311 if (sc->ndis_res_io != NULL) { 312 sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io)); 313 ndis_add_sysctl(sc, "IOBaseAddress", 314 "Base I/O Address", buf, CTLFLAG_RD); 315 } 316 317 if (sc->ndis_irq != NULL) { 318 sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq)); 319 ndis_add_sysctl(sc, "InterruptNumber", 320 "Interrupt Number", buf, CTLFLAG_RD); 321 } 322 323 return(0); 324} 325 326int 327ndis_add_sysctl(arg, key, desc, val, flag) 328 void *arg; 329 char *key; 330 char *desc; 331 char *val; 332 int flag; 333{ 334 struct ndis_softc *sc; 335 struct ndis_cfglist *cfg; 336 char descstr[256]; 337 338 sc = arg; 339 340 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 341 342 if (cfg == NULL) 343 return(ENOMEM); 344 345 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 346 if (desc == NULL) { 347 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 348 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 349 } else 350 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 351 strcpy(cfg->ndis_cfg.nc_val, val); 352 353 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 354 355 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 356 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 357 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 358 cfg->ndis_cfg.nc_cfgdesc); 359 360 return(0); 361} 362 363int 364ndis_flush_sysctls(arg) 365 void *arg; 366{ 367 struct ndis_softc *sc; 368 struct ndis_cfglist *cfg; 369 370 sc = arg; 371 372 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 373 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 374 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 375 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 376 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 377 free(cfg, M_DEVBUF); 378 } 379 380 return(0); 381} 382 383void 384ndis_return_packet(buf, arg) 385 void *buf; /* not used */ 386 void *arg; 387{ 388 struct ndis_softc *sc; 389 ndis_handle adapter; 390 ndis_packet *p; 391 __stdcall ndis_return_handler returnfunc; 392 393 if (arg == NULL) 394 return; 395 396 p = arg; 397 398 /* Decrement refcount. */ 399 p->np_refcnt--; 400 401 /* Release packet when refcount hits zero, otherwise return. */ 402 if (p->np_refcnt) 403 return; 404 405 sc = p->np_softc; 406 returnfunc = sc->ndis_chars.nmc_return_packet_func; 407 adapter = sc->ndis_block.nmb_miniportadapterctx; 408 if (returnfunc != NULL) 409 returnfunc(adapter, p); 410 411 return; 412} 413 414void 415ndis_free_bufs(b0) 416 ndis_buffer *b0; 417{ 418 ndis_buffer *next; 419 420 if (b0 == NULL) 421 return; 422 423 while(b0 != NULL) { 424 next = b0->nb_next; 425 uma_zfree (ndis_buffer_zone, b0); 426 b0 = next; 427 } 428 429 return; 430} 431 432void 433ndis_free_packet(p) 434 ndis_packet *p; 435{ 436 if (p == NULL) 437 return; 438 439 ndis_free_bufs(p->np_private.npp_head); 440 uma_zfree(ndis_packet_zone, p); 441 442 return; 443} 444 445int 446ndis_convert_res(arg) 447 void *arg; 448{ 449 struct ndis_softc *sc; 450 ndis_resource_list *rl = NULL; 451 cm_partial_resource_desc *prd = NULL; 452 ndis_miniport_block *block; 453 device_t dev; 454 struct resource_list *brl; 455 struct resource_list_entry *brle; 456 457 sc = arg; 458 block = &sc->ndis_block; 459 dev = sc->ndis_dev; 460 461 rl = malloc(sizeof(ndis_resource_list) + 462 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 463 M_DEVBUF, M_NOWAIT|M_ZERO); 464 465 if (rl == NULL) 466 return(ENOMEM); 467 468 rl->cprl_version = 5; 469 rl->cprl_version = 1; 470 rl->cprl_count = sc->ndis_rescnt; 471 prd = rl->cprl_partial_descs; 472 473 brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 474 if (brl != NULL) { 475 SLIST_FOREACH(brle, brl, link) { 476 switch (brle->type) { 477 case SYS_RES_IOPORT: 478 prd->cprd_type = CmResourceTypePort; 479 prd->u.cprd_port.cprd_start.np_quad = 480 brle->start; 481 prd->u.cprd_port.cprd_len = brle->count; 482 break; 483 case SYS_RES_MEMORY: 484 prd->cprd_type = CmResourceTypeMemory; 485 prd->u.cprd_port.cprd_start.np_quad = 486 brle->start; 487 prd->u.cprd_port.cprd_len = brle->count; 488 break; 489 case SYS_RES_IRQ: 490 prd->cprd_type = CmResourceTypeInterrupt; 491 prd->u.cprd_intr.cprd_level = brle->start; 492 prd->u.cprd_intr.cprd_vector = brle->start; 493 prd->u.cprd_intr.cprd_affinity = 0; 494 break; 495 default: 496 break; 497 } 498 prd++; 499 } 500 } 501 502 block->nmb_rlist = rl; 503 504 return(0); 505} 506 507/* 508 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 509 * packet, it will hand it to us in the form of an ndis_packet, 510 * which we need to convert to an mbuf that is then handed off 511 * to the stack. Note: we configure the mbuf list so that it uses 512 * the memory regions specified by the ndis_buffer structures in 513 * the ndis_packet as external storage. In most cases, this will 514 * point to a memory region allocated by the driver (either by 515 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 516 * the driver to handle free()ing this region for is, so we set up 517 * a dummy no-op free handler for it. 518 */ 519 520int 521ndis_ptom(m0, p) 522 struct mbuf **m0; 523 ndis_packet *p; 524{ 525 struct mbuf *m, *prev = NULL; 526 ndis_buffer *buf; 527 ndis_packet_private *priv; 528 uint32_t totlen = 0; 529 530 if (p == NULL || m0 == NULL) 531 return(EINVAL); 532 533 priv = &p->np_private; 534 buf = priv->npp_head; 535 p->np_refcnt = 0; 536 537 for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) { 538 if (buf == priv->npp_head) 539 MGETHDR(m, M_DONTWAIT, MT_HEADER); 540 else 541 MGET(m, M_DONTWAIT, MT_DATA); 542 if (m == NULL) { 543 m_freem(*m0); 544 *m0 = NULL; 545 return(ENOBUFS); 546 } 547 m->m_len = buf->nb_bytecount; 548 m->m_data = MDL_VA(buf); 549 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 550 p, 0, EXT_NDIS); 551 p->np_refcnt++; 552 totlen += m->m_len; 553 if (m->m_flags & MT_HEADER) 554 *m0 = m; 555 else 556 prev->m_next = m; 557 prev = m; 558 } 559 560 (*m0)->m_pkthdr.len = totlen; 561 562 return(0); 563} 564 565/* 566 * Create an mbuf chain from an NDIS packet chain. 567 * This is used mainly when transmitting packets, where we need 568 * to turn an mbuf off an interface's send queue and transform it 569 * into an NDIS packet which will be fed into the NDIS driver's 570 * send routine. 571 * 572 * NDIS packets consist of two parts: an ndis_packet structure, 573 * which is vaguely analagous to the pkthdr portion of an mbuf, 574 * and one or more ndis_buffer structures, which define the 575 * actual memory segments in which the packet data resides. 576 * We need to allocate one ndis_buffer for each mbuf in a chain, 577 * plus one ndis_packet as the header. 578 */ 579 580int 581ndis_mtop(m0, p) 582 struct mbuf *m0; 583 ndis_packet **p; 584{ 585 struct mbuf *m; 586 ndis_buffer *buf = NULL, *prev = NULL; 587 ndis_packet_private *priv; 588 589 if (p == NULL || m0 == NULL) 590 return(EINVAL); 591 592 /* If caller didn't supply a packet, make one. */ 593 if (*p == NULL) { 594 *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO); 595 596 if (*p == NULL) 597 return(ENOMEM); 598 } 599 600 priv = &(*p)->np_private; 601 priv->npp_totlen = m0->m_pkthdr.len; 602 priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 603 604 for (m = m0; m != NULL; m = m->m_next) { 605 if (m->m_len == 0) 606 continue; 607 buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO); 608 if (buf == NULL) { 609 ndis_free_packet(*p); 610 *p = NULL; 611 return(ENOMEM); 612 } 613 614 MDL_INIT(buf, m->m_data, m->m_len); 615 if (priv->npp_head == NULL) 616 priv->npp_head = buf; 617 else 618 prev->nb_next = buf; 619 prev = buf; 620 } 621 622 priv->npp_tail = buf; 623 priv->npp_totlen = m0->m_pkthdr.len; 624 625 return(0); 626} 627 628int 629ndis_get_supported_oids(arg, oids, oidcnt) 630 void *arg; 631 ndis_oid **oids; 632 int *oidcnt; 633{ 634 int len, rval; 635 ndis_oid *o; 636 637 if (arg == NULL || oids == NULL || oidcnt == NULL) 638 return(EINVAL); 639 len = 0; 640 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 641 642 o = malloc(len, M_DEVBUF, M_NOWAIT); 643 if (o == NULL) 644 return(ENOMEM); 645 646 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 647 648 if (rval) { 649 free(o, M_DEVBUF); 650 return(rval); 651 } 652 653 *oids = o; 654 *oidcnt = len / 4; 655 656 return(0); 657} 658 659int 660ndis_set_info(arg, oid, buf, buflen) 661 void *arg; 662 ndis_oid oid; 663 void *buf; 664 int *buflen; 665{ 666 struct ndis_softc *sc; 667 ndis_status rval; 668 ndis_handle adapter; 669 __stdcall ndis_setinfo_handler setfunc; 670 uint32_t byteswritten = 0, bytesneeded = 0; 671 struct timeval tv; 672 int error; 673 674 sc = arg; 675 setfunc = sc->ndis_chars.nmc_setinfo_func; 676 adapter = sc->ndis_block.nmb_miniportadapterctx; 677 678 rval = setfunc(adapter, oid, buf, *buflen, 679 &byteswritten, &bytesneeded); 680 681 if (rval == NDIS_STATUS_PENDING) { 682 tv.tv_sec = 60; 683 tv.tv_usec = 0; 684 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 685 PPAUSE|PCATCH, "ndisset", tvtohz(&tv)); 686 rval = sc->ndis_block.nmb_setstat; 687 } 688 689 if (byteswritten) 690 *buflen = byteswritten; 691 if (bytesneeded) 692 *buflen = bytesneeded; 693 694 if (rval == NDIS_STATUS_INVALID_LENGTH) 695 return(ENOSPC); 696 697 if (rval == NDIS_STATUS_INVALID_OID) 698 return(EINVAL); 699 700 if (rval == NDIS_STATUS_NOT_SUPPORTED || 701 rval == NDIS_STATUS_NOT_ACCEPTED) 702 return(ENOTSUP); 703 704 return(0); 705} 706 707int 708ndis_send_packets(arg, packets, cnt) 709 void *arg; 710 ndis_packet **packets; 711 int cnt; 712{ 713 struct ndis_softc *sc; 714 ndis_handle adapter; 715 __stdcall ndis_sendmulti_handler sendfunc; 716 int i, idx; 717 struct ifnet *ifp; 718 struct mbuf *m; 719 ndis_packet *p; 720 721 sc = arg; 722 adapter = sc->ndis_block.nmb_miniportadapterctx; 723 sendfunc = sc->ndis_chars.nmc_sendmulti_func; 724 sendfunc(adapter, packets, cnt); 725 726 for (i = 0; i < cnt; i++) { 727 p = packets[i]; 728 /* 729 * Either the driver already handed the packet to 730 * ndis_txeof() due to a failure, or it wants to keep 731 * it and release it asynchronously later. Skip to the 732 * next one. 733 */ 734 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 735 continue; 736 idx = p->np_txidx; 737 m = p->np_m0; 738 ifp = &sc->arpcom.ac_if; 739 if (sc->ndis_sc) 740 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]); 741 sc->ndis_txarray[idx] = NULL; 742 sc->ndis_txpending++; 743 m_freem(m); 744 ndis_free_packet(p); 745 if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) 746 ifp->if_opackets++; 747 else 748 ifp->if_oerrors++; 749 ifp->if_timer = 0; 750 ifp->if_flags &= ~IFF_OACTIVE; 751 } 752 753 return(0); 754} 755 756int 757ndis_init_dma(arg) 758 void *arg; 759{ 760 struct ndis_softc *sc; 761 int i, error; 762 763 sc = arg; 764 765 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 766 M_DEVBUF, M_NOWAIT|M_ZERO); 767 768 if (sc->ndis_tmaps == NULL) 769 return(ENOMEM); 770 771 for (i = 0; i < sc->ndis_maxpkts; i++) { 772 error = bus_dmamap_create(sc->ndis_ttag, 0, 773 &sc->ndis_tmaps[i]); 774 if (error) { 775 free(sc->ndis_tmaps, M_DEVBUF); 776 return(ENODEV); 777 } 778 } 779 780 return(0); 781} 782 783int 784ndis_destroy_dma(arg) 785 void *arg; 786{ 787 struct ndis_softc *sc; 788 struct mbuf *m; 789 ndis_packet *p = NULL; 790 int i; 791 792 sc = arg; 793 794 for (i = 0; i < sc->ndis_maxpkts; i++) { 795 if (sc->ndis_txarray[i] != NULL) { 796 p = sc->ndis_txarray[i]; 797 m = (struct mbuf *)p->np_rsvd[1]; 798 if (m != NULL) 799 m_freem(m); 800 ndis_free_packet(sc->ndis_txarray[i]); 801 } 802 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 803 } 804 805 free(sc->ndis_tmaps, M_DEVBUF); 806 807 bus_dma_tag_destroy(sc->ndis_ttag); 808 809 return(0); 810} 811 812int 813ndis_reset_nic(arg) 814 void *arg; 815{ 816 struct ndis_softc *sc; 817 ndis_handle adapter; 818 __stdcall ndis_reset_handler resetfunc; 819 uint8_t addressing_reset; 820 struct ifnet *ifp; 821 822 sc = arg; 823 ifp = &sc->arpcom.ac_if; 824 adapter = sc->ndis_block.nmb_miniportadapterctx; 825 if (adapter == NULL) 826 return(EIO); 827 resetfunc = sc->ndis_chars.nmc_reset_func; 828 829 if (resetfunc == NULL) 830 return(EINVAL); 831 832 resetfunc(&addressing_reset, adapter); 833 834 return(0); 835} 836 837int 838ndis_halt_nic(arg) 839 void *arg; 840{ 841 struct ndis_softc *sc; 842 ndis_handle adapter; 843 __stdcall ndis_halt_handler haltfunc; 844 struct ifnet *ifp; 845 struct ndis_timer_entry *ne; 846 847 sc = arg; 848 ifp = &sc->arpcom.ac_if; 849 adapter = sc->ndis_block.nmb_miniportadapterctx; 850 if (adapter == NULL) 851 return(EIO); 852 853 haltfunc = sc->ndis_chars.nmc_halt_func; 854 855 if (haltfunc == NULL) 856 return(EINVAL); 857 858 haltfunc(adapter); 859 860 /* 861 * The adapter context is only valid after the init 862 * handler has been called, and is invalid once the 863 * halt handler has been called. 864 */ 865 866 sc->ndis_block.nmb_miniportadapterctx = NULL; 867 868 /* Clobber all the timers in case the driver left one running. */ 869 870 while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) { 871 ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist); 872 TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link); 873 callout_stop(&ne->nte_ch); 874 free(ne, M_DEVBUF); 875 } 876 877 return(0); 878} 879 880int 881ndis_shutdown_nic(arg) 882 void *arg; 883{ 884 struct ndis_softc *sc; 885 ndis_handle adapter; 886 __stdcall ndis_shutdown_handler shutdownfunc; 887 888 889 sc = arg; 890 adapter = sc->ndis_block.nmb_miniportadapterctx; 891 if (adapter == NULL) 892 return(EIO); 893 shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 894 895 if (shutdownfunc == NULL) 896 return(EINVAL); 897 898 if (sc->ndis_chars.nmc_rsvd0 == NULL) 899 shutdownfunc(adapter); 900 else 901 shutdownfunc(sc->ndis_chars.nmc_rsvd0); 902 903 return(0); 904} 905 906int 907ndis_init_nic(arg) 908 void *arg; 909{ 910 struct ndis_softc *sc; 911 ndis_miniport_block *block; 912 __stdcall ndis_init_handler initfunc; 913 ndis_status status, openstatus = 0; 914 ndis_medium mediumarray[NdisMediumMax]; 915 uint32_t chosenmedium, i; 916 917 if (arg == NULL) 918 return(EINVAL); 919 920 sc = arg; 921 block = &sc->ndis_block; 922 initfunc = sc->ndis_chars.nmc_init_func; 923 924 TAILQ_INIT(&block->nmb_timerlist); 925 926 for (i = 0; i < NdisMediumMax; i++) 927 mediumarray[i] = i; 928 929 status = initfunc(&openstatus, &chosenmedium, 930 mediumarray, NdisMediumMax, block, block); 931 932 /* 933 * If the init fails, blow away the other exported routines 934 * we obtained from the driver so we can't call them later. 935 * If the init failed, none of these will work. 936 */ 937 if (status != NDIS_STATUS_SUCCESS) { 938 bzero((char *)&sc->ndis_chars, 939 sizeof(ndis_miniport_characteristics)); 940 return(ENXIO); 941 } 942 943 return(0); 944} 945 946void 947ndis_enable_intr(arg) 948 void *arg; 949{ 950 struct ndis_softc *sc; 951 ndis_handle adapter; 952 __stdcall ndis_enable_interrupts_handler intrenbfunc; 953 954 sc = arg; 955 adapter = sc->ndis_block.nmb_miniportadapterctx; 956 if (adapter == NULL) 957 return; 958 intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 959 if (intrenbfunc == NULL) 960 return; 961 intrenbfunc(adapter); 962 963 return; 964} 965 966void 967ndis_disable_intr(arg) 968 void *arg; 969{ 970 struct ndis_softc *sc; 971 ndis_handle adapter; 972 __stdcall ndis_disable_interrupts_handler intrdisfunc; 973 974 sc = arg; 975 adapter = sc->ndis_block.nmb_miniportadapterctx; 976 if (adapter == NULL) 977 return; 978 intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 979 if (intrdisfunc == NULL) 980 return; 981 intrdisfunc(adapter); 982 983 return; 984} 985 986int 987ndis_isr(arg, ourintr, callhandler) 988 void *arg; 989 int *ourintr; 990 int *callhandler; 991{ 992 struct ndis_softc *sc; 993 ndis_handle adapter; 994 __stdcall ndis_isr_handler isrfunc; 995 uint8_t accepted, queue; 996 997 if (arg == NULL || ourintr == NULL || callhandler == NULL) 998 return(EINVAL); 999 1000 sc = arg; 1001 adapter = sc->ndis_block.nmb_miniportadapterctx; 1002 isrfunc = sc->ndis_chars.nmc_isr_func; 1003 isrfunc(&accepted, &queue, adapter); 1004 *ourintr = accepted; 1005 *callhandler = queue; 1006 1007 return(0); 1008} 1009 1010int 1011ndis_intrhand(arg) 1012 void *arg; 1013{ 1014 struct ndis_softc *sc; 1015 ndis_handle adapter; 1016 __stdcall ndis_interrupt_handler intrfunc; 1017 1018 if (arg == NULL) 1019 return(EINVAL); 1020 1021 sc = arg; 1022 adapter = sc->ndis_block.nmb_miniportadapterctx; 1023 intrfunc = sc->ndis_chars.nmc_interrupt_func; 1024 intrfunc(adapter); 1025 1026 return(0); 1027} 1028 1029int 1030ndis_get_info(arg, oid, buf, buflen) 1031 void *arg; 1032 ndis_oid oid; 1033 void *buf; 1034 int *buflen; 1035{ 1036 struct ndis_softc *sc; 1037 ndis_status rval; 1038 ndis_handle adapter; 1039 __stdcall ndis_queryinfo_handler queryfunc; 1040 uint32_t byteswritten = 0, bytesneeded = 0; 1041 struct timeval tv; 1042 int error; 1043 1044 sc = arg; 1045 queryfunc = sc->ndis_chars.nmc_queryinfo_func; 1046 adapter = sc->ndis_block.nmb_miniportadapterctx; 1047 1048 rval = queryfunc(adapter, oid, buf, *buflen, 1049 &byteswritten, &bytesneeded); 1050 1051 /* Wait for requests that block. */ 1052 1053 if (rval == NDIS_STATUS_PENDING) { 1054 tv.tv_sec = 60; 1055 tv.tv_usec = 0; 1056 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 1057 PPAUSE|PCATCH, "ndisget", tvtohz(&tv)); 1058 rval = sc->ndis_block.nmb_getstat; 1059 } 1060 1061 if (byteswritten) 1062 *buflen = byteswritten; 1063 if (bytesneeded) 1064 *buflen = bytesneeded; 1065 1066 if (rval == NDIS_STATUS_INVALID_LENGTH || 1067 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1068 return(ENOSPC); 1069 1070 if (rval == NDIS_STATUS_INVALID_OID) 1071 return(EINVAL); 1072 1073 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1074 rval == NDIS_STATUS_NOT_ACCEPTED) 1075 return(ENOTSUP); 1076 1077 return(0); 1078} 1079 1080int 1081ndis_unload_driver(arg) 1082 void *arg; 1083{ 1084 struct ndis_softc *sc; 1085 1086 sc = arg; 1087 1088 free(sc->ndis_block.nmb_rlist, M_DEVBUF); 1089 1090 ndis_flush_sysctls(sc); 1091 1092 return(0); 1093} 1094 1095int 1096ndis_load_driver(img, arg) 1097 vm_offset_t img; 1098 void *arg; 1099{ 1100 __stdcall driver_entry entry; 1101 image_optional_header opt_hdr; 1102 image_import_descriptor imp_desc; 1103 ndis_unicode_string dummystr; 1104 ndis_driver_object drv; 1105 ndis_miniport_block *block; 1106 ndis_status status; 1107 int idx; 1108 uint32_t *ptr; 1109 struct ndis_softc *sc; 1110 1111 sc = arg; 1112 1113 /* Perform text relocation */ 1114 if (pe_relocate(img)) 1115 return(ENOEXEC); 1116 1117 /* Dynamically link the NDIS.SYS routines -- required. */ 1118 if (pe_patch_imports(img, "NDIS", ndis_functbl)) 1119 return(ENOEXEC); 1120 1121 /* Dynamically link the HAL.dll routines -- also required. */ 1122 if (pe_patch_imports(img, "HAL", hal_functbl)) 1123 return(ENOEXEC); 1124 1125 /* Dynamically link ntoskrnl.exe -- optional. */ 1126 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) { 1127 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl)) 1128 return(ENOEXEC); 1129 } 1130 1131 /* Locate the driver entry point */ 1132 pe_get_optional_header(img, &opt_hdr); 1133 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 1134 1135 /* 1136 * Now call the DriverEntry() routine. This will cause 1137 * a callout to the NdisInitializeWrapper() and 1138 * NdisMRegisterMiniport() routines. 1139 */ 1140 dummystr.nus_len = strlen(NDIS_DUMMY_PATH); 1141 dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH); 1142 dummystr.nus_buf = NULL; 1143 ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 1144 drv.ndo_ifname = "ndis0"; 1145 1146 status = entry(&drv, &dummystr); 1147 1148 free (dummystr.nus_buf, M_DEVBUF); 1149 1150 if (status != NDIS_STATUS_SUCCESS) 1151 return(ENODEV); 1152 1153 /* 1154 * Now that we have the miniport driver characteristics, 1155 * create an NDIS block and call the init handler. 1156 * This will cause the driver to try to probe for 1157 * a device. 1158 */ 1159 1160 block = &sc->ndis_block; 1161 bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars, 1162 sizeof(ndis_miniport_characteristics)); 1163 1164 /*block->nmb_signature = 0xcafebabe;*/ 1165 1166 ptr = (uint32_t *)block; 1167 for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 1168 *ptr = idx | 0xdead0000; 1169 ptr++; 1170 } 1171 1172 block->nmb_signature = (void *)0xcafebabe; 1173 block->nmb_setdone_func = ndis_setdone_func; 1174 block->nmb_querydone_func = ndis_getdone_func; 1175 block->nmb_status_func = ndis_status_func; 1176 block->nmb_statusdone_func = ndis_statusdone_func; 1177 block->nmb_resetdone_func = ndis_resetdone_func; 1178 block->nmb_sendrsrc_func = ndis_sendrsrcavail_func; 1179 1180 block->nmb_ifp = &sc->arpcom.ac_if; 1181 block->nmb_dev = sc->ndis_dev;
| 35 36#include <sys/param.h> 37#include <sys/types.h> 38#include <sys/errno.h> 39#include <sys/callout.h> 40#include <sys/socket.h> 41#include <sys/queue.h> 42#include <sys/sysctl.h> 43#include <sys/systm.h> 44#include <sys/malloc.h> 45#include <sys/lock.h> 46#include <sys/mutex.h> 47#include <sys/conf.h> 48#include <sys/taskqueue.h> 49 50#include <sys/kernel.h> 51#include <machine/bus.h> 52#include <machine/resource.h> 53#include <sys/bus.h> 54#include <sys/rman.h> 55 56#include <vm/uma.h> 57 58#include <net/if.h> 59#include <net/if_arp.h> 60#include <net/ethernet.h> 61#include <net/if_dl.h> 62#include <net/if_media.h> 63 64#include <net80211/ieee80211_var.h> 65#include <net80211/ieee80211_ioctl.h> 66 67#include <dev/pccard/pccardvar.h> 68#include "card_if.h" 69 70#include <compat/ndis/pe_var.h> 71#include <compat/ndis/resource_var.h> 72#include <compat/ndis/ndis_var.h> 73#include <compat/ndis/hal_var.h> 74#include <compat/ndis/ntoskrnl_var.h> 75#include <compat/ndis/cfg_var.h> 76#include <dev/if_ndis/if_ndisvar.h> 77 78#define __stdcall __attribute__((__stdcall__)) 79#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 80 81__stdcall static void ndis_status_func(ndis_handle, ndis_status, 82 void *, uint32_t); 83__stdcall static void ndis_statusdone_func(ndis_handle); 84__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); 85__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); 86__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 87__stdcall static void ndis_sendrsrcavail_func(ndis_handle); 88 89static uma_zone_t ndis_packet_zone, ndis_buffer_zone; 90 91/* 92 * This allows us to export our symbols to other modules. 93 * Note that we call ourselves 'ndisapi' to avoid a namespace 94 * collision with if_ndis.ko, which internally calls itself 95 * 'ndis.' 96 */ 97static int 98ndis_modevent(module_t mod, int cmd, void *arg) 99{ 100 int error = 0; 101 102 switch (cmd) { 103 case MOD_LOAD: 104 /* Initialize subsystems */ 105 ndis_libinit(); 106 ntoskrnl_libinit(); 107 108 /* Initialize TX buffer UMA zone. */ 109 ndis_packet_zone = uma_zcreate("NDIS packet", 110 sizeof(ndis_packet), NULL, NULL, NULL, 111 NULL, UMA_ALIGN_PTR, 0); 112 ndis_buffer_zone = uma_zcreate("NDIS buffer", 113 sizeof(ndis_buffer), NULL, NULL, NULL, 114 NULL, UMA_ALIGN_PTR, 0); 115 break; 116 case MOD_UNLOAD: 117 case MOD_SHUTDOWN: 118 /* Shut down subsystems */ 119 ndis_libfini(); 120 ntoskrnl_libfini(); 121 122 /* Remove zones */ 123 uma_zdestroy(ndis_packet_zone); 124 uma_zdestroy(ndis_buffer_zone); 125 break; 126 default: 127 error = EINVAL; 128 break; 129 } 130 131 return(error); 132} 133DEV_MODULE(ndisapi, ndis_modevent, NULL); 134MODULE_VERSION(ndisapi, 1); 135 136 137__stdcall static void 138ndis_sendrsrcavail_func(adapter) 139 ndis_handle adapter; 140{ 141 return; 142} 143 144__stdcall static void 145ndis_status_func(adapter, status, sbuf, slen) 146 ndis_handle adapter; 147 ndis_status status; 148 void *sbuf; 149 uint32_t slen; 150{ 151 ndis_miniport_block *block; 152 block = adapter; 153 154 device_printf (block->nmb_dev, "status: %x\n", status); 155 return; 156} 157 158__stdcall static void 159ndis_statusdone_func(adapter) 160 ndis_handle adapter; 161{ 162 ndis_miniport_block *block; 163 block = adapter; 164 165 device_printf (block->nmb_dev, "status complete\n"); 166 return; 167} 168 169__stdcall static void 170ndis_setdone_func(adapter, status) 171 ndis_handle adapter; 172 ndis_status status; 173{ 174 ndis_miniport_block *block; 175 block = adapter; 176 177 block->nmb_setstat = status; 178 wakeup(&block->nmb_wkupdpctimer); 179 return; 180} 181 182__stdcall static void 183ndis_getdone_func(adapter, status) 184 ndis_handle adapter; 185 ndis_status status; 186{ 187 ndis_miniport_block *block; 188 block = adapter; 189 190 block->nmb_getstat = status; 191 wakeup(&block->nmb_wkupdpctimer); 192 return; 193} 194 195__stdcall static void 196ndis_resetdone_func(adapter, status, addressingreset) 197 ndis_handle adapter; 198 ndis_status status; 199 uint8_t addressingreset; 200{ 201 ndis_miniport_block *block; 202 block = adapter; 203 204 device_printf (block->nmb_dev, "reset done...\n"); 205 return; 206} 207 208#define NDIS_AM_RID 3 209 210int 211ndis_alloc_amem(arg) 212 void *arg; 213{ 214 struct ndis_softc *sc; 215 int error, rid; 216 217 if (arg == NULL) 218 return(EINVAL); 219 220 sc = arg; 221 rid = NDIS_AM_RID; 222 sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, 223 &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); 224 225 if (sc->ndis_res_am == NULL) { 226 device_printf(sc->ndis_dev, 227 "failed to allocate attribute memory\n"); 228 return(ENXIO); 229 } 230 231 error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), 232 sc->ndis_dev, rid, 0, NULL); 233 234 if (error) { 235 device_printf(sc->ndis_dev, 236 "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error); 237 return(error); 238 } 239 240 error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), 241 sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 242 243 if (error) { 244 device_printf(sc->ndis_dev, 245 "CARD_SET_RES_FLAGS() returned 0x%x\n", error); 246 return(error); 247 } 248 249 return(0); 250} 251 252int 253ndis_create_sysctls(arg) 254 void *arg; 255{ 256 struct ndis_softc *sc; 257 ndis_cfg *vals; 258 char buf[256]; 259 260 if (arg == NULL) 261 return(EINVAL); 262 263 sc = arg; 264 vals = sc->ndis_regvals; 265 266 TAILQ_INIT(&sc->ndis_cfglist_head); 267 268 /* Create the sysctl tree. */ 269 270 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 271 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 272 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 273 device_get_desc(sc->ndis_dev)); 274 275 /* Add the driver-specific registry keys. */ 276 277 vals = sc->ndis_regvals; 278 while(1) { 279 if (vals->nc_cfgkey == NULL) 280 break; 281 if (vals->nc_idx != sc->ndis_devidx) { 282 vals++; 283 continue; 284 } 285 SYSCTL_ADD_STRING(&sc->ndis_ctx, 286 SYSCTL_CHILDREN(sc->ndis_tree), 287 OID_AUTO, vals->nc_cfgkey, 288 CTLFLAG_RW, vals->nc_val, 289 sizeof(vals->nc_val), 290 vals->nc_cfgdesc); 291 vals++; 292 } 293 294 /* Now add a couple of builtin keys. */ 295 296 /* 297 * Environment can be either Windows (0) or WindowsNT (1). 298 * We qualify as the latter. 299 */ 300 ndis_add_sysctl(sc, "Environment", 301 "Windows environment", "1", CTLFLAG_RD); 302 303 /* NDIS version should be 5.1. */ 304 ndis_add_sysctl(sc, "NdisVersion", 305 "NDIS API Version", "0x00050001", CTLFLAG_RD); 306 307 /* Bus type (PCI, PCMCIA, etc...) */ 308 sprintf(buf, "%d\n", (int)sc->ndis_iftype); 309 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 310 311 if (sc->ndis_res_io != NULL) { 312 sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io)); 313 ndis_add_sysctl(sc, "IOBaseAddress", 314 "Base I/O Address", buf, CTLFLAG_RD); 315 } 316 317 if (sc->ndis_irq != NULL) { 318 sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq)); 319 ndis_add_sysctl(sc, "InterruptNumber", 320 "Interrupt Number", buf, CTLFLAG_RD); 321 } 322 323 return(0); 324} 325 326int 327ndis_add_sysctl(arg, key, desc, val, flag) 328 void *arg; 329 char *key; 330 char *desc; 331 char *val; 332 int flag; 333{ 334 struct ndis_softc *sc; 335 struct ndis_cfglist *cfg; 336 char descstr[256]; 337 338 sc = arg; 339 340 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 341 342 if (cfg == NULL) 343 return(ENOMEM); 344 345 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 346 if (desc == NULL) { 347 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 348 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 349 } else 350 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 351 strcpy(cfg->ndis_cfg.nc_val, val); 352 353 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 354 355 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 356 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 357 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 358 cfg->ndis_cfg.nc_cfgdesc); 359 360 return(0); 361} 362 363int 364ndis_flush_sysctls(arg) 365 void *arg; 366{ 367 struct ndis_softc *sc; 368 struct ndis_cfglist *cfg; 369 370 sc = arg; 371 372 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 373 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 374 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 375 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 376 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 377 free(cfg, M_DEVBUF); 378 } 379 380 return(0); 381} 382 383void 384ndis_return_packet(buf, arg) 385 void *buf; /* not used */ 386 void *arg; 387{ 388 struct ndis_softc *sc; 389 ndis_handle adapter; 390 ndis_packet *p; 391 __stdcall ndis_return_handler returnfunc; 392 393 if (arg == NULL) 394 return; 395 396 p = arg; 397 398 /* Decrement refcount. */ 399 p->np_refcnt--; 400 401 /* Release packet when refcount hits zero, otherwise return. */ 402 if (p->np_refcnt) 403 return; 404 405 sc = p->np_softc; 406 returnfunc = sc->ndis_chars.nmc_return_packet_func; 407 adapter = sc->ndis_block.nmb_miniportadapterctx; 408 if (returnfunc != NULL) 409 returnfunc(adapter, p); 410 411 return; 412} 413 414void 415ndis_free_bufs(b0) 416 ndis_buffer *b0; 417{ 418 ndis_buffer *next; 419 420 if (b0 == NULL) 421 return; 422 423 while(b0 != NULL) { 424 next = b0->nb_next; 425 uma_zfree (ndis_buffer_zone, b0); 426 b0 = next; 427 } 428 429 return; 430} 431 432void 433ndis_free_packet(p) 434 ndis_packet *p; 435{ 436 if (p == NULL) 437 return; 438 439 ndis_free_bufs(p->np_private.npp_head); 440 uma_zfree(ndis_packet_zone, p); 441 442 return; 443} 444 445int 446ndis_convert_res(arg) 447 void *arg; 448{ 449 struct ndis_softc *sc; 450 ndis_resource_list *rl = NULL; 451 cm_partial_resource_desc *prd = NULL; 452 ndis_miniport_block *block; 453 device_t dev; 454 struct resource_list *brl; 455 struct resource_list_entry *brle; 456 457 sc = arg; 458 block = &sc->ndis_block; 459 dev = sc->ndis_dev; 460 461 rl = malloc(sizeof(ndis_resource_list) + 462 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 463 M_DEVBUF, M_NOWAIT|M_ZERO); 464 465 if (rl == NULL) 466 return(ENOMEM); 467 468 rl->cprl_version = 5; 469 rl->cprl_version = 1; 470 rl->cprl_count = sc->ndis_rescnt; 471 prd = rl->cprl_partial_descs; 472 473 brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 474 if (brl != NULL) { 475 SLIST_FOREACH(brle, brl, link) { 476 switch (brle->type) { 477 case SYS_RES_IOPORT: 478 prd->cprd_type = CmResourceTypePort; 479 prd->u.cprd_port.cprd_start.np_quad = 480 brle->start; 481 prd->u.cprd_port.cprd_len = brle->count; 482 break; 483 case SYS_RES_MEMORY: 484 prd->cprd_type = CmResourceTypeMemory; 485 prd->u.cprd_port.cprd_start.np_quad = 486 brle->start; 487 prd->u.cprd_port.cprd_len = brle->count; 488 break; 489 case SYS_RES_IRQ: 490 prd->cprd_type = CmResourceTypeInterrupt; 491 prd->u.cprd_intr.cprd_level = brle->start; 492 prd->u.cprd_intr.cprd_vector = brle->start; 493 prd->u.cprd_intr.cprd_affinity = 0; 494 break; 495 default: 496 break; 497 } 498 prd++; 499 } 500 } 501 502 block->nmb_rlist = rl; 503 504 return(0); 505} 506 507/* 508 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 509 * packet, it will hand it to us in the form of an ndis_packet, 510 * which we need to convert to an mbuf that is then handed off 511 * to the stack. Note: we configure the mbuf list so that it uses 512 * the memory regions specified by the ndis_buffer structures in 513 * the ndis_packet as external storage. In most cases, this will 514 * point to a memory region allocated by the driver (either by 515 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 516 * the driver to handle free()ing this region for is, so we set up 517 * a dummy no-op free handler for it. 518 */ 519 520int 521ndis_ptom(m0, p) 522 struct mbuf **m0; 523 ndis_packet *p; 524{ 525 struct mbuf *m, *prev = NULL; 526 ndis_buffer *buf; 527 ndis_packet_private *priv; 528 uint32_t totlen = 0; 529 530 if (p == NULL || m0 == NULL) 531 return(EINVAL); 532 533 priv = &p->np_private; 534 buf = priv->npp_head; 535 p->np_refcnt = 0; 536 537 for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) { 538 if (buf == priv->npp_head) 539 MGETHDR(m, M_DONTWAIT, MT_HEADER); 540 else 541 MGET(m, M_DONTWAIT, MT_DATA); 542 if (m == NULL) { 543 m_freem(*m0); 544 *m0 = NULL; 545 return(ENOBUFS); 546 } 547 m->m_len = buf->nb_bytecount; 548 m->m_data = MDL_VA(buf); 549 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 550 p, 0, EXT_NDIS); 551 p->np_refcnt++; 552 totlen += m->m_len; 553 if (m->m_flags & MT_HEADER) 554 *m0 = m; 555 else 556 prev->m_next = m; 557 prev = m; 558 } 559 560 (*m0)->m_pkthdr.len = totlen; 561 562 return(0); 563} 564 565/* 566 * Create an mbuf chain from an NDIS packet chain. 567 * This is used mainly when transmitting packets, where we need 568 * to turn an mbuf off an interface's send queue and transform it 569 * into an NDIS packet which will be fed into the NDIS driver's 570 * send routine. 571 * 572 * NDIS packets consist of two parts: an ndis_packet structure, 573 * which is vaguely analagous to the pkthdr portion of an mbuf, 574 * and one or more ndis_buffer structures, which define the 575 * actual memory segments in which the packet data resides. 576 * We need to allocate one ndis_buffer for each mbuf in a chain, 577 * plus one ndis_packet as the header. 578 */ 579 580int 581ndis_mtop(m0, p) 582 struct mbuf *m0; 583 ndis_packet **p; 584{ 585 struct mbuf *m; 586 ndis_buffer *buf = NULL, *prev = NULL; 587 ndis_packet_private *priv; 588 589 if (p == NULL || m0 == NULL) 590 return(EINVAL); 591 592 /* If caller didn't supply a packet, make one. */ 593 if (*p == NULL) { 594 *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO); 595 596 if (*p == NULL) 597 return(ENOMEM); 598 } 599 600 priv = &(*p)->np_private; 601 priv->npp_totlen = m0->m_pkthdr.len; 602 priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 603 604 for (m = m0; m != NULL; m = m->m_next) { 605 if (m->m_len == 0) 606 continue; 607 buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO); 608 if (buf == NULL) { 609 ndis_free_packet(*p); 610 *p = NULL; 611 return(ENOMEM); 612 } 613 614 MDL_INIT(buf, m->m_data, m->m_len); 615 if (priv->npp_head == NULL) 616 priv->npp_head = buf; 617 else 618 prev->nb_next = buf; 619 prev = buf; 620 } 621 622 priv->npp_tail = buf; 623 priv->npp_totlen = m0->m_pkthdr.len; 624 625 return(0); 626} 627 628int 629ndis_get_supported_oids(arg, oids, oidcnt) 630 void *arg; 631 ndis_oid **oids; 632 int *oidcnt; 633{ 634 int len, rval; 635 ndis_oid *o; 636 637 if (arg == NULL || oids == NULL || oidcnt == NULL) 638 return(EINVAL); 639 len = 0; 640 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 641 642 o = malloc(len, M_DEVBUF, M_NOWAIT); 643 if (o == NULL) 644 return(ENOMEM); 645 646 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 647 648 if (rval) { 649 free(o, M_DEVBUF); 650 return(rval); 651 } 652 653 *oids = o; 654 *oidcnt = len / 4; 655 656 return(0); 657} 658 659int 660ndis_set_info(arg, oid, buf, buflen) 661 void *arg; 662 ndis_oid oid; 663 void *buf; 664 int *buflen; 665{ 666 struct ndis_softc *sc; 667 ndis_status rval; 668 ndis_handle adapter; 669 __stdcall ndis_setinfo_handler setfunc; 670 uint32_t byteswritten = 0, bytesneeded = 0; 671 struct timeval tv; 672 int error; 673 674 sc = arg; 675 setfunc = sc->ndis_chars.nmc_setinfo_func; 676 adapter = sc->ndis_block.nmb_miniportadapterctx; 677 678 rval = setfunc(adapter, oid, buf, *buflen, 679 &byteswritten, &bytesneeded); 680 681 if (rval == NDIS_STATUS_PENDING) { 682 tv.tv_sec = 60; 683 tv.tv_usec = 0; 684 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 685 PPAUSE|PCATCH, "ndisset", tvtohz(&tv)); 686 rval = sc->ndis_block.nmb_setstat; 687 } 688 689 if (byteswritten) 690 *buflen = byteswritten; 691 if (bytesneeded) 692 *buflen = bytesneeded; 693 694 if (rval == NDIS_STATUS_INVALID_LENGTH) 695 return(ENOSPC); 696 697 if (rval == NDIS_STATUS_INVALID_OID) 698 return(EINVAL); 699 700 if (rval == NDIS_STATUS_NOT_SUPPORTED || 701 rval == NDIS_STATUS_NOT_ACCEPTED) 702 return(ENOTSUP); 703 704 return(0); 705} 706 707int 708ndis_send_packets(arg, packets, cnt) 709 void *arg; 710 ndis_packet **packets; 711 int cnt; 712{ 713 struct ndis_softc *sc; 714 ndis_handle adapter; 715 __stdcall ndis_sendmulti_handler sendfunc; 716 int i, idx; 717 struct ifnet *ifp; 718 struct mbuf *m; 719 ndis_packet *p; 720 721 sc = arg; 722 adapter = sc->ndis_block.nmb_miniportadapterctx; 723 sendfunc = sc->ndis_chars.nmc_sendmulti_func; 724 sendfunc(adapter, packets, cnt); 725 726 for (i = 0; i < cnt; i++) { 727 p = packets[i]; 728 /* 729 * Either the driver already handed the packet to 730 * ndis_txeof() due to a failure, or it wants to keep 731 * it and release it asynchronously later. Skip to the 732 * next one. 733 */ 734 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 735 continue; 736 idx = p->np_txidx; 737 m = p->np_m0; 738 ifp = &sc->arpcom.ac_if; 739 if (sc->ndis_sc) 740 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]); 741 sc->ndis_txarray[idx] = NULL; 742 sc->ndis_txpending++; 743 m_freem(m); 744 ndis_free_packet(p); 745 if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) 746 ifp->if_opackets++; 747 else 748 ifp->if_oerrors++; 749 ifp->if_timer = 0; 750 ifp->if_flags &= ~IFF_OACTIVE; 751 } 752 753 return(0); 754} 755 756int 757ndis_init_dma(arg) 758 void *arg; 759{ 760 struct ndis_softc *sc; 761 int i, error; 762 763 sc = arg; 764 765 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 766 M_DEVBUF, M_NOWAIT|M_ZERO); 767 768 if (sc->ndis_tmaps == NULL) 769 return(ENOMEM); 770 771 for (i = 0; i < sc->ndis_maxpkts; i++) { 772 error = bus_dmamap_create(sc->ndis_ttag, 0, 773 &sc->ndis_tmaps[i]); 774 if (error) { 775 free(sc->ndis_tmaps, M_DEVBUF); 776 return(ENODEV); 777 } 778 } 779 780 return(0); 781} 782 783int 784ndis_destroy_dma(arg) 785 void *arg; 786{ 787 struct ndis_softc *sc; 788 struct mbuf *m; 789 ndis_packet *p = NULL; 790 int i; 791 792 sc = arg; 793 794 for (i = 0; i < sc->ndis_maxpkts; i++) { 795 if (sc->ndis_txarray[i] != NULL) { 796 p = sc->ndis_txarray[i]; 797 m = (struct mbuf *)p->np_rsvd[1]; 798 if (m != NULL) 799 m_freem(m); 800 ndis_free_packet(sc->ndis_txarray[i]); 801 } 802 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 803 } 804 805 free(sc->ndis_tmaps, M_DEVBUF); 806 807 bus_dma_tag_destroy(sc->ndis_ttag); 808 809 return(0); 810} 811 812int 813ndis_reset_nic(arg) 814 void *arg; 815{ 816 struct ndis_softc *sc; 817 ndis_handle adapter; 818 __stdcall ndis_reset_handler resetfunc; 819 uint8_t addressing_reset; 820 struct ifnet *ifp; 821 822 sc = arg; 823 ifp = &sc->arpcom.ac_if; 824 adapter = sc->ndis_block.nmb_miniportadapterctx; 825 if (adapter == NULL) 826 return(EIO); 827 resetfunc = sc->ndis_chars.nmc_reset_func; 828 829 if (resetfunc == NULL) 830 return(EINVAL); 831 832 resetfunc(&addressing_reset, adapter); 833 834 return(0); 835} 836 837int 838ndis_halt_nic(arg) 839 void *arg; 840{ 841 struct ndis_softc *sc; 842 ndis_handle adapter; 843 __stdcall ndis_halt_handler haltfunc; 844 struct ifnet *ifp; 845 struct ndis_timer_entry *ne; 846 847 sc = arg; 848 ifp = &sc->arpcom.ac_if; 849 adapter = sc->ndis_block.nmb_miniportadapterctx; 850 if (adapter == NULL) 851 return(EIO); 852 853 haltfunc = sc->ndis_chars.nmc_halt_func; 854 855 if (haltfunc == NULL) 856 return(EINVAL); 857 858 haltfunc(adapter); 859 860 /* 861 * The adapter context is only valid after the init 862 * handler has been called, and is invalid once the 863 * halt handler has been called. 864 */ 865 866 sc->ndis_block.nmb_miniportadapterctx = NULL; 867 868 /* Clobber all the timers in case the driver left one running. */ 869 870 while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) { 871 ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist); 872 TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link); 873 callout_stop(&ne->nte_ch); 874 free(ne, M_DEVBUF); 875 } 876 877 return(0); 878} 879 880int 881ndis_shutdown_nic(arg) 882 void *arg; 883{ 884 struct ndis_softc *sc; 885 ndis_handle adapter; 886 __stdcall ndis_shutdown_handler shutdownfunc; 887 888 889 sc = arg; 890 adapter = sc->ndis_block.nmb_miniportadapterctx; 891 if (adapter == NULL) 892 return(EIO); 893 shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 894 895 if (shutdownfunc == NULL) 896 return(EINVAL); 897 898 if (sc->ndis_chars.nmc_rsvd0 == NULL) 899 shutdownfunc(adapter); 900 else 901 shutdownfunc(sc->ndis_chars.nmc_rsvd0); 902 903 return(0); 904} 905 906int 907ndis_init_nic(arg) 908 void *arg; 909{ 910 struct ndis_softc *sc; 911 ndis_miniport_block *block; 912 __stdcall ndis_init_handler initfunc; 913 ndis_status status, openstatus = 0; 914 ndis_medium mediumarray[NdisMediumMax]; 915 uint32_t chosenmedium, i; 916 917 if (arg == NULL) 918 return(EINVAL); 919 920 sc = arg; 921 block = &sc->ndis_block; 922 initfunc = sc->ndis_chars.nmc_init_func; 923 924 TAILQ_INIT(&block->nmb_timerlist); 925 926 for (i = 0; i < NdisMediumMax; i++) 927 mediumarray[i] = i; 928 929 status = initfunc(&openstatus, &chosenmedium, 930 mediumarray, NdisMediumMax, block, block); 931 932 /* 933 * If the init fails, blow away the other exported routines 934 * we obtained from the driver so we can't call them later. 935 * If the init failed, none of these will work. 936 */ 937 if (status != NDIS_STATUS_SUCCESS) { 938 bzero((char *)&sc->ndis_chars, 939 sizeof(ndis_miniport_characteristics)); 940 return(ENXIO); 941 } 942 943 return(0); 944} 945 946void 947ndis_enable_intr(arg) 948 void *arg; 949{ 950 struct ndis_softc *sc; 951 ndis_handle adapter; 952 __stdcall ndis_enable_interrupts_handler intrenbfunc; 953 954 sc = arg; 955 adapter = sc->ndis_block.nmb_miniportadapterctx; 956 if (adapter == NULL) 957 return; 958 intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 959 if (intrenbfunc == NULL) 960 return; 961 intrenbfunc(adapter); 962 963 return; 964} 965 966void 967ndis_disable_intr(arg) 968 void *arg; 969{ 970 struct ndis_softc *sc; 971 ndis_handle adapter; 972 __stdcall ndis_disable_interrupts_handler intrdisfunc; 973 974 sc = arg; 975 adapter = sc->ndis_block.nmb_miniportadapterctx; 976 if (adapter == NULL) 977 return; 978 intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 979 if (intrdisfunc == NULL) 980 return; 981 intrdisfunc(adapter); 982 983 return; 984} 985 986int 987ndis_isr(arg, ourintr, callhandler) 988 void *arg; 989 int *ourintr; 990 int *callhandler; 991{ 992 struct ndis_softc *sc; 993 ndis_handle adapter; 994 __stdcall ndis_isr_handler isrfunc; 995 uint8_t accepted, queue; 996 997 if (arg == NULL || ourintr == NULL || callhandler == NULL) 998 return(EINVAL); 999 1000 sc = arg; 1001 adapter = sc->ndis_block.nmb_miniportadapterctx; 1002 isrfunc = sc->ndis_chars.nmc_isr_func; 1003 isrfunc(&accepted, &queue, adapter); 1004 *ourintr = accepted; 1005 *callhandler = queue; 1006 1007 return(0); 1008} 1009 1010int 1011ndis_intrhand(arg) 1012 void *arg; 1013{ 1014 struct ndis_softc *sc; 1015 ndis_handle adapter; 1016 __stdcall ndis_interrupt_handler intrfunc; 1017 1018 if (arg == NULL) 1019 return(EINVAL); 1020 1021 sc = arg; 1022 adapter = sc->ndis_block.nmb_miniportadapterctx; 1023 intrfunc = sc->ndis_chars.nmc_interrupt_func; 1024 intrfunc(adapter); 1025 1026 return(0); 1027} 1028 1029int 1030ndis_get_info(arg, oid, buf, buflen) 1031 void *arg; 1032 ndis_oid oid; 1033 void *buf; 1034 int *buflen; 1035{ 1036 struct ndis_softc *sc; 1037 ndis_status rval; 1038 ndis_handle adapter; 1039 __stdcall ndis_queryinfo_handler queryfunc; 1040 uint32_t byteswritten = 0, bytesneeded = 0; 1041 struct timeval tv; 1042 int error; 1043 1044 sc = arg; 1045 queryfunc = sc->ndis_chars.nmc_queryinfo_func; 1046 adapter = sc->ndis_block.nmb_miniportadapterctx; 1047 1048 rval = queryfunc(adapter, oid, buf, *buflen, 1049 &byteswritten, &bytesneeded); 1050 1051 /* Wait for requests that block. */ 1052 1053 if (rval == NDIS_STATUS_PENDING) { 1054 tv.tv_sec = 60; 1055 tv.tv_usec = 0; 1056 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 1057 PPAUSE|PCATCH, "ndisget", tvtohz(&tv)); 1058 rval = sc->ndis_block.nmb_getstat; 1059 } 1060 1061 if (byteswritten) 1062 *buflen = byteswritten; 1063 if (bytesneeded) 1064 *buflen = bytesneeded; 1065 1066 if (rval == NDIS_STATUS_INVALID_LENGTH || 1067 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1068 return(ENOSPC); 1069 1070 if (rval == NDIS_STATUS_INVALID_OID) 1071 return(EINVAL); 1072 1073 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1074 rval == NDIS_STATUS_NOT_ACCEPTED) 1075 return(ENOTSUP); 1076 1077 return(0); 1078} 1079 1080int 1081ndis_unload_driver(arg) 1082 void *arg; 1083{ 1084 struct ndis_softc *sc; 1085 1086 sc = arg; 1087 1088 free(sc->ndis_block.nmb_rlist, M_DEVBUF); 1089 1090 ndis_flush_sysctls(sc); 1091 1092 return(0); 1093} 1094 1095int 1096ndis_load_driver(img, arg) 1097 vm_offset_t img; 1098 void *arg; 1099{ 1100 __stdcall driver_entry entry; 1101 image_optional_header opt_hdr; 1102 image_import_descriptor imp_desc; 1103 ndis_unicode_string dummystr; 1104 ndis_driver_object drv; 1105 ndis_miniport_block *block; 1106 ndis_status status; 1107 int idx; 1108 uint32_t *ptr; 1109 struct ndis_softc *sc; 1110 1111 sc = arg; 1112 1113 /* Perform text relocation */ 1114 if (pe_relocate(img)) 1115 return(ENOEXEC); 1116 1117 /* Dynamically link the NDIS.SYS routines -- required. */ 1118 if (pe_patch_imports(img, "NDIS", ndis_functbl)) 1119 return(ENOEXEC); 1120 1121 /* Dynamically link the HAL.dll routines -- also required. */ 1122 if (pe_patch_imports(img, "HAL", hal_functbl)) 1123 return(ENOEXEC); 1124 1125 /* Dynamically link ntoskrnl.exe -- optional. */ 1126 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) { 1127 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl)) 1128 return(ENOEXEC); 1129 } 1130 1131 /* Locate the driver entry point */ 1132 pe_get_optional_header(img, &opt_hdr); 1133 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 1134 1135 /* 1136 * Now call the DriverEntry() routine. This will cause 1137 * a callout to the NdisInitializeWrapper() and 1138 * NdisMRegisterMiniport() routines. 1139 */ 1140 dummystr.nus_len = strlen(NDIS_DUMMY_PATH); 1141 dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH); 1142 dummystr.nus_buf = NULL; 1143 ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 1144 drv.ndo_ifname = "ndis0"; 1145 1146 status = entry(&drv, &dummystr); 1147 1148 free (dummystr.nus_buf, M_DEVBUF); 1149 1150 if (status != NDIS_STATUS_SUCCESS) 1151 return(ENODEV); 1152 1153 /* 1154 * Now that we have the miniport driver characteristics, 1155 * create an NDIS block and call the init handler. 1156 * This will cause the driver to try to probe for 1157 * a device. 1158 */ 1159 1160 block = &sc->ndis_block; 1161 bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars, 1162 sizeof(ndis_miniport_characteristics)); 1163 1164 /*block->nmb_signature = 0xcafebabe;*/ 1165 1166 ptr = (uint32_t *)block; 1167 for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 1168 *ptr = idx | 0xdead0000; 1169 ptr++; 1170 } 1171 1172 block->nmb_signature = (void *)0xcafebabe; 1173 block->nmb_setdone_func = ndis_setdone_func; 1174 block->nmb_querydone_func = ndis_getdone_func; 1175 block->nmb_status_func = ndis_status_func; 1176 block->nmb_statusdone_func = ndis_statusdone_func; 1177 block->nmb_resetdone_func = ndis_resetdone_func; 1178 block->nmb_sendrsrc_func = ndis_sendrsrcavail_func; 1179 1180 block->nmb_ifp = &sc->arpcom.ac_if; 1181 block->nmb_dev = sc->ndis_dev;
|