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