]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/if_ndis/if_ndis.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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 originally contributed by Arvind Srinivasan <arvind@celar.us>
33  * then hacked upon mercilessly by my.
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/sockio.h>
42 #include <sys/mbuf.h>
43 #include <sys/malloc.h>
44 #include <sys/endian.h>
45 #include <sys/priv.h>
46 #include <sys/kernel.h>
47 #include <sys/socket.h>
48 #include <sys/queue.h>
49 #include <sys/module.h>
50 #include <sys/proc.h>
51 #include <sys/sysctl.h>
52 #include <sys/kthread.h>
53 #include <sys/taskqueue.h>
54
55
56 #include <net/if.h>
57 #include <net/if_arp.h>
58 #include <net/ethernet.h>
59 #include <net/if_dl.h>
60 #include <net/if_media.h>
61 #include <net/if_types.h>
62 #include <net/route.h>
63
64 #include <net/bpf.h>
65
66 #include <machine/bus.h>
67 #include <machine/resource.h>
68 #include <sys/bus.h>
69 #include <sys/rman.h>
70
71 #include <net80211/ieee80211_var.h>
72 #include <net80211/ieee80211_ioctl.h>
73 #include <net80211/ieee80211_regdomain.h>
74
75 #if __FreeBSD_version < 700046
76 #include <dev/wi/if_wavelan_ieee.h>
77 #endif
78
79 #include <dev/pci/pcireg.h>
80 #include <dev/pci/pcivar.h>
81
82 #include <compat/ndis/pe_var.h>
83 #include <compat/ndis/cfg_var.h>
84 #include <compat/ndis/resource_var.h>
85 #include <compat/ndis/ntoskrnl_var.h>
86 #include <compat/ndis/hal_var.h>
87 #include <compat/ndis/ndis_var.h>
88 #include <dev/if_ndis/if_ndisvar.h>
89
90 #define NDIS_DEBUG
91 #ifdef NDIS_DEBUG
92 #define DPRINTF(x)      do { if (ndis_debug > 0) printf x; } while (0)
93 int ndis_debug = 0;
94 SYSCTL_INT(_debug, OID_AUTO, ndis, CTLFLAG_RW, &ndis_debug, 0,
95     "if_ndis debug level");
96 #else
97 #define DPRINTF(x)
98 #endif
99
100 MODULE_DEPEND(ndis, ether, 1, 1, 1);
101 MODULE_DEPEND(ndis, wlan, 1, 1, 1);
102 MODULE_DEPEND(ndis, ndisapi, 1, 1, 1);
103
104 MODULE_VERSION(ndis, 1);
105
106 int ndis_attach                 (device_t);
107 int ndis_detach                 (device_t);
108 int ndis_suspend                (device_t);
109 int ndis_resume                 (device_t);
110 void ndis_shutdown              (device_t);
111
112 int ndisdrv_modevent            (module_t, int, void *);
113
114 static void ndis_txeof          (ndis_handle, ndis_packet *, ndis_status);
115 static void ndis_rxeof          (ndis_handle, ndis_packet **, uint32_t);
116 static void ndis_rxeof_eth      (ndis_handle, ndis_handle, char *, void *,
117                                  uint32_t, void *, uint32_t, uint32_t);
118 static void ndis_rxeof_done     (ndis_handle);
119 static void ndis_rxeof_xfr      (kdpc *, ndis_handle, void *, void *);
120 static void ndis_rxeof_xfr_done (ndis_handle, ndis_packet *,
121                                  uint32_t, uint32_t);
122 static void ndis_linksts        (ndis_handle, ndis_status, void *, uint32_t);
123 static void ndis_linksts_done   (ndis_handle);
124
125 /* We need to wrap these functions for amd64. */
126
127 static funcptr ndis_txeof_wrap;
128 static funcptr ndis_rxeof_wrap;
129 static funcptr ndis_rxeof_eth_wrap;
130 static funcptr ndis_rxeof_done_wrap;
131 static funcptr ndis_rxeof_xfr_wrap;
132 static funcptr ndis_rxeof_xfr_done_wrap;
133 static funcptr ndis_linksts_wrap;
134 static funcptr ndis_linksts_done_wrap;
135 static funcptr ndis_ticktask_wrap;
136 static funcptr ndis_starttask_wrap;
137 static funcptr ndis_resettask_wrap;
138 static funcptr ndis_inputtask_wrap;
139
140 static void ndis_tick           (void *);
141 static void ndis_ticktask       (device_object *, void *);
142 static void ndis_start          (struct ifnet *);
143 static void ndis_starttask      (device_object *, void *);
144 static void ndis_resettask      (device_object *, void *);
145 static void ndis_inputtask      (device_object *, void *);
146 static int ndis_ioctl           (struct ifnet *, u_long, caddr_t);
147 #if __FreeBSD_version < 700046
148 static int ndis_wi_ioctl_get    (struct ifnet *, u_long, caddr_t);
149 static int ndis_wi_ioctl_set    (struct ifnet *, u_long, caddr_t);
150 #endif
151 static int ndis_80211_ioctl_get (struct ifnet *, u_long, caddr_t);
152 static int ndis_80211_ioctl_set (struct ifnet *, u_long, caddr_t);
153 static int ndis_newstate        (struct ieee80211com *, enum ieee80211_state,
154         int);
155 static int ndis_nettype_chan    (uint32_t);
156 static int ndis_nettype_mode    (uint32_t);
157 static void ndis_scan           (void *, int);
158 static void ndis_scan_results   (struct ndis_softc *);
159 static void ndis_scan_start     (struct ieee80211com *);
160 static void ndis_scan_end       (struct ieee80211com *);
161 static void ndis_set_channel    (struct ieee80211com *);
162 static void ndis_scan_curchan   (struct ieee80211com *, unsigned long);
163 static void ndis_scan_mindwell  (struct ieee80211com *);
164 static void ndis_init           (void *);
165 static void ndis_stop           (struct ndis_softc *);
166 static void ndis_watchdog       (struct ifnet *);
167 static int ndis_ifmedia_upd     (struct ifnet *);
168 static void ndis_ifmedia_sts    (struct ifnet *, struct ifmediareq *);
169 static int ndis_get_assoc       (struct ndis_softc *, ndis_wlan_bssid_ex **);
170 static int ndis_probe_offload   (struct ndis_softc *);
171 static int ndis_set_offload     (struct ndis_softc *);
172 static void ndis_getstate_80211 (struct ndis_softc *);
173 static void ndis_setstate_80211 (struct ndis_softc *);
174 #ifdef IEEE80211_F_WPA
175 static int ndis_set_cipher      (struct ndis_softc *, int);
176 static int ndis_set_wpa         (struct ndis_softc *);
177 static int ndis_add_key         (struct ieee80211com *,
178         const struct ieee80211_key *, const u_int8_t []);
179 static int ndis_del_key         (struct ieee80211com *,
180         const struct ieee80211_key *);
181 #endif
182 static void ndis_media_status   (struct ifnet *, struct ifmediareq *);
183
184 static void ndis_setmulti       (struct ndis_softc *);
185 static void ndis_map_sclist     (void *, bus_dma_segment_t *,
186         int, bus_size_t, int);
187
188 static int ndisdrv_loaded = 0;
189
190 /*
191  * This routine should call windrv_load() once for each driver
192  * image. This will do the relocation and dynalinking for the
193  * image, and create a Windows driver object which will be
194  * saved in our driver database.
195  */
196
197 int
198 ndisdrv_modevent(mod, cmd, arg)
199         module_t                mod;
200         int                     cmd;
201         void                    *arg;
202 {
203         int                     error = 0;
204
205         switch (cmd) {
206         case MOD_LOAD:
207                 ndisdrv_loaded++;
208                 if (ndisdrv_loaded > 1)
209                         break;
210                 windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap,
211                     3, WINDRV_WRAP_STDCALL);
212                 windrv_wrap((funcptr)ndis_rxeof_eth, &ndis_rxeof_eth_wrap,
213                     8, WINDRV_WRAP_STDCALL);
214                 windrv_wrap((funcptr)ndis_rxeof_done, &ndis_rxeof_done_wrap,
215                     1, WINDRV_WRAP_STDCALL);
216                 windrv_wrap((funcptr)ndis_rxeof_xfr, &ndis_rxeof_xfr_wrap,
217                     4, WINDRV_WRAP_STDCALL);
218                 windrv_wrap((funcptr)ndis_rxeof_xfr_done,
219                     &ndis_rxeof_xfr_done_wrap, 4, WINDRV_WRAP_STDCALL);
220                 windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap,
221                     3, WINDRV_WRAP_STDCALL);
222                 windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap,
223                     4, WINDRV_WRAP_STDCALL);
224                 windrv_wrap((funcptr)ndis_linksts_done,
225                     &ndis_linksts_done_wrap, 1, WINDRV_WRAP_STDCALL);
226                 windrv_wrap((funcptr)ndis_ticktask, &ndis_ticktask_wrap,
227                     2, WINDRV_WRAP_STDCALL);
228                 windrv_wrap((funcptr)ndis_starttask, &ndis_starttask_wrap,
229                     2, WINDRV_WRAP_STDCALL);
230                 windrv_wrap((funcptr)ndis_resettask, &ndis_resettask_wrap,
231                     2, WINDRV_WRAP_STDCALL);
232                 windrv_wrap((funcptr)ndis_inputtask, &ndis_inputtask_wrap,
233                     2, WINDRV_WRAP_STDCALL);
234                 break;
235         case MOD_UNLOAD:
236                 ndisdrv_loaded--;
237                 if (ndisdrv_loaded > 0)
238                         break;
239                 /* fallthrough */
240         case MOD_SHUTDOWN:
241                 windrv_unwrap(ndis_rxeof_wrap);
242                 windrv_unwrap(ndis_rxeof_eth_wrap);
243                 windrv_unwrap(ndis_rxeof_done_wrap);
244                 windrv_unwrap(ndis_rxeof_xfr_wrap);
245                 windrv_unwrap(ndis_rxeof_xfr_done_wrap);
246                 windrv_unwrap(ndis_txeof_wrap);
247                 windrv_unwrap(ndis_linksts_wrap);
248                 windrv_unwrap(ndis_linksts_done_wrap);
249                 windrv_unwrap(ndis_ticktask_wrap);
250                 windrv_unwrap(ndis_starttask_wrap);
251                 windrv_unwrap(ndis_resettask_wrap);
252                 windrv_unwrap(ndis_inputtask_wrap);
253                 break;
254         default:
255                 error = EINVAL;
256                 break;
257         }
258
259         return (error);
260 }
261
262 /*
263  * Program the 64-bit multicast hash filter.
264  */
265 static void
266 ndis_setmulti(sc)
267         struct ndis_softc       *sc;
268 {
269         struct ifnet            *ifp;
270         struct ifmultiaddr      *ifma;
271         int                     len, mclistsz, error;
272         uint8_t                 *mclist;
273
274         ifp = sc->ifp;
275
276         if (!NDIS_INITIALIZED(sc))
277                 return;
278
279         if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
280                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
281                 len = sizeof(sc->ndis_filter);
282                 error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
283                     &sc->ndis_filter, &len);
284                 if (error)
285                         device_printf (sc->ndis_dev,
286                             "set allmulti failed: %d\n", error);
287                 return;
288         }
289
290         if (TAILQ_EMPTY(&ifp->if_multiaddrs))
291                 return;
292
293         len = sizeof(mclistsz);
294         ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len);
295
296         mclist = malloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_NOWAIT|M_ZERO);
297
298         if (mclist == NULL) {
299                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
300                 goto out;
301         }
302
303         sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST;
304
305         len = 0;
306         IF_ADDR_LOCK(ifp);
307         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
308                 if (ifma->ifma_addr->sa_family != AF_LINK)
309                         continue;
310                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
311                     mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN);
312                 len++;
313                 if (len > mclistsz) {
314                         IF_ADDR_UNLOCK(ifp);
315                         sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
316                         sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
317                         goto out;
318                 }
319         }
320         IF_ADDR_UNLOCK(ifp);
321
322         len = len * ETHER_ADDR_LEN;
323         error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len);
324         if (error) {
325                 device_printf (sc->ndis_dev, "set mclist failed: %d\n", error);
326                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
327                 sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
328         }
329
330 out:
331         free(mclist, M_TEMP);
332
333         len = sizeof(sc->ndis_filter);
334         error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
335             &sc->ndis_filter, &len);
336         if (error)
337                 device_printf (sc->ndis_dev, "set multi failed: %d\n", error);
338
339         return;
340 }
341
342 static int
343 ndis_set_offload(sc)
344         struct ndis_softc       *sc;
345 {
346         ndis_task_offload       *nto;
347         ndis_task_offload_hdr   *ntoh;
348         ndis_task_tcpip_csum    *nttc;
349         struct ifnet            *ifp;
350         int                     len, error;
351
352         ifp = sc->ifp;
353
354         if (!NDIS_INITIALIZED(sc))
355                 return(EINVAL);
356
357         /* See if there's anything to set. */
358
359         error = ndis_probe_offload(sc);
360         if (error)
361                 return(error);
362                 
363         if (sc->ndis_hwassist == 0 && ifp->if_capabilities == 0)
364                 return(0);
365
366         len = sizeof(ndis_task_offload_hdr) + sizeof(ndis_task_offload) +
367             sizeof(ndis_task_tcpip_csum);
368
369         ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
370
371         if (ntoh == NULL)
372                 return(ENOMEM);
373
374         ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
375         ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
376         ntoh->ntoh_offset_firsttask = sizeof(ndis_task_offload_hdr);
377         ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
378         ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
379         ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
380
381         nto = (ndis_task_offload *)((char *)ntoh +
382             ntoh->ntoh_offset_firsttask);
383
384         nto->nto_vers = NDIS_TASK_OFFLOAD_VERSION;
385         nto->nto_len = sizeof(ndis_task_offload);
386         nto->nto_task = NDIS_TASK_TCPIP_CSUM;
387         nto->nto_offset_nexttask = 0;
388         nto->nto_taskbuflen = sizeof(ndis_task_tcpip_csum);
389
390         nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
391
392         if (ifp->if_capenable & IFCAP_TXCSUM)
393                 nttc->nttc_v4tx = sc->ndis_v4tx;
394
395         if (ifp->if_capenable & IFCAP_RXCSUM)
396                 nttc->nttc_v4rx = sc->ndis_v4rx;
397
398         error = ndis_set_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
399         free(ntoh, M_TEMP);
400
401         return(error);
402 }
403
404 static int
405 ndis_probe_offload(sc)
406         struct ndis_softc       *sc;
407 {
408         ndis_task_offload       *nto;
409         ndis_task_offload_hdr   *ntoh;
410         ndis_task_tcpip_csum    *nttc = NULL;
411         struct ifnet            *ifp;
412         int                     len, error, dummy;
413
414         ifp = sc->ifp;
415
416         len = sizeof(dummy);
417         error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, &dummy, &len);
418
419         if (error != ENOSPC)
420                 return(error);
421
422         ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
423
424         if (ntoh == NULL)
425                 return(ENOMEM);
426
427         ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
428         ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
429         ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
430         ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
431         ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
432
433         error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
434
435         if (error) {
436                 free(ntoh, M_TEMP);
437                 return(error);
438         }
439
440         if (ntoh->ntoh_vers != NDIS_TASK_OFFLOAD_VERSION) {
441                 free(ntoh, M_TEMP);
442                 return(EINVAL);
443         }
444
445         nto = (ndis_task_offload *)((char *)ntoh +
446             ntoh->ntoh_offset_firsttask);
447
448         while (1) {
449                 switch (nto->nto_task) {
450                 case NDIS_TASK_TCPIP_CSUM:
451                         nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
452                         break;
453                 /* Don't handle these yet. */
454                 case NDIS_TASK_IPSEC:
455                 case NDIS_TASK_TCP_LARGESEND:
456                 default:
457                         break;
458                 }
459                 if (nto->nto_offset_nexttask == 0)
460                         break;
461                 nto = (ndis_task_offload *)((char *)nto +
462                     nto->nto_offset_nexttask);
463         }
464
465         if (nttc == NULL) {
466                 free(ntoh, M_TEMP);
467                 return(ENOENT);
468         }
469
470         sc->ndis_v4tx = nttc->nttc_v4tx;
471         sc->ndis_v4rx = nttc->nttc_v4rx;
472
473         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_IP_CSUM)
474                 sc->ndis_hwassist |= CSUM_IP;
475         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
476                 sc->ndis_hwassist |= CSUM_TCP;
477         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
478                 sc->ndis_hwassist |= CSUM_UDP;
479
480         if (sc->ndis_hwassist)
481                 ifp->if_capabilities |= IFCAP_TXCSUM;
482
483         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_IP_CSUM)
484                 ifp->if_capabilities |= IFCAP_RXCSUM;
485         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
486                 ifp->if_capabilities |= IFCAP_RXCSUM;
487         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
488                 ifp->if_capabilities |= IFCAP_RXCSUM;
489
490         free(ntoh, M_TEMP);
491         return(0);
492 }
493
494 static int
495 ndis_nettype_chan(uint32_t type)
496 {
497         switch (type) {
498         case NDIS_80211_NETTYPE_11FH:           return (IEEE80211_CHAN_FHSS);
499         case NDIS_80211_NETTYPE_11DS:           return (IEEE80211_CHAN_B);
500         case NDIS_80211_NETTYPE_11OFDM5:        return (IEEE80211_CHAN_A);
501         case NDIS_80211_NETTYPE_11OFDM24:       return (IEEE80211_CHAN_G);
502         }
503         DPRINTF(("unknown channel nettype %d\n", type));
504         return (IEEE80211_CHAN_B);      /* Default to 11B chan */
505 }
506
507 static int
508 ndis_nettype_mode(uint32_t type)
509 {
510         switch (type) {
511         case NDIS_80211_NETTYPE_11FH:           return (IEEE80211_MODE_FH);
512         case NDIS_80211_NETTYPE_11DS:           return (IEEE80211_MODE_11B);
513         case NDIS_80211_NETTYPE_11OFDM5:        return (IEEE80211_MODE_11A);
514         case NDIS_80211_NETTYPE_11OFDM24:       return (IEEE80211_MODE_11G);
515         }
516         DPRINTF(("unknown mode nettype %d\n", type));
517         return (IEEE80211_MODE_AUTO);
518 }
519
520 /*
521  * Attach the interface. Allocate softc structures, do ifmedia
522  * setup and ethernet/BPF attach.
523  */
524 int
525 ndis_attach(dev)
526         device_t                dev;
527 {
528         u_char                  eaddr[ETHER_ADDR_LEN];
529         struct ndis_softc       *sc;
530         driver_object           *pdrv;
531         device_object           *pdo;
532         struct ifnet            *ifp = NULL;
533         int                     error = 0, len, mode, bands = 0;
534         int                     i;
535
536         sc = device_get_softc(dev);
537 #if __FreeBSD_version < 600031
538         sc->ifp = &sc->arpcom.ac_if;
539         ifp = sc->ifp;
540 #else
541         ifp = sc->ifp = if_alloc(IFT_ETHER);
542         if (ifp == NULL) {
543                 error = ENOSPC;
544                 goto fail;
545         }
546 #endif
547         ifp->if_softc = sc;
548
549         KeInitializeSpinLock(&sc->ndis_spinlock);
550         KeInitializeSpinLock(&sc->ndis_rxlock);
551         InitializeListHead(&sc->ndis_shlist);
552
553         if (sc->ndis_iftype == PCMCIABus) {
554                 error = ndis_alloc_amem(sc);
555                 if (error) {
556                         device_printf(dev, "failed to allocate "
557                             "attribute memory\n");
558                         goto fail;
559                 }
560         }
561
562 #if __FreeBSD_version < 502113
563         sysctl_ctx_init(&sc->ndis_ctx);
564 #endif
565
566         /* Create sysctl registry nodes */
567         ndis_create_sysctls(sc);
568
569         /* Find the PDO for this device instance. */
570
571         if (sc->ndis_iftype == PCIBus)
572                 pdrv = windrv_lookup(0, "PCI Bus");
573         else if (sc->ndis_iftype == PCMCIABus)
574                 pdrv = windrv_lookup(0, "PCCARD Bus");
575         else
576                 pdrv = windrv_lookup(0, "USB Bus");
577         pdo = windrv_find_pdo(pdrv, dev);
578
579         /*
580          * Create a new functional device object for this
581          * device. This is what creates the miniport block
582          * for this device instance.
583          */
584
585         if (NdisAddDevice(sc->ndis_dobj, pdo) != STATUS_SUCCESS) {
586                 device_printf(dev, "failed to create FDO!\n");
587                 error = ENXIO;
588                 goto fail;
589         }
590
591         /* Tell the user what version of the API the driver is using. */
592         device_printf(dev, "NDIS API version: %d.%d\n",
593             sc->ndis_chars->nmc_version_major,
594             sc->ndis_chars->nmc_version_minor);
595
596         /* Do resource conversion. */
597         if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus)
598                 ndis_convert_res(sc);
599         else
600                 sc->ndis_block->nmb_rlist = NULL;
601
602         /* Install our RX and TX interrupt handlers. */
603         sc->ndis_block->nmb_senddone_func = ndis_txeof_wrap;
604         sc->ndis_block->nmb_pktind_func = ndis_rxeof_wrap;
605         sc->ndis_block->nmb_ethrxindicate_func = ndis_rxeof_eth_wrap;
606         sc->ndis_block->nmb_ethrxdone_func = ndis_rxeof_done_wrap;
607         sc->ndis_block->nmb_tdcond_func = ndis_rxeof_xfr_done_wrap;
608
609         /* Override the status handler so we can detect link changes. */
610         sc->ndis_block->nmb_status_func = ndis_linksts_wrap;
611         sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap;
612
613         /* Set up work item handlers. */
614         sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
615         sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
616         sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
617         sc->ndis_inputitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
618         KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block);
619
620         /* make sure drv flags are all cleared before initing the NIC. */
621
622         ifp->if_drv_flags = 0;
623
624         /* Call driver's init routine. */
625         if (ndis_init_nic(sc)) {
626                 device_printf (dev, "init handler failed\n");
627                 error = ENXIO;
628                 goto fail;
629         }
630
631         /*
632          * Get station address from the driver.
633          */
634         len = sizeof(eaddr);
635         ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len);
636
637         /*
638          * Figure out how big to make the TX buffer pool.
639          */
640
641         len = sizeof(sc->ndis_maxpkts);
642         if (ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS,
643                     &sc->ndis_maxpkts, &len)) {
644                 device_printf (dev, "failed to get max TX packets\n");
645                 error = ENXIO;
646                 goto fail;
647         }
648
649         /*
650          * If this is a deserialized miniport, we don't have
651          * to honor the OID_GEN_MAXIMUM_SEND_PACKETS result.
652          */
653
654         if (!NDIS_SERIALIZED(sc->ndis_block))
655                 sc->ndis_maxpkts = NDIS_TXPKTS;
656
657         /* Enforce some sanity, just in case. */
658
659         if (sc->ndis_maxpkts == 0)
660                 sc->ndis_maxpkts = 10;
661
662         sc->ndis_txarray = malloc(sizeof(ndis_packet *) *
663             sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT|M_ZERO);
664
665         /* Allocate a pool of ndis_packets for TX encapsulation. */
666
667         NdisAllocatePacketPool(&i, &sc->ndis_txpool,
668             sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET);
669
670         if (i != NDIS_STATUS_SUCCESS) {
671                 sc->ndis_txpool = NULL;
672                 device_printf(dev, "failed to allocate TX packet pool");
673                 error = ENOMEM;
674                 goto fail;
675         }
676
677         sc->ndis_txpending = sc->ndis_maxpkts;
678
679         sc->ndis_oidcnt = 0;
680         /* Get supported oid list. */
681         ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt);
682
683         /* If the NDIS module requested scatter/gather, init maps. */
684         if (sc->ndis_sc)
685                 ndis_init_dma(sc);
686
687         /*
688          * See if the OID_802_11_CONFIGURATION OID is
689          * supported by this driver. If it is, then this an 802.11
690          * wireless driver, and we should set up media for wireless.
691          */
692         for (i = 0; i < sc->ndis_oidcnt; i++) {
693                 if (sc->ndis_oids[i] == OID_802_11_CONFIGURATION) {
694                         sc->ndis_80211++;
695                         break;
696                 }
697         }
698
699         /* Check for task offload support. */
700         ndis_probe_offload(sc);
701
702 #if __FreeBSD_version < 502109
703         /*
704          * An NDIS device was detected. Inform the world.
705          */
706         device_printf(dev, "%s address: %6D\n",
707             sc->ndis_80211 ? "802.11" : "Ethernet", eaddr, ":");
708 #endif
709
710         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
711         ifp->if_mtu = ETHERMTU;
712         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
713         ifp->if_ioctl = ndis_ioctl;
714         ifp->if_start = ndis_start;
715         ifp->if_watchdog = ndis_watchdog;
716         ifp->if_init = ndis_init;
717         ifp->if_baudrate = 10000000;
718 #if __FreeBSD_version < 502114
719         ifp->if_snd.ifq_maxlen = 50;
720 #else
721         IFQ_SET_MAXLEN(&ifp->if_snd, 50);
722         ifp->if_snd.ifq_drv_maxlen = 25;
723         IFQ_SET_READY(&ifp->if_snd);
724 #endif
725         ifp->if_capenable = ifp->if_capabilities;
726         ifp->if_hwassist = sc->ndis_hwassist;
727
728         /* Do media setup */
729         if (sc->ndis_80211) {
730                 struct ieee80211com     *ic = (void *)&sc->ic;
731                 ndis_80211_rates_ex     rates;
732                 struct ndis_80211_nettype_list *ntl;
733                 uint32_t                arg;
734                 int                     r;
735
736 #if __FreeBSD_version >= 700000
737                 sc->ndis_tq = taskqueue_create("nids_taskq", M_NOWAIT | M_ZERO,
738                     taskqueue_thread_enqueue, &sc->ndis_tq);
739                 taskqueue_start_threads(&sc->ndis_tq, 1, PI_NET, "%s taskq",
740                     device_get_nameunit(dev));
741 #else
742                 sc->ndis_tq = taskqueue_create("ndis_taskq", M_NOWAIT | M_ZERO,
743                     taskqueue_thread_enqueue, &sc->ndis_tq, &sc->sc_tqproc);
744                 kthread_create(taskqueue_thread_loop, &sc->ndis_tq, &sc->sc_tqproc,
745                     0, 0, "%s taskq", device_get_nameunit(dev));
746 #endif
747                 TASK_INIT(&sc->ndis_scantask, 0, ndis_scan, sc);
748
749 #if __FreeBSD_version >= 600007
750                 ic->ic_ifp = ifp;
751 #endif
752                 ic->ic_phytype = IEEE80211_T_DS;
753                 ic->ic_opmode = IEEE80211_M_STA;
754                 ic->ic_caps = IEEE80211_C_IBSS;
755                 setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO);
756                 len = 0;
757                 r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
758                     NULL, &len);
759                 if (r != ENOSPC)
760                         goto nonettypes;
761                 ntl = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
762                 r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
763                     ntl, &len);
764                 if (r != 0) {
765                         free(ntl, M_DEVBUF);
766                         goto nonettypes;
767                 }
768
769                 for (i = 0; i < ntl->ntl_items; i++) {
770                         mode = ndis_nettype_mode(ntl->ntl_type[i]);
771                         if (mode) {
772                                 setbit(ic->ic_modecaps, mode);
773                                 setbit(&bands, mode);
774                         } else
775                                 device_printf(dev, "Unknown nettype %d\n",
776                                     ntl->ntl_type[i]);
777                 }
778                 free(ntl, M_DEVBUF);
779 nonettypes:
780                 /* Default to 11b channels if the card did not supply any */
781                 if (bands == 0) {
782                         setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
783                         setbit(&bands, IEEE80211_MODE_11B);
784                 }
785                 len = sizeof(rates);
786                 bzero((char *)&rates, len);
787                 r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES,
788                     (void *)rates, &len);
789                 if (r)
790                         device_printf (dev, "get rates failed: 0x%x\n", r);
791                 /*
792                  * Since the supported rates only up to 8 can be supported,
793                  * if this is not 802.11b we're just going to be faking it
794                  * all up to heck.
795                  */
796
797 #define TESTSETRATE(x, y)                                               \
798         do {                                                            \
799                 int                     i;                              \
800                 for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) {   \
801                         if (ic->ic_sup_rates[x].rs_rates[i] == (y))     \
802                                 break;                                  \
803                 }                                                       \
804                 if (i == ic->ic_sup_rates[x].rs_nrates) {               \
805                         ic->ic_sup_rates[x].rs_rates[i] = (y);          \
806                         ic->ic_sup_rates[x].rs_nrates++;                \
807                 }                                                       \
808         } while (0)
809
810 #define SETRATE(x, y)   \
811         ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y)
812 #define INCRATE(x)      \
813         ic->ic_sup_rates[x].rs_nrates++
814
815                 ic->ic_curmode = IEEE80211_MODE_AUTO;
816                 if (isset(ic->ic_modecaps, IEEE80211_MODE_11A))
817                         ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0;
818                 if (isset(ic->ic_modecaps, IEEE80211_MODE_11B))
819                         ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0;
820                 if (isset(ic->ic_modecaps, IEEE80211_MODE_11G))
821                         ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0;
822                 for (i = 0; i < len; i++) {
823                         switch (rates[i] & IEEE80211_RATE_VAL) {
824                         case 2:
825                         case 4:
826                         case 11:
827                         case 10:
828                         case 22:
829                                 if (isclr(ic->ic_modecaps, IEEE80211_MODE_11B)) {
830                                         /* Lazy-init 802.11b. */
831                                         setbit(ic->ic_modecaps,
832                                             IEEE80211_MODE_11B);
833                                         ic->ic_sup_rates[IEEE80211_MODE_11B].
834                                             rs_nrates = 0;
835                                 }
836                                 SETRATE(IEEE80211_MODE_11B, rates[i]);
837                                 INCRATE(IEEE80211_MODE_11B);
838                                 break;
839                         default:
840                                 if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) {
841                                         SETRATE(IEEE80211_MODE_11A, rates[i]);
842                                         INCRATE(IEEE80211_MODE_11A);
843                                 }
844                                 if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) {
845                                         SETRATE(IEEE80211_MODE_11G, rates[i]);
846                                         INCRATE(IEEE80211_MODE_11G);
847                                 }
848                                 break;
849                         }
850                 }
851
852                 /*
853                  * If the hardware supports 802.11g, it most
854                  * likely supports 802.11b and all of the
855                  * 802.11b and 802.11g speeds, so maybe we can
856                  * just cheat here.  Just how in the heck do
857                  * we detect turbo modes, though?
858                  */
859                 if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) {
860                         TESTSETRATE(IEEE80211_MODE_11B,
861                             IEEE80211_RATE_BASIC|2);
862                         TESTSETRATE(IEEE80211_MODE_11B,
863                             IEEE80211_RATE_BASIC|4);
864                         TESTSETRATE(IEEE80211_MODE_11B,
865                             IEEE80211_RATE_BASIC|11);
866                         TESTSETRATE(IEEE80211_MODE_11B,
867                             IEEE80211_RATE_BASIC|22);
868                 }
869                 if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) {
870                         TESTSETRATE(IEEE80211_MODE_11G, 48);
871                         TESTSETRATE(IEEE80211_MODE_11G, 72);
872                         TESTSETRATE(IEEE80211_MODE_11G, 96);
873                         TESTSETRATE(IEEE80211_MODE_11G, 108);
874                 }
875                 if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) {
876                         TESTSETRATE(IEEE80211_MODE_11A, 48);
877                         TESTSETRATE(IEEE80211_MODE_11A, 72);
878                         TESTSETRATE(IEEE80211_MODE_11A, 96);
879                         TESTSETRATE(IEEE80211_MODE_11A, 108);
880                 }
881 #undef SETRATE
882 #undef INCRATE
883                 ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
884
885                 /*
886                  * To test for WPA support, we need to see if we can
887                  * set AUTHENTICATION_MODE to WPA and read it back
888                  * successfully.
889                  */
890 #ifdef IEEE80211_F_WPA
891                 i = sizeof(arg);
892                 arg = NDIS_80211_AUTHMODE_WPA;
893                 r = ndis_set_info(sc,
894                     OID_802_11_AUTHENTICATION_MODE, &arg, &i);
895                 if (r == 0) {
896                         r = ndis_get_info(sc,
897                             OID_802_11_AUTHENTICATION_MODE, &arg, &i);
898                         if (r == 0 && arg == NDIS_80211_AUTHMODE_WPA)
899                                 ic->ic_caps |= IEEE80211_C_WPA;
900                 }
901
902                 /*
903                  * To test for supported ciphers, we set each
904                  * available encryption type in descending order.
905                  * If ENC3 works, then we have WEP, TKIP and AES.
906                  * If only ENC2 works, then we have WEP and TKIP.
907                  * If only ENC1 works, then we have just WEP.
908                  */
909                 i = sizeof(arg);
910                 arg = NDIS_80211_WEPSTAT_ENC3ENABLED;
911                 r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
912                 if (r == 0) {
913                         ic->ic_caps |= IEEE80211_C_WEP|IEEE80211_C_TKIP|
914                             IEEE80211_C_AES_CCM;
915                         goto got_crypto;
916                 }
917                 arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
918                 r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
919                 if (r == 0) {
920                         ic->ic_caps |= IEEE80211_C_WEP|IEEE80211_C_TKIP;
921                         goto got_crypto;
922                 }
923 #endif
924                 arg = NDIS_80211_WEPSTAT_ENC1ENABLED;
925                 r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
926                 if (r == 0)
927                         ic->ic_caps |= IEEE80211_C_WEP;
928 #ifdef IEEE80211_F_WPA
929 got_crypto:
930 #endif
931                 i = sizeof(arg);
932                 r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i);
933                 if (r == 0)
934                         ic->ic_caps |= IEEE80211_C_PMGT;
935                 bcopy(eaddr, &ic->ic_myaddr, sizeof(eaddr));
936 #if __FreeBSD_version < 600007
937                 ieee80211_ifattach(ifp);
938                 ieee80211_media_init(ifp, ieee80211_media_change,
939                     ndis_media_status);
940 #else
941                 ieee80211_ifattach(ic);
942                 ieee80211_media_init(ic, ieee80211_media_change,
943                     ndis_media_status);
944 #endif
945                 ic->ic_scan_start = ndis_scan_start;
946                 ic->ic_scan_end = ndis_scan_end;
947                 ic->ic_set_channel = ndis_set_channel;
948                 ic->ic_scan_curchan = ndis_scan_curchan;
949                 ic->ic_scan_mindwell = ndis_scan_mindwell;
950                 ic->ic_bsschan = IEEE80211_CHAN_ANYC;
951                 ic->ic_bss->ni_chan = ic->ic_bsschan;
952                 /* override state transition machine */
953                 sc->ndis_newstate = ic->ic_newstate;
954                 ic->ic_newstate = ndis_newstate;
955 #ifdef IEEE80211_F_WPA
956                 /* install key handing routines */
957                 ic->ic_crypto.cs_key_set = ndis_add_key;
958                 ic->ic_crypto.cs_key_delete = ndis_del_key;
959 #endif
960         } else {
961                 ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd,
962                     ndis_ifmedia_sts);
963                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
964                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
965                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
966                 ifmedia_add(&sc->ifmedia,
967                     IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
968                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
969                 ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
970                 ether_ifattach(ifp, eaddr);
971         }
972
973 fail:
974         if (error)
975                 ndis_detach(dev);
976         else
977                 /* We're done talking to the NIC for now; halt it. */
978                 ndis_halt_nic(sc);
979
980         return(error);
981 }
982
983 /*
984  * Shutdown hardware and free up resources. This can be called any
985  * time after the mutex has been initialized. It is called in both
986  * the error case in attach and the normal detach case so it needs
987  * to be careful about only freeing resources that have actually been
988  * allocated.
989  */
990 int
991 ndis_detach(dev)
992         device_t                dev;
993 {
994         struct ndis_softc       *sc;
995         struct ifnet            *ifp;
996         driver_object           *drv;
997
998         sc = device_get_softc(dev);
999         NDIS_LOCK(sc);
1000         ifp = sc->ifp;
1001         ifp->if_flags &= ~IFF_UP;
1002
1003         if (device_is_attached(dev)) {
1004                 NDIS_UNLOCK(sc);
1005                 ndis_stop(sc);
1006                 if (sc->ndis_80211)
1007 #if __FreeBSD_version < 600007
1008                         ieee80211_ifdetach(ifp);
1009 #else
1010                         ieee80211_ifdetach(&sc->ic);
1011 #endif
1012                 else
1013                         ether_ifdetach(ifp);
1014         } else
1015                 NDIS_UNLOCK(sc);
1016
1017         taskqueue_drain(sc->ndis_tq, &sc->ndis_scantask);
1018
1019         if (sc->ndis_tickitem != NULL)
1020                 IoFreeWorkItem(sc->ndis_tickitem);
1021         if (sc->ndis_startitem != NULL)
1022                 IoFreeWorkItem(sc->ndis_startitem);
1023         if (sc->ndis_resetitem != NULL)
1024                 IoFreeWorkItem(sc->ndis_resetitem);
1025         if (sc->ndis_inputitem != NULL)
1026                 IoFreeWorkItem(sc->ndis_inputitem);
1027
1028         bus_generic_detach(dev);
1029         ndis_unload_driver(sc);
1030
1031         if (sc->ndis_irq)
1032                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq);
1033         if (sc->ndis_res_io)
1034                 bus_release_resource(dev, SYS_RES_IOPORT,
1035                     sc->ndis_io_rid, sc->ndis_res_io);
1036         if (sc->ndis_res_mem)
1037                 bus_release_resource(dev, SYS_RES_MEMORY,
1038                     sc->ndis_mem_rid, sc->ndis_res_mem);
1039         if (sc->ndis_res_altmem)
1040                 bus_release_resource(dev, SYS_RES_MEMORY,
1041                     sc->ndis_altmem_rid, sc->ndis_res_altmem);
1042
1043 #if __FreeBSD_version >= 600031
1044         if (ifp != NULL)
1045                 if_free(ifp);
1046 #endif
1047
1048         if (sc->ndis_iftype == PCMCIABus)
1049                 ndis_free_amem(sc);
1050
1051         if (sc->ndis_sc)
1052                 ndis_destroy_dma(sc);
1053
1054         if (sc->ndis_txarray)
1055                 free(sc->ndis_txarray, M_DEVBUF);
1056
1057         if (!sc->ndis_80211)
1058                 ifmedia_removeall(&sc->ifmedia);
1059
1060         if (sc->ndis_txpool != NULL)
1061                 NdisFreePacketPool(sc->ndis_txpool);
1062
1063         /* Destroy the PDO for this device. */
1064         
1065         if (sc->ndis_iftype == PCIBus)
1066                 drv = windrv_lookup(0, "PCI Bus");
1067         else if (sc->ndis_iftype == PCMCIABus)
1068                 drv = windrv_lookup(0, "PCCARD Bus");
1069         else
1070                 drv = windrv_lookup(0, "USB Bus");
1071         if (drv == NULL)
1072                 panic("couldn't find driver object");
1073         windrv_destroy_pdo(drv, dev);
1074
1075         if (sc->ndis_iftype == PCIBus)
1076                 bus_dma_tag_destroy(sc->ndis_parent_tag);
1077
1078         taskqueue_free(sc->ndis_tq);
1079 #if __FreeBSD_version < 502113
1080         sysctl_ctx_free(&sc->ndis_ctx);
1081 #endif
1082
1083         return(0);
1084 }
1085
1086 int
1087 ndis_suspend(dev)
1088         device_t                dev;
1089 {
1090         struct ndis_softc       *sc;
1091         struct ifnet            *ifp;
1092
1093         sc = device_get_softc(dev);
1094         ifp = sc->ifp;
1095
1096 #ifdef notdef
1097         if (NDIS_INITIALIZED(sc))
1098                 ndis_stop(sc);
1099 #endif
1100
1101         return(0);
1102 }
1103
1104 int
1105 ndis_resume(dev)
1106         device_t                dev;
1107 {
1108         struct ndis_softc       *sc;
1109         struct ifnet            *ifp;
1110
1111         sc = device_get_softc(dev);
1112         ifp = sc->ifp;
1113
1114         if (NDIS_INITIALIZED(sc))
1115                 ndis_init(sc);
1116
1117         return(0);
1118 }
1119
1120 /*
1121  * The following bunch of routines are here to support drivers that
1122  * use the NdisMEthIndicateReceive()/MiniportTransferData() mechanism.
1123  * The NdisMEthIndicateReceive() handler runs at DISPATCH_LEVEL for
1124  * serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
1125  * miniports.
1126  */
1127  
1128 static void
1129 ndis_rxeof_eth(adapter, ctx, addr, hdr, hdrlen, lookahead, lookaheadlen, pktlen)
1130         ndis_handle             adapter;
1131         ndis_handle             ctx;
1132         char                    *addr;
1133         void                    *hdr;
1134         uint32_t                hdrlen;
1135         void                    *lookahead;
1136         uint32_t                lookaheadlen;
1137         uint32_t                pktlen;
1138 {
1139         ndis_miniport_block     *block;
1140         uint8_t                 irql = 0;
1141         uint32_t                status;
1142         ndis_buffer             *b;
1143         ndis_packet             *p;
1144         struct mbuf             *m;
1145         ndis_ethpriv            *priv;
1146
1147         block = adapter;
1148
1149         m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1150
1151         if (m == NULL) {
1152                 NdisFreePacket(p);
1153                 return;
1154         }
1155
1156         /* Save the data provided to us so far. */
1157
1158         m->m_len = lookaheadlen + hdrlen;
1159         m->m_pkthdr.len = pktlen + hdrlen;
1160         m->m_next = NULL;
1161         m_copyback(m, 0, hdrlen, hdr);
1162         m_copyback(m, hdrlen, lookaheadlen, lookahead);
1163
1164         /* Now create a fake NDIS_PACKET to hold the data */
1165
1166         NdisAllocatePacket(&status, &p, block->nmb_rxpool);
1167
1168         if (status != NDIS_STATUS_SUCCESS) {
1169                 m_freem(m);
1170                 return;
1171         }
1172
1173         p->np_m0 = m;
1174
1175         b = IoAllocateMdl(m->m_data, m->m_pkthdr.len, FALSE, FALSE, NULL);
1176
1177         if (b == NULL) {
1178                 NdisFreePacket(p);
1179                 m_freem(m);
1180                 return;
1181         }
1182
1183         p->np_private.npp_head = p->np_private.npp_tail = b;
1184         p->np_private.npp_totlen = m->m_pkthdr.len;
1185
1186         /* Save the packet RX context somewhere. */
1187         priv = (ndis_ethpriv *)&p->np_protocolreserved;
1188         priv->nep_ctx = ctx;
1189
1190         if (!NDIS_SERIALIZED(block))
1191                 KeAcquireSpinLock(&block->nmb_lock, &irql);
1192
1193         InsertTailList((&block->nmb_packetlist), (&p->np_list));
1194
1195         if (!NDIS_SERIALIZED(block))
1196                 KeReleaseSpinLock(&block->nmb_lock, irql);
1197
1198         return;
1199 }
1200
1201 /*
1202  * NdisMEthIndicateReceiveComplete() handler, runs at DISPATCH_LEVEL
1203  * for serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
1204  * miniports.
1205  */
1206
1207 static void
1208 ndis_rxeof_done(adapter)
1209         ndis_handle             adapter;
1210 {
1211         struct ndis_softc       *sc;
1212         ndis_miniport_block     *block;
1213
1214         block = adapter;
1215
1216         /* Schedule transfer/RX of queued packets. */
1217
1218         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1219
1220         KeInsertQueueDpc(&sc->ndis_rxdpc, NULL, NULL);
1221
1222         return;
1223 }
1224
1225 /*
1226  * MiniportTransferData() handler, runs at DISPATCH_LEVEL.
1227  */
1228 static void
1229 ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
1230         kdpc                    *dpc;
1231         ndis_handle             adapter;
1232         void                    *sysarg1;
1233         void                    *sysarg2;
1234 {
1235         ndis_miniport_block     *block;
1236         struct ndis_softc       *sc;
1237         ndis_packet             *p;
1238         list_entry              *l;
1239         uint32_t                status;
1240         ndis_ethpriv            *priv;
1241         struct ifnet            *ifp;
1242         struct mbuf             *m;
1243
1244         block = adapter;
1245         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1246         ifp = sc->ifp;
1247
1248         KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
1249
1250         l = block->nmb_packetlist.nle_flink;
1251         while(!IsListEmpty(&block->nmb_packetlist)) {
1252                 l = RemoveHeadList((&block->nmb_packetlist));
1253                 p = CONTAINING_RECORD(l, ndis_packet, np_list);
1254                 InitializeListHead((&p->np_list));
1255
1256                 priv = (ndis_ethpriv *)&p->np_protocolreserved;
1257                 m = p->np_m0;
1258                 p->np_softc = sc;
1259                 p->np_m0 = NULL;
1260
1261                 KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
1262
1263                 status = MSCALL6(sc->ndis_chars->nmc_transferdata_func,
1264                     p, &p->np_private.npp_totlen, block, priv->nep_ctx,
1265                     m->m_len, m->m_pkthdr.len - m->m_len);
1266
1267                 KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
1268
1269                 /*
1270                  * If status is NDIS_STATUS_PENDING, do nothing and
1271                  * wait for a callback to the ndis_rxeof_xfr_done()
1272                  * handler.
1273                  */
1274
1275                 m->m_len = m->m_pkthdr.len;
1276                 m->m_pkthdr.rcvif = ifp;
1277
1278                 if (status == NDIS_STATUS_SUCCESS) {
1279                         IoFreeMdl(p->np_private.npp_head);
1280                         NdisFreePacket(p);
1281                         KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
1282                         _IF_ENQUEUE(&sc->ndis_rxqueue, m);
1283                         KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
1284                         IoQueueWorkItem(sc->ndis_inputitem,
1285                             (io_workitem_func)ndis_inputtask_wrap,
1286                             WORKQUEUE_CRITICAL, ifp);
1287                 }
1288
1289                 if (status == NDIS_STATUS_FAILURE)
1290                         m_freem(m);
1291
1292                 /* Advance to next packet */
1293                 l = block->nmb_packetlist.nle_flink;
1294         }
1295
1296         KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
1297
1298         return;
1299 }
1300
1301 /*
1302  * NdisMTransferDataComplete() handler, runs at DISPATCH_LEVEL.
1303  */
1304 static void
1305 ndis_rxeof_xfr_done(adapter, packet, status, len)
1306         ndis_handle             adapter;
1307         ndis_packet             *packet;
1308         uint32_t                status;
1309         uint32_t                len;
1310 {
1311         ndis_miniport_block     *block;
1312         struct ndis_softc       *sc;
1313         struct ifnet            *ifp;
1314         struct mbuf             *m;
1315
1316         block = adapter;
1317         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1318         ifp = sc->ifp;
1319
1320         m = packet->np_m0;
1321         IoFreeMdl(packet->np_private.npp_head);
1322         NdisFreePacket(packet);
1323
1324         if (status != NDIS_STATUS_SUCCESS) {
1325                 m_freem(m);
1326                 return;
1327         }
1328
1329         m->m_len = m->m_pkthdr.len;
1330         m->m_pkthdr.rcvif = ifp;
1331         KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
1332         _IF_ENQUEUE(&sc->ndis_rxqueue, m);
1333         KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
1334         IoQueueWorkItem(sc->ndis_inputitem,
1335             (io_workitem_func)ndis_inputtask_wrap,
1336             WORKQUEUE_CRITICAL, ifp);
1337
1338         return;
1339 }
1340 /*
1341  * A frame has been uploaded: pass the resulting mbuf chain up to
1342  * the higher level protocols.
1343  *
1344  * When handling received NDIS packets, the 'status' field in the
1345  * out-of-band portion of the ndis_packet has special meaning. In the
1346  * most common case, the underlying NDIS driver will set this field
1347  * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
1348  * take posession of it. We then change the status field to
1349  * NDIS_STATUS_PENDING to tell the driver that we now own the packet,
1350  * and that we will return it at some point in the future via the
1351  * return packet handler.
1352  *
1353  * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
1354  * this means the driver is running out of packet/buffer resources and
1355  * wants to maintain ownership of the packet. In this case, we have to
1356  * copy the packet data into local storage and let the driver keep the
1357  * packet.
1358  */
1359 static void
1360 ndis_rxeof(adapter, packets, pktcnt)
1361         ndis_handle             adapter;
1362         ndis_packet             **packets;
1363         uint32_t                pktcnt;
1364 {
1365         struct ndis_softc       *sc;
1366         ndis_miniport_block     *block;
1367         ndis_packet             *p;
1368         uint32_t                s;
1369         ndis_tcpip_csum         *csum;
1370         struct ifnet            *ifp;
1371         struct mbuf             *m0, *m;
1372         int                     i;
1373
1374         block = (ndis_miniport_block *)adapter;
1375         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1376         ifp = sc->ifp;
1377
1378         /*
1379          * There's a slim chance the driver may indicate some packets
1380          * before we're completely ready to handle them. If we detect this,
1381          * we need to return them to the miniport and ignore them.
1382          */
1383
1384         if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1385                 for (i = 0; i < pktcnt; i++) {
1386                         p = packets[i];
1387                         if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) {
1388                                 p->np_refcnt++;
1389                                 ndis_return_packet(p, block);
1390                         }
1391                 }
1392                 return;
1393         }
1394
1395         for (i = 0; i < pktcnt; i++) {
1396                 p = packets[i];
1397                 /* Stash the softc here so ptom can use it. */
1398                 p->np_softc = sc;
1399                 if (ndis_ptom(&m0, p)) {
1400                         device_printf (sc->ndis_dev, "ptom failed\n");
1401                         if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
1402                                 ndis_return_packet(p, block);
1403                 } else {
1404 #ifdef notdef
1405                         if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
1406                                 m = m_dup(m0, M_DONTWAIT);
1407                                 /*
1408                                  * NOTE: we want to destroy the mbuf here, but
1409                                  * we don't actually want to return it to the
1410                                  * driver via the return packet handler. By
1411                                  * bumping np_refcnt, we can prevent the
1412                                  * ndis_return_packet() routine from actually
1413                                  * doing anything.
1414                                  */
1415                                 p->np_refcnt++;
1416                                 m_freem(m0);
1417                                 if (m == NULL)
1418                                         ifp->if_ierrors++;
1419                                 else
1420                                         m0 = m;
1421                         } else
1422                                 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1423 #endif
1424                         m = m_dup(m0, M_DONTWAIT);
1425                         if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES)
1426                                 p->np_refcnt++;
1427                         else
1428                                 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1429                         m_freem(m0);
1430                         if (m == NULL) {
1431                                 ifp->if_ierrors++;
1432                                 continue;
1433                         }
1434                         m0 = m;
1435                         m0->m_pkthdr.rcvif = ifp;
1436
1437                         /* Deal with checksum offload. */
1438
1439                         if (ifp->if_capenable & IFCAP_RXCSUM &&
1440                             p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) {
1441                                 s = (uintptr_t)
1442                                     p->np_ext.npe_info[ndis_tcpipcsum_info];
1443                                 csum = (ndis_tcpip_csum *)&s;
1444                                 if (csum->u.ntc_rxflags &
1445                                     NDIS_RXCSUM_IP_PASSED)
1446                                         m0->m_pkthdr.csum_flags |=
1447                                             CSUM_IP_CHECKED|CSUM_IP_VALID;
1448                                 if (csum->u.ntc_rxflags &
1449                                     (NDIS_RXCSUM_TCP_PASSED |
1450                                     NDIS_RXCSUM_UDP_PASSED)) {
1451                                         m0->m_pkthdr.csum_flags |=
1452                                             CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
1453                                         m0->m_pkthdr.csum_data = 0xFFFF;
1454                                 }
1455                         }
1456
1457                         KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
1458                         _IF_ENQUEUE(&sc->ndis_rxqueue, m0);
1459                         KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
1460                         IoQueueWorkItem(sc->ndis_inputitem,
1461                             (io_workitem_func)ndis_inputtask_wrap,
1462                             WORKQUEUE_CRITICAL, ifp);
1463                 }
1464         }
1465
1466         return;
1467 }
1468
1469 /*
1470  * This routine is run at PASSIVE_LEVEL. We use this routine to pass
1471  * packets into the stack in order to avoid calling (*ifp->if_input)()
1472  * with any locks held (at DISPATCH_LEVEL, we'll be holding the
1473  * 'dispatch level' per-cpu sleep lock).
1474  */
1475
1476 static void
1477 ndis_inputtask(dobj, arg)
1478         device_object           *dobj;
1479         void                    *arg;
1480 {
1481         ndis_miniport_block     *block;
1482         struct ifnet            *ifp;
1483         struct ndis_softc       *sc;
1484         struct mbuf             *m;
1485         uint8_t                 irql;
1486
1487         ifp = arg;
1488         sc = ifp->if_softc;
1489         block = dobj->do_devext;
1490
1491         KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
1492         while(1) {
1493                 _IF_DEQUEUE(&sc->ndis_rxqueue, m);
1494                 if (m == NULL)
1495                         break;
1496                 KeReleaseSpinLock(&sc->ndis_rxlock, irql);
1497                 ifp->if_ipackets++;
1498                 (*ifp->if_input)(ifp, m);
1499                 KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
1500         }
1501         KeReleaseSpinLock(&sc->ndis_rxlock, irql);
1502
1503         return;
1504 }
1505
1506 /*
1507  * A frame was downloaded to the chip. It's safe for us to clean up
1508  * the list buffers.
1509  */
1510 static void
1511 ndis_txeof(adapter, packet, status)
1512         ndis_handle             adapter;
1513         ndis_packet             *packet;
1514         ndis_status             status;
1515
1516 {
1517         struct ndis_softc       *sc;
1518         ndis_miniport_block     *block;
1519         struct ifnet            *ifp;
1520         int                     idx;
1521         struct mbuf             *m;
1522
1523         block = (ndis_miniport_block *)adapter;
1524         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1525         ifp = sc->ifp;
1526
1527         m = packet->np_m0;
1528         idx = packet->np_txidx;
1529         if (sc->ndis_sc)
1530                 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
1531
1532         ndis_free_packet(packet);
1533         m_freem(m);
1534
1535         NDIS_LOCK(sc);
1536         sc->ndis_txarray[idx] = NULL;
1537         sc->ndis_txpending++;
1538
1539         if (status == NDIS_STATUS_SUCCESS)
1540                 ifp->if_opackets++;
1541         else
1542                 ifp->if_oerrors++;
1543
1544         ifp->if_timer = 0;
1545         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1546
1547         NDIS_UNLOCK(sc);
1548
1549         IoQueueWorkItem(sc->ndis_startitem,
1550             (io_workitem_func)ndis_starttask_wrap,
1551             WORKQUEUE_CRITICAL, ifp);
1552
1553         return;
1554 }
1555
1556 static void
1557 ndis_linksts(adapter, status, sbuf, slen)
1558         ndis_handle             adapter;
1559         ndis_status             status;
1560         void                    *sbuf;
1561         uint32_t                slen;
1562 {
1563         ndis_miniport_block     *block;
1564         struct ndis_softc       *sc;
1565
1566         block = adapter;
1567         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1568         sc->ndis_sts = status;
1569
1570         /* Event list is all full up, drop this one. */
1571
1572         NDIS_LOCK(sc);
1573         if (sc->ndis_evt[sc->ndis_evtpidx].ne_sts) {
1574                 NDIS_UNLOCK(sc);
1575                 return;
1576         }
1577
1578         /* Cache the event. */
1579
1580         if (slen) {
1581                 sc->ndis_evt[sc->ndis_evtpidx].ne_buf = malloc(slen,
1582                     M_TEMP, M_NOWAIT);
1583                 if (sc->ndis_evt[sc->ndis_evtpidx].ne_buf == NULL) {
1584                         NDIS_UNLOCK(sc);
1585                         return;
1586                 }
1587                 bcopy((char *)sbuf,
1588                     sc->ndis_evt[sc->ndis_evtpidx].ne_buf, slen);
1589         }
1590         sc->ndis_evt[sc->ndis_evtpidx].ne_sts = status;
1591         sc->ndis_evt[sc->ndis_evtpidx].ne_len = slen;
1592         NDIS_EVTINC(sc->ndis_evtpidx);
1593         NDIS_UNLOCK(sc);
1594
1595         return;
1596 }
1597
1598 static void
1599 ndis_linksts_done(adapter)
1600         ndis_handle             adapter;
1601 {
1602         ndis_miniport_block     *block;
1603         struct ndis_softc       *sc;
1604         struct ifnet            *ifp;
1605
1606         block = adapter;
1607         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1608         ifp = sc->ifp;
1609
1610         if (!NDIS_INITIALIZED(sc))
1611                 return;
1612
1613         switch (sc->ndis_sts) {
1614         case NDIS_STATUS_MEDIA_CONNECT:
1615                 IoQueueWorkItem(sc->ndis_tickitem, 
1616                     (io_workitem_func)ndis_ticktask_wrap,
1617                     WORKQUEUE_CRITICAL, sc);
1618                 IoQueueWorkItem(sc->ndis_startitem,
1619                     (io_workitem_func)ndis_starttask_wrap,
1620                     WORKQUEUE_CRITICAL, ifp);
1621                 break;
1622         case NDIS_STATUS_MEDIA_DISCONNECT:
1623                 if (sc->ndis_link)
1624                         IoQueueWorkItem(sc->ndis_tickitem,
1625                             (io_workitem_func)ndis_ticktask_wrap,
1626                             WORKQUEUE_CRITICAL, sc);
1627                 break;
1628         default:
1629                 break;
1630         }
1631
1632         /* Notify possible listners of interface change. */
1633
1634         rt_ifmsg(ifp);
1635
1636         return;
1637 }
1638
1639 static void
1640 ndis_tick(xsc)
1641         void                    *xsc;
1642 {
1643         struct ndis_softc       *sc;
1644
1645         mtx_unlock(&Giant);
1646
1647         sc = xsc;
1648
1649         IoQueueWorkItem(sc->ndis_tickitem,
1650             (io_workitem_func)ndis_ticktask_wrap,
1651             WORKQUEUE_CRITICAL, sc);
1652         sc->ndis_stat_ch = timeout(ndis_tick, sc, hz *
1653             sc->ndis_block->nmb_checkforhangsecs);
1654
1655         mtx_lock(&Giant);
1656
1657         return;
1658 }
1659
1660 static void
1661 ndis_ticktask(d, xsc)
1662         device_object           *d;
1663         void                    *xsc;
1664 {
1665         struct ndis_softc       *sc;
1666         struct ieee80211com     *ic;
1667         ndis_checkforhang_handler hangfunc;
1668         uint8_t                 rval;
1669
1670         sc = xsc;
1671         ic = &sc->ic;
1672
1673         NDIS_LOCK(sc);
1674         if (!NDIS_INITIALIZED(sc)) {
1675                 NDIS_UNLOCK(sc);
1676                 return;
1677         }
1678         NDIS_UNLOCK(sc);
1679
1680         hangfunc = sc->ndis_chars->nmc_checkhang_func;
1681
1682         if (hangfunc != NULL) {
1683                 rval = MSCALL1(hangfunc,
1684                     sc->ndis_block->nmb_miniportadapterctx);
1685                 if (rval == TRUE) {
1686                         ndis_reset_nic(sc);
1687                         return;
1688                 }
1689         }
1690
1691         NDIS_LOCK(sc);
1692         if (sc->ndis_link == 0 &&
1693             sc->ndis_sts == NDIS_STATUS_MEDIA_CONNECT) {
1694                 sc->ndis_link = 1;
1695                 NDIS_UNLOCK(sc);
1696                 if (sc->ndis_80211) {
1697                         ndis_getstate_80211(sc);
1698                         ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
1699                 }
1700                 NDIS_LOCK(sc);
1701 #ifdef LINK_STATE_UP
1702 #if __FreeBSD_version > 600006
1703                 if_link_state_change(sc->ifp, LINK_STATE_UP);
1704 #else
1705                 sc->ifp->if_link_state = LINK_STATE_UP;
1706                 rt_ifmsg(sc->ifp);
1707 #endif
1708 #else
1709                 device_printf(sc->ndis_dev, "link state changed to UP\n");
1710 #endif /* LINK_STATE_UP */
1711         }
1712
1713         if (sc->ndis_link == 1 &&
1714             sc->ndis_sts == NDIS_STATUS_MEDIA_DISCONNECT) {
1715                 sc->ndis_link = 0;
1716                 if (sc->ndis_80211)
1717                         ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
1718 #ifdef LINK_STATE_DOWN
1719 #if __FreeBSD_version > 600006
1720                 if_link_state_change(sc->ifp, LINK_STATE_DOWN);
1721 #else
1722                 sc->ifp->if_link_state = LINK_STATE_DOWN;
1723                 rt_ifmsg(sc->ifp);
1724 #endif
1725 #else
1726                 device_printf(sc->ndis_dev, "link state changed to DOWN\n");
1727 #endif /* LINK_STATE_DOWN */
1728         }
1729
1730         NDIS_UNLOCK(sc);
1731
1732         return;
1733 }
1734
1735 static void
1736 ndis_map_sclist(arg, segs, nseg, mapsize, error)
1737         void                    *arg;
1738         bus_dma_segment_t       *segs;
1739         int                     nseg;
1740         bus_size_t              mapsize;
1741         int                     error;
1742
1743 {
1744         struct ndis_sc_list     *sclist;
1745         int                     i;
1746
1747         if (error || arg == NULL)
1748                 return;
1749
1750         sclist = arg;
1751
1752         sclist->nsl_frags = nseg;
1753
1754         for (i = 0; i < nseg; i++) {
1755                 sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr;
1756                 sclist->nsl_elements[i].nse_len = segs[i].ds_len;
1757         }
1758
1759         return;
1760 }
1761
1762 static void
1763 ndis_starttask(d, arg)
1764         device_object           *d;
1765         void                    *arg;
1766 {
1767         struct ifnet            *ifp;
1768
1769         ifp = arg;
1770
1771 #if __FreeBSD_version < 502114
1772         if (ifp->if_snd.ifq_head != NULL)
1773 #else
1774         if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1775 #endif
1776                 ndis_start(ifp);
1777         return;
1778 }
1779
1780 /*
1781  * Main transmit routine. To make NDIS drivers happy, we need to
1782  * transform mbuf chains into NDIS packets and feed them to the
1783  * send packet routines. Most drivers allow you to send several
1784  * packets at once (up to the maxpkts limit). Unfortunately, rather
1785  * that accepting them in the form of a linked list, they expect
1786  * a contiguous array of pointers to packets.
1787  *
1788  * For those drivers which use the NDIS scatter/gather DMA mechanism,
1789  * we need to perform busdma work here. Those that use map registers
1790  * will do the mapping themselves on a buffer by buffer basis.
1791  */
1792
1793 static void
1794 ndis_start(ifp)
1795         struct ifnet            *ifp;
1796 {
1797         struct ndis_softc       *sc;
1798         struct mbuf             *m = NULL;
1799         ndis_packet             **p0 = NULL, *p = NULL;
1800         ndis_tcpip_csum         *csum;
1801         int                     pcnt = 0, status;
1802
1803         sc = ifp->if_softc;
1804
1805         NDIS_LOCK(sc);
1806
1807         if (!sc->ndis_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1808                 NDIS_UNLOCK(sc);
1809                 return;
1810         }
1811
1812         p0 = &sc->ndis_txarray[sc->ndis_txidx];
1813
1814         while(sc->ndis_txpending) {
1815 #if __FreeBSD_version < 502114
1816                 IF_DEQUEUE(&ifp->if_snd, m);
1817 #else
1818                 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1819 #endif
1820                 if (m == NULL)
1821                         break;
1822
1823                 NdisAllocatePacket(&status,
1824                     &sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool);
1825
1826                 if (status != NDIS_STATUS_SUCCESS)
1827                         break;
1828
1829                 if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
1830 #if __FreeBSD_version >= 502114
1831                         IFQ_DRV_PREPEND(&ifp->if_snd, m);
1832 #endif
1833                         NDIS_UNLOCK(sc);
1834 #if __FreeBSD_version < 502114
1835                         IF_PREPEND(&ifp->if_snd, m);
1836 #endif
1837                         return;
1838                 }
1839
1840                 /*
1841                  * Save pointer to original mbuf
1842                  * so we can free it later.
1843                  */
1844
1845                 p = sc->ndis_txarray[sc->ndis_txidx];
1846                 p->np_txidx = sc->ndis_txidx;
1847                 p->np_m0 = m;
1848                 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1849
1850                 /*
1851                  * Do scatter/gather processing, if driver requested it.
1852                  */
1853                 if (sc->ndis_sc) {
1854                         bus_dmamap_load_mbuf(sc->ndis_ttag,
1855                             sc->ndis_tmaps[sc->ndis_txidx], m,
1856                             ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT);
1857                         bus_dmamap_sync(sc->ndis_ttag,
1858                             sc->ndis_tmaps[sc->ndis_txidx],
1859                             BUS_DMASYNC_PREREAD);
1860                         p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist;
1861                 }
1862
1863                 /* Handle checksum offload. */
1864
1865                 if (ifp->if_capenable & IFCAP_TXCSUM &&
1866                     m->m_pkthdr.csum_flags) {
1867                         csum = (ndis_tcpip_csum *)
1868                                 &p->np_ext.npe_info[ndis_tcpipcsum_info];
1869                         csum->u.ntc_txflags = NDIS_TXCSUM_DO_IPV4;
1870                         if (m->m_pkthdr.csum_flags & CSUM_IP)
1871                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_IP;
1872                         if (m->m_pkthdr.csum_flags & CSUM_TCP)
1873                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_TCP;
1874                         if (m->m_pkthdr.csum_flags & CSUM_UDP)
1875                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_UDP;
1876                         p->np_private.npp_flags = NDIS_PROTOCOL_ID_TCP_IP;
1877                 }
1878
1879                 NDIS_INC(sc);
1880                 sc->ndis_txpending--;
1881
1882                 pcnt++;
1883
1884                 /*
1885                  * If there's a BPF listener, bounce a copy of this frame
1886                  * to him.
1887                  */
1888
1889                 BPF_MTAP(ifp, m);
1890
1891                 /*
1892                  * The array that p0 points to must appear contiguous,
1893                  * so we must not wrap past the end of sc->ndis_txarray[].
1894                  * If it looks like we're about to wrap, break out here
1895                  * so the this batch of packets can be transmitted, then
1896                  * wait for txeof to ask us to send the rest.
1897                  */
1898
1899                 if (sc->ndis_txidx == 0)
1900                         break;
1901         }
1902
1903         if (pcnt == 0) {
1904                 NDIS_UNLOCK(sc);
1905                 return;
1906         }
1907
1908         if (sc->ndis_txpending == 0)
1909                 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1910
1911         /*
1912          * Set a timeout in case the chip goes out to lunch.
1913          */
1914         ifp->if_timer = 5;
1915
1916         NDIS_UNLOCK(sc);
1917
1918         /*
1919          * According to NDIS documentation, if a driver exports
1920          * a MiniportSendPackets() routine, we prefer that over
1921          * a MiniportSend() routine (which sends just a single
1922          * packet).
1923          */
1924
1925         if (sc->ndis_chars->nmc_sendmulti_func != NULL)
1926                 ndis_send_packets(sc, p0, pcnt);
1927         else
1928                 ndis_send_packet(sc, p);
1929
1930         return;
1931 }
1932
1933 static void
1934 ndis_init(xsc)
1935         void                    *xsc;
1936 {
1937         struct ndis_softc       *sc = xsc;
1938         struct ieee80211com     *ic = (void *)&sc->ic;
1939         struct ifnet            *ifp = sc->ifp;
1940         int                     i, len, error;
1941
1942         /*
1943          * Avoid reintializing the link unnecessarily.
1944          * This should be dealt with in a better way by
1945          * fixing the upper layer modules so they don't
1946          * call ifp->if_init() quite as often.
1947          */
1948         if (sc->ndis_link && sc->ndis_skip)
1949                 return;
1950
1951         /*
1952          * Cancel pending I/O and free all RX/TX buffers.
1953          */
1954         ndis_stop(sc);
1955
1956         if (ndis_init_nic(sc))
1957                 return;
1958
1959         /* Init our MAC address */
1960
1961         /* Program the packet filter */
1962
1963         sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED;
1964
1965         if (ifp->if_flags & IFF_BROADCAST)
1966                 sc->ndis_filter |= NDIS_PACKET_TYPE_BROADCAST;
1967
1968         if (ifp->if_flags & IFF_PROMISC)
1969                 sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS;
1970
1971         len = sizeof(sc->ndis_filter);
1972
1973         error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
1974             &sc->ndis_filter, &len);
1975
1976         if (error)
1977                 device_printf (sc->ndis_dev, "set filter failed: %d\n", error);
1978
1979         /*
1980          * Set lookahead.
1981          */
1982
1983         i = ifp->if_mtu;
1984         len = sizeof(i);
1985         ndis_set_info(sc, OID_GEN_CURRENT_LOOKAHEAD, &i, &len);
1986
1987         /*
1988          * Program the multicast filter, if necessary.
1989          */
1990         ndis_setmulti(sc);
1991
1992         /* Setup task offload. */
1993         ndis_set_offload(sc);
1994
1995         if (sc->ndis_80211)
1996                 ndis_setstate_80211(sc);
1997
1998         NDIS_LOCK(sc);
1999
2000         sc->ndis_txidx = 0;
2001         sc->ndis_txpending = sc->ndis_maxpkts;
2002         sc->ndis_link = 0;
2003
2004 #ifdef LINK_STATE_UNKNOWN
2005 #if __FreeBSD_version > 600006
2006         if_link_state_change(sc->ifp, LINK_STATE_UNKNOWN);
2007 #else
2008         sc->ifp->if_link_state = LINK_STATE_DOWN;
2009         rt_ifmsg(sc->ifp);
2010 #endif
2011 #endif /* LINK_STATE_UNKNOWN */
2012
2013         if (ic->ic_opmode != IEEE80211_M_MONITOR) {
2014                 /*
2015                  * NB: When restarting the adapter clock the state
2016                  * machine regardless of the roaming mode; otherwise
2017                  * we need to notify user apps so they can manually
2018                  * get us going again.
2019                  */
2020                 if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
2021                         ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
2022         } else
2023                 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2024
2025         ifp->if_drv_flags |= IFF_DRV_RUNNING;
2026         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2027
2028         NDIS_UNLOCK(sc);
2029
2030         /*
2031          * Some drivers don't set this value. The NDIS spec says
2032          * the default checkforhang timeout is "approximately 2
2033          * seconds." We use 3 seconds, because it seems for some
2034          * drivers, exactly 2 seconds is too fast.
2035          */
2036
2037         if (sc->ndis_block->nmb_checkforhangsecs == 0)
2038                 sc->ndis_block->nmb_checkforhangsecs = 3;
2039
2040         sc->ndis_stat_ch = timeout(ndis_tick, sc,
2041             hz * sc->ndis_block->nmb_checkforhangsecs);
2042
2043         return;
2044 }
2045
2046 /*
2047  * Set media options.
2048  */
2049 static int
2050 ndis_ifmedia_upd(ifp)
2051         struct ifnet            *ifp;
2052 {
2053         struct ndis_softc               *sc;
2054
2055         sc = ifp->if_softc;
2056
2057         if (NDIS_INITIALIZED(sc))
2058                 ndis_init(sc);
2059
2060         return(0);
2061 }
2062
2063 /*
2064  * Report current media status.
2065  */
2066 static void
2067 ndis_ifmedia_sts(ifp, ifmr)
2068         struct ifnet            *ifp;
2069         struct ifmediareq       *ifmr;
2070 {
2071         struct ndis_softc       *sc;
2072         uint32_t                media_info;
2073         ndis_media_state        linkstate;
2074         int                     error, len;
2075
2076         ifmr->ifm_status = IFM_AVALID;
2077         ifmr->ifm_active = IFM_ETHER;
2078         sc = ifp->if_softc;
2079
2080         if (!NDIS_INITIALIZED(sc))
2081                 return;
2082
2083         len = sizeof(linkstate);
2084         error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
2085             (void *)&linkstate, &len);
2086
2087         len = sizeof(media_info);
2088         error = ndis_get_info(sc, OID_GEN_LINK_SPEED,
2089             (void *)&media_info, &len);
2090
2091         if (linkstate == nmc_connected)
2092                 ifmr->ifm_status |= IFM_ACTIVE;
2093
2094         switch(media_info) {
2095         case 100000:
2096                 ifmr->ifm_active |= IFM_10_T;
2097                 break;
2098         case 1000000:
2099                 ifmr->ifm_active |= IFM_100_TX;
2100                 break;
2101         case 10000000:
2102                 ifmr->ifm_active |= IFM_1000_T;
2103                 break;
2104         default:
2105                 device_printf(sc->ndis_dev, "unknown speed: %d\n", media_info);
2106                 break;
2107         }
2108
2109         return;
2110 }
2111
2112 #ifdef IEEE80211_F_WPA
2113 static int
2114 ndis_set_cipher(sc, cipher)
2115         struct ndis_softc       *sc;
2116         int                     cipher;
2117 {
2118         struct ieee80211com     *ic;
2119         int                     rval = 0, len;
2120         uint32_t                arg, save;
2121
2122         ic = &sc->ic;
2123
2124         len = sizeof(arg);
2125
2126         if (cipher == WPA_CSE_WEP40 || WPA_CSE_WEP104) {
2127                 if (!(ic->ic_caps & IEEE80211_C_WEP))
2128                         return(ENOTSUP);
2129                 arg = NDIS_80211_WEPSTAT_ENC1ENABLED;
2130         }
2131
2132         if (cipher == WPA_CSE_TKIP) {
2133                 if (!(ic->ic_caps & IEEE80211_C_TKIP))
2134                         return(ENOTSUP);
2135                 arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
2136         }
2137
2138         if (cipher == WPA_CSE_CCMP) {
2139                 if (!(ic->ic_caps & IEEE80211_C_AES_CCM))
2140                         return(ENOTSUP);
2141                 arg = NDIS_80211_WEPSTAT_ENC3ENABLED;
2142         }
2143
2144         DPRINTF(("Setting cipher to %d\n", arg));
2145         save = arg;
2146         rval = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
2147
2148         if (rval)
2149                 return(rval);
2150
2151         /* Check that the cipher was set correctly. */
2152
2153         len = sizeof(save);
2154         rval = ndis_get_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
2155
2156         if (rval != 0 || arg != save)
2157                 return(ENODEV);
2158
2159         return(0);
2160 }
2161
2162 /*
2163  * WPA is hairy to set up. Do the work in a separate routine
2164  * so we don't clutter the setstate function too much.
2165  * Important yet undocumented fact: first we have to set the
2166  * authentication mode, _then_ we enable the ciphers. If one
2167  * of the WPA authentication modes isn't enabled, the driver
2168  * might not permit the TKIP or AES ciphers to be selected.
2169  */
2170
2171 static int
2172 ndis_set_wpa(sc)
2173         struct ndis_softc       *sc;
2174 {
2175         struct ieee80211com     *ic;
2176         struct ieee80211_ie_wpa *w;
2177         struct ndis_ie          *n;
2178         char                    *pos;
2179         uint32_t                arg;
2180         int                     i;
2181
2182         ic = &sc->ic;
2183
2184         /*
2185          * Apparently, the only way for us to know what ciphers
2186          * and key management/authentication mode to use is for
2187          * us to inspect the optional information element (IE)
2188          * stored in the 802.11 state machine. This IE should be
2189          * supplied by the WPA supplicant.
2190          */
2191
2192         w = (struct ieee80211_ie_wpa *)ic->ic_opt_ie;
2193
2194         /* Check for the right kind of IE. */
2195         if (w->wpa_id != IEEE80211_ELEMID_VENDOR) {
2196                 DPRINTF(("Incorrect IE type %d\n", w->wpa_id));
2197                 return(EINVAL);
2198         }
2199
2200         /* Skip over the ucast cipher OIDs. */
2201         pos = (char *)&w->wpa_uciphers[0];
2202         pos += w->wpa_uciphercnt * sizeof(struct ndis_ie);
2203
2204         /* Skip over the authmode count. */
2205         pos += sizeof(u_int16_t);
2206
2207         /*
2208          * Check for the authentication modes. I'm
2209          * pretty sure there's only supposed to be one.
2210          */
2211
2212         n = (struct ndis_ie *)pos;
2213         if (n->ni_val == WPA_ASE_NONE)
2214                 arg = NDIS_80211_AUTHMODE_WPANONE;
2215
2216         if (n->ni_val == WPA_ASE_8021X_UNSPEC)
2217                 arg = NDIS_80211_AUTHMODE_WPA;
2218
2219         if (n->ni_val == WPA_ASE_8021X_PSK)
2220                 arg = NDIS_80211_AUTHMODE_WPAPSK;
2221
2222         DPRINTF(("Setting WPA auth mode to %d\n", arg));
2223         i = sizeof(arg);
2224         if (ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i))
2225                 return(ENOTSUP);
2226         i = sizeof(arg);
2227         ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i);
2228
2229         /* Now configure the desired ciphers. */
2230
2231         /* First, set up the multicast group cipher. */
2232         n = (struct ndis_ie *)&w->wpa_mcipher[0];
2233
2234         if (ndis_set_cipher(sc, n->ni_val))
2235                 return(ENOTSUP);
2236
2237         /* Now start looking around for the unicast ciphers. */
2238         pos = (char *)&w->wpa_uciphers[0];
2239         n = (struct ndis_ie *)pos;
2240
2241         for (i = 0; i < w->wpa_uciphercnt; i++) {
2242                 if (ndis_set_cipher(sc, n->ni_val))
2243                         return(ENOTSUP);
2244                 n++;
2245         }
2246
2247         return(0);
2248 }
2249 #endif
2250
2251 static void
2252 ndis_setstate_80211(sc)
2253         struct ndis_softc       *sc;
2254 {
2255         struct ieee80211com     *ic;
2256         struct ieee80211_node   *ni;
2257         ndis_80211_ssid         ssid;
2258         ndis_80211_macaddr      bssid;
2259         ndis_80211_config       config;
2260         ndis_80211_wep          wep;
2261         int                     i, rval = 0, len;
2262         uint32_t                arg;
2263         struct ifnet            *ifp;
2264
2265         ic = &sc->ic;
2266         ifp = sc->ifp;
2267         ni = ic->ic_bss;
2268
2269         if (!NDIS_INITIALIZED(sc)) {
2270                 DPRINTF(("%s: NDIS not initialized\n", __func__));
2271                 return;
2272         }
2273
2274         /* Disassociate and turn off radio. */
2275
2276         len = sizeof(arg);
2277         arg = 1;
2278         ndis_set_info(sc, OID_802_11_DISASSOCIATE, &arg, &len);
2279
2280         /* Set network infrastructure mode. */
2281
2282         len = sizeof(arg);
2283         if (ic->ic_opmode == IEEE80211_M_IBSS)
2284                 arg = NDIS_80211_NET_INFRA_IBSS;
2285         else
2286                 arg = NDIS_80211_NET_INFRA_BSS;
2287
2288         rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
2289
2290         if (rval)
2291                 device_printf (sc->ndis_dev, "set infra failed: %d\n", rval);
2292
2293         /* Set RTS threshold */
2294
2295         len = sizeof(arg);
2296         arg = ic->ic_rtsthreshold;
2297         ndis_set_info(sc, OID_802_11_RTS_THRESHOLD, &arg, &len);
2298
2299         /* Set fragmentation threshold */
2300
2301         len = sizeof(arg);
2302         arg = ic->ic_fragthreshold;
2303         ndis_set_info(sc, OID_802_11_FRAGMENTATION_THRESHOLD, &arg, &len);
2304
2305         /* Set power management */
2306
2307         len = sizeof(arg);
2308         if (ic->ic_flags & IEEE80211_F_PMGTON)
2309                 arg = NDIS_80211_POWERMODE_FAST_PSP;
2310         else
2311                 arg = NDIS_80211_POWERMODE_CAM;
2312         ndis_set_info(sc, OID_802_11_POWER_MODE, &arg, &len);
2313
2314         /*
2315          * Default encryption mode to off, authentication
2316          * to open and privacy to 'accept everything.'
2317          */
2318
2319         len = sizeof(arg);
2320         arg = NDIS_80211_WEPSTAT_DISABLED;
2321         ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
2322
2323         len = sizeof(arg);
2324         arg = NDIS_80211_AUTHMODE_OPEN;
2325         ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
2326
2327         /*
2328          * Note that OID_80211_PRIVACY_FILTER is optional:
2329          * not all drivers implement it.
2330          */
2331         len = sizeof(arg);
2332         arg = NDIS_80211_PRIVFILT_8021XWEP;
2333         ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len);
2334
2335         /* Set WEP */
2336
2337 #if __FreeBSD_version < 600007
2338         if (ic->ic_flags & IEEE80211_F_WEPON) {
2339 #else
2340         if (ic->ic_flags & IEEE80211_F_PRIVACY &&
2341             !(ic->ic_flags & IEEE80211_F_WPA)) {
2342 #endif
2343                 int                     keys_set = 0;
2344
2345 #if __FreeBSD_version >= 600007
2346                 if (ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED) {
2347                         len = sizeof(arg);
2348                         arg = NDIS_80211_AUTHMODE_SHARED;
2349                         DPRINTF(("Setting shared auth\n"));
2350                         ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE,
2351                             &arg, &len);
2352                 }
2353 #endif
2354                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2355                         if (ic->ic_nw_keys[i].wk_keylen) {
2356 #if __FreeBSD_version >= 600007
2357                                 if (ic->ic_nw_keys[i].wk_cipher->ic_cipher !=
2358                                     IEEE80211_CIPHER_WEP)
2359                                         continue;
2360 #endif
2361                                 bzero((char *)&wep, sizeof(wep));
2362                                 wep.nw_keylen = ic->ic_nw_keys[i].wk_keylen;
2363
2364                                 /*
2365                                  * 5, 13 and 16 are the only valid
2366                                  * only valid key lengths. Anything
2367                                  * in between will be zero padded out to
2368                                  * the next highest boundary.
2369                                  */
2370                                 if (ic->ic_nw_keys[i].wk_keylen < 5)
2371                                         wep.nw_keylen = 5;
2372                                 else if (ic->ic_nw_keys[i].wk_keylen > 5 &&
2373                                      ic->ic_nw_keys[i].wk_keylen < 13)
2374                                         wep.nw_keylen = 13;
2375                                 else if (ic->ic_nw_keys[i].wk_keylen > 13 &&
2376                                      ic->ic_nw_keys[i].wk_keylen < 16)
2377                                         wep.nw_keylen = 16;
2378
2379                                 wep.nw_keyidx = i;
2380                                 wep.nw_length = (sizeof(uint32_t) * 3)
2381                                     + wep.nw_keylen;
2382                                 if (i == ic->ic_def_txkey)
2383                                         wep.nw_keyidx |= NDIS_80211_WEPKEY_TX;
2384                                 bcopy(ic->ic_nw_keys[i].wk_key,
2385                                     wep.nw_keydata, wep.nw_length);
2386                                 len = sizeof(wep);
2387                                 DPRINTF(("Setting WEP key %d\n", i));
2388                                 rval = ndis_set_info(sc,
2389                                     OID_802_11_ADD_WEP, &wep, &len);
2390                                 if (rval)
2391                                         device_printf(sc->ndis_dev,
2392                                             "set wepkey failed: %d\n", rval);
2393                                 keys_set++;
2394                         }
2395                 }
2396                 if (keys_set) {
2397                         DPRINTF(("Setting WEP on\n"));
2398                         arg = NDIS_80211_WEPSTAT_ENABLED;
2399                         len = sizeof(arg);
2400                         rval = ndis_set_info(sc,
2401                             OID_802_11_WEP_STATUS, &arg, &len);
2402                         if (rval)
2403                                 device_printf(sc->ndis_dev,
2404                                     "enable WEP failed: %d\n", rval);
2405 #ifdef IEEE80211_F_DROPUNENC
2406                         if (ic->ic_flags & IEEE80211_F_DROPUNENC)
2407                                 arg = NDIS_80211_PRIVFILT_8021XWEP;
2408                         else
2409                                 arg = NDIS_80211_PRIVFILT_ACCEPTALL;
2410
2411                         len = sizeof(arg);
2412                         ndis_set_info(sc,
2413                             OID_802_11_PRIVACY_FILTER, &arg, &len);
2414 #endif
2415                 }
2416         } 
2417
2418 #ifdef IEEE80211_F_WPA
2419         /* Set up WPA. */
2420
2421         if (ic->ic_flags & IEEE80211_F_WPA1 && ic->ic_opt_ie_len &&
2422             ic->ic_caps & IEEE80211_C_WPA)
2423                 if (ndis_set_wpa(sc))
2424                         device_printf(sc->ndis_dev, "WPA setup failed\n");
2425 #endif
2426
2427 #ifdef notyet
2428         /* Set network type. */
2429
2430         arg = 0;
2431
2432         switch (ic->ic_curmode) {
2433         case IEEE80211_MODE_11A:
2434                 arg = NDIS_80211_NETTYPE_11OFDM5;
2435                 break;
2436         case IEEE80211_MODE_11B:
2437                 arg = NDIS_80211_NETTYPE_11DS;
2438                 break;
2439         case IEEE80211_MODE_11G:
2440                 arg = NDIS_80211_NETTYPE_11OFDM24;
2441                 break;
2442         default:
2443                 device_printf(sc->ndis_dev, "unknown mode: %d\n",
2444                     ic->ic_curmode);
2445         }
2446
2447         if (arg) {
2448                 DPRINTF(("Setting network type to %d\n", arg));
2449                 len = sizeof(arg);
2450                 rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE,
2451                     &arg, &len);
2452                 if (rval)
2453                         device_printf (sc->ndis_dev,
2454                             "set nettype failed: %d\n", rval);
2455         }
2456 #endif
2457
2458         len = sizeof(config);
2459         bzero((char *)&config, len);
2460         config.nc_length = len;
2461         config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
2462         rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); 
2463
2464         /*
2465          * Some drivers expect us to initialize these values, so
2466          * provide some defaults.
2467          */
2468
2469         if (config.nc_beaconperiod == 0)
2470                 config.nc_beaconperiod = 100;
2471         if (config.nc_atimwin == 0)
2472                 config.nc_atimwin = 100;
2473         if (config.nc_fhconfig.ncf_dwelltime == 0)
2474                 config.nc_fhconfig.ncf_dwelltime = 200;
2475         if (rval == 0 && ic->ic_bsschan != IEEE80211_CHAN_ANYC) { 
2476                 int chan, chanflag;
2477
2478                 chan = ieee80211_chan2ieee(ic, ic->ic_bsschan);
2479                 chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
2480                     IEEE80211_CHAN_5GHZ;
2481                 if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
2482                         config.nc_dsconfig =
2483                                 ic->ic_bsschan->ic_freq * 1000;
2484                         ic->ic_bss->ni_chan = ic->ic_bsschan;
2485                         len = sizeof(config);
2486                         config.nc_length = len;
2487                         config.nc_fhconfig.ncf_length =
2488                             sizeof(ndis_80211_config_fh);
2489                         DPRINTF(("Setting channel to %ukHz\n", config.nc_dsconfig));
2490                         rval = ndis_set_info(sc, OID_802_11_CONFIGURATION,
2491                             &config, &len);
2492                         if (rval)
2493                                 device_printf(sc->ndis_dev, "couldn't change "
2494                                     "DS config to %ukHz: %d\n",
2495                                     config.nc_dsconfig, rval);
2496                 }
2497         } else if (rval)
2498                 device_printf(sc->ndis_dev, "couldn't retrieve "
2499                     "channel info: %d\n", rval);
2500
2501         /*
2502          * If the user selected a specific BSSID, try
2503          * to use that one. This is useful in the case where
2504          * there are several APs in range with the same network
2505          * name. To delete the BSSID, we use the broadcast
2506          * address as the BSSID.
2507          * Note that some drivers seem to allow setting a BSSID
2508          * in ad-hoc mode, which has the effect of forcing the
2509          * NIC to create an ad-hoc cell with a specific BSSID,
2510          * instead of a randomly chosen one. However, the net80211
2511          * code makes the assumtion that the BSSID setting is invalid
2512          * when you're in ad-hoc mode, so we don't allow that here.
2513          */
2514
2515         len = IEEE80211_ADDR_LEN;
2516         if (ic->ic_flags & IEEE80211_F_DESBSSID &&
2517             ic->ic_opmode != IEEE80211_M_IBSS)
2518                 bcopy(ni->ni_bssid, bssid, len);
2519         else
2520                 bcopy(ifp->if_broadcastaddr, bssid, len);
2521
2522         DPRINTF(("Setting BSSID to %6D\n", &bssid, ":"));
2523         rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len);
2524         if (rval)
2525                 device_printf(sc->ndis_dev,
2526                     "setting BSSID failed: %d\n", rval);
2527
2528         /* Set SSID -- always do this last. */
2529
2530 #ifdef NDIS_DEBUG
2531         if (ndis_debug > 0) {
2532                 printf("Setting ESSID to ");
2533                 ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
2534                 printf("\n");
2535         }
2536 #endif
2537
2538         len = sizeof(ssid);
2539         bzero((char *)&ssid, len);
2540         ssid.ns_ssidlen = ni->ni_esslen;
2541         if (ssid.ns_ssidlen == 0) {
2542                 ssid.ns_ssidlen = 1;
2543         } else
2544                 bcopy(ni->ni_essid, ssid.ns_ssid, ssid.ns_ssidlen);
2545
2546         rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
2547
2548         if (rval)
2549                 device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval);
2550
2551         if (ic->ic_state == IEEE80211_S_AUTH)
2552                 ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0);
2553
2554         return;
2555 }
2556
2557 static void
2558 ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
2559 {
2560         struct ieee80211com *ic = &((struct ndis_softc *)ifp->if_softc)->ic;
2561         struct ieee80211_node *ni = NULL;
2562
2563         imr->ifm_status = IFM_AVALID;
2564         imr->ifm_active = IFM_IEEE80211;
2565         if (ic->ic_state == IEEE80211_S_RUN)
2566                 imr->ifm_status |= IFM_ACTIVE;
2567         imr->ifm_active |= IFM_AUTO;
2568         switch (ic->ic_opmode) {
2569         case IEEE80211_M_STA:
2570                 ni = ic->ic_bss;
2571                 /* calculate rate subtype */
2572                 imr->ifm_active |= ieee80211_rate2media(ic,
2573                         ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
2574                 break;
2575         case IEEE80211_M_IBSS:
2576                 ni = ic->ic_bss;
2577                 /* calculate rate subtype */
2578                 imr->ifm_active |= ieee80211_rate2media(ic,
2579                         ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
2580                 imr->ifm_active |= IFM_IEEE80211_ADHOC;
2581                 break;
2582         case IEEE80211_M_AHDEMO:
2583                 /* should not come here */
2584                 break;
2585         case IEEE80211_M_HOSTAP:
2586                 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
2587                 break;
2588         case IEEE80211_M_MONITOR:
2589                 imr->ifm_active |= IFM_IEEE80211_MONITOR;
2590                 break;
2591         case IEEE80211_M_WDS:
2592                 printf("WARNING: WDS operation mode not supported by NDIS\n");
2593                 break;
2594         }
2595         switch (ic->ic_curmode) {
2596         case IEEE80211_MODE_11A:
2597                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A);
2598                 break;
2599         case IEEE80211_MODE_11B:
2600                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B);
2601                 break;
2602         case IEEE80211_MODE_11G:
2603                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G);
2604                 break;
2605 #ifdef IEEE80211_MODE_TURBO_A
2606         case IEEE80211_MODE_TURBO_A:
2607                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
2608                                 |  IFM_IEEE80211_TURBO;
2609 #endif
2610                 break;
2611         }
2612 }
2613
2614 static int
2615 ndis_get_assoc(sc, assoc)
2616         struct ndis_softc       *sc;
2617         ndis_wlan_bssid_ex      **assoc;
2618 {
2619         ndis_80211_bssid_list_ex        *bl;
2620         ndis_wlan_bssid_ex      *bs;
2621         ndis_80211_macaddr      bssid;
2622         int                     i, len, error;
2623
2624         if (!sc->ndis_link)
2625                 return(ENOENT);
2626
2627         len = sizeof(bssid);
2628         error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len);
2629         if (error) {
2630                 device_printf(sc->ndis_dev, "failed to get bssid\n");
2631                 return(ENOENT);
2632         }
2633
2634         len = 4;
2635         error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
2636         if (error != ENOSPC)
2637                 len = 65536;
2638
2639         bl = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
2640         error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
2641         if (error) {
2642                 free(bl, M_TEMP);
2643                 device_printf(sc->ndis_dev, "bssid_list failed\n");
2644                 return (error);
2645         }
2646
2647         bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0];
2648         for (i = 0; i < bl->nblx_items; i++) {
2649                 if (bcmp(bs->nwbx_macaddr, bssid, sizeof(bssid)) == 0) {
2650                         *assoc = malloc(bs->nwbx_len, M_TEMP, M_NOWAIT);
2651                         if (*assoc == NULL) {
2652                                 free(bl, M_TEMP);
2653                                 return(ENOMEM);
2654                         }
2655                         bcopy((char *)bs, (char *)*assoc, bs->nwbx_len);
2656                         free(bl, M_TEMP);
2657                         return(0);
2658                 }       
2659                 bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len);
2660         }
2661
2662         free(bl, M_TEMP);
2663         return(ENOENT);
2664 }
2665
2666 static void
2667 ndis_getstate_80211(sc)
2668         struct ndis_softc       *sc;
2669 {
2670         struct ieee80211com     *ic;
2671         ndis_wlan_bssid_ex      *bs;
2672         int                     rval, len, i = 0;
2673         int                     chanflag;
2674         uint32_t                arg;
2675         struct ifnet            *ifp;
2676
2677         ic = &sc->ic;
2678         ifp = sc->ifp;
2679
2680         if (!NDIS_INITIALIZED(sc))
2681                 return;
2682
2683         if ((rval = ndis_get_assoc(sc, &bs)) != 0)
2684                 return;
2685
2686         /* We're associated, retrieve info on the current bssid. */
2687         ic->ic_curmode = ndis_nettype_mode(bs->nwbx_nettype);
2688         chanflag = ndis_nettype_chan(bs->nwbx_nettype);
2689         IEEE80211_ADDR_COPY(ic->ic_bss->ni_bssid, bs->nwbx_macaddr);
2690
2691         /* Get SSID from current association info. */
2692         bcopy(bs->nwbx_ssid.ns_ssid, ic->ic_bss->ni_essid,
2693             bs->nwbx_ssid.ns_ssidlen);
2694         ic->ic_bss->ni_esslen = bs->nwbx_ssid.ns_ssidlen;
2695
2696         len = sizeof(arg);
2697         rval = ndis_get_info(sc, OID_GEN_LINK_SPEED, &arg, &len);
2698         if (rval)
2699                 device_printf (sc->ndis_dev, "get link speed failed: %d\n",
2700                     rval);
2701
2702         if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) {
2703                 ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];
2704                 for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
2705                         if ((ic->ic_bss->ni_rates.rs_rates[i] &
2706                             IEEE80211_RATE_VAL) == arg / 5000)
2707                                 break;
2708                 }
2709         }
2710
2711         if (i == ic->ic_bss->ni_rates.rs_nrates &&
2712             isset(ic->ic_modecaps, IEEE80211_MODE_11G)) {
2713                 ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11G];
2714                 for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
2715                         if ((ic->ic_bss->ni_rates.rs_rates[i] &
2716                             IEEE80211_RATE_VAL) == arg / 5000)
2717                                 break;
2718                 }
2719         }
2720
2721         if (i == ic->ic_bss->ni_rates.rs_nrates)
2722                 device_printf(sc->ndis_dev, "no matching rate for: %d\n",
2723                     arg / 5000);
2724         else
2725                 ic->ic_bss->ni_txrate = i;
2726
2727         if (ic->ic_caps & IEEE80211_C_PMGT) {
2728                 len = sizeof(arg);
2729                 rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len);
2730
2731                 if (rval)
2732                         device_printf(sc->ndis_dev,
2733                             "get power mode failed: %d\n", rval);
2734                 if (arg == NDIS_80211_POWERMODE_CAM)
2735                         ic->ic_flags &= ~IEEE80211_F_PMGTON;
2736                 else
2737                         ic->ic_flags |= IEEE80211_F_PMGTON;
2738         }
2739
2740         /*
2741          * Use the current association information to reflect
2742          * what channel we're on.
2743          */
2744         ic->ic_curchan = ieee80211_find_channel(ic,
2745             bs->nwbx_config.nc_dsconfig / 1000, chanflag);
2746         if (ic->ic_curchan == NULL)
2747                 ic->ic_curchan = &ic->ic_channels[0];
2748         ic->ic_bss->ni_chan = ic->ic_curchan;
2749         ic->ic_bsschan = ic->ic_curchan;
2750
2751         free(bs, M_TEMP);
2752
2753         /*
2754          * Determine current authentication mode. Note: authmode
2755          * reporting isn't supported prior to FreeBSD 6.x.
2756          */
2757
2758 #if __FreeBSD_version >= 600007
2759         len = sizeof(arg);
2760         rval = ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
2761         if (rval)
2762                 device_printf (sc->ndis_dev,
2763                     "get authmode status failed: %d\n", rval);
2764         else {
2765                 ic->ic_flags &= ~IEEE80211_F_WPA;
2766                 switch(arg) {
2767                 case NDIS_80211_AUTHMODE_OPEN:
2768                         ic->ic_bss->ni_authmode = IEEE80211_AUTH_OPEN;
2769                         break;
2770                 case NDIS_80211_AUTHMODE_SHARED:
2771                         ic->ic_bss->ni_authmode = IEEE80211_AUTH_SHARED;
2772                         break;
2773                 case NDIS_80211_AUTHMODE_AUTO:
2774                         ic->ic_bss->ni_authmode = IEEE80211_AUTH_AUTO;
2775                         break;
2776                 case NDIS_80211_AUTHMODE_WPA:
2777                 case NDIS_80211_AUTHMODE_WPAPSK:
2778                 case NDIS_80211_AUTHMODE_WPANONE:
2779                         ic->ic_bss->ni_authmode = IEEE80211_AUTH_WPA;
2780                         ic->ic_flags |= IEEE80211_F_WPA1;
2781                         break;
2782                 case NDIS_80211_AUTHMODE_WPA2:
2783                 case NDIS_80211_AUTHMODE_WPA2PSK:
2784                         ic->ic_bss->ni_authmode = IEEE80211_AUTH_WPA;
2785                         ic->ic_flags |= IEEE80211_F_WPA2;
2786                         break;
2787                 default:
2788                         ic->ic_bss->ni_authmode = IEEE80211_AUTH_NONE;
2789                         break;
2790                 }
2791         }
2792 #endif
2793
2794         len = sizeof(arg);
2795         rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
2796
2797         if (rval)
2798                 device_printf (sc->ndis_dev,
2799                     "get wep status failed: %d\n", rval);
2800
2801 #if __FreeBSD_version < 600007
2802         if (arg == NDIS_80211_WEPSTAT_ENABLED)
2803                 ic->ic_flags |= IEEE80211_F_WEPON;
2804         else
2805                 ic->ic_flags &= ~IEEE80211_F_WEPON;
2806 #else
2807         if (arg == NDIS_80211_WEPSTAT_ENABLED)
2808                 ic->ic_flags |= IEEE80211_F_PRIVACY|IEEE80211_F_DROPUNENC;
2809         else
2810                 ic->ic_flags &= ~(IEEE80211_F_PRIVACY|IEEE80211_F_DROPUNENC);
2811                 
2812 #endif
2813
2814         return;
2815 }
2816
2817 static int
2818 ndis_ioctl(ifp, command, data)
2819         struct ifnet            *ifp;
2820         u_long                  command;
2821         caddr_t                 data;
2822 {
2823         struct ndis_softc       *sc = ifp->if_softc;
2824         struct ifreq            *ifr = (struct ifreq *) data;
2825         struct ndis_oid_data    oid;
2826         struct ndis_evt         evt;
2827         void                    *oidbuf;
2828         int                     i, error = 0;
2829
2830         /*NDIS_LOCK(sc);*/
2831
2832         switch(command) {
2833         case SIOCSIFFLAGS:
2834                 if (ifp->if_flags & IFF_UP) {
2835                         if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
2836                             ifp->if_flags & IFF_PROMISC &&
2837                             !(sc->ndis_if_flags & IFF_PROMISC)) {
2838                                 sc->ndis_filter |=
2839                                     NDIS_PACKET_TYPE_PROMISCUOUS;
2840                                 i = sizeof(sc->ndis_filter);
2841                                 error = ndis_set_info(sc,
2842                                     OID_GEN_CURRENT_PACKET_FILTER,
2843                                     &sc->ndis_filter, &i);
2844                         } else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
2845                             !(ifp->if_flags & IFF_PROMISC) &&
2846                             sc->ndis_if_flags & IFF_PROMISC) {
2847                                 sc->ndis_filter &=
2848                                     ~NDIS_PACKET_TYPE_PROMISCUOUS;
2849                                 i = sizeof(sc->ndis_filter);
2850                                 error = ndis_set_info(sc,
2851                                     OID_GEN_CURRENT_PACKET_FILTER,
2852                                     &sc->ndis_filter, &i);
2853                         } else
2854                                 ndis_init(sc);
2855                 } else {
2856                         if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2857                                 ndis_stop(sc);
2858                 }
2859                 sc->ndis_if_flags = ifp->if_flags;
2860                 error = 0;
2861                 break;
2862         case SIOCADDMULTI:
2863         case SIOCDELMULTI:
2864                 ndis_setmulti(sc);
2865                 error = 0;
2866                 break;
2867         case SIOCGIFMEDIA:
2868         case SIOCSIFMEDIA:
2869                 if (sc->ndis_80211) {
2870 #if __FreeBSD_version < 600007
2871                         error = ieee80211_ioctl(ifp, command, data);
2872 #else
2873                         error = ieee80211_ioctl(&sc->ic, command, data);
2874 #endif
2875                         if (error == ENETRESET) {
2876                                 ndis_setstate_80211(sc);
2877                                 /*ndis_init(sc);*/
2878                                 error = 0;
2879                         }
2880                 } else
2881                         error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
2882                 break;
2883         case SIOCSIFCAP:
2884                 ifp->if_capenable = ifr->ifr_reqcap;
2885                 if (ifp->if_capenable & IFCAP_TXCSUM)
2886                         ifp->if_hwassist = sc->ndis_hwassist;
2887                 else
2888                         ifp->if_hwassist = 0;
2889                 ndis_set_offload(sc);
2890                 break;
2891         case SIOCG80211:
2892                 if (!NDIS_INITIALIZED(sc))
2893                         goto do_80211;
2894                 if (sc->ndis_80211)
2895                         error = ndis_80211_ioctl_get(ifp, command, data);
2896                 else
2897                         error = ENOTTY;
2898                 break;
2899         case SIOCS80211:
2900                 if (!NDIS_INITIALIZED(sc))
2901                         goto do_80211;
2902                 if (sc->ndis_80211)
2903                         error = ndis_80211_ioctl_set(ifp, command, data);
2904                 else
2905                         error = ENOTTY;
2906                 break;
2907         case SIOCGDRVSPEC:
2908                 if ((error = priv_check(curthread, PRIV_DRIVER)))
2909                         break;
2910                 error =  copyin(ifr->ifr_data, &oid, sizeof(oid));
2911                 if (error)
2912                         break;
2913                 oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO);
2914                 if (oidbuf == NULL) {
2915                         error = ENOMEM;
2916                         break;
2917                 }
2918                 error =  copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len);
2919                 if (error) {
2920                         free(oidbuf, M_TEMP);
2921                         break;
2922                 }
2923                 error = ndis_get_info(sc, oid.oid, oidbuf, &oid.len);
2924                 if (error) {
2925                         free(oidbuf, M_TEMP);
2926                         break;
2927                 }
2928                 error = copyout(&oid, ifr->ifr_data, sizeof(oid));
2929                 if (error) {
2930                         free(oidbuf, M_TEMP);
2931                         break;
2932                 }
2933                 error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len);
2934                 free(oidbuf, M_TEMP);
2935                 break;
2936         case SIOCSDRVSPEC:
2937                 if ((error = priv_check(curthread, PRIV_DRIVER)))
2938                         break;
2939                 error =  copyin(ifr->ifr_data, &oid, sizeof(oid));
2940                 if (error)
2941                         break;
2942                 oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO);
2943                 if (oidbuf == NULL) {
2944                         error = ENOMEM;
2945                         break;
2946                 }
2947                 error =  copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len);
2948                 if (error) {
2949                         free(oidbuf, M_TEMP);
2950                         break;
2951                 }
2952                 error = ndis_set_info(sc, oid.oid, oidbuf, &oid.len);
2953                 if (error) {
2954                         free(oidbuf, M_TEMP);
2955                         break;
2956                 }
2957                 error = copyout(&oid, ifr->ifr_data, sizeof(oid));
2958                 if (error) {
2959                         free(oidbuf, M_TEMP);
2960                         break;
2961                 }
2962                 error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len);
2963                 free(oidbuf, M_TEMP);
2964                 break;
2965         case SIOCGPRIVATE_0:
2966                 if ((error = priv_check(curthread, PRIV_DRIVER)))
2967                         break;
2968                 NDIS_LOCK(sc);
2969                 if (sc->ndis_evt[sc->ndis_evtcidx].ne_sts == 0) {
2970                         error = ENOENT;
2971                         NDIS_UNLOCK(sc);
2972                         break;
2973                 }
2974                 error =  copyin(ifr->ifr_data, &evt, sizeof(evt));
2975                 if (error) {
2976                         NDIS_UNLOCK(sc);
2977                         break;
2978                 }
2979                 if (evt.ne_len < sc->ndis_evt[sc->ndis_evtcidx].ne_len) {
2980                         error = ENOSPC;
2981                         NDIS_UNLOCK(sc);
2982                         break;
2983                 }
2984                 error = copyout(&sc->ndis_evt[sc->ndis_evtcidx],
2985                     ifr->ifr_data, sizeof(uint32_t) * 2);
2986                 if (error) {
2987                         NDIS_UNLOCK(sc);
2988                         break;
2989                 }
2990                 if (sc->ndis_evt[sc->ndis_evtcidx].ne_len) {
2991                         error = copyout(sc->ndis_evt[sc->ndis_evtcidx].ne_buf,
2992                             ifr->ifr_data + (sizeof(uint32_t) * 2),
2993                             sc->ndis_evt[sc->ndis_evtcidx].ne_len);
2994                         if (error) {
2995                                 NDIS_UNLOCK(sc);
2996                                 break;
2997                         }
2998                         free(sc->ndis_evt[sc->ndis_evtcidx].ne_buf, M_TEMP);
2999                         sc->ndis_evt[sc->ndis_evtcidx].ne_buf = NULL;
3000                 }
3001                 sc->ndis_evt[sc->ndis_evtcidx].ne_len = 0;
3002                 sc->ndis_evt[sc->ndis_evtcidx].ne_sts = 0;
3003                 NDIS_EVTINC(sc->ndis_evtcidx);
3004                 NDIS_UNLOCK(sc);
3005                 break;
3006 #if __FreeBSD_version < 700046
3007         case SIOCGIFGENERIC:
3008         case SIOCSIFGENERIC:
3009                 if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) {
3010                         if (command == SIOCGIFGENERIC)
3011                                 error = ndis_wi_ioctl_get(ifp, command, data);
3012                         else
3013                                 error = ndis_wi_ioctl_set(ifp, command, data);
3014                 } else
3015                         error = ENOTTY;
3016                 if (error != ENOTTY)
3017                         break;
3018 #endif
3019         default:
3020 do_80211:
3021                 sc->ndis_skip = 1;
3022                 if (sc->ndis_80211) {
3023 #if __FreeBSD_version < 600007
3024                         error = ieee80211_ioctl(ifp, command, data);
3025 #else
3026                         error = ieee80211_ioctl(&sc->ic, command, data);
3027 #endif
3028                         if (error == ENETRESET) {
3029                                 ndis_setstate_80211(sc);
3030                                 error = 0;
3031                         }
3032                 } else
3033                         error = ether_ioctl(ifp, command, data);
3034                 sc->ndis_skip = 0;
3035                 break;
3036         }
3037
3038         /*NDIS_UNLOCK(sc);*/
3039
3040         return(error);
3041 }
3042
3043 #if __FreeBSD_version < 700046
3044 static int
3045 ndis_wi_ioctl_get(ifp, command, data)
3046         struct ifnet            *ifp;
3047         u_long                  command;
3048         caddr_t                 data;
3049 {
3050         struct wi_req           wreq;
3051         struct ifreq            *ifr;
3052         struct ndis_softc       *sc;
3053         ndis_80211_bssid_list_ex *bl;
3054         ndis_wlan_bssid_ex      *wb;
3055         struct wi_apinfo        *api;
3056         int                     error, i, j, len, maxaps;
3057
3058         sc = ifp->if_softc;
3059         ifr = (struct ifreq *)data;
3060         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
3061         if (error)
3062                 return (error);
3063
3064         switch (wreq.wi_type) {
3065         case WI_RID_READ_APS:
3066                 len = 0;
3067                 error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN,
3068                     NULL, &len);
3069                 if (error == 0)
3070                         tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2);
3071                 len = 0;
3072                 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
3073                 if (error != ENOSPC)
3074                         len = 65536;    
3075                 bl = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
3076                 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
3077                 if (error) {
3078                         free(bl, M_DEVBUF);
3079                         break;
3080                 }
3081                 maxaps = (2 * wreq.wi_len - sizeof(int)) / sizeof(*api);
3082                 maxaps = MIN(maxaps, bl->nblx_items);
3083                 wreq.wi_len = (maxaps * sizeof(*api) + sizeof(int)) / 2;
3084                 *(int *)&wreq.wi_val = maxaps;
3085                 api = (struct wi_apinfo *)&((int *)&wreq.wi_val)[1];
3086                 wb = bl->nblx_bssid;
3087                 while (maxaps--) {
3088                         bzero(api, sizeof(*api));
3089                         bcopy(&wb->nwbx_macaddr, &api->bssid,
3090                             sizeof(api->bssid));
3091                         api->namelen = wb->nwbx_ssid.ns_ssidlen;
3092                         bcopy(&wb->nwbx_ssid.ns_ssid, &api->name, api->namelen);
3093                         if (wb->nwbx_privacy)
3094                                 api->capinfo |= IEEE80211_CAPINFO_PRIVACY;
3095                         /* XXX Where can we get noise information? */
3096                         api->signal = wb->nwbx_rssi + 149;      /* XXX */
3097                         api->quality = api->signal;
3098                         api->channel =
3099                             ieee80211_mhz2ieee(wb->nwbx_config.nc_dsconfig /
3100                             1000, 0);
3101                         /* In "auto" infrastructure mode, this is useless. */
3102                         if (wb->nwbx_netinfra == NDIS_80211_NET_INFRA_IBSS)
3103                                 api->capinfo |= IEEE80211_CAPINFO_IBSS;
3104                         if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
3105                                 j = sizeof(ndis_80211_rates_ex);
3106                                 /* handle other extended things */
3107                         } else
3108                                 j = sizeof(ndis_80211_rates);
3109                         for (i = api->rate = 0; i < j; i++)
3110                                 api->rate = MAX(api->rate, 5 *
3111                                     (wb->nwbx_supportedrates[i] & 0x7f));
3112                         api++;
3113                         wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
3114                 }
3115                 free(bl, M_DEVBUF);
3116                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
3117                 break;
3118         default:
3119                 error = ENOTTY;
3120                 break;
3121         }
3122         return (error);
3123 }
3124
3125 static int
3126 ndis_wi_ioctl_set(ifp, command, data)
3127         struct ifnet            *ifp;
3128         u_long                  command;
3129         caddr_t                 data;
3130 {
3131         struct wi_req           wreq;
3132         struct ifreq            *ifr;
3133         struct ndis_softc       *sc;
3134         uint32_t                foo;
3135         int                     error, len;
3136
3137         error = priv_check(curthread, PRIV_DRIVER);
3138         if (error)
3139                 return (error);
3140
3141         sc = ifp->if_softc;
3142         ifr = (struct ifreq *)data;
3143         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
3144         if (error)
3145                 return (error);
3146
3147         switch (wreq.wi_type) {
3148         case WI_RID_SCAN_APS:
3149         case WI_RID_SCAN_REQ:                   /* arguments ignored */
3150                 len = sizeof(foo);
3151                 foo = 0;
3152                 error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, &foo,
3153                     &len);
3154                 break;
3155         default:
3156                 error = ENOTTY;
3157                 break;
3158         }
3159         return (error);
3160 }
3161 #endif
3162
3163 static int
3164 ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data)
3165 {
3166         struct ndis_softc       *sc;
3167         struct ieee80211req     *ireq;
3168         int                     error, len;
3169         uint16_t                nodename_u[IEEE80211_NWID_LEN + 1];
3170         unicode_string          us;
3171         ansi_string             as;
3172
3173         sc = ifp->if_softc;
3174         ireq = (struct ieee80211req *) data;
3175
3176         switch (ireq->i_type) {
3177 #ifdef IEEE80211_IOC_MLME
3178         case IEEE80211_IOC_MLME:
3179                 error = 0;
3180                 break;
3181 #endif
3182         case IEEE80211_IOC_STATIONNAME:
3183                 error = ndis_get_info(sc, OID_GEN_MACHINE_NAME,
3184                     &nodename_u, &len);
3185                 if (error)
3186                         break;
3187                 us.us_len = us.us_maxlen = len;
3188                 us.us_buf = nodename_u;
3189                 if (RtlUnicodeStringToAnsiString(&as, &us, TRUE)) {
3190                         error = ENOMEM;
3191                         break;
3192                 }
3193                 ireq->i_len = as.as_len;
3194                 error = copyout(as.as_buf, ireq->i_data, ireq->i_len);
3195                 RtlFreeAnsiString(&as);
3196                 break;
3197         default:
3198 #if __FreeBSD_version < 600007
3199                 error = ieee80211_ioctl(ifp, command, data);
3200 #else
3201                 error = ieee80211_ioctl(&sc->ic, command, data);
3202 #endif
3203                 break;
3204         }
3205         
3206         return(error);
3207 }
3208
3209 #ifdef IEEE80211_F_WPA
3210 int
3211 ndis_del_key(ic, key)
3212         struct ieee80211com     *ic;
3213         const struct ieee80211_key *key;
3214 {
3215         struct ndis_softc       *sc;
3216         ndis_80211_key          rkey;
3217         int                     len, error = 0;
3218
3219         sc = ic->ic_ifp->if_softc;
3220
3221         bzero((char *)&rkey, sizeof(rkey));
3222         len = sizeof(rkey);
3223
3224         rkey.nk_len = len;
3225         rkey.nk_keyidx = key->wk_keyix;
3226
3227         bcopy(ic->ic_ifp->if_broadcastaddr,
3228             rkey.nk_bssid, IEEE80211_ADDR_LEN);
3229
3230         error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len);
3231
3232         if (error)
3233                 return(0);
3234
3235         return(1);
3236 }
3237
3238 /*
3239  * In theory this could be called for any key, but we'll
3240  * only use it for WPA TKIP or AES keys. These need to be
3241  * set after initial authentication with the AP.
3242  */
3243
3244 static int
3245 ndis_add_key(ic, key, mac)
3246         struct ieee80211com     *ic;
3247         const struct ieee80211_key *key;
3248         const uint8_t           mac[IEEE80211_ADDR_LEN];
3249 {
3250         struct ndis_softc       *sc;
3251         ndis_80211_key          rkey;
3252         int                     len, error = 0;
3253
3254         sc = ic->ic_ifp->if_softc;
3255
3256         switch (key->wk_cipher->ic_cipher) {
3257         case IEEE80211_CIPHER_TKIP:
3258
3259                 len = sizeof(ndis_80211_key);
3260                 bzero((char *)&rkey, sizeof(rkey));
3261
3262                 rkey.nk_len = len;
3263                 rkey.nk_keylen = key->wk_keylen;
3264
3265                 if (key->wk_flags & IEEE80211_KEY_SWMIC)
3266                         rkey.nk_keylen += 16;
3267
3268                 /* key index - gets weird in NDIS */
3269
3270                 if (key->wk_keyix != IEEE80211_KEYIX_NONE)
3271                         rkey.nk_keyidx = key->wk_keyix;
3272                 else
3273                         rkey.nk_keyidx = 0;
3274
3275                 if (key->wk_flags & IEEE80211_KEY_XMIT)
3276                         rkey.nk_keyidx |= 1 << 31;
3277
3278                 if (key->wk_flags & IEEE80211_KEY_GROUP) {
3279                         bcopy(ic->ic_ifp->if_broadcastaddr,
3280                             rkey.nk_bssid, IEEE80211_ADDR_LEN);
3281                 } else {
3282                         bcopy(ic->ic_bss->ni_bssid,
3283                             rkey.nk_bssid, IEEE80211_ADDR_LEN);
3284                         /* pairwise key */
3285                         rkey.nk_keyidx |= 1 << 30;
3286                 }
3287
3288                 /* need to set bit 29 based on keyrsc */
3289                 rkey.nk_keyrsc = key->wk_keyrsc;
3290
3291                 if (rkey.nk_keyrsc)
3292                         rkey.nk_keyidx |= 1 << 29;
3293
3294                 if (key->wk_flags & IEEE80211_KEY_SWMIC) {
3295                         bcopy(key->wk_key, rkey.nk_keydata, 16);
3296                         bcopy(key->wk_key + 24, rkey.nk_keydata + 16, 8);
3297                         bcopy(key->wk_key + 16, rkey.nk_keydata + 24, 8);
3298                 } else
3299                         bcopy(key->wk_key, rkey.nk_keydata, key->wk_keylen);
3300
3301                 error = ndis_set_info(sc, OID_802_11_ADD_KEY, &rkey, &len);
3302                 break;
3303         case IEEE80211_CIPHER_WEP:
3304                 error = 0;
3305                 break;
3306         /*
3307          * I don't know how to set up keys for the AES
3308          * cipher yet. Is it the same as TKIP?
3309          */
3310         case IEEE80211_CIPHER_AES_CCM:
3311         default:
3312                 error = ENOTTY;
3313                 break;
3314         }
3315
3316         /* We need to return 1 for success, 0 for failure. */
3317
3318         if (error)
3319                 return(0);
3320
3321         return (1);
3322 }
3323 #endif
3324
3325 static int
3326 ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data)
3327 {
3328         struct ndis_softc       *sc;
3329         struct ieee80211req     *ireq;
3330         int                     error = EINVAL, len;
3331         ansi_string             as;
3332         unicode_string          us;
3333
3334         sc = ifp->if_softc;
3335         ireq = (struct ieee80211req *) data;
3336
3337         switch (ireq->i_type) {
3338 #ifdef IEEE80211_IOC_COUNTERMEASURES
3339         case IEEE80211_IOC_COUNTERMEASURES:
3340         case IEEE80211_IOC_DROPUNENCRYPTED:
3341                 error = 0;
3342                 break;
3343 #endif
3344         case IEEE80211_IOC_STATIONNAME:
3345                 error = priv_check(curthread, PRIV_NET80211_MANAGE);
3346                 if (error)
3347                         break;
3348                 if (ireq->i_val != 0 ||
3349                     ireq->i_len > IEEE80211_NWID_LEN) {
3350                         error = EINVAL;
3351                         break;
3352                 }
3353                 as.as_len = as.as_maxlen = ireq->i_len;
3354                 as.as_buf = ireq->i_data;
3355                 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE)) {
3356                         error = ENOMEM;
3357                         break;
3358                 }
3359                 len = us.us_len;
3360                 error = ndis_set_info(sc, OID_GEN_MACHINE_NAME,
3361                     us.us_buf, &len);
3362                 RtlFreeUnicodeString(&us);
3363                 break;
3364         default:
3365 #if __FreeBSD_version < 600007
3366                 error = ieee80211_ioctl(ifp, command, data);
3367 #else
3368                 error = ieee80211_ioctl(&sc->ic, command, data);
3369 #endif
3370                 if (error == ENETRESET) {
3371                         ndis_setstate_80211(sc);
3372                         error = 0;
3373                 }
3374         }
3375         
3376         return(error);
3377 }
3378
3379 static void
3380 ndis_resettask(d, arg)
3381         device_object           *d;
3382         void                    *arg;
3383 {
3384         struct ndis_softc               *sc;
3385
3386         sc = arg;
3387         ndis_reset_nic(sc);
3388         return;
3389 }
3390
3391 static void
3392 ndis_watchdog(ifp)
3393         struct ifnet            *ifp;
3394 {
3395         struct ndis_softc               *sc;
3396
3397         sc = ifp->if_softc;
3398
3399         NDIS_LOCK(sc);
3400         ifp->if_oerrors++;
3401         device_printf(sc->ndis_dev, "watchdog timeout\n");
3402         NDIS_UNLOCK(sc);
3403
3404         IoQueueWorkItem(sc->ndis_resetitem,
3405             (io_workitem_func)ndis_resettask_wrap,
3406             WORKQUEUE_CRITICAL, sc);
3407         IoQueueWorkItem(sc->ndis_startitem,
3408             (io_workitem_func)ndis_starttask_wrap,
3409             WORKQUEUE_CRITICAL, ifp);
3410
3411         return;
3412 }
3413
3414 /*
3415  * Stop the adapter and free any mbufs allocated to the
3416  * RX and TX lists.
3417  */
3418 static void
3419 ndis_stop(sc)
3420         struct ndis_softc               *sc;
3421 {
3422         struct ifnet            *ifp;
3423         struct ieee80211com     *ic;
3424         int                     i;
3425
3426         ic = &sc->ic;
3427         if (sc->ndis_80211)
3428                 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3429
3430         ifp = sc->ifp;
3431         untimeout(ndis_tick, sc, sc->ndis_stat_ch);
3432
3433         NDIS_LOCK(sc);
3434         ifp->if_timer = 0;
3435         sc->ndis_link = 0;
3436         ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3437         NDIS_UNLOCK(sc);
3438
3439         ndis_halt_nic(sc);
3440
3441         NDIS_LOCK(sc);
3442         for (i = 0; i < NDIS_EVENTS; i++) {
3443                 if (sc->ndis_evt[i].ne_sts && sc->ndis_evt[i].ne_buf != NULL)
3444                         free(sc->ndis_evt[i].ne_buf, M_TEMP);
3445                 sc->ndis_evt[i].ne_sts = 0;
3446                 sc->ndis_evt[i].ne_len = 0;
3447         }
3448         sc->ndis_evtcidx = 0;
3449         sc->ndis_evtpidx = 0;
3450         NDIS_UNLOCK(sc);
3451
3452         return;
3453 }
3454
3455 /*
3456  * Stop all chip I/O so that the kernel's probe routines don't
3457  * get confused by errant DMAs when rebooting.
3458  */
3459 void
3460 ndis_shutdown(dev)
3461         device_t                dev;
3462 {
3463         struct ndis_softc               *sc;
3464
3465         sc = device_get_softc(dev);
3466         ndis_stop(sc);
3467
3468         return;
3469 }
3470
3471 static int
3472 ndis_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
3473 {
3474         struct ifnet *ifp = ic->ic_ifp;
3475         struct ndis_softc *sc = ifp->if_softc;
3476          enum ieee80211_state ostate;
3477
3478         DPRINTF(("%s: %s -> %s\n", __func__,
3479                 ieee80211_state_name[ic->ic_state],
3480                 ieee80211_state_name[nstate]));
3481
3482         ostate = ic->ic_state;
3483         ic->ic_state = nstate;
3484
3485         switch (nstate) {
3486         /* pass on to net80211 */
3487         case IEEE80211_S_INIT:
3488         case IEEE80211_S_SCAN:
3489                 return (sc->ndis_newstate(ic, nstate, arg));
3490
3491         case IEEE80211_S_ASSOC:
3492                 if (ostate != IEEE80211_S_AUTH)
3493                         ndis_setstate_80211(sc);
3494                 break;
3495
3496         case IEEE80211_S_AUTH:
3497                 ndis_setstate_80211(sc);
3498                 break;
3499
3500         default:
3501                 break;
3502         }
3503         return (0);
3504 }
3505
3506 static void
3507 ndis_scan(void *arg, int npending)
3508 {
3509         struct ndis_softc *sc = arg;
3510         struct ieee80211com *ic = (void *)&sc->ic;
3511         struct ieee80211_scan_state *ss = ic->ic_scan;
3512         ndis_80211_ssid ssid;
3513         int error, len;
3514
3515         if (!NDIS_INITIALIZED(sc)) {
3516                 DPRINTF(("%s: scan aborted\n", __func__));
3517                 ieee80211_cancel_scan(ic);
3518                 return;
3519         }
3520
3521         if (ss->ss_nssid != 0) {
3522                 /* Perform a directed scan */
3523                 len = sizeof(ssid);
3524                 bzero((char *)&ssid, len);
3525                 ssid.ns_ssidlen = ss->ss_ssid[0].len;
3526                 bcopy(ss->ss_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen);
3527
3528                 error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
3529                 if (error)
3530                         DPRINTF(("%s: set ESSID failed\n", __func__));
3531         }
3532
3533         len = 0;
3534         error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN,
3535             NULL, &len);
3536         if (error) {
3537                 DPRINTF(("%s: scan command failed\n", __func__));
3538                 ieee80211_cancel_scan(ic);
3539                 return;
3540         }
3541
3542         pause("ssidscan", hz * 3);
3543         if (!NDIS_INITIALIZED(sc))
3544                 /* The interface was downed while we were sleeping */
3545                 return;
3546
3547         ndis_scan_results(sc);
3548         ieee80211_scan_done(ic);
3549 }
3550
3551 static void
3552 ndis_scan_results(struct ndis_softc *sc)
3553 {
3554         struct ieee80211com *ic = (void *)&sc->ic;
3555         ndis_80211_bssid_list_ex *bl;
3556         ndis_wlan_bssid_ex      *wb;
3557         struct ieee80211_scanparams sp;
3558         struct ieee80211_frame wh;
3559         int i, j;
3560         int error, len, rssi, noise, freq, chanflag;
3561         static long rstamp;
3562         uint8_t ssid[2+IEEE80211_NWID_LEN];
3563         uint8_t rates[2+IEEE80211_RATE_MAXSIZE];
3564         uint8_t *frm, *efrm;
3565
3566         len = 0;
3567         noise = -96;
3568         error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
3569         if (error != ENOSPC)
3570                 len = 65536;
3571         bl = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
3572         error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
3573         if (error) {
3574                 DPRINTF(("%s: failed to read\n", __func__));
3575                 free(bl, M_DEVBUF);
3576                 return;;
3577         }
3578
3579         DPRINTF(("%s: %d results\n", __func__, bl->nblx_items));
3580         rstamp++;
3581         wb = &bl->nblx_bssid[0];
3582         for (i = 0; i < bl->nblx_items; i++) {
3583                 memset(&sp, 0, sizeof(sp));
3584
3585                 memcpy(wh.i_addr2, wb->nwbx_macaddr, sizeof(wh.i_addr2));
3586                 memcpy(wh.i_addr3, wb->nwbx_macaddr, sizeof(wh.i_addr3));
3587                 rssi = 100 * (wb->nwbx_rssi - noise) / (-32 - noise);
3588                 rssi = max(0, min(rssi, 100));  /* limit 0 <= rssi <= 100 */
3589                 if (wb->nwbx_privacy)
3590                         sp.capinfo |= IEEE80211_CAPINFO_PRIVACY;
3591                 sp.bintval = wb->nwbx_config.nc_beaconperiod;
3592                 switch (wb->nwbx_netinfra) {
3593                         case NDIS_80211_NET_INFRA_IBSS:
3594                                 sp.capinfo |= IEEE80211_CAPINFO_IBSS;
3595                                 break;
3596                         case NDIS_80211_NET_INFRA_BSS:
3597                                 sp.capinfo |= IEEE80211_CAPINFO_ESS;
3598                                 break;
3599                 }
3600                 sp.rates = &rates[0];
3601                 for (j = 0; j < IEEE80211_RATE_MAXSIZE; j++) {
3602                         /* XXX - check units */
3603                         if (wb->nwbx_supportedrates[j] == 0)
3604                                 break;
3605                         rates[2 + j] =
3606                         wb->nwbx_supportedrates[j] & 0x7f;
3607                 }
3608                 rates[1] = j;
3609                 sp.ssid = (uint8_t *)&ssid[0];
3610                 memcpy(sp.ssid + 2, &wb->nwbx_ssid.ns_ssid,
3611                     wb->nwbx_ssid.ns_ssidlen);
3612                 sp.ssid[1] = wb->nwbx_ssid.ns_ssidlen;
3613
3614                 chanflag = ndis_nettype_chan(wb->nwbx_nettype);
3615                 freq = wb->nwbx_config.nc_dsconfig / 1000;
3616                 sp.bchan = ieee80211_mhz2ieee(freq, chanflag);
3617                 sp.curchan = ieee80211_find_channel(ic, freq, chanflag);
3618                 if (sp.curchan == NULL)
3619                         sp.curchan = &ic->ic_channels[0];
3620
3621                 /* Process extended info from AP */
3622                 if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
3623                         frm = (uint8_t *)&wb->nwbx_ies;
3624                         efrm = frm + wb->nwbx_ielen;
3625                         if (efrm - frm < 12)
3626                                 goto done;
3627                         sp.tstamp = frm;
3628                         frm += 8;
3629                         sp.bintval = le16toh(*(uint16_t *)frm);
3630                         frm += 2;
3631                         sp.capinfo = le16toh(*(uint16_t *)frm);
3632                         frm += 2;
3633
3634                         /* Grab variable length ies */
3635                         while (efrm - frm > 1) {
3636                                 if (efrm - frm < frm[1] + 2)
3637                                         break;
3638                                 switch (*frm) {
3639                                 case IEEE80211_ELEMID_RSN:
3640                                         sp.rsn = frm;
3641                                         break;
3642                                 }
3643                                 frm += frm[1] + 2;
3644                         }
3645                 }
3646 done:
3647                 DPRINTF(("scan: bssid %s chan %dMHz (%d/%d) rssi %d\n",
3648                     ether_sprintf(wb->nwbx_macaddr), freq, sp.bchan, chanflag,
3649                     rssi));
3650                 ieee80211_add_scan(ic, &sp, &wh, 0, rssi, noise, rstamp);
3651                 wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
3652         }
3653         free(bl, M_DEVBUF);
3654 }
3655
3656 static void
3657 ndis_scan_start(struct ieee80211com *ic)
3658 {
3659         struct ifnet *ifp = ic->ic_ifp;
3660         struct ndis_softc *sc = ifp->if_softc;
3661
3662         taskqueue_enqueue(sc->ndis_tq, &sc->ndis_scantask);
3663 }
3664
3665 static void
3666 ndis_set_channel(struct ieee80211com *ic)
3667 {
3668         /* ignore */
3669 }
3670
3671 static void
3672 ndis_scan_curchan(struct ieee80211com *ic, unsigned long maxdwell)
3673 {
3674         /* ignore */
3675 }
3676
3677 static void
3678 ndis_scan_mindwell(struct ieee80211com *ic)
3679 {
3680         /* NB: don't try to abort scan; wait for firmware to finish */
3681 }
3682
3683 static void
3684 ndis_scan_end(struct ieee80211com *ic)
3685 {
3686         /* ignore */
3687 }
3688