]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/if_ndis/if_ndis.c
This commit was generated by cvs2svn to compensate for changes in r146309,
[FreeBSD/FreeBSD.git] / sys / dev / if_ndis / if_ndis.c
1 /*-
2  * Copyright (c) 2003
3  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * WPA support added by Arvind Srinivasan <arvind@celar.us>
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include "opt_bdg.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/sockio.h>
43 #include <sys/mbuf.h>
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46 #include <sys/socket.h>
47 #include <sys/queue.h>
48 #include <sys/module.h>
49 #include <sys/proc.h>
50 #if __FreeBSD_version < 502113
51 #include <sys/sysctl.h>
52 #endif
53
54 #include <net/if.h>
55 #include <net/if_arp.h>
56 #include <net/ethernet.h>
57 #include <net/if_dl.h>
58 #include <net/if_media.h>
59 #include <net/route.h>
60
61 #include <net/bpf.h>
62
63 #include <machine/bus_memio.h>
64 #include <machine/bus_pio.h>
65 #include <machine/bus.h>
66 #include <machine/resource.h>
67 #include <sys/bus.h>
68 #include <sys/rman.h>
69
70 #include <net80211/ieee80211_var.h>
71 #include <net80211/ieee80211_ioctl.h>
72
73 #include <dev/wi/if_wavelan_ieee.h>
74
75 #include <dev/pci/pcireg.h>
76 #include <dev/pci/pcivar.h>
77
78 #include <compat/ndis/pe_var.h>
79 #include <compat/ndis/cfg_var.h>
80 #include <compat/ndis/resource_var.h>
81 #include <compat/ndis/ntoskrnl_var.h>
82 #include <compat/ndis/hal_var.h>
83 #include <compat/ndis/ndis_var.h>
84 #include <dev/if_ndis/if_ndisvar.h>
85
86 MODULE_DEPEND(ndis, ether, 1, 1, 1);
87 MODULE_DEPEND(ndis, wlan, 1, 1, 1);
88 MODULE_DEPEND(ndis, ndisapi, 1, 1, 1);
89
90 MODULE_VERSION(ndis, 1);
91
92 int ndis_attach                 (device_t);
93 int ndis_detach                 (device_t);
94 int ndis_suspend                (device_t);
95 int ndis_resume                 (device_t);
96 void ndis_shutdown              (device_t);
97
98 int ndisdrv_modevent            (module_t, int, void *);
99
100 static void ndis_txeof          (ndis_handle, ndis_packet *, ndis_status);
101 static void ndis_rxeof          (ndis_handle, ndis_packet **, uint32_t);
102 static void ndis_rxeof_eth      (ndis_handle, ndis_handle, char *, void *,
103                                  uint32_t, void *, uint32_t, uint32_t);
104 static void ndis_rxeof_done     (ndis_handle);
105 static void ndis_rxeof_xfr      (kdpc *, ndis_handle, void *, void *);
106 static void ndis_rxeof_xfr_done (ndis_handle, ndis_packet *,
107                                  uint32_t, uint32_t);
108 static void ndis_linksts        (ndis_handle, ndis_status, void *, uint32_t);
109 static void ndis_linksts_done   (ndis_handle);
110
111 /* We need to wrap these functions for amd64. */
112
113 static funcptr ndis_txeof_wrap;
114 static funcptr ndis_rxeof_wrap;
115 static funcptr ndis_rxeof_eth_wrap;
116 static funcptr ndis_rxeof_done_wrap;
117 static funcptr ndis_rxeof_xfr_wrap;
118 static funcptr ndis_rxeof_xfr_done_wrap;
119 static funcptr ndis_linksts_wrap;
120 static funcptr ndis_linksts_done_wrap;
121 static funcptr ndis_ticktask_wrap;
122 static funcptr ndis_starttask_wrap;
123 static funcptr ndis_resettask_wrap;
124
125 static void ndis_intr           (void *);
126 static void ndis_tick           (void *);
127 static void ndis_ticktask       (ndis_work_item *, void *);
128 static void ndis_start          (struct ifnet *);
129 static void ndis_starttask      (ndis_work_item *, void *);
130 static void ndis_resettask      (ndis_work_item *, void *);
131 static int ndis_ioctl           (struct ifnet *, u_long, caddr_t);
132 static int ndis_wi_ioctl_get    (struct ifnet *, u_long, caddr_t);
133 static int ndis_wi_ioctl_set    (struct ifnet *, u_long, caddr_t);
134 static int ndis_80211_ioctl_get (struct ifnet *, u_long, caddr_t);
135 static int ndis_80211_ioctl_set (struct ifnet *, u_long, caddr_t);
136 static void ndis_init           (void *);
137 static void ndis_stop           (struct ndis_softc *);
138 static void ndis_watchdog       (struct ifnet *);
139 static int ndis_ifmedia_upd     (struct ifnet *);
140 static void ndis_ifmedia_sts    (struct ifnet *, struct ifmediareq *);
141 static int ndis_get_assoc       (struct ndis_softc *, ndis_wlan_bssid_ex **);
142 static int ndis_probe_offload   (struct ndis_softc *);
143 static int ndis_set_offload     (struct ndis_softc *);
144 static void ndis_getstate_80211 (struct ndis_softc *);
145 static void ndis_setstate_80211 (struct ndis_softc *);
146 static int ndis_add_key         (struct ndis_softc *,
147         struct ieee80211req_key *, int16_t);
148 static void ndis_media_status   (struct ifnet *, struct ifmediareq *);
149
150 static void ndis_setmulti       (struct ndis_softc *);
151 static void ndis_map_sclist     (void *, bus_dma_segment_t *,
152         int, bus_size_t, int);
153
154 static int ndisdrv_loaded = 0;
155
156 /*
157  * This routine should call windrv_load() once for each driver
158  * image. This will do the relocation and dynalinking for the
159  * image, and create a Windows driver object which will be
160  * saved in our driver database.
161  */
162
163 int
164 ndisdrv_modevent(mod, cmd, arg)
165         module_t                mod;
166         int                     cmd;
167         void                    *arg;
168 {
169         int                     error = 0;
170
171         switch (cmd) {
172         case MOD_LOAD:
173                 ndisdrv_loaded++;
174                 if (ndisdrv_loaded > 1)
175                         break;
176                 windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap,
177                     3, WINDRV_WRAP_STDCALL);
178                 windrv_wrap((funcptr)ndis_rxeof_eth, &ndis_rxeof_eth_wrap,
179                     8, WINDRV_WRAP_STDCALL);
180                 windrv_wrap((funcptr)ndis_rxeof_done, &ndis_rxeof_done_wrap,
181                     1, WINDRV_WRAP_STDCALL);
182                 windrv_wrap((funcptr)ndis_rxeof_xfr, &ndis_rxeof_xfr_wrap,
183                     4, WINDRV_WRAP_STDCALL);
184                 windrv_wrap((funcptr)ndis_rxeof_xfr_done,
185                     &ndis_rxeof_xfr_done_wrap, 4, WINDRV_WRAP_STDCALL);
186                 windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap,
187                     3, WINDRV_WRAP_STDCALL);
188                 windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap,
189                     4, WINDRV_WRAP_STDCALL);
190                 windrv_wrap((funcptr)ndis_linksts_done,
191                     &ndis_linksts_done_wrap, 1, WINDRV_WRAP_STDCALL);
192                 windrv_wrap((funcptr)ndis_ticktask, &ndis_ticktask_wrap,
193                     2, WINDRV_WRAP_STDCALL);
194                 windrv_wrap((funcptr)ndis_starttask, &ndis_starttask_wrap,
195                     2, WINDRV_WRAP_STDCALL);
196                 windrv_wrap((funcptr)ndis_resettask, &ndis_resettask_wrap,
197                     2, WINDRV_WRAP_STDCALL);
198                 break;
199         case MOD_UNLOAD:
200                 ndisdrv_loaded--;
201                 if (ndisdrv_loaded > 0)
202                         break;
203                 /* fallthrough */
204         case MOD_SHUTDOWN:
205                 windrv_unwrap(ndis_rxeof_wrap);
206                 windrv_unwrap(ndis_rxeof_eth_wrap);
207                 windrv_unwrap(ndis_rxeof_done_wrap);
208                 windrv_unwrap(ndis_rxeof_xfr_wrap);
209                 windrv_unwrap(ndis_rxeof_xfr_done_wrap);
210                 windrv_unwrap(ndis_txeof_wrap);
211                 windrv_unwrap(ndis_linksts_wrap);
212                 windrv_unwrap(ndis_linksts_done_wrap);
213                 windrv_unwrap(ndis_ticktask_wrap);
214                 windrv_unwrap(ndis_starttask_wrap);
215                 windrv_unwrap(ndis_resettask_wrap);
216                 break;
217         default:
218                 error = EINVAL;
219                 break;
220         }
221
222         return (error);
223 }
224
225 /*
226  * Program the 64-bit multicast hash filter.
227  */
228 static void
229 ndis_setmulti(sc)
230         struct ndis_softc       *sc;
231 {
232         struct ifnet            *ifp;
233         struct ifmultiaddr      *ifma;
234         int                     len, mclistsz, error;
235         uint8_t                 *mclist;
236
237         ifp = &sc->arpcom.ac_if;
238
239         if (!NDIS_INITIALIZED(sc))
240                 return;
241
242         if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
243                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
244                 len = sizeof(sc->ndis_filter);
245                 error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
246                     &sc->ndis_filter, &len);
247                 if (error)
248                         device_printf (sc->ndis_dev,
249                             "set filter failed: %d\n", error);
250                 return;
251         }
252
253         if (TAILQ_EMPTY(&ifp->if_multiaddrs))
254                 return;
255
256         len = sizeof(mclistsz);
257         ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len);
258
259         mclist = malloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_NOWAIT|M_ZERO);
260
261         if (mclist == NULL) {
262                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
263                 goto out;
264         }
265
266         sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST;
267
268         len = 0;
269         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
270                 if (ifma->ifma_addr->sa_family != AF_LINK)
271                         continue;
272                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
273                     mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN);
274                 len++;
275                 if (len > mclistsz) {
276                         sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
277                         sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
278                         goto out;
279                 }
280         }
281
282         len = len * ETHER_ADDR_LEN;
283         error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len);
284         if (error) {
285                 device_printf (sc->ndis_dev, "set mclist failed: %d\n", error);
286                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
287                 sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
288         }
289
290 out:
291         free(mclist, M_TEMP);
292
293         len = sizeof(sc->ndis_filter);
294         error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
295             &sc->ndis_filter, &len);
296         if (error)
297                 device_printf (sc->ndis_dev, "set filter failed: %d\n", error);
298
299         return;
300 }
301
302 static int
303 ndis_set_offload(sc)
304         struct ndis_softc       *sc;
305 {
306         ndis_task_offload       *nto;
307         ndis_task_offload_hdr   *ntoh;
308         ndis_task_tcpip_csum    *nttc;
309         struct ifnet            *ifp;
310         int                     len, error;
311
312         ifp = &sc->arpcom.ac_if;
313
314         if (!NDIS_INITIALIZED(sc))
315                 return(EINVAL);
316
317         /* See if there's anything to set. */
318
319         error = ndis_probe_offload(sc);
320         if (error)
321                 return(error);
322                 
323         if (sc->ndis_hwassist == 0 && ifp->if_capabilities == 0)
324                 return(0);
325
326         len = sizeof(ndis_task_offload_hdr) + sizeof(ndis_task_offload) +
327             sizeof(ndis_task_tcpip_csum);
328
329         ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
330
331         if (ntoh == NULL)
332                 return(ENOMEM);
333
334         ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
335         ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
336         ntoh->ntoh_offset_firsttask = sizeof(ndis_task_offload_hdr);
337         ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
338         ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
339         ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
340
341         nto = (ndis_task_offload *)((char *)ntoh +
342             ntoh->ntoh_offset_firsttask);
343
344         nto->nto_vers = NDIS_TASK_OFFLOAD_VERSION;
345         nto->nto_len = sizeof(ndis_task_offload);
346         nto->nto_task = NDIS_TASK_TCPIP_CSUM;
347         nto->nto_offset_nexttask = 0;
348         nto->nto_taskbuflen = sizeof(ndis_task_tcpip_csum);
349
350         nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
351
352         if (ifp->if_capenable & IFCAP_TXCSUM)
353                 nttc->nttc_v4tx = sc->ndis_v4tx;
354
355         if (ifp->if_capenable & IFCAP_RXCSUM)
356                 nttc->nttc_v4rx = sc->ndis_v4rx;
357
358         error = ndis_set_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
359         free(ntoh, M_TEMP);
360
361         return(error);
362 }
363
364 static int
365 ndis_probe_offload(sc)
366         struct ndis_softc       *sc;
367 {
368         ndis_task_offload       *nto;
369         ndis_task_offload_hdr   *ntoh;
370         ndis_task_tcpip_csum    *nttc = NULL;
371         struct ifnet            *ifp;
372         int                     len, error, dummy;
373
374         ifp = &sc->arpcom.ac_if;
375
376         len = sizeof(dummy);
377         error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, &dummy, &len);
378
379         if (error != ENOSPC)
380                 return(error);
381
382         ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
383
384         if (ntoh == NULL)
385                 return(ENOMEM);
386
387         ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
388         ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
389         ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
390         ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
391         ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
392
393         error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
394
395         if (error) {
396                 free(ntoh, M_TEMP);
397                 return(error);
398         }
399
400         if (ntoh->ntoh_vers != NDIS_TASK_OFFLOAD_VERSION) {
401                 free(ntoh, M_TEMP);
402                 return(EINVAL);
403         }
404
405         nto = (ndis_task_offload *)((char *)ntoh +
406             ntoh->ntoh_offset_firsttask);
407
408         while (1) {
409                 switch (nto->nto_task) {
410                 case NDIS_TASK_TCPIP_CSUM:
411                         nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
412                         break;
413                 /* Don't handle these yet. */
414                 case NDIS_TASK_IPSEC:
415                 case NDIS_TASK_TCP_LARGESEND:
416                 default:
417                         break;
418                 }
419                 if (nto->nto_offset_nexttask == 0)
420                         break;
421                 nto = (ndis_task_offload *)((char *)nto +
422                     nto->nto_offset_nexttask);
423         }
424
425         if (nttc == NULL) {
426                 free(ntoh, M_TEMP);
427                 return(ENOENT);
428         }
429
430         sc->ndis_v4tx = nttc->nttc_v4tx;
431         sc->ndis_v4rx = nttc->nttc_v4rx;
432
433         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_IP_CSUM)
434                 sc->ndis_hwassist |= CSUM_IP;
435         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
436                 sc->ndis_hwassist |= CSUM_TCP;
437         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
438                 sc->ndis_hwassist |= CSUM_UDP;
439
440         if (sc->ndis_hwassist)
441                 ifp->if_capabilities |= IFCAP_TXCSUM;
442
443         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_IP_CSUM)
444                 ifp->if_capabilities |= IFCAP_RXCSUM;
445         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
446                 ifp->if_capabilities |= IFCAP_RXCSUM;
447         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
448                 ifp->if_capabilities |= IFCAP_RXCSUM;
449
450         free(ntoh, M_TEMP);
451         return(0);
452 }
453
454 /*
455  * Attach the interface. Allocate softc structures, do ifmedia
456  * setup and ethernet/BPF attach.
457  */
458 int
459 ndis_attach(dev)
460         device_t                dev;
461 {
462         u_char                  eaddr[ETHER_ADDR_LEN];
463         struct ndis_softc       *sc;
464         driver_object           *pdrv;
465         device_object           *pdo;
466         struct ifnet            *ifp = NULL;
467         int                     error = 0, len;
468         int                     i;
469
470         sc = device_get_softc(dev);
471
472         mtx_init(&sc->ndis_mtx, "ndis softc lock",
473             MTX_NETWORK_LOCK, MTX_DEF);
474
475         /*
476          * Hook interrupt early, since calling the driver's
477          * init routine may trigger an interrupt. Note that
478          * we don't need to do any explicit interrupt setup
479          * for USB.
480          */
481
482         if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) {
483                 error = bus_setup_intr(dev, sc->ndis_irq,
484                     INTR_TYPE_NET | INTR_MPSAFE,
485                     ndis_intr, sc, &sc->ndis_intrhand);
486
487                 if (error) {
488                         device_printf(dev, "couldn't set up irq\n");
489                         goto fail;
490                 }
491         }
492
493         if (sc->ndis_iftype == PCMCIABus) {
494                 error = ndis_alloc_amem(sc);
495                 if (error) {
496                         device_printf(dev, "failed to allocate "
497                             "attribute memory\n");
498                         goto fail;
499                 }
500         }
501
502 #if __FreeBSD_version < 502113
503         sysctl_ctx_init(&sc->ndis_ctx);
504 #endif
505
506         /* Create sysctl registry nodes */
507         ndis_create_sysctls(sc);
508
509         /* Find the PDO for this device instance. */
510
511         if (sc->ndis_iftype == PCIBus)
512                 pdrv = windrv_lookup(0, "PCI Bus");
513         else if (sc->ndis_iftype == PCMCIABus)
514                 pdrv = windrv_lookup(0, "PCCARD Bus");
515         else
516                 pdrv = windrv_lookup(0, "USB Bus");
517         pdo = windrv_find_pdo(pdrv, dev);
518
519         /*
520          * Create a new functional device object for this
521          * device. This is what creates the miniport block
522          * for this device instance.
523          */
524
525         if (NdisAddDevice(sc->ndis_dobj, pdo) != STATUS_SUCCESS) {
526                 device_printf(dev, "failed to create FDO!\n");
527                 error = ENXIO;
528                 goto fail;
529         }
530
531         /* Tell the user what version of the API the driver is using. */
532         device_printf(dev, "NDIS API version: %d.%d\n",
533             sc->ndis_chars->nmc_version_major,
534             sc->ndis_chars->nmc_version_minor);
535
536         /* Do resource conversion. */
537         if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus)
538                 ndis_convert_res(sc);
539         else
540                 sc->ndis_block->nmb_rlist = NULL;
541
542         /* Install our RX and TX interrupt handlers. */
543         sc->ndis_block->nmb_senddone_func = ndis_txeof_wrap;
544         sc->ndis_block->nmb_pktind_func = ndis_rxeof_wrap;
545         sc->ndis_block->nmb_ethrxindicate_func = ndis_rxeof_eth_wrap;
546         sc->ndis_block->nmb_ethrxdone_func = ndis_rxeof_done_wrap;
547         sc->ndis_block->nmb_tdcond_func = ndis_rxeof_xfr_done_wrap;
548
549         /* Call driver's init routine. */
550         if (ndis_init_nic(sc)) {
551                 device_printf (dev, "init handler failed\n");
552                 error = ENXIO;
553                 goto fail;
554         }
555
556         /*
557          * Get station address from the driver.
558          */
559         len = sizeof(eaddr);
560         ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len);
561
562         bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
563
564         /*
565          * Figure out if we're allowed to use multipacket sends
566          * with this driver, and if so, how many.
567          */
568
569         if (sc->ndis_chars->nmc_sendsingle_func &&
570             sc->ndis_chars->nmc_sendmulti_func == NULL) {
571                 sc->ndis_maxpkts = 1;
572         } else {
573                 len = sizeof(sc->ndis_maxpkts);
574                 ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS,
575                     &sc->ndis_maxpkts, &len);
576         }
577
578         sc->ndis_txarray = malloc(sizeof(ndis_packet *) *
579             sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT|M_ZERO);
580
581         /* Allocate a pool of ndis_packets for TX encapsulation. */
582
583         NdisAllocatePacketPool(&i, &sc->ndis_txpool,
584            sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET);
585
586         if (i != NDIS_STATUS_SUCCESS) {
587                 sc->ndis_txpool = NULL;
588                 device_printf(dev, "failed to allocate TX packet pool");
589                 error = ENOMEM;
590                 goto fail;
591         }
592
593         sc->ndis_txpending = sc->ndis_maxpkts;
594
595         sc->ndis_oidcnt = 0;
596         /* Get supported oid list. */
597         ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt);
598
599         /* If the NDIS module requested scatter/gather, init maps. */
600         if (sc->ndis_sc)
601                 ndis_init_dma(sc);
602
603         /*
604          * See if the OID_802_11_CONFIGURATION OID is
605          * supported by this driver. If it is, then this an 802.11
606          * wireless driver, and we should set up media for wireless.
607          */
608         for (i = 0; i < sc->ndis_oidcnt; i++) {
609                 if (sc->ndis_oids[i] == OID_802_11_CONFIGURATION) {
610                         sc->ndis_80211++;
611                         break;
612                 }
613         }
614
615         /* Check for task offload support. */
616         ndis_probe_offload(sc);
617
618         ifp = &sc->arpcom.ac_if;
619         ifp->if_softc = sc;
620         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
621         ifp->if_mtu = ETHERMTU;
622         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
623         ifp->if_ioctl = ndis_ioctl;
624         ifp->if_start = ndis_start;
625         ifp->if_watchdog = ndis_watchdog;
626         ifp->if_init = ndis_init;
627         ifp->if_baudrate = 10000000;
628 #if __FreeBSD_version < 502114
629         ifp->if_snd.ifq_maxlen = 50;
630 #else
631         IFQ_SET_MAXLEN(&ifp->if_snd, 50);
632         ifp->if_snd.ifq_drv_maxlen = 25;
633         IFQ_SET_READY(&ifp->if_snd);
634 #endif
635         ifp->if_capenable = ifp->if_capabilities;
636         ifp->if_hwassist = sc->ndis_hwassist;
637
638         /* Do media setup */
639         if (sc->ndis_80211) {
640                 struct ieee80211com     *ic = (void *)&sc->ic;
641                 ndis_80211_rates_ex     rates;
642                 struct ndis_80211_nettype_list *ntl;
643                 uint32_t                arg;
644                 int                     r;
645
646                 ic->ic_ifp = ifp;
647                 ic->ic_phytype = IEEE80211_T_DS;
648                 ic->ic_opmode = IEEE80211_M_STA;
649                 ic->ic_caps = IEEE80211_C_IBSS;
650                 ic->ic_state = IEEE80211_S_ASSOC;
651                 ic->ic_modecaps = (1<<IEEE80211_MODE_AUTO);
652                 len = 0;
653                 r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
654                     NULL, &len);
655                 if (r != ENOSPC)
656                         goto nonettypes;
657                 ntl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
658                 r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
659                     ntl, &len);
660                 if (r != 0) {
661                         free(ntl, M_DEVBUF);
662                         goto nonettypes;
663                 }
664
665                 for (i = 0; i < ntl->ntl_items; i++) {
666                         switch (ntl->ntl_type[i]) {
667                         case NDIS_80211_NETTYPE_11FH:
668                         case NDIS_80211_NETTYPE_11DS:
669                                 ic->ic_modecaps |= (1<<IEEE80211_MODE_11B);
670                                 break;
671                         case NDIS_80211_NETTYPE_11OFDM5:
672                                 ic->ic_modecaps |= (1<<IEEE80211_MODE_11A);
673                                 break;
674                         case NDIS_80211_NETTYPE_11OFDM24:
675                                 ic->ic_modecaps |= (1<<IEEE80211_MODE_11G);
676                                 break;
677                         default:
678                                 break;
679                         }
680                 }
681                 free(ntl, M_DEVBUF);
682 nonettypes:
683                 len = sizeof(rates);
684                 bzero((char *)&rates, len);
685                 r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES,
686                     (void *)rates, &len);
687                 if (r)
688                         device_printf (dev, "get rates failed: 0x%x\n", r);
689                 /*
690                  * Since the supported rates only up to 8 can be supported,
691                  * if this is not 802.11b we're just going to be faking it
692                  * all up to heck.
693                  */
694
695 #define TESTSETRATE(x, y)                                               \
696         do {                                                            \
697                 int                     i;                              \
698                 for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) {   \
699                         if (ic->ic_sup_rates[x].rs_rates[i] == (y))     \
700                                 break;                                  \
701                 }                                                       \
702                 if (i == ic->ic_sup_rates[x].rs_nrates) {               \
703                         ic->ic_sup_rates[x].rs_rates[i] = (y);          \
704                         ic->ic_sup_rates[x].rs_nrates++;                \
705                 }                                                       \
706         } while (0)
707
708 #define SETRATE(x, y)   \
709         ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y)
710 #define INCRATE(x)      \
711         ic->ic_sup_rates[x].rs_nrates++
712
713                 ic->ic_curmode = IEEE80211_MODE_AUTO;
714                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A))
715                         ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0;
716                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B))
717                         ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0;
718                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G))
719                         ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0;
720                 for (i = 0; i < len; i++) {
721                         switch (rates[i] & IEEE80211_RATE_VAL) {
722                         case 2:
723                         case 4:
724                         case 11:
725                         case 10:
726                         case 22:
727                                 if (!(ic->ic_modecaps &
728                                     (1<<IEEE80211_MODE_11B))) {
729                                         /* Lazy-init 802.11b. */
730                                         ic->ic_modecaps |=
731                                             (1<<IEEE80211_MODE_11B);
732                                         ic->ic_sup_rates[IEEE80211_MODE_11B].
733                                             rs_nrates = 0;
734                                 }
735                                 SETRATE(IEEE80211_MODE_11B, rates[i]);
736                                 INCRATE(IEEE80211_MODE_11B);
737                                 break;
738                         default:
739                                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
740                                         SETRATE(IEEE80211_MODE_11A, rates[i]);
741                                         INCRATE(IEEE80211_MODE_11A);
742                                 }
743                                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
744                                         SETRATE(IEEE80211_MODE_11G, rates[i]);
745                                         INCRATE(IEEE80211_MODE_11G);
746                                 }
747                                 break;
748                         }
749                 }
750
751                 /*
752                  * If the hardware supports 802.11g, it most
753                  * likely supports 802.11b and all of the
754                  * 802.11b and 802.11g speeds, so maybe we can
755                  * just cheat here.  Just how in the heck do
756                  * we detect turbo modes, though?
757                  */
758                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
759                         TESTSETRATE(IEEE80211_MODE_11B,
760                             IEEE80211_RATE_BASIC|2);
761                         TESTSETRATE(IEEE80211_MODE_11B,
762                             IEEE80211_RATE_BASIC|4);
763                         TESTSETRATE(IEEE80211_MODE_11B,
764                             IEEE80211_RATE_BASIC|11);
765                         TESTSETRATE(IEEE80211_MODE_11B,
766                             IEEE80211_RATE_BASIC|22);
767                 }
768                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
769                         TESTSETRATE(IEEE80211_MODE_11G, 47);
770                         TESTSETRATE(IEEE80211_MODE_11G, 72);
771                         TESTSETRATE(IEEE80211_MODE_11G, 96);
772                         TESTSETRATE(IEEE80211_MODE_11G, 108);
773                 }
774                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
775                         TESTSETRATE(IEEE80211_MODE_11A, 47);
776                         TESTSETRATE(IEEE80211_MODE_11A, 72);
777                         TESTSETRATE(IEEE80211_MODE_11A, 96);
778                         TESTSETRATE(IEEE80211_MODE_11A, 108);
779                 }
780 #undef SETRATE
781 #undef INCRATE
782                 /*
783                  * Taking yet more guesses here.
784                  */
785                 for (i = 1; i < IEEE80211_CHAN_MAX; i++) {
786                         int chanflag = 0;
787
788                         if (ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates)
789                                 chanflag |= IEEE80211_CHAN_G;
790                         if (i <= 14)
791                                 chanflag |= IEEE80211_CHAN_B;
792                         if (ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates &&
793                             i > 14)
794                                 chanflag = IEEE80211_CHAN_A;
795                         if (chanflag == 0)
796                                 break;
797                         ic->ic_channels[i].ic_freq =
798                             ieee80211_ieee2mhz(i, chanflag);
799                         ic->ic_channels[i].ic_flags = chanflag;
800                 }
801
802                 i = sizeof(arg);
803                 r = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &i);
804                 if (arg != NDIS_80211_WEPSTAT_NOTSUPPORTED)
805                         ic->ic_caps |= IEEE80211_C_WEP;
806                 i = sizeof(arg);
807                 r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i);
808                 if (r == 0)
809                         ic->ic_caps |= IEEE80211_C_PMGT;
810                 bcopy(eaddr, &ic->ic_myaddr, sizeof(eaddr));
811                 ieee80211_ifattach(ic);
812                 ieee80211_media_init(ic, ieee80211_media_change,
813                     ndis_media_status);
814                 ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
815                 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
816         } else {
817                 ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd,
818                     ndis_ifmedia_sts);
819                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
820                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
821                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
822                 ifmedia_add(&sc->ifmedia,
823                     IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
824                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
825                 ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
826                 ether_ifattach(ifp, eaddr);
827         }
828
829         /* Override the status handler so we can detect link changes. */
830         sc->ndis_block->nmb_status_func = ndis_linksts_wrap;
831         sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap;
832
833         /* Set up work item handlers. */
834         NdisInitializeWorkItem(&sc->ndis_tickitem,
835             (ndis_proc)ndis_ticktask_wrap, sc);
836         NdisInitializeWorkItem(&sc->ndis_startitem,
837             (ndis_proc)ndis_starttask_wrap, ifp);
838         NdisInitializeWorkItem(&sc->ndis_resetitem,
839             (ndis_proc)ndis_resettask_wrap, sc);
840         KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block);
841
842
843 fail:
844         if (error)
845                 ndis_detach(dev);
846         else
847                 /* We're done talking to the NIC for now; halt it. */
848                 ndis_halt_nic(sc);
849
850         return(error);
851 }
852
853 /*
854  * Shutdown hardware and free up resources. This can be called any
855  * time after the mutex has been initialized. It is called in both
856  * the error case in attach and the normal detach case so it needs
857  * to be careful about only freeing resources that have actually been
858  * allocated.
859  */
860 int
861 ndis_detach(dev)
862         device_t                dev;
863 {
864         struct ndis_softc       *sc;
865         struct ifnet            *ifp;
866         driver_object           *drv;
867
868         sc = device_get_softc(dev);
869         KASSERT(mtx_initialized(&sc->ndis_mtx),
870             ("ndis mutex not initialized"));
871         NDIS_LOCK(sc);
872         ifp = &sc->arpcom.ac_if;
873         ifp->if_flags &= ~IFF_UP;
874
875         if (device_is_attached(dev)) {
876                 NDIS_UNLOCK(sc);
877                 ndis_stop(sc);
878                 if (sc->ndis_80211)
879                         ieee80211_ifdetach(&sc->ic);
880                 else
881                         ether_ifdetach(ifp);
882         } else
883                 NDIS_UNLOCK(sc);
884
885         bus_generic_detach(dev);
886
887         if (sc->ndis_intrhand)
888                 bus_teardown_intr(dev, sc->ndis_irq, sc->ndis_intrhand);
889         if (sc->ndis_irq)
890                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq);
891         if (sc->ndis_res_io)
892                 bus_release_resource(dev, SYS_RES_IOPORT,
893                     sc->ndis_io_rid, sc->ndis_res_io);
894         if (sc->ndis_res_mem)
895                 bus_release_resource(dev, SYS_RES_MEMORY,
896                     sc->ndis_mem_rid, sc->ndis_res_mem);
897         if (sc->ndis_res_altmem)
898                 bus_release_resource(dev, SYS_RES_MEMORY,
899                     sc->ndis_altmem_rid, sc->ndis_res_altmem);
900
901         if (sc->ndis_iftype == PCMCIABus)
902                 ndis_free_amem(sc);
903
904         if (sc->ndis_sc)
905                 ndis_destroy_dma(sc);
906
907         if (sc->ndis_txarray)
908                 free(sc->ndis_txarray, M_DEVBUF);
909
910         if (!sc->ndis_80211)
911                 ifmedia_removeall(&sc->ifmedia);
912
913         if (sc->ndis_txpool != NULL)
914                 NdisFreePacketPool(sc->ndis_txpool);
915
916         ndis_unload_driver(sc);
917
918         /* Destroy the PDO for this device. */
919         
920         if (sc->ndis_iftype == PCIBus)
921                 drv = windrv_lookup(0, "PCI Bus");
922         else if (sc->ndis_iftype == PCMCIABus)
923                 drv = windrv_lookup(0, "PCCARD Bus");
924         else
925                 drv = windrv_lookup(0, "USB Bus");
926         if (drv == NULL)
927                 panic("couldn't find driver object");
928         windrv_destroy_pdo(drv, dev);
929
930         if (sc->ndis_iftype == PCIBus)
931                 bus_dma_tag_destroy(sc->ndis_parent_tag);
932
933 #if __FreeBSD_version < 502113
934         sysctl_ctx_free(&sc->ndis_ctx);
935 #endif
936
937         mtx_destroy(&sc->ndis_mtx);
938
939         return(0);
940 }
941
942 int
943 ndis_suspend(dev)
944         device_t                dev;
945 {
946         struct ndis_softc       *sc;
947         struct ifnet            *ifp;
948
949         sc = device_get_softc(dev);
950         ifp = &sc->arpcom.ac_if;
951
952 #ifdef notdef
953         if (NDIS_INITIALIZED(sc))
954                 ndis_stop(sc);
955 #endif
956
957         return(0);
958 }
959
960 int
961 ndis_resume(dev)
962         device_t                dev;
963 {
964         struct ndis_softc       *sc;
965         struct ifnet            *ifp;
966
967         sc = device_get_softc(dev);
968         ifp = &sc->arpcom.ac_if;
969
970         if (NDIS_INITIALIZED(sc))
971                 ndis_init(sc);
972
973         return(0);
974 }
975
976 /*
977  * The following bunch of routines are here to support drivers that
978  * use the NdisMEthIndicateReceive()/MiniportTransferData() mechanism.
979  */
980  
981 static void
982 ndis_rxeof_eth(adapter, ctx, addr, hdr, hdrlen, lookahead, lookaheadlen, pktlen)
983         ndis_handle             adapter;
984         ndis_handle             ctx;
985         char                    *addr;
986         void                    *hdr;
987         uint32_t                hdrlen;
988         void                    *lookahead;
989         uint32_t                lookaheadlen;
990         uint32_t                pktlen;
991 {
992         ndis_miniport_block     *block;
993         uint8_t                 irql;
994         uint32_t                status;
995         ndis_buffer             *b;
996         ndis_packet             *p;
997         struct mbuf             *m;
998         ndis_ethpriv            *priv;
999
1000         block = adapter;
1001
1002         m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1003
1004         if (m == NULL) {
1005                 NdisFreePacket(p);
1006                 return;
1007         }
1008
1009         /* Save the data provided to us so far. */
1010
1011         m->m_len = lookaheadlen + hdrlen;
1012         m->m_pkthdr.len = pktlen + hdrlen;
1013         m->m_next = NULL;
1014         m_copyback(m, 0, hdrlen, hdr);
1015         m_copyback(m, hdrlen, lookaheadlen, lookahead);
1016
1017         /* Now create a fake NDIS_PACKET to hold the data */
1018
1019         NdisAllocatePacket(&status, &p, block->nmb_rxpool);
1020
1021         if (status != NDIS_STATUS_SUCCESS) {
1022                 m_freem(m);
1023                 return;
1024         }
1025
1026         p->np_m0 = m;
1027
1028         b = IoAllocateMdl(m->m_data, m->m_pkthdr.len, FALSE, FALSE, NULL);
1029
1030         if (b == NULL) {
1031                 NdisFreePacket(p);
1032                 m_freem(m);
1033                 return;
1034         }
1035
1036         p->np_private.npp_head = p->np_private.npp_tail = b;
1037         p->np_private.npp_totlen = m->m_pkthdr.len;
1038
1039         /* Save the packet RX context somewhere. */
1040         priv = (ndis_ethpriv *)&p->np_protocolreserved;
1041         priv->nep_ctx = ctx;
1042
1043         KeAcquireSpinLock(&block->nmb_lock, &irql);
1044
1045         INSERT_LIST_TAIL((&block->nmb_packetlist),
1046                 ((list_entry *)&p->u.np_clrsvd.np_miniport_rsvd));
1047
1048         KeReleaseSpinLock(&block->nmb_lock, irql);
1049
1050         return;
1051 }
1052
1053 static void
1054 ndis_rxeof_done(adapter)
1055         ndis_handle             adapter;
1056 {
1057         struct ndis_softc       *sc;
1058         ndis_miniport_block     *block;
1059
1060         block = adapter;
1061
1062         /* Schedule transfer/RX of queued packets. */
1063
1064         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1065
1066         KeInsertQueueDpc(&sc->ndis_rxdpc, NULL, NULL);
1067
1068         return;
1069 }
1070
1071 /*
1072  * Runs at DISPATCH_LEVEL.
1073  */
1074 static void
1075 ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
1076         kdpc                    *dpc;
1077         ndis_handle             adapter;
1078         void                    *sysarg1;
1079         void                    *sysarg2;
1080 {
1081         ndis_miniport_block     *block;
1082         struct ndis_softc       *sc;
1083         ndis_packet             *p;
1084         list_entry              *l;
1085         uint32_t                status;
1086         ndis_ethpriv            *priv;
1087         struct ifnet            *ifp;
1088         struct mbuf             *m;
1089
1090         block = adapter;
1091         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1092         ifp = &sc->arpcom.ac_if;
1093
1094         KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
1095
1096         l = block->nmb_packetlist.nle_flink;
1097         while(l != &block->nmb_packetlist) {
1098                 REMOVE_LIST_HEAD((&block->nmb_packetlist));
1099                 p = CONTAINING_RECORD(l, ndis_packet,
1100                     u.np_clrsvd.np_miniport_rsvd);
1101
1102                 priv = (ndis_ethpriv *)&p->np_protocolreserved;
1103                 m = p->np_m0;
1104                 p->np_softc = sc;
1105                 p->np_m0 = NULL;
1106
1107                 KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
1108
1109                 status = MSCALL6(sc->ndis_chars->nmc_transferdata_func,
1110                     p, &p->np_private.npp_totlen, block, priv->nep_ctx,
1111                     m->m_len, m->m_pkthdr.len - m->m_len);
1112
1113                 KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
1114
1115                 /*
1116                  * If status is NDIS_STATUS_PENDING, do nothing and
1117                  * wait for a callback to the ndis_rxeof_xfr_done()
1118                  * handler.
1119                  */
1120
1121                 m->m_len = m->m_pkthdr.len;
1122                 m->m_pkthdr.rcvif = ifp;
1123
1124                 if (status == NDIS_STATUS_SUCCESS) {
1125                         IoFreeMdl(p->np_private.npp_head);
1126                         NdisFreePacket(p);
1127                         ifp->if_ipackets++;
1128                         (*ifp->if_input)(ifp, m);
1129                 }
1130
1131                 if (status == NDIS_STATUS_FAILURE)
1132                         m_freem(m);
1133
1134                 /* Advance to next packet */
1135                 l = block->nmb_packetlist.nle_flink;
1136         }
1137
1138         KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
1139
1140         return;
1141 }
1142
1143 static void
1144 ndis_rxeof_xfr_done(adapter, packet, status, len)
1145         ndis_handle             adapter;
1146         ndis_packet             *packet;
1147         uint32_t                status;
1148         uint32_t                len;
1149 {
1150         ndis_miniport_block     *block;
1151         struct ndis_softc       *sc;
1152         struct ifnet            *ifp;
1153         struct mbuf             *m;
1154
1155         block = adapter;
1156         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1157         ifp = &sc->arpcom.ac_if;
1158
1159         m = packet->np_m0;
1160         IoFreeMdl(packet->np_private.npp_head);
1161         NdisFreePacket(packet);
1162
1163         if (status != NDIS_STATUS_SUCCESS) {
1164                 m_freem(m);
1165                 return;
1166         }
1167
1168         m->m_len = m->m_pkthdr.len;
1169         m->m_pkthdr.rcvif = ifp;
1170         ifp->if_ipackets++;
1171         (*ifp->if_input)(ifp, m);
1172         return;
1173 }
1174 /*
1175  * A frame has been uploaded: pass the resulting mbuf chain up to
1176  * the higher level protocols.
1177  *
1178  * When handling received NDIS packets, the 'status' field in the
1179  * out-of-band portion of the ndis_packet has special meaning. In the
1180  * most common case, the underlying NDIS driver will set this field
1181  * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
1182  * take posession of it. We then change the status field to
1183  * NDIS_STATUS_PENDING to tell the driver that we now own the packet,
1184  * and that we will return it at some point in the future via the
1185  * return packet handler.
1186  *
1187  * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
1188  * this means the driver is running out of packet/buffer resources and
1189  * wants to maintain ownership of the packet. In this case, we have to
1190  * copy the packet data into local storage and let the driver keep the
1191  * packet.
1192  */
1193 static void
1194 ndis_rxeof(adapter, packets, pktcnt)
1195         ndis_handle             adapter;
1196         ndis_packet             **packets;
1197         uint32_t                pktcnt;
1198 {
1199         struct ndis_softc       *sc;
1200         ndis_miniport_block     *block;
1201         ndis_packet             *p;
1202         uint32_t                s;
1203         ndis_tcpip_csum         *csum;
1204         struct ifnet            *ifp;
1205         struct mbuf             *m0, *m;
1206         int                     i;
1207
1208         block = (ndis_miniport_block *)adapter;
1209         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1210         ifp = &sc->arpcom.ac_if;
1211
1212         for (i = 0; i < pktcnt; i++) {
1213                 p = packets[i];
1214                 /* Stash the softc here so ptom can use it. */
1215                 p->np_softc = sc;
1216                 if (ndis_ptom(&m0, p)) {
1217                         device_printf (sc->ndis_dev, "ptom failed\n");
1218                         if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
1219                                 ndis_return_packet(sc, p);
1220                 } else {
1221                         if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
1222                                 m = m_dup(m0, M_DONTWAIT);
1223                                 /*
1224                                  * NOTE: we want to destroy the mbuf here, but
1225                                  * we don't actually want to return it to the
1226                                  * driver via the return packet handler. By
1227                                  * bumping np_refcnt, we can prevent the
1228                                  * ndis_return_packet() routine from actually
1229                                  * doing anything.
1230                                  */
1231                                 p->np_refcnt++;
1232                                 m_freem(m0);
1233                                 if (m == NULL)
1234                                         ifp->if_ierrors++;
1235                                 else
1236                                         m0 = m;
1237                         } else
1238                                 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1239                         m0->m_pkthdr.rcvif = ifp;
1240                         ifp->if_ipackets++;
1241
1242                         /* Deal with checksum offload. */
1243
1244                         if (ifp->if_capenable & IFCAP_RXCSUM &&
1245                             p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) {
1246                                 s = (uintptr_t)
1247                                     p->np_ext.npe_info[ndis_tcpipcsum_info];
1248                                 csum = (ndis_tcpip_csum *)&s;
1249                                 if (csum->u.ntc_rxflags &
1250                                     NDIS_RXCSUM_IP_PASSED)
1251                                         m0->m_pkthdr.csum_flags |=
1252                                             CSUM_IP_CHECKED|CSUM_IP_VALID;
1253                                 if (csum->u.ntc_rxflags &
1254                                     (NDIS_RXCSUM_TCP_PASSED |
1255                                     NDIS_RXCSUM_UDP_PASSED)) {
1256                                         m0->m_pkthdr.csum_flags |=
1257                                             CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
1258                                         m0->m_pkthdr.csum_data = 0xFFFF;
1259                                 }
1260                         }
1261
1262                         (*ifp->if_input)(ifp, m0);
1263                 }
1264         }
1265
1266         return;
1267 }
1268
1269 /*
1270  * A frame was downloaded to the chip. It's safe for us to clean up
1271  * the list buffers.
1272  */
1273 static void
1274 ndis_txeof(adapter, packet, status)
1275         ndis_handle             adapter;
1276         ndis_packet             *packet;
1277         ndis_status             status;
1278
1279 {
1280         struct ndis_softc       *sc;
1281         ndis_miniport_block     *block;
1282         struct ifnet            *ifp;
1283         int                     idx;
1284         struct mbuf             *m;
1285
1286         block = (ndis_miniport_block *)adapter;
1287         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1288         ifp = &sc->arpcom.ac_if;
1289
1290         m = packet->np_m0;
1291         idx = packet->np_txidx;
1292         if (sc->ndis_sc)
1293                 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
1294
1295         ndis_free_packet(packet);
1296         m_freem(m);
1297
1298         NDIS_LOCK(sc);
1299         sc->ndis_txarray[idx] = NULL;
1300         sc->ndis_txpending++;
1301
1302         if (status == NDIS_STATUS_SUCCESS)
1303                 ifp->if_opackets++;
1304         else
1305                 ifp->if_oerrors++;
1306         ifp->if_timer = 0;
1307         ifp->if_flags &= ~IFF_OACTIVE;
1308
1309         NDIS_UNLOCK(sc);
1310
1311         NdisScheduleWorkItem(&sc->ndis_startitem);
1312
1313         return;
1314 }
1315
1316 static void
1317 ndis_linksts(adapter, status, sbuf, slen)
1318         ndis_handle             adapter;
1319         ndis_status             status;
1320         void                    *sbuf;
1321         uint32_t                slen;
1322 {
1323         ndis_miniport_block     *block;
1324         struct ndis_softc       *sc;
1325
1326         block = adapter;
1327         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1328
1329         block->nmb_getstat = status;
1330
1331         return;
1332 }
1333
1334 static void
1335 ndis_linksts_done(adapter)
1336         ndis_handle             adapter;
1337 {
1338         ndis_miniport_block     *block;
1339         struct ndis_softc       *sc;
1340         struct ifnet            *ifp;
1341
1342         block = adapter;
1343         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1344         ifp = &sc->arpcom.ac_if;
1345
1346         if (!NDIS_INITIALIZED(sc))
1347                 return;
1348
1349         switch (block->nmb_getstat) {
1350         case NDIS_STATUS_MEDIA_CONNECT:
1351                 NdisScheduleWorkItem(&sc->ndis_tickitem);
1352                 NdisScheduleWorkItem(&sc->ndis_startitem);
1353                 break;
1354         case NDIS_STATUS_MEDIA_DISCONNECT:
1355                 if (sc->ndis_link)
1356                         NdisScheduleWorkItem(&sc->ndis_tickitem);
1357                 break;
1358         default:
1359                 break;
1360         }
1361
1362         return;
1363 }
1364
1365 static void
1366 ndis_intr(arg)
1367         void                    *arg;
1368 {
1369         struct ndis_softc       *sc;
1370         struct ifnet            *ifp;
1371         int                     is_our_intr = 0;
1372         int                     call_isr = 0;
1373         uint8_t                 irql;
1374         ndis_miniport_interrupt *intr;
1375
1376         sc = arg;
1377         ifp = &sc->arpcom.ac_if;
1378         intr = sc->ndis_block->nmb_interrupt;
1379
1380         if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL)
1381                 return;
1382
1383         KeAcquireSpinLock(&intr->ni_dpccountlock, &irql);
1384         if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
1385                 ndis_isr(sc, &is_our_intr, &call_isr);
1386         else {
1387                 ndis_disable_intr(sc);
1388                 call_isr = 1;
1389         }
1390         KeReleaseSpinLock(&intr->ni_dpccountlock, irql);
1391
1392         if ((is_our_intr || call_isr))
1393                 IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
1394
1395         return;
1396 }
1397
1398 static void
1399 ndis_tick(xsc)
1400         void                    *xsc;
1401 {
1402         struct ndis_softc       *sc;
1403
1404         mtx_unlock(&Giant);
1405
1406         sc = xsc;
1407
1408         NdisScheduleWorkItem(&sc->ndis_tickitem);
1409         sc->ndis_stat_ch = timeout(ndis_tick, sc, hz *
1410             sc->ndis_block->nmb_checkforhangsecs);
1411
1412         mtx_lock(&Giant);
1413
1414         return;
1415 }
1416
1417 static void
1418 ndis_ticktask(w, xsc)
1419         ndis_work_item          *w;
1420         void                    *xsc;
1421 {
1422         struct ndis_softc       *sc;
1423         ndis_checkforhang_handler hangfunc;
1424         uint8_t                 rval;
1425         ndis_media_state        linkstate;
1426         int                     error, len;
1427
1428         sc = xsc;
1429
1430         hangfunc = sc->ndis_chars->nmc_checkhang_func;
1431
1432         if (hangfunc != NULL) {
1433                 rval = MSCALL1(hangfunc,
1434                     sc->ndis_block->nmb_miniportadapterctx);
1435                 if (rval == TRUE) {
1436                         ndis_reset_nic(sc);
1437                         return;
1438                 }
1439         }
1440
1441         len = sizeof(linkstate);
1442         error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
1443             (void *)&linkstate, &len);
1444
1445         NDIS_LOCK(sc);
1446
1447         if (sc->ndis_link == 0 && linkstate == nmc_connected) {
1448                 device_printf(sc->ndis_dev, "link up\n");
1449                 sc->ndis_link = 1;
1450                 NDIS_UNLOCK(sc);
1451                 if (sc->ndis_80211)
1452                         ndis_getstate_80211(sc);
1453                 NDIS_LOCK(sc);
1454 #ifdef LINK_STATE_UP
1455                 sc->arpcom.ac_if.if_link_state = LINK_STATE_UP;
1456                 rt_ifmsg(&(sc->arpcom.ac_if));
1457 #endif /* LINK_STATE_UP */
1458         }
1459
1460         if (sc->ndis_link == 1 && linkstate == nmc_disconnected) {
1461                 device_printf(sc->ndis_dev, "link down\n");
1462                 sc->ndis_link = 0;
1463 #ifdef LINK_STATE_DOWN
1464                 sc->arpcom.ac_if.if_link_state = LINK_STATE_DOWN;
1465                 rt_ifmsg(&(sc->arpcom.ac_if));
1466 #endif /* LINK_STATE_DOWN */
1467         }
1468
1469         NDIS_UNLOCK(sc);
1470
1471         return;
1472 }
1473
1474 static void
1475 ndis_map_sclist(arg, segs, nseg, mapsize, error)
1476         void                    *arg;
1477         bus_dma_segment_t       *segs;
1478         int                     nseg;
1479         bus_size_t              mapsize;
1480         int                     error;
1481
1482 {
1483         struct ndis_sc_list     *sclist;
1484         int                     i;
1485
1486         if (error || arg == NULL)
1487                 return;
1488
1489         sclist = arg;
1490
1491         sclist->nsl_frags = nseg;
1492
1493         for (i = 0; i < nseg; i++) {
1494                 sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr;
1495                 sclist->nsl_elements[i].nse_len = segs[i].ds_len;
1496         }
1497
1498         return;
1499 }
1500
1501 static void
1502 ndis_starttask(w, arg)
1503         ndis_work_item          *w;
1504         void                    *arg;
1505 {
1506         struct ifnet            *ifp;
1507
1508         ifp = arg;
1509
1510 #if __FreeBSD_version < 502114
1511         if (ifp->if_snd.ifq_head != NULL)
1512 #else
1513         if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1514 #endif
1515                 ndis_start(ifp);
1516         return;
1517 }
1518
1519 /*
1520  * Main transmit routine. To make NDIS drivers happy, we need to
1521  * transform mbuf chains into NDIS packets and feed them to the
1522  * send packet routines. Most drivers allow you to send several
1523  * packets at once (up to the maxpkts limit). Unfortunately, rather
1524  * that accepting them in the form of a linked list, they expect
1525  * a contiguous array of pointers to packets.
1526  *
1527  * For those drivers which use the NDIS scatter/gather DMA mechanism,
1528  * we need to perform busdma work here. Those that use map registers
1529  * will do the mapping themselves on a buffer by buffer basis.
1530  */
1531
1532 static void
1533 ndis_start(ifp)
1534         struct ifnet            *ifp;
1535 {
1536         struct ndis_softc       *sc;
1537         struct mbuf             *m = NULL;
1538         ndis_packet             **p0 = NULL, *p = NULL;
1539         ndis_tcpip_csum         *csum;
1540         int                     pcnt = 0, status;
1541
1542         sc = ifp->if_softc;
1543
1544         NDIS_LOCK(sc);
1545
1546         if (!sc->ndis_link || ifp->if_flags & IFF_OACTIVE) {
1547                 NDIS_UNLOCK(sc);
1548                 return;
1549         }
1550
1551         p0 = &sc->ndis_txarray[sc->ndis_txidx];
1552
1553         while(sc->ndis_txpending) {
1554 #if __FreeBSD_version < 502114
1555                 IF_DEQUEUE(&ifp->if_snd, m);
1556 #else
1557                 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1558 #endif
1559                 if (m == NULL)
1560                         break;
1561
1562                 NdisAllocatePacket(&status,
1563                     &sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool);
1564
1565                 if (status != NDIS_STATUS_SUCCESS)
1566                         break;
1567
1568                 if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
1569 #if __FreeBSD_version >= 502114
1570                         IFQ_DRV_PREPEND(&ifp->if_snd, m);
1571 #endif
1572                         NDIS_UNLOCK(sc);
1573 #if __FreeBSD_version < 502114
1574                         IF_PREPEND(&ifp->if_snd, m);
1575 #endif
1576                         return;
1577                 }
1578
1579                 /*
1580                  * Save pointer to original mbuf
1581                  * so we can free it later.
1582                  */
1583
1584                 p = sc->ndis_txarray[sc->ndis_txidx];
1585                 p->np_txidx = sc->ndis_txidx;
1586                 p->np_m0 = m;
1587                 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1588
1589                 /*
1590                  * Do scatter/gather processing, if driver requested it.
1591                  */
1592                 if (sc->ndis_sc) {
1593                         bus_dmamap_load_mbuf(sc->ndis_ttag,
1594                             sc->ndis_tmaps[sc->ndis_txidx], m,
1595                             ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT);
1596                         bus_dmamap_sync(sc->ndis_ttag,
1597                             sc->ndis_tmaps[sc->ndis_txidx],
1598                             BUS_DMASYNC_PREREAD);
1599                         p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist;
1600                 }
1601
1602                 /* Handle checksum offload. */
1603
1604                 if (ifp->if_capenable & IFCAP_TXCSUM &&
1605                     m->m_pkthdr.csum_flags) {
1606                         csum = (ndis_tcpip_csum *)
1607                                 &p->np_ext.npe_info[ndis_tcpipcsum_info];
1608                         csum->u.ntc_txflags = NDIS_TXCSUM_DO_IPV4;
1609                         if (m->m_pkthdr.csum_flags & CSUM_IP)
1610                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_IP;
1611                         if (m->m_pkthdr.csum_flags & CSUM_TCP)
1612                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_TCP;
1613                         if (m->m_pkthdr.csum_flags & CSUM_UDP)
1614                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_UDP;
1615                         p->np_private.npp_flags = NDIS_PROTOCOL_ID_TCP_IP;
1616                 }
1617
1618                 NDIS_INC(sc);
1619                 sc->ndis_txpending--;
1620
1621                 pcnt++;
1622
1623                 /*
1624                  * If there's a BPF listener, bounce a copy of this frame
1625                  * to him.
1626                  */
1627
1628                 BPF_MTAP(ifp, m);
1629
1630                 /*
1631                  * The array that p0 points to must appear contiguous,
1632                  * so we must not wrap past the end of sc->ndis_txarray[].
1633                  * If it looks like we're about to wrap, break out here
1634                  * so the this batch of packets can be transmitted, then
1635                  * wait for txeof to ask us to send the rest.
1636                  */
1637
1638                 if (sc->ndis_txidx == 0)
1639                         break;
1640         }
1641
1642         if (pcnt == 0) {
1643                 NDIS_UNLOCK(sc);
1644                 return;
1645         }
1646
1647         if (sc->ndis_txpending == 0)
1648                 ifp->if_flags |= IFF_OACTIVE;
1649
1650         /*
1651          * Set a timeout in case the chip goes out to lunch.
1652          */
1653         ifp->if_timer = 5;
1654
1655         NDIS_UNLOCK(sc);
1656
1657         if (sc->ndis_maxpkts == 1)
1658                 ndis_send_packet(sc, p);
1659         else
1660                 ndis_send_packets(sc, p0, pcnt);
1661
1662         return;
1663 }
1664
1665 static void
1666 ndis_init(xsc)
1667         void                    *xsc;
1668 {
1669         struct ndis_softc       *sc = xsc;
1670         struct ifnet            *ifp = &sc->arpcom.ac_if;
1671         int                     i, error;
1672
1673         /*
1674          * Avoid reintializing the link unnecessarily.
1675          * This should be dealt with in a better way by
1676          * fixing the upper layer modules so they don't
1677          * call ifp->if_init() quite as often.
1678          */
1679         if (sc->ndis_link && sc->ndis_skip)
1680                 return;
1681
1682         /*
1683          * Cancel pending I/O and free all RX/TX buffers.
1684          */
1685         ndis_stop(sc);
1686         if (ndis_init_nic(sc))
1687                 return;
1688
1689         /* Init our MAC address */
1690
1691         /* Program the packet filter */
1692
1693         sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED;
1694
1695         if (ifp->if_flags & IFF_BROADCAST)
1696                 sc->ndis_filter |= NDIS_PACKET_TYPE_BROADCAST;
1697
1698         if (ifp->if_flags & IFF_PROMISC)
1699                 sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS;
1700
1701         i = sizeof(sc->ndis_filter);
1702
1703         error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
1704             &sc->ndis_filter, &i);
1705
1706         if (error)
1707                 device_printf (sc->ndis_dev, "set filter failed: %d\n", error);
1708
1709         /*
1710          * Program the multicast filter, if necessary.
1711          */
1712         ndis_setmulti(sc);
1713
1714         /* Setup task offload. */
1715         ndis_set_offload(sc);
1716
1717         /* Enable interrupts. */
1718         ndis_enable_intr(sc);
1719
1720         if (sc->ndis_80211)
1721                 ndis_setstate_80211(sc);
1722
1723         NDIS_LOCK(sc);
1724
1725         sc->ndis_txidx = 0;
1726         sc->ndis_txpending = sc->ndis_maxpkts;
1727         sc->ndis_link = 0;
1728
1729         ifp->if_flags |= IFF_RUNNING;
1730         ifp->if_flags &= ~IFF_OACTIVE;
1731
1732         NDIS_UNLOCK(sc);
1733
1734         /*
1735          * Some drivers don't set this value. The NDIS spec says
1736          * the default checkforhang timeout is "approximately 2
1737          * seconds." We use 3 seconds, because it seems for some
1738          * drivers, exactly 2 seconds is too fast.
1739          */
1740
1741         if (sc->ndis_block->nmb_checkforhangsecs == 0)
1742                 sc->ndis_block->nmb_checkforhangsecs = 3;
1743
1744         sc->ndis_stat_ch = timeout(ndis_tick, sc,
1745             hz * sc->ndis_block->nmb_checkforhangsecs);
1746
1747         return;
1748 }
1749
1750 /*
1751  * Set media options.
1752  */
1753 static int
1754 ndis_ifmedia_upd(ifp)
1755         struct ifnet            *ifp;
1756 {
1757         struct ndis_softc               *sc;
1758
1759         sc = ifp->if_softc;
1760
1761         if (NDIS_INITIALIZED(sc))
1762                 ndis_init(sc);
1763
1764         return(0);
1765 }
1766
1767 /*
1768  * Report current media status.
1769  */
1770 static void
1771 ndis_ifmedia_sts(ifp, ifmr)
1772         struct ifnet            *ifp;
1773         struct ifmediareq       *ifmr;
1774 {
1775         struct ndis_softc       *sc;
1776         uint32_t                media_info;
1777         ndis_media_state        linkstate;
1778         int                     error, len;
1779
1780         ifmr->ifm_status = IFM_AVALID;
1781         ifmr->ifm_active = IFM_ETHER;
1782         sc = ifp->if_softc;
1783
1784         if (!NDIS_INITIALIZED(sc))
1785                 return;
1786
1787         len = sizeof(linkstate);
1788         error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
1789             (void *)&linkstate, &len);
1790
1791         len = sizeof(media_info);
1792         error = ndis_get_info(sc, OID_GEN_LINK_SPEED,
1793             (void *)&media_info, &len);
1794
1795         if (linkstate == nmc_connected)
1796                 ifmr->ifm_status |= IFM_ACTIVE;
1797
1798         switch(media_info) {
1799         case 100000:
1800                 ifmr->ifm_active |= IFM_10_T;
1801                 break;
1802         case 1000000:
1803                 ifmr->ifm_active |= IFM_100_TX;
1804                 break;
1805         case 10000000:
1806                 ifmr->ifm_active |= IFM_1000_T;
1807                 break;
1808         default:
1809                 device_printf(sc->ndis_dev, "unknown speed: %d\n", media_info);
1810                 break;
1811         }
1812
1813         return;
1814 }
1815
1816 static void
1817 ndis_setstate_80211(sc)
1818         struct ndis_softc       *sc;
1819 {
1820         struct ieee80211com     *ic;
1821         ndis_80211_ssid         ssid;
1822         ndis_80211_config       config;
1823         ndis_80211_wep          wep;
1824         int                     i, rval = 0, len;
1825         uint32_t                arg;
1826         struct ifnet            *ifp;
1827
1828         ic = &sc->ic;
1829         ifp = &sc->arpcom.ac_if;
1830
1831         if (!NDIS_INITIALIZED(sc))
1832                 return;
1833
1834         /* Set network infrastructure mode. */
1835
1836         len = sizeof(arg);
1837         if (ic->ic_opmode == IEEE80211_M_IBSS)
1838                 arg = NDIS_80211_NET_INFRA_IBSS;
1839         else
1840                 arg = NDIS_80211_NET_INFRA_BSS;
1841
1842         rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
1843
1844         if (rval)
1845                 device_printf (sc->ndis_dev, "set infra failed: %d\n", rval);
1846
1847         /* Set WEP */
1848
1849 #ifdef IEEE80211_F_PRIVACY
1850         if (ic->ic_flags & IEEE80211_F_PRIVACY) {
1851 #else
1852         if (ic->ic_wep_mode >= IEEE80211_WEP_ON) {
1853 #endif
1854                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1855                         if (ic->ic_nw_keys[i].wk_keylen) {
1856                                 bzero((char *)&wep, sizeof(wep));
1857                                 wep.nw_keylen = ic->ic_nw_keys[i].wk_keylen;
1858 #ifdef notdef
1859                                 /* 5 and 13 are the only valid key lengths */
1860                                 if (ic->ic_nw_keys[i].wk_keylen < 5)
1861                                         wep.nw_keylen = 5;
1862                                 else if (ic->ic_nw_keys[i].wk_keylen > 5 &&
1863                                      ic->ic_nw_keys[i].wk_keylen < 13)
1864                                         wep.nw_keylen = 13;
1865 #endif
1866                                 wep.nw_keyidx = i;
1867                                 wep.nw_length = (sizeof(uint32_t) * 3)
1868                                     + wep.nw_keylen;
1869                                 if (i == ic->ic_def_txkey)
1870                                         wep.nw_keyidx |= NDIS_80211_WEPKEY_TX;
1871                                 bcopy(ic->ic_nw_keys[i].wk_key,
1872                                     wep.nw_keydata, wep.nw_length);
1873                                 len = sizeof(wep);
1874                                 rval = ndis_set_info(sc,
1875                                     OID_802_11_ADD_WEP, &wep, &len);
1876                                 if (rval)
1877                                         device_printf(sc->ndis_dev,
1878                                             "set wepkey failed: %d\n", rval);
1879                         }
1880                 }
1881                 arg = NDIS_80211_WEPSTAT_ENABLED;
1882                 len = sizeof(arg);
1883                 rval = ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
1884                 if (rval)
1885                         device_printf(sc->ndis_dev,
1886                             "enable WEP failed: %d\n", rval);
1887 #ifndef IEEE80211_F_WEPON
1888 #if 0
1889                 if (ic->ic_wep_mode != IEEE80211_WEP_8021X &&
1890                     ic->ic_wep_mode != IEEE80211_WEP_ON)
1891                         arg = NDIS_80211_PRIVFILT_ACCEPTALL;
1892                 else
1893 #endif
1894 #endif
1895                         arg = NDIS_80211_PRIVFILT_8021XWEP;
1896                 len = sizeof(arg);
1897                 rval = ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len);
1898 #ifdef IEEE80211_WEP_8021X /*IEEE80211_F_WEPON*/
1899                 /* Accept that we only have "shared" and 802.1x modes. */
1900                 if (rval == 0) {
1901                         if (arg == NDIS_80211_PRIVFILT_ACCEPTALL)
1902                                 ic->ic_wep_mode = IEEE80211_WEP_MIXED;
1903                         else
1904                                 ic->ic_wep_mode = IEEE80211_WEP_8021X;
1905                 }
1906 #endif
1907                 arg = NDIS_80211_AUTHMODE_OPEN;
1908         } else {
1909                 arg = NDIS_80211_WEPSTAT_DISABLED;
1910                 len = sizeof(arg);
1911                 ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
1912                 arg = NDIS_80211_AUTHMODE_OPEN;
1913         }
1914
1915         len = sizeof(arg);
1916         rval = ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
1917
1918 #ifdef notyet
1919         if (rval)
1920                 device_printf (sc->ndis_dev, "set auth failed: %d\n", rval);
1921 #endif
1922
1923 #ifdef notyet
1924         /* Set network type. */
1925
1926         arg = 0;
1927
1928         switch (ic->ic_curmode) {
1929         case IEEE80211_MODE_11A:
1930                 arg = NDIS_80211_NETTYPE_11OFDM5;
1931                 break;
1932         case IEEE80211_MODE_11B:
1933                 arg = NDIS_80211_NETTYPE_11DS;
1934                 break;
1935         case IEEE80211_MODE_11G:
1936                 arg = NDIS_80211_NETTYPE_11OFDM24;
1937                 break;
1938         default:
1939                 device_printf(sc->ndis_dev, "unknown mode: %d\n",
1940                     ic->ic_curmode);
1941         }
1942
1943         if (arg) {
1944                 len = sizeof(arg);
1945                 rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE,
1946                     &arg, &len);
1947                 if (rval)
1948                         device_printf (sc->ndis_dev,
1949                             "set nettype failed: %d\n", rval);
1950         }
1951 #endif
1952
1953         len = sizeof(config);
1954         bzero((char *)&config, len);
1955         config.nc_length = len;
1956         config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
1957         rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); 
1958
1959         /*
1960          * Some drivers expect us to initialize these values, so
1961          * provide some defaults.
1962          */
1963         if (config.nc_beaconperiod == 0)
1964                 config.nc_beaconperiod = 100;
1965         if (config.nc_atimwin == 0)
1966                 config.nc_atimwin = 100;
1967         if (config.nc_fhconfig.ncf_dwelltime == 0)
1968                 config.nc_fhconfig.ncf_dwelltime = 200;
1969
1970         if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) { 
1971                 int chan, chanflag;
1972
1973                 chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
1974                 chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
1975                     IEEE80211_CHAN_5GHZ;
1976                 if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
1977                         config.nc_dsconfig =
1978                             ic->ic_ibss_chan->ic_freq * 1000;
1979                         ic->ic_bss->ni_chan = ic->ic_ibss_chan;
1980                         len = sizeof(config);
1981                         config.nc_length = len;
1982                         config.nc_fhconfig.ncf_length =
1983                             sizeof(ndis_80211_config_fh);
1984                         rval = ndis_set_info(sc, OID_802_11_CONFIGURATION,
1985                             &config, &len);
1986                         if (rval)
1987                                 device_printf(sc->ndis_dev, "couldn't change "
1988                                     "DS config to %ukHz: %d\n",
1989                                     config.nc_dsconfig, rval);
1990                 }
1991         } else if (rval)
1992                 device_printf(sc->ndis_dev, "couldn't retrieve "
1993                     "channel info: %d\n", rval);
1994
1995         /* Set SSID -- always do this last. */
1996
1997         len = sizeof(ssid);
1998         bzero((char *)&ssid, len);
1999         ssid.ns_ssidlen = ic->ic_des_esslen;
2000         if (ssid.ns_ssidlen == 0) {
2001                 ssid.ns_ssidlen = 1;
2002         } else
2003                 bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen);
2004         rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
2005
2006         if (rval)
2007                 device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval);
2008
2009         return;
2010 }
2011
2012 static void
2013 ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
2014 {
2015         struct ieee80211com *ic = &((struct ndis_softc *)ifp->if_softc)->ic;
2016         struct ieee80211_node *ni = NULL;
2017
2018         imr->ifm_status = IFM_AVALID;
2019         imr->ifm_active = IFM_IEEE80211;
2020         if (ic->ic_state == IEEE80211_S_RUN)
2021                 imr->ifm_status |= IFM_ACTIVE;
2022         imr->ifm_active |= IFM_AUTO;
2023         switch (ic->ic_opmode) {
2024         case IEEE80211_M_STA:
2025                 ni = ic->ic_bss;
2026                 /* calculate rate subtype */
2027                 imr->ifm_active |= ieee80211_rate2media(ic,
2028                         ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
2029                 break;
2030         case IEEE80211_M_IBSS:
2031                 ni = ic->ic_bss;
2032                 /* calculate rate subtype */
2033                 imr->ifm_active |= ieee80211_rate2media(ic,
2034                         ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
2035                 imr->ifm_active |= IFM_IEEE80211_ADHOC;
2036                 break;
2037         case IEEE80211_M_AHDEMO:
2038                 /* should not come here */
2039                 break;
2040         case IEEE80211_M_HOSTAP:
2041                 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
2042                 break;
2043         case IEEE80211_M_MONITOR:
2044                 imr->ifm_active |= IFM_IEEE80211_MONITOR;
2045                 break;
2046         }
2047         switch (ic->ic_curmode) {
2048         case IEEE80211_MODE_11A:
2049                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A);
2050                 break;
2051         case IEEE80211_MODE_11B:
2052                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B);
2053                 break;
2054         case IEEE80211_MODE_11G:
2055                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G);
2056                 break;
2057         case IEEE80211_MODE_TURBO_A:
2058                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
2059                                 |  IFM_IEEE80211_TURBO;
2060                 break;
2061         }
2062 }
2063
2064 static int
2065 ndis_get_assoc(sc, assoc)
2066         struct ndis_softc       *sc;
2067         ndis_wlan_bssid_ex      **assoc;
2068 {
2069         ndis_80211_bssid_list_ex        *bl;
2070         ndis_wlan_bssid_ex      *bs;
2071         ndis_80211_macaddr      bssid;
2072         int                     i, len, error;
2073
2074         if (!sc->ndis_link)
2075                 return(ENOENT);
2076
2077         len = sizeof(bssid);
2078         error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len);
2079         if (error) {
2080                 device_printf(sc->ndis_dev, "failed to get bssid\n");
2081                 return(ENOENT);
2082         }
2083         len = 0;
2084         error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
2085         if (error != ENOSPC) {
2086                 device_printf(sc->ndis_dev, "bssid_list failed\n");
2087                 return (error);
2088         }
2089
2090         bl = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
2091         error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
2092         if (error) {
2093                 free(bl, M_TEMP);
2094                 device_printf(sc->ndis_dev, "bssid_list failed\n");
2095                 return (error);
2096         }
2097
2098         bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0];
2099         for (i = 0; i < bl->nblx_items; i++) {
2100                 if (bcmp(bs->nwbx_macaddr, bssid, sizeof(bssid)) == 0) {
2101                         *assoc = malloc(bs->nwbx_len, M_TEMP, M_NOWAIT);
2102                         if (*assoc == NULL) {
2103                                 free(bl, M_TEMP);
2104                                 return(ENOMEM);
2105                         }
2106                         bcopy((char *)bs, (char *)*assoc, bs->nwbx_len);
2107                         free(bl, M_TEMP);
2108                         return(0);
2109                 }       
2110                 bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len);
2111         }
2112
2113         free(bl, M_TEMP);
2114         return(ENOENT);
2115 }
2116
2117 static void
2118 ndis_getstate_80211(sc)
2119         struct ndis_softc       *sc;
2120 {
2121         struct ieee80211com     *ic;
2122         ndis_80211_ssid         ssid;
2123         ndis_80211_config       config;
2124         ndis_wlan_bssid_ex      *bs;
2125         int                     rval, len, i = 0;
2126         uint32_t                arg;
2127         struct ifnet            *ifp;
2128
2129         ic = &sc->ic;
2130         ifp = &sc->arpcom.ac_if;
2131
2132         if (!NDIS_INITIALIZED(sc))
2133                 return;
2134
2135         if (sc->ndis_link)
2136                 ic->ic_state = IEEE80211_S_RUN;
2137         else
2138                 ic->ic_state = IEEE80211_S_ASSOC;
2139
2140
2141         /*
2142          * If we're associated, retrieve info on the current bssid.
2143          */
2144         if ((rval = ndis_get_assoc(sc, &bs)) == 0) {
2145                 switch(bs->nwbx_nettype) {
2146                 case NDIS_80211_NETTYPE_11FH:
2147                 case NDIS_80211_NETTYPE_11DS:
2148                         ic->ic_curmode = IEEE80211_MODE_11B;
2149                         break;
2150                 case NDIS_80211_NETTYPE_11OFDM5:
2151                         ic->ic_curmode = IEEE80211_MODE_11A;
2152                         break;
2153                 case NDIS_80211_NETTYPE_11OFDM24:
2154                         ic->ic_curmode = IEEE80211_MODE_11G;
2155                         break;
2156                 default:
2157                         device_printf(sc->ndis_dev,
2158                             "unknown nettype %d\n", arg);
2159                         break;
2160                 }
2161                 IEEE80211_ADDR_COPY(ic->ic_bss->ni_bssid, bs->nwbx_macaddr);
2162                 free(bs, M_TEMP);
2163         } else
2164                 return;
2165
2166         len = sizeof(ssid);
2167         bzero((char *)&ssid, len);
2168         rval = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len);
2169
2170         if (rval)
2171                 device_printf (sc->ndis_dev, "get ssid failed: %d\n", rval);
2172         bcopy(ssid.ns_ssid, ic->ic_bss->ni_essid, ssid.ns_ssidlen);
2173         ic->ic_bss->ni_esslen = ssid.ns_ssidlen;
2174
2175         len = sizeof(arg);
2176         rval = ndis_get_info(sc, OID_GEN_LINK_SPEED, &arg, &len);
2177         if (rval)
2178                 device_printf (sc->ndis_dev, "get link speed failed: %d\n",
2179                     rval);
2180
2181         if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
2182                 ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];
2183                 for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
2184                         if ((ic->ic_bss->ni_rates.rs_rates[i] &
2185                             IEEE80211_RATE_VAL) == arg / 5000)
2186                                 break;
2187                 }
2188         }
2189
2190         if (i == ic->ic_bss->ni_rates.rs_nrates &&
2191             ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
2192                 ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11G];
2193                 for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
2194                         if ((ic->ic_bss->ni_rates.rs_rates[i] &
2195                             IEEE80211_RATE_VAL) == arg / 5000)
2196                                 break;
2197                 }
2198         }
2199
2200         if (i == ic->ic_bss->ni_rates.rs_nrates)
2201                 device_printf(sc->ndis_dev, "no matching rate for: %d\n",
2202                     arg / 5000);
2203         else
2204                 ic->ic_bss->ni_txrate = i;
2205
2206         if (ic->ic_caps & IEEE80211_C_PMGT) {
2207                 len = sizeof(arg);
2208                 rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len);
2209
2210                 if (rval)
2211                         device_printf(sc->ndis_dev,
2212                             "get power mode failed: %d\n", rval);
2213                 if (arg == NDIS_80211_POWERMODE_CAM)
2214                         ic->ic_flags &= ~IEEE80211_F_PMGTON;
2215                 else
2216                         ic->ic_flags |= IEEE80211_F_PMGTON;
2217         }
2218
2219         len = sizeof(config);
2220         bzero((char *)&config, len);
2221         config.nc_length = len;
2222         config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
2223         rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len);   
2224         if (rval == 0) { 
2225                 int chan;
2226
2227                 chan = ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0);
2228                 if (chan < 0 || chan >= IEEE80211_CHAN_MAX) {
2229                         if (ifp->if_flags & IFF_DEBUG)
2230                                 device_printf(sc->ndis_dev, "current channel "
2231                                     "(%uMHz) out of bounds\n", 
2232                                     config.nc_dsconfig / 1000);
2233                         ic->ic_bss->ni_chan = &ic->ic_channels[1];
2234                 } else
2235                         ic->ic_bss->ni_chan = &ic->ic_channels[chan];
2236         } else
2237                 device_printf(sc->ndis_dev, "couldn't retrieve "
2238                     "channel info: %d\n", rval);
2239
2240 /*
2241         len = sizeof(arg);
2242         rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
2243
2244         if (rval)
2245                 device_printf (sc->ndis_dev,
2246                     "get wep status failed: %d\n", rval);
2247
2248         if (arg == NDIS_80211_WEPSTAT_ENABLED)
2249                 ic->ic_flags |= IEEE80211_F_WEPON;
2250         else
2251                 ic->ic_flags &= ~IEEE80211_F_WEPON;
2252 */
2253         return;
2254 }
2255
2256 static int
2257 ndis_ioctl(ifp, command, data)
2258         struct ifnet            *ifp;
2259         u_long                  command;
2260         caddr_t                 data;
2261 {
2262         struct ndis_softc       *sc = ifp->if_softc;
2263         struct ifreq            *ifr = (struct ifreq *) data;
2264         int                     i, error = 0;
2265
2266         /*NDIS_LOCK(sc);*/
2267
2268         switch(command) {
2269         case SIOCSIFFLAGS:
2270                 if (ifp->if_flags & IFF_UP) {
2271                         if (ifp->if_flags & IFF_RUNNING &&
2272                             ifp->if_flags & IFF_PROMISC &&
2273                             !(sc->ndis_if_flags & IFF_PROMISC)) {
2274                                 sc->ndis_filter |=
2275                                     NDIS_PACKET_TYPE_PROMISCUOUS;
2276                                 i = sizeof(sc->ndis_filter);
2277                                 error = ndis_set_info(sc,
2278                                     OID_GEN_CURRENT_PACKET_FILTER,
2279                                     &sc->ndis_filter, &i);
2280                         } else if (ifp->if_flags & IFF_RUNNING &&
2281                             !(ifp->if_flags & IFF_PROMISC) &&
2282                             sc->ndis_if_flags & IFF_PROMISC) {
2283                                 sc->ndis_filter &=
2284                                     ~NDIS_PACKET_TYPE_PROMISCUOUS;
2285                                 i = sizeof(sc->ndis_filter);
2286                                 error = ndis_set_info(sc,
2287                                     OID_GEN_CURRENT_PACKET_FILTER,
2288                                     &sc->ndis_filter, &i);
2289                         } else
2290                                 ndis_init(sc);
2291                 } else {
2292                         if (ifp->if_flags & IFF_RUNNING)
2293                                 ndis_stop(sc);
2294                 }
2295                 sc->ndis_if_flags = ifp->if_flags;
2296                 error = 0;
2297                 break;
2298         case SIOCADDMULTI:
2299         case SIOCDELMULTI:
2300                 ndis_setmulti(sc);
2301                 error = 0;
2302                 break;
2303         case SIOCGIFMEDIA:
2304         case SIOCSIFMEDIA:
2305                 if (sc->ndis_80211) {
2306                         error = ieee80211_ioctl(&sc->ic, command, data);
2307                         if (error == ENETRESET) {
2308                                 ndis_setstate_80211(sc);
2309                                 /*ndis_init(sc);*/
2310                                 error = 0;
2311                         }
2312                 } else
2313                         error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
2314                 break;
2315         case SIOCSIFCAP:
2316                 ifp->if_capenable = ifr->ifr_reqcap;
2317                 if (ifp->if_capenable & IFCAP_TXCSUM)
2318                         ifp->if_hwassist = sc->ndis_hwassist;
2319                 else
2320                         ifp->if_hwassist = 0;
2321                 ndis_set_offload(sc);
2322                 break;
2323         case SIOCG80211:
2324                 if (!NDIS_INITIALIZED(sc))
2325                         goto do_80211;
2326                 if (sc->ndis_80211)
2327                         error = ndis_80211_ioctl_get(ifp, command, data);
2328                 else
2329                         error = ENOTTY;
2330                 break;
2331         case SIOCS80211:
2332                 if (!NDIS_INITIALIZED(sc))
2333                         goto do_80211;
2334                 if (sc->ndis_80211)
2335                         error = ndis_80211_ioctl_set(ifp, command, data);
2336                 else
2337                         error = ENOTTY;
2338                 break;
2339         case SIOCGIFGENERIC:
2340         case SIOCSIFGENERIC:
2341                 if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) {
2342                         if (command == SIOCGIFGENERIC)
2343                                 error = ndis_wi_ioctl_get(ifp, command, data);
2344                         else
2345                                 error = ndis_wi_ioctl_set(ifp, command, data);
2346                 } else
2347                         error = ENOTTY;
2348                 if (error != ENOTTY)
2349                         break;
2350         default:
2351 do_80211:
2352                 sc->ndis_skip = 1;
2353                 if (sc->ndis_80211) {
2354                         error = ieee80211_ioctl(&sc->ic, command, data);
2355                         if (error == ENETRESET) {
2356                                 ndis_setstate_80211(sc);
2357                                 error = 0;
2358                         }
2359                 } else
2360                         error = ether_ioctl(ifp, command, data);
2361                 sc->ndis_skip = 0;
2362                 break;
2363         }
2364
2365         /*NDIS_UNLOCK(sc);*/
2366
2367         return(error);
2368 }
2369
2370 static int
2371 ndis_wi_ioctl_get(ifp, command, data)
2372         struct ifnet            *ifp;
2373         u_long                  command;
2374         caddr_t                 data;
2375 {
2376         struct wi_req           wreq;
2377         struct ifreq            *ifr;
2378         struct ndis_softc       *sc;
2379         ndis_80211_bssid_list_ex *bl;
2380         ndis_wlan_bssid_ex      *wb;
2381         struct wi_apinfo        *api;
2382         int                     error, i, j, len, maxaps;
2383
2384         sc = ifp->if_softc;
2385         ifr = (struct ifreq *)data;
2386         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
2387         if (error)
2388                 return (error);
2389
2390         switch (wreq.wi_type) {
2391         case WI_RID_READ_APS:
2392                 len = 0;
2393                 error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN,
2394                     NULL, &len);
2395                 if (error == 0)
2396                         tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2);
2397                 len = 0;
2398                 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
2399                 if (error != ENOSPC)
2400                         break;
2401                 bl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
2402                 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
2403                 if (error) {
2404                         free(bl, M_DEVBUF);
2405                         break;
2406                 }
2407                 maxaps = (2 * wreq.wi_len - sizeof(int)) / sizeof(*api);
2408                 maxaps = MIN(maxaps, bl->nblx_items);
2409                 wreq.wi_len = (maxaps * sizeof(*api) + sizeof(int)) / 2;
2410                 *(int *)&wreq.wi_val = maxaps;
2411                 api = (struct wi_apinfo *)&((int *)&wreq.wi_val)[1];
2412                 wb = bl->nblx_bssid;
2413                 while (maxaps--) {
2414                         bzero(api, sizeof(*api));
2415                         bcopy(&wb->nwbx_macaddr, &api->bssid,
2416                             sizeof(api->bssid));
2417                         api->namelen = wb->nwbx_ssid.ns_ssidlen;
2418                         bcopy(&wb->nwbx_ssid.ns_ssid, &api->name, api->namelen);
2419                         if (wb->nwbx_privacy)
2420                                 api->capinfo |= IEEE80211_CAPINFO_PRIVACY;
2421                         /* XXX Where can we get noise information? */
2422                         api->signal = wb->nwbx_rssi + 149;      /* XXX */
2423                         api->quality = api->signal;
2424                         api->channel =
2425                             ieee80211_mhz2ieee(wb->nwbx_config.nc_dsconfig /
2426                             1000, 0);
2427                         /* In "auto" infrastructure mode, this is useless. */
2428                         if (wb->nwbx_netinfra == NDIS_80211_NET_INFRA_IBSS)
2429                                 api->capinfo |= IEEE80211_CAPINFO_IBSS;
2430                         if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
2431                                 j = sizeof(ndis_80211_rates_ex);
2432                                 /* handle other extended things */
2433                         } else
2434                                 j = sizeof(ndis_80211_rates);
2435                         for (i = api->rate = 0; i < j; i++)
2436                                 api->rate = MAX(api->rate, 5 *
2437                                     (wb->nwbx_supportedrates[i] & 0x7f));
2438                         api++;
2439                         wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
2440                 }
2441                 free(bl, M_DEVBUF);
2442                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
2443                 break;
2444         default:
2445                 error = ENOTTY;
2446                 break;
2447         }
2448         return (error);
2449 }
2450
2451 static int
2452 ndis_wi_ioctl_set(ifp, command, data)
2453         struct ifnet            *ifp;
2454         u_long                  command;
2455         caddr_t                 data;
2456 {
2457         struct wi_req           wreq;
2458         struct ifreq            *ifr;
2459         struct ndis_softc       *sc;
2460         uint32_t                foo;
2461         int                     error, len;
2462
2463         error = suser(curthread);
2464         if (error)
2465                 return (error);
2466
2467         sc = ifp->if_softc;
2468         ifr = (struct ifreq *)data;
2469         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
2470         if (error)
2471                 return (error);
2472
2473         switch (wreq.wi_type) {
2474         case WI_RID_SCAN_APS:
2475         case WI_RID_SCAN_REQ:                   /* arguments ignored */
2476                 len = sizeof(foo);
2477                 foo = 0;
2478                 error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, &foo,
2479                     &len);
2480                 break;
2481         default:
2482                 error = ENOTTY;
2483                 break;
2484         }
2485         return (error);
2486 }
2487
2488 static int
2489 ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data)
2490 {
2491         struct ndis_softc       *sc;
2492         struct ieee80211req     *ireq;
2493         ndis_80211_bssid_list_ex *bl;
2494         ndis_80211_ssid         ssid;
2495         ndis_80211_macaddr      bssid;
2496         ndis_wlan_bssid_ex      *wb;
2497         struct ieee80211req_scan_result *sr, *bsr;
2498         int                     error, len, i, j;
2499         char                    *cp;
2500         uint8_t                 nodename[IEEE80211_NWID_LEN];
2501         uint16_t                nodename_u[IEEE80211_NWID_LEN + 1];
2502         char                    *acode;
2503
2504         sc = ifp->if_softc;
2505         ireq = (struct ieee80211req *) data;
2506                 
2507         switch (ireq->i_type) {
2508         case IEEE80211_IOC_MLME:
2509                 error = 0;
2510                 break;
2511         case IEEE80211_IOC_BSSID:
2512                 len = sizeof(bssid);
2513                 bzero((char*)&bssid, len);
2514                 error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len);
2515                 if (error) {
2516                         device_printf(sc->ndis_dev, "failed to get bssid\n");
2517                         return(error);
2518                 }
2519                 ireq->i_len = len;
2520                 error = copyout(&bssid, ireq->i_data, len);
2521                 break;
2522         case IEEE80211_IOC_SSID:
2523                 len = sizeof(ssid);
2524                 bzero((char*)&ssid, len);
2525                 error = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len);
2526                 if (error) {
2527                         device_printf(sc->ndis_dev, "failed to get ssid: %d\n", error);
2528                         return(error);
2529                 }
2530                 ireq->i_len = ssid.ns_ssidlen;
2531                 error = copyout(&ssid.ns_ssid, ireq->i_data, ssid.ns_ssidlen);
2532                 break;
2533         case IEEE80211_IOC_SCAN_RESULTS:
2534                 len = 0;
2535                 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
2536                 if (error != ENOSPC)
2537                         break;
2538                 bl = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
2539                 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
2540                 if (error) {
2541                         free(bl, M_DEVBUF);
2542                         break;
2543                 }
2544                 sr = bsr = malloc(ireq->i_len, M_DEVBUF, M_WAITOK | M_ZERO);
2545                 wb = bl->nblx_bssid;
2546                 len = 0;
2547                 for (i = 0; i < bl->nblx_items; i++) {
2548                         /*
2549                          * Check if we have enough space left for this ap
2550                          */
2551                         j = roundup(sizeof(*sr) + wb->nwbx_ssid.ns_ssidlen
2552                             + wb->nwbx_ielen -
2553                             sizeof(struct ndis_80211_fixed_ies),
2554                             sizeof(uint32_t));
2555                         if (len + j > ireq->i_len)
2556                                 break;
2557                         bcopy(&wb->nwbx_macaddr, &sr->isr_bssid,
2558                             sizeof(sr->isr_bssid));
2559                         if (wb->nwbx_privacy)
2560                                 sr->isr_capinfo |= IEEE80211_CAPINFO_PRIVACY;
2561                         sr->isr_rssi = wb->nwbx_rssi + 200;
2562                         sr->isr_freq = wb->nwbx_config.nc_dsconfig / 1000;
2563                         sr->isr_intval = wb->nwbx_config.nc_beaconperiod;
2564                         switch (wb->nwbx_netinfra) {
2565                         case NDIS_80211_NET_INFRA_IBSS:
2566                                 sr->isr_capinfo |= IEEE80211_CAPINFO_IBSS;
2567                                 break;
2568                         case NDIS_80211_NET_INFRA_BSS:
2569                                 sr->isr_capinfo |= IEEE80211_CAPINFO_ESS;
2570                                 break;
2571                         }
2572                         for (j = 0; j < sizeof(sr->isr_rates); j++) {
2573                                 /* XXX - check units */
2574                                 if (wb->nwbx_supportedrates[j] == 0)
2575                                         break;
2576                                 sr->isr_rates[j] =
2577                                     wb->nwbx_supportedrates[j] & 0x7f;
2578                         }
2579                         sr->isr_nrates = j;
2580                         sr->isr_ssid_len = wb->nwbx_ssid.ns_ssidlen;
2581                         cp = (char *)sr + sizeof(*sr);
2582                         bcopy(&wb->nwbx_ssid.ns_ssid, cp, sr->isr_ssid_len);
2583                         cp += sr->isr_ssid_len;
2584                         sr->isr_ie_len = wb->nwbx_ielen
2585                             - sizeof(struct ndis_80211_fixed_ies);
2586                         bcopy((char *)wb->nwbx_ies +
2587                             sizeof(struct ndis_80211_fixed_ies),
2588                             cp, sr->isr_ie_len);
2589                         sr->isr_len = roundup(sizeof(*sr) + sr->isr_ssid_len
2590                             + sr->isr_ie_len, sizeof(uint32_t));
2591                         len += sr->isr_len;
2592                         sr = (struct ieee80211req_scan_result *)((char *)sr +
2593                             sr->isr_len);
2594                         wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
2595                 }
2596                 ireq->i_len = len;
2597                 error = copyout(bsr, ireq->i_data, len);
2598                 free(bl, M_DEVBUF);
2599                 free(bsr, M_DEVBUF);
2600                 break;
2601         case IEEE80211_IOC_STATIONNAME:
2602                 error = ndis_get_info(sc, OID_GEN_MACHINE_NAME,
2603                     &nodename_u, &len);
2604                 if (error)
2605                         break;
2606                 acode = nodename;
2607                 bzero((char *)nodename, IEEE80211_NWID_LEN);
2608                 ndis_unicode_to_ascii(nodename_u, len, &acode);
2609                 ireq->i_len = len / 2 + 1;
2610                 error = copyout(acode, ireq->i_data, ireq->i_len);
2611                 break;
2612         default:
2613                 error = ieee80211_ioctl(&sc->ic, command, data);
2614         }
2615         
2616         return(error);
2617 }
2618
2619 static int
2620 ndis_add_key(sc, wk, i_len)
2621         struct ndis_softc       *sc;
2622         struct ieee80211req_key *wk;
2623         int16_t                 i_len;
2624 {
2625         ndis_80211_key          *rkey;
2626         ndis_80211_wep          *wep;
2627         int                     len, error;
2628         uint32_t                arg;
2629
2630         /* infrastructure mode only supported for now */
2631         len = sizeof(arg);
2632         arg = NDIS_80211_NET_INFRA_BSS;
2633         error = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
2634         if (error) {
2635                 device_printf(sc->ndis_dev,
2636                     "setting infrastructure mode failed\n");
2637                 return(error);
2638         }
2639
2640         switch(wk->ik_type) {
2641         case IEEE80211_CIPHER_WEP:
2642                 len = 12 + wk->ik_keylen;
2643                 wep = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
2644                 if(!wep)
2645                         return(ENOSPC);
2646                 wep->nw_length = len;
2647                 wep->nw_keyidx = wk->ik_keyix;
2648                 wep->nw_keylen = wk->ik_keylen;
2649                 if(wk->ik_flags & IEEE80211_KEY_XMIT)
2650                         wep->nw_keyidx |= 1 << 31;
2651                 device_printf(sc->ndis_dev, "setting wep key\n");
2652                 error = copyin(wk->ik_keydata, wep->nw_keydata, wk->ik_keylen);
2653                 if(error) {
2654                         device_printf(sc->ndis_dev,
2655                             "copyin of wep key to kernel space failed\n");
2656                         free(wep, M_TEMP);
2657                         break;
2658                 }
2659                 error = ndis_set_info(sc, OID_802_11_ADD_WEP, wep, &len);
2660                 if(error) {
2661                         device_printf(sc->ndis_dev,
2662                             "setting wep key failed\n");
2663                         break;
2664                 }
2665                 free(wep, M_TEMP);
2666
2667                 /* set the authentication mode */
2668
2669                 arg = NDIS_80211_AUTHMODE_OPEN;
2670                 error = ndis_set_info(sc,
2671                     OID_802_11_AUTHENTICATION_MODE, &arg, &len);
2672                 if(error) {
2673                         device_printf(sc->ndis_dev,
2674                             "setting authentication mode failed\n");
2675                 }
2676
2677                 /* set the encryption */
2678
2679                 len = sizeof(arg);
2680                 arg = NDIS_80211_WEPSTAT_ENABLED;
2681                 error = ndis_set_info(sc,
2682                     OID_802_11_ENCRYPTION_STATUS, &arg, &len);
2683                 if(error) {
2684                         device_printf(sc->ndis_dev,
2685                             "setting encryption status failed\n");
2686                         return(error);
2687                 }
2688                 break;
2689         case IEEE80211_CIPHER_TKIP:
2690                 len = 12 + 6 + 6 + 8 + wk->ik_keylen;
2691                 rkey = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
2692                 if(!rkey)
2693                         return(ENOSPC);
2694                 rkey->nk_len = len;
2695                 error = copyin(wk->ik_macaddr,
2696                     rkey->nk_bssid, IEEE80211_ADDR_LEN);
2697                 if(error) {
2698                         device_printf(sc->ndis_dev,
2699                             "copyin of bssid to kernel space failed\n");
2700                         free(rkey, M_TEMP);
2701                         break;
2702                 }
2703
2704                 /* keyrsc needs to be fixed: need to do some shifting */
2705                 error = copyin(&(wk->ik_keyrsc),
2706                     &(rkey->nk_keyrsc), sizeof(rkey->nk_keyrsc));
2707                 if(error) {
2708                         device_printf(sc->ndis_dev,
2709                             "copyin of keyrsc to kernel space failed\n");
2710                         free(rkey, M_TEMP);
2711                         break;
2712                 }
2713
2714                 /* key index - gets weird in NDIS */
2715
2716                 rkey->nk_keyidx = wk->ik_keyix;
2717                 if(wk->ik_flags & IEEE80211_KEY_XMIT)
2718                         rkey->nk_keyidx |= 1 << 31;
2719                 if((bcmp(rkey->nk_bssid, "\xff\xff\xff\xff\xff\xff",
2720                     IEEE80211_ADDR_LEN) == 0) ||
2721                    (bcmp(rkey->nk_bssid, "\x0\x0\x0\x0\x0\x0",
2722                     IEEE80211_ADDR_LEN) == 0)) {
2723                         /* group key - nothing to do in ndis */
2724                 } else {
2725                         /* pairwise key */
2726                         rkey->nk_keyidx |= 1 << 30;
2727                 }
2728
2729                 /* need to set bit 29 based on keyrsc */
2730
2731                 rkey->nk_keylen = wk->ik_keylen;
2732                 if (wk->ik_type == IEEE80211_CIPHER_TKIP &&
2733                     wk->ik_keylen == 32) {
2734                         /*
2735                          * key data needs to be offset by 4 due
2736                          * to mismatch between NDIS spec and BSD??
2737                          */
2738                         error = copyin(wk->ik_keydata,
2739                             rkey->nk_keydata + 4, 16);
2740                         if(error) {
2741                                 device_printf(sc->ndis_dev, "copyin of "
2742                                     "keydata(0) to kernel space failed\n");
2743                                 free(rkey, M_TEMP);
2744                                 break;
2745                         }
2746                         error = copyin(wk->ik_keydata + 24,
2747                             rkey->nk_keydata + 20, 8);
2748                         if(error) {
2749                                 device_printf(sc->ndis_dev, "copyin of "
2750                                     "keydata(1) to kernel space failed\n");
2751                                 free(rkey, M_TEMP);
2752                                 break;
2753                         }
2754                         error = copyin(wk->ik_keydata + 16,
2755                             rkey->nk_keydata + 28, 8);
2756                         if(error) {
2757                                 device_printf(sc->ndis_dev, "copyin of "
2758                                     "keydata(2) to kernel space failed\n");
2759                                 free(rkey, M_TEMP);
2760                                 break;
2761                         }
2762                 } else {
2763                         error = copyin(wk->ik_keydata,
2764                             rkey->nk_keydata + 4, wk->ik_keylen);
2765                         if(error) {
2766                                 device_printf(sc->ndis_dev, "copyin of "
2767                                     "keydata(CCMP) to kernel space failed\n");
2768                                 free(rkey, M_TEMP);
2769                                 break;
2770                         }
2771                 }
2772                 error = ndis_set_info(sc, OID_802_11_ADD_KEY, rkey, &len);
2773                 break;
2774         case IEEE80211_CIPHER_AES_CCM:
2775                 return(ENOTTY);
2776         default:
2777                 return(ENOTTY);
2778         }
2779         return(error);
2780 }
2781
2782 static int
2783 ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data)
2784 {
2785         struct ndis_softc       *sc;
2786         struct ieee80211req     *ireq;
2787         int                     error, len, arg, ucnt;
2788         uint8_t                 nodename[IEEE80211_NWID_LEN];
2789         uint16_t                nodename_u[IEEE80211_NWID_LEN + 1];
2790         uint16_t                *ucode;
2791         struct ieee80211req_del_key *rk;
2792         struct ieee80211req_key *wk;
2793         unsigned char           *wpa_ie;
2794         ndis_80211_ssid         ssid;
2795         ndis_80211_remove_key   rkey;
2796
2797         sc = ifp->if_softc;
2798         ireq = (struct ieee80211req *) data;
2799                 
2800         switch (ireq->i_type) {
2801         case IEEE80211_IOC_MLME:
2802         case IEEE80211_IOC_ROAMING:
2803         case IEEE80211_IOC_COUNTERMEASURES:
2804         case IEEE80211_IOC_DROPUNENCRYPTED:
2805                 error = 0;
2806                 break;
2807         case IEEE80211_IOC_PRIVACY:
2808                 len = sizeof(arg);
2809                 arg = NDIS_80211_PRIVFILT_8021XWEP;
2810                 error = ndis_set_info(sc,
2811                     OID_802_11_PRIVACY_FILTER, &arg, &len);
2812                 if (error) {
2813                         device_printf(sc->ndis_dev,
2814                             "setting wep privacy filter failed\n");
2815                         error = 0;
2816                 }
2817                 break;
2818         case IEEE80211_IOC_WPA:
2819                 /* nothing to do */
2820                 error = 0;
2821                 break;
2822         case IEEE80211_IOC_OPTIE:
2823                 wpa_ie = (char*)ireq->i_data;
2824                 if (ireq->i_len < 14 || !wpa_ie) {
2825                         /* cannot figure out anything */ 
2826                         arg = NDIS_80211_AUTHMODE_OPEN;
2827                         error = ndis_set_info(sc,
2828                             OID_802_11_AUTHENTICATION_MODE, &arg, &len);
2829                         return(error);
2830                 }
2831                 if (wpa_ie[0] == IEEE80211_ELEMID_RSN) {
2832                         error = ENOTTY;
2833                         break;
2834                 } else if (wpa_ie[0] == IEEE80211_ELEMID_VENDOR) {
2835
2836                         /* set the encryption based on multicast cipher */
2837
2838                         if (!memcmp(wpa_ie + 8, "\x00\x50\xf2\x02", 4)) {
2839                                 len = sizeof(arg);
2840                                 arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
2841                                 error = ndis_set_info(sc,
2842                                     OID_802_11_ENCRYPTION_STATUS, &arg, &len);
2843                                 if (error) {
2844                                         device_printf(sc->ndis_dev, "setting "
2845                                             "encryption status to "
2846                                             "ENC2 failed\n");
2847                                         /* continue anyway */
2848                                 }
2849                         }
2850                 }
2851
2852                 /* set the authentication mode */
2853
2854                 ucnt = wpa_ie[12] + 256* wpa_ie[13];
2855
2856                 /* 4 bytes per unicast cipher */
2857
2858                 ucnt = 14 + 4*ucnt + 2; /* account for number of authsels */
2859
2860                 if (ireq->i_len < ucnt) {
2861                         arg = NDIS_80211_AUTHMODE_WPANONE;
2862                 } else {
2863                         if (!memcmp((void*)(&wpa_ie[ucnt]),
2864                             "\x00\x50\xf2\x02", 4)) {
2865                                 arg = NDIS_80211_AUTHMODE_WPAPSK;
2866                         } else if (!memcmp((void*)(&wpa_ie[ucnt]),
2867                             "\x00\x50\xf2\x01", 4)) {
2868                                 arg = NDIS_80211_AUTHMODE_WPA;
2869                         } else {
2870                                 arg = NDIS_80211_AUTHMODE_WPANONE;
2871                         }
2872                 }
2873                 len = sizeof(arg);
2874                 error = ndis_set_info(sc,
2875                     OID_802_11_AUTHENTICATION_MODE, &arg, &len);
2876                 if (error) {
2877                         device_printf(sc->ndis_dev,
2878                             "setting authentication mode to WPA-PSK failed\n");
2879                         break;
2880                 }
2881                 break;
2882         case IEEE80211_IOC_SSID:
2883                 len = sizeof(ssid);
2884                 bzero((char*)&ssid, len);
2885                 ssid.ns_ssidlen = ireq->i_len;
2886                 error = copyin(ireq->i_data, &(ssid.ns_ssid), ireq->i_len);
2887                 if (error)
2888                         break;
2889                 device_printf(sc->ndis_dev,
2890                     "setting SSID to %s\n", ssid.ns_ssid);
2891                 error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
2892                 if (error) {
2893                         device_printf(sc->ndis_dev,
2894                             "setting SSID to %s\n", ssid.ns_ssid);
2895                 }
2896                 break;
2897         case IEEE80211_IOC_DELKEY:
2898                 len = sizeof(rkey);
2899                 bzero((char*)&rkey, len);
2900                 rk = (struct ieee80211req_del_key*)ireq->i_data;
2901                 rkey.nk_len = len;
2902                 rkey.nk_keyidx = rk->idk_keyix;
2903                 error = copyin(rk->idk_macaddr,
2904                     &(rkey.nk_bssid), sizeof(ndis_80211_macaddr));
2905                 if (error)
2906                         break;
2907                 error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len);
2908                 if (error)
2909                         device_printf(sc->ndis_dev, "deleting key\n");
2910                 break;
2911         case IEEE80211_IOC_WPAKEY:
2912                 wk = (struct ieee80211req_key*)ireq->i_data;
2913                 error = ndis_add_key(sc, wk, ireq->i_len);
2914                 break;
2915         case IEEE80211_IOC_SCAN_REQ:
2916                 len = 0;
2917                 error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN,
2918                     NULL, &len);
2919                 tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2);
2920                 rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
2921                 break;
2922         case IEEE80211_IOC_STATIONNAME:
2923                 error = suser(curthread);
2924                 if (error)
2925                         break;
2926                 if (ireq->i_val != 0 ||
2927                     ireq->i_len > IEEE80211_NWID_LEN) {
2928                         error = EINVAL;
2929                         break;
2930                 }
2931                 bzero((char *)nodename, IEEE80211_NWID_LEN);
2932                 error = copyin(ireq->i_data, nodename, ireq->i_len);
2933                 if (error)
2934                         break;
2935                 ucode = nodename_u;
2936                 ndis_ascii_to_unicode((char *)nodename, &ucode);
2937                 len = ireq->i_len * 2;
2938                 error = ndis_set_info(sc, OID_GEN_MACHINE_NAME,
2939                     &nodename_u, &len);
2940                 break;
2941         default:
2942                 error = ieee80211_ioctl(&sc->ic, command, data);
2943                 if (error == ENETRESET) {
2944                         ndis_setstate_80211(sc);
2945                         error = 0;
2946                 }
2947         }
2948         
2949         return(error);
2950 }
2951
2952 static void
2953 ndis_resettask(w, arg)
2954         ndis_work_item          *w;
2955         void                    *arg;
2956 {
2957         struct ndis_softc               *sc;
2958
2959         sc = arg;
2960         ndis_reset_nic(sc);
2961         return;
2962 }
2963
2964 static void
2965 ndis_watchdog(ifp)
2966         struct ifnet            *ifp;
2967 {
2968         struct ndis_softc               *sc;
2969
2970         sc = ifp->if_softc;
2971
2972         NDIS_LOCK(sc);
2973         ifp->if_oerrors++;
2974         device_printf(sc->ndis_dev, "watchdog timeout\n");
2975         NDIS_UNLOCK(sc);
2976
2977         NdisScheduleWorkItem(&sc->ndis_resetitem);
2978         NdisScheduleWorkItem(&sc->ndis_startitem);
2979
2980         return;
2981 }
2982
2983 /*
2984  * Stop the adapter and free any mbufs allocated to the
2985  * RX and TX lists.
2986  */
2987 static void
2988 ndis_stop(sc)
2989         struct ndis_softc               *sc;
2990 {
2991         struct ifnet            *ifp;
2992
2993         ifp = &sc->arpcom.ac_if;
2994         untimeout(ndis_tick, sc, sc->ndis_stat_ch);
2995
2996         NDIS_LOCK(sc);
2997         ifp->if_timer = 0;
2998         sc->ndis_link = 0;
2999         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
3000         NDIS_UNLOCK(sc);
3001
3002         ndis_halt_nic(sc);
3003
3004         return;
3005 }
3006
3007 /*
3008  * Stop all chip I/O so that the kernel's probe routines don't
3009  * get confused by errant DMAs when rebooting.
3010  */
3011 void
3012 ndis_shutdown(dev)
3013         device_t                dev;
3014 {
3015         struct ndis_softc               *sc;
3016
3017         sc = device_get_softc(dev);
3018         ndis_shutdown_nic(sc);
3019
3020         return;
3021 }