kernel: Use NULL for pointers in DRIVER_MODULE().
[dragonfly.git] / sys / dev / netif / ndis / if_ndis.c
blob8df000fd9689eb4c455a17710ce9875efde300cd
1 /*-
2 * Copyright (c) 2003
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
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.
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.
32 * $FreeBSD: head/sys/dev/if_ndis/if_ndis.c 298955 2016-05-03 03:41:25Z pfg $
34 * WPA support originally contributed by Arvind Srinivasan <arvind@celar.us>
35 * then hacked upon mercilessly by me.
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/endian.h>
44 #include <sys/priv.h>
45 #include <sys/kernel.h>
46 #include <sys/socket.h>
47 #include <sys/queue.h>
48 #include <sys/module.h>
49 #include <sys/proc.h>
50 #include <sys/sysctl.h>
51 #include <sys/kthread.h>
52 #include <sys/limits.h>
54 #include <net/if.h>
55 #include <net/if_var.h>
56 #include <net/if_arp.h>
57 #include <net/ethernet.h>
58 #include <net/if_dl.h>
59 #include <net/if_media.h>
60 #include <net/if_types.h>
61 #include <net/route.h>
63 #include <net/bpf.h>
64 #include <net/ifq_var.h>
66 #if !defined(__DragonFly__)
67 #include <machine/bus.h>
68 #include <machine/resource.h>
69 #endif
70 #include <sys/bus.h>
71 #include <sys/rman.h>
73 #if defined(__DragonFly__)
74 #include <netproto/802_11/ieee80211_var.h>
75 #include <netproto/802_11/ieee80211_ioctl.h>
76 #include <netproto/802_11/ieee80211_regdomain.h>
77 #else
78 #include <net80211/ieee80211_var.h>
79 #include <net80211/ieee80211_ioctl.h>
80 #include <net80211/ieee80211_regdomain.h>
81 #endif
83 #if defined(__DragonFly__)
84 #include <bus/pci/pcireg.h>
85 #include <bus/pci/pcivar.h>
86 #include <bus/u4b/usb.h>
87 #include <bus/u4b/usbdi.h>
88 #else
89 #include <dev/pci/pcireg.h>
90 #include <dev/pci/pcivar.h>
91 #include <dev/usb/usb.h>
92 #include <dev/usb/usbdi.h>
93 #endif
95 #if defined(__DragonFly__)
96 #include <emulation/ndis/pe_var.h>
97 #include <emulation/ndis/cfg_var.h>
98 #include <emulation/ndis/resource_var.h>
99 #include <emulation/ndis/ntoskrnl_var.h>
100 #include <emulation/ndis/hal_var.h>
101 #include <emulation/ndis/ndis_var.h>
102 #include <emulation/ndis/u4bd_var.h>
103 #include <dev/netif/ndis/if_ndisvar.h>
104 #else
105 #include <compat/ndis/pe_var.h>
106 #include <compat/ndis/cfg_var.h>
107 #include <compat/ndis/resource_var.h>
108 #include <compat/ndis/ntoskrnl_var.h>
109 #include <compat/ndis/hal_var.h>
110 #include <compat/ndis/ndis_var.h>
111 #include <compat/ndis/usbd_var.h>
112 #include <dev/if_ndis/if_ndisvar.h>
113 #endif
115 #define NDIS_DEBUG
116 #ifdef NDIS_DEBUG
117 #define DPRINTF(x) do { if (ndis_debug > 0) kprintf x; } while (0)
118 int ndis_debug = 0;
119 SYSCTL_INT(_debug, OID_AUTO, ndis, CTLFLAG_RW, &ndis_debug, 0,
120 "if_ndis debug level");
121 #else
122 #define DPRINTF(x)
123 #endif
125 SYSCTL_DECL(_hw_ndisusb);
126 int ndisusb_halt = 1;
127 SYSCTL_INT(_hw_ndisusb, OID_AUTO, halt, CTLFLAG_RW, &ndisusb_halt, 0,
128 "Halt NDIS USB driver when it's attached");
130 /* 0 - 30 dBm to mW conversion table */
131 static const uint16_t dBm2mW[] = {
132 1, 1, 1, 1, 2, 2, 2, 2, 3, 3,
133 3, 4, 4, 4, 5, 6, 6, 7, 8, 9,
134 10, 11, 13, 14, 16, 18, 20, 22, 25, 28,
135 32, 35, 40, 45, 50, 56, 63, 71, 79, 89,
136 100, 112, 126, 141, 158, 178, 200, 224, 251, 282,
137 316, 355, 398, 447, 501, 562, 631, 708, 794, 891,
138 1000
141 MODULE_DEPEND(if_ndis, ether, 1, 1, 1);
142 MODULE_DEPEND(if_ndis, wlan, 1, 1, 1);
143 MODULE_DEPEND(if_ndis, ndis, 1, 1, 1);
145 MODULE_VERSION(if_ndis, 1);
147 int ndis_attach (device_t);
148 int ndis_detach (device_t);
149 int ndis_suspend (device_t);
150 int ndis_resume (device_t);
151 void ndis_shutdown (device_t);
153 int ndisdrv_modevent (module_t, int, void *);
155 static void ndis_txeof (ndis_handle, ndis_packet *, ndis_status);
156 static void ndis_rxeof (ndis_handle, ndis_packet **, uint32_t);
157 static void ndis_rxeof_eth (ndis_handle, ndis_handle, char *, void *,
158 uint32_t, void *, uint32_t, uint32_t);
159 static void ndis_rxeof_done (ndis_handle);
160 static void ndis_rxeof_xfr (kdpc *, ndis_handle, void *, void *);
161 static void ndis_rxeof_xfr_done (ndis_handle, ndis_packet *,
162 uint32_t, uint32_t);
163 static void ndis_linksts (ndis_handle, ndis_status, void *, uint32_t);
164 static void ndis_linksts_done (ndis_handle);
166 /* We need to wrap these functions for amd64. */
167 static funcptr ndis_txeof_wrap;
168 static funcptr ndis_rxeof_wrap;
169 static funcptr ndis_rxeof_eth_wrap;
170 static funcptr ndis_rxeof_done_wrap;
171 static funcptr ndis_rxeof_xfr_wrap;
172 static funcptr ndis_rxeof_xfr_done_wrap;
173 static funcptr ndis_linksts_wrap;
174 static funcptr ndis_linksts_done_wrap;
175 static funcptr ndis_ticktask_wrap;
176 static funcptr ndis_starttask_wrap;
177 static funcptr ndis_resettask_wrap;
178 static funcptr ndis_inputtask_wrap;
180 static struct ieee80211vap *ndis_vap_create(struct ieee80211com *,
181 const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
182 const uint8_t [IEEE80211_ADDR_LEN],
183 const uint8_t [IEEE80211_ADDR_LEN]);
184 static void ndis_vap_delete (struct ieee80211vap *);
185 static void ndis_tick (void *);
186 static void ndis_ticktask (device_object *, void *);
187 static int ndis_raw_xmit (struct ieee80211_node *, struct mbuf *,
188 const struct ieee80211_bpf_params *);
189 static void ndis_update_mcast (struct ieee80211com *);
190 static void ndis_update_promisc (struct ieee80211com *);
191 static void ndis_start (struct ifnet *ifp, struct ifaltq_subque *ifsq);
192 static void ndis_starttask (device_object *, void *);
193 static void ndis_resettask (device_object *, void *);
194 static void ndis_inputtask (device_object *, void *);
195 static int ndis_ioctl (struct ifnet *, u_long, caddr_t, struct ucred *);
196 static int ndis_newstate (struct ieee80211vap *, enum ieee80211_state,
197 int);
198 static int ndis_nettype_chan (uint32_t);
199 static int ndis_nettype_mode (uint32_t);
200 static void ndis_scan (void *);
201 static void ndis_scan_results (struct ndis_softc *);
202 static void ndis_scan_start (struct ieee80211com *);
203 static void ndis_scan_end (struct ieee80211com *);
204 static void ndis_set_channel (struct ieee80211com *);
205 static void ndis_scan_curchan (struct ieee80211_scan_state *, unsigned long);
206 static void ndis_scan_mindwell (struct ieee80211_scan_state *);
207 static void ndis_init (void *);
208 static void ndis_stop (struct ndis_softc *);
209 static int ndis_ifmedia_upd (struct ifnet *);
210 static void ndis_ifmedia_sts (struct ifnet *, struct ifmediareq *);
211 static int ndis_get_bssid_list (struct ndis_softc *,
212 ndis_80211_bssid_list_ex **);
213 static int ndis_get_assoc (struct ndis_softc *, ndis_wlan_bssid_ex **);
214 static int ndis_probe_offload (struct ndis_softc *);
215 static int ndis_set_offload (struct ndis_softc *);
216 static void ndis_getstate_80211 (struct ndis_softc *);
217 static void ndis_setstate_80211 (struct ndis_softc *);
218 static void ndis_auth_and_assoc (struct ndis_softc *, struct ieee80211vap *);
219 static void ndis_media_status (struct ifnet *, struct ifmediareq *);
220 static int ndis_set_cipher (struct ndis_softc *, int);
221 static int ndis_set_wpa (struct ndis_softc *, void *, int);
222 static int ndis_add_key (struct ieee80211vap *,
223 const struct ieee80211_key *);
224 static int ndis_del_key (struct ieee80211vap *,
225 const struct ieee80211_key *);
226 static void ndis_setmulti (struct ndis_softc *);
227 static void ndis_map_sclist (void *, bus_dma_segment_t *,
228 int, bus_size_t, int);
229 static int ndis_ifattach(struct ndis_softc *);
231 static int ndis_80211attach(struct ndis_softc *);
232 static int ndis_80211ioctl(struct ieee80211com *, u_long , void *);
233 static int ndis_80211transmit(struct ieee80211com *, struct mbuf *);
234 static void ndis_80211parent(struct ieee80211com *);
236 static int ndisdrv_loaded = 0;
239 * This routine should call windrv_load() once for each driver
240 * image. This will do the relocation and dynalinking for the
241 * image, and create a Windows driver object which will be
242 * saved in our driver database.
245 ndisdrv_modevent(module_t mod, int cmd, void *arg)
247 int error = 0;
249 switch (cmd) {
250 case MOD_LOAD:
251 ndisdrv_loaded++;
252 if (ndisdrv_loaded > 1)
253 break;
254 windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap,
255 3, WINDRV_WRAP_STDCALL);
256 windrv_wrap((funcptr)ndis_rxeof_eth, &ndis_rxeof_eth_wrap,
257 8, WINDRV_WRAP_STDCALL);
258 windrv_wrap((funcptr)ndis_rxeof_done, &ndis_rxeof_done_wrap,
259 1, WINDRV_WRAP_STDCALL);
260 windrv_wrap((funcptr)ndis_rxeof_xfr, &ndis_rxeof_xfr_wrap,
261 4, WINDRV_WRAP_STDCALL);
262 windrv_wrap((funcptr)ndis_rxeof_xfr_done,
263 &ndis_rxeof_xfr_done_wrap, 4, WINDRV_WRAP_STDCALL);
264 windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap,
265 3, WINDRV_WRAP_STDCALL);
266 windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap,
267 4, WINDRV_WRAP_STDCALL);
268 windrv_wrap((funcptr)ndis_linksts_done,
269 &ndis_linksts_done_wrap, 1, WINDRV_WRAP_STDCALL);
270 windrv_wrap((funcptr)ndis_ticktask, &ndis_ticktask_wrap,
271 2, WINDRV_WRAP_STDCALL);
272 windrv_wrap((funcptr)ndis_starttask, &ndis_starttask_wrap,
273 2, WINDRV_WRAP_STDCALL);
274 windrv_wrap((funcptr)ndis_resettask, &ndis_resettask_wrap,
275 2, WINDRV_WRAP_STDCALL);
276 windrv_wrap((funcptr)ndis_inputtask, &ndis_inputtask_wrap,
277 2, WINDRV_WRAP_STDCALL);
278 break;
279 case MOD_UNLOAD:
280 ndisdrv_loaded--;
281 if (ndisdrv_loaded > 0)
282 break;
283 /* fallthrough */
284 case MOD_SHUTDOWN:
285 windrv_unwrap(ndis_rxeof_wrap);
286 windrv_unwrap(ndis_rxeof_eth_wrap);
287 windrv_unwrap(ndis_rxeof_done_wrap);
288 windrv_unwrap(ndis_rxeof_xfr_wrap);
289 windrv_unwrap(ndis_rxeof_xfr_done_wrap);
290 windrv_unwrap(ndis_txeof_wrap);
291 windrv_unwrap(ndis_linksts_wrap);
292 windrv_unwrap(ndis_linksts_done_wrap);
293 windrv_unwrap(ndis_ticktask_wrap);
294 windrv_unwrap(ndis_starttask_wrap);
295 windrv_unwrap(ndis_resettask_wrap);
296 windrv_unwrap(ndis_inputtask_wrap);
297 break;
298 default:
299 error = EINVAL;
300 break;
303 return (error);
307 * Program the 64-bit multicast hash filter.
309 static void
310 ndis_setmulti(struct ndis_softc *sc)
312 struct ifnet *ifp;
313 struct ifmultiaddr *ifma;
314 int len, mclistsz, error;
315 uint8_t *mclist;
317 ifp = sc->ifp;
319 if (!NDIS_INITIALIZED(sc))
320 return;
322 if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
323 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
324 len = sizeof(sc->ndis_filter);
325 error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
326 &sc->ndis_filter, &len);
327 if (error)
328 device_printf(sc->ndis_dev,
329 "set allmulti failed: %d\n", error);
330 return;
333 if (TAILQ_EMPTY(&ifp->if_multiaddrs))
334 return;
336 len = sizeof(mclistsz);
337 ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len);
339 mclist = kmalloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_INTWAIT|M_ZERO);
341 if (mclist == NULL) {
342 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
343 goto out;
346 sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST;
348 len = 0;
349 #if 0 /* XXX swildner */
350 if_maddr_rlock(ifp);
351 #endif
352 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
353 if (ifma->ifma_addr->sa_family != AF_LINK)
354 continue;
355 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
356 mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN);
357 len++;
358 if (len > mclistsz) {
359 #if 0 /* XXX swildner */
360 if_maddr_runlock(ifp);
361 #endif
362 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
363 sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
364 goto out;
367 #if 0 /* XXX swildner */
368 if_maddr_runlock(ifp);
369 #endif
371 len = len * ETHER_ADDR_LEN;
372 error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len);
373 if (error) {
374 device_printf(sc->ndis_dev, "set mclist failed: %d\n", error);
375 sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
376 sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
379 out:
380 kfree(mclist, M_TEMP);
382 len = sizeof(sc->ndis_filter);
383 error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
384 &sc->ndis_filter, &len);
385 if (error)
386 device_printf(sc->ndis_dev, "set multi failed: %d\n", error);
389 static int
390 ndis_set_offload(struct ndis_softc *sc)
392 ndis_task_offload *nto;
393 ndis_task_offload_hdr *ntoh;
394 ndis_task_tcpip_csum *nttc;
395 struct ifnet *ifp;
396 int len, error;
398 ifp = sc->ifp;
400 if (!NDIS_INITIALIZED(sc))
401 return (EINVAL);
403 /* See if there's anything to set. */
405 error = ndis_probe_offload(sc);
406 if (error)
407 return (error);
409 if (sc->ndis_hwassist == 0 && ifp->if_capabilities == 0)
410 return (0);
412 len = sizeof(ndis_task_offload_hdr) + sizeof(ndis_task_offload) +
413 sizeof(ndis_task_tcpip_csum);
415 ntoh = kmalloc(len, M_TEMP, M_INTWAIT|M_ZERO);
417 if (ntoh == NULL)
418 return (ENOMEM);
420 ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
421 ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
422 ntoh->ntoh_offset_firsttask = sizeof(ndis_task_offload_hdr);
423 ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
424 ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
425 ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
427 nto = (ndis_task_offload *)((char *)ntoh +
428 ntoh->ntoh_offset_firsttask);
430 nto->nto_vers = NDIS_TASK_OFFLOAD_VERSION;
431 nto->nto_len = sizeof(ndis_task_offload);
432 nto->nto_task = NDIS_TASK_TCPIP_CSUM;
433 nto->nto_offset_nexttask = 0;
434 nto->nto_taskbuflen = sizeof(ndis_task_tcpip_csum);
436 nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
438 if (ifp->if_capenable & IFCAP_TXCSUM)
439 nttc->nttc_v4tx = sc->ndis_v4tx;
441 if (ifp->if_capenable & IFCAP_RXCSUM)
442 nttc->nttc_v4rx = sc->ndis_v4rx;
444 error = ndis_set_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
445 kfree(ntoh, M_TEMP);
447 return (error);
450 static int
451 ndis_probe_offload(struct ndis_softc *sc)
453 ndis_task_offload *nto;
454 ndis_task_offload_hdr *ntoh;
455 ndis_task_tcpip_csum *nttc = NULL;
456 struct ifnet *ifp;
457 int len, error, dummy;
459 ifp = sc->ifp;
461 len = sizeof(dummy);
462 error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, &dummy, &len);
464 if (error != ENOSPC)
465 return (error);
467 ntoh = kmalloc(len, M_TEMP, M_INTWAIT|M_ZERO);
469 if (ntoh == NULL)
470 return (ENOMEM);
472 ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
473 ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
474 ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
475 ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
476 ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
478 error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
480 if (error) {
481 kfree(ntoh, M_TEMP);
482 return (error);
485 if (ntoh->ntoh_vers != NDIS_TASK_OFFLOAD_VERSION) {
486 kfree(ntoh, M_TEMP);
487 return (EINVAL);
490 nto = (ndis_task_offload *)((char *)ntoh +
491 ntoh->ntoh_offset_firsttask);
493 while (1) {
494 switch (nto->nto_task) {
495 case NDIS_TASK_TCPIP_CSUM:
496 nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
497 break;
498 /* Don't handle these yet. */
499 case NDIS_TASK_IPSEC:
500 case NDIS_TASK_TCP_LARGESEND:
501 default:
502 break;
504 if (nto->nto_offset_nexttask == 0)
505 break;
506 nto = (ndis_task_offload *)((char *)nto +
507 nto->nto_offset_nexttask);
510 if (nttc == NULL) {
511 kfree(ntoh, M_TEMP);
512 return (ENOENT);
515 sc->ndis_v4tx = nttc->nttc_v4tx;
516 sc->ndis_v4rx = nttc->nttc_v4rx;
518 if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_IP_CSUM)
519 sc->ndis_hwassist |= CSUM_IP;
520 if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
521 sc->ndis_hwassist |= CSUM_TCP;
522 if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
523 sc->ndis_hwassist |= CSUM_UDP;
525 if (sc->ndis_hwassist)
526 ifp->if_capabilities |= IFCAP_TXCSUM;
528 if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_IP_CSUM)
529 ifp->if_capabilities |= IFCAP_RXCSUM;
530 if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
531 ifp->if_capabilities |= IFCAP_RXCSUM;
532 if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
533 ifp->if_capabilities |= IFCAP_RXCSUM;
535 kfree(ntoh, M_TEMP);
536 return (0);
539 static int
540 ndis_nettype_chan(uint32_t type)
542 switch (type) {
543 case NDIS_80211_NETTYPE_11FH: return (IEEE80211_CHAN_FHSS);
544 case NDIS_80211_NETTYPE_11DS: return (IEEE80211_CHAN_B);
545 case NDIS_80211_NETTYPE_11OFDM5: return (IEEE80211_CHAN_A);
546 case NDIS_80211_NETTYPE_11OFDM24: return (IEEE80211_CHAN_G);
548 DPRINTF(("unknown channel nettype %d\n", type));
549 return (IEEE80211_CHAN_B); /* Default to 11B chan */
552 static int
553 ndis_nettype_mode(uint32_t type)
555 switch (type) {
556 case NDIS_80211_NETTYPE_11FH: return (IEEE80211_MODE_FH);
557 case NDIS_80211_NETTYPE_11DS: return (IEEE80211_MODE_11B);
558 case NDIS_80211_NETTYPE_11OFDM5: return (IEEE80211_MODE_11A);
559 case NDIS_80211_NETTYPE_11OFDM24: return (IEEE80211_MODE_11G);
561 DPRINTF(("unknown mode nettype %d\n", type));
562 return (IEEE80211_MODE_AUTO);
566 * Attach the interface. Allocate softc structures, do ifmedia
567 * setup and ethernet/BPF attach.
570 ndis_attach(device_t dev)
572 struct ndis_softc *sc;
573 driver_object *pdrv;
574 device_object *pdo;
575 int error = 0, len;
576 int i;
578 sc = device_get_softc(dev);
580 #if defined(__DragonFly__)
581 lockinit(&sc->ndis_lock, "network driver", 0, LK_CANRECURSE);
582 #else
583 mtx_init(&sc->ndis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
584 MTX_DEF);
585 #endif
586 KeInitializeSpinLock(&sc->ndis_rxlock);
587 KeInitializeSpinLock(&sc->ndisusb_tasklock);
588 KeInitializeSpinLock(&sc->ndisusb_xferdonelock);
589 InitializeListHead(&sc->ndis_shlist);
590 InitializeListHead(&sc->ndisusb_tasklist);
591 InitializeListHead(&sc->ndisusb_xferdonelist);
592 #if defined(__DragonFly__)
593 callout_init_mp(&sc->ndis_stat_callout);
594 #else
595 callout_init(&sc->ndis_stat_callout, 1);
596 #endif
597 mbufq_init(&sc->ndis_rxqueue, INT_MAX); /* XXXGL: sane maximum */
599 if (sc->ndis_iftype == PCMCIABus) {
600 error = ndis_alloc_amem(sc);
601 if (error) {
602 device_printf(dev, "failed to allocate "
603 "attribute memory\n");
604 goto fail;
608 /* Create sysctl registry nodes */
609 ndis_create_sysctls(sc);
611 /* Find the PDO for this device instance. */
613 if (sc->ndis_iftype == PCIBus)
614 pdrv = windrv_lookup(0, "PCI Bus");
615 else if (sc->ndis_iftype == PCMCIABus)
616 pdrv = windrv_lookup(0, "PCCARD Bus");
617 else
618 pdrv = windrv_lookup(0, "USB Bus");
619 pdo = windrv_find_pdo(pdrv, dev);
622 * Create a new functional device object for this
623 * device. This is what creates the miniport block
624 * for this device instance.
627 if (NdisAddDevice(sc->ndis_dobj, pdo) != STATUS_SUCCESS) {
628 device_printf(dev, "failed to create FDO!\n");
629 error = ENXIO;
630 goto fail;
633 /* Tell the user what version of the API the driver is using. */
634 device_printf(dev, "NDIS API version: %d.%d\n",
635 sc->ndis_chars->nmc_version_major,
636 sc->ndis_chars->nmc_version_minor);
638 /* Do resource conversion. */
639 if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus)
640 ndis_convert_res(sc);
641 else
642 sc->ndis_block->nmb_rlist = NULL;
644 /* Install our RX and TX interrupt handlers. */
645 sc->ndis_block->nmb_senddone_func = ndis_txeof_wrap;
646 sc->ndis_block->nmb_pktind_func = ndis_rxeof_wrap;
647 sc->ndis_block->nmb_ethrxindicate_func = ndis_rxeof_eth_wrap;
648 sc->ndis_block->nmb_ethrxdone_func = ndis_rxeof_done_wrap;
649 sc->ndis_block->nmb_tdcond_func = ndis_rxeof_xfr_done_wrap;
651 /* Override the status handler so we can detect link changes. */
652 sc->ndis_block->nmb_status_func = ndis_linksts_wrap;
653 sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap;
655 /* Set up work item handlers. */
656 sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
657 sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
658 sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
659 sc->ndis_inputitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
660 sc->ndisusb_xferdoneitem =
661 IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
662 sc->ndisusb_taskitem =
663 IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
664 KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block);
666 /* Call driver's init routine. */
667 if (ndis_init_nic(sc)) {
668 device_printf(dev, "init handler failed\n");
669 error = ENXIO;
670 goto fail;
674 * Figure out how big to make the TX buffer pool.
676 len = sizeof(sc->ndis_maxpkts);
677 if (ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS,
678 &sc->ndis_maxpkts, &len)) {
679 device_printf(dev, "failed to get max TX packets\n");
680 error = ENXIO;
681 goto fail;
685 * If this is a deserialized miniport, we don't have
686 * to honor the OID_GEN_MAXIMUM_SEND_PACKETS result.
688 if (!NDIS_SERIALIZED(sc->ndis_block))
689 sc->ndis_maxpkts = NDIS_TXPKTS;
691 /* Enforce some sanity, just in case. */
693 if (sc->ndis_maxpkts == 0)
694 sc->ndis_maxpkts = 10;
696 sc->ndis_txarray = kmalloc(sizeof(ndis_packet *) *
697 sc->ndis_maxpkts, M_DEVBUF, M_INTWAIT|M_ZERO);
699 /* Allocate a pool of ndis_packets for TX encapsulation. */
701 NdisAllocatePacketPool(&i, &sc->ndis_txpool,
702 sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET);
704 if (i != NDIS_STATUS_SUCCESS) {
705 sc->ndis_txpool = NULL;
706 device_printf(dev, "failed to allocate TX packet pool");
707 error = ENOMEM;
708 goto fail;
711 sc->ndis_txpending = sc->ndis_maxpkts;
713 sc->ndis_oidcnt = 0;
714 /* Get supported oid list. */
715 ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt);
717 /* If the NDIS module requested scatter/gather, init maps. */
718 if (sc->ndis_sc)
719 ndis_init_dma(sc);
722 * See if the OID_802_11_CONFIGURATION OID is
723 * supported by this driver. If it is, then this an 802.11
724 * wireless driver, and we should set up media for wireless.
726 for (i = 0; i < sc->ndis_oidcnt; i++)
727 if (sc->ndis_oids[i] == OID_802_11_CONFIGURATION) {
728 sc->ndis_80211 = 1;
729 break;
732 if (sc->ndis_80211)
733 error = ndis_80211attach(sc);
734 else
735 error = ndis_ifattach(sc);
737 fail:
738 if (error) {
739 ndis_detach(dev);
740 return (error);
743 if (sc->ndis_iftype == PNPBus && ndisusb_halt == 0)
744 return (error);
746 DPRINTF(("attach done.\n"));
747 /* We're done talking to the NIC for now; halt it. */
748 ndis_halt_nic(sc);
749 DPRINTF(("halting done.\n"));
751 return (error);
754 static int
755 ndis_80211attach(struct ndis_softc *sc)
757 struct ieee80211com *ic = &sc->ndis_ic;
758 ndis_80211_rates_ex rates;
759 struct ndis_80211_nettype_list *ntl;
760 uint32_t arg;
761 int mode, i, r, len, nonettypes = 1;
762 uint8_t bands[IEEE80211_MODE_BYTES] = { 0 };
764 #if defined(__DragonFly__)
765 callout_init_mp(&sc->ndis_scan_callout);
766 #else
767 callout_init(&sc->ndis_scan_callout, 1);
768 #endif
770 ic->ic_softc = sc;
771 ic->ic_ioctl = ndis_80211ioctl;
772 ic->ic_name = device_get_nameunit(sc->ndis_dev);
773 ic->ic_opmode = IEEE80211_M_STA;
774 ic->ic_phytype = IEEE80211_T_DS;
775 ic->ic_caps = IEEE80211_C_8023ENCAP |
776 IEEE80211_C_STA | IEEE80211_C_IBSS;
777 setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO);
778 len = 0;
779 r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, NULL, &len);
780 if (r != ENOSPC)
781 goto nonettypes;
782 ntl = kmalloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
783 r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, ntl, &len);
784 if (r != 0) {
785 kfree(ntl, M_DEVBUF);
786 goto nonettypes;
789 for (i = 0; i < ntl->ntl_items; i++) {
790 mode = ndis_nettype_mode(ntl->ntl_type[i]);
791 if (mode) {
792 nonettypes = 0;
793 setbit(ic->ic_modecaps, mode);
794 setbit(bands, mode);
795 } else
796 device_printf(sc->ndis_dev, "Unknown nettype %d\n",
797 ntl->ntl_type[i]);
799 kfree(ntl, M_DEVBUF);
800 nonettypes:
801 /* Default to 11b channels if the card did not supply any */
802 if (nonettypes) {
803 setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
804 setbit(bands, IEEE80211_MODE_11B);
806 len = sizeof(rates);
807 bzero((char *)&rates, len);
808 r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES, (void *)rates, &len);
809 if (r != 0)
810 device_printf(sc->ndis_dev, "get rates failed: 0x%x\n", r);
812 * Since the supported rates only up to 8 can be supported,
813 * if this is not 802.11b we're just going to be faking it
814 * all up to heck.
817 #define TESTSETRATE(x, y) \
818 do { \
819 int i; \
820 for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) { \
821 if (ic->ic_sup_rates[x].rs_rates[i] == (y)) \
822 break; \
824 if (i == ic->ic_sup_rates[x].rs_nrates) { \
825 ic->ic_sup_rates[x].rs_rates[i] = (y); \
826 ic->ic_sup_rates[x].rs_nrates++; \
828 } while (0)
830 #define SETRATE(x, y) \
831 ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y)
832 #define INCRATE(x) \
833 ic->ic_sup_rates[x].rs_nrates++
835 ic->ic_curmode = IEEE80211_MODE_AUTO;
836 if (isset(ic->ic_modecaps, IEEE80211_MODE_11A))
837 ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0;
838 if (isset(ic->ic_modecaps, IEEE80211_MODE_11B))
839 ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0;
840 if (isset(ic->ic_modecaps, IEEE80211_MODE_11G))
841 ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0;
842 for (i = 0; i < len; i++) {
843 switch (rates[i] & IEEE80211_RATE_VAL) {
844 case 2:
845 case 4:
846 case 11:
847 case 10:
848 case 22:
849 if (isclr(ic->ic_modecaps, IEEE80211_MODE_11B)) {
850 /* Lazy-init 802.11b. */
851 setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
852 ic->ic_sup_rates[IEEE80211_MODE_11B].
853 rs_nrates = 0;
855 SETRATE(IEEE80211_MODE_11B, rates[i]);
856 INCRATE(IEEE80211_MODE_11B);
857 break;
858 default:
859 if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) {
860 SETRATE(IEEE80211_MODE_11A, rates[i]);
861 INCRATE(IEEE80211_MODE_11A);
863 if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) {
864 SETRATE(IEEE80211_MODE_11G, rates[i]);
865 INCRATE(IEEE80211_MODE_11G);
867 break;
872 * If the hardware supports 802.11g, it most
873 * likely supports 802.11b and all of the
874 * 802.11b and 802.11g speeds, so maybe we can
875 * just cheat here. Just how in the heck do
876 * we detect turbo modes, though?
878 if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) {
879 TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|2);
880 TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|4);
881 TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|11);
882 TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|22);
884 if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) {
885 TESTSETRATE(IEEE80211_MODE_11G, 48);
886 TESTSETRATE(IEEE80211_MODE_11G, 72);
887 TESTSETRATE(IEEE80211_MODE_11G, 96);
888 TESTSETRATE(IEEE80211_MODE_11G, 108);
890 if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) {
891 TESTSETRATE(IEEE80211_MODE_11A, 48);
892 TESTSETRATE(IEEE80211_MODE_11A, 72);
893 TESTSETRATE(IEEE80211_MODE_11A, 96);
894 TESTSETRATE(IEEE80211_MODE_11A, 108);
897 #undef SETRATE
898 #undef INCRATE
899 #undef TESTSETRATE
901 ieee80211_init_channels(ic, NULL, bands);
904 * To test for WPA support, we need to see if we can
905 * set AUTHENTICATION_MODE to WPA and read it back
906 * successfully.
908 i = sizeof(arg);
909 arg = NDIS_80211_AUTHMODE_WPA;
910 r = ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i);
911 if (r == 0) {
912 r = ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i);
913 if (r == 0 && arg == NDIS_80211_AUTHMODE_WPA)
914 ic->ic_caps |= IEEE80211_C_WPA;
918 * To test for supported ciphers, we set each
919 * available encryption type in descending order.
920 * If ENC3 works, then we have WEP, TKIP and AES.
921 * If only ENC2 works, then we have WEP and TKIP.
922 * If only ENC1 works, then we have just WEP.
924 i = sizeof(arg);
925 arg = NDIS_80211_WEPSTAT_ENC3ENABLED;
926 r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
927 if (r == 0) {
928 ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP
929 | IEEE80211_CRYPTO_TKIP
930 | IEEE80211_CRYPTO_AES_CCM;
931 goto got_crypto;
933 arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
934 r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
935 if (r == 0) {
936 ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP
937 | IEEE80211_CRYPTO_TKIP;
938 goto got_crypto;
940 arg = NDIS_80211_WEPSTAT_ENC1ENABLED;
941 r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i);
942 if (r == 0)
943 ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP;
944 got_crypto:
945 i = sizeof(arg);
946 r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i);
947 if (r == 0)
948 ic->ic_caps |= IEEE80211_C_PMGT;
950 r = ndis_get_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &i);
951 if (r == 0)
952 ic->ic_caps |= IEEE80211_C_TXPMGT;
955 * Get station address from the driver.
957 len = sizeof(ic->ic_macaddr);
958 ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &ic->ic_macaddr, &len);
960 ieee80211_ifattach(ic);
961 ic->ic_raw_xmit = ndis_raw_xmit;
962 ic->ic_scan_start = ndis_scan_start;
963 ic->ic_scan_end = ndis_scan_end;
964 ic->ic_set_channel = ndis_set_channel;
965 ic->ic_scan_curchan = ndis_scan_curchan;
966 ic->ic_scan_mindwell = ndis_scan_mindwell;
967 ic->ic_bsschan = IEEE80211_CHAN_ANYC;
968 ic->ic_vap_create = ndis_vap_create;
969 ic->ic_vap_delete = ndis_vap_delete;
970 ic->ic_update_mcast = ndis_update_mcast;
971 ic->ic_update_promisc = ndis_update_promisc;
972 ic->ic_transmit = ndis_80211transmit;
973 ic->ic_parent = ndis_80211parent;
975 if (bootverbose)
976 ieee80211_announce(ic);
978 return (0);
981 static int
982 ndis_ifattach(struct ndis_softc *sc)
984 struct ifnet *ifp;
985 u_char eaddr[ETHER_ADDR_LEN];
986 int len;
988 ifp = if_alloc(IFT_ETHER);
989 if (ifp == NULL)
990 return (ENOSPC);
991 sc->ifp = ifp;
992 ifp->if_softc = sc;
994 /* Check for task offload support. */
995 ndis_probe_offload(sc);
998 * Get station address from the driver.
1000 len = sizeof(eaddr);
1001 ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, eaddr, &len);
1003 if_initname(ifp, device_get_name(sc->ndis_dev),
1004 device_get_unit(sc->ndis_dev));
1005 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1006 ifp->if_ioctl = ndis_ioctl;
1007 ifp->if_start = ndis_start;
1008 ifp->if_init = ndis_init;
1009 ifp->if_baudrate = 10000000;
1010 #if defined(__DragonFly__)
1011 ifq_set_maxlen(&ifp->if_snd, 50);
1012 /* ifq_set_ready(&ifp->if_snd); */
1013 #else
1014 IFQ_SET_MAXLEN(&ifp->if_snd, 50);
1015 ifp->if_snd.ifq_drv_maxlen = 25;
1016 IFQ_SET_READY(&ifp->if_snd);
1017 #endif
1018 ifp->if_capenable = ifp->if_capabilities;
1019 ifp->if_hwassist = sc->ndis_hwassist;
1021 ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd,
1022 ndis_ifmedia_sts);
1023 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
1024 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
1025 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
1026 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
1027 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
1028 ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
1029 #if defined(__DragonFly__)
1030 ether_ifattach(ifp, eaddr, NULL);
1031 #else
1032 ether_ifattach(ifp, eaddr);
1033 #endif
1035 return (0);
1038 static struct ieee80211vap *
1039 ndis_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
1040 enum ieee80211_opmode opmode, int flags,
1041 const uint8_t bssid[IEEE80211_ADDR_LEN],
1042 const uint8_t mac[IEEE80211_ADDR_LEN])
1044 struct ndis_vap *nvp;
1045 struct ieee80211vap *vap;
1047 if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
1048 return NULL;
1049 nvp = kmalloc(sizeof(struct ndis_vap), M_80211_VAP, M_WAITOK | M_ZERO);
1050 vap = &nvp->vap;
1051 ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
1052 /* override with driver methods */
1053 nvp->newstate = vap->iv_newstate;
1054 vap->iv_newstate = ndis_newstate;
1056 /* complete setup */
1057 ieee80211_vap_attach(vap, ieee80211_media_change, ndis_media_status,
1058 mac);
1059 ic->ic_opmode = opmode;
1060 /* install key handing routines */
1061 vap->iv_key_set = ndis_add_key;
1062 vap->iv_key_delete = ndis_del_key;
1063 return vap;
1066 static void
1067 ndis_vap_delete(struct ieee80211vap *vap)
1069 struct ndis_vap *nvp = NDIS_VAP(vap);
1070 struct ieee80211com *ic = vap->iv_ic;
1071 struct ndis_softc *sc = ic->ic_softc;
1073 ndis_stop(sc);
1074 callout_drain(&sc->ndis_scan_callout);
1075 ieee80211_vap_detach(vap);
1076 kfree(nvp, M_80211_VAP);
1080 * Shutdown hardware and free up resources. This can be called any
1081 * time after the mutex has been initialized. It is called in both
1082 * the error case in attach and the normal detach case so it needs
1083 * to be careful about only freeing resources that have actually been
1084 * allocated.
1087 ndis_detach(device_t dev)
1089 struct ifnet *ifp;
1090 struct ndis_softc *sc;
1091 driver_object *drv;
1093 sc = device_get_softc(dev);
1094 NDIS_LOCK(sc);
1095 if (!sc->ndis_80211)
1096 ifp = sc->ifp;
1097 else
1098 ifp = NULL;
1099 if (ifp != NULL)
1100 ifp->if_flags &= ~IFF_UP;
1101 if (device_is_attached(dev)) {
1102 NDIS_UNLOCK(sc);
1103 ndis_stop(sc);
1104 if (sc->ndis_80211)
1105 ieee80211_ifdetach(&sc->ndis_ic);
1106 else if (ifp != NULL)
1107 ether_ifdetach(ifp);
1108 } else
1109 NDIS_UNLOCK(sc);
1111 if (sc->ndis_tickitem != NULL)
1112 IoFreeWorkItem(sc->ndis_tickitem);
1113 if (sc->ndis_startitem != NULL)
1114 IoFreeWorkItem(sc->ndis_startitem);
1115 if (sc->ndis_resetitem != NULL)
1116 IoFreeWorkItem(sc->ndis_resetitem);
1117 if (sc->ndis_inputitem != NULL)
1118 IoFreeWorkItem(sc->ndis_inputitem);
1119 if (sc->ndisusb_xferdoneitem != NULL)
1120 IoFreeWorkItem(sc->ndisusb_xferdoneitem);
1121 if (sc->ndisusb_taskitem != NULL)
1122 IoFreeWorkItem(sc->ndisusb_taskitem);
1124 bus_generic_detach(dev);
1125 ndis_unload_driver(sc);
1127 if (sc->ndis_irq)
1128 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq);
1129 if (sc->ndis_res_io)
1130 bus_release_resource(dev, SYS_RES_IOPORT,
1131 sc->ndis_io_rid, sc->ndis_res_io);
1132 if (sc->ndis_res_mem)
1133 bus_release_resource(dev, SYS_RES_MEMORY,
1134 sc->ndis_mem_rid, sc->ndis_res_mem);
1135 if (sc->ndis_res_altmem)
1136 bus_release_resource(dev, SYS_RES_MEMORY,
1137 sc->ndis_altmem_rid, sc->ndis_res_altmem);
1139 if (ifp != NULL)
1140 if_free(ifp);
1142 if (sc->ndis_iftype == PCMCIABus)
1143 ndis_free_amem(sc);
1145 if (sc->ndis_sc)
1146 ndis_destroy_dma(sc);
1148 if (sc->ndis_txarray)
1149 kfree(sc->ndis_txarray, M_DEVBUF);
1151 if (!sc->ndis_80211)
1152 ifmedia_removeall(&sc->ifmedia);
1154 if (sc->ndis_txpool != NULL)
1155 NdisFreePacketPool(sc->ndis_txpool);
1157 /* Destroy the PDO for this device. */
1159 if (sc->ndis_iftype == PCIBus)
1160 drv = windrv_lookup(0, "PCI Bus");
1161 else if (sc->ndis_iftype == PCMCIABus)
1162 drv = windrv_lookup(0, "PCCARD Bus");
1163 else
1164 drv = windrv_lookup(0, "USB Bus");
1165 if (drv == NULL)
1166 panic("couldn't find driver object");
1167 windrv_destroy_pdo(drv, dev);
1169 if (sc->ndis_iftype == PCIBus)
1170 bus_dma_tag_destroy(sc->ndis_parent_tag);
1172 return (0);
1176 ndis_suspend(device_t dev)
1178 #if 0 /* notdef */
1179 struct ndis_softc *sc;
1180 struct ifnet *ifp;
1182 sc = device_get_softc(dev);
1183 ifp = sc->ifp;
1185 if (NDIS_INITIALIZED(sc))
1186 ndis_stop(sc);
1187 #endif
1188 return (0);
1192 ndis_resume(device_t dev)
1194 struct ndis_softc *sc;
1195 struct ifnet *ifp;
1197 sc = device_get_softc(dev);
1198 ifp = sc->ifp;
1200 if (NDIS_INITIALIZED(sc))
1201 ndis_init(sc);
1203 return (0);
1207 * The following bunch of routines are here to support drivers that
1208 * use the NdisMEthIndicateReceive()/MiniportTransferData() mechanism.
1209 * The NdisMEthIndicateReceive() handler runs at DISPATCH_LEVEL for
1210 * serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
1211 * miniports.
1213 static void
1214 ndis_rxeof_eth(ndis_handle adapter, ndis_handle ctx, char *addr, void *hdr,
1215 uint32_t hdrlen, void *lookahead, uint32_t lookaheadlen, uint32_t pktlen)
1217 ndis_miniport_block *block;
1218 uint8_t irql = 0;
1219 uint32_t status;
1220 ndis_buffer *b;
1221 ndis_packet *p;
1222 struct mbuf *m;
1223 ndis_ethpriv *priv;
1225 block = adapter;
1227 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1228 if (m == NULL)
1229 return;
1231 /* Save the data provided to us so far. */
1233 m->m_len = lookaheadlen + hdrlen;
1234 m->m_pkthdr.len = pktlen + hdrlen;
1235 m->m_next = NULL;
1236 m_copyback(m, 0, hdrlen, hdr);
1237 m_copyback(m, hdrlen, lookaheadlen, lookahead);
1239 /* Now create a fake NDIS_PACKET to hold the data */
1241 NdisAllocatePacket(&status, &p, block->nmb_rxpool);
1243 if (status != NDIS_STATUS_SUCCESS) {
1244 m_freem(m);
1245 return;
1248 p->np_m0 = m;
1250 b = IoAllocateMdl(m->m_data, m->m_pkthdr.len, FALSE, FALSE, NULL);
1252 if (b == NULL) {
1253 NdisFreePacket(p);
1254 m_freem(m);
1255 return;
1258 p->np_private.npp_head = p->np_private.npp_tail = b;
1259 p->np_private.npp_totlen = m->m_pkthdr.len;
1261 /* Save the packet RX context somewhere. */
1262 priv = (ndis_ethpriv *)&p->np_protocolreserved;
1263 priv->nep_ctx = ctx;
1265 if (!NDIS_SERIALIZED(block))
1266 KeAcquireSpinLock(&block->nmb_lock, &irql);
1268 InsertTailList((&block->nmb_packetlist), (&p->np_list));
1270 if (!NDIS_SERIALIZED(block))
1271 KeReleaseSpinLock(&block->nmb_lock, irql);
1275 * NdisMEthIndicateReceiveComplete() handler, runs at DISPATCH_LEVEL
1276 * for serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
1277 * miniports.
1279 static void
1280 ndis_rxeof_done(ndis_handle adapter)
1282 struct ndis_softc *sc;
1283 ndis_miniport_block *block;
1285 block = adapter;
1287 /* Schedule transfer/RX of queued packets. */
1289 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1291 KeInsertQueueDpc(&sc->ndis_rxdpc, NULL, NULL);
1295 * MiniportTransferData() handler, runs at DISPATCH_LEVEL.
1297 static void
1298 ndis_rxeof_xfr(kdpc *dpc, ndis_handle adapter, void *sysarg1, void *sysarg2)
1300 ndis_miniport_block *block;
1301 struct ndis_softc *sc;
1302 ndis_packet *p;
1303 list_entry *l;
1304 uint32_t status;
1305 ndis_ethpriv *priv;
1306 struct ifnet *ifp;
1307 struct mbuf *m;
1309 block = adapter;
1310 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1311 ifp = sc->ifp;
1313 KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
1315 l = block->nmb_packetlist.nle_flink;
1316 while(!IsListEmpty(&block->nmb_packetlist)) {
1317 l = RemoveHeadList((&block->nmb_packetlist));
1318 p = CONTAINING_RECORD(l, ndis_packet, np_list);
1319 InitializeListHead((&p->np_list));
1321 priv = (ndis_ethpriv *)&p->np_protocolreserved;
1322 m = p->np_m0;
1323 p->np_softc = sc;
1324 p->np_m0 = NULL;
1326 KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
1328 status = MSCALL6(sc->ndis_chars->nmc_transferdata_func,
1329 p, &p->np_private.npp_totlen, block, priv->nep_ctx,
1330 m->m_len, m->m_pkthdr.len - m->m_len);
1332 KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
1335 * If status is NDIS_STATUS_PENDING, do nothing and
1336 * wait for a callback to the ndis_rxeof_xfr_done()
1337 * handler.
1340 m->m_len = m->m_pkthdr.len;
1341 m->m_pkthdr.rcvif = ifp;
1343 if (status == NDIS_STATUS_SUCCESS) {
1344 IoFreeMdl(p->np_private.npp_head);
1345 NdisFreePacket(p);
1346 KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
1347 mbufq_enqueue(&sc->ndis_rxqueue, m);
1348 KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
1349 IoQueueWorkItem(sc->ndis_inputitem,
1350 (io_workitem_func)ndis_inputtask_wrap,
1351 WORKQUEUE_CRITICAL, sc);
1354 if (status == NDIS_STATUS_FAILURE)
1355 m_freem(m);
1357 /* Advance to next packet */
1358 l = block->nmb_packetlist.nle_flink;
1361 KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
1365 * NdisMTransferDataComplete() handler, runs at DISPATCH_LEVEL.
1367 static void
1368 ndis_rxeof_xfr_done(ndis_handle adapter, ndis_packet *packet, uint32_t status,
1369 uint32_t len)
1371 ndis_miniport_block *block;
1372 struct ndis_softc *sc;
1373 struct ifnet *ifp;
1374 struct mbuf *m;
1376 block = adapter;
1377 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1378 ifp = sc->ifp;
1380 m = packet->np_m0;
1381 IoFreeMdl(packet->np_private.npp_head);
1382 NdisFreePacket(packet);
1384 if (status != NDIS_STATUS_SUCCESS) {
1385 m_freem(m);
1386 return;
1389 m->m_len = m->m_pkthdr.len;
1390 m->m_pkthdr.rcvif = ifp;
1391 KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
1392 mbufq_enqueue(&sc->ndis_rxqueue, m);
1393 KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
1394 IoQueueWorkItem(sc->ndis_inputitem,
1395 (io_workitem_func)ndis_inputtask_wrap,
1396 WORKQUEUE_CRITICAL, sc);
1399 * A frame has been uploaded: pass the resulting mbuf chain up to
1400 * the higher level protocols.
1402 * When handling received NDIS packets, the 'status' field in the
1403 * out-of-band portion of the ndis_packet has special meaning. In the
1404 * most common case, the underlying NDIS driver will set this field
1405 * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
1406 * take possession of it. We then change the status field to
1407 * NDIS_STATUS_PENDING to tell the driver that we now own the packet,
1408 * and that we will return it at some point in the future via the
1409 * return packet handler.
1411 * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
1412 * this means the driver is running out of packet/buffer resources and
1413 * wants to maintain ownership of the packet. In this case, we have to
1414 * copy the packet data into local storage and let the driver keep the
1415 * packet.
1417 static void
1418 ndis_rxeof(ndis_handle adapter, ndis_packet **packets, uint32_t pktcnt)
1420 struct ndis_softc *sc;
1421 ndis_miniport_block *block;
1422 ndis_packet *p;
1423 uint32_t s;
1424 ndis_tcpip_csum *csum;
1425 struct ifnet *ifp;
1426 struct mbuf *m0, *m;
1427 int i;
1429 block = (ndis_miniport_block *)adapter;
1430 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1431 ifp = sc->ifp;
1434 * There's a slim chance the driver may indicate some packets
1435 * before we're completely ready to handle them. If we detect this,
1436 * we need to return them to the miniport and ignore them.
1438 if (!sc->ndis_running) {
1439 for (i = 0; i < pktcnt; i++) {
1440 p = packets[i];
1441 if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) {
1442 p->np_refcnt++;
1443 #if defined(__DragonFly__)
1444 ndis_return_packet(p);
1445 #else
1446 (void)ndis_return_packet(NULL, p, block);
1447 #endif
1450 return;
1453 for (i = 0; i < pktcnt; i++) {
1454 p = packets[i];
1455 /* Stash the softc here so ptom can use it. */
1456 p->np_softc = sc;
1457 if (ndis_ptom(&m0, p)) {
1458 device_printf(sc->ndis_dev, "ptom failed\n");
1459 if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) {
1460 #if defined(__DragonFly__)
1461 ndis_return_packet(p);
1462 #else
1463 (void)ndis_return_packet(NULL, p, block);
1464 #endif
1466 } else {
1467 #ifdef notdef
1468 if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
1469 m = m_dup(m0, M_NOWAIT);
1471 * NOTE: we want to destroy the mbuf here, but
1472 * we don't actually want to return it to the
1473 * driver via the return packet handler. By
1474 * bumping np_refcnt, we can prevent the
1475 * ndis_return_packet() routine from actually
1476 * doing anything.
1478 p->np_refcnt++;
1479 m_freem(m0);
1480 if (m == NULL)
1481 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1482 else
1483 m0 = m;
1484 } else
1485 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1486 #endif
1487 m = m_dup(m0, M_NOWAIT);
1488 if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES)
1489 p->np_refcnt++;
1490 else
1491 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1492 m_freem(m0);
1493 if (m == NULL) {
1494 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1495 continue;
1497 m0 = m;
1498 m0->m_pkthdr.rcvif = ifp;
1500 /* Deal with checksum offload. */
1502 if (ifp->if_capenable & IFCAP_RXCSUM &&
1503 p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) {
1504 s = (uintptr_t)
1505 p->np_ext.npe_info[ndis_tcpipcsum_info];
1506 csum = (ndis_tcpip_csum *)&s;
1507 if (csum->u.ntc_rxflags &
1508 NDIS_RXCSUM_IP_PASSED)
1509 m0->m_pkthdr.csum_flags |=
1510 CSUM_IP_CHECKED|CSUM_IP_VALID;
1511 if (csum->u.ntc_rxflags &
1512 (NDIS_RXCSUM_TCP_PASSED |
1513 NDIS_RXCSUM_UDP_PASSED)) {
1514 m0->m_pkthdr.csum_flags |=
1515 CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
1516 m0->m_pkthdr.csum_data = 0xFFFF;
1520 KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
1521 mbufq_enqueue(&sc->ndis_rxqueue, m0);
1522 KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
1523 IoQueueWorkItem(sc->ndis_inputitem,
1524 (io_workitem_func)ndis_inputtask_wrap,
1525 WORKQUEUE_CRITICAL, sc);
1531 * This routine is run at PASSIVE_LEVEL. We use this routine to pass
1532 * packets into the stack in order to avoid calling (*ifp->if_input)()
1533 * with any locks held (at DISPATCH_LEVEL, we'll be holding the
1534 * 'dispatch level' per-cpu sleep lock).
1536 static void
1537 ndis_inputtask(device_object *dobj, void *arg)
1539 ndis_miniport_block *block;
1540 struct ndis_softc *sc = arg;
1541 struct mbuf *m;
1542 uint8_t irql;
1544 block = dobj->do_devext;
1546 KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
1547 while ((m = mbufq_dequeue(&sc->ndis_rxqueue)) != NULL) {
1548 KeReleaseSpinLock(&sc->ndis_rxlock, irql);
1549 if ((sc->ndis_80211 != 0)) {
1550 struct ieee80211com *ic = &sc->ndis_ic;
1551 struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
1553 if (vap != NULL)
1554 vap->iv_deliver_data(vap, vap->iv_bss, m);
1555 } else {
1556 struct ifnet *ifp = sc->ifp;
1558 #if defined(__DragonFly__)
1559 ifp->if_input(ifp, m, NULL, -1);
1560 #else
1561 (*ifp->if_input)(ifp, m);
1562 #endif
1564 KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
1566 KeReleaseSpinLock(&sc->ndis_rxlock, irql);
1570 * A frame was downloaded to the chip. It's safe for us to clean up
1571 * the list buffers.
1573 static void
1574 ndis_txeof(ndis_handle adapter, ndis_packet *packet, ndis_status status)
1576 struct ndis_softc *sc;
1577 ndis_miniport_block *block;
1578 struct ifnet *ifp;
1579 int idx;
1580 struct mbuf *m;
1582 block = (ndis_miniport_block *)adapter;
1583 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1584 ifp = sc->ifp;
1586 m = packet->np_m0;
1587 idx = packet->np_txidx;
1588 if (sc->ndis_sc)
1589 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
1591 ndis_free_packet(packet);
1592 m_freem(m);
1594 NDIS_LOCK(sc);
1595 sc->ndis_txarray[idx] = NULL;
1596 sc->ndis_txpending++;
1598 if (status == NDIS_STATUS_SUCCESS)
1599 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1600 else
1601 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1603 sc->ndis_tx_timer = 0;
1604 #if defined(__DragonFly__)
1605 ifq_clr_oactive(&sc->ifp->if_snd);
1606 #else
1607 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1608 #endif
1610 NDIS_UNLOCK(sc);
1612 IoQueueWorkItem(sc->ndis_startitem,
1613 (io_workitem_func)ndis_starttask_wrap,
1614 WORKQUEUE_CRITICAL, ifp);
1617 static void
1618 ndis_linksts(ndis_handle adapter, ndis_status status, void *sbuf,
1619 uint32_t slen)
1621 ndis_miniport_block *block;
1622 struct ndis_softc *sc;
1624 block = adapter;
1625 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1626 sc->ndis_sts = status;
1628 /* Event list is all full up, drop this one. */
1630 NDIS_LOCK(sc);
1631 if (sc->ndis_evt[sc->ndis_evtpidx].ne_sts) {
1632 NDIS_UNLOCK(sc);
1633 return;
1636 /* Cache the event. */
1638 if (slen) {
1639 sc->ndis_evt[sc->ndis_evtpidx].ne_buf = kmalloc(slen,
1640 M_TEMP, M_INTWAIT);
1641 if (sc->ndis_evt[sc->ndis_evtpidx].ne_buf == NULL) {
1642 NDIS_UNLOCK(sc);
1643 return;
1645 bcopy((char *)sbuf,
1646 sc->ndis_evt[sc->ndis_evtpidx].ne_buf, slen);
1648 sc->ndis_evt[sc->ndis_evtpidx].ne_sts = status;
1649 sc->ndis_evt[sc->ndis_evtpidx].ne_len = slen;
1650 NDIS_EVTINC(sc->ndis_evtpidx);
1651 NDIS_UNLOCK(sc);
1654 static void
1655 ndis_linksts_done(ndis_handle adapter)
1657 ndis_miniport_block *block;
1658 struct ndis_softc *sc;
1659 struct ifnet *ifp;
1661 block = adapter;
1662 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1663 ifp = sc->ifp;
1665 if (!NDIS_INITIALIZED(sc))
1666 return;
1668 switch (sc->ndis_sts) {
1669 case NDIS_STATUS_MEDIA_CONNECT:
1670 IoQueueWorkItem(sc->ndis_tickitem,
1671 (io_workitem_func)ndis_ticktask_wrap,
1672 WORKQUEUE_CRITICAL, sc);
1673 IoQueueWorkItem(sc->ndis_startitem,
1674 (io_workitem_func)ndis_starttask_wrap,
1675 WORKQUEUE_CRITICAL, ifp);
1676 break;
1677 case NDIS_STATUS_MEDIA_DISCONNECT:
1678 if (sc->ndis_link)
1679 IoQueueWorkItem(sc->ndis_tickitem,
1680 (io_workitem_func)ndis_ticktask_wrap,
1681 WORKQUEUE_CRITICAL, sc);
1682 break;
1683 default:
1684 break;
1688 static void
1689 ndis_tick(void *xsc)
1691 struct ndis_softc *sc;
1693 sc = xsc;
1695 if (sc->ndis_hang_timer && --sc->ndis_hang_timer == 0) {
1696 IoQueueWorkItem(sc->ndis_tickitem,
1697 (io_workitem_func)ndis_ticktask_wrap,
1698 WORKQUEUE_CRITICAL, sc);
1699 sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs;
1702 if (sc->ndis_tx_timer && --sc->ndis_tx_timer == 0) {
1703 if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
1704 device_printf(sc->ndis_dev, "watchdog timeout\n");
1706 IoQueueWorkItem(sc->ndis_resetitem,
1707 (io_workitem_func)ndis_resettask_wrap,
1708 WORKQUEUE_CRITICAL, sc);
1709 IoQueueWorkItem(sc->ndis_startitem,
1710 (io_workitem_func)ndis_starttask_wrap,
1711 WORKQUEUE_CRITICAL, sc->ifp);
1714 callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc);
1717 static void
1718 ndis_ticktask(device_object *d, void *xsc)
1720 struct ndis_softc *sc = xsc;
1721 ndis_checkforhang_handler hangfunc;
1722 uint8_t rval;
1724 NDIS_LOCK(sc);
1725 if (!NDIS_INITIALIZED(sc)) {
1726 NDIS_UNLOCK(sc);
1727 return;
1729 NDIS_UNLOCK(sc);
1731 hangfunc = sc->ndis_chars->nmc_checkhang_func;
1733 if (hangfunc != NULL) {
1734 rval = MSCALL1(hangfunc,
1735 sc->ndis_block->nmb_miniportadapterctx);
1736 if (rval == TRUE) {
1737 ndis_reset_nic(sc);
1738 return;
1742 NDIS_LOCK(sc);
1743 if (sc->ndis_link == 0 &&
1744 sc->ndis_sts == NDIS_STATUS_MEDIA_CONNECT) {
1745 sc->ndis_link = 1;
1746 if (sc->ndis_80211 != 0) {
1747 struct ieee80211com *ic = &sc->ndis_ic;
1748 struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
1750 if (vap != NULL) {
1751 NDIS_UNLOCK(sc);
1752 ndis_getstate_80211(sc);
1753 ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
1754 NDIS_LOCK(sc);
1755 #if defined(__DragonFly__)
1756 vap->iv_ifp->if_link_state = LINK_STATE_UP;
1757 if_link_state_change(vap->iv_ifp);
1758 #else
1759 if_link_state_change(vap->iv_ifp,
1760 LINK_STATE_UP);
1761 #endif
1763 } else {
1764 #if defined(__DragonFly__)
1765 sc->ifp->if_link_state = LINK_STATE_UP;
1766 if_link_state_change(sc->ifp);
1767 #else
1768 if_link_state_change(sc->ifp, LINK_STATE_UP);
1769 #endif
1773 if (sc->ndis_link == 1 &&
1774 sc->ndis_sts == NDIS_STATUS_MEDIA_DISCONNECT) {
1775 sc->ndis_link = 0;
1776 if (sc->ndis_80211 != 0) {
1777 struct ieee80211com *ic = &sc->ndis_ic;
1778 struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
1780 if (vap != NULL) {
1781 NDIS_UNLOCK(sc);
1782 ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
1783 NDIS_LOCK(sc);
1784 #if defined(__DragonFly__)
1785 vap->iv_ifp->if_link_state = LINK_STATE_DOWN;
1786 if_link_state_change(vap->iv_ifp);
1787 #else
1788 if_link_state_change(vap->iv_ifp,
1789 LINK_STATE_DOWN);
1790 #endif
1792 } else {
1793 #if defined(__DragonFly__)
1794 sc->ifp->if_link_state = LINK_STATE_DOWN;
1795 if_link_state_change(sc->ifp);
1796 #else
1797 if_link_state_change(sc->ifp, LINK_STATE_DOWN);
1798 #endif
1802 NDIS_UNLOCK(sc);
1805 static void
1806 ndis_map_sclist(void *arg, bus_dma_segment_t *segs, int nseg,
1807 bus_size_t mapsize, int error)
1809 struct ndis_sc_list *sclist;
1810 int i;
1812 if (error || arg == NULL)
1813 return;
1815 sclist = arg;
1817 sclist->nsl_frags = nseg;
1819 for (i = 0; i < nseg; i++) {
1820 sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr;
1821 sclist->nsl_elements[i].nse_len = segs[i].ds_len;
1825 static int
1826 ndis_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
1827 const struct ieee80211_bpf_params *params)
1829 /* no support; just discard */
1830 m_freem(m);
1831 ieee80211_free_node(ni);
1832 return (0);
1835 static void
1836 ndis_update_mcast(struct ieee80211com *ic)
1838 struct ndis_softc *sc = ic->ic_softc;
1840 ndis_setmulti(sc);
1843 static void
1844 ndis_update_promisc(struct ieee80211com *ic)
1846 /* not supported */
1849 static void
1850 ndis_starttask(device_object *d, void *arg)
1852 struct ifnet *ifp;
1854 ifp = arg;
1856 #if defined(__DragonFly__)
1857 if (!ifq_is_empty(&ifp->if_snd))
1858 if_devstart(ifp);
1859 #else
1860 if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1861 ndis_start(ifp);
1862 #endif
1866 * Main transmit routine. To make NDIS drivers happy, we need to
1867 * transform mbuf chains into NDIS packets and feed them to the
1868 * send packet routines. Most drivers allow you to send several
1869 * packets at once (up to the maxpkts limit). Unfortunately, rather
1870 * that accepting them in the form of a linked list, they expect
1871 * a contiguous array of pointers to packets.
1873 * For those drivers which use the NDIS scatter/gather DMA mechanism,
1874 * we need to perform busdma work here. Those that use map registers
1875 * will do the mapping themselves on a buffer by buffer basis.
1877 static void
1878 ndis_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
1880 struct ndis_softc *sc;
1881 struct mbuf *m = NULL;
1882 ndis_packet **p0 = NULL, *p = NULL;
1883 ndis_tcpip_csum *csum;
1884 int pcnt = 0, status;
1886 sc = ifp->if_softc;
1888 NDIS_LOCK(sc);
1889 #if defined(__DragonFly__)
1890 if (!sc->ndis_link || ifq_is_oactive(&ifp->if_snd)) {
1891 #else
1892 if (!sc->ndis_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1893 #endif
1894 NDIS_UNLOCK(sc);
1895 return;
1898 p0 = &sc->ndis_txarray[sc->ndis_txidx];
1900 while(sc->ndis_txpending) {
1901 #if defined(__DragonFly__)
1902 m = ifq_dequeue(&ifp->if_snd);
1903 #else
1904 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1905 #endif
1906 if (m == NULL)
1907 break;
1909 NdisAllocatePacket(&status,
1910 &sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool);
1912 if (status != NDIS_STATUS_SUCCESS)
1913 break;
1915 if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
1916 #if defined(__DragonFly__)
1917 ifq_prepend(&ifp->if_snd, m);
1918 #else
1919 IFQ_DRV_PREPEND(&ifp->if_snd, m);
1920 #endif
1921 NDIS_UNLOCK(sc);
1922 return;
1926 * Save pointer to original mbuf
1927 * so we can free it later.
1930 p = sc->ndis_txarray[sc->ndis_txidx];
1931 p->np_txidx = sc->ndis_txidx;
1932 p->np_m0 = m;
1933 p->np_oob.npo_status = NDIS_STATUS_PENDING;
1936 * Do scatter/gather processing, if driver requested it.
1938 if (sc->ndis_sc) {
1939 bus_dmamap_load_mbuf(sc->ndis_ttag,
1940 sc->ndis_tmaps[sc->ndis_txidx], m,
1941 ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT);
1942 bus_dmamap_sync(sc->ndis_ttag,
1943 sc->ndis_tmaps[sc->ndis_txidx],
1944 BUS_DMASYNC_PREREAD);
1945 p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist;
1948 /* Handle checksum offload. */
1950 if (ifp->if_capenable & IFCAP_TXCSUM &&
1951 m->m_pkthdr.csum_flags) {
1952 csum = (ndis_tcpip_csum *)
1953 &p->np_ext.npe_info[ndis_tcpipcsum_info];
1954 csum->u.ntc_txflags = NDIS_TXCSUM_DO_IPV4;
1955 if (m->m_pkthdr.csum_flags & CSUM_IP)
1956 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_IP;
1957 if (m->m_pkthdr.csum_flags & CSUM_TCP)
1958 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_TCP;
1959 if (m->m_pkthdr.csum_flags & CSUM_UDP)
1960 csum->u.ntc_txflags |= NDIS_TXCSUM_DO_UDP;
1961 p->np_private.npp_flags = NDIS_PROTOCOL_ID_TCP_IP;
1964 NDIS_INC(sc);
1965 sc->ndis_txpending--;
1967 pcnt++;
1970 * If there's a BPF listener, bounce a copy of this frame
1971 * to him.
1973 if (!sc->ndis_80211) /* XXX handle 80211 */
1974 BPF_MTAP(ifp, m);
1977 * The array that p0 points to must appear contiguous,
1978 * so we must not wrap past the end of sc->ndis_txarray[].
1979 * If it looks like we're about to wrap, break out here
1980 * so the this batch of packets can be transmitted, then
1981 * wait for txeof to ask us to send the rest.
1983 if (sc->ndis_txidx == 0)
1984 break;
1987 if (pcnt == 0) {
1988 NDIS_UNLOCK(sc);
1989 return;
1992 if (sc->ndis_txpending == 0) {
1993 #if defined(__DragonFly__)
1994 ifq_set_oactive(&ifp->if_snd);
1995 #else
1996 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1997 #endif
2001 * Set a timeout in case the chip goes out to lunch.
2003 sc->ndis_tx_timer = 5;
2005 NDIS_UNLOCK(sc);
2008 * According to NDIS documentation, if a driver exports
2009 * a MiniportSendPackets() routine, we prefer that over
2010 * a MiniportSend() routine (which sends just a single
2011 * packet).
2013 if (sc->ndis_chars->nmc_sendmulti_func != NULL)
2014 ndis_send_packets(sc, p0, pcnt);
2015 else
2016 ndis_send_packet(sc, p);
2018 return;
2021 static int
2022 ndis_80211transmit(struct ieee80211com *ic, struct mbuf *m)
2024 struct ndis_softc *sc = ic->ic_softc;
2025 ndis_packet **p0 = NULL, *p = NULL;
2026 int status;
2028 NDIS_LOCK(sc);
2029 if (!sc->ndis_link || !sc->ndis_running) {
2030 NDIS_UNLOCK(sc);
2031 return (ENXIO);
2034 if (sc->ndis_txpending == 0) {
2035 NDIS_UNLOCK(sc);
2036 return (ENOBUFS);
2039 p0 = &sc->ndis_txarray[sc->ndis_txidx];
2041 NdisAllocatePacket(&status,
2042 &sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool);
2044 if (status != NDIS_STATUS_SUCCESS) {
2045 NDIS_UNLOCK(sc);
2046 return (ENOBUFS);
2049 if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
2050 NDIS_UNLOCK(sc);
2051 return (ENOBUFS);
2055 * Save pointer to original mbuf
2056 * so we can free it later.
2059 p = sc->ndis_txarray[sc->ndis_txidx];
2060 p->np_txidx = sc->ndis_txidx;
2061 p->np_m0 = m;
2062 p->np_oob.npo_status = NDIS_STATUS_PENDING;
2065 * Do scatter/gather processing, if driver requested it.
2067 if (sc->ndis_sc) {
2068 bus_dmamap_load_mbuf(sc->ndis_ttag,
2069 sc->ndis_tmaps[sc->ndis_txidx], m,
2070 ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT);
2071 bus_dmamap_sync(sc->ndis_ttag,
2072 sc->ndis_tmaps[sc->ndis_txidx],
2073 BUS_DMASYNC_PREREAD);
2074 p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist;
2077 NDIS_INC(sc);
2078 sc->ndis_txpending--;
2081 * Set a timeout in case the chip goes out to lunch.
2083 sc->ndis_tx_timer = 5;
2084 NDIS_UNLOCK(sc);
2087 * According to NDIS documentation, if a driver exports
2088 * a MiniportSendPackets() routine, we prefer that over
2089 * a MiniportSend() routine (which sends just a single
2090 * packet).
2092 if (sc->ndis_chars->nmc_sendmulti_func != NULL)
2093 ndis_send_packets(sc, p0, 1);
2094 else
2095 ndis_send_packet(sc, p);
2097 return (0);
2100 static void
2101 ndis_80211parent(struct ieee80211com *ic)
2103 struct ndis_softc *sc = ic->ic_softc;
2105 /*NDIS_LOCK(sc);*/
2106 if (ic->ic_nrunning > 0) {
2107 if (!sc->ndis_running)
2108 ndis_init(sc);
2109 } else if (sc->ndis_running)
2110 ndis_stop(sc);
2111 /*NDIS_UNLOCK(sc);*/
2114 static void
2115 ndis_init(void *xsc)
2117 struct ndis_softc *sc = xsc;
2118 int i, len, error;
2121 * Avoid reintializing the link unnecessarily.
2122 * This should be dealt with in a better way by
2123 * fixing the upper layer modules so they don't
2124 * call ifp->if_init() quite as often.
2126 if (sc->ndis_link)
2127 return;
2130 * Cancel pending I/O and free all RX/TX buffers.
2132 ndis_stop(sc);
2134 if (!(sc->ndis_iftype == PNPBus && ndisusb_halt == 0)) {
2135 error = ndis_init_nic(sc);
2136 if (error != 0) {
2137 device_printf(sc->ndis_dev,
2138 "failed to initialize the device: %d\n", error);
2139 return;
2143 /* Program the packet filter */
2144 sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED |
2145 NDIS_PACKET_TYPE_BROADCAST;
2147 if (sc->ndis_80211) {
2148 struct ieee80211com *ic = &sc->ndis_ic;
2150 if (ic->ic_promisc > 0)
2151 sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS;
2152 } else {
2153 struct ifnet *ifp = sc->ifp;
2155 if (ifp->if_flags & IFF_PROMISC)
2156 sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS;
2159 len = sizeof(sc->ndis_filter);
2161 error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
2162 &sc->ndis_filter, &len);
2164 if (error)
2165 device_printf(sc->ndis_dev, "set filter failed: %d\n", error);
2168 * Set lookahead.
2170 if (sc->ndis_80211)
2171 i = ETHERMTU;
2172 else
2173 i = sc->ifp->if_mtu;
2174 len = sizeof(i);
2175 ndis_set_info(sc, OID_GEN_CURRENT_LOOKAHEAD, &i, &len);
2178 * Program the multicast filter, if necessary.
2180 ndis_setmulti(sc);
2182 /* Setup task offload. */
2183 ndis_set_offload(sc);
2185 NDIS_LOCK(sc);
2187 sc->ndis_txidx = 0;
2188 sc->ndis_txpending = sc->ndis_maxpkts;
2189 sc->ndis_link = 0;
2191 if (!sc->ndis_80211) {
2192 #if defined(__DragonFly__)
2193 sc->ifp->if_link_state = LINK_STATE_UNKNOWN;
2194 if_link_state_change(sc->ifp);
2195 sc->ifp->if_flags |= IFF_RUNNING;
2196 ifq_clr_oactive(&sc->ifp->if_snd);
2197 #else
2198 if_link_state_change(sc->ifp, LINK_STATE_UNKNOWN);
2199 sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
2200 sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2201 #endif
2204 sc->ndis_tx_timer = 0;
2207 * Some drivers don't set this value. The NDIS spec says
2208 * the default checkforhang timeout is "approximately 2
2209 * seconds." We use 3 seconds, because it seems for some
2210 * drivers, exactly 2 seconds is too fast.
2212 if (sc->ndis_block->nmb_checkforhangsecs == 0)
2213 sc->ndis_block->nmb_checkforhangsecs = 3;
2215 sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs;
2216 callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc);
2217 sc->ndis_running = 1;
2218 NDIS_UNLOCK(sc);
2220 /* XXX force handling */
2221 if (sc->ndis_80211)
2222 ieee80211_start_all(&sc->ndis_ic); /* start all vap's */
2226 * Set media options.
2228 static int
2229 ndis_ifmedia_upd(struct ifnet *ifp)
2231 struct ndis_softc *sc;
2233 sc = ifp->if_softc;
2235 if (NDIS_INITIALIZED(sc))
2236 ndis_init(sc);
2238 return (0);
2242 * Report current media status.
2244 static void
2245 ndis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
2247 struct ndis_softc *sc;
2248 uint32_t media_info;
2249 ndis_media_state linkstate;
2250 int len;
2252 ifmr->ifm_status = IFM_AVALID;
2253 ifmr->ifm_active = IFM_ETHER;
2254 sc = ifp->if_softc;
2256 if (!NDIS_INITIALIZED(sc))
2257 return;
2259 len = sizeof(linkstate);
2260 ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
2261 (void *)&linkstate, &len);
2263 len = sizeof(media_info);
2264 ndis_get_info(sc, OID_GEN_LINK_SPEED,
2265 (void *)&media_info, &len);
2267 if (linkstate == nmc_connected)
2268 ifmr->ifm_status |= IFM_ACTIVE;
2270 switch (media_info) {
2271 case 100000:
2272 ifmr->ifm_active |= IFM_10_T;
2273 break;
2274 case 1000000:
2275 ifmr->ifm_active |= IFM_100_TX;
2276 break;
2277 case 10000000:
2278 ifmr->ifm_active |= IFM_1000_T;
2279 break;
2280 default:
2281 device_printf(sc->ndis_dev, "unknown speed: %d\n", media_info);
2282 break;
2286 static int
2287 ndis_set_cipher(struct ndis_softc *sc, int cipher)
2289 struct ieee80211com *ic = &sc->ndis_ic;
2290 int rval = 0, len;
2291 uint32_t arg, save;
2293 len = sizeof(arg);
2295 if (cipher == WPA_CSE_WEP40 || cipher == WPA_CSE_WEP104) {
2296 if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_WEP))
2297 return (ENOTSUP);
2298 arg = NDIS_80211_WEPSTAT_ENC1ENABLED;
2301 if (cipher == WPA_CSE_TKIP) {
2302 if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIP))
2303 return (ENOTSUP);
2304 arg = NDIS_80211_WEPSTAT_ENC2ENABLED;
2307 if (cipher == WPA_CSE_CCMP) {
2308 if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_AES_CCM))
2309 return (ENOTSUP);
2310 arg = NDIS_80211_WEPSTAT_ENC3ENABLED;
2313 DPRINTF(("Setting cipher to %d\n", arg));
2314 save = arg;
2315 rval = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
2317 if (rval)
2318 return (rval);
2320 /* Check that the cipher was set correctly. */
2322 len = sizeof(save);
2323 rval = ndis_get_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
2325 if (rval != 0 || arg != save)
2326 return (ENODEV);
2328 return (0);
2332 * WPA is hairy to set up. Do the work in a separate routine
2333 * so we don't clutter the setstate function too much.
2334 * Important yet undocumented fact: first we have to set the
2335 * authentication mode, _then_ we enable the ciphers. If one
2336 * of the WPA authentication modes isn't enabled, the driver
2337 * might not permit the TKIP or AES ciphers to be selected.
2339 static int
2340 ndis_set_wpa(struct ndis_softc *sc, void *ie, int ielen)
2342 struct ieee80211_ie_wpa *w;
2343 struct ndis_ie *n;
2344 char *pos;
2345 uint32_t arg;
2346 int i;
2349 * Apparently, the only way for us to know what ciphers
2350 * and key management/authentication mode to use is for
2351 * us to inspect the optional information element (IE)
2352 * stored in the 802.11 state machine. This IE should be
2353 * supplied by the WPA supplicant.
2356 w = (struct ieee80211_ie_wpa *)ie;
2358 /* Check for the right kind of IE. */
2359 if (w->wpa_id != IEEE80211_ELEMID_VENDOR) {
2360 DPRINTF(("Incorrect IE type %d\n", w->wpa_id));
2361 return (EINVAL);
2364 /* Skip over the ucast cipher OIDs. */
2365 pos = (char *)&w->wpa_uciphers[0];
2366 pos += w->wpa_uciphercnt * sizeof(struct ndis_ie);
2368 /* Skip over the authmode count. */
2369 pos += sizeof(u_int16_t);
2372 * Check for the authentication modes. I'm
2373 * pretty sure there's only supposed to be one.
2376 n = (struct ndis_ie *)pos;
2377 if (n->ni_val == WPA_ASE_NONE)
2378 arg = NDIS_80211_AUTHMODE_WPANONE;
2380 if (n->ni_val == WPA_ASE_8021X_UNSPEC)
2381 arg = NDIS_80211_AUTHMODE_WPA;
2383 if (n->ni_val == WPA_ASE_8021X_PSK)
2384 arg = NDIS_80211_AUTHMODE_WPAPSK;
2386 DPRINTF(("Setting WPA auth mode to %d\n", arg));
2387 i = sizeof(arg);
2388 if (ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i))
2389 return (ENOTSUP);
2390 i = sizeof(arg);
2391 ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i);
2393 /* Now configure the desired ciphers. */
2395 /* First, set up the multicast group cipher. */
2396 n = (struct ndis_ie *)&w->wpa_mcipher[0];
2398 if (ndis_set_cipher(sc, n->ni_val))
2399 return (ENOTSUP);
2401 /* Now start looking around for the unicast ciphers. */
2402 pos = (char *)&w->wpa_uciphers[0];
2403 n = (struct ndis_ie *)pos;
2405 for (i = 0; i < w->wpa_uciphercnt; i++) {
2406 if (ndis_set_cipher(sc, n->ni_val))
2407 return (ENOTSUP);
2408 n++;
2411 return (0);
2414 static void
2415 ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
2417 struct ieee80211vap *vap = ifp->if_softc;
2418 struct ndis_softc *sc = vap->iv_ic->ic_softc;
2419 uint32_t txrate;
2420 int len;
2422 if (!NDIS_INITIALIZED(sc))
2423 return;
2425 len = sizeof(txrate);
2426 if (ndis_get_info(sc, OID_GEN_LINK_SPEED, &txrate, &len) == 0)
2427 vap->iv_bss->ni_txrate = txrate / 5000;
2428 ieee80211_media_status(ifp, imr);
2431 static void
2432 ndis_setstate_80211(struct ndis_softc *sc)
2434 struct ieee80211com *ic = &sc->ndis_ic;
2435 struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2436 ndis_80211_macaddr bssid;
2437 ndis_80211_config config;
2438 int rval = 0, len;
2439 uint32_t arg;
2441 if (!NDIS_INITIALIZED(sc)) {
2442 DPRINTF(("%s: NDIS not initialized\n", __func__));
2443 return;
2446 /* Disassociate and turn off radio. */
2447 len = sizeof(arg);
2448 arg = 1;
2449 ndis_set_info(sc, OID_802_11_DISASSOCIATE, &arg, &len);
2451 /* Set network infrastructure mode. */
2453 len = sizeof(arg);
2454 if (ic->ic_opmode == IEEE80211_M_IBSS)
2455 arg = NDIS_80211_NET_INFRA_IBSS;
2456 else
2457 arg = NDIS_80211_NET_INFRA_BSS;
2459 rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
2461 if (rval)
2462 device_printf (sc->ndis_dev, "set infra failed: %d\n", rval);
2464 /* Set power management */
2465 len = sizeof(arg);
2466 if (vap->iv_flags & IEEE80211_F_PMGTON)
2467 arg = NDIS_80211_POWERMODE_FAST_PSP;
2468 else
2469 arg = NDIS_80211_POWERMODE_CAM;
2470 ndis_set_info(sc, OID_802_11_POWER_MODE, &arg, &len);
2472 /* Set TX power */
2473 if ((ic->ic_caps & IEEE80211_C_TXPMGT) &&
2474 ic->ic_txpowlimit < nitems(dBm2mW)) {
2475 arg = dBm2mW[ic->ic_txpowlimit];
2476 len = sizeof(arg);
2477 ndis_set_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &len);
2481 * Default encryption mode to off, authentication
2482 * to open and privacy to 'accept everything.'
2484 len = sizeof(arg);
2485 arg = NDIS_80211_WEPSTAT_DISABLED;
2486 ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len);
2488 len = sizeof(arg);
2489 arg = NDIS_80211_AUTHMODE_OPEN;
2490 ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
2493 * Note that OID_802_11_PRIVACY_FILTER is optional:
2494 * not all drivers implement it.
2496 len = sizeof(arg);
2497 arg = NDIS_80211_PRIVFILT_8021XWEP;
2498 ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len);
2500 len = sizeof(config);
2501 bzero((char *)&config, len);
2502 config.nc_length = len;
2503 config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
2504 rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len);
2507 * Some drivers expect us to initialize these values, so
2508 * provide some defaults.
2511 if (config.nc_beaconperiod == 0)
2512 config.nc_beaconperiod = 100;
2513 if (config.nc_atimwin == 0)
2514 config.nc_atimwin = 100;
2515 if (config.nc_fhconfig.ncf_dwelltime == 0)
2516 config.nc_fhconfig.ncf_dwelltime = 200;
2517 if (rval == 0 && ic->ic_bsschan != IEEE80211_CHAN_ANYC) {
2518 int chan, chanflag;
2520 chan = ieee80211_chan2ieee(ic, ic->ic_bsschan);
2521 chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
2522 IEEE80211_CHAN_5GHZ;
2523 if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
2524 config.nc_dsconfig =
2525 ic->ic_bsschan->ic_freq * 1000;
2526 len = sizeof(config);
2527 config.nc_length = len;
2528 config.nc_fhconfig.ncf_length =
2529 sizeof(ndis_80211_config_fh);
2530 DPRINTF(("Setting channel to %ukHz\n", config.nc_dsconfig));
2531 rval = ndis_set_info(sc, OID_802_11_CONFIGURATION,
2532 &config, &len);
2533 if (rval)
2534 device_printf(sc->ndis_dev, "couldn't change "
2535 "DS config to %ukHz: %d\n",
2536 config.nc_dsconfig, rval);
2538 } else if (rval)
2539 device_printf(sc->ndis_dev, "couldn't retrieve "
2540 "channel info: %d\n", rval);
2542 /* Set the BSSID to our value so the driver doesn't associate */
2543 len = IEEE80211_ADDR_LEN;
2544 bcopy(vap->iv_myaddr, bssid, len);
2545 #if defined(__DragonFly__)
2546 DPRINTF(("Setting BSSID to %s\n", ether_sprintf(bssid)));
2547 #else
2548 DPRINTF(("Setting BSSID to %6D\n", (uint8_t *)&bssid, ":"));
2549 #endif
2550 rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len);
2551 if (rval)
2552 device_printf(sc->ndis_dev,
2553 "setting BSSID failed: %d\n", rval);
2556 static void
2557 ndis_auth_and_assoc(struct ndis_softc *sc, struct ieee80211vap *vap)
2559 struct ieee80211_node *ni = vap->iv_bss;
2560 ndis_80211_ssid ssid;
2561 ndis_80211_macaddr bssid;
2562 ndis_80211_wep wep;
2563 int i, rval = 0, len, error;
2564 uint32_t arg;
2566 if (!NDIS_INITIALIZED(sc)) {
2567 DPRINTF(("%s: NDIS not initialized\n", __func__));
2568 return;
2571 /* Initial setup */
2572 ndis_setstate_80211(sc);
2574 /* Set network infrastructure mode. */
2576 len = sizeof(arg);
2577 if (vap->iv_opmode == IEEE80211_M_IBSS)
2578 arg = NDIS_80211_NET_INFRA_IBSS;
2579 else
2580 arg = NDIS_80211_NET_INFRA_BSS;
2582 rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
2584 if (rval)
2585 device_printf (sc->ndis_dev, "set infra failed: %d\n", rval);
2587 /* Set RTS threshold */
2589 len = sizeof(arg);
2590 arg = vap->iv_rtsthreshold;
2591 ndis_set_info(sc, OID_802_11_RTS_THRESHOLD, &arg, &len);
2593 /* Set fragmentation threshold */
2595 len = sizeof(arg);
2596 arg = vap->iv_fragthreshold;
2597 ndis_set_info(sc, OID_802_11_FRAGMENTATION_THRESHOLD, &arg, &len);
2599 /* Set WEP */
2601 if (vap->iv_flags & IEEE80211_F_PRIVACY &&
2602 !(vap->iv_flags & IEEE80211_F_WPA)) {
2603 int keys_set = 0;
2605 if (ni->ni_authmode == IEEE80211_AUTH_SHARED) {
2606 len = sizeof(arg);
2607 arg = NDIS_80211_AUTHMODE_SHARED;
2608 DPRINTF(("Setting shared auth\n"));
2609 ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE,
2610 &arg, &len);
2612 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2613 if (vap->iv_nw_keys[i].wk_keylen) {
2614 if (vap->iv_nw_keys[i].wk_cipher->ic_cipher !=
2615 IEEE80211_CIPHER_WEP)
2616 continue;
2617 bzero((char *)&wep, sizeof(wep));
2618 wep.nw_keylen = vap->iv_nw_keys[i].wk_keylen;
2621 * 5, 13 and 16 are the only valid
2622 * key lengths. Anything in between
2623 * will be zero padded out to the
2624 * next highest boundary.
2626 if (vap->iv_nw_keys[i].wk_keylen < 5)
2627 wep.nw_keylen = 5;
2628 else if (vap->iv_nw_keys[i].wk_keylen > 5 &&
2629 vap->iv_nw_keys[i].wk_keylen < 13)
2630 wep.nw_keylen = 13;
2631 else if (vap->iv_nw_keys[i].wk_keylen > 13 &&
2632 vap->iv_nw_keys[i].wk_keylen < 16)
2633 wep.nw_keylen = 16;
2635 wep.nw_keyidx = i;
2636 wep.nw_length = (sizeof(uint32_t) * 3)
2637 + wep.nw_keylen;
2638 if (i == vap->iv_def_txkey)
2639 wep.nw_keyidx |= NDIS_80211_WEPKEY_TX;
2640 bcopy(vap->iv_nw_keys[i].wk_key,
2641 wep.nw_keydata, wep.nw_length);
2642 len = sizeof(wep);
2643 DPRINTF(("Setting WEP key %d\n", i));
2644 rval = ndis_set_info(sc,
2645 OID_802_11_ADD_WEP, &wep, &len);
2646 if (rval)
2647 device_printf(sc->ndis_dev,
2648 "set wepkey failed: %d\n", rval);
2649 keys_set++;
2652 if (keys_set) {
2653 DPRINTF(("Setting WEP on\n"));
2654 arg = NDIS_80211_WEPSTAT_ENABLED;
2655 len = sizeof(arg);
2656 rval = ndis_set_info(sc,
2657 OID_802_11_WEP_STATUS, &arg, &len);
2658 if (rval)
2659 device_printf(sc->ndis_dev,
2660 "enable WEP failed: %d\n", rval);
2661 if (vap->iv_flags & IEEE80211_F_DROPUNENC)
2662 arg = NDIS_80211_PRIVFILT_8021XWEP;
2663 else
2664 arg = NDIS_80211_PRIVFILT_ACCEPTALL;
2666 len = sizeof(arg);
2667 ndis_set_info(sc,
2668 OID_802_11_PRIVACY_FILTER, &arg, &len);
2672 /* Set up WPA. */
2673 if ((vap->iv_flags & IEEE80211_F_WPA) &&
2674 vap->iv_appie_assocreq != NULL) {
2675 struct ieee80211_appie *ie = vap->iv_appie_assocreq;
2676 error = ndis_set_wpa(sc, ie->ie_data, ie->ie_len);
2677 if (error != 0)
2678 device_printf(sc->ndis_dev, "WPA setup failed\n");
2681 #ifdef notyet
2682 /* Set network type. */
2684 arg = 0;
2686 switch (vap->iv_curmode) {
2687 case IEEE80211_MODE_11A:
2688 arg = NDIS_80211_NETTYPE_11OFDM5;
2689 break;
2690 case IEEE80211_MODE_11B:
2691 arg = NDIS_80211_NETTYPE_11DS;
2692 break;
2693 case IEEE80211_MODE_11G:
2694 arg = NDIS_80211_NETTYPE_11OFDM24;
2695 break;
2696 default:
2697 device_printf(sc->ndis_dev, "unknown mode: %d\n",
2698 vap->iv_curmode);
2701 if (arg) {
2702 DPRINTF(("Setting network type to %d\n", arg));
2703 len = sizeof(arg);
2704 rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE,
2705 &arg, &len);
2706 if (rval)
2707 device_printf(sc->ndis_dev,
2708 "set nettype failed: %d\n", rval);
2710 #endif
2713 * If the user selected a specific BSSID, try
2714 * to use that one. This is useful in the case where
2715 * there are several APs in range with the same network
2716 * name. To delete the BSSID, we use the broadcast
2717 * address as the BSSID.
2718 * Note that some drivers seem to allow setting a BSSID
2719 * in ad-hoc mode, which has the effect of forcing the
2720 * NIC to create an ad-hoc cell with a specific BSSID,
2721 * instead of a randomly chosen one. However, the net80211
2722 * code makes the assumtion that the BSSID setting is invalid
2723 * when you're in ad-hoc mode, so we don't allow that here.
2726 len = IEEE80211_ADDR_LEN;
2727 if (vap->iv_flags & IEEE80211_F_DESBSSID &&
2728 vap->iv_opmode != IEEE80211_M_IBSS)
2729 bcopy(ni->ni_bssid, bssid, len);
2730 else
2731 bcopy(ieee80211broadcastaddr, bssid, len);
2733 #if defined(__DragonFly__)
2734 DPRINTF(("Setting BSSID to %s\n", ether_sprintf(bssid)));
2735 #else
2736 DPRINTF(("Setting BSSID to %6D\n", (uint8_t *)&bssid, ":"));
2737 #endif
2738 rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len);
2739 if (rval)
2740 device_printf(sc->ndis_dev,
2741 "setting BSSID failed: %d\n", rval);
2743 /* Set SSID -- always do this last. */
2745 #ifdef NDIS_DEBUG
2746 if (ndis_debug > 0) {
2747 kprintf("Setting ESSID to ");
2748 ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
2749 kprintf("\n");
2751 #endif
2753 len = sizeof(ssid);
2754 bzero((char *)&ssid, len);
2755 ssid.ns_ssidlen = ni->ni_esslen;
2756 if (ssid.ns_ssidlen == 0) {
2757 ssid.ns_ssidlen = 1;
2758 } else
2759 bcopy(ni->ni_essid, ssid.ns_ssid, ssid.ns_ssidlen);
2761 rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
2763 if (rval)
2764 device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval);
2766 return;
2769 static int
2770 ndis_get_bssid_list(struct ndis_softc *sc, ndis_80211_bssid_list_ex **bl)
2772 int len, error;
2774 len = sizeof(uint32_t) + (sizeof(ndis_wlan_bssid_ex) * 16);
2775 *bl = kmalloc(len, M_DEVBUF, M_INTWAIT | M_ZERO);
2776 if (*bl == NULL)
2777 return (ENOMEM);
2779 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, *bl, &len);
2780 if (error == ENOSPC) {
2781 kfree(*bl, M_DEVBUF);
2782 *bl = kmalloc(len, M_DEVBUF, M_INTWAIT | M_ZERO);
2783 if (*bl == NULL)
2784 return (ENOMEM);
2786 error = ndis_get_info(sc, OID_802_11_BSSID_LIST, *bl, &len);
2788 if (error) {
2789 DPRINTF(("%s: failed to read\n", __func__));
2790 kfree(*bl, M_DEVBUF);
2791 return (error);
2794 return (0);
2797 static int
2798 ndis_get_assoc(struct ndis_softc *sc, ndis_wlan_bssid_ex **assoc)
2800 struct ieee80211com *ic = &sc->ndis_ic;
2801 struct ieee80211vap *vap;
2802 struct ieee80211_node *ni;
2803 ndis_80211_bssid_list_ex *bl;
2804 ndis_wlan_bssid_ex *bs;
2805 ndis_80211_macaddr bssid;
2806 int i, len, error;
2808 if (!sc->ndis_link)
2809 return (ENOENT);
2811 len = sizeof(bssid);
2812 error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len);
2813 if (error) {
2814 device_printf(sc->ndis_dev, "failed to get bssid\n");
2815 return (ENOENT);
2818 vap = TAILQ_FIRST(&ic->ic_vaps);
2819 ni = vap->iv_bss;
2821 error = ndis_get_bssid_list(sc, &bl);
2822 if (error)
2823 return (error);
2825 bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0];
2826 for (i = 0; i < bl->nblx_items; i++) {
2827 if (bcmp(bs->nwbx_macaddr, bssid, sizeof(bssid)) == 0) {
2828 *assoc = kmalloc(bs->nwbx_len, M_TEMP, M_INTWAIT);
2829 if (*assoc == NULL) {
2830 kfree(bl, M_TEMP);
2831 return (ENOMEM);
2833 bcopy((char *)bs, (char *)*assoc, bs->nwbx_len);
2834 kfree(bl, M_TEMP);
2835 if (ic->ic_opmode == IEEE80211_M_STA)
2836 ni->ni_associd = 1 | 0xc000; /* fake associd */
2837 return (0);
2839 bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len);
2842 kfree(bl, M_TEMP);
2843 return (ENOENT);
2846 static void
2847 ndis_getstate_80211(struct ndis_softc *sc)
2849 struct ieee80211com *ic = &sc->ndis_ic;
2850 struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2851 struct ieee80211_node *ni = vap->iv_bss;
2852 ndis_wlan_bssid_ex *bs;
2853 int rval, len, i = 0;
2854 int chanflag;
2855 uint32_t arg;
2857 if (!NDIS_INITIALIZED(sc))
2858 return;
2860 if ((rval = ndis_get_assoc(sc, &bs)) != 0)
2861 return;
2863 /* We're associated, retrieve info on the current bssid. */
2864 ic->ic_curmode = ndis_nettype_mode(bs->nwbx_nettype);
2865 chanflag = ndis_nettype_chan(bs->nwbx_nettype);
2866 IEEE80211_ADDR_COPY(ni->ni_bssid, bs->nwbx_macaddr);
2868 /* Get SSID from current association info. */
2869 bcopy(bs->nwbx_ssid.ns_ssid, ni->ni_essid,
2870 bs->nwbx_ssid.ns_ssidlen);
2871 ni->ni_esslen = bs->nwbx_ssid.ns_ssidlen;
2873 if (ic->ic_caps & IEEE80211_C_PMGT) {
2874 len = sizeof(arg);
2875 rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len);
2877 if (rval)
2878 device_printf(sc->ndis_dev,
2879 "get power mode failed: %d\n", rval);
2880 if (arg == NDIS_80211_POWERMODE_CAM)
2881 vap->iv_flags &= ~IEEE80211_F_PMGTON;
2882 else
2883 vap->iv_flags |= IEEE80211_F_PMGTON;
2886 /* Get TX power */
2887 if (ic->ic_caps & IEEE80211_C_TXPMGT) {
2888 len = sizeof(arg);
2889 ndis_get_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &len);
2890 for (i = 0; i < nitems(dBm2mW); i++)
2891 if (dBm2mW[i] >= arg)
2892 break;
2893 ic->ic_txpowlimit = i;
2897 * Use the current association information to reflect
2898 * what channel we're on.
2900 ic->ic_curchan = ieee80211_find_channel(ic,
2901 bs->nwbx_config.nc_dsconfig / 1000, chanflag);
2902 if (ic->ic_curchan == NULL)
2903 ic->ic_curchan = &ic->ic_channels[0];
2904 ni->ni_chan = ic->ic_curchan;
2905 ic->ic_bsschan = ic->ic_curchan;
2907 kfree(bs, M_TEMP);
2910 * Determine current authentication mode.
2912 len = sizeof(arg);
2913 rval = ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
2914 if (rval)
2915 device_printf(sc->ndis_dev,
2916 "get authmode status failed: %d\n", rval);
2917 else {
2918 vap->iv_flags &= ~IEEE80211_F_WPA;
2919 switch (arg) {
2920 case NDIS_80211_AUTHMODE_OPEN:
2921 ni->ni_authmode = IEEE80211_AUTH_OPEN;
2922 break;
2923 case NDIS_80211_AUTHMODE_SHARED:
2924 ni->ni_authmode = IEEE80211_AUTH_SHARED;
2925 break;
2926 case NDIS_80211_AUTHMODE_AUTO:
2927 ni->ni_authmode = IEEE80211_AUTH_AUTO;
2928 break;
2929 case NDIS_80211_AUTHMODE_WPA:
2930 case NDIS_80211_AUTHMODE_WPAPSK:
2931 case NDIS_80211_AUTHMODE_WPANONE:
2932 ni->ni_authmode = IEEE80211_AUTH_WPA;
2933 vap->iv_flags |= IEEE80211_F_WPA1;
2934 break;
2935 case NDIS_80211_AUTHMODE_WPA2:
2936 case NDIS_80211_AUTHMODE_WPA2PSK:
2937 ni->ni_authmode = IEEE80211_AUTH_WPA;
2938 vap->iv_flags |= IEEE80211_F_WPA2;
2939 break;
2940 default:
2941 ni->ni_authmode = IEEE80211_AUTH_NONE;
2942 break;
2946 len = sizeof(arg);
2947 rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
2949 if (rval)
2950 device_printf(sc->ndis_dev,
2951 "get wep status failed: %d\n", rval);
2953 if (arg == NDIS_80211_WEPSTAT_ENABLED)
2954 vap->iv_flags |= IEEE80211_F_PRIVACY|IEEE80211_F_DROPUNENC;
2955 else
2956 vap->iv_flags &= ~(IEEE80211_F_PRIVACY|IEEE80211_F_DROPUNENC);
2959 static int
2960 ndis_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
2962 struct ndis_softc *sc = ifp->if_softc;
2963 struct ifreq *ifr = (struct ifreq *) data;
2964 int i, error = 0;
2966 /*NDIS_LOCK(sc);*/
2968 switch (command) {
2969 case SIOCSIFFLAGS:
2970 if (ifp->if_flags & IFF_UP) {
2971 if (sc->ndis_running &&
2972 ifp->if_flags & IFF_PROMISC &&
2973 !(sc->ndis_if_flags & IFF_PROMISC)) {
2974 sc->ndis_filter |=
2975 NDIS_PACKET_TYPE_PROMISCUOUS;
2976 i = sizeof(sc->ndis_filter);
2977 error = ndis_set_info(sc,
2978 OID_GEN_CURRENT_PACKET_FILTER,
2979 &sc->ndis_filter, &i);
2980 } else if (sc->ndis_running &&
2981 !(ifp->if_flags & IFF_PROMISC) &&
2982 sc->ndis_if_flags & IFF_PROMISC) {
2983 sc->ndis_filter &=
2984 ~NDIS_PACKET_TYPE_PROMISCUOUS;
2985 i = sizeof(sc->ndis_filter);
2986 error = ndis_set_info(sc,
2987 OID_GEN_CURRENT_PACKET_FILTER,
2988 &sc->ndis_filter, &i);
2989 } else
2990 ndis_init(sc);
2991 } else {
2992 if (sc->ndis_running)
2993 ndis_stop(sc);
2995 sc->ndis_if_flags = ifp->if_flags;
2996 error = 0;
2997 break;
2998 case SIOCADDMULTI:
2999 case SIOCDELMULTI:
3000 ndis_setmulti(sc);
3001 error = 0;
3002 break;
3003 case SIOCGIFMEDIA:
3004 case SIOCSIFMEDIA:
3005 error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
3006 break;
3007 case SIOCSIFCAP:
3008 ifp->if_capenable = ifr->ifr_reqcap;
3009 if (ifp->if_capenable & IFCAP_TXCSUM)
3010 ifp->if_hwassist = sc->ndis_hwassist;
3011 else
3012 ifp->if_hwassist = 0;
3013 ndis_set_offload(sc);
3014 break;
3015 default:
3016 error = ether_ioctl(ifp, command, data);
3017 break;
3020 /*NDIS_UNLOCK(sc);*/
3022 return(error);
3025 static int
3026 ndis_80211ioctl(struct ieee80211com *ic, u_long cmd, void *data)
3028 struct ndis_softc *sc = ic->ic_softc;
3029 struct ifreq *ifr = data;
3030 struct ndis_oid_data oid;
3031 struct ndis_evt evt;
3032 void *oidbuf = NULL;
3033 int error = 0;
3035 if ((error = priv_check(curthread, PRIV_DRIVER)) != 0)
3036 return (error);
3038 switch (cmd) {
3039 case SIOCGDRVSPEC:
3040 case SIOCSDRVSPEC:
3041 error = copyin(ifr->ifr_data, &oid, sizeof(oid));
3042 if (error)
3043 break;
3044 oidbuf = kmalloc(oid.len, M_TEMP, M_WAITOK | M_ZERO);
3045 error = copyin((char *)ifr->ifr_data + sizeof(oid), oidbuf, oid.len);
3048 if (error) {
3049 kfree(oidbuf, M_TEMP);
3050 return (error);
3053 switch (cmd) {
3054 case SIOCGDRVSPEC:
3055 error = ndis_get_info(sc, oid.oid, oidbuf, &oid.len);
3056 break;
3057 case SIOCSDRVSPEC:
3058 error = ndis_set_info(sc, oid.oid, oidbuf, &oid.len);
3059 break;
3060 case SIOCGPRIVATE_0:
3061 NDIS_LOCK(sc);
3062 if (sc->ndis_evt[sc->ndis_evtcidx].ne_sts == 0) {
3063 error = ENOENT;
3064 NDIS_UNLOCK(sc);
3065 break;
3067 error = copyin(ifr->ifr_data, &evt, sizeof(evt));
3068 if (error) {
3069 NDIS_UNLOCK(sc);
3070 break;
3072 if (evt.ne_len < sc->ndis_evt[sc->ndis_evtcidx].ne_len) {
3073 error = ENOSPC;
3074 NDIS_UNLOCK(sc);
3075 break;
3077 error = copyout(&sc->ndis_evt[sc->ndis_evtcidx],
3078 ifr->ifr_data, sizeof(uint32_t) * 2);
3079 if (error) {
3080 NDIS_UNLOCK(sc);
3081 break;
3083 if (sc->ndis_evt[sc->ndis_evtcidx].ne_len) {
3084 error = copyout(sc->ndis_evt[sc->ndis_evtcidx].ne_buf,
3085 (caddr_t)ifr->ifr_data + (sizeof(uint32_t) * 2),
3086 sc->ndis_evt[sc->ndis_evtcidx].ne_len);
3087 if (error) {
3088 NDIS_UNLOCK(sc);
3089 break;
3091 kfree(sc->ndis_evt[sc->ndis_evtcidx].ne_buf, M_TEMP);
3092 sc->ndis_evt[sc->ndis_evtcidx].ne_buf = NULL;
3094 sc->ndis_evt[sc->ndis_evtcidx].ne_len = 0;
3095 sc->ndis_evt[sc->ndis_evtcidx].ne_sts = 0;
3096 NDIS_EVTINC(sc->ndis_evtcidx);
3097 NDIS_UNLOCK(sc);
3098 break;
3099 default:
3100 error = ENOTTY;
3101 break;
3104 switch (cmd) {
3105 case SIOCGDRVSPEC:
3106 case SIOCSDRVSPEC:
3107 error = copyout(&oid, ifr->ifr_data, sizeof(oid));
3108 if (error)
3109 break;
3110 error = copyout(oidbuf, (char *)ifr->ifr_data + sizeof(oid), oid.len);
3113 kfree(oidbuf, M_TEMP);
3115 return (error);
3118 static int
3119 ndis_del_key(struct ieee80211vap *vap, const struct ieee80211_key *key)
3121 struct ndis_softc *sc = vap->iv_ic->ic_softc;
3122 ndis_80211_key rkey;
3123 int len, error = 0;
3125 bzero((char *)&rkey, sizeof(rkey));
3126 len = sizeof(rkey);
3128 rkey.nk_len = len;
3129 rkey.nk_keyidx = key->wk_keyix;
3131 bcopy(vap->iv_ifp->if_broadcastaddr,
3132 rkey.nk_bssid, IEEE80211_ADDR_LEN);
3134 error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len);
3136 if (error)
3137 return (0);
3139 return (1);
3143 * In theory this could be called for any key, but we'll
3144 * only use it for WPA TKIP or AES keys. These need to be
3145 * set after initial authentication with the AP.
3147 static int
3148 ndis_add_key(struct ieee80211vap *vap, const struct ieee80211_key *key)
3150 struct ndis_softc *sc = vap->iv_ic->ic_softc;
3151 ndis_80211_key rkey;
3152 int len, error = 0;
3154 switch (key->wk_cipher->ic_cipher) {
3155 case IEEE80211_CIPHER_TKIP:
3157 len = sizeof(ndis_80211_key);
3158 bzero((char *)&rkey, sizeof(rkey));
3160 rkey.nk_len = len;
3161 rkey.nk_keylen = key->wk_keylen;
3163 if (key->wk_flags & IEEE80211_KEY_SWMIC)
3164 rkey.nk_keylen += 16;
3166 /* key index - gets weird in NDIS */
3168 if (key->wk_keyix != IEEE80211_KEYIX_NONE)
3169 rkey.nk_keyidx = key->wk_keyix;
3170 else
3171 rkey.nk_keyidx = 0;
3173 if (key->wk_flags & IEEE80211_KEY_XMIT)
3174 rkey.nk_keyidx |= 1 << 31;
3176 if (key->wk_flags & IEEE80211_KEY_GROUP) {
3177 bcopy(ieee80211broadcastaddr,
3178 rkey.nk_bssid, IEEE80211_ADDR_LEN);
3179 } else {
3180 bcopy(vap->iv_bss->ni_bssid,
3181 rkey.nk_bssid, IEEE80211_ADDR_LEN);
3182 /* pairwise key */
3183 rkey.nk_keyidx |= 1 << 30;
3186 /* need to set bit 29 based on keyrsc */
3187 rkey.nk_keyrsc = key->wk_keyrsc[0]; /* XXX need tid */
3189 if (rkey.nk_keyrsc)
3190 rkey.nk_keyidx |= 1 << 29;
3192 if (key->wk_flags & IEEE80211_KEY_SWMIC) {
3193 bcopy(key->wk_key, rkey.nk_keydata, 16);
3194 bcopy(key->wk_key + 24, rkey.nk_keydata + 16, 8);
3195 bcopy(key->wk_key + 16, rkey.nk_keydata + 24, 8);
3196 } else
3197 bcopy(key->wk_key, rkey.nk_keydata, key->wk_keylen);
3199 error = ndis_set_info(sc, OID_802_11_ADD_KEY, &rkey, &len);
3200 break;
3201 case IEEE80211_CIPHER_WEP:
3202 error = 0;
3203 break;
3205 * I don't know how to set up keys for the AES
3206 * cipher yet. Is it the same as TKIP?
3208 case IEEE80211_CIPHER_AES_CCM:
3209 default:
3210 error = ENOTTY;
3211 break;
3214 /* We need to return 1 for success, 0 for failure. */
3216 if (error)
3217 return (0);
3219 return (1);
3222 static void
3223 ndis_resettask(device_object *d, void *arg)
3225 struct ndis_softc *sc;
3227 sc = arg;
3228 ndis_reset_nic(sc);
3232 * Stop the adapter and free any mbufs allocated to the
3233 * RX and TX lists.
3235 static void
3236 ndis_stop(struct ndis_softc *sc)
3238 int i;
3240 callout_drain(&sc->ndis_stat_callout);
3242 NDIS_LOCK(sc);
3243 sc->ndis_tx_timer = 0;
3244 sc->ndis_link = 0;
3245 if (!sc->ndis_80211) {
3246 #if defined(__DragonFly__)
3247 sc->ifp->if_flags &= ~IFF_RUNNING;
3248 ifq_clr_oactive(&sc->ifp->if_snd);
3249 #else
3250 sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3251 #endif
3253 sc->ndis_running = 0;
3254 NDIS_UNLOCK(sc);
3256 if (sc->ndis_iftype != PNPBus ||
3257 (sc->ndis_iftype == PNPBus &&
3258 !(sc->ndisusb_status & NDISUSB_STATUS_DETACH) &&
3259 ndisusb_halt != 0))
3260 ndis_halt_nic(sc);
3262 NDIS_LOCK(sc);
3263 for (i = 0; i < NDIS_EVENTS; i++) {
3264 if (sc->ndis_evt[i].ne_sts && sc->ndis_evt[i].ne_buf != NULL) {
3265 kfree(sc->ndis_evt[i].ne_buf, M_TEMP);
3266 sc->ndis_evt[i].ne_buf = NULL;
3268 sc->ndis_evt[i].ne_sts = 0;
3269 sc->ndis_evt[i].ne_len = 0;
3271 sc->ndis_evtcidx = 0;
3272 sc->ndis_evtpidx = 0;
3273 NDIS_UNLOCK(sc);
3277 * Stop all chip I/O so that the kernel's probe routines don't
3278 * get confused by errant DMAs when rebooting.
3280 void
3281 ndis_shutdown(device_t dev)
3283 struct ndis_softc *sc;
3285 sc = device_get_softc(dev);
3286 ndis_stop(sc);
3289 static int
3290 ndis_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
3292 struct ndis_vap *nvp = NDIS_VAP(vap);
3293 struct ieee80211com *ic = vap->iv_ic;
3294 struct ndis_softc *sc = ic->ic_softc;
3295 enum ieee80211_state ostate;
3297 DPRINTF(("%s: %s -> %s\n", __func__,
3298 ieee80211_state_name[vap->iv_state],
3299 ieee80211_state_name[nstate]));
3301 ostate = vap->iv_state;
3302 vap->iv_state = nstate;
3304 switch (nstate) {
3305 /* pass on to net80211 */
3306 case IEEE80211_S_INIT:
3307 case IEEE80211_S_SCAN:
3308 return nvp->newstate(vap, nstate, arg);
3309 case IEEE80211_S_ASSOC:
3310 if (ostate != IEEE80211_S_AUTH) {
3311 IEEE80211_UNLOCK(ic);
3312 ndis_auth_and_assoc(sc, vap);
3313 IEEE80211_LOCK(ic);
3315 break;
3316 case IEEE80211_S_AUTH:
3317 IEEE80211_UNLOCK(ic);
3318 ndis_auth_and_assoc(sc, vap);
3319 if (vap->iv_state == IEEE80211_S_AUTH) /* XXX */
3320 ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0);
3321 IEEE80211_LOCK(ic);
3322 break;
3323 default:
3324 break;
3326 return (0);
3329 static void
3330 ndis_scan(void *arg)
3332 struct ieee80211vap *vap = arg;
3334 ieee80211_scan_done(vap);
3337 static void
3338 ndis_scan_results(struct ndis_softc *sc)
3340 struct ieee80211com *ic = &sc->ndis_ic;
3341 struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
3342 ndis_80211_bssid_list_ex *bl;
3343 ndis_wlan_bssid_ex *wb;
3344 struct ieee80211_scanparams sp;
3345 struct ieee80211_frame wh;
3346 struct ieee80211_channel *saved_chan;
3347 int i, j;
3348 int rssi, noise, freq, chanflag;
3349 uint8_t ssid[2+IEEE80211_NWID_LEN];
3350 uint8_t rates[2+IEEE80211_RATE_MAXSIZE];
3351 uint8_t *frm, *efrm;
3353 saved_chan = ic->ic_curchan;
3354 noise = -96;
3356 if (ndis_get_bssid_list(sc, &bl))
3357 return;
3359 DPRINTF(("%s: %d results\n", __func__, bl->nblx_items));
3360 wb = &bl->nblx_bssid[0];
3361 for (i = 0; i < bl->nblx_items; i++) {
3362 memset(&sp, 0, sizeof(sp));
3364 memcpy(wh.i_addr2, wb->nwbx_macaddr, sizeof(wh.i_addr2));
3365 memcpy(wh.i_addr3, wb->nwbx_macaddr, sizeof(wh.i_addr3));
3366 rssi = 100 * (wb->nwbx_rssi - noise) / (-32 - noise);
3367 rssi = max(0, min(rssi, 100)); /* limit 0 <= rssi <= 100 */
3368 if (wb->nwbx_privacy)
3369 sp.capinfo |= IEEE80211_CAPINFO_PRIVACY;
3370 sp.bintval = wb->nwbx_config.nc_beaconperiod;
3371 switch (wb->nwbx_netinfra) {
3372 case NDIS_80211_NET_INFRA_IBSS:
3373 sp.capinfo |= IEEE80211_CAPINFO_IBSS;
3374 break;
3375 case NDIS_80211_NET_INFRA_BSS:
3376 sp.capinfo |= IEEE80211_CAPINFO_ESS;
3377 break;
3379 sp.rates = &rates[0];
3380 for (j = 0; j < IEEE80211_RATE_MAXSIZE; j++) {
3381 /* XXX - check units */
3382 if (wb->nwbx_supportedrates[j] == 0)
3383 break;
3384 rates[2 + j] =
3385 wb->nwbx_supportedrates[j] & 0x7f;
3387 rates[1] = j;
3388 sp.ssid = (uint8_t *)&ssid[0];
3389 memcpy(sp.ssid + 2, &wb->nwbx_ssid.ns_ssid,
3390 wb->nwbx_ssid.ns_ssidlen);
3391 sp.ssid[1] = wb->nwbx_ssid.ns_ssidlen;
3393 chanflag = ndis_nettype_chan(wb->nwbx_nettype);
3394 freq = wb->nwbx_config.nc_dsconfig / 1000;
3395 sp.chan = sp.bchan = ieee80211_mhz2ieee(freq, chanflag);
3396 /* Hack ic->ic_curchan to be in sync with the scan result */
3397 ic->ic_curchan = ieee80211_find_channel(ic, freq, chanflag);
3398 if (ic->ic_curchan == NULL)
3399 ic->ic_curchan = &ic->ic_channels[0];
3401 /* Process extended info from AP */
3402 if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
3403 frm = (uint8_t *)&wb->nwbx_ies;
3404 efrm = frm + wb->nwbx_ielen;
3405 if (efrm - frm < 12)
3406 goto done;
3407 sp.tstamp = frm; frm += 8;
3408 sp.bintval = le16toh(*(uint16_t *)frm); frm += 2;
3409 sp.capinfo = le16toh(*(uint16_t *)frm); frm += 2;
3410 sp.ies = frm;
3411 sp.ies_len = efrm - frm;
3413 done:
3414 DPRINTF(("scan: bssid %s chan %dMHz (%d/%d) rssi %d\n",
3415 ether_sprintf(wb->nwbx_macaddr), freq, sp.bchan, chanflag,
3416 rssi));
3417 ieee80211_add_scan(vap, ic->ic_curchan, &sp, &wh, 0, rssi, noise);
3418 wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
3420 kfree(bl, M_DEVBUF);
3421 /* Restore the channel after messing with it */
3422 ic->ic_curchan = saved_chan;
3425 static void
3426 ndis_scan_start(struct ieee80211com *ic)
3428 struct ndis_softc *sc = ic->ic_softc;
3429 struct ieee80211vap *vap;
3430 struct ieee80211_scan_state *ss;
3431 ndis_80211_ssid ssid;
3432 int error, len;
3434 ss = ic->ic_scan;
3435 vap = TAILQ_FIRST(&ic->ic_vaps);
3437 if (!NDIS_INITIALIZED(sc)) {
3438 DPRINTF(("%s: scan aborted\n", __func__));
3439 ieee80211_cancel_scan(vap);
3440 return;
3443 len = sizeof(ssid);
3444 bzero((char *)&ssid, len);
3445 if (ss->ss_nssid == 0)
3446 ssid.ns_ssidlen = 1;
3447 else {
3448 /* Perform a directed scan */
3449 ssid.ns_ssidlen = ss->ss_ssid[0].len;
3450 bcopy(ss->ss_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen);
3453 error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
3454 if (error)
3455 DPRINTF(("%s: set ESSID failed\n", __func__));
3457 len = 0;
3458 error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, NULL, &len);
3459 if (error) {
3460 DPRINTF(("%s: scan command failed\n", __func__));
3461 ieee80211_cancel_scan(vap);
3462 return;
3464 /* Set a timer to collect the results */
3465 callout_reset(&sc->ndis_scan_callout, hz * 3, ndis_scan, vap);
3468 static void
3469 ndis_set_channel(struct ieee80211com *ic)
3471 /* ignore */
3474 static void
3475 ndis_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
3477 /* ignore */
3480 static void
3481 ndis_scan_mindwell(struct ieee80211_scan_state *ss)
3483 /* NB: don't try to abort scan; wait for firmware to finish */
3486 static void
3487 ndis_scan_end(struct ieee80211com *ic)
3489 struct ndis_softc *sc = ic->ic_softc;
3491 ndis_scan_results(sc);