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