3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD: src/sys/dev/if_ndis/if_ndis.c,v 1.69.2.6 2005/03/31 04:24:36 wpaul Exp $");
38 __KERNEL_RCSID(0, "$NetBSD: if_ndis.c,v 1.28 2009/08/02 20:22:34 dsl Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/sockio.h>
46 #include <sys/malloc.h>
47 #include <sys/kernel.h>
48 #include <sys/socket.h>
49 #include <sys/queue.h>
51 #include <sys/device.h>
52 #include <sys/kauth.h>
54 #include <sys/module.h>
57 #include <sys/sysctl.h>
60 #include <net/if_arp.h>
62 #include <net/if_ether.h>
64 #include <net/if_dl.h>
65 #include <net/if_media.h>
66 #include <net/route.h>
74 #include <net80211/ieee80211_var.h>
75 #include <net80211/ieee80211_ioctl.h>
77 #include <dev/ic/wi_ieee.h>
79 #include <dev/pci/pcireg.h>
80 #include <dev/pci/pcivar.h>
81 #include <dev/pci/pcidevs.h>
83 #include <compat/ndis/pe_var.h>
84 #include <compat/ndis/resource_var.h>
85 #include <compat/ndis/ntoskrnl_var.h>
86 #include <compat/ndis/hal_var.h>
87 #include <compat/ndis/ndis_var.h>
88 #include <compat/ndis/cfg_var.h>
89 #include <compat/ndis/nbcompat.h>
90 #include <dev/if_ndis/if_ndisvar.h>
95 #include "ndis_driver_data.h"
97 void ndis_attach(void *);
98 int ndis_detach(device_t
, int);
99 int ndis_suspend(device_t
);
100 int ndis_resume(device_t
);
101 void ndis_shutdown(device_t
);
104 /* I moved these to if_ndisvar.h */
106 static __stdcall void ndis_txeof (ndis_handle,
107 ndis_packet *, ndis_status);
108 static __stdcall void ndis_rxeof (ndis_handle,
109 ndis_packet **, uint32_t);
110 static __stdcall void ndis_linksts (ndis_handle,
111 ndis_status, void *, uint32_t);
112 static __stdcall void ndis_linksts_done (ndis_handle);
115 /* We need to wrap these functions for amd64. */
117 static funcptr ndis_txeof_wrap
;
118 static funcptr ndis_rxeof_wrap
;
119 static funcptr ndis_linksts_wrap
;
120 static funcptr ndis_linksts_done_wrap
;
122 int ndis_intr(void *);
123 static void ndis_tick (void *);
124 static void ndis_ticktask (void *);
125 static void ndis_start (struct ifnet
*);
126 static void ndis_starttask (void *);
127 static int ndis_ioctl (struct ifnet
*, u_long
, void *);
128 static int ndis_wi_ioctl_get (struct ifnet
*, u_long
, void *);
129 static int ndis_wi_ioctl_set (struct ifnet
*, u_long
, void *);
130 static int ndis_init (struct ifnet
*);
131 static void ndis_stop (struct ndis_softc
*);
132 static void ndis_watchdog (struct ifnet
*);
133 static int ndis_ifmedia_upd (struct ifnet
*);
134 static void ndis_ifmedia_sts (struct ifnet
*, struct ifmediareq
*);
135 static int ndis_get_assoc (struct ndis_softc
*, ndis_wlan_bssid_ex
**);
136 static int ndis_probe_offload (struct ndis_softc
*);
137 static int ndis_set_offload (struct ndis_softc
*);
138 static void ndis_getstate_80211 (struct ndis_softc
*);
139 static void ndis_setstate_80211 (struct ndis_softc
*);
140 static void ndis_media_status (struct ifnet
*, struct ifmediareq
*);
142 static void ndis_setmulti (struct ndis_softc
*);
143 static void ndis_map_sclist (void *, bus_dma_segment_t
*,
144 int, bus_size_t
, int);
148 static int ndisdrv_loaded
= 0;
149 int ndisdrv_modevent(module_t
, int);
151 MODULE(MODULE_CLASS_DRIVER
, ndisdrv_modevent
, NULL
);
153 * This routine should call windrv_load() once for each driver
154 * image. This will do the relocation and dynalinking for the
155 * image, and create a Windows driver object which will be
156 * saved in our driver database.
159 ndisdrv_modevent(module_t mod
, int cmd
)
164 printf("in ndisdrv_modevent\n");
167 case MODULE_CMD_INIT
:
169 if (ndisdrv_loaded
> 1)
171 error
= windrv_load(mod
, (vm_offset_t
)drv_data
, 0);
172 windrv_wrap((funcptr
)ndis_rxeof
, &ndis_rxeof_wrap
);
173 windrv_wrap((funcptr
)ndis_txeof
, &ndis_txeof_wrap
);
174 windrv_wrap((funcptr
)ndis_linksts
, &ndis_linksts_wrap
);
175 windrv_wrap((funcptr
)ndis_linksts_done
,
176 &ndis_linksts_done_wrap
);
178 case MODULE_CMD_FINI
:
180 if (ndisdrv_loaded
> 0)
182 windrv_unload(mod
, (vm_offset_t
)drv_data
, 0);
183 windrv_unwrap(ndis_rxeof_wrap
);
184 windrv_unwrap(ndis_txeof_wrap
);
185 windrv_unwrap(ndis_linksts_wrap
);
186 windrv_unwrap(ndis_linksts_done_wrap
);
188 case MODULE_CMD_STAT
:
199 int if_ndis_lkmentry(struct lkm_table
*lkmtp
, int cmd
, int ver
);
201 CFDRIVER_DECL(ndis
, DV_DULL
, NULL
);
202 extern struct cfattach ndis_ca
;
204 static int pciloc
[] = { -1, -1 }; /* device, function */
205 static struct cfparent pciparent
= {
206 "pci", "pci", DVUNIT_ANY
208 static struct cfdata ndis_cfdata
[] = {
209 {"ndis", "ndis", 0, FSTATE_STAR
, pciloc
, 0, &pciparent
, 0},
213 static struct cfdriver
*ndis_cfdrivers
[] = {
217 static struct cfattach
*ndis_cfattachs
[] = {
221 static const struct cfattachlkminit ndis_cfattachinit
[] = {
222 { "ndis", ndis_cfattachs
},
226 MOD_DRV("ndis", ndis_cfdrivers
, ndis_cfattachinit
,
230 if_ndis_lkmentry(struct lkm_table
*lkmtp
, int cmd
, int ver
)
232 DISPATCH(lkmtp
, cmd
, ver
, lkm_nofunc
, lkm_nofunc
, lkm_nofunc
);
238 * Program the 64-bit multicast hash filter.
241 ndis_setmulti(struct ndis_softc
*sc
)
244 struct ether_multi
*ifma
;
245 int len
, mclistsz
, error
;
248 ifp
= &sc
->arpcom
.ac_if
;
250 if (!NDIS_INITIALIZED(sc
))
253 if (ifp
->if_flags
& IFF_ALLMULTI
|| ifp
->if_flags
& IFF_PROMISC
) {
254 sc
->ndis_filter
|= NDIS_PACKET_TYPE_ALL_MULTICAST
;
255 len
= sizeof(sc
->ndis_filter
);
256 error
= ndis_set_info(sc
, OID_GEN_CURRENT_PACKET_FILTER
,
257 &sc
->ndis_filter
, &len
);
259 aprint_error_dev(sc
->ndis_dev
, "set filter failed: %d\n",
265 if (LIST_EMPTY(&sc
->arpcom
.ec_multiaddrs
))
268 len
= sizeof(mclistsz
);
269 ndis_get_info(sc
, OID_802_3_MAXIMUM_LIST_SIZE
, &mclistsz
, &len
);
271 mclist
= malloc(ETHER_ADDR_LEN
* mclistsz
, M_TEMP
, M_NOWAIT
|M_ZERO
);
273 if (mclist
== NULL
) {
274 sc
->ndis_filter
|= NDIS_PACKET_TYPE_ALL_MULTICAST
;
278 sc
->ndis_filter
|= NDIS_PACKET_TYPE_MULTICAST
;
281 LIST_FOREACH(ifma
, &sc
->arpcom
.ec_multiaddrs
, enm_list
) {
283 *****************************************************************************
284 * TODO: The NetBSD ether_multi structure (sys/net/if_ether.h) defines a range
285 * of addresses TODO: (enm_addrlo to enm_addrhi), but FreeBSD's ifmultiaddr
286 * structure (in sys/net/if_var.h) defines only a single address. Do we need
287 * to add every address in the range to the list? Seems like it to me.
288 * But for right now I'm assuming there is only a single address.
289 *****************************************************************************
291 memcpy(mclist
+ (ETHER_ADDR_LEN
* len
), ifma
->enm_addrlo
,
294 if (len
> mclistsz
) {
295 sc
->ndis_filter
|= NDIS_PACKET_TYPE_ALL_MULTICAST
;
296 sc
->ndis_filter
&= ~NDIS_PACKET_TYPE_MULTICAST
;
301 len
= len
* ETHER_ADDR_LEN
;
302 error
= ndis_set_info(sc
, OID_802_3_MULTICAST_LIST
, mclist
, &len
);
304 aprint_error_dev(sc
->ndis_dev
, "set mclist failed: %d\n",
306 sc
->ndis_filter
|= NDIS_PACKET_TYPE_ALL_MULTICAST
;
307 sc
->ndis_filter
&= ~NDIS_PACKET_TYPE_MULTICAST
;
311 free(mclist
, M_TEMP
);
313 len
= sizeof(sc
->ndis_filter
);
314 error
= ndis_set_info(sc
, OID_GEN_CURRENT_PACKET_FILTER
,
315 &sc
->ndis_filter
, &len
);
317 aprint_error_dev(sc
->ndis_dev
, "set filter failed: %d\n",
325 ndis_set_offload(struct ndis_softc
*sc
)
327 ndis_task_offload
*nto
;
328 ndis_task_offload_hdr
*ntoh
;
329 ndis_task_tcpip_csum
*nttc
;
333 ifp
= &sc
->arpcom
.ac_if
;
335 if (!NDIS_INITIALIZED(sc
))
338 /* See if there's anything to set. */
340 error
= ndis_probe_offload(sc
);
344 if (sc
->ndis_hwassist
== 0 && ifp
->if_capabilities
== 0)
347 len
= sizeof(ndis_task_offload_hdr
) + sizeof(ndis_task_offload
) +
348 sizeof(ndis_task_tcpip_csum
);
350 ntoh
= malloc(len
, M_TEMP
, M_NOWAIT
|M_ZERO
);
355 ntoh
->ntoh_vers
= NDIS_TASK_OFFLOAD_VERSION
;
356 ntoh
->ntoh_len
= sizeof(ndis_task_offload_hdr
);
357 ntoh
->ntoh_offset_firsttask
= sizeof(ndis_task_offload_hdr
);
358 ntoh
->ntoh_encapfmt
.nef_encaphdrlen
= sizeof(struct ether_header
);
359 ntoh
->ntoh_encapfmt
.nef_encap
= NDIS_ENCAP_IEEE802_3
;
360 ntoh
->ntoh_encapfmt
.nef_flags
= NDIS_ENCAPFLAG_FIXEDHDRLEN
;
362 nto
= (ndis_task_offload
*)((char *)ntoh
+
363 ntoh
->ntoh_offset_firsttask
);
365 nto
->nto_vers
= NDIS_TASK_OFFLOAD_VERSION
;
366 nto
->nto_len
= sizeof(ndis_task_offload
);
367 nto
->nto_task
= NDIS_TASK_TCPIP_CSUM
;
368 nto
->nto_offset_nexttask
= 0;
369 nto
->nto_taskbuflen
= sizeof(ndis_task_tcpip_csum
);
371 nttc
= (ndis_task_tcpip_csum
*)nto
->nto_taskbuf
;
373 if (ifp
->if_capenable
& IFCAP_TXCSUM
)
374 nttc
->nttc_v4tx
= sc
->ndis_v4tx
;
376 if (ifp
->if_capenable
& IFCAP_RXCSUM
)
377 nttc
->nttc_v4rx
= sc
->ndis_v4rx
;
379 error
= ndis_set_info(sc
, OID_TCP_TASK_OFFLOAD
, ntoh
, &len
);
386 ndis_probe_offload(struct ndis_softc
*sc
)
388 ndis_task_offload
*nto
;
389 ndis_task_offload_hdr
*ntoh
;
390 ndis_task_tcpip_csum
*nttc
= NULL
;
392 int len
, error
, dummy
;
394 ifp
= &sc
->arpcom
.ac_if
;
397 error
= ndis_get_info(sc
, OID_TCP_TASK_OFFLOAD
, &dummy
, &len
);
402 ntoh
= malloc(len
, M_TEMP
, M_NOWAIT
|M_ZERO
);
407 ntoh
->ntoh_vers
= NDIS_TASK_OFFLOAD_VERSION
;
408 ntoh
->ntoh_len
= sizeof(ndis_task_offload_hdr
);
409 ntoh
->ntoh_encapfmt
.nef_encaphdrlen
= sizeof(struct ether_header
);
410 ntoh
->ntoh_encapfmt
.nef_encap
= NDIS_ENCAP_IEEE802_3
;
411 ntoh
->ntoh_encapfmt
.nef_flags
= NDIS_ENCAPFLAG_FIXEDHDRLEN
;
413 error
= ndis_get_info(sc
, OID_TCP_TASK_OFFLOAD
, ntoh
, &len
);
420 if (ntoh
->ntoh_vers
!= NDIS_TASK_OFFLOAD_VERSION
) {
425 nto
= (ndis_task_offload
*)((char *)ntoh
+
426 ntoh
->ntoh_offset_firsttask
);
429 switch (nto
->nto_task
) {
430 case NDIS_TASK_TCPIP_CSUM
:
431 nttc
= (ndis_task_tcpip_csum
*)nto
->nto_taskbuf
;
433 /* Don't handle these yet. */
434 case NDIS_TASK_IPSEC
:
435 case NDIS_TASK_TCP_LARGESEND
:
439 if (nto
->nto_offset_nexttask
== 0)
441 nto
= (ndis_task_offload
*)((char *)nto
+
442 nto
->nto_offset_nexttask
);
450 sc
->ndis_v4tx
= nttc
->nttc_v4tx
;
451 sc
->ndis_v4rx
= nttc
->nttc_v4rx
;
453 if (nttc
->nttc_v4tx
& NDIS_TCPSUM_FLAGS_IP_CSUM
)
454 sc
->ndis_hwassist
|= CSUM_IP
;
455 if (nttc
->nttc_v4tx
& NDIS_TCPSUM_FLAGS_TCP_CSUM
)
456 sc
->ndis_hwassist
|= CSUM_TCP
;
457 if (nttc
->nttc_v4tx
& NDIS_TCPSUM_FLAGS_UDP_CSUM
)
458 sc
->ndis_hwassist
|= CSUM_UDP
;
459 if (sc
->ndis_hwassist
)
460 ifp
->if_capabilities
|= IFCAP_TXCSUM
;
462 if (nttc
->nttc_v4rx
& NDIS_TCPSUM_FLAGS_IP_CSUM
)
463 ifp
->if_capabilities
|= IFCAP_RXCSUM
;
464 if (nttc
->nttc_v4rx
& NDIS_TCPSUM_FLAGS_TCP_CSUM
)
465 ifp
->if_capabilities
|= IFCAP_RXCSUM
;
466 if (nttc
->nttc_v4rx
& NDIS_TCPSUM_FLAGS_UDP_CSUM
)
467 ifp
->if_capabilities
|= IFCAP_RXCSUM
;
474 * Attach the interface. Allocate softc structures, do ifmedia
475 * setup and ethernet/BPF attach.
481 u_char eaddr
[ETHER_ADDR_LEN
];
482 struct ndis_softc
*sc
;
486 struct ifnet
*ifp
= NULL
;
492 printf("In ndis_attach()\n");
495 sc
= device_get_softc(dev
);
497 /* start out at dispatch level */
498 win_irql
= DISPATCH_LEVEL
;
500 simple_lock_init(&sc
->ndis_mtx
);
503 * Hook interrupt early, since calling the driver's
504 * init routine may trigger an interrupt. Note that
505 * we don't need to do any explicit interrupt setup
509 * For NetBSD, the interrupt is set up in the bus-dependent
510 * code. For PCI it's done in ndis_attach_pci()
514 * TODO: remove this #ifdef once if_ndis_pcmcia.c compiles
517 sc
->ndis_regvals
= ndis_regvals
;
520 /* Create sysctl registry nodes */
521 ndis_create_sysctls(sc
);
523 /* Find the PDO for this device instance. */
524 if (sc
->ndis_iftype
== PCIBus
)
525 pdrv
= windrv_lookup(0, "PCI Bus");
526 else if (sc
->ndis_iftype
== PCMCIABus
)
527 pdrv
= windrv_lookup(0, "PCCARD Bus");
529 pdrv
= windrv_lookup(0, "USB Bus");
530 /* here dev is actuially just a pointer to the softc */
531 pdo
= windrv_find_pdo(pdrv
, sc
->ndis_dev
->dv_parent
);
535 * Create a new functional device object for this
536 * device. This is what creates the miniport block
537 * for this device instance.
541 drv
= windrv_lookup((vm_offset_t
)img
, NULL
);
543 * Stash a pointer to the softc in the Windows device_object, since
544 * we can't get it from the NetBSD device structure.
549 if (NdisAddDevice(drv
, pdo
) != STATUS_SUCCESS
) {
550 aprint_error_dev(sc
->ndis_dev
, "failed to create FDO!\n");
555 /* Tell the user what version of the API the driver is using. */
556 aprint_normal_dev(sc
->ndis_dev
, "NDIS API version: %d.%d\n",
557 sc
->ndis_chars
->nmc_version_major
,
558 sc
->ndis_chars
->nmc_version_minor
);
561 * For NetBSD so far we do the resource conversion directly in
565 /* Install our RX and TX interrupt handlers. */
566 sc
->ndis_block
->nmb_senddone_func
= ndis_txeof_wrap
;
567 sc
->ndis_block
->nmb_pktind_func
= ndis_rxeof_wrap
;
569 /* Set up the resource list in the block */
570 sc
->ndis_block
->nmb_rlist
= sc
->ndis_rl
;
571 /* sc->ndis_block->nmb_rlist = &sc->ndis_rl; */
573 /* TODO: Free this memory! */
574 sc
->arpcom
.ec_if
.if_sadl
=
575 malloc(sizeof(struct sockaddr_dl
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
577 /* Call driver's init routine. */
578 if (ndis_init_nic(sc
)) {
579 aprint_error_dev(sc
->ndis_dev
, "init handler failed\n");
585 * Get station address from the driver.
588 ndis_get_info(sc
, OID_802_3_CURRENT_ADDRESS
, &eaddr
, &len
);
591 * Figure out if we're allowed to use multipacket sends
592 * with this driver, and if so, how many.
595 if (sc
->ndis_chars
->nmc_sendsingle_func
&&
596 sc
->ndis_chars
->nmc_sendmulti_func
== NULL
) {
597 sc
->ndis_maxpkts
= 1;
599 len
= sizeof(sc
->ndis_maxpkts
);
600 ndis_get_info(sc
, OID_GEN_MAXIMUM_SEND_PACKETS
,
601 &sc
->ndis_maxpkts
, &len
);
604 sc
->ndis_txarray
= malloc(sizeof(ndis_packet
*) *
605 sc
->ndis_maxpkts
, M_DEVBUF
, M_NOWAIT
|M_ZERO
);
607 /* Allocate a pool of ndis_packets for TX encapsulation. */
609 NdisAllocatePacketPool(&j
, &sc
->ndis_txpool
,
610 sc
->ndis_maxpkts
, PROTOCOL_RESERVED_SIZE_IN_PACKET
);
612 if (j
!= NDIS_STATUS_SUCCESS
) {
613 sc
->ndis_txpool
= NULL
;
614 aprint_error_dev(sc
->ndis_dev
, "failed to allocate TX packet pool");
619 sc
->ndis_txpending
= sc
->ndis_maxpkts
;
622 /* Get supported oid list. */
623 ndis_get_supported_oids(sc
, &sc
->ndis_oids
, &sc
->ndis_oidcnt
);
625 /* If the NDIS module requested scatter/gather, init maps. */
630 * See if the OID_802_11_CONFIGURATION OID is
631 * supported by this driver. If it is, then this an 802.11
632 * wireless driver, and we should set up media for wireless.
634 for (j
= 0; j
< sc
->ndis_oidcnt
; j
++) {
635 if (sc
->ndis_oids
[j
] == OID_802_11_CONFIGURATION
) {
641 /* Check for task offload support. */
642 ndis_probe_offload(sc
);
644 ifp
= &sc
->arpcom
.ac_if
;
649 strlcpy(ifp
->if_xname
, device_xname(sc
->ndis_dev
), IFNAMSIZ
);
650 ifp
->if_mtu
= ETHERMTU
;
651 ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
| IFF_MULTICAST
;
652 ifp
->if_ioctl
= ndis_ioctl
;
653 ifp
->if_start
= ndis_start
;
654 ifp
->if_watchdog
= ndis_watchdog
;
655 ifp
->if_init
= ndis_init
;
656 ifp
->if_baudrate
= 10000000;
657 IFQ_SET_MAXLEN(&ifp
->if_snd
, 50);
658 IFQ_SET_READY(&ifp
->if_snd
);
659 ifp
->if_capenable
= ifp
->if_capabilities
;
661 * TODO: I don't think NetBSD has this field describing "HW offload
662 * capabilities" as found in FreeBSD's
663 * if_data structure, but maybe there is something else that
664 * needs to be done here for NetBSD
668 if (sc
->ndis_80211
) {
669 struct ieee80211com
*ic
= &sc
->ic
;
670 ndis_80211_rates_ex rates
;
671 struct ndis_80211_nettype_list
*ntl
;
675 ic
->ic_phytype
= IEEE80211_T_DS
;
676 ic
->ic_opmode
= IEEE80211_M_STA
;
677 ic
->ic_caps
= IEEE80211_C_IBSS
;
678 ic
->ic_state
= IEEE80211_S_ASSOC
;
679 ic
->ic_modecaps
= (1<<IEEE80211_MODE_AUTO
);
681 r
= ndis_get_info(sc
, OID_802_11_NETWORK_TYPES_SUPPORTED
,
685 ntl
= malloc(len
, M_DEVBUF
, M_WAITOK
|M_ZERO
);
686 r
= ndis_get_info(sc
, OID_802_11_NETWORK_TYPES_SUPPORTED
,
693 for (j
= 0; j
< ntl
->ntl_items
; j
++) {
694 switch (ntl
->ntl_type
[j
]) {
695 case NDIS_80211_NETTYPE_11FH
:
696 case NDIS_80211_NETTYPE_11DS
:
697 ic
->ic_modecaps
|= (1<<IEEE80211_MODE_11B
);
699 case NDIS_80211_NETTYPE_11OFDM5
:
700 ic
->ic_modecaps
|= (1<<IEEE80211_MODE_11A
);
702 case NDIS_80211_NETTYPE_11OFDM24
:
703 ic
->ic_modecaps
|= (1<<IEEE80211_MODE_11G
);
712 memset((char *)&rates
, 0, len
);
713 r
= ndis_get_info(sc
, OID_802_11_SUPPORTED_RATES
,
714 (void *)rates
, &len
);
716 aprint_error_dev(sc
->ndis_dev
, "get rates failed: 0x%x\n", r
);
718 * Since the supported rates only up to 8 can be supported,
719 * if this is not 802.11b we're just going to be faking it
723 #define TESTSETRATE(x, y) \
726 for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) { \
727 if (ic->ic_sup_rates[x].rs_rates[i] == (y)) \
730 if (i == ic->ic_sup_rates[x].rs_nrates) { \
731 ic->ic_sup_rates[x].rs_rates[i] = (y); \
732 ic->ic_sup_rates[x].rs_nrates++; \
736 #define SETRATE(x, y) \
737 ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y)
739 ic->ic_sup_rates[x].rs_nrates++
741 ic
->ic_curmode
= IEEE80211_MODE_AUTO
;
742 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11A
))
743 ic
->ic_sup_rates
[IEEE80211_MODE_11A
].rs_nrates
= 0;
744 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11B
))
745 ic
->ic_sup_rates
[IEEE80211_MODE_11B
].rs_nrates
= 0;
746 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11G
))
747 ic
->ic_sup_rates
[IEEE80211_MODE_11G
].rs_nrates
= 0;
748 for (j
= 0; j
< len
; j
++) {
749 switch (rates
[j
] & IEEE80211_RATE_VAL
) {
755 if (!(ic
->ic_modecaps
&
756 (1<<IEEE80211_MODE_11B
))) {
757 /* Lazy-init 802.11b. */
759 (1<<IEEE80211_MODE_11B
);
760 ic
->ic_sup_rates
[IEEE80211_MODE_11B
].
763 SETRATE(IEEE80211_MODE_11B
, rates
[j
]);
764 INCRATE(IEEE80211_MODE_11B
);
767 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11A
)) {
768 SETRATE(IEEE80211_MODE_11A
, rates
[j
]);
769 INCRATE(IEEE80211_MODE_11A
);
771 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11G
)) {
772 SETRATE(IEEE80211_MODE_11G
, rates
[j
]);
773 INCRATE(IEEE80211_MODE_11G
);
780 * If the hardware supports 802.11g, it most
781 * likely supports 802.11b and all of the
782 * 802.11b and 802.11g speeds, so maybe we can
783 * just cheat here. Just how in the heck do
784 * we detect turbo modes, though?
786 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11B
)) {
787 TESTSETRATE(IEEE80211_MODE_11B
,
788 IEEE80211_RATE_BASIC
|2);
789 TESTSETRATE(IEEE80211_MODE_11B
,
790 IEEE80211_RATE_BASIC
|4);
791 TESTSETRATE(IEEE80211_MODE_11B
,
792 IEEE80211_RATE_BASIC
|11);
793 TESTSETRATE(IEEE80211_MODE_11B
,
794 IEEE80211_RATE_BASIC
|22);
796 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11G
)) {
797 TESTSETRATE(IEEE80211_MODE_11G
, 47);
798 TESTSETRATE(IEEE80211_MODE_11G
, 72);
799 TESTSETRATE(IEEE80211_MODE_11G
, 96);
800 TESTSETRATE(IEEE80211_MODE_11G
, 108);
802 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11A
)) {
803 TESTSETRATE(IEEE80211_MODE_11A
, 47);
804 TESTSETRATE(IEEE80211_MODE_11A
, 72);
805 TESTSETRATE(IEEE80211_MODE_11A
, 96);
806 TESTSETRATE(IEEE80211_MODE_11A
, 108);
811 * Taking yet more guesses here.
813 for (j
= 1; j
< IEEE80211_CHAN_MAX
; j
++) {
816 if (ic
->ic_sup_rates
[IEEE80211_MODE_11G
].rs_nrates
)
817 chanflag
|= IEEE80211_CHAN_G
;
819 chanflag
|= IEEE80211_CHAN_B
;
820 if (ic
->ic_sup_rates
[IEEE80211_MODE_11A
].rs_nrates
&&
822 chanflag
= IEEE80211_CHAN_A
;
825 ic
->ic_channels
[j
].ic_freq
=
826 ieee80211_ieee2mhz(j
, chanflag
);
827 ic
->ic_channels
[j
].ic_flags
= chanflag
;
831 r
= ndis_get_info(sc
, OID_802_11_WEP_STATUS
, &arg
, &j
);
832 if (arg
!= NDIS_80211_WEPSTAT_NOTSUPPORTED
)
833 ic
->ic_caps
|= IEEE80211_C_WEP
;
835 r
= ndis_get_info(sc
, OID_802_11_POWER_MODE
, &arg
, &j
);
837 ic
->ic_caps
|= IEEE80211_C_PMGT
;
838 memcpy(&ic
->ic_myaddr
, eaddr
, sizeof(eaddr
));
840 ieee80211_ifattach(&sc
->ic
);
841 ieee80211_media_init(&sc
->ic
, ieee80211_media_change
,
844 ic
->ic_ibss_chan
= IEEE80211_CHAN_ANYC
;
845 ic
->ic_bss
->ni_chan
= ic
->ic_ibss_chan
;
847 ifmedia_init(&sc
->ifmedia
, IFM_IMASK
, ndis_ifmedia_upd
,
849 ifmedia_add(&sc
->ifmedia
, IFM_ETHER
|IFM_10_T
, 0, NULL
);
850 ifmedia_add(&sc
->ifmedia
, IFM_ETHER
|IFM_10_T
|IFM_FDX
, 0, NULL
);
851 ifmedia_add(&sc
->ifmedia
, IFM_ETHER
|IFM_100_TX
, 0, NULL
);
852 ifmedia_add(&sc
->ifmedia
,
853 IFM_ETHER
|IFM_100_TX
|IFM_FDX
, 0, NULL
);
854 ifmedia_add(&sc
->ifmedia
, IFM_ETHER
|IFM_AUTO
, 0, NULL
);
855 ifmedia_set(&sc
->ifmedia
, IFM_ETHER
|IFM_AUTO
);
857 ether_ifattach(ifp
, eaddr
);
860 /* Override the status handler so we can detect link changes. */
861 sc
->ndis_block
->nmb_status_func
= ndis_linksts_wrap
;
862 sc
->ndis_block
->nmb_statusdone_func
= ndis_linksts_done_wrap
;
867 /* We're done talking to the NIC for now; halt it. */
874 * Shutdown hardware and free up resources. This can be called any
875 * time after the mutex has been initialized. It is called in both
876 * the error case in attach and the normal detach case so it needs
877 * to be careful about only freeing resources that have actually been
881 ndis_detach (dev
, flags
)
885 struct ndis_softc
*sc
;
891 printf("in ndis_detach\n");
894 sc
= device_get_softc(dev
);
898 ifp
= &sc
->arpcom
.ac_if
;
899 ifp
->if_flags
&= ~IFF_UP
;
901 if (device_is_attached(dev
)) {
905 ieee80211_ifdetach(&sc
->ic
);
914 * TODO: unmap interrupts when unloading in NetBSD
917 bus_release_resource(dev
, SYS_RES_IOPORT
,
918 sc
->ndis_io_rid
, sc
->ndis_res_io
);
919 if (sc
->ndis_res_mem
)
920 bus_release_resource(dev
, SYS_RES_MEMORY
,
921 sc
->ndis_mem_rid
, sc
->ndis_res_mem
);
923 ndis_destroy_dma(sc
);
925 if (sc
->ndis_txarray
)
926 free(sc
->ndis_txarray
, M_DEVBUF
);
929 ndis_unload_driver((void *)ifp
);
931 if (sc
->ndis_txpool
!= NULL
)
932 NdisFreePacketPool(sc
->ndis_txpool
);
934 /* Destroy the PDO for this device. */
936 if (sc
->ndis_iftype
== PCIBus
)
937 drv
= windrv_lookup(0, "PCI Bus");
938 else if (sc
->ndis_iftype
== PCMCIABus
)
939 drv
= windrv_lookup(0, "PCCARD Bus");
941 drv
= windrv_lookup(0, "USB Bus");
943 panic("couldn't find driver object");
944 windrv_destroy_pdo(drv
, dev
);
946 * TODO: Unmap dma for NetBSD
952 /* TODO: write a NetBSD version of ndis_suspend() */
954 /* TODO: write a NetBSD version of ndis_resume() */
957 * A frame has been uploaded: pass the resulting mbuf chain up to
958 * the higher level protocols.
960 * When handling received NDIS packets, the 'status' field in the
961 * out-of-band portion of the ndis_packet has special meaning. In the
962 * most common case, the underlying NDIS driver will set this field
963 * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
964 * take posession of it. We then change the status field to
965 * NDIS_STATUS_PENDING to tell the driver that we now own the packet,
966 * and that we will return it at some point in the future via the
967 * return packet handler.
969 * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
970 * this means the driver is running out of packet/buffer resources and
971 * wants to maintain ownership of the packet. In this case, we have to
972 * copy the packet data into local storage and let the driver keep the
975 __stdcall
/*static*/ void
976 ndis_rxeof(ndis_handle adapter
, ndis_packet
**packets
, uint32_t pktcnt
)
978 struct ndis_softc
*sc
;
979 ndis_miniport_block
*block
;
982 ndis_tcpip_csum
*csum
;
987 block
= (ndis_miniport_block
*)adapter
;
988 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
989 ifp
= &sc
->arpcom
.ac_if
;
991 for (i
= 0; i
< pktcnt
; i
++) {
993 /* Stash the softc here so ptom can use it. */
995 if (ndis_ptom(&m0
, p
)) {
996 aprint_error_dev(sc
->ndis_dev
, "ptom failed\n");
997 if (p
->np_oob
.npo_status
== NDIS_STATUS_SUCCESS
)
998 ndis_return_packet(NULL
, (void *)sc
, 0, p
);
1000 if (p
->np_oob
.npo_status
== NDIS_STATUS_RESOURCES
) {
1001 m
= m_dup(m0
, 0, m0
->m_pkthdr
.len
, FALSE
);
1003 * NOTE: we want to destroy the mbuf here, but
1004 * we don't actually want to return it to the
1005 * driver via the return packet handler. By
1006 * bumping np_refcnt, we can prevent the
1007 * ndis_return_packet() routine from actually
1017 p
->np_oob
.npo_status
= NDIS_STATUS_PENDING
;
1018 m0
->m_pkthdr
.rcvif
= ifp
;
1021 /* Deal with checksum offload. */
1023 * TODO: deal with checksum offload in NetBSD
1024 * (see IFCAP_XXX in sys/net/if.h, these differ from the FreeBSD ones)
1026 if (ifp
->if_capenable
& IFCAP_RXCSUM
&&
1027 p
->np_ext
.npe_info
[ndis_tcpipcsum_info
] != NULL
) {
1029 p
->np_ext
.npe_info
[ndis_tcpipcsum_info
];
1030 csum
= (ndis_tcpip_csum
*)&s
;
1031 if (!(csum
->u
.ntc_rxflags
&
1032 NDIS_RXCSUM_IP_PASSED
))
1033 m0
->m_pkthdr
.csum_flags
|=
1035 if (csum
->u
.ntc_rxflags
&
1036 (NDIS_RXCSUM_TCP_PASSED
|
1037 NDIS_RXCSUM_UDP_PASSED
)) {
1038 //m0->m_pkthdr.csum_flags |=
1039 // CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
1040 m0
->m_pkthdr
.csum_data
= 0xFFFF;
1045 bpf_mtap(ifp
->if_bpf
, m0
);
1048 (*ifp
->if_input
)(ifp
, m0
);
1056 * A frame was downloaded to the chip. It's safe for us to clean up
1059 __stdcall
/*static*/ void
1060 ndis_txeof(adapter
, packet
, status
)
1061 ndis_handle adapter
;
1062 ndis_packet
*packet
;
1066 struct ndis_softc
*sc
;
1067 ndis_miniport_block
*block
;
1073 block
= (ndis_miniport_block
*)adapter
;
1074 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1075 ifp
= &sc
->arpcom
.ac_if
;
1078 idx
= packet
->np_txidx
;
1080 bus_dmamap_unload(sc
->ndis_ttag
, sc
->ndis_tmaps
[idx
]);
1082 ndis_free_packet(packet
);
1087 sc
->ndis_txarray
[idx
] = NULL
;
1088 sc
->ndis_txpending
++;
1090 if (status
== NDIS_STATUS_SUCCESS
)
1095 ifp
->if_flags
&= ~IFF_OACTIVE
;
1098 ndis_sched(ndis_starttask
, ifp
, NDIS_TASKQUEUE
);
1103 __stdcall
/*static*/ void
1104 ndis_linksts(ndis_handle adapter
, ndis_status status
, void *sbuf
, uint32_t slen
)
1106 ndis_miniport_block
*block
;
1107 struct ndis_softc
*sc
;
1110 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1113 block
->nmb_getstat
= status
;
1118 __stdcall
/*static*/ void
1119 ndis_linksts_done(ndis_handle adapter
)
1121 ndis_miniport_block
*block
;
1122 struct ndis_softc
*sc
;
1126 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1127 ifp
= &sc
->arpcom
.ac_if
;
1129 if (!NDIS_INITIALIZED(sc
))
1132 switch (block
->nmb_getstat
) {
1133 case NDIS_STATUS_MEDIA_CONNECT
:
1134 ndis_sched(ndis_ticktask
, sc
, NDIS_TASKQUEUE
);
1135 ndis_sched(ndis_starttask
, ifp
, NDIS_TASKQUEUE
);
1137 case NDIS_STATUS_MEDIA_DISCONNECT
:
1139 ndis_sched(ndis_ticktask
, sc
, NDIS_TASKQUEUE
);
1152 struct ndis_softc
*sc
;
1154 int is_our_intr
= 0;
1157 ndis_miniport_interrupt
*intr
;
1160 ifp
= &sc
->arpcom
.ac_if
;
1163 * I was getting an interrupt before NdisAddDevice was called,
1164 * which sets up the ndis_block, so...
1166 if(sc
->ndis_block
== NULL
) {
1170 intr
= sc
->ndis_block
->nmb_interrupt
;
1172 if (sc
->ndis_block
->nmb_miniportadapterctx
== NULL
) {
1176 KeAcquireSpinLock(&intr
->ni_dpccountlock
, &irql
);
1177 if (sc
->ndis_block
->nmb_interrupt
->ni_isrreq
== TRUE
)
1178 ndis_isr(sc
, &is_our_intr
, &call_isr
);
1180 ndis_disable_intr(sc
);
1183 KeReleaseSpinLock(&intr
->ni_dpccountlock
, irql
);
1185 if ((is_our_intr
|| call_isr
)) {
1187 IoRequestDpc(sc
->ndis_block
->nmb_deviceobj
, NULL
, sc
);
1188 ndis_in_isr
= FALSE
;
1195 * just here so I can wake up the SWI thread
1199 struct ndisqhead
*np_q
;
1202 uint8_t np_stack
[PAGE_SIZE
*NDIS_KSTACK_PAGES
];
1203 int np_needs_wakeup
;
1205 extern struct ndisproc ndis_iproc
;
1208 ndis_tick(void *xsc
)
1210 struct ndis_softc
*sc
;
1212 /* TODO: do we need the lock for NetBSD? */
1216 ndis_sched(ndis_ticktask
, sc
, NDIS_TASKQUEUE
);
1218 callout_reset(&sc
->ndis_stat_ch
, hz
*
1219 sc
->ndis_block
->nmb_checkforhangsecs
, ndis_tick
, sc
);
1226 ndis_ticktask(void *xsc
)
1228 struct ndis_softc
*sc
;
1229 __stdcall ndis_checkforhang_handler hangfunc
;
1231 ndis_media_state linkstate
;
1237 hangfunc
= sc
->ndis_chars
->nmc_checkhang_func
;
1239 if (hangfunc
!= NULL
) {
1240 rval
= MSCALL1(hangfunc
,
1241 sc
->ndis_block
->nmb_miniportadapterctx
);
1248 len
= sizeof(linkstate
);
1249 error
= ndis_get_info(sc
, OID_GEN_MEDIA_CONNECT_STATUS
,
1250 (void *)&linkstate
, &len
);
1254 if (sc
->ndis_link
== 0 && linkstate
== nmc_connected
) {
1255 aprint_normal_dev(sc
->ndis_dev
, "link up\n");
1260 ndis_getstate_80211(sc
);
1263 #ifdef LINK_STATE_UP
1264 sc
->arpcom
.ac_if
.if_link_state
= LINK_STATE_UP
;
1265 rt_ifmsg(&(sc
->arpcom
.ac_if
));
1266 #endif /* LINK_STATE_UP */
1269 if (sc
->ndis_link
== 1 && linkstate
== nmc_disconnected
) {
1270 aprint_normal_dev(sc
->ndis_dev
, "link down\n");
1272 #ifdef LINK_STATE_DOWN
1273 sc
->arpcom
.ac_if
.if_link_state
= LINK_STATE_DOWN
;
1274 rt_ifmsg(&(sc
->arpcom
.ac_if
));
1275 #endif /* LINK_STATE_DOWN */
1284 ndis_map_sclist(arg
, segs
, nseg
, mapsize
, error
)
1286 bus_dma_segment_t
*segs
;
1292 struct ndis_sc_list
*sclist
;
1295 if (error
|| arg
== NULL
)
1300 sclist
->nsl_frags
= nseg
;
1302 for (i
= 0; i
< nseg
; i
++) {
1303 sclist
->nsl_elements
[i
].nse_addr
.np_quad
= segs
[i
].ds_addr
;
1304 sclist
->nsl_elements
[i
].nse_len
= segs
[i
].ds_len
;
1311 ndis_starttask(void *arg
)
1316 if (!IFQ_IS_EMPTY(&ifp
->if_snd
))
1322 * Main transmit routine. To make NDIS drivers happy, we need to
1323 * transform mbuf chains into NDIS packets and feed them to the
1324 * send packet routines. Most drivers allow you to send several
1325 * packets at once (up to the maxpkts limit). Unfortunately, rather
1326 * that accepting them in the form of a linked list, they expect
1327 * a contiguous array of pointers to packets.
1329 * For those drivers which use the NDIS scatter/gather DMA mechanism,
1330 * we need to perform busdma work here. Those that use map registers
1331 * will do the mapping themselves on a buffer by buffer basis.
1334 ndis_start(struct ifnet
*ifp
)
1336 struct ndis_softc
*sc
;
1337 struct mbuf
*m
= NULL
;
1338 ndis_packet
**p0
= NULL
, *p
= NULL
;
1339 ndis_tcpip_csum
*csum
;
1340 int pcnt
= 0, status
;
1347 if (!sc
->ndis_link
|| ifp
->if_flags
& IFF_OACTIVE
) {
1352 p0
= &sc
->ndis_txarray
[sc
->ndis_txidx
];
1354 while(sc
->ndis_txpending
) {
1355 IFQ_DEQUEUE(&ifp
->if_snd
, m
);
1359 NdisAllocatePacket(&status
,
1360 &sc
->ndis_txarray
[sc
->ndis_txidx
], sc
->ndis_txpool
);
1362 if (status
!= NDIS_STATUS_SUCCESS
)
1365 if (ndis_mtop(m
, &sc
->ndis_txarray
[sc
->ndis_txidx
])) {
1366 #if __FreeBSD_version >= 502114
1367 IFQ_DRV_PREPEND(&ifp
->if_snd
, m
);
1370 #if __FreeBSD_version < 502114
1371 IF_PREPEND(&ifp
->if_snd
, m
);
1377 * Save pointer to original mbuf
1378 * so we can free it later.
1381 p
= sc
->ndis_txarray
[sc
->ndis_txidx
];
1382 p
->np_txidx
= sc
->ndis_txidx
;
1384 p
->np_oob
.npo_status
= NDIS_STATUS_PENDING
;
1387 * Do scatter/gather processing, if driver requested it.
1391 * TODO: NetBSD's bus_dmamap_load_mbuf dosen't provide a callback function
1392 * argumet as FreeBSD's does figure out what to do about this.
1394 bus_dmamap_load_mbuf(sc
->ndis_ttag
,
1395 sc
->ndis_tmaps
[sc
->ndis_txidx
], m
,
1396 BUS_DMA_WRITE
|BUS_DMA_NOWAIT
);
1397 /* Just call the callback function ? */
1398 ndis_map_sclist(&p
->np_sclist
,
1399 sc
->ndis_tmaps
[sc
->ndis_txidx
]->dm_segs
,
1400 sc
->ndis_tmaps
[sc
->ndis_txidx
]->dm_nsegs
,
1401 sc
->ndis_tmaps
[sc
->ndis_txidx
]->dm_mapsize
, 0);
1403 * TODO: Need an offset and length to pass to bus_dmamap_sync() (not needed in
1404 * FreeBSD), I'm not sure I did this correctly, as man 9 bus_dma says that
1405 * dm_segs is "an array of segments or a pointer to an array of segments".
1407 bus_dmamap_sync(sc
->ndis_ttag
,
1408 sc
->ndis_tmaps
[sc
->ndis_txidx
],
1409 sc
->ndis_tmaps
[sc
->ndis_txidx
]->dm_segs
->ds_addr
,
1410 sc
->ndis_tmaps
[sc
->ndis_txidx
]->dm_segs
->ds_len
,
1411 BUS_DMASYNC_PREREAD
);
1412 p
->np_ext
.npe_info
[ndis_sclist_info
] = &p
->np_sclist
;
1415 /* Handle checksum offload. */
1416 if (ifp
->if_capenable
& IFCAP_TXCSUM
&&
1417 m
->m_pkthdr
.csum_flags
) {
1418 csum
= (ndis_tcpip_csum
*)
1419 &p
->np_ext
.npe_info
[ndis_tcpipcsum_info
];
1420 csum
->u
.ntc_txflags
= NDIS_TXCSUM_DO_IPV4
;
1421 if (m
->m_pkthdr
.csum_flags
& CSUM_IP
)
1422 csum
->u
.ntc_txflags
|= NDIS_TXCSUM_DO_IP
;
1423 if (m
->m_pkthdr
.csum_flags
& CSUM_TCP
)
1424 csum
->u
.ntc_txflags
|= NDIS_TXCSUM_DO_TCP
;
1425 if (m
->m_pkthdr
.csum_flags
& CSUM_UDP
)
1426 csum
->u
.ntc_txflags
|= NDIS_TXCSUM_DO_UDP
;
1427 p
->np_private
.npp_flags
= NDIS_PROTOCOL_ID_TCP_IP
;
1431 sc
->ndis_txpending
--;
1436 * If there's a BPF listener, bounce a copy of this frame
1441 * The array that p0 points to must appear contiguous,
1442 * so we must not wrap past the end of sc->ndis_txarray[].
1443 * If it looks like we're about to wrap, break out here
1444 * so the this batch of packets can be transmitted, then
1445 * wait for txeof to ask us to send the rest.
1448 if (sc
->ndis_txidx
== 0)
1457 if (sc
->ndis_txpending
== 0)
1458 ifp
->if_flags
|= IFF_OACTIVE
;
1461 * Set a timeout in case the chip goes out to lunch.
1467 if (sc
->ndis_maxpkts
== 1)
1468 ndis_send_packet(sc
, p
);
1470 ndis_send_packets(sc
, p0
, pcnt
);
1479 struct ndis_softc
*sc
= xsc
->if_softc
;
1480 struct ifnet
*ifp
= xsc
;
1485 * Avoid reintializing the link unnecessarily.
1486 * This should be dealt with in a better way by
1487 * fixing the upper layer modules so they don't
1488 * call ifp->if_init() quite as often.
1490 if (sc
->ndis_link
&& sc
->ndis_skip
)
1494 * Cancel pending I/O and free all RX/TX buffers.
1497 if (ndis_init_nic(sc
)) {
1501 /* Init our MAC address */
1503 /* Program the packet filter */
1505 sc
->ndis_filter
= NDIS_PACKET_TYPE_DIRECTED
;
1507 if (ifp
->if_flags
& IFF_BROADCAST
)
1508 sc
->ndis_filter
|= NDIS_PACKET_TYPE_BROADCAST
;
1510 if (ifp
->if_flags
& IFF_PROMISC
)
1511 sc
->ndis_filter
|= NDIS_PACKET_TYPE_PROMISCUOUS
;
1513 i
= sizeof(sc
->ndis_filter
);
1515 error
= ndis_set_info(sc
, OID_GEN_CURRENT_PACKET_FILTER
,
1516 &sc
->ndis_filter
, &i
);
1519 aprint_error_dev(sc
->ndis_dev
, "set filter failed: %d\n",
1523 * Program the multicast filter, if necessary.
1527 /* Setup task offload. */
1528 ndis_set_offload(sc
);
1530 /* Enable interrupts. */
1531 ndis_enable_intr(sc
);
1534 ndis_setstate_80211(sc
);
1539 sc
->ndis_txpending
= sc
->ndis_maxpkts
;
1542 ifp
->if_flags
|= IFF_RUNNING
;
1543 ifp
->if_flags
&= ~IFF_OACTIVE
;
1548 * Some drivers don't set this value. The NDIS spec says
1549 * the default checkforhang timeout is "approximately 2
1550 * seconds." We use 3 seconds, because it seems for some
1551 * drivers, exactly 2 seconds is too fast.
1554 if (sc
->ndis_block
->nmb_checkforhangsecs
== 0)
1555 sc
->ndis_block
->nmb_checkforhangsecs
= 3;
1557 callout_reset(&sc
->ndis_stat_ch
,
1558 hz
* sc
->ndis_block
->nmb_checkforhangsecs
,
1565 * Set media options.
1568 ndis_ifmedia_upd(struct ifnet
*ifp
)
1570 struct ndis_softc
*sc
;
1574 if (NDIS_INITIALIZED(sc
))
1575 ndis_init(&sc
->arpcom
.ac_if
);
1581 * Report current media status.
1584 ndis_ifmedia_sts(struct ifnet
*ifp
, struct ifmediareq
*ifmr
)
1586 struct ndis_softc
*sc
;
1587 uint32_t media_info
;
1588 ndis_media_state linkstate
;
1591 ifmr
->ifm_status
= IFM_AVALID
;
1592 ifmr
->ifm_active
= IFM_ETHER
;
1595 if (!NDIS_INITIALIZED(sc
))
1598 len
= sizeof(linkstate
);
1599 error
= ndis_get_info(sc
, OID_GEN_MEDIA_CONNECT_STATUS
,
1600 (void *)&linkstate
, &len
);
1602 len
= sizeof(media_info
);
1603 error
= ndis_get_info(sc
, OID_GEN_LINK_SPEED
,
1604 (void *)&media_info
, &len
);
1606 if (linkstate
== nmc_connected
)
1607 ifmr
->ifm_status
|= IFM_ACTIVE
;
1609 switch(media_info
) {
1611 ifmr
->ifm_active
|= IFM_10_T
;
1614 ifmr
->ifm_active
|= IFM_100_TX
;
1617 ifmr
->ifm_active
|= IFM_1000_T
;
1620 aprint_error_dev(sc
->ndis_dev
, "unknown speed: %d\n",
1628 /* TODO: Perhaps raise the IPL while in these wireless functions ? */
1631 ndis_setstate_80211(struct ndis_softc
*sc
)
1633 struct ieee80211com
*ic
;
1634 ndis_80211_ssid ssid
;
1635 ndis_80211_config config
;
1637 int i
, rval
= 0, len
;
1641 #define wk_len wk_keylen
1642 #define ic_wep_txkey ic_def_txkey
1646 /* TODO: are these equivelant? */
1647 ifp
= sc
->ic
.ic_ifp
;
1649 if (!NDIS_INITIALIZED(sc
))
1652 /* Set network infrastructure mode. */
1655 if (ic
->ic_opmode
== IEEE80211_M_IBSS
)
1656 arg
= NDIS_80211_NET_INFRA_IBSS
;
1658 arg
= NDIS_80211_NET_INFRA_BSS
;
1660 rval
= ndis_set_info(sc
, OID_802_11_INFRASTRUCTURE_MODE
, &arg
, &len
);
1663 aprint_error_dev(sc
->ndis_dev
, "set infra failed: %d\n", rval
);
1666 /* TODO: Clean up these #ifdef's */
1667 if (ic
->ic_flags
& IEEE80211_F_PRIVACY
) {
1668 for (i
= 0; i
< IEEE80211_WEP_NKID
; i
++) {
1669 if (ic
->ic_nw_keys
[i
].wk_len
) {
1670 memset((char *)&wep
, 0, sizeof(wep
));
1671 wep
.nw_keylen
= ic
->ic_nw_keys
[i
].wk_len
;
1673 /* 5 and 13 are the only valid key lengths */
1674 if (ic
->ic_nw_keys
[i
].wk_len
< 5)
1676 else if (ic
->ic_nw_keys
[i
].wk_len
> 5 &&
1677 ic
->ic_nw_keys
[i
].wk_len
< 13)
1681 wep
.nw_length
= (sizeof(uint32_t) * 3)
1683 if (i
== ic
->ic_wep_txkey
)
1684 wep
.nw_keyidx
|= NDIS_80211_WEPKEY_TX
;
1685 bcopy(ic
->ic_nw_keys
[i
].wk_key
,
1686 wep
.nw_keydata
, wep
.nw_length
);
1688 rval
= ndis_set_info(sc
,
1689 OID_802_11_ADD_WEP
, &wep
, &len
);
1691 aprint_error_dev(sc
->ndis_dev
, "set wepkey failed: %d\n", rval
);
1694 arg
= NDIS_80211_WEPSTAT_ENABLED
;
1696 rval
= ndis_set_info(sc
, OID_802_11_WEP_STATUS
, &arg
, &len
);
1698 aprint_error_dev(sc
->ndis_dev
, "enable WEP failed: %d\n",
1700 arg
= NDIS_80211_PRIVFILT_8021XWEP
;
1702 rval
= ndis_set_info(sc
, OID_802_11_PRIVACY_FILTER
, &arg
, &len
);
1703 #ifdef IEEE80211_WEP_8021X /*IEEE80211_F_WEPON*/
1704 /* Accept that we only have "shared" and 802.1x modes. */
1706 if (arg
== NDIS_80211_PRIVFILT_ACCEPTALL
)
1707 ic
->ic_wep_mode
= IEEE80211_WEP_MIXED
;
1709 ic
->ic_wep_mode
= IEEE80211_WEP_8021X
;
1712 arg
= NDIS_80211_AUTHMODE_OPEN
;
1714 arg
= NDIS_80211_WEPSTAT_DISABLED
;
1716 ndis_set_info(sc
, OID_802_11_WEP_STATUS
, &arg
, &len
);
1717 arg
= NDIS_80211_AUTHMODE_OPEN
;
1721 rval
= ndis_set_info(sc
, OID_802_11_AUTHENTICATION_MODE
, &arg
, &len
);
1725 aprint_error_dev(sc
->ndis_dev
, "set auth failed: %d\n", rval
);
1729 /* Set network type. */
1733 switch (ic
->ic_curmode
) {
1734 case IEEE80211_MODE_11A
:
1735 arg
= NDIS_80211_NETTYPE_11OFDM5
;
1737 case IEEE80211_MODE_11B
:
1738 arg
= NDIS_80211_NETTYPE_11DS
;
1740 case IEEE80211_MODE_11G
:
1741 arg
= NDIS_80211_NETTYPE_11OFDM24
;
1744 aprint_error_dev(sc
->ndis_dev
, "unknown mode: %d\n",
1750 rval
= ndis_set_info(sc
, OID_802_11_NETWORK_TYPE_IN_USE
,
1753 aprint_error_dev(sc
->ndis_dev
, "set nettype failed: %d\n",
1758 len
= sizeof(config
);
1759 memset((char *)&config
, 0, len
);
1760 config
.nc_length
= len
;
1761 config
.nc_fhconfig
.ncf_length
= sizeof(ndis_80211_config_fh
);
1762 rval
= ndis_get_info(sc
, OID_802_11_CONFIGURATION
, &config
, &len
);
1765 * Some drivers expect us to initialize these values, so
1766 * provide some defaults.
1768 if (config
.nc_beaconperiod
== 0)
1769 config
.nc_beaconperiod
= 100;
1770 if (config
.nc_atimwin
== 0)
1771 config
.nc_atimwin
= 100;
1772 if (config
.nc_fhconfig
.ncf_dwelltime
== 0)
1773 config
.nc_fhconfig
.ncf_dwelltime
= 200;
1775 if (rval
== 0 && ic
->ic_ibss_chan
!= IEEE80211_CHAN_ANYC
) {
1778 chan
= ieee80211_chan2ieee(ic
, ic
->ic_ibss_chan
);
1779 chanflag
= config
.nc_dsconfig
> 2500000 ? IEEE80211_CHAN_2GHZ
:
1780 IEEE80211_CHAN_5GHZ
;
1781 if (chan
!= ieee80211_mhz2ieee(config
.nc_dsconfig
/ 1000, 0)) {
1782 config
.nc_dsconfig
=
1783 ic
->ic_ibss_chan
->ic_freq
* 1000;
1784 ic
->ic_bss
->ni_chan
= ic
->ic_ibss_chan
;
1785 len
= sizeof(config
);
1786 config
.nc_length
= len
;
1787 config
.nc_fhconfig
.ncf_length
=
1788 sizeof(ndis_80211_config_fh
);
1789 rval
= ndis_set_info(sc
, OID_802_11_CONFIGURATION
,
1792 aprint_error_dev(sc
->ndis_dev
, "couldn't change "
1793 "DS config to %ukHz: %d\n",
1798 aprint_error_dev(sc
->ndis_dev
, "couldn't retrieve "
1799 "channel info: %d\n", rval
);
1801 /* Set SSID -- always do this last. */
1804 memset((char *)&ssid
, 0, len
);
1805 ssid
.ns_ssidlen
= ic
->ic_des_esslen
;
1806 if (ssid
.ns_ssidlen
== 0) {
1807 ssid
.ns_ssidlen
= 1;
1809 memcpy(ssid
.ns_ssid
, ic
->ic_des_essid
, ssid
.ns_ssidlen
);
1810 rval
= ndis_set_info(sc
, OID_802_11_SSID
, &ssid
, &len
);
1813 aprint_error_dev(sc
->ndis_dev
, "set ssid failed: %d\n", rval
);
1819 ndis_media_status(struct ifnet
*ifp
, struct ifmediareq
*imr
)
1821 struct ieee80211com
*ic
= (void *)ifp
;
1822 struct ieee80211_node
*ni
= NULL
;
1824 imr
->ifm_status
= IFM_AVALID
;
1825 imr
->ifm_active
= IFM_IEEE80211
;
1826 if (ic
->ic_state
== IEEE80211_S_RUN
)
1827 imr
->ifm_status
|= IFM_ACTIVE
;
1828 imr
->ifm_active
|= IFM_AUTO
;
1829 switch (ic
->ic_opmode
) {
1830 case IEEE80211_M_STA
:
1832 /* calculate rate subtype */
1833 imr
->ifm_active
|= ieee80211_rate2media(ic
,
1834 ni
->ni_rates
.rs_rates
[ni
->ni_txrate
], ic
->ic_curmode
);
1836 case IEEE80211_M_IBSS
:
1838 /* calculate rate subtype */
1839 imr
->ifm_active
|= ieee80211_rate2media(ic
,
1840 ni
->ni_rates
.rs_rates
[ni
->ni_txrate
], ic
->ic_curmode
);
1841 imr
->ifm_active
|= IFM_IEEE80211_ADHOC
;
1843 case IEEE80211_M_AHDEMO
:
1844 /* should not come here */
1846 case IEEE80211_M_HOSTAP
:
1847 imr
->ifm_active
|= IFM_IEEE80211_HOSTAP
;
1849 case IEEE80211_M_MONITOR
:
1850 imr
->ifm_active
|= IFM_IEEE80211_MONITOR
;
1853 switch (ic
->ic_curmode
) {
1854 case IEEE80211_MODE_11A
:
1855 imr
->ifm_active
|= IFM_MAKEMODE(IFM_IEEE80211_11A
);
1857 case IEEE80211_MODE_11B
:
1858 imr
->ifm_active
|= IFM_MAKEMODE(IFM_IEEE80211_11B
);
1860 case IEEE80211_MODE_11G
:
1861 imr
->ifm_active
|= IFM_MAKEMODE(IFM_IEEE80211_11G
);
1864 * TODO: is this correct? (IEEE80211_MODE_TURBO_A and IEEE80211_MODE_TURBO_G
1865 * are defined in _ieee80211.h)
1867 case IEEE80211_MODE_TURBO_A
:
1868 case IEEE80211_MODE_TURBO_G
:
1869 imr
->ifm_active
|= IFM_MAKEMODE(IFM_IEEE80211_11A
)
1870 | IFM_IEEE80211_TURBO
;
1876 ndis_get_assoc(struct ndis_softc
*sc
, ndis_wlan_bssid_ex
**assoc
)
1878 ndis_80211_bssid_list_ex
*bl
;
1879 ndis_wlan_bssid_ex
*bs
;
1880 ndis_80211_macaddr bssid
;
1886 len
= sizeof(bssid
);
1887 error
= ndis_get_info(sc
, OID_802_11_BSSID
, &bssid
, &len
);
1889 aprint_error_dev(sc
->ndis_dev
, "failed to get bssid\n");
1893 error
= ndis_get_info(sc
, OID_802_11_BSSID_LIST
, NULL
, &len
);
1894 if (error
!= ENOSPC
) {
1895 aprint_error_dev(sc
->ndis_dev
, "bssid_list failed\n");
1899 bl
= malloc(len
, M_TEMP
, M_NOWAIT
|M_ZERO
);
1900 error
= ndis_get_info(sc
, OID_802_11_BSSID_LIST
, bl
, &len
);
1903 aprint_error_dev(sc
->ndis_dev
, "bssid_list failed\n");
1907 bs
= (ndis_wlan_bssid_ex
*)&bl
->nblx_bssid
[0];
1908 for (i
= 0; i
< bl
->nblx_items
; i
++) {
1909 if (memcmp(bs
->nwbx_macaddr
, bssid
, sizeof(bssid
)) == 0) {
1910 *assoc
= malloc(bs
->nwbx_len
, M_TEMP
, M_NOWAIT
);
1911 if (*assoc
== NULL
) {
1915 memcpy((char *)*assoc
, (char *)bs
, bs
->nwbx_len
);
1919 bs
= (ndis_wlan_bssid_ex
*)((char *)bs
+ bs
->nwbx_len
);
1927 ndis_getstate_80211(struct ndis_softc
*sc
)
1929 struct ieee80211com
*ic
;
1930 ndis_80211_ssid ssid
;
1931 ndis_80211_config config
;
1932 ndis_wlan_bssid_ex
*bs
= 0;
1933 int rval
, len
, i
= 0;
1938 /* TODO: are these equivelant? */
1939 ifp
= sc
->ic
.ic_ifp
;
1941 if (!NDIS_INITIALIZED(sc
))
1945 ic
->ic_state
= IEEE80211_S_RUN
;
1947 ic
->ic_state
= IEEE80211_S_ASSOC
;
1951 * If we're associated, retrieve info on the current bssid.
1953 if ((rval
= ndis_get_assoc(sc
, &bs
)) == 0) {
1954 switch(bs
->nwbx_nettype
) {
1955 case NDIS_80211_NETTYPE_11FH
:
1956 case NDIS_80211_NETTYPE_11DS
:
1957 ic
->ic_curmode
= IEEE80211_MODE_11B
;
1959 case NDIS_80211_NETTYPE_11OFDM5
:
1960 ic
->ic_curmode
= IEEE80211_MODE_11A
;
1962 case NDIS_80211_NETTYPE_11OFDM24
:
1963 ic
->ic_curmode
= IEEE80211_MODE_11G
;
1966 aprint_error_dev(sc
->ndis_dev
, "unknown nettype %d\n",
1975 memset((char *)&ssid
, 0, len
);
1976 rval
= ndis_get_info(sc
, OID_802_11_SSID
, &ssid
, &len
);
1979 aprint_error_dev(sc
->ndis_dev
, "get ssid failed: %d\n", rval
);
1980 memcpy(ic
->ic_bss
->ni_essid
, ssid
.ns_ssid
, ssid
.ns_ssidlen
);
1981 ic
->ic_bss
->ni_esslen
= ssid
.ns_ssidlen
;
1984 rval
= ndis_get_info(sc
, OID_GEN_LINK_SPEED
, &arg
, &len
);
1986 aprint_error_dev(sc
->ndis_dev
, "get link speed failed: %d\n",
1989 if (ic
->ic_modecaps
& (1<<IEEE80211_MODE_11B
)) {
1990 ic
->ic_bss
->ni_rates
= ic
->ic_sup_rates
[IEEE80211_MODE_11B
];
1991 for (i
= 0; i
< ic
->ic_bss
->ni_rates
.rs_nrates
; i
++) {
1992 if ((ic
->ic_bss
->ni_rates
.rs_rates
[i
] &
1993 IEEE80211_RATE_VAL
) == arg
/ 5000)
1998 if (i
== ic
->ic_bss
->ni_rates
.rs_nrates
&&
1999 ic
->ic_modecaps
& (1<<IEEE80211_MODE_11G
)) {
2000 ic
->ic_bss
->ni_rates
= ic
->ic_sup_rates
[IEEE80211_MODE_11G
];
2001 for (i
= 0; i
< ic
->ic_bss
->ni_rates
.rs_nrates
; i
++) {
2002 if ((ic
->ic_bss
->ni_rates
.rs_rates
[i
] &
2003 IEEE80211_RATE_VAL
) == arg
/ 5000)
2008 if (i
== ic
->ic_bss
->ni_rates
.rs_nrates
)
2009 aprint_error_dev(sc
->ndis_dev
, "no matching rate for: %d\n",
2012 ic
->ic_bss
->ni_txrate
= i
;
2014 if (ic
->ic_caps
& IEEE80211_C_PMGT
) {
2016 rval
= ndis_get_info(sc
, OID_802_11_POWER_MODE
, &arg
, &len
);
2019 aprint_error_dev(sc
->ndis_dev
, "get power mode failed: %d\n",
2021 if (arg
== NDIS_80211_POWERMODE_CAM
)
2022 ic
->ic_flags
&= ~IEEE80211_F_PMGTON
;
2024 ic
->ic_flags
|= IEEE80211_F_PMGTON
;
2027 len
= sizeof(config
);
2028 memset((char *)&config
, 0, len
);
2029 config
.nc_length
= len
;
2030 config
.nc_fhconfig
.ncf_length
= sizeof(ndis_80211_config_fh
);
2031 rval
= ndis_get_info(sc
, OID_802_11_CONFIGURATION
, &config
, &len
);
2035 chan
= ieee80211_mhz2ieee(config
.nc_dsconfig
/ 1000, 0);
2036 if (chan
< 0 || chan
>= IEEE80211_CHAN_MAX
) {
2037 if (ifp
->if_flags
& IFF_DEBUG
)
2038 aprint_error_dev(sc
->ndis_dev
, "current channel "
2039 "(%uMHz) out of bounds\n",
2040 config
.nc_dsconfig
/ 1000);
2041 ic
->ic_bss
->ni_chan
= &ic
->ic_channels
[1];
2043 ic
->ic_bss
->ni_chan
= &ic
->ic_channels
[chan
];
2045 aprint_error_dev(sc
->ndis_dev
, "couldn't retrieve "
2046 "channel info: %d\n", rval
);
2050 rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
2053 device_printf (sc->ndis_dev,
2054 "get wep status failed: %d\n", rval);
2056 if (arg == NDIS_80211_WEPSTAT_ENABLED)
2057 ic->ic_flags |= IEEE80211_F_WEPON;
2059 ic->ic_flags &= ~IEEE80211_F_WEPON;
2065 ndis_ioctl(struct ifnet
*ifp
, u_long command
, void *data
)
2067 struct ndis_softc
*sc
= ifp
->if_softc
;
2068 struct ifreq
*ifr
= (struct ifreq
*) data
;
2077 if ((error
= ifioctl_common(ifp
, command
, data
)) != 0)
2079 if (ifp
->if_flags
& IFF_UP
) {
2080 if (ifp
->if_flags
& IFF_RUNNING
&&
2081 ifp
->if_flags
& IFF_PROMISC
&&
2082 !(sc
->ndis_if_flags
& IFF_PROMISC
)) {
2084 NDIS_PACKET_TYPE_PROMISCUOUS
;
2085 i
= sizeof(sc
->ndis_filter
);
2086 error
= ndis_set_info(sc
,
2087 OID_GEN_CURRENT_PACKET_FILTER
,
2088 &sc
->ndis_filter
, &i
);
2089 } else if (ifp
->if_flags
& IFF_RUNNING
&&
2090 !(ifp
->if_flags
& IFF_PROMISC
) &&
2091 sc
->ndis_if_flags
& IFF_PROMISC
) {
2093 ~NDIS_PACKET_TYPE_PROMISCUOUS
;
2094 i
= sizeof(sc
->ndis_filter
);
2095 error
= ndis_set_info(sc
,
2096 OID_GEN_CURRENT_PACKET_FILTER
,
2097 &sc
->ndis_filter
, &i
);
2101 if (ifp
->if_flags
& IFF_RUNNING
)
2104 sc
->ndis_if_flags
= ifp
->if_flags
;
2110 * TODO: I'm really not sure this is the correct thing to do here, but multicast
2111 * address lists weren't getting set in ether_ioctl because they SIOCADDMULTI
2112 * is routed to ndis_setmulti here.
2114 error
= ether_ioctl(ifp
, command
, data
);
2120 if (sc
->ndis_80211
) {
2121 error
= ieee80211_ioctl(&sc
->ic
, command
, data
);
2122 if (error
== ENETRESET
) {
2123 ndis_setstate_80211(sc
);
2128 error
= ifmedia_ioctl(ifp
, ifr
, &sc
->ifmedia
, command
);
2131 if ((error
= ether_ioctl(ifp
, command
, data
)) == ENETRESET
) {
2132 ndis_set_offload(sc
);
2136 case SIOCGIFGENERIC
:
2137 case SIOCSIFGENERIC
:
2138 if (sc
->ndis_80211
&& NDIS_INITIALIZED(sc
)) {
2139 if (command
== SIOCGIFGENERIC
)
2140 error
= ndis_wi_ioctl_get(ifp
, command
, data
);
2142 error
= ndis_wi_ioctl_set(ifp
, command
, data
);
2145 if (error
!= ENOTTY
)
2149 if (sc
->ndis_80211
) {
2150 error
= ieee80211_ioctl(&sc
->ic
, command
, data
);
2152 if (error
== ENETRESET
) {
2153 ndis_setstate_80211(sc
);
2157 error
= ether_ioctl(ifp
, command
, data
);
2163 /*NDIS_UNLOCK(sc);*/
2170 ndis_wi_ioctl_get(struct ifnet
*ifp
, u_long command
, void * data
)
2174 struct ndis_softc
*sc
;
2175 ndis_80211_bssid_list_ex
*bl
;
2176 ndis_wlan_bssid_ex
*wb
;
2177 struct wi_apinfo
*api
;
2178 int error
, i
, j
, len
, maxaps
;
2181 ifr
= (struct ifreq
*)data
;
2182 error
= copyin(ifr
->ifr_data
, &wreq
, sizeof(wreq
));
2186 switch (wreq
.wi_type
) {
2187 case WI_RID_READ_APS
:
2189 error
= ndis_set_info(sc
, OID_802_11_BSSID_LIST_SCAN
,
2192 tsleep(&error
, PPAUSE
|PCATCH
, "ssidscan", hz
* 2);
2194 error
= ndis_get_info(sc
, OID_802_11_BSSID_LIST
, NULL
, &len
);
2195 if (error
!= ENOSPC
)
2197 bl
= malloc(len
, M_DEVBUF
, M_WAITOK
|M_ZERO
);
2198 error
= ndis_get_info(sc
, OID_802_11_BSSID_LIST
, bl
, &len
);
2203 maxaps
= (2 * wreq
.wi_len
- sizeof(int)) / sizeof(*api
);
2204 maxaps
= MIN(maxaps
, bl
->nblx_items
);
2205 wreq
.wi_len
= (maxaps
* sizeof(*api
) + sizeof(int)) / 2;
2206 *(int *)&wreq
.wi_val
= maxaps
;
2207 api
= (struct wi_apinfo
*)&((int *)&wreq
.wi_val
)[1];
2208 wb
= bl
->nblx_bssid
;
2210 memset(api
, 0, sizeof(*api
));
2211 memcpy(&api
->bssid
, &wb
->nwbx_macaddr
,
2212 sizeof(api
->bssid
));
2213 api
->namelen
= wb
->nwbx_ssid
.ns_ssidlen
;
2214 memcpy(&api
->name
, &wb
->nwbx_ssid
.ns_ssid
, api
->namelen
);
2215 if (wb
->nwbx_privacy
)
2216 api
->capinfo
|= IEEE80211_CAPINFO_PRIVACY
;
2217 /* XXX Where can we get noise information? */
2218 api
->signal
= wb
->nwbx_rssi
+ 149; /* XXX */
2219 api
->quality
= api
->signal
;
2221 ieee80211_mhz2ieee(wb
->nwbx_config
.nc_dsconfig
/
2223 /* In "auto" infrastructure mode, this is useless. */
2224 if (wb
->nwbx_netinfra
== NDIS_80211_NET_INFRA_IBSS
)
2225 api
->capinfo
|= IEEE80211_CAPINFO_IBSS
;
2226 if (wb
->nwbx_len
> sizeof(ndis_wlan_bssid
)) {
2227 j
= sizeof(ndis_80211_rates_ex
);
2228 /* handle other extended things */
2230 j
= sizeof(ndis_80211_rates
);
2231 for (i
= api
->rate
= 0; i
< j
; i
++)
2232 api
->rate
= MAX(api
->rate
, 5 *
2233 (wb
->nwbx_supportedrates
[i
] & 0x7f));
2235 wb
= (ndis_wlan_bssid_ex
*)((char *)wb
+ wb
->nwbx_len
);
2238 error
= copyout(&wreq
, ifr
->ifr_data
, sizeof(wreq
));
2248 ndis_wi_ioctl_set(struct ifnet
*ifp
, u_long command
, void * data
)
2252 struct ndis_softc
*sc
;
2256 error
= kauth_authorize_network(kauth_cred_get(),
2257 KAUTH_NETWORK_INTERFACE
, KAUTH_REQ_NETWORK_INTERFACE_SETPRIV
,
2258 ifp
, KAUTH_ARG(command
), NULL
);
2263 ifr
= (struct ifreq
*)data
;
2264 error
= copyin(ifr
->ifr_data
, &wreq
, sizeof(wreq
));
2268 switch (wreq
.wi_type
) {
2269 case WI_RID_SCAN_APS
:
2270 case WI_RID_SCAN_REQ
: /* arguments ignored */
2273 error
= ndis_set_info(sc
, OID_802_11_BSSID_LIST_SCAN
, &foo
,
2284 ndis_watchdog(struct ifnet
*ifp
)
2286 struct ndis_softc
*sc
;
2294 aprint_error_dev(sc
->ndis_dev
, "watchdog timeout\n");
2298 ndis_sched((void(*)(void *))ndis_reset_nic
, sc
, NDIS_TASKQUEUE
);
2299 ndis_sched(ndis_starttask
, ifp
, NDIS_TASKQUEUE
);
2305 * Stop the adapter and free any mbufs allocated to the
2309 ndis_stop(struct ndis_softc
*sc
)
2314 ifp
= &sc
->arpcom
.ac_if
;
2315 callout_stop(&sc
->ndis_stat_ch
);
2323 ifp
->if_flags
&= ~(IFF_RUNNING
| IFF_OACTIVE
);
2331 * Stop all chip I/O so that the kernel's probe routines don't
2332 * get confused by errant DMAs when rebooting.
2334 /* TODO: remove this #ifdef once ndis_shutdown_nic() is working on NetBSD */