]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/if_ndis/if_ndis.c
Begin the first phase of trying to add IRP support (and ultimately
[FreeBSD/FreeBSD.git] / sys / dev / if_ndis / if_ndis.c
1 /*-
2  * Copyright (c) 2003
3  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include "opt_bdg.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/sockio.h>
41 #include <sys/mbuf.h>
42 #include <sys/malloc.h>
43 #include <sys/kernel.h>
44 #include <sys/socket.h>
45 #include <sys/queue.h>
46 #if __FreeBSD_version < 502113
47 #include <sys/sysctl.h>
48 #endif
49
50 #include <net/if.h>
51 #include <net/if_arp.h>
52 #include <net/ethernet.h>
53 #include <net/if_dl.h>
54 #include <net/if_media.h>
55 #include <net/route.h>
56
57 #include <net/bpf.h>
58
59 #include <machine/bus_memio.h>
60 #include <machine/bus_pio.h>
61 #include <machine/bus.h>
62 #include <machine/resource.h>
63 #include <sys/bus.h>
64 #include <sys/rman.h>
65
66 #include <net80211/ieee80211_var.h>
67 #include <net80211/ieee80211_ioctl.h>
68
69 #include <dev/wi/if_wavelan_ieee.h>
70
71 #include <dev/pci/pcireg.h>
72 #include <dev/pci/pcivar.h>
73
74 #include <compat/ndis/pe_var.h>
75 #include <compat/ndis/resource_var.h>
76 #include <compat/ndis/ntoskrnl_var.h>
77 #include <compat/ndis/hal_var.h>
78 #include <compat/ndis/ndis_var.h>
79 #include <compat/ndis/cfg_var.h>
80 #include <dev/if_ndis/if_ndisvar.h>
81
82 #define NDIS_IMAGE
83 #define NDIS_REGVALS
84
85 #include "ndis_driver_data.h"
86
87 int ndis_attach                 (device_t);
88 int ndis_detach                 (device_t);
89 int ndis_suspend                (device_t);
90 int ndis_resume                 (device_t);
91 void ndis_shutdown              (device_t);
92
93 static __stdcall void ndis_txeof        (ndis_handle,
94         ndis_packet *, ndis_status);
95 static __stdcall void ndis_rxeof        (ndis_handle,
96         ndis_packet **, uint32_t);
97 static __stdcall void ndis_linksts      (ndis_handle,
98         ndis_status, void *, uint32_t);
99 static __stdcall void ndis_linksts_done (ndis_handle);
100
101 static void ndis_intr           (void *);
102 static void ndis_intrtask       (void *);
103 static void ndis_tick           (void *);
104 static void ndis_ticktask       (void *);
105 static void ndis_start          (struct ifnet *);
106 static void ndis_starttask      (void *);
107 static int ndis_ioctl           (struct ifnet *, u_long, caddr_t);
108 static int ndis_wi_ioctl_get    (struct ifnet *, u_long, caddr_t);
109 static int ndis_wi_ioctl_set    (struct ifnet *, u_long, caddr_t);
110 static void ndis_init           (void *);
111 static void ndis_stop           (struct ndis_softc *);
112 static void ndis_watchdog       (struct ifnet *);
113 static int ndis_ifmedia_upd     (struct ifnet *);
114 static void ndis_ifmedia_sts    (struct ifnet *, struct ifmediareq *);
115 static int ndis_get_assoc       (struct ndis_softc *, ndis_wlan_bssid_ex **);
116 static int ndis_probe_offload   (struct ndis_softc *);
117 static int ndis_set_offload     (struct ndis_softc *);
118 static void ndis_getstate_80211 (struct ndis_softc *);
119 static void ndis_setstate_80211 (struct ndis_softc *);
120 static void ndis_media_status   (struct ifnet *, struct ifmediareq *);
121
122 static void ndis_setmulti       (struct ndis_softc *);
123 static void ndis_map_sclist     (void *, bus_dma_segment_t *,
124         int, bus_size_t, int);
125
126 extern struct mtx_pool *ndis_mtxpool;
127
128 /*
129  * Program the 64-bit multicast hash filter.
130  */
131 static void
132 ndis_setmulti(sc)
133         struct ndis_softc       *sc;
134 {
135         struct ifnet            *ifp;
136         struct ifmultiaddr      *ifma;
137         int                     len, mclistsz, error;
138         uint8_t                 *mclist;
139
140         ifp = &sc->arpcom.ac_if;
141
142         if (!NDIS_INITIALIZED(sc))
143                 return;
144
145         if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
146                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
147                 len = sizeof(sc->ndis_filter);
148                 error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
149                     &sc->ndis_filter, &len);
150                 if (error)
151                         device_printf (sc->ndis_dev,
152                             "set filter failed: %d\n", error);
153                 return;
154         }
155
156         if (TAILQ_EMPTY(&ifp->if_multiaddrs))
157                 return;
158
159         len = sizeof(mclistsz);
160         ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len);
161
162         mclist = malloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_NOWAIT|M_ZERO);
163
164         if (mclist == NULL) {
165                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
166                 goto out;
167         }
168
169         sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST;
170
171         len = 0;
172         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
173                 if (ifma->ifma_addr->sa_family != AF_LINK)
174                         continue;
175                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
176                     mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN);
177                 len++;
178                 if (len > mclistsz) {
179                         sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
180                         sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
181                         goto out;
182                 }
183         }
184
185         len = len * ETHER_ADDR_LEN;
186         error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len);
187         if (error) {
188                 device_printf (sc->ndis_dev, "set mclist failed: %d\n", error);
189                 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
190                 sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
191         }
192
193 out:
194         free(mclist, M_TEMP);
195
196         len = sizeof(sc->ndis_filter);
197         error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
198             &sc->ndis_filter, &len);
199         if (error)
200                 device_printf (sc->ndis_dev, "set filter failed: %d\n", error);
201
202         return;
203 }
204
205 static int
206 ndis_set_offload(sc)
207         struct ndis_softc       *sc;
208 {
209         ndis_task_offload       *nto;
210         ndis_task_offload_hdr   *ntoh;
211         ndis_task_tcpip_csum    *nttc;
212         struct ifnet            *ifp;
213         int                     len, error;
214
215         ifp = &sc->arpcom.ac_if;
216
217         if (!NDIS_INITIALIZED(sc))
218                 return(EINVAL);
219
220         /* See if there's anything to set. */
221
222         error = ndis_probe_offload(sc);
223         if (error)
224                 return(error);
225                 
226         if (sc->ndis_hwassist == 0 && ifp->if_capabilities == 0)
227                 return(0);
228
229         len = sizeof(ndis_task_offload_hdr) + sizeof(ndis_task_offload) +
230             sizeof(ndis_task_tcpip_csum);
231
232         ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
233
234         if (ntoh == NULL)
235                 return(ENOMEM);
236
237         ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
238         ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
239         ntoh->ntoh_offset_firsttask = sizeof(ndis_task_offload_hdr);
240         ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
241         ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
242         ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
243
244         nto = (ndis_task_offload *)((char *)ntoh +
245             ntoh->ntoh_offset_firsttask);
246
247         nto->nto_vers = NDIS_TASK_OFFLOAD_VERSION;
248         nto->nto_len = sizeof(ndis_task_offload);
249         nto->nto_task = NDIS_TASK_TCPIP_CSUM;
250         nto->nto_offset_nexttask = 0;
251         nto->nto_taskbuflen = sizeof(ndis_task_tcpip_csum);
252
253         nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
254
255         if (ifp->if_capenable & IFCAP_TXCSUM)
256                 nttc->nttc_v4tx = sc->ndis_v4tx;
257
258         if (ifp->if_capenable & IFCAP_RXCSUM)
259                 nttc->nttc_v4rx = sc->ndis_v4rx;
260
261         error = ndis_set_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
262         free(ntoh, M_TEMP);
263
264         return(error);
265 }
266
267 static int
268 ndis_probe_offload(sc)
269         struct ndis_softc       *sc;
270 {
271         ndis_task_offload       *nto;
272         ndis_task_offload_hdr   *ntoh;
273         ndis_task_tcpip_csum    *nttc = NULL;
274         struct ifnet            *ifp;
275         int                     len, error, dummy;
276
277         ifp = &sc->arpcom.ac_if;
278
279         len = sizeof(dummy);
280         error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, &dummy, &len);
281
282         if (error != ENOSPC)
283                 return(error);
284
285         ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
286
287         if (ntoh == NULL)
288                 return(ENOMEM);
289
290         ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
291         ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
292         ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
293         ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
294         ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
295
296         error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
297
298         if (error) {
299                 free(ntoh, M_TEMP);
300                 return(error);
301         }
302
303         if (ntoh->ntoh_vers != NDIS_TASK_OFFLOAD_VERSION) {
304                 free(ntoh, M_TEMP);
305                 return(EINVAL);
306         }
307
308         nto = (ndis_task_offload *)((char *)ntoh +
309             ntoh->ntoh_offset_firsttask);
310
311         while (1) {
312                 switch (nto->nto_task) {
313                 case NDIS_TASK_TCPIP_CSUM:
314                         nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
315                         break;
316                 /* Don't handle these yet. */
317                 case NDIS_TASK_IPSEC:
318                 case NDIS_TASK_TCP_LARGESEND:
319                 default:
320                         break;
321                 }
322                 if (nto->nto_offset_nexttask == 0)
323                         break;
324                 nto = (ndis_task_offload *)((char *)nto +
325                     nto->nto_offset_nexttask);
326         }
327
328         if (nttc == NULL) {
329                 free(ntoh, M_TEMP);
330                 return(ENOENT);
331         }
332
333         sc->ndis_v4tx = nttc->nttc_v4tx;
334         sc->ndis_v4rx = nttc->nttc_v4rx;
335
336         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_IP_CSUM)
337                 sc->ndis_hwassist |= CSUM_IP;
338         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
339                 sc->ndis_hwassist |= CSUM_TCP;
340         if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
341                 sc->ndis_hwassist |= CSUM_UDP;
342
343         if (sc->ndis_hwassist)
344                 ifp->if_capabilities |= IFCAP_TXCSUM;
345
346         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_IP_CSUM)
347                 ifp->if_capabilities |= IFCAP_RXCSUM;
348         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
349                 ifp->if_capabilities |= IFCAP_RXCSUM;
350         if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
351                 ifp->if_capabilities |= IFCAP_RXCSUM;
352
353         free(ntoh, M_TEMP);
354         return(0);
355 }
356
357 /*
358  * Attach the interface. Allocate softc structures, do ifmedia
359  * setup and ethernet/BPF attach.
360  */
361 int
362 ndis_attach(dev)
363         device_t                dev;
364 {
365         u_char                  eaddr[ETHER_ADDR_LEN];
366         struct ndis_softc       *sc;
367         struct ifnet            *ifp = NULL;
368         void                    *img;
369         int                     error = 0, len;
370         int                     i;
371
372         sc = device_get_softc(dev);
373
374         mtx_init(&sc->ndis_mtx, "ndis softc lock",
375             MTX_NETWORK_LOCK, MTX_DEF);
376         mtx_init(&sc->ndis_intrmtx,
377             "ndis irq lock", MTX_NETWORK_LOCK, MTX_DEF);
378
379         /*
380          * Hook interrupt early, since calling the driver's
381          * init routine may trigger an interrupt.
382          */
383
384         error = bus_setup_intr(dev, sc->ndis_irq, INTR_TYPE_NET | INTR_MPSAFE,
385             ndis_intr, sc, &sc->ndis_intrhand);
386
387         if (error) {
388                 device_printf(dev, "couldn't set up irq\n");
389                 goto fail;
390         }
391
392         if (sc->ndis_iftype == PCMCIABus) {
393                 error = ndis_alloc_amem(sc);
394                 if (error) {
395                         device_printf(dev, "failed to allocate "
396                             "attribute memory\n");
397                         goto fail;
398                 }
399         }
400
401         sc->ndis_regvals = ndis_regvals;
402
403 #if __FreeBSD_version < 502113
404         sysctl_ctx_init(&sc->ndis_ctx);
405
406 #endif
407         /* Create sysctl registry nodes */
408         ndis_create_sysctls(sc);
409
410         /* Set up driver image in memory. */
411         img = drv_data;
412         ndis_load_driver((vm_offset_t)img, sc);
413
414         /* Tell the user what version of the API the driver is using. */
415         device_printf(dev, "NDIS API version: %d.%d\n",
416             sc->ndis_chars.nmc_version_major,
417             sc->ndis_chars.nmc_version_minor);
418
419         /* Do resource conversion. */
420         ndis_convert_res(sc);
421
422         /* Install our RX and TX interrupt handlers. */
423         sc->ndis_block.nmb_senddone_func = ndis_txeof;
424         sc->ndis_block.nmb_pktind_func = ndis_rxeof;
425
426         /* Call driver's init routine. */
427         if (ndis_init_nic(sc)) {
428                 device_printf (dev, "init handler failed\n");
429                 error = ENXIO;
430                 goto fail;
431         }
432
433         /*
434          * Get station address from the driver.
435          */
436         len = sizeof(eaddr);
437         ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len);
438
439         bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
440
441         /*
442          * Figure out if we're allowed to use multipacket sends
443          * with this driver, and if so, how many.
444          */
445
446         if (sc->ndis_chars.nmc_sendsingle_func &&
447             sc->ndis_chars.nmc_sendmulti_func == NULL) {
448                 sc->ndis_maxpkts = 1;
449         } else {
450                 len = sizeof(sc->ndis_maxpkts);
451                 ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS,
452                     &sc->ndis_maxpkts, &len);
453         }
454
455         sc->ndis_txarray = malloc(sizeof(ndis_packet *) *
456             sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT|M_ZERO);
457
458         sc->ndis_txpending = sc->ndis_maxpkts;
459
460         sc->ndis_oidcnt = 0;
461         /* Get supported oid list. */
462         ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt);
463
464         /* If the NDIS module requested scatter/gather, init maps. */
465         if (sc->ndis_sc)
466                 ndis_init_dma(sc);
467
468         /*
469          * See if the OID_802_11_CONFIGURATION OID is
470          * supported by this driver. If it is, then this an 802.11
471          * wireless driver, and we should set up media for wireless.
472          */
473         for (i = 0; i < sc->ndis_oidcnt; i++) {
474                 if (sc->ndis_oids[i] == OID_802_11_CONFIGURATION) {
475                         sc->ndis_80211++;
476                         break;
477                 }
478         }
479
480         /* Check for task offload support. */
481         ndis_probe_offload(sc);
482
483         ifp = &sc->arpcom.ac_if;
484         ifp->if_softc = sc;
485         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
486         ifp->if_mtu = ETHERMTU;
487         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
488         ifp->if_ioctl = ndis_ioctl;
489         ifp->if_start = ndis_start;
490         ifp->if_watchdog = ndis_watchdog;
491         ifp->if_init = ndis_init;
492         ifp->if_baudrate = 10000000;
493 #if __FreeBSD_version < 502114
494         ifp->if_snd.ifq_maxlen = 50;
495 #else
496         IFQ_SET_MAXLEN(&ifp->if_snd, 50);
497         ifp->if_snd.ifq_drv_maxlen = 25;
498         IFQ_SET_READY(&ifp->if_snd);
499 #endif
500         ifp->if_capenable = ifp->if_capabilities;
501         ifp->if_hwassist = sc->ndis_hwassist;
502
503         /* Do media setup */
504         if (sc->ndis_80211) {
505                 struct ieee80211com     *ic = (void *)&sc->ic;
506                 ndis_80211_rates_ex     rates;
507                 struct ndis_80211_nettype_list *ntl;
508                 uint32_t                arg;
509                 int                     r;
510
511                 ic->ic_ifp = ifp;
512                 ic->ic_phytype = IEEE80211_T_DS;
513                 ic->ic_opmode = IEEE80211_M_STA;
514                 ic->ic_caps = IEEE80211_C_IBSS;
515                 ic->ic_state = IEEE80211_S_ASSOC;
516                 ic->ic_modecaps = (1<<IEEE80211_MODE_AUTO);
517                 len = 0;
518                 r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
519                     NULL, &len);
520                 if (r != ENOSPC)
521                         goto nonettypes;
522                 ntl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
523                 r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
524                     ntl, &len);
525                 if (r != 0) {
526                         free(ntl, M_DEVBUF);
527                         goto nonettypes;
528                 }
529
530                 for (i = 0; i < ntl->ntl_items; i++) {
531                         switch (ntl->ntl_type[i]) {
532                         case NDIS_80211_NETTYPE_11FH:
533                         case NDIS_80211_NETTYPE_11DS:
534                                 ic->ic_modecaps |= (1<<IEEE80211_MODE_11B);
535                                 break;
536                         case NDIS_80211_NETTYPE_11OFDM5:
537                                 ic->ic_modecaps |= (1<<IEEE80211_MODE_11A);
538                                 break;
539                         case NDIS_80211_NETTYPE_11OFDM24:
540                                 ic->ic_modecaps |= (1<<IEEE80211_MODE_11G);
541                                 break;
542                         default:
543                                 break;
544                         }
545                 }
546                 free(ntl, M_DEVBUF);
547 nonettypes:
548                 len = sizeof(rates);
549                 bzero((char *)&rates, len);
550                 r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES,
551                     (void *)rates, &len);
552                 if (r)
553                         device_printf (dev, "get rates failed: 0x%x\n", r);
554                 /*
555                  * Since the supported rates only up to 8 can be supported,
556                  * if this is not 802.11b we're just going to be faking it
557                  * all up to heck.
558                  */
559
560 #define TESTSETRATE(x, y)                                               \
561         do {                                                            \
562                 int                     i;                              \
563                 for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) {   \
564                         if (ic->ic_sup_rates[x].rs_rates[i] == (y))     \
565                                 break;                                  \
566                 }                                                       \
567                 if (i == ic->ic_sup_rates[x].rs_nrates) {               \
568                         ic->ic_sup_rates[x].rs_rates[i] = (y);          \
569                         ic->ic_sup_rates[x].rs_nrates++;                \
570                 }                                                       \
571         } while (0)
572
573 #define SETRATE(x, y)   \
574         ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y)
575 #define INCRATE(x)      \
576         ic->ic_sup_rates[x].rs_nrates++
577
578                 ic->ic_curmode = IEEE80211_MODE_AUTO;
579                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A))
580                         ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0;
581                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B))
582                         ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0;
583                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G))
584                         ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0;
585                 for (i = 0; i < len; i++) {
586                         switch (rates[i] & IEEE80211_RATE_VAL) {
587                         case 2:
588                         case 4:
589                         case 11:
590                         case 10:
591                         case 22:
592                                 if (!(ic->ic_modecaps &
593                                     (1<<IEEE80211_MODE_11B))) {
594                                         /* Lazy-init 802.11b. */
595                                         ic->ic_modecaps |=
596                                             (1<<IEEE80211_MODE_11B);
597                                         ic->ic_sup_rates[IEEE80211_MODE_11B].
598                                             rs_nrates = 0;
599                                 }
600                                 SETRATE(IEEE80211_MODE_11B, rates[i]);
601                                 INCRATE(IEEE80211_MODE_11B);
602                                 break;
603                         default:
604                                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
605                                         SETRATE(IEEE80211_MODE_11A, rates[i]);
606                                         INCRATE(IEEE80211_MODE_11A);
607                                 }
608                                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
609                                         SETRATE(IEEE80211_MODE_11G, rates[i]);
610                                         INCRATE(IEEE80211_MODE_11G);
611                                 }
612                                 break;
613                         }
614                 }
615
616                 /*
617                  * If the hardware supports 802.11g, it most
618                  * likely supports 802.11b and all of the
619                  * 802.11b and 802.11g speeds, so maybe we can
620                  * just cheat here.  Just how in the heck do
621                  * we detect turbo modes, though?
622                  */
623                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
624                         TESTSETRATE(IEEE80211_MODE_11B,
625                             IEEE80211_RATE_BASIC|2);
626                         TESTSETRATE(IEEE80211_MODE_11B,
627                             IEEE80211_RATE_BASIC|4);
628                         TESTSETRATE(IEEE80211_MODE_11B,
629                             IEEE80211_RATE_BASIC|11);
630                         TESTSETRATE(IEEE80211_MODE_11B,
631                             IEEE80211_RATE_BASIC|22);
632                 }
633                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
634                         TESTSETRATE(IEEE80211_MODE_11G, 47);
635                         TESTSETRATE(IEEE80211_MODE_11G, 72);
636                         TESTSETRATE(IEEE80211_MODE_11G, 96);
637                         TESTSETRATE(IEEE80211_MODE_11G, 108);
638                 }
639                 if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
640                         TESTSETRATE(IEEE80211_MODE_11A, 47);
641                         TESTSETRATE(IEEE80211_MODE_11A, 72);
642                         TESTSETRATE(IEEE80211_MODE_11A, 96);
643                         TESTSETRATE(IEEE80211_MODE_11A, 108);
644                 }
645 #undef SETRATE
646 #undef INCRATE
647                 /*
648                  * Taking yet more guesses here.
649                  */
650                 for (i = 1; i < IEEE80211_CHAN_MAX; i++) {
651                         int chanflag = 0;
652
653                         if (ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates)
654                                 chanflag |= IEEE80211_CHAN_G;
655                         if (i <= 14)
656                                 chanflag |= IEEE80211_CHAN_B;
657                         if (ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates &&
658                             i > 14)
659                                 chanflag = IEEE80211_CHAN_A;
660                         if (chanflag == 0)
661                                 break;
662                         ic->ic_channels[i].ic_freq =
663                             ieee80211_ieee2mhz(i, chanflag);
664                         ic->ic_channels[i].ic_flags = chanflag;
665                 }
666
667                 i = sizeof(arg);
668                 r = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &i);
669                 if (arg != NDIS_80211_WEPSTAT_NOTSUPPORTED)
670                         ic->ic_caps |= IEEE80211_C_WEP;
671                 i = sizeof(arg);
672                 r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i);
673                 if (r == 0)
674                         ic->ic_caps |= IEEE80211_C_PMGT;
675                 bcopy(eaddr, &ic->ic_myaddr, sizeof(eaddr));
676                 ieee80211_ifattach(ic);
677                 ieee80211_media_init(ic, ieee80211_media_change,
678                     ndis_media_status);
679                 ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
680                 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
681         } else {
682                 ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd,
683                     ndis_ifmedia_sts);
684                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
685                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
686                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
687                 ifmedia_add(&sc->ifmedia,
688                     IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
689                 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
690                 ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
691                 ether_ifattach(ifp, eaddr);
692         }
693
694         /* Override the status handler so we can detect link changes. */
695         sc->ndis_block.nmb_status_func = ndis_linksts;
696         sc->ndis_block.nmb_statusdone_func = ndis_linksts_done;
697 fail:
698         if (error)
699                 ndis_detach(dev);
700         else
701                 /* We're done talking to the NIC for now; halt it. */
702                 ndis_halt_nic(sc);
703
704         return(error);
705 }
706
707 /*
708  * Shutdown hardware and free up resources. This can be called any
709  * time after the mutex has been initialized. It is called in both
710  * the error case in attach and the normal detach case so it needs
711  * to be careful about only freeing resources that have actually been
712  * allocated.
713  */
714 int
715 ndis_detach(dev)
716         device_t                dev;
717 {
718         struct ndis_softc       *sc;
719         struct ifnet            *ifp;
720
721         sc = device_get_softc(dev);
722         KASSERT(mtx_initialized(&sc->ndis_mtx),
723             ("ndis mutex not initialized"));
724         KASSERT(mtx_initialized(&sc->ndis_intrmtx),
725             ("ndis interrupt mutex not initialized"));
726         NDIS_LOCK(sc);
727         ifp = &sc->arpcom.ac_if;
728         ifp->if_flags &= ~IFF_UP;
729
730         if (device_is_attached(dev)) {
731                 NDIS_UNLOCK(sc);
732                 ndis_stop(sc);
733                 if (sc->ndis_80211)
734                         ieee80211_ifdetach(&sc->ic);
735                 else
736                         ether_ifdetach(ifp);
737         } else
738                 NDIS_UNLOCK(sc);
739
740         bus_generic_detach(dev);
741
742         if (sc->ndis_intrhand)
743                 bus_teardown_intr(dev, sc->ndis_irq, sc->ndis_intrhand);
744         if (sc->ndis_irq)
745                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq);
746         if (sc->ndis_res_io)
747                 bus_release_resource(dev, SYS_RES_IOPORT,
748                     sc->ndis_io_rid, sc->ndis_res_io);
749         if (sc->ndis_res_mem)
750                 bus_release_resource(dev, SYS_RES_MEMORY,
751                     sc->ndis_mem_rid, sc->ndis_res_mem);
752         if (sc->ndis_res_altmem)
753                 bus_release_resource(dev, SYS_RES_MEMORY,
754                     sc->ndis_altmem_rid, sc->ndis_res_altmem);
755
756         if (sc->ndis_iftype == PCMCIABus)
757                 ndis_free_amem(sc);
758
759         if (sc->ndis_sc)
760                 ndis_destroy_dma(sc);
761
762         if (sc->ndis_txarray)
763                 free(sc->ndis_txarray, M_DEVBUF);
764
765         if (!sc->ndis_80211)
766                 ifmedia_removeall(&sc->ifmedia);
767
768         ndis_unload_driver(sc);
769
770         if (sc->ndis_iftype == PCIBus)
771                 bus_dma_tag_destroy(sc->ndis_parent_tag);
772
773 #if __FreeBSD_version < 502113
774         sysctl_ctx_free(&sc->ndis_ctx);
775 #endif
776
777         mtx_destroy(&sc->ndis_mtx);
778         mtx_destroy(&sc->ndis_intrmtx);
779
780         return(0);
781 }
782
783 int
784 ndis_suspend(dev)
785         device_t                dev;
786 {
787         struct ndis_softc       *sc;
788         struct ifnet            *ifp;
789
790         sc = device_get_softc(dev);
791         ifp = &sc->arpcom.ac_if;
792
793 #ifdef notdef
794         if (NDIS_INITIALIZED(sc))
795                 ndis_stop(sc);
796 #endif
797
798         return(0);
799 }
800
801 int
802 ndis_resume(dev)
803         device_t                dev;
804 {
805         struct ndis_softc       *sc;
806         struct ifnet            *ifp;
807
808         sc = device_get_softc(dev);
809         ifp = &sc->arpcom.ac_if;
810
811         if (NDIS_INITIALIZED(sc))
812                 ndis_init(sc);
813
814         return(0);
815 }
816
817 /*
818  * A frame has been uploaded: pass the resulting mbuf chain up to
819  * the higher level protocols.
820  *
821  * When handling received NDIS packets, the 'status' field in the
822  * out-of-band portion of the ndis_packet has special meaning. In the
823  * most common case, the underlying NDIS driver will set this field
824  * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
825  * take posession of it. We then change the status field to
826  * NDIS_STATUS_PENDING to tell the driver that we now own the packet,
827  * and that we will return it at some point in the future via the
828  * return packet handler.
829  *
830  * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
831  * this means the driver is running out of packet/buffer resources and
832  * wants to maintain ownership of the packet. In this case, we have to
833  * copy the packet data into local storage and let the driver keep the
834  * packet.
835  */
836 __stdcall static void
837 ndis_rxeof(adapter, packets, pktcnt)
838         ndis_handle             adapter;
839         ndis_packet             **packets;
840         uint32_t                pktcnt;
841 {
842         struct ndis_softc       *sc;
843         ndis_miniport_block     *block;
844         ndis_packet             *p;
845         uint32_t                s;
846         ndis_tcpip_csum         *csum;
847         struct ifnet            *ifp;
848         struct mbuf             *m0, *m;
849         int                     i;
850
851         block = (ndis_miniport_block *)adapter;
852         sc = (struct ndis_softc *)(block->nmb_ifp->if_softc);
853         ifp = block->nmb_ifp;
854
855         for (i = 0; i < pktcnt; i++) {
856                 p = packets[i];
857                 /* Stash the softc here so ptom can use it. */
858                 p->np_softc = sc;
859                 if (ndis_ptom(&m0, p)) {
860                         device_printf (sc->ndis_dev, "ptom failed\n");
861                         if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
862                                 ndis_return_packet(sc, p);
863                 } else {
864                         if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
865                                 m = m_dup(m0, M_DONTWAIT);
866                                 /*
867                                  * NOTE: we want to destroy the mbuf here, but
868                                  * we don't actually want to return it to the
869                                  * driver via the return packet handler. By
870                                  * bumping np_refcnt, we can prevent the
871                                  * ndis_return_packet() routine from actually
872                                  * doing anything.
873                                  */
874                                 p->np_refcnt++;
875                                 m_freem(m0);
876                                 if (m == NULL)
877                                         ifp->if_ierrors++;
878                                 else
879                                         m0 = m;
880                         } else
881                                 p->np_oob.npo_status = NDIS_STATUS_PENDING;
882                         m0->m_pkthdr.rcvif = ifp;
883                         ifp->if_ipackets++;
884
885                         /* Deal with checksum offload. */
886
887                         if (ifp->if_capenable & IFCAP_RXCSUM &&
888                             p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) {
889                                 s = (uintptr_t)
890                                     p->np_ext.npe_info[ndis_tcpipcsum_info];
891                                 csum = (ndis_tcpip_csum *)&s;
892                                 if (csum->u.ntc_rxflags &
893                                     NDIS_RXCSUM_IP_PASSED)
894                                         m0->m_pkthdr.csum_flags |=
895                                             CSUM_IP_CHECKED|CSUM_IP_VALID;
896                                 if (csum->u.ntc_rxflags &
897                                     (NDIS_RXCSUM_TCP_PASSED |
898                                     NDIS_RXCSUM_UDP_PASSED)) {
899                                         m0->m_pkthdr.csum_flags |=
900                                             CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
901                                         m0->m_pkthdr.csum_data = 0xFFFF;
902                                 }
903                         }
904
905                         (*ifp->if_input)(ifp, m0);
906                 }
907         }
908
909         return;
910 }
911
912 /*
913  * A frame was downloaded to the chip. It's safe for us to clean up
914  * the list buffers.
915  */
916 __stdcall static void
917 ndis_txeof(adapter, packet, status)
918         ndis_handle             adapter;
919         ndis_packet             *packet;
920         ndis_status             status;
921
922 {
923         struct ndis_softc       *sc;
924         ndis_miniport_block     *block;
925         struct ifnet            *ifp;
926         int                     idx;
927         struct mbuf             *m;
928
929         block = (ndis_miniport_block *)adapter;
930         sc = (struct ndis_softc *)block->nmb_ifp->if_softc;
931         ifp = block->nmb_ifp;
932
933         m = packet->np_m0;
934         idx = packet->np_txidx;
935         if (sc->ndis_sc)
936                 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
937
938         ndis_free_packet(packet);
939         m_freem(m);
940
941         NDIS_LOCK(sc);
942         sc->ndis_txarray[idx] = NULL;
943         sc->ndis_txpending++;
944
945         if (status == NDIS_STATUS_SUCCESS)
946                 ifp->if_opackets++;
947         else
948                 ifp->if_oerrors++;
949         ifp->if_timer = 0;
950         ifp->if_flags &= ~IFF_OACTIVE;
951         NDIS_UNLOCK(sc);
952
953         ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
954
955         return;
956 }
957
958 __stdcall static void
959 ndis_linksts(adapter, status, sbuf, slen)
960         ndis_handle             adapter;
961         ndis_status             status;
962         void                    *sbuf;
963         uint32_t                slen;
964 {
965         ndis_miniport_block     *block;
966
967         block = adapter;
968         block->nmb_getstat = status;
969
970         return;
971 }
972
973 __stdcall static void
974 ndis_linksts_done(adapter)
975         ndis_handle             adapter;
976 {
977         ndis_miniport_block     *block;
978         struct ndis_softc       *sc;
979         struct ifnet            *ifp;
980
981         block = adapter;
982         ifp = block->nmb_ifp;
983         sc = ifp->if_softc;
984
985         NDIS_LOCK(sc);
986         if (!NDIS_INITIALIZED(sc)) {
987                 NDIS_UNLOCK(sc);
988                 return;
989         }
990
991         switch (block->nmb_getstat) {
992         case NDIS_STATUS_MEDIA_CONNECT:
993                 ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
994                 ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
995                 break;
996         case NDIS_STATUS_MEDIA_DISCONNECT:
997                 if (sc->ndis_link)
998                         ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
999                 break;
1000         default:
1001                 break;
1002         }
1003
1004         NDIS_UNLOCK(sc);
1005         return;
1006 }
1007
1008 static void
1009 ndis_intrtask(arg)
1010         void                    *arg;
1011 {
1012         struct ndis_softc       *sc;
1013         struct ifnet            *ifp;
1014         uint8_t                 irql;
1015
1016         sc = arg;
1017         ifp = &sc->arpcom.ac_if;
1018
1019         irql = KeRaiseIrql(DISPATCH_LEVEL);
1020         ndis_intrhand(sc);
1021         KeLowerIrql(irql);
1022         mtx_lock(&sc->ndis_intrmtx);
1023         ndis_enable_intr(sc);
1024         mtx_unlock(&sc->ndis_intrmtx);
1025
1026         return;
1027 }
1028
1029 static void
1030 ndis_intr(arg)
1031         void                    *arg;
1032 {
1033         struct ndis_softc       *sc;
1034         struct ifnet            *ifp;
1035         int                     is_our_intr = 0;
1036         int                     call_isr = 0;
1037
1038         sc = arg;
1039         ifp = &sc->arpcom.ac_if;
1040
1041         if (sc->ndis_block.nmb_miniportadapterctx == NULL)
1042                 return;
1043
1044         mtx_lock(&sc->ndis_intrmtx);
1045         if (sc->ndis_block.nmb_interrupt->ni_isrreq == TRUE)
1046                 ndis_isr(sc, &is_our_intr, &call_isr);
1047         else {
1048                 ndis_disable_intr(sc);
1049                 call_isr = 1;
1050         }
1051         mtx_unlock(&sc->ndis_intrmtx);
1052
1053         if ((is_our_intr || call_isr))
1054                 ndis_sched(ndis_intrtask, ifp->if_softc, NDIS_SWI);
1055
1056         return;
1057 }
1058
1059 static void
1060 ndis_tick(xsc)
1061         void                    *xsc;
1062 {
1063         struct ndis_softc       *sc;
1064
1065         mtx_unlock(&Giant);
1066
1067         sc = xsc;
1068
1069         ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
1070         sc->ndis_stat_ch = timeout(ndis_tick, sc, hz *
1071             sc->ndis_block.nmb_checkforhangsecs);
1072
1073         mtx_lock(&Giant);
1074
1075         return;
1076 }
1077
1078 static void
1079 ndis_ticktask(xsc)
1080         void                    *xsc;
1081 {
1082         struct ndis_softc       *sc;
1083         __stdcall ndis_checkforhang_handler hangfunc;
1084         uint8_t                 rval;
1085         ndis_media_state        linkstate;
1086         int                     error, len;
1087
1088         sc = xsc;
1089
1090         hangfunc = sc->ndis_chars.nmc_checkhang_func;
1091
1092         if (hangfunc != NULL) {
1093                 rval = hangfunc(sc->ndis_block.nmb_miniportadapterctx);
1094                 if (rval == TRUE) {
1095                         ndis_reset_nic(sc);
1096                         return;
1097                 }
1098         }
1099
1100         len = sizeof(linkstate);
1101         error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
1102             (void *)&linkstate, &len);
1103
1104         NDIS_LOCK(sc);
1105
1106         if (sc->ndis_link == 0 && linkstate == nmc_connected) {
1107                 device_printf(sc->ndis_dev, "link up\n");
1108                 sc->ndis_link = 1;
1109                 NDIS_UNLOCK(sc);
1110                 if (sc->ndis_80211)
1111                         ndis_getstate_80211(sc);
1112                 NDIS_LOCK(sc);
1113 #ifdef LINK_STATE_UP
1114                 sc->arpcom.ac_if.if_link_state = LINK_STATE_UP;
1115                 rt_ifmsg(&(sc->arpcom.ac_if));
1116 #endif /* LINK_STATE_UP */
1117         }
1118
1119         if (sc->ndis_link == 1 && linkstate == nmc_disconnected) {
1120                 device_printf(sc->ndis_dev, "link down\n");
1121                 sc->ndis_link = 0;
1122 #ifdef LINK_STATE_DOWN
1123                 sc->arpcom.ac_if.if_link_state = LINK_STATE_DOWN;
1124                 rt_ifmsg(&(sc->arpcom.ac_if));
1125 #endif /* LINK_STATE_DOWN */
1126         }
1127
1128         NDIS_UNLOCK(sc);
1129
1130         return;
1131 }
1132
1133 static void
1134 ndis_map_sclist(arg, segs, nseg, mapsize, error)
1135         void                    *arg;
1136         bus_dma_segment_t       *segs;
1137         int                     nseg;
1138         bus_size_t              mapsize;
1139         int                     error;
1140
1141 {
1142         struct ndis_sc_list     *sclist;
1143         int                     i;
1144
1145         if (error || arg == NULL)
1146                 return;
1147
1148         sclist = arg;
1149
1150         sclist->nsl_frags = nseg;
1151
1152         for (i = 0; i < nseg; i++) {
1153                 sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr;
1154                 sclist->nsl_elements[i].nse_len = segs[i].ds_len;
1155         }
1156
1157         return;
1158 }
1159
1160 static void
1161 ndis_starttask(arg)
1162         void                    *arg;
1163 {
1164         struct ifnet            *ifp;
1165
1166         ifp = arg;
1167 #if __FreeBSD_version < 502114
1168         if (ifp->if_snd.ifq_head != NULL)
1169 #else
1170         if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1171 #endif
1172                 ndis_start(ifp);
1173         return;
1174 }
1175
1176 /*
1177  * Main transmit routine. To make NDIS drivers happy, we need to
1178  * transform mbuf chains into NDIS packets and feed them to the
1179  * send packet routines. Most drivers allow you to send several
1180  * packets at once (up to the maxpkts limit). Unfortunately, rather
1181  * that accepting them in the form of a linked list, they expect
1182  * a contiguous array of pointers to packets.
1183  *
1184  * For those drivers which use the NDIS scatter/gather DMA mechanism,
1185  * we need to perform busdma work here. Those that use map registers
1186  * will do the mapping themselves on a buffer by buffer basis.
1187  */
1188
1189 static void
1190 ndis_start(ifp)
1191         struct ifnet            *ifp;
1192 {
1193         struct ndis_softc       *sc;
1194         struct mbuf             *m = NULL;
1195         ndis_packet             **p0 = NULL, *p = NULL;
1196         ndis_tcpip_csum         *csum;
1197         int                     pcnt = 0;
1198
1199         sc = ifp->if_softc;
1200
1201         NDIS_LOCK(sc);
1202
1203         if (!sc->ndis_link || ifp->if_flags & IFF_OACTIVE) {
1204                 NDIS_UNLOCK(sc);
1205                 return;
1206         }
1207
1208         p0 = &sc->ndis_txarray[sc->ndis_txidx];
1209
1210         while(sc->ndis_txpending) {
1211 #if __FreeBSD_version < 502114
1212                 IF_DEQUEUE(&ifp->if_snd, m);
1213 #else
1214                 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1215 #endif
1216                 if (m == NULL)
1217                         break;
1218
1219                 sc->ndis_txarray[sc->ndis_txidx] = NULL;
1220
1221                 if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
1222 #if __FreeBSD_version >= 502114
1223                         IFQ_DRV_PREPEND(&ifp->if_snd, m);
1224 #endif
1225                         NDIS_UNLOCK(sc);
1226 #if __FreeBSD_version < 502114
1227                         IF_PREPEND(&ifp->if_snd, m);
1228 #endif
1229                         return;
1230                 }
1231
1232                 /*
1233                  * Save pointer to original mbuf
1234                  * so we can free it later.
1235                  */
1236
1237                 p = sc->ndis_txarray[sc->ndis_txidx];
1238                 p->np_txidx = sc->ndis_txidx;
1239                 p->np_m0 = m;
1240                 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1241
1242                 /*
1243                  * Do scatter/gather processing, if driver requested it.
1244                  */
1245                 if (sc->ndis_sc) {
1246                         bus_dmamap_load_mbuf(sc->ndis_ttag,
1247                             sc->ndis_tmaps[sc->ndis_txidx], m,
1248                             ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT);
1249                         bus_dmamap_sync(sc->ndis_ttag,
1250                             sc->ndis_tmaps[sc->ndis_txidx],
1251                             BUS_DMASYNC_PREREAD);
1252                         p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist;
1253                 }
1254
1255                 /* Handle checksum offload. */
1256
1257                 if (ifp->if_capenable & IFCAP_TXCSUM &&
1258                     m->m_pkthdr.csum_flags) {
1259                         csum = (ndis_tcpip_csum *)
1260                                 &p->np_ext.npe_info[ndis_tcpipcsum_info];
1261                         csum->u.ntc_txflags = NDIS_TXCSUM_DO_IPV4;
1262                         if (m->m_pkthdr.csum_flags & CSUM_IP)
1263                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_IP;
1264                         if (m->m_pkthdr.csum_flags & CSUM_TCP)
1265                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_TCP;
1266                         if (m->m_pkthdr.csum_flags & CSUM_UDP)
1267                                 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_UDP;
1268                         p->np_private.npp_flags = NDIS_PROTOCOL_ID_TCP_IP;
1269                 }
1270
1271                 NDIS_INC(sc);
1272                 sc->ndis_txpending--;
1273
1274                 pcnt++;
1275
1276                 /*
1277                  * If there's a BPF listener, bounce a copy of this frame
1278                  * to him.
1279                  */
1280
1281                 BPF_MTAP(ifp, m);
1282
1283                 /*
1284                  * The array that p0 points to must appear contiguous,
1285                  * so we must not wrap past the end of sc->ndis_txarray[].
1286                  * If it looks like we're about to wrap, break out here
1287                  * so the this batch of packets can be transmitted, then
1288                  * wait for txeof to ask us to send the rest.
1289                  */
1290
1291                 if (sc->ndis_txidx == 0)
1292                         break;
1293         }
1294
1295         if (pcnt == 0) {
1296                 NDIS_UNLOCK(sc);
1297                 return;
1298         }
1299
1300         if (sc->ndis_txpending == 0)
1301                 ifp->if_flags |= IFF_OACTIVE;
1302
1303         /*
1304          * Set a timeout in case the chip goes out to lunch.
1305          */
1306         ifp->if_timer = 5;
1307
1308         NDIS_UNLOCK(sc);
1309
1310         if (sc->ndis_maxpkts == 1)
1311                 ndis_send_packet(sc, p);
1312         else
1313                 ndis_send_packets(sc, p0, pcnt);
1314
1315         return;
1316 }
1317
1318 static void
1319 ndis_init(xsc)
1320         void                    *xsc;
1321 {
1322         struct ndis_softc       *sc = xsc;
1323         struct ifnet            *ifp = &sc->arpcom.ac_if;
1324         int                     i, error;
1325
1326         /*
1327          * Avoid reintializing the link unnecessarily.
1328          * This should be dealt with in a better way by
1329          * fixing the upper layer modules so they don't
1330          * call ifp->if_init() quite as often.
1331          */
1332         if (sc->ndis_link && sc->ndis_skip)
1333                 return;
1334
1335         /*
1336          * Cancel pending I/O and free all RX/TX buffers.
1337          */
1338         ndis_stop(sc);
1339         if (ndis_init_nic(sc))
1340                 return;
1341
1342         /* Init our MAC address */
1343
1344         /* Program the packet filter */
1345
1346         sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED;
1347
1348         if (ifp->if_flags & IFF_BROADCAST)
1349                 sc->ndis_filter |= NDIS_PACKET_TYPE_BROADCAST;
1350
1351         if (ifp->if_flags & IFF_PROMISC)
1352                 sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS;
1353
1354         i = sizeof(sc->ndis_filter);
1355
1356         error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
1357             &sc->ndis_filter, &i);
1358
1359         if (error)
1360                 device_printf (sc->ndis_dev, "set filter failed: %d\n", error);
1361
1362         /*
1363          * Program the multicast filter, if necessary.
1364          */
1365         ndis_setmulti(sc);
1366
1367         /* Setup task offload. */
1368         ndis_set_offload(sc);
1369
1370         /* Enable interrupts. */
1371         ndis_enable_intr(sc);
1372
1373         if (sc->ndis_80211)
1374                 ndis_setstate_80211(sc);
1375
1376         NDIS_LOCK(sc);
1377
1378         sc->ndis_txidx = 0;
1379         sc->ndis_txpending = sc->ndis_maxpkts;
1380         sc->ndis_link = 0;
1381
1382         ifp->if_flags |= IFF_RUNNING;
1383         ifp->if_flags &= ~IFF_OACTIVE;
1384
1385         NDIS_UNLOCK(sc);
1386
1387         /*
1388          * Some drivers don't set this value. The NDIS spec says
1389          * the default checkforhang timeout is "approximately 2
1390          * seconds." We use 3 seconds, because it seems for some
1391          * drivers, exactly 2 seconds is too fast.
1392          */
1393
1394         if (sc->ndis_block.nmb_checkforhangsecs == 0)
1395                 sc->ndis_block.nmb_checkforhangsecs = 3;
1396
1397         sc->ndis_stat_ch = timeout(ndis_tick, sc,
1398             hz * sc->ndis_block.nmb_checkforhangsecs);
1399
1400         return;
1401 }
1402
1403 /*
1404  * Set media options.
1405  */
1406 static int
1407 ndis_ifmedia_upd(ifp)
1408         struct ifnet            *ifp;
1409 {
1410         struct ndis_softc               *sc;
1411
1412         sc = ifp->if_softc;
1413
1414         if (NDIS_INITIALIZED(sc))
1415                 ndis_init(sc);
1416
1417         return(0);
1418 }
1419
1420 /*
1421  * Report current media status.
1422  */
1423 static void
1424 ndis_ifmedia_sts(ifp, ifmr)
1425         struct ifnet            *ifp;
1426         struct ifmediareq       *ifmr;
1427 {
1428         struct ndis_softc       *sc;
1429         uint32_t                media_info;
1430         ndis_media_state        linkstate;
1431         int                     error, len;
1432
1433         ifmr->ifm_status = IFM_AVALID;
1434         ifmr->ifm_active = IFM_ETHER;
1435         sc = ifp->if_softc;
1436
1437         if (!NDIS_INITIALIZED(sc))
1438                 return;
1439
1440         len = sizeof(linkstate);
1441         error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
1442             (void *)&linkstate, &len);
1443
1444         len = sizeof(media_info);
1445         error = ndis_get_info(sc, OID_GEN_LINK_SPEED,
1446             (void *)&media_info, &len);
1447
1448         if (linkstate == nmc_connected)
1449                 ifmr->ifm_status |= IFM_ACTIVE;
1450
1451         switch(media_info) {
1452         case 100000:
1453                 ifmr->ifm_active |= IFM_10_T;
1454                 break;
1455         case 1000000:
1456                 ifmr->ifm_active |= IFM_100_TX;
1457                 break;
1458         case 10000000:
1459                 ifmr->ifm_active |= IFM_1000_T;
1460                 break;
1461         default:
1462                 device_printf(sc->ndis_dev, "unknown speed: %d\n", media_info);
1463                 break;
1464         }
1465
1466         return;
1467 }
1468
1469 static void
1470 ndis_setstate_80211(sc)
1471         struct ndis_softc       *sc;
1472 {
1473         struct ieee80211com     *ic;
1474         ndis_80211_ssid         ssid;
1475         ndis_80211_config       config;
1476         ndis_80211_wep          wep;
1477         int                     i, rval = 0, len;
1478         uint32_t                arg;
1479         struct ifnet            *ifp;
1480
1481         ic = &sc->ic;
1482         ifp = &sc->arpcom.ac_if;
1483
1484         if (!NDIS_INITIALIZED(sc))
1485                 return;
1486
1487         /* Set network infrastructure mode. */
1488
1489         len = sizeof(arg);
1490         if (ic->ic_opmode == IEEE80211_M_IBSS)
1491                 arg = NDIS_80211_NET_INFRA_IBSS;
1492         else
1493                 arg = NDIS_80211_NET_INFRA_BSS;
1494
1495         rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
1496
1497         if (rval)
1498                 device_printf (sc->ndis_dev, "set infra failed: %d\n", rval);
1499
1500         /* Set WEP */
1501
1502 #ifdef IEEE80211_F_PRIVACY
1503         if (ic->ic_flags & IEEE80211_F_PRIVACY) {
1504 #else
1505         if (ic->ic_wep_mode >= IEEE80211_WEP_ON) {
1506 #endif
1507                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1508                         if (ic->ic_nw_keys[i].wk_keylen) {
1509                                 bzero((char *)&wep, sizeof(wep));
1510                                 wep.nw_keylen = ic->ic_nw_keys[i].wk_keylen;
1511 #ifdef notdef
1512                                 /* 5 and 13 are the only valid key lengths */
1513                                 if (ic->ic_nw_keys[i].wk_keylen < 5)
1514                                         wep.nw_keylen = 5;
1515                                 else if (ic->ic_nw_keys[i].wk_keylen > 5 &&
1516                                      ic->ic_nw_keys[i].wk_keylen < 13)
1517                                         wep.nw_keylen = 13;
1518 #endif
1519                                 wep.nw_keyidx = i;
1520                                 wep.nw_length = (sizeof(uint32_t) * 3)
1521                                     + wep.nw_keylen;
1522                                 if (i == ic->ic_def_txkey)
1523                                         wep.nw_keyidx |= NDIS_80211_WEPKEY_TX;
1524                                 bcopy(ic->ic_nw_keys[i].wk_key,
1525                                     wep.nw_keydata, wep.nw_length);
1526                                 len = sizeof(wep);
1527                                 rval = ndis_set_info(sc,
1528                                     OID_802_11_ADD_WEP, &wep, &len);
1529                                 if (rval)
1530                                         device_printf(sc->ndis_dev,
1531                                             "set wepkey failed: %d\n", rval);
1532                         }
1533                 }
1534                 arg = NDIS_80211_WEPSTAT_ENABLED;
1535                 len = sizeof(arg);
1536                 rval = ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
1537                 if (rval)
1538                         device_printf(sc->ndis_dev,
1539                             "enable WEP failed: %d\n", rval);
1540 #ifndef IEEE80211_F_WEPON
1541 #if 0
1542                 if (ic->ic_wep_mode != IEEE80211_WEP_8021X &&
1543                     ic->ic_wep_mode != IEEE80211_WEP_ON)
1544                         arg = NDIS_80211_PRIVFILT_ACCEPTALL;
1545                 else
1546 #endif
1547 #endif
1548                         arg = NDIS_80211_PRIVFILT_8021XWEP;
1549                 len = sizeof(arg);
1550                 rval = ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len);
1551 #ifdef IEEE80211_WEP_8021X /*IEEE80211_F_WEPON*/
1552                 /* Accept that we only have "shared" and 802.1x modes. */
1553                 if (rval == 0) {
1554                         if (arg == NDIS_80211_PRIVFILT_ACCEPTALL)
1555                                 ic->ic_wep_mode = IEEE80211_WEP_MIXED;
1556                         else
1557                                 ic->ic_wep_mode = IEEE80211_WEP_8021X;
1558                 }
1559 #endif
1560                 arg = NDIS_80211_AUTHMODE_OPEN;
1561         } else {
1562                 arg = NDIS_80211_WEPSTAT_DISABLED;
1563                 len = sizeof(arg);
1564                 ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
1565                 arg = NDIS_80211_AUTHMODE_OPEN;
1566         }
1567
1568         len = sizeof(arg);
1569         rval = ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
1570
1571 #ifdef notyet
1572         if (rval)
1573                 device_printf (sc->ndis_dev, "set auth failed: %d\n", rval);
1574 #endif
1575
1576 #ifdef notyet
1577         /* Set network type. */
1578
1579         arg = 0;
1580
1581         switch (ic->ic_curmode) {
1582         case IEEE80211_MODE_11A:
1583                 arg = NDIS_80211_NETTYPE_11OFDM5;
1584                 break;
1585         case IEEE80211_MODE_11B:
1586                 arg = NDIS_80211_NETTYPE_11DS;
1587                 break;
1588         case IEEE80211_MODE_11G:
1589                 arg = NDIS_80211_NETTYPE_11OFDM24;
1590                 break;
1591         default:
1592                 device_printf(sc->ndis_dev, "unknown mode: %d\n",
1593                     ic->ic_curmode);
1594         }
1595
1596         if (arg) {
1597                 len = sizeof(arg);
1598                 rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE,
1599                     &arg, &len);
1600                 if (rval)
1601                         device_printf (sc->ndis_dev,
1602                             "set nettype failed: %d\n", rval);
1603         }
1604 #endif
1605
1606         len = sizeof(config);
1607         bzero((char *)&config, len);
1608         config.nc_length = len;
1609         config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
1610         rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); 
1611
1612         /*
1613          * Some drivers expect us to initialize these values, so
1614          * provide some defaults.
1615          */
1616         if (config.nc_beaconperiod == 0)
1617                 config.nc_beaconperiod = 100;
1618         if (config.nc_atimwin == 0)
1619                 config.nc_atimwin = 100;
1620         if (config.nc_fhconfig.ncf_dwelltime == 0)
1621                 config.nc_fhconfig.ncf_dwelltime = 200;
1622
1623         if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) { 
1624                 int chan, chanflag;
1625
1626                 chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
1627                 chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
1628                     IEEE80211_CHAN_5GHZ;
1629                 if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
1630                         config.nc_dsconfig =
1631                             ic->ic_ibss_chan->ic_freq * 1000;
1632                         ic->ic_bss->ni_chan = ic->ic_ibss_chan;
1633                         len = sizeof(config);
1634                         config.nc_length = len;
1635                         config.nc_fhconfig.ncf_length =
1636                             sizeof(ndis_80211_config_fh);
1637                         rval = ndis_set_info(sc, OID_802_11_CONFIGURATION,
1638                             &config, &len);
1639                         if (rval)
1640                                 device_printf(sc->ndis_dev, "couldn't change "
1641                                     "DS config to %ukHz: %d\n",
1642                                     config.nc_dsconfig, rval);
1643                 }
1644         } else if (rval)
1645                 device_printf(sc->ndis_dev, "couldn't retrieve "
1646                     "channel info: %d\n", rval);
1647
1648         /* Set SSID -- always do this last. */
1649
1650         len = sizeof(ssid);
1651         bzero((char *)&ssid, len);
1652         ssid.ns_ssidlen = ic->ic_des_esslen;
1653         if (ssid.ns_ssidlen == 0) {
1654                 ssid.ns_ssidlen = 1;
1655         } else
1656                 bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen);
1657         rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
1658
1659         if (rval)
1660                 device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval);
1661
1662         return;
1663 }
1664
1665 static void
1666 ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1667 {
1668         struct ieee80211com *ic = &((struct ndis_softc *)ifp->if_softc)->ic;
1669         struct ieee80211_node *ni = NULL;
1670
1671         imr->ifm_status = IFM_AVALID;
1672         imr->ifm_active = IFM_IEEE80211;
1673         if (ic->ic_state == IEEE80211_S_RUN)
1674                 imr->ifm_status |= IFM_ACTIVE;
1675         imr->ifm_active |= IFM_AUTO;
1676         switch (ic->ic_opmode) {
1677         case IEEE80211_M_STA:
1678                 ni = ic->ic_bss;
1679                 /* calculate rate subtype */
1680                 imr->ifm_active |= ieee80211_rate2media(ic,
1681                         ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
1682                 break;
1683         case IEEE80211_M_IBSS:
1684                 ni = ic->ic_bss;
1685                 /* calculate rate subtype */
1686                 imr->ifm_active |= ieee80211_rate2media(ic,
1687                         ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
1688                 imr->ifm_active |= IFM_IEEE80211_ADHOC;
1689                 break;
1690         case IEEE80211_M_AHDEMO:
1691                 /* should not come here */
1692                 break;
1693         case IEEE80211_M_HOSTAP:
1694                 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
1695                 break;
1696         case IEEE80211_M_MONITOR:
1697                 imr->ifm_active |= IFM_IEEE80211_MONITOR;
1698                 break;
1699         }
1700         switch (ic->ic_curmode) {
1701         case IEEE80211_MODE_11A:
1702                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A);
1703                 break;
1704         case IEEE80211_MODE_11B:
1705                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B);
1706                 break;
1707         case IEEE80211_MODE_11G:
1708                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G);
1709                 break;
1710         case IEEE80211_MODE_TURBO_A:
1711                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
1712                                 |  IFM_IEEE80211_TURBO;
1713                 break;
1714         }
1715 }
1716
1717 static int
1718 ndis_get_assoc(sc, assoc)
1719         struct ndis_softc       *sc;
1720         ndis_wlan_bssid_ex      **assoc;
1721 {
1722         ndis_80211_bssid_list_ex        *bl;
1723         ndis_wlan_bssid_ex      *bs;
1724         ndis_80211_macaddr      bssid;
1725         int                     i, len, error;
1726
1727         if (!sc->ndis_link)
1728                 return(ENOENT);
1729
1730         len = sizeof(bssid);
1731         error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len);
1732         if (error) {
1733                 device_printf(sc->ndis_dev, "failed to get bssid\n");
1734                 return(ENOENT);
1735         }
1736         len = 0;
1737         error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
1738         if (error != ENOSPC) {
1739                 device_printf(sc->ndis_dev, "bssid_list failed\n");
1740                 return (error);
1741         }
1742
1743         bl = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
1744         error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
1745         if (error) {
1746                 free(bl, M_TEMP);
1747                 device_printf(sc->ndis_dev, "bssid_list failed\n");
1748                 return (error);
1749         }
1750
1751         bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0];
1752         for (i = 0; i < bl->nblx_items; i++) {
1753                 if (bcmp(bs->nwbx_macaddr, bssid, sizeof(bssid)) == 0) {
1754                         *assoc = malloc(bs->nwbx_len, M_TEMP, M_NOWAIT);
1755                         if (*assoc == NULL) {
1756                                 free(bl, M_TEMP);
1757                                 return(ENOMEM);
1758                         }
1759                         bcopy((char *)bs, (char *)*assoc, bs->nwbx_len);
1760                         free(bl, M_TEMP);
1761                         return(0);
1762                 }       
1763                 bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len);
1764         }
1765
1766         free(bl, M_TEMP);
1767         return(ENOENT);
1768 }
1769
1770 static void
1771 ndis_getstate_80211(sc)
1772         struct ndis_softc       *sc;
1773 {
1774         struct ieee80211com     *ic;
1775         ndis_80211_ssid         ssid;
1776         ndis_80211_config       config;
1777         ndis_wlan_bssid_ex      *bs;
1778         int                     rval, len, i = 0;
1779         uint32_t                arg;
1780         struct ifnet            *ifp;
1781
1782         ic = &sc->ic;
1783         ifp = &sc->arpcom.ac_if;
1784
1785         if (!NDIS_INITIALIZED(sc))
1786                 return;
1787
1788         if (sc->ndis_link)
1789                 ic->ic_state = IEEE80211_S_RUN;
1790         else
1791                 ic->ic_state = IEEE80211_S_ASSOC;
1792
1793
1794         /*
1795          * If we're associated, retrieve info on the current bssid.
1796          */
1797         if ((rval = ndis_get_assoc(sc, &bs)) == 0) {
1798                 switch(bs->nwbx_nettype) {
1799                 case NDIS_80211_NETTYPE_11FH:
1800                 case NDIS_80211_NETTYPE_11DS:
1801                         ic->ic_curmode = IEEE80211_MODE_11B;
1802                         break;
1803                 case NDIS_80211_NETTYPE_11OFDM5:
1804                         ic->ic_curmode = IEEE80211_MODE_11A;
1805                         break;
1806                 case NDIS_80211_NETTYPE_11OFDM24:
1807                         ic->ic_curmode = IEEE80211_MODE_11G;
1808                         break;
1809                 default:
1810                         device_printf(sc->ndis_dev,
1811                             "unknown nettype %d\n", arg);
1812                         break;
1813                 }
1814                 IEEE80211_ADDR_COPY(ic->ic_bss->ni_bssid, bs->nwbx_macaddr);
1815                 free(bs, M_TEMP);
1816         } else
1817                 return;
1818
1819         len = sizeof(ssid);
1820         bzero((char *)&ssid, len);
1821         rval = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len);
1822
1823         if (rval)
1824                 device_printf (sc->ndis_dev, "get ssid failed: %d\n", rval);
1825         bcopy(ssid.ns_ssid, ic->ic_bss->ni_essid, ssid.ns_ssidlen);
1826         ic->ic_bss->ni_esslen = ssid.ns_ssidlen;
1827
1828         len = sizeof(arg);
1829         rval = ndis_get_info(sc, OID_GEN_LINK_SPEED, &arg, &len);
1830         if (rval)
1831                 device_printf (sc->ndis_dev, "get link speed failed: %d\n",
1832                     rval);
1833
1834         if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
1835                 ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];
1836                 for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
1837                         if ((ic->ic_bss->ni_rates.rs_rates[i] &
1838                             IEEE80211_RATE_VAL) == arg / 5000)
1839                                 break;
1840                 }
1841         }
1842
1843         if (i == ic->ic_bss->ni_rates.rs_nrates &&
1844             ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
1845                 ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11G];
1846                 for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
1847                         if ((ic->ic_bss->ni_rates.rs_rates[i] &
1848                             IEEE80211_RATE_VAL) == arg / 5000)
1849                                 break;
1850                 }
1851         }
1852
1853         if (i == ic->ic_bss->ni_rates.rs_nrates)
1854                 device_printf(sc->ndis_dev, "no matching rate for: %d\n",
1855                     arg / 5000);
1856         else
1857                 ic->ic_bss->ni_txrate = i;
1858
1859         if (ic->ic_caps & IEEE80211_C_PMGT) {
1860                 len = sizeof(arg);
1861                 rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len);
1862
1863                 if (rval)
1864                         device_printf(sc->ndis_dev,
1865                             "get power mode failed: %d\n", rval);
1866                 if (arg == NDIS_80211_POWERMODE_CAM)
1867                         ic->ic_flags &= ~IEEE80211_F_PMGTON;
1868                 else
1869                         ic->ic_flags |= IEEE80211_F_PMGTON;
1870         }
1871
1872         len = sizeof(config);
1873         bzero((char *)&config, len);
1874         config.nc_length = len;
1875         config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
1876         rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len);   
1877         if (rval == 0) { 
1878                 int chan;
1879
1880                 chan = ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0);
1881                 if (chan < 0 || chan >= IEEE80211_CHAN_MAX) {
1882                         if (ifp->if_flags & IFF_DEBUG)
1883                                 device_printf(sc->ndis_dev, "current channel "
1884                                     "(%uMHz) out of bounds\n", 
1885                                     config.nc_dsconfig / 1000);
1886                         ic->ic_bss->ni_chan = &ic->ic_channels[1];
1887                 } else
1888                         ic->ic_bss->ni_chan = &ic->ic_channels[chan];
1889         } else
1890                 device_printf(sc->ndis_dev, "couldn't retrieve "
1891                     "channel info: %d\n", rval);
1892
1893 /*
1894         len = sizeof(arg);
1895         rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
1896
1897         if (rval)
1898                 device_printf (sc->ndis_dev,
1899                     "get wep status failed: %d\n", rval);
1900
1901         if (arg == NDIS_80211_WEPSTAT_ENABLED)
1902                 ic->ic_flags |= IEEE80211_F_WEPON;
1903         else
1904                 ic->ic_flags &= ~IEEE80211_F_WEPON;
1905 */
1906         return;
1907 }
1908
1909 static int
1910 ndis_ioctl(ifp, command, data)
1911         struct ifnet            *ifp;
1912         u_long                  command;
1913         caddr_t                 data;
1914 {
1915         struct ndis_softc       *sc = ifp->if_softc;
1916         struct ifreq            *ifr = (struct ifreq *) data;
1917         int                     i, error = 0;
1918
1919         /*NDIS_LOCK(sc);*/
1920
1921         switch(command) {
1922         case SIOCSIFFLAGS:
1923                 if (ifp->if_flags & IFF_UP) {
1924                         if (ifp->if_flags & IFF_RUNNING &&
1925                             ifp->if_flags & IFF_PROMISC &&
1926                             !(sc->ndis_if_flags & IFF_PROMISC)) {
1927                                 sc->ndis_filter |=
1928                                     NDIS_PACKET_TYPE_PROMISCUOUS;
1929                                 i = sizeof(sc->ndis_filter);
1930                                 error = ndis_set_info(sc,
1931                                     OID_GEN_CURRENT_PACKET_FILTER,
1932                                     &sc->ndis_filter, &i);
1933                         } else if (ifp->if_flags & IFF_RUNNING &&
1934                             !(ifp->if_flags & IFF_PROMISC) &&
1935                             sc->ndis_if_flags & IFF_PROMISC) {
1936                                 sc->ndis_filter &=
1937                                     ~NDIS_PACKET_TYPE_PROMISCUOUS;
1938                                 i = sizeof(sc->ndis_filter);
1939                                 error = ndis_set_info(sc,
1940                                     OID_GEN_CURRENT_PACKET_FILTER,
1941                                     &sc->ndis_filter, &i);
1942                         } else
1943                                 ndis_init(sc);
1944                 } else {
1945                         if (ifp->if_flags & IFF_RUNNING)
1946                                 ndis_stop(sc);
1947                 }
1948                 sc->ndis_if_flags = ifp->if_flags;
1949                 error = 0;
1950                 break;
1951         case SIOCADDMULTI:
1952         case SIOCDELMULTI:
1953                 ndis_setmulti(sc);
1954                 error = 0;
1955                 break;
1956         case SIOCGIFMEDIA:
1957         case SIOCSIFMEDIA:
1958                 if (sc->ndis_80211) {
1959                         error = ieee80211_ioctl(&sc->ic, command, data);
1960                         if (error == ENETRESET) {
1961                                 ndis_setstate_80211(sc);
1962                                 /*ndis_init(sc);*/
1963                                 error = 0;
1964                         }
1965                 } else
1966                         error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
1967                 break;
1968         case SIOCSIFCAP:
1969                 ifp->if_capenable = ifr->ifr_reqcap;
1970                 if (ifp->if_capenable & IFCAP_TXCSUM)
1971                         ifp->if_hwassist = sc->ndis_hwassist;
1972                 else
1973                         ifp->if_hwassist = 0;
1974                 ndis_set_offload(sc);
1975                 break;
1976         case SIOCGIFGENERIC:
1977         case SIOCSIFGENERIC:
1978                 if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) {
1979                         if (command == SIOCGIFGENERIC)
1980                                 error = ndis_wi_ioctl_get(ifp, command, data);
1981                         else
1982                                 error = ndis_wi_ioctl_set(ifp, command, data);
1983                 } else
1984                         error = ENOTTY;
1985                 if (error != ENOTTY)
1986                         break;
1987         default:
1988                 sc->ndis_skip = 1;
1989                 if (sc->ndis_80211) {
1990                         error = ieee80211_ioctl(&sc->ic, command, data);
1991                         if (error == ENETRESET) {
1992                                 ndis_setstate_80211(sc);
1993                                 error = 0;
1994                         }
1995                 } else
1996                         error = ether_ioctl(ifp, command, data);
1997                 sc->ndis_skip = 0;
1998                 break;
1999         }
2000
2001         /*NDIS_UNLOCK(sc);*/
2002
2003         return(error);
2004 }
2005
2006 static int
2007 ndis_wi_ioctl_get(ifp, command, data)
2008         struct ifnet            *ifp;
2009         u_long                  command;
2010         caddr_t                 data;
2011 {
2012         struct wi_req           wreq;
2013         struct ifreq            *ifr;
2014         struct ndis_softc       *sc;
2015         ndis_80211_bssid_list_ex *bl;
2016         ndis_wlan_bssid_ex      *wb;
2017         struct wi_apinfo        *api;
2018         int                     error, i, j, len, maxaps;
2019
2020         sc = ifp->if_softc;
2021         ifr = (struct ifreq *)data;
2022         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
2023         if (error)
2024                 return (error);
2025
2026         switch (wreq.wi_type) {
2027         case WI_RID_READ_APS:
2028                 len = 0;
2029                 error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN,
2030                     NULL, &len);
2031                 if (error == 0)
2032                         tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2);
2033                 len = 0;
2034                 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
2035                 if (error != ENOSPC)
2036                         break;
2037                 bl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
2038                 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
2039                 if (error) {
2040                         free(bl, M_DEVBUF);
2041                         break;
2042                 }
2043                 maxaps = (2 * wreq.wi_len - sizeof(int)) / sizeof(*api);
2044                 maxaps = MIN(maxaps, bl->nblx_items);
2045                 wreq.wi_len = (maxaps * sizeof(*api) + sizeof(int)) / 2;
2046                 *(int *)&wreq.wi_val = maxaps;
2047                 api = (struct wi_apinfo *)&((int *)&wreq.wi_val)[1];
2048                 wb = bl->nblx_bssid;
2049                 while (maxaps--) {
2050                         bzero(api, sizeof(*api));
2051                         bcopy(&wb->nwbx_macaddr, &api->bssid,
2052                             sizeof(api->bssid));
2053                         api->namelen = wb->nwbx_ssid.ns_ssidlen;
2054                         bcopy(&wb->nwbx_ssid.ns_ssid, &api->name, api->namelen);
2055                         if (wb->nwbx_privacy)
2056                                 api->capinfo |= IEEE80211_CAPINFO_PRIVACY;
2057                         /* XXX Where can we get noise information? */
2058                         api->signal = wb->nwbx_rssi + 149;      /* XXX */
2059                         api->quality = api->signal;
2060                         api->channel =
2061                             ieee80211_mhz2ieee(wb->nwbx_config.nc_dsconfig /
2062                             1000, 0);
2063                         /* In "auto" infrastructure mode, this is useless. */
2064                         if (wb->nwbx_netinfra == NDIS_80211_NET_INFRA_IBSS)
2065                                 api->capinfo |= IEEE80211_CAPINFO_IBSS;
2066                         if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
2067                                 j = sizeof(ndis_80211_rates_ex);
2068                                 /* handle other extended things */
2069                         } else
2070                                 j = sizeof(ndis_80211_rates);
2071                         for (i = api->rate = 0; i < j; i++)
2072                                 api->rate = MAX(api->rate, 5 *
2073                                     (wb->nwbx_supportedrates[i] & 0x7f));
2074                         api++;
2075                         wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
2076                 }
2077                 free(bl, M_DEVBUF);
2078                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
2079                 break;
2080         default:
2081                 error = ENOTTY;
2082                 break;
2083         }
2084         return (error);
2085 }
2086
2087 static int
2088 ndis_wi_ioctl_set(ifp, command, data)
2089         struct ifnet            *ifp;
2090         u_long                  command;
2091         caddr_t                 data;
2092 {
2093         struct wi_req           wreq;
2094         struct ifreq            *ifr;
2095         struct ndis_softc       *sc;
2096         uint32_t                foo;
2097         int                     error, len;
2098
2099         error = suser(curthread);
2100         if (error)
2101                 return (error);
2102
2103         sc = ifp->if_softc;
2104         ifr = (struct ifreq *)data;
2105         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
2106         if (error)
2107                 return (error);
2108
2109         switch (wreq.wi_type) {
2110         case WI_RID_SCAN_APS:
2111         case WI_RID_SCAN_REQ:                   /* arguments ignored */
2112                 len = sizeof(foo);
2113                 foo = 0;
2114                 error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, &foo,
2115                     &len);
2116                 break;
2117         default:
2118                 error = ENOTTY;
2119                 break;
2120         }
2121         return (error);
2122 }
2123
2124 static void
2125 ndis_watchdog(ifp)
2126         struct ifnet            *ifp;
2127 {
2128         struct ndis_softc               *sc;
2129
2130         sc = ifp->if_softc;
2131
2132         NDIS_LOCK(sc);
2133         ifp->if_oerrors++;
2134         device_printf(sc->ndis_dev, "watchdog timeout\n");
2135         NDIS_UNLOCK(sc);
2136
2137         ndis_sched((void(*)(void *))ndis_reset_nic, sc, NDIS_TASKQUEUE);
2138         ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
2139
2140         return;
2141 }
2142
2143 /*
2144  * Stop the adapter and free any mbufs allocated to the
2145  * RX and TX lists.
2146  */
2147 static void
2148 ndis_stop(sc)
2149         struct ndis_softc               *sc;
2150 {
2151         struct ifnet            *ifp;
2152
2153         ifp = &sc->arpcom.ac_if;
2154         untimeout(ndis_tick, sc, sc->ndis_stat_ch);
2155
2156         ndis_halt_nic(sc);
2157
2158         NDIS_LOCK(sc);
2159         ifp->if_timer = 0;
2160         sc->ndis_link = 0;
2161         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
2162         NDIS_UNLOCK(sc);
2163
2164         return;
2165 }
2166
2167 /*
2168  * Stop all chip I/O so that the kernel's probe routines don't
2169  * get confused by errant DMAs when rebooting.
2170  */
2171 void
2172 ndis_shutdown(dev)
2173         device_t                dev;
2174 {
2175         struct ndis_softc               *sc;
2176
2177         sc = device_get_softc(dev);
2178         ndis_shutdown_nic(sc);
2179
2180         return;
2181 }