2012-10-27 21:17:22 +04:00
|
|
|
/* $NetBSD: if_ndis.c,v 1.34 2012/10/27 17:18:23 chs Exp $ */
|
2011-05-14 16:44:15 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2003
|
|
|
|
* Bill Paul <wpaul@windriver.com>. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by Bill Paul.
|
|
|
|
* 4. Neither the name of the author nor the names of any co-contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2006-03-31 04:03:57 +04:00
|
|
|
#ifdef __FreeBSD__
|
2006-03-31 02:57:56 +04:00
|
|
|
__FBSDID("$FreeBSD: src/sys/dev/if_ndis/if_ndis.c,v 1.69.2.6 2005/03/31 04:24:36 wpaul Exp $");
|
2006-03-31 04:03:57 +04:00
|
|
|
#endif
|
|
|
|
#ifdef __NetBSD__
|
2012-10-27 21:17:22 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: if_ndis.c,v 1.34 2012/10/27 17:18:23 chs Exp $");
|
2006-03-31 04:03:57 +04:00
|
|
|
#endif
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/queue.h>
|
2006-03-31 04:03:57 +04:00
|
|
|
|
|
|
|
#include <sys/device.h>
|
2006-05-15 01:42:26 +04:00
|
|
|
#include <sys/kauth.h>
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2008-11-12 15:35:50 +03:00
|
|
|
#include <sys/module.h>
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_arp.h>
|
2006-03-31 04:03:57 +04:00
|
|
|
|
|
|
|
#include <net/if_ether.h>
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/if_media.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
|
|
|
|
#include <net/bpf.h>
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2007-10-19 15:59:34 +04:00
|
|
|
#include <sys/bus.h>
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
#include <net80211/ieee80211_var.h>
|
|
|
|
#include <net80211/ieee80211_ioctl.h>
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
#include <dev/ic/wi_ieee.h>
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
#include <dev/pci/pcireg.h>
|
|
|
|
#include <dev/pci/pcivar.h>
|
2006-03-31 04:03:57 +04:00
|
|
|
#include <dev/pci/pcidevs.h>
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
#include <compat/ndis/pe_var.h>
|
|
|
|
#include <compat/ndis/resource_var.h>
|
|
|
|
#include <compat/ndis/ntoskrnl_var.h>
|
|
|
|
#include <compat/ndis/hal_var.h>
|
|
|
|
#include <compat/ndis/ndis_var.h>
|
|
|
|
#include <compat/ndis/cfg_var.h>
|
2006-03-31 04:03:57 +04:00
|
|
|
#include <compat/ndis/nbcompat.h>
|
2006-03-31 02:57:56 +04:00
|
|
|
#include <dev/if_ndis/if_ndisvar.h>
|
|
|
|
|
|
|
|
#define NDIS_IMAGE
|
|
|
|
#define NDIS_REGVALS
|
|
|
|
|
2006-04-18 20:49:19 +04:00
|
|
|
#include "ndis_driver_data.h"
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2009-10-20 23:04:59 +04:00
|
|
|
void ndis_attach(void *);
|
|
|
|
int ndis_detach(device_t, int);
|
|
|
|
int ndis_suspend(device_t);
|
|
|
|
int ndis_resume(device_t);
|
|
|
|
void ndis_shutdown(device_t);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
/* I moved these to if_ndisvar.h */
|
|
|
|
/*
|
2006-03-31 02:57:56 +04:00
|
|
|
static __stdcall void ndis_txeof (ndis_handle,
|
|
|
|
ndis_packet *, ndis_status);
|
|
|
|
static __stdcall void ndis_rxeof (ndis_handle,
|
|
|
|
ndis_packet **, uint32_t);
|
|
|
|
static __stdcall void ndis_linksts (ndis_handle,
|
|
|
|
ndis_status, void *, uint32_t);
|
|
|
|
static __stdcall void ndis_linksts_done (ndis_handle);
|
2006-03-31 04:03:57 +04:00
|
|
|
*/
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/* We need to wrap these functions for amd64. */
|
|
|
|
|
|
|
|
static funcptr ndis_txeof_wrap;
|
|
|
|
static funcptr ndis_rxeof_wrap;
|
|
|
|
static funcptr ndis_linksts_wrap;
|
|
|
|
static funcptr ndis_linksts_done_wrap;
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
int ndis_intr(void *);
|
2006-03-31 02:57:56 +04:00
|
|
|
static void ndis_tick (void *);
|
|
|
|
static void ndis_ticktask (void *);
|
|
|
|
static void ndis_start (struct ifnet *);
|
|
|
|
static void ndis_starttask (void *);
|
2007-03-04 08:59:00 +03:00
|
|
|
static int ndis_ioctl (struct ifnet *, u_long, void *);
|
|
|
|
static int ndis_wi_ioctl_get (struct ifnet *, u_long, void *);
|
|
|
|
static int ndis_wi_ioctl_set (struct ifnet *, u_long, void *);
|
2006-03-31 04:03:57 +04:00
|
|
|
static int ndis_init (struct ifnet *);
|
2006-03-31 02:57:56 +04:00
|
|
|
static void ndis_stop (struct ndis_softc *);
|
|
|
|
static void ndis_watchdog (struct ifnet *);
|
|
|
|
static int ndis_ifmedia_upd (struct ifnet *);
|
|
|
|
static void ndis_ifmedia_sts (struct ifnet *, struct ifmediareq *);
|
|
|
|
static int ndis_get_assoc (struct ndis_softc *, ndis_wlan_bssid_ex **);
|
|
|
|
static int ndis_probe_offload (struct ndis_softc *);
|
|
|
|
static int ndis_set_offload (struct ndis_softc *);
|
|
|
|
static void ndis_getstate_80211 (struct ndis_softc *);
|
|
|
|
static void ndis_setstate_80211 (struct ndis_softc *);
|
|
|
|
static void ndis_media_status (struct ifnet *, struct ifmediareq *);
|
|
|
|
|
|
|
|
static void ndis_setmulti (struct ndis_softc *);
|
|
|
|
static void ndis_map_sclist (void *, bus_dma_segment_t *,
|
|
|
|
int, bus_size_t, int);
|
2009-10-20 23:04:59 +04:00
|
|
|
|
2012-07-28 04:43:22 +04:00
|
|
|
int ndis_in_isr;
|
|
|
|
|
2009-10-20 23:04:59 +04:00
|
|
|
#ifdef _MODULE
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
static int ndisdrv_loaded = 0;
|
2009-10-20 23:04:59 +04:00
|
|
|
int ndisdrv_modevent(module_t, int);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2009-10-20 23:04:59 +04:00
|
|
|
MODULE(MODULE_CLASS_DRIVER, ndisdrv_modevent, NULL);
|
2006-03-31 02:57:56 +04:00
|
|
|
/*
|
|
|
|
* This routine should call windrv_load() once for each driver
|
|
|
|
* image. This will do the relocation and dynalinking for the
|
|
|
|
* image, and create a Windows driver object which will be
|
|
|
|
* saved in our driver database.
|
2006-03-31 04:03:57 +04:00
|
|
|
*/
|
2006-03-31 02:57:56 +04:00
|
|
|
int
|
2009-10-20 23:04:59 +04:00
|
|
|
ndisdrv_modevent(module_t mod, int cmd)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
2006-05-26 23:27:49 +04:00
|
|
|
#ifdef NDIS_DBG
|
2006-03-31 04:03:57 +04:00
|
|
|
printf("in ndisdrv_modevent\n");
|
2006-05-26 23:27:49 +04:00
|
|
|
#endif
|
2006-03-31 02:57:56 +04:00
|
|
|
switch (cmd) {
|
2009-10-20 23:04:59 +04:00
|
|
|
case MODULE_CMD_INIT:
|
2006-03-31 02:57:56 +04:00
|
|
|
ndisdrv_loaded++;
|
|
|
|
if (ndisdrv_loaded > 1)
|
|
|
|
break;
|
2006-03-31 04:03:57 +04:00
|
|
|
error = windrv_load(mod, (vm_offset_t)drv_data, 0);
|
2006-03-31 02:57:56 +04:00
|
|
|
windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap);
|
|
|
|
windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap);
|
|
|
|
windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap);
|
|
|
|
windrv_wrap((funcptr)ndis_linksts_done,
|
|
|
|
&ndis_linksts_done_wrap);
|
|
|
|
break;
|
2009-10-20 23:04:59 +04:00
|
|
|
case MODULE_CMD_FINI:
|
2006-03-31 02:57:56 +04:00
|
|
|
ndisdrv_loaded--;
|
|
|
|
if (ndisdrv_loaded > 0)
|
|
|
|
break;
|
|
|
|
windrv_unload(mod, (vm_offset_t)drv_data, 0);
|
|
|
|
windrv_unwrap(ndis_rxeof_wrap);
|
|
|
|
windrv_unwrap(ndis_txeof_wrap);
|
|
|
|
windrv_unwrap(ndis_linksts_wrap);
|
|
|
|
windrv_unwrap(ndis_linksts_done_wrap);
|
|
|
|
break;
|
2009-10-20 23:04:59 +04:00
|
|
|
case MODULE_CMD_STAT:
|
|
|
|
error = ENOTTY;
|
|
|
|
break;
|
2006-03-31 02:57:56 +04:00
|
|
|
default:
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-10-20 23:04:59 +04:00
|
|
|
return error;
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
int if_ndis_lkmentry(struct lkm_table *lkmtp, int cmd, int ver);
|
|
|
|
|
|
|
|
CFDRIVER_DECL(ndis, DV_DULL, NULL);
|
|
|
|
extern struct cfattach ndis_ca;
|
|
|
|
|
|
|
|
static int pciloc[] = { -1, -1 }; /* device, function */
|
|
|
|
static struct cfparent pciparent = {
|
|
|
|
"pci", "pci", DVUNIT_ANY
|
|
|
|
};
|
|
|
|
static struct cfdata ndis_cfdata[] = {
|
|
|
|
{"ndis", "ndis", 0, FSTATE_STAR, pciloc, 0, &pciparent, 0},
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct cfdriver *ndis_cfdrivers[] = {
|
|
|
|
&ndis_cd,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
static struct cfattach *ndis_cfattachs[] = {
|
|
|
|
&ndis_ca,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
static const struct cfattachlkminit ndis_cfattachinit[] = {
|
|
|
|
{ "ndis", ndis_cfattachs },
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
MOD_DRV("ndis", ndis_cfdrivers, ndis_cfattachinit,
|
|
|
|
ndis_cfdata);
|
|
|
|
|
|
|
|
int
|
|
|
|
if_ndis_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
|
|
|
|
{
|
|
|
|
DISPATCH(lkmtp, cmd, ver, lkm_nofunc, lkm_nofunc, lkm_nofunc);
|
|
|
|
}
|
|
|
|
|
2009-10-20 23:04:59 +04:00
|
|
|
#endif /* _MODULE */
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
/*
|
|
|
|
* Program the 64-bit multicast hash filter.
|
|
|
|
*/
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_setmulti(struct ndis_softc *sc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
2006-03-31 04:03:57 +04:00
|
|
|
struct ether_multi *ifma;
|
2006-03-31 02:57:56 +04:00
|
|
|
int len, mclistsz, error;
|
|
|
|
uint8_t *mclist;
|
|
|
|
|
|
|
|
ifp = &sc->arpcom.ac_if;
|
|
|
|
|
|
|
|
if (!NDIS_INITIALIZED(sc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
|
|
|
|
sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
|
|
|
|
len = sizeof(sc->ndis_filter);
|
|
|
|
error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
|
|
|
|
&sc->ndis_filter, &len);
|
2006-04-24 02:53:43 +04:00
|
|
|
if (error) {
|
2009-08-03 00:22:34 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set filter failed: %d\n",
|
2006-04-24 02:53:43 +04:00
|
|
|
error);
|
2006-03-31 04:03:57 +04:00
|
|
|
}
|
2006-03-31 02:57:56 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
if (LIST_EMPTY(&sc->arpcom.ec_multiaddrs))
|
|
|
|
return;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
len = sizeof(mclistsz);
|
|
|
|
ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len);
|
|
|
|
|
|
|
|
mclist = malloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_NOWAIT|M_ZERO);
|
|
|
|
|
|
|
|
if (mclist == NULL) {
|
|
|
|
sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST;
|
|
|
|
|
|
|
|
len = 0;
|
2006-03-31 04:03:57 +04:00
|
|
|
LIST_FOREACH(ifma, &sc->arpcom.ec_multiaddrs, enm_list) {
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
*****************************************************************************
|
|
|
|
* TODO: The NetBSD ether_multi structure (sys/net/if_ether.h) defines a range
|
|
|
|
* of addresses TODO: (enm_addrlo to enm_addrhi), but FreeBSD's ifmultiaddr
|
|
|
|
* structure (in sys/net/if_var.h) defines only a single address. Do we need
|
|
|
|
* to add every address in the range to the list? Seems like it to me.
|
|
|
|
* But for right now I'm assuming there is only a single address.
|
|
|
|
*****************************************************************************
|
|
|
|
*/
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(mclist + (ETHER_ADDR_LEN * len), ifma->enm_addrlo,
|
2006-03-31 04:03:57 +04:00
|
|
|
ETHER_ADDR_LEN);
|
2006-03-31 02:57:56 +04:00
|
|
|
len++;
|
|
|
|
if (len > mclistsz) {
|
|
|
|
sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
|
|
|
|
sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
len = len * ETHER_ADDR_LEN;
|
|
|
|
error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len);
|
2006-03-31 04:03:57 +04:00
|
|
|
if (error) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set mclist failed: %d\n",
|
|
|
|
error);
|
2006-03-31 02:57:56 +04:00
|
|
|
sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
|
|
|
|
sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
free(mclist, M_TEMP);
|
|
|
|
|
|
|
|
len = sizeof(sc->ndis_filter);
|
|
|
|
error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
|
|
|
|
&sc->ndis_filter, &len);
|
2006-03-31 04:03:57 +04:00
|
|
|
if (error) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set filter failed: %d\n",
|
|
|
|
error);
|
2006-03-31 04:03:57 +04:00
|
|
|
}
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_set_offload(struct ndis_softc *sc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
ndis_task_offload *nto;
|
|
|
|
ndis_task_offload_hdr *ntoh;
|
|
|
|
ndis_task_tcpip_csum *nttc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int len, error;
|
|
|
|
|
|
|
|
ifp = &sc->arpcom.ac_if;
|
|
|
|
|
|
|
|
if (!NDIS_INITIALIZED(sc))
|
|
|
|
return(EINVAL);
|
|
|
|
|
|
|
|
/* See if there's anything to set. */
|
|
|
|
|
|
|
|
error = ndis_probe_offload(sc);
|
|
|
|
if (error)
|
|
|
|
return(error);
|
|
|
|
|
|
|
|
if (sc->ndis_hwassist == 0 && ifp->if_capabilities == 0)
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
len = sizeof(ndis_task_offload_hdr) + sizeof(ndis_task_offload) +
|
|
|
|
sizeof(ndis_task_tcpip_csum);
|
|
|
|
|
|
|
|
ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
|
|
|
|
|
|
|
|
if (ntoh == NULL)
|
|
|
|
return(ENOMEM);
|
|
|
|
|
|
|
|
ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
|
|
|
|
ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
|
|
|
|
ntoh->ntoh_offset_firsttask = sizeof(ndis_task_offload_hdr);
|
|
|
|
ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
|
|
|
|
ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
|
|
|
|
ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
|
|
|
|
|
|
|
|
nto = (ndis_task_offload *)((char *)ntoh +
|
|
|
|
ntoh->ntoh_offset_firsttask);
|
|
|
|
|
|
|
|
nto->nto_vers = NDIS_TASK_OFFLOAD_VERSION;
|
|
|
|
nto->nto_len = sizeof(ndis_task_offload);
|
|
|
|
nto->nto_task = NDIS_TASK_TCPIP_CSUM;
|
|
|
|
nto->nto_offset_nexttask = 0;
|
|
|
|
nto->nto_taskbuflen = sizeof(ndis_task_tcpip_csum);
|
|
|
|
|
|
|
|
nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
|
|
|
|
|
|
|
|
if (ifp->if_capenable & IFCAP_TXCSUM)
|
|
|
|
nttc->nttc_v4tx = sc->ndis_v4tx;
|
|
|
|
|
|
|
|
if (ifp->if_capenable & IFCAP_RXCSUM)
|
|
|
|
nttc->nttc_v4rx = sc->ndis_v4rx;
|
|
|
|
|
|
|
|
error = ndis_set_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
|
|
|
|
free(ntoh, M_TEMP);
|
|
|
|
|
|
|
|
return(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_probe_offload(struct ndis_softc *sc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
ndis_task_offload *nto;
|
|
|
|
ndis_task_offload_hdr *ntoh;
|
|
|
|
ndis_task_tcpip_csum *nttc = NULL;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int len, error, dummy;
|
|
|
|
|
|
|
|
ifp = &sc->arpcom.ac_if;
|
|
|
|
|
|
|
|
len = sizeof(dummy);
|
|
|
|
error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, &dummy, &len);
|
|
|
|
|
|
|
|
if (error != ENOSPC)
|
|
|
|
return(error);
|
|
|
|
|
|
|
|
ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
|
|
|
|
|
|
|
|
if (ntoh == NULL)
|
|
|
|
return(ENOMEM);
|
|
|
|
|
|
|
|
ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
|
|
|
|
ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
|
|
|
|
ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
|
|
|
|
ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
|
|
|
|
ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
|
|
|
|
|
|
|
|
error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
free(ntoh, M_TEMP);
|
|
|
|
return(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ntoh->ntoh_vers != NDIS_TASK_OFFLOAD_VERSION) {
|
|
|
|
free(ntoh, M_TEMP);
|
|
|
|
return(EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
nto = (ndis_task_offload *)((char *)ntoh +
|
|
|
|
ntoh->ntoh_offset_firsttask);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
switch (nto->nto_task) {
|
|
|
|
case NDIS_TASK_TCPIP_CSUM:
|
|
|
|
nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
|
|
|
|
break;
|
|
|
|
/* Don't handle these yet. */
|
|
|
|
case NDIS_TASK_IPSEC:
|
|
|
|
case NDIS_TASK_TCP_LARGESEND:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (nto->nto_offset_nexttask == 0)
|
|
|
|
break;
|
|
|
|
nto = (ndis_task_offload *)((char *)nto +
|
|
|
|
nto->nto_offset_nexttask);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nttc == NULL) {
|
|
|
|
free(ntoh, M_TEMP);
|
|
|
|
return(ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
sc->ndis_v4tx = nttc->nttc_v4tx;
|
|
|
|
sc->ndis_v4rx = nttc->nttc_v4rx;
|
2006-04-23 06:55:04 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_IP_CSUM)
|
|
|
|
sc->ndis_hwassist |= CSUM_IP;
|
|
|
|
if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
|
|
|
|
sc->ndis_hwassist |= CSUM_TCP;
|
|
|
|
if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
|
|
|
|
sc->ndis_hwassist |= CSUM_UDP;
|
|
|
|
if (sc->ndis_hwassist)
|
2006-03-31 04:03:57 +04:00
|
|
|
ifp->if_capabilities |= IFCAP_TXCSUM;
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_IP_CSUM)
|
|
|
|
ifp->if_capabilities |= IFCAP_RXCSUM;
|
|
|
|
if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
|
|
|
|
ifp->if_capabilities |= IFCAP_RXCSUM;
|
|
|
|
if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
|
2006-03-31 04:03:57 +04:00
|
|
|
ifp->if_capabilities |= IFCAP_RXCSUM;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
free(ntoh, M_TEMP);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attach the interface. Allocate softc structures, do ifmedia
|
|
|
|
* setup and ethernet/BPF attach.
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
void
|
|
|
|
ndis_attach(dev)
|
|
|
|
void *dev;
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
u_char eaddr[ETHER_ADDR_LEN];
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
driver_object *drv;
|
|
|
|
driver_object *pdrv;
|
|
|
|
device_object *pdo;
|
|
|
|
struct ifnet *ifp = NULL;
|
|
|
|
void *img;
|
|
|
|
int error = 0, len;
|
2006-03-31 04:03:57 +04:00
|
|
|
int j;
|
|
|
|
|
2006-05-26 23:27:49 +04:00
|
|
|
#ifdef NDIS_DBG
|
2006-03-31 04:03:57 +04:00
|
|
|
printf("In ndis_attach()\n");
|
2006-05-26 23:27:49 +04:00
|
|
|
#endif
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
sc = device_get_softc(dev);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
|
|
|
/* start out at dispatch level */
|
|
|
|
win_irql = DISPATCH_LEVEL;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2011-05-14 16:44:15 +04:00
|
|
|
mutex_init(&sc->ndis_mtx, MUTEX_DEFAULT, IPL_NET);
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
/*
|
|
|
|
* Hook interrupt early, since calling the driver's
|
|
|
|
* init routine may trigger an interrupt. Note that
|
|
|
|
* we don't need to do any explicit interrupt setup
|
|
|
|
* for USB.
|
|
|
|
*/
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* For NetBSD, the interrupt is set up in the bus-dependent
|
|
|
|
* code. For PCI it's done in ndis_attach_pci()
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: remove this #ifdef once if_ndis_pcmcia.c compiles
|
|
|
|
*/
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
sc->ndis_regvals = ndis_regvals;
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
/* Create sysctl registry nodes */
|
|
|
|
ndis_create_sysctls(sc);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
/* Find the PDO for this device instance. */
|
|
|
|
if (sc->ndis_iftype == PCIBus)
|
|
|
|
pdrv = windrv_lookup(0, "PCI Bus");
|
|
|
|
else if (sc->ndis_iftype == PCMCIABus)
|
|
|
|
pdrv = windrv_lookup(0, "PCCARD Bus");
|
|
|
|
else
|
|
|
|
pdrv = windrv_lookup(0, "USB Bus");
|
2012-10-27 21:17:22 +04:00
|
|
|
pdo = windrv_find_pdo(pdrv, device_parent(sc->ndis_dev));
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new functional device object for this
|
|
|
|
* device. This is what creates the miniport block
|
|
|
|
* for this device instance.
|
2006-03-31 04:03:57 +04:00
|
|
|
*/
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
img = drv_data;
|
|
|
|
drv = windrv_lookup((vm_offset_t)img, NULL);
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* Stash a pointer to the softc in the Windows device_object, since
|
2006-03-31 04:03:57 +04:00
|
|
|
* we can't get it from the NetBSD device structure.
|
|
|
|
*/
|
|
|
|
pdo->pdo_sc = sc;
|
|
|
|
pdo->fdo_sc = sc;
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
if (NdisAddDevice(drv, pdo) != STATUS_SUCCESS) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "failed to create FDO!\n");
|
2006-03-31 02:57:56 +04:00
|
|
|
error = ENXIO;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Tell the user what version of the API the driver is using. */
|
2009-08-03 00:22:34 +04:00
|
|
|
aprint_normal_dev(sc->ndis_dev, "NDIS API version: %d.%d\n",
|
2006-04-24 02:53:43 +04:00
|
|
|
sc->ndis_chars->nmc_version_major,
|
|
|
|
sc->ndis_chars->nmc_version_minor);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* For NetBSD so far we do the resource conversion directly in
|
|
|
|
* ndis_attach_pci()
|
|
|
|
*/
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/* Install our RX and TX interrupt handlers. */
|
|
|
|
sc->ndis_block->nmb_senddone_func = ndis_txeof_wrap;
|
|
|
|
sc->ndis_block->nmb_pktind_func = ndis_rxeof_wrap;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
|
|
|
/* Set up the resource list in the block */
|
|
|
|
sc->ndis_block->nmb_rlist = sc->ndis_rl;
|
2006-04-23 06:55:04 +04:00
|
|
|
/* sc->ndis_block->nmb_rlist = &sc->ndis_rl; */
|
2006-03-31 04:03:57 +04:00
|
|
|
|
|
|
|
/* TODO: Free this memory! */
|
|
|
|
sc->arpcom.ec_if.if_sadl =
|
2006-04-23 06:55:04 +04:00
|
|
|
malloc(sizeof(struct sockaddr_dl), M_DEVBUF, M_NOWAIT|M_ZERO);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/* Call driver's init routine. */
|
|
|
|
if (ndis_init_nic(sc)) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "init handler failed\n");
|
2006-03-31 02:57:56 +04:00
|
|
|
error = ENXIO;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get station address from the driver.
|
|
|
|
*/
|
|
|
|
len = sizeof(eaddr);
|
|
|
|
ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out if we're allowed to use multipacket sends
|
|
|
|
* with this driver, and if so, how many.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (sc->ndis_chars->nmc_sendsingle_func &&
|
|
|
|
sc->ndis_chars->nmc_sendmulti_func == NULL) {
|
|
|
|
sc->ndis_maxpkts = 1;
|
|
|
|
} else {
|
|
|
|
len = sizeof(sc->ndis_maxpkts);
|
|
|
|
ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS,
|
|
|
|
&sc->ndis_maxpkts, &len);
|
|
|
|
}
|
|
|
|
|
|
|
|
sc->ndis_txarray = malloc(sizeof(ndis_packet *) *
|
|
|
|
sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT|M_ZERO);
|
|
|
|
|
|
|
|
/* Allocate a pool of ndis_packets for TX encapsulation. */
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
NdisAllocatePacketPool(&j, &sc->ndis_txpool,
|
2006-03-31 02:57:56 +04:00
|
|
|
sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET);
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
if (j != NDIS_STATUS_SUCCESS) {
|
2006-03-31 02:57:56 +04:00
|
|
|
sc->ndis_txpool = NULL;
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "failed to allocate TX packet pool");
|
2006-03-31 02:57:56 +04:00
|
|
|
error = ENOMEM;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
sc->ndis_txpending = sc->ndis_maxpkts;
|
|
|
|
|
|
|
|
sc->ndis_oidcnt = 0;
|
|
|
|
/* Get supported oid list. */
|
|
|
|
ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt);
|
|
|
|
|
|
|
|
/* If the NDIS module requested scatter/gather, init maps. */
|
|
|
|
if (sc->ndis_sc)
|
|
|
|
ndis_init_dma(sc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if the OID_802_11_CONFIGURATION OID is
|
|
|
|
* supported by this driver. If it is, then this an 802.11
|
|
|
|
* wireless driver, and we should set up media for wireless.
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
for (j = 0; j < sc->ndis_oidcnt; j++) {
|
|
|
|
if (sc->ndis_oids[j] == OID_802_11_CONFIGURATION) {
|
2006-03-31 02:57:56 +04:00
|
|
|
sc->ndis_80211++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for task offload support. */
|
|
|
|
ndis_probe_offload(sc);
|
|
|
|
|
|
|
|
ifp = &sc->arpcom.ac_if;
|
|
|
|
ifp->if_softc = sc;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
|
|
|
sc->ic.ic_ifp = ifp;
|
|
|
|
|
2008-04-08 10:12:21 +04:00
|
|
|
strlcpy(ifp->if_xname, device_xname(sc->ndis_dev), IFNAMSIZ);
|
2006-03-31 02:57:56 +04:00
|
|
|
ifp->if_mtu = ETHERMTU;
|
|
|
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
|
|
|
ifp->if_ioctl = ndis_ioctl;
|
|
|
|
ifp->if_start = ndis_start;
|
|
|
|
ifp->if_watchdog = ndis_watchdog;
|
|
|
|
ifp->if_init = ndis_init;
|
|
|
|
ifp->if_baudrate = 10000000;
|
|
|
|
IFQ_SET_MAXLEN(&ifp->if_snd, 50);
|
|
|
|
IFQ_SET_READY(&ifp->if_snd);
|
|
|
|
ifp->if_capenable = ifp->if_capabilities;
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* TODO: I don't think NetBSD has this field describing "HW offload
|
|
|
|
* capabilities" as found in FreeBSD's
|
|
|
|
* if_data structure, but maybe there is something else that
|
|
|
|
* needs to be done here for NetBSD
|
|
|
|
*/
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/* Do media setup */
|
|
|
|
if (sc->ndis_80211) {
|
2006-03-31 04:03:57 +04:00
|
|
|
struct ieee80211com *ic = &sc->ic;
|
2006-03-31 02:57:56 +04:00
|
|
|
ndis_80211_rates_ex rates;
|
|
|
|
struct ndis_80211_nettype_list *ntl;
|
|
|
|
uint32_t arg;
|
|
|
|
int r;
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
ic->ic_phytype = IEEE80211_T_DS;
|
2006-03-31 02:57:56 +04:00
|
|
|
ic->ic_opmode = IEEE80211_M_STA;
|
|
|
|
ic->ic_caps = IEEE80211_C_IBSS;
|
|
|
|
ic->ic_state = IEEE80211_S_ASSOC;
|
|
|
|
ic->ic_modecaps = (1<<IEEE80211_MODE_AUTO);
|
|
|
|
len = 0;
|
|
|
|
r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
|
|
|
|
NULL, &len);
|
|
|
|
if (r != ENOSPC)
|
|
|
|
goto nonettypes;
|
|
|
|
ntl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
|
|
|
|
r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
|
|
|
|
ntl, &len);
|
|
|
|
if (r != 0) {
|
|
|
|
free(ntl, M_DEVBUF);
|
|
|
|
goto nonettypes;
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
for (j = 0; j < ntl->ntl_items; j++) {
|
|
|
|
switch (ntl->ntl_type[j]) {
|
2006-03-31 02:57:56 +04:00
|
|
|
case NDIS_80211_NETTYPE_11FH:
|
|
|
|
case NDIS_80211_NETTYPE_11DS:
|
|
|
|
ic->ic_modecaps |= (1<<IEEE80211_MODE_11B);
|
|
|
|
break;
|
|
|
|
case NDIS_80211_NETTYPE_11OFDM5:
|
|
|
|
ic->ic_modecaps |= (1<<IEEE80211_MODE_11A);
|
|
|
|
break;
|
|
|
|
case NDIS_80211_NETTYPE_11OFDM24:
|
|
|
|
ic->ic_modecaps |= (1<<IEEE80211_MODE_11G);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(ntl, M_DEVBUF);
|
|
|
|
nonettypes:
|
|
|
|
len = sizeof(rates);
|
2009-03-18 19:00:08 +03:00
|
|
|
memset((char *)&rates, 0, len);
|
2006-03-31 02:57:56 +04:00
|
|
|
r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES,
|
|
|
|
(void *)rates, &len);
|
|
|
|
if (r)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "get rates failed: 0x%x\n", r);
|
2006-03-31 02:57:56 +04:00
|
|
|
/*
|
|
|
|
* Since the supported rates only up to 8 can be supported,
|
|
|
|
* if this is not 802.11b we're just going to be faking it
|
|
|
|
* all up to heck.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define TESTSETRATE(x, y) \
|
|
|
|
do { \
|
|
|
|
int i; \
|
|
|
|
for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) { \
|
|
|
|
if (ic->ic_sup_rates[x].rs_rates[i] == (y)) \
|
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
if (i == ic->ic_sup_rates[x].rs_nrates) { \
|
|
|
|
ic->ic_sup_rates[x].rs_rates[i] = (y); \
|
|
|
|
ic->ic_sup_rates[x].rs_nrates++; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define SETRATE(x, y) \
|
|
|
|
ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y)
|
|
|
|
#define INCRATE(x) \
|
|
|
|
ic->ic_sup_rates[x].rs_nrates++
|
|
|
|
|
|
|
|
ic->ic_curmode = IEEE80211_MODE_AUTO;
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A))
|
|
|
|
ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0;
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B))
|
|
|
|
ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0;
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G))
|
|
|
|
ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0;
|
2006-03-31 04:03:57 +04:00
|
|
|
for (j = 0; j < len; j++) {
|
|
|
|
switch (rates[j] & IEEE80211_RATE_VAL) {
|
2006-03-31 02:57:56 +04:00
|
|
|
case 2:
|
|
|
|
case 4:
|
|
|
|
case 11:
|
|
|
|
case 10:
|
|
|
|
case 22:
|
|
|
|
if (!(ic->ic_modecaps &
|
|
|
|
(1<<IEEE80211_MODE_11B))) {
|
|
|
|
/* Lazy-init 802.11b. */
|
|
|
|
ic->ic_modecaps |=
|
|
|
|
(1<<IEEE80211_MODE_11B);
|
|
|
|
ic->ic_sup_rates[IEEE80211_MODE_11B].
|
|
|
|
rs_nrates = 0;
|
|
|
|
}
|
2006-03-31 04:03:57 +04:00
|
|
|
SETRATE(IEEE80211_MODE_11B, rates[j]);
|
2006-03-31 02:57:56 +04:00
|
|
|
INCRATE(IEEE80211_MODE_11B);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
|
2006-03-31 04:03:57 +04:00
|
|
|
SETRATE(IEEE80211_MODE_11A, rates[j]);
|
2006-03-31 02:57:56 +04:00
|
|
|
INCRATE(IEEE80211_MODE_11A);
|
|
|
|
}
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
|
2006-03-31 04:03:57 +04:00
|
|
|
SETRATE(IEEE80211_MODE_11G, rates[j]);
|
2006-03-31 02:57:56 +04:00
|
|
|
INCRATE(IEEE80211_MODE_11G);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the hardware supports 802.11g, it most
|
|
|
|
* likely supports 802.11b and all of the
|
|
|
|
* 802.11b and 802.11g speeds, so maybe we can
|
|
|
|
* just cheat here. Just how in the heck do
|
|
|
|
* we detect turbo modes, though?
|
|
|
|
*/
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11B,
|
|
|
|
IEEE80211_RATE_BASIC|2);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11B,
|
|
|
|
IEEE80211_RATE_BASIC|4);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11B,
|
|
|
|
IEEE80211_RATE_BASIC|11);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11B,
|
|
|
|
IEEE80211_RATE_BASIC|22);
|
|
|
|
}
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11G, 47);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11G, 72);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11G, 96);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11G, 108);
|
|
|
|
}
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11A, 47);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11A, 72);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11A, 96);
|
|
|
|
TESTSETRATE(IEEE80211_MODE_11A, 108);
|
|
|
|
}
|
|
|
|
#undef SETRATE
|
|
|
|
#undef INCRATE
|
|
|
|
/*
|
|
|
|
* Taking yet more guesses here.
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
for (j = 1; j < IEEE80211_CHAN_MAX; j++) {
|
2006-03-31 02:57:56 +04:00
|
|
|
int chanflag = 0;
|
|
|
|
|
|
|
|
if (ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates)
|
|
|
|
chanflag |= IEEE80211_CHAN_G;
|
2006-03-31 04:03:57 +04:00
|
|
|
if (j <= 14)
|
2006-03-31 02:57:56 +04:00
|
|
|
chanflag |= IEEE80211_CHAN_B;
|
|
|
|
if (ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates &&
|
2006-03-31 04:03:57 +04:00
|
|
|
j > 14)
|
2006-03-31 02:57:56 +04:00
|
|
|
chanflag = IEEE80211_CHAN_A;
|
|
|
|
if (chanflag == 0)
|
|
|
|
break;
|
2006-03-31 04:03:57 +04:00
|
|
|
ic->ic_channels[j].ic_freq =
|
|
|
|
ieee80211_ieee2mhz(j, chanflag);
|
|
|
|
ic->ic_channels[j].ic_flags = chanflag;
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
j = sizeof(arg);
|
|
|
|
r = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &j);
|
2006-03-31 02:57:56 +04:00
|
|
|
if (arg != NDIS_80211_WEPSTAT_NOTSUPPORTED)
|
|
|
|
ic->ic_caps |= IEEE80211_C_WEP;
|
2006-03-31 04:03:57 +04:00
|
|
|
j = sizeof(arg);
|
|
|
|
r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &j);
|
2006-03-31 02:57:56 +04:00
|
|
|
if (r == 0)
|
|
|
|
ic->ic_caps |= IEEE80211_C_PMGT;
|
2009-04-02 04:39:37 +04:00
|
|
|
memcpy(&ic->ic_myaddr, eaddr, sizeof(eaddr));
|
2006-03-31 04:03:57 +04:00
|
|
|
if_attach(ifp);
|
|
|
|
ieee80211_ifattach(&sc->ic);
|
|
|
|
ieee80211_media_init(&sc->ic, ieee80211_media_change,
|
|
|
|
ndis_media_status);
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
|
|
|
|
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
|
|
|
|
} else {
|
|
|
|
ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd,
|
|
|
|
ndis_ifmedia_sts);
|
|
|
|
ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
|
|
|
|
ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
|
|
|
|
ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
|
|
|
|
ifmedia_add(&sc->ifmedia,
|
|
|
|
IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
|
|
|
|
ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
|
|
|
|
ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
|
2006-03-31 04:03:57 +04:00
|
|
|
if_attach(ifp);
|
2006-03-31 02:57:56 +04:00
|
|
|
ether_ifattach(ifp, eaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Override the status handler so we can detect link changes. */
|
|
|
|
sc->ndis_block->nmb_status_func = ndis_linksts_wrap;
|
|
|
|
sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap;
|
|
|
|
fail:
|
|
|
|
if (error)
|
2006-03-31 04:03:57 +04:00
|
|
|
ndis_detach(dev, 0);
|
2006-03-31 02:57:56 +04:00
|
|
|
else
|
|
|
|
/* We're done talking to the NIC for now; halt it. */
|
|
|
|
ndis_halt_nic(sc);
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
return;
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Shutdown hardware and free up resources. This can be called any
|
|
|
|
* time after the mutex has been initialized. It is called in both
|
|
|
|
* the error case in attach and the normal detach case so it needs
|
|
|
|
* to be careful about only freeing resources that have actually been
|
|
|
|
* allocated.
|
|
|
|
*/
|
|
|
|
int
|
2006-03-31 04:03:57 +04:00
|
|
|
ndis_detach (dev, flags)
|
|
|
|
device_t dev;
|
|
|
|
int flags;
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
driver_object *drv;
|
2006-03-31 04:03:57 +04:00
|
|
|
int s;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2006-05-26 23:27:49 +04:00
|
|
|
#ifdef NDIS_DBG
|
2006-03-31 04:03:57 +04:00
|
|
|
printf("in ndis_detach\n");
|
2006-05-26 23:27:49 +04:00
|
|
|
#endif
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
sc = device_get_softc(dev);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_LOCK(sc);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
ifp = &sc->arpcom.ac_if;
|
|
|
|
ifp->if_flags &= ~IFF_UP;
|
|
|
|
|
|
|
|
if (device_is_attached(dev)) {
|
2006-03-31 04:03:57 +04:00
|
|
|
NDIS_UNLOCK(sc);
|
2006-03-31 02:57:56 +04:00
|
|
|
ndis_stop(sc);
|
|
|
|
if (sc->ndis_80211)
|
2006-03-31 04:03:57 +04:00
|
|
|
ieee80211_ifdetach(&sc->ic);
|
2006-03-31 02:57:56 +04:00
|
|
|
else
|
|
|
|
ether_ifdetach(ifp);
|
2006-03-31 04:03:57 +04:00
|
|
|
} else {
|
|
|
|
NDIS_UNLOCK(sc);
|
|
|
|
}
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* TODO: unmap interrupts when unloading in NetBSD
|
|
|
|
*/
|
2006-03-31 02:57:56 +04:00
|
|
|
if (sc->ndis_res_io)
|
|
|
|
bus_release_resource(dev, SYS_RES_IOPORT,
|
|
|
|
sc->ndis_io_rid, sc->ndis_res_io);
|
|
|
|
if (sc->ndis_res_mem)
|
|
|
|
bus_release_resource(dev, SYS_RES_MEMORY,
|
|
|
|
sc->ndis_mem_rid, sc->ndis_res_mem);
|
|
|
|
if (sc->ndis_sc)
|
|
|
|
ndis_destroy_dma(sc);
|
|
|
|
|
|
|
|
if (sc->ndis_txarray)
|
|
|
|
free(sc->ndis_txarray, M_DEVBUF);
|
|
|
|
|
|
|
|
|
|
|
|
ndis_unload_driver((void *)ifp);
|
|
|
|
|
|
|
|
if (sc->ndis_txpool != NULL)
|
|
|
|
NdisFreePacketPool(sc->ndis_txpool);
|
|
|
|
|
|
|
|
/* Destroy the PDO for this device. */
|
|
|
|
|
|
|
|
if (sc->ndis_iftype == PCIBus)
|
|
|
|
drv = windrv_lookup(0, "PCI Bus");
|
|
|
|
else if (sc->ndis_iftype == PCMCIABus)
|
|
|
|
drv = windrv_lookup(0, "PCCARD Bus");
|
|
|
|
else
|
|
|
|
drv = windrv_lookup(0, "USB Bus");
|
|
|
|
if (drv == NULL)
|
|
|
|
panic("couldn't find driver object");
|
|
|
|
windrv_destroy_pdo(drv, dev);
|
2011-05-14 16:44:15 +04:00
|
|
|
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* TODO: Unmap dma for NetBSD
|
|
|
|
*/
|
2011-05-14 16:44:15 +04:00
|
|
|
mutex_destroy(&sc->ndis_mtx);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
/* TODO: write a NetBSD version of ndis_suspend() */
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
/* TODO: write a NetBSD version of ndis_resume() */
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* A frame has been uploaded: pass the resulting mbuf chain up to
|
|
|
|
* the higher level protocols.
|
|
|
|
*
|
|
|
|
* When handling received NDIS packets, the 'status' field in the
|
|
|
|
* out-of-band portion of the ndis_packet has special meaning. In the
|
|
|
|
* most common case, the underlying NDIS driver will set this field
|
|
|
|
* to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
|
|
|
|
* take posession of it. We then change the status field to
|
|
|
|
* NDIS_STATUS_PENDING to tell the driver that we now own the packet,
|
|
|
|
* and that we will return it at some point in the future via the
|
|
|
|
* return packet handler.
|
|
|
|
*
|
|
|
|
* If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
|
|
|
|
* this means the driver is running out of packet/buffer resources and
|
|
|
|
* wants to maintain ownership of the packet. In this case, we have to
|
|
|
|
* copy the packet data into local storage and let the driver keep the
|
|
|
|
* packet.
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
__stdcall /*static*/ void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_rxeof(ndis_handle adapter, ndis_packet **packets, uint32_t pktcnt)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
ndis_miniport_block *block;
|
|
|
|
ndis_packet *p;
|
|
|
|
uint32_t s;
|
|
|
|
ndis_tcpip_csum *csum;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct mbuf *m0, *m;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
block = (ndis_miniport_block *)adapter;
|
2006-03-31 04:03:57 +04:00
|
|
|
sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
|
2006-03-31 02:57:56 +04:00
|
|
|
ifp = &sc->arpcom.ac_if;
|
2006-04-23 06:55:04 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
for (i = 0; i < pktcnt; i++) {
|
|
|
|
p = packets[i];
|
|
|
|
/* Stash the softc here so ptom can use it. */
|
|
|
|
p->np_softc = sc;
|
|
|
|
if (ndis_ptom(&m0, p)) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "ptom failed\n");
|
2006-03-31 02:57:56 +04:00
|
|
|
if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
|
2007-03-04 08:59:00 +03:00
|
|
|
ndis_return_packet(NULL, (void *)sc, 0, p);
|
2006-03-31 02:57:56 +04:00
|
|
|
} else {
|
|
|
|
if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
|
2006-03-31 04:03:57 +04:00
|
|
|
m = m_dup(m0, 0, m0->m_pkthdr.len, FALSE);
|
2006-03-31 02:57:56 +04:00
|
|
|
/*
|
|
|
|
* NOTE: we want to destroy the mbuf here, but
|
|
|
|
* we don't actually want to return it to the
|
|
|
|
* driver via the return packet handler. By
|
|
|
|
* bumping np_refcnt, we can prevent the
|
|
|
|
* ndis_return_packet() routine from actually
|
|
|
|
* doing anything.
|
|
|
|
*/
|
|
|
|
p->np_refcnt++;
|
|
|
|
m_freem(m0);
|
|
|
|
if (m == NULL)
|
|
|
|
ifp->if_ierrors++;
|
|
|
|
else
|
|
|
|
m0 = m;
|
|
|
|
} else
|
|
|
|
p->np_oob.npo_status = NDIS_STATUS_PENDING;
|
|
|
|
m0->m_pkthdr.rcvif = ifp;
|
|
|
|
ifp->if_ipackets++;
|
|
|
|
|
|
|
|
/* Deal with checksum offload. */
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* TODO: deal with checksum offload in NetBSD
|
|
|
|
* (see IFCAP_XXX in sys/net/if.h, these differ from the FreeBSD ones)
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
if (ifp->if_capenable & IFCAP_RXCSUM &&
|
|
|
|
p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) {
|
|
|
|
s = (uintptr_t)
|
|
|
|
p->np_ext.npe_info[ndis_tcpipcsum_info];
|
|
|
|
csum = (ndis_tcpip_csum *)&s;
|
|
|
|
if (!(csum->u.ntc_rxflags &
|
|
|
|
NDIS_RXCSUM_IP_PASSED))
|
|
|
|
m0->m_pkthdr.csum_flags |=
|
|
|
|
M_CSUM_IPv4_BAD;
|
|
|
|
if (csum->u.ntc_rxflags &
|
|
|
|
(NDIS_RXCSUM_TCP_PASSED |
|
|
|
|
NDIS_RXCSUM_UDP_PASSED)) {
|
|
|
|
//m0->m_pkthdr.csum_flags |=
|
|
|
|
// CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
|
|
|
|
m0->m_pkthdr.csum_data = 0xFFFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-05 11:19:28 +04:00
|
|
|
bpf_mtap(ifp, m0);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
(*ifp->if_input)(ifp, m0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A frame was downloaded to the chip. It's safe for us to clean up
|
|
|
|
* the list buffers.
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
__stdcall /*static*/ void
|
2006-03-31 02:57:56 +04:00
|
|
|
ndis_txeof(adapter, packet, status)
|
|
|
|
ndis_handle adapter;
|
|
|
|
ndis_packet *packet;
|
|
|
|
ndis_status status;
|
|
|
|
|
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
ndis_miniport_block *block;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int idx;
|
|
|
|
struct mbuf *m;
|
2006-03-31 04:03:57 +04:00
|
|
|
int s;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
block = (ndis_miniport_block *)adapter;
|
2006-03-31 04:03:57 +04:00
|
|
|
sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
|
2006-03-31 02:57:56 +04:00
|
|
|
ifp = &sc->arpcom.ac_if;
|
|
|
|
|
|
|
|
m = packet->np_m0;
|
|
|
|
idx = packet->np_txidx;
|
|
|
|
if (sc->ndis_sc)
|
|
|
|
bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
|
|
|
|
|
|
|
|
ndis_free_packet(packet);
|
|
|
|
m_freem(m);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_LOCK(sc);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
sc->ndis_txarray[idx] = NULL;
|
|
|
|
sc->ndis_txpending++;
|
|
|
|
|
|
|
|
if (status == NDIS_STATUS_SUCCESS)
|
|
|
|
ifp->if_opackets++;
|
|
|
|
else
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
ifp->if_timer = 0;
|
|
|
|
ifp->if_flags &= ~IFF_OACTIVE;
|
2006-03-31 04:03:57 +04:00
|
|
|
NDIS_UNLOCK(sc);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
__stdcall /*static*/ void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_linksts(ndis_handle adapter, ndis_status status, void *sbuf, uint32_t slen)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
ndis_miniport_block *block;
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
|
|
|
|
block = adapter;
|
2006-03-31 04:03:57 +04:00
|
|
|
sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
block->nmb_getstat = status;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
__stdcall /*static*/ void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_linksts_done(ndis_handle adapter)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
ndis_miniport_block *block;
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
|
|
|
|
block = adapter;
|
2006-03-31 04:03:57 +04:00
|
|
|
sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
|
2006-03-31 02:57:56 +04:00
|
|
|
ifp = &sc->arpcom.ac_if;
|
|
|
|
|
|
|
|
if (!NDIS_INITIALIZED(sc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (block->nmb_getstat) {
|
|
|
|
case NDIS_STATUS_MEDIA_CONNECT:
|
|
|
|
ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
|
|
|
|
ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
|
|
|
|
break;
|
|
|
|
case NDIS_STATUS_MEDIA_DISCONNECT:
|
|
|
|
if (sc->ndis_link)
|
|
|
|
ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
int
|
|
|
|
ndis_intr(arg)
|
2006-03-31 02:57:56 +04:00
|
|
|
void *arg;
|
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int is_our_intr = 0;
|
|
|
|
int call_isr = 0;
|
|
|
|
uint8_t irql;
|
|
|
|
ndis_miniport_interrupt *intr;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
sc = arg;
|
|
|
|
ifp = &sc->arpcom.ac_if;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* I was getting an interrupt before NdisAddDevice was called,
|
|
|
|
* which sets up the ndis_block, so...
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
if(sc->ndis_block == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
intr = sc->ndis_block->nmb_interrupt;
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
if (sc->ndis_block->nmb_miniportadapterctx == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
KeAcquireSpinLock(&intr->ni_dpccountlock, &irql);
|
|
|
|
if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
|
|
|
|
ndis_isr(sc, &is_our_intr, &call_isr);
|
|
|
|
else {
|
|
|
|
ndis_disable_intr(sc);
|
|
|
|
call_isr = 1;
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&intr->ni_dpccountlock, irql);
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
if ((is_our_intr || call_isr)) {
|
|
|
|
ndis_in_isr = TRUE;
|
2006-03-31 02:57:56 +04:00
|
|
|
IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
|
2006-03-31 04:03:57 +04:00
|
|
|
ndis_in_isr = FALSE;
|
|
|
|
}
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
return 0;
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* just here so I can wake up the SWI thread
|
2006-03-31 04:03:57 +04:00
|
|
|
* in ndis_ticktask
|
|
|
|
*/
|
|
|
|
struct ndisproc {
|
|
|
|
struct ndisqhead *np_q;
|
|
|
|
struct proc *np_p;
|
|
|
|
int np_state;
|
|
|
|
uint8_t np_stack[PAGE_SIZE*NDIS_KSTACK_PAGES];
|
|
|
|
int np_needs_wakeup;
|
|
|
|
};
|
|
|
|
extern struct ndisproc ndis_iproc;
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_tick(void *xsc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
2006-04-23 06:55:04 +04:00
|
|
|
|
|
|
|
/* TODO: do we need the lock for NetBSD? */
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
sc = xsc;
|
|
|
|
|
|
|
|
ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
|
|
|
callout_reset(&sc->ndis_stat_ch, hz *
|
|
|
|
sc->ndis_block->nmb_checkforhangsecs, ndis_tick, sc);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_ticktask(void *xsc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
__stdcall ndis_checkforhang_handler hangfunc;
|
|
|
|
uint8_t rval;
|
|
|
|
ndis_media_state linkstate;
|
|
|
|
int error, len;
|
2006-03-31 04:03:57 +04:00
|
|
|
int s;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
sc = xsc;
|
|
|
|
|
|
|
|
hangfunc = sc->ndis_chars->nmc_checkhang_func;
|
|
|
|
|
|
|
|
if (hangfunc != NULL) {
|
|
|
|
rval = MSCALL1(hangfunc,
|
|
|
|
sc->ndis_block->nmb_miniportadapterctx);
|
|
|
|
if (rval == TRUE) {
|
|
|
|
ndis_reset_nic(sc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
len = sizeof(linkstate);
|
|
|
|
error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
|
|
|
|
(void *)&linkstate, &len);
|
|
|
|
|
|
|
|
NDIS_LOCK(sc);
|
|
|
|
|
|
|
|
if (sc->ndis_link == 0 && linkstate == nmc_connected) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_normal_dev(sc->ndis_dev, "link up\n");
|
2006-03-31 02:57:56 +04:00
|
|
|
sc->ndis_link = 1;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-09-12 01:17:18 +04:00
|
|
|
NDIS_UNLOCK(sc);
|
2006-03-31 02:57:56 +04:00
|
|
|
if (sc->ndis_80211)
|
|
|
|
ndis_getstate_80211(sc);
|
|
|
|
NDIS_LOCK(sc);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
#ifdef LINK_STATE_UP
|
|
|
|
sc->arpcom.ac_if.if_link_state = LINK_STATE_UP;
|
|
|
|
rt_ifmsg(&(sc->arpcom.ac_if));
|
|
|
|
#endif /* LINK_STATE_UP */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->ndis_link == 1 && linkstate == nmc_disconnected) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_normal_dev(sc->ndis_dev, "link down\n");
|
2006-03-31 02:57:56 +04:00
|
|
|
sc->ndis_link = 0;
|
|
|
|
#ifdef LINK_STATE_DOWN
|
|
|
|
sc->arpcom.ac_if.if_link_state = LINK_STATE_DOWN;
|
|
|
|
rt_ifmsg(&(sc->arpcom.ac_if));
|
|
|
|
#endif /* LINK_STATE_DOWN */
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_UNLOCK(sc);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ndis_map_sclist(arg, segs, nseg, mapsize, error)
|
|
|
|
void *arg;
|
|
|
|
bus_dma_segment_t *segs;
|
|
|
|
int nseg;
|
|
|
|
bus_size_t mapsize;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
{
|
|
|
|
struct ndis_sc_list *sclist;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (error || arg == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sclist = arg;
|
|
|
|
|
|
|
|
sclist->nsl_frags = nseg;
|
|
|
|
|
|
|
|
for (i = 0; i < nseg; i++) {
|
|
|
|
sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr;
|
|
|
|
sclist->nsl_elements[i].nse_len = segs[i].ds_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_starttask(void *arg)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
|
|
|
|
|
|
|
ifp = arg;
|
2009-04-02 04:39:37 +04:00
|
|
|
if (!IFQ_IS_EMPTY(&ifp->if_snd))
|
2006-03-31 02:57:56 +04:00
|
|
|
ndis_start(ifp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Main transmit routine. To make NDIS drivers happy, we need to
|
|
|
|
* transform mbuf chains into NDIS packets and feed them to the
|
|
|
|
* send packet routines. Most drivers allow you to send several
|
|
|
|
* packets at once (up to the maxpkts limit). Unfortunately, rather
|
|
|
|
* that accepting them in the form of a linked list, they expect
|
|
|
|
* a contiguous array of pointers to packets.
|
|
|
|
*
|
|
|
|
* For those drivers which use the NDIS scatter/gather DMA mechanism,
|
|
|
|
* we need to perform busdma work here. Those that use map registers
|
|
|
|
* will do the mapping themselves on a buffer by buffer basis.
|
|
|
|
*/
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_start(struct ifnet *ifp)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
struct mbuf *m = NULL;
|
|
|
|
ndis_packet **p0 = NULL, *p = NULL;
|
2006-03-31 04:03:57 +04:00
|
|
|
ndis_tcpip_csum *csum;
|
2006-03-31 02:57:56 +04:00
|
|
|
int pcnt = 0, status;
|
2006-03-31 04:03:57 +04:00
|
|
|
int s;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
sc = ifp->if_softc;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_LOCK(sc);
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
if (!sc->ndis_link || ifp->if_flags & IFF_OACTIVE) {
|
|
|
|
NDIS_UNLOCK(sc);
|
2006-03-31 02:57:56 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
p0 = &sc->ndis_txarray[sc->ndis_txidx];
|
|
|
|
|
|
|
|
while(sc->ndis_txpending) {
|
2009-04-02 04:39:37 +04:00
|
|
|
IFQ_DEQUEUE(&ifp->if_snd, m);
|
2006-03-31 02:57:56 +04:00
|
|
|
if (m == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
NdisAllocatePacket(&status,
|
|
|
|
&sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool);
|
|
|
|
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
|
|
|
|
#if __FreeBSD_version >= 502114
|
|
|
|
IFQ_DRV_PREPEND(&ifp->if_snd, m);
|
|
|
|
#endif
|
|
|
|
NDIS_UNLOCK(sc);
|
|
|
|
#if __FreeBSD_version < 502114
|
|
|
|
IF_PREPEND(&ifp->if_snd, m);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save pointer to original mbuf
|
|
|
|
* so we can free it later.
|
|
|
|
*/
|
|
|
|
|
|
|
|
p = sc->ndis_txarray[sc->ndis_txidx];
|
|
|
|
p->np_txidx = sc->ndis_txidx;
|
|
|
|
p->np_m0 = m;
|
|
|
|
p->np_oob.npo_status = NDIS_STATUS_PENDING;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do scatter/gather processing, if driver requested it.
|
|
|
|
*/
|
|
|
|
if (sc->ndis_sc) {
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* TODO: NetBSD's bus_dmamap_load_mbuf dosen't provide a callback function
|
|
|
|
* argumet as FreeBSD's does figure out what to do about this.
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
bus_dmamap_load_mbuf(sc->ndis_ttag,
|
|
|
|
sc->ndis_tmaps[sc->ndis_txidx], m,
|
|
|
|
BUS_DMA_WRITE|BUS_DMA_NOWAIT);
|
|
|
|
/* Just call the callback function ? */
|
2006-04-23 06:55:04 +04:00
|
|
|
ndis_map_sclist(&p->np_sclist,
|
|
|
|
sc->ndis_tmaps[sc->ndis_txidx]->dm_segs,
|
|
|
|
sc->ndis_tmaps[sc->ndis_txidx]->dm_nsegs,
|
|
|
|
sc->ndis_tmaps[sc->ndis_txidx]->dm_mapsize, 0);
|
|
|
|
/*
|
|
|
|
* TODO: Need an offset and length to pass to bus_dmamap_sync() (not needed in
|
|
|
|
* FreeBSD), I'm not sure I did this correctly, as man 9 bus_dma says that
|
|
|
|
* dm_segs is "an array of segments or a pointer to an array of segments".
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
bus_dmamap_sync(sc->ndis_ttag,
|
|
|
|
sc->ndis_tmaps[sc->ndis_txidx],
|
|
|
|
sc->ndis_tmaps[sc->ndis_txidx]->dm_segs->ds_addr,
|
|
|
|
sc->ndis_tmaps[sc->ndis_txidx]->dm_segs->ds_len,
|
|
|
|
BUS_DMASYNC_PREREAD);
|
2006-03-31 02:57:56 +04:00
|
|
|
p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle checksum offload. */
|
|
|
|
if (ifp->if_capenable & IFCAP_TXCSUM &&
|
|
|
|
m->m_pkthdr.csum_flags) {
|
|
|
|
csum = (ndis_tcpip_csum *)
|
|
|
|
&p->np_ext.npe_info[ndis_tcpipcsum_info];
|
|
|
|
csum->u.ntc_txflags = NDIS_TXCSUM_DO_IPV4;
|
|
|
|
if (m->m_pkthdr.csum_flags & CSUM_IP)
|
|
|
|
csum->u.ntc_txflags |= NDIS_TXCSUM_DO_IP;
|
|
|
|
if (m->m_pkthdr.csum_flags & CSUM_TCP)
|
|
|
|
csum->u.ntc_txflags |= NDIS_TXCSUM_DO_TCP;
|
|
|
|
if (m->m_pkthdr.csum_flags & CSUM_UDP)
|
|
|
|
csum->u.ntc_txflags |= NDIS_TXCSUM_DO_UDP;
|
|
|
|
p->np_private.npp_flags = NDIS_PROTOCOL_ID_TCP_IP;
|
|
|
|
}
|
2006-04-23 06:55:04 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_INC(sc);
|
|
|
|
sc->ndis_txpending--;
|
|
|
|
|
|
|
|
pcnt++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there's a BPF listener, bounce a copy of this frame
|
|
|
|
* to him.
|
|
|
|
*/
|
2010-04-05 11:19:28 +04:00
|
|
|
bpf_mtap(ifp, m);
|
2006-03-31 02:57:56 +04:00
|
|
|
/*
|
|
|
|
* The array that p0 points to must appear contiguous,
|
|
|
|
* so we must not wrap past the end of sc->ndis_txarray[].
|
|
|
|
* If it looks like we're about to wrap, break out here
|
|
|
|
* so the this batch of packets can be transmitted, then
|
|
|
|
* wait for txeof to ask us to send the rest.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (sc->ndis_txidx == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
if (pcnt == 0) {
|
|
|
|
NDIS_UNLOCK(sc);
|
2006-03-31 02:57:56 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->ndis_txpending == 0)
|
|
|
|
ifp->if_flags |= IFF_OACTIVE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set a timeout in case the chip goes out to lunch.
|
|
|
|
*/
|
|
|
|
ifp->if_timer = 5;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_UNLOCK(sc);
|
|
|
|
|
|
|
|
if (sc->ndis_maxpkts == 1)
|
|
|
|
ndis_send_packet(sc, p);
|
|
|
|
else
|
2006-03-31 04:03:57 +04:00
|
|
|
ndis_send_packets(sc, p0, pcnt);
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
static int
|
|
|
|
ndis_init(xsc)
|
|
|
|
struct ifnet *xsc;
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
2006-03-31 04:03:57 +04:00
|
|
|
struct ndis_softc *sc = xsc->if_softc;
|
|
|
|
struct ifnet *ifp = xsc;
|
|
|
|
int s;
|
2006-03-31 02:57:56 +04:00
|
|
|
int i, error;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
/*
|
|
|
|
* Avoid reintializing the link unnecessarily.
|
|
|
|
* This should be dealt with in a better way by
|
|
|
|
* fixing the upper layer modules so they don't
|
|
|
|
* call ifp->if_init() quite as often.
|
|
|
|
*/
|
|
|
|
if (sc->ndis_link && sc->ndis_skip)
|
2006-04-23 06:55:04 +04:00
|
|
|
return 0;
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
/*
|
|
|
|
* Cancel pending I/O and free all RX/TX buffers.
|
|
|
|
*/
|
2006-04-23 06:55:04 +04:00
|
|
|
ndis_stop(sc);
|
|
|
|
if (ndis_init_nic(sc)) {
|
2006-03-31 04:03:57 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/* Init our MAC address */
|
|
|
|
|
|
|
|
/* Program the packet filter */
|
|
|
|
|
|
|
|
sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED;
|
|
|
|
|
|
|
|
if (ifp->if_flags & IFF_BROADCAST)
|
|
|
|
sc->ndis_filter |= NDIS_PACKET_TYPE_BROADCAST;
|
|
|
|
|
|
|
|
if (ifp->if_flags & IFF_PROMISC)
|
|
|
|
sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS;
|
|
|
|
|
|
|
|
i = sizeof(sc->ndis_filter);
|
|
|
|
|
|
|
|
error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
|
|
|
|
&sc->ndis_filter, &i);
|
|
|
|
|
|
|
|
if (error)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set filter failed: %d\n",
|
2006-04-24 02:53:43 +04:00
|
|
|
error);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Program the multicast filter, if necessary.
|
|
|
|
*/
|
|
|
|
ndis_setmulti(sc);
|
|
|
|
|
|
|
|
/* Setup task offload. */
|
|
|
|
ndis_set_offload(sc);
|
|
|
|
|
|
|
|
/* Enable interrupts. */
|
|
|
|
ndis_enable_intr(sc);
|
|
|
|
|
|
|
|
if (sc->ndis_80211)
|
|
|
|
ndis_setstate_80211(sc);
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
NDIS_LOCK(sc);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
sc->ndis_txidx = 0;
|
|
|
|
sc->ndis_txpending = sc->ndis_maxpkts;
|
|
|
|
sc->ndis_link = 0;
|
|
|
|
|
|
|
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
|
ifp->if_flags &= ~IFF_OACTIVE;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_UNLOCK(sc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some drivers don't set this value. The NDIS spec says
|
|
|
|
* the default checkforhang timeout is "approximately 2
|
|
|
|
* seconds." We use 3 seconds, because it seems for some
|
|
|
|
* drivers, exactly 2 seconds is too fast.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (sc->ndis_block->nmb_checkforhangsecs == 0)
|
|
|
|
sc->ndis_block->nmb_checkforhangsecs = 3;
|
|
|
|
|
2006-04-23 06:55:04 +04:00
|
|
|
callout_reset(&sc->ndis_stat_ch,
|
|
|
|
hz * sc->ndis_block->nmb_checkforhangsecs,
|
|
|
|
ndis_tick, sc);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2006-04-23 06:55:04 +04:00
|
|
|
return 0;
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set media options.
|
|
|
|
*/
|
|
|
|
static int
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_ifmedia_upd(struct ifnet *ifp)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
|
|
|
|
sc = ifp->if_softc;
|
|
|
|
|
|
|
|
if (NDIS_INITIALIZED(sc))
|
2006-03-31 04:03:57 +04:00
|
|
|
ndis_init(&sc->arpcom.ac_if);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Report current media status.
|
|
|
|
*/
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
uint32_t media_info;
|
|
|
|
ndis_media_state linkstate;
|
|
|
|
int error, len;
|
|
|
|
|
|
|
|
ifmr->ifm_status = IFM_AVALID;
|
|
|
|
ifmr->ifm_active = IFM_ETHER;
|
|
|
|
sc = ifp->if_softc;
|
|
|
|
|
|
|
|
if (!NDIS_INITIALIZED(sc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
len = sizeof(linkstate);
|
|
|
|
error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
|
|
|
|
(void *)&linkstate, &len);
|
|
|
|
|
|
|
|
len = sizeof(media_info);
|
|
|
|
error = ndis_get_info(sc, OID_GEN_LINK_SPEED,
|
|
|
|
(void *)&media_info, &len);
|
|
|
|
|
|
|
|
if (linkstate == nmc_connected)
|
|
|
|
ifmr->ifm_status |= IFM_ACTIVE;
|
|
|
|
|
|
|
|
switch(media_info) {
|
|
|
|
case 100000:
|
|
|
|
ifmr->ifm_active |= IFM_10_T;
|
|
|
|
break;
|
|
|
|
case 1000000:
|
|
|
|
ifmr->ifm_active |= IFM_100_TX;
|
|
|
|
break;
|
|
|
|
case 10000000:
|
|
|
|
ifmr->ifm_active |= IFM_1000_T;
|
|
|
|
break;
|
|
|
|
default:
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "unknown speed: %d\n",
|
2006-04-24 02:53:43 +04:00
|
|
|
media_info);
|
2006-03-31 02:57:56 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
/* TODO: Perhaps raise the IPL while in these wireless functions ? */
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_setstate_80211(struct ndis_softc *sc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ieee80211com *ic;
|
|
|
|
ndis_80211_ssid ssid;
|
|
|
|
ndis_80211_config config;
|
|
|
|
ndis_80211_wep wep;
|
|
|
|
int i, rval = 0, len;
|
|
|
|
uint32_t arg;
|
|
|
|
struct ifnet *ifp;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
|
|
|
#define wk_len wk_keylen
|
|
|
|
#define ic_wep_txkey ic_def_txkey
|
2006-03-31 02:57:56 +04:00
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
ic = &sc->ic;
|
2006-04-23 06:55:04 +04:00
|
|
|
|
2006-03-31 04:03:57 +04:00
|
|
|
/* TODO: are these equivelant? */
|
|
|
|
ifp = sc->ic.ic_ifp;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
if (!NDIS_INITIALIZED(sc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Set network infrastructure mode. */
|
|
|
|
|
|
|
|
len = sizeof(arg);
|
|
|
|
if (ic->ic_opmode == IEEE80211_M_IBSS)
|
|
|
|
arg = NDIS_80211_NET_INFRA_IBSS;
|
|
|
|
else
|
|
|
|
arg = NDIS_80211_NET_INFRA_BSS;
|
|
|
|
|
|
|
|
rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
|
|
|
|
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set infra failed: %d\n", rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/* Set WEP */
|
2006-03-31 04:03:57 +04:00
|
|
|
/* TODO: Clean up these #ifdef's */
|
|
|
|
if (ic->ic_flags & IEEE80211_F_PRIVACY) {
|
|
|
|
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
|
2006-03-31 02:57:56 +04:00
|
|
|
if (ic->ic_nw_keys[i].wk_len) {
|
2009-03-18 19:00:08 +03:00
|
|
|
memset((char *)&wep, 0, sizeof(wep));
|
2006-03-31 02:57:56 +04:00
|
|
|
wep.nw_keylen = ic->ic_nw_keys[i].wk_len;
|
|
|
|
#ifdef notdef
|
|
|
|
/* 5 and 13 are the only valid key lengths */
|
|
|
|
if (ic->ic_nw_keys[i].wk_len < 5)
|
|
|
|
wep.nw_keylen = 5;
|
|
|
|
else if (ic->ic_nw_keys[i].wk_len > 5 &&
|
|
|
|
ic->ic_nw_keys[i].wk_len < 13)
|
|
|
|
wep.nw_keylen = 13;
|
|
|
|
#endif
|
|
|
|
wep.nw_keyidx = i;
|
|
|
|
wep.nw_length = (sizeof(uint32_t) * 3)
|
|
|
|
+ wep.nw_keylen;
|
|
|
|
if (i == ic->ic_wep_txkey)
|
|
|
|
wep.nw_keyidx |= NDIS_80211_WEPKEY_TX;
|
|
|
|
bcopy(ic->ic_nw_keys[i].wk_key,
|
|
|
|
wep.nw_keydata, wep.nw_length);
|
|
|
|
len = sizeof(wep);
|
|
|
|
rval = ndis_set_info(sc,
|
|
|
|
OID_802_11_ADD_WEP, &wep, &len);
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set wepkey failed: %d\n", rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
arg = NDIS_80211_WEPSTAT_ENABLED;
|
|
|
|
len = sizeof(arg);
|
|
|
|
rval = ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "enable WEP failed: %d\n",
|
2006-04-24 02:53:43 +04:00
|
|
|
rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
arg = NDIS_80211_PRIVFILT_8021XWEP;
|
|
|
|
len = sizeof(arg);
|
|
|
|
rval = ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len);
|
|
|
|
#ifdef IEEE80211_WEP_8021X /*IEEE80211_F_WEPON*/
|
|
|
|
/* Accept that we only have "shared" and 802.1x modes. */
|
|
|
|
if (rval == 0) {
|
|
|
|
if (arg == NDIS_80211_PRIVFILT_ACCEPTALL)
|
|
|
|
ic->ic_wep_mode = IEEE80211_WEP_MIXED;
|
|
|
|
else
|
|
|
|
ic->ic_wep_mode = IEEE80211_WEP_8021X;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
arg = NDIS_80211_AUTHMODE_OPEN;
|
|
|
|
} else {
|
|
|
|
arg = NDIS_80211_WEPSTAT_DISABLED;
|
|
|
|
len = sizeof(arg);
|
|
|
|
ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
|
|
|
|
arg = NDIS_80211_AUTHMODE_OPEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = sizeof(arg);
|
|
|
|
rval = ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set auth failed: %d\n", rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
/* Set network type. */
|
|
|
|
|
|
|
|
arg = 0;
|
|
|
|
|
|
|
|
switch (ic->ic_curmode) {
|
|
|
|
case IEEE80211_MODE_11A:
|
|
|
|
arg = NDIS_80211_NETTYPE_11OFDM5;
|
|
|
|
break;
|
|
|
|
case IEEE80211_MODE_11B:
|
|
|
|
arg = NDIS_80211_NETTYPE_11DS;
|
|
|
|
break;
|
|
|
|
case IEEE80211_MODE_11G:
|
|
|
|
arg = NDIS_80211_NETTYPE_11OFDM24;
|
|
|
|
break;
|
|
|
|
default:
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "unknown mode: %d\n",
|
|
|
|
ic->ic_curmode);
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (arg) {
|
|
|
|
len = sizeof(arg);
|
|
|
|
rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE,
|
|
|
|
&arg, &len);
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set nettype failed: %d\n",
|
|
|
|
rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
len = sizeof(config);
|
2009-03-18 19:00:08 +03:00
|
|
|
memset((char *)&config, 0, len);
|
2006-03-31 02:57:56 +04:00
|
|
|
config.nc_length = len;
|
|
|
|
config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
|
|
|
|
rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some drivers expect us to initialize these values, so
|
|
|
|
* provide some defaults.
|
|
|
|
*/
|
|
|
|
if (config.nc_beaconperiod == 0)
|
|
|
|
config.nc_beaconperiod = 100;
|
|
|
|
if (config.nc_atimwin == 0)
|
|
|
|
config.nc_atimwin = 100;
|
|
|
|
if (config.nc_fhconfig.ncf_dwelltime == 0)
|
|
|
|
config.nc_fhconfig.ncf_dwelltime = 200;
|
|
|
|
|
|
|
|
if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) {
|
|
|
|
int chan, chanflag;
|
|
|
|
|
|
|
|
chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
|
|
|
|
chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
|
|
|
|
IEEE80211_CHAN_5GHZ;
|
|
|
|
if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
|
|
|
|
config.nc_dsconfig =
|
|
|
|
ic->ic_ibss_chan->ic_freq * 1000;
|
|
|
|
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
|
|
|
|
len = sizeof(config);
|
|
|
|
config.nc_length = len;
|
|
|
|
config.nc_fhconfig.ncf_length =
|
|
|
|
sizeof(ndis_80211_config_fh);
|
|
|
|
rval = ndis_set_info(sc, OID_802_11_CONFIGURATION,
|
|
|
|
&config, &len);
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "couldn't change "
|
2006-04-24 02:53:43 +04:00
|
|
|
"DS config to %ukHz: %d\n",
|
|
|
|
config.nc_dsconfig,
|
|
|
|
rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
}
|
|
|
|
} else if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "couldn't retrieve "
|
|
|
|
"channel info: %d\n", rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/* Set SSID -- always do this last. */
|
|
|
|
|
|
|
|
len = sizeof(ssid);
|
2009-03-18 19:00:08 +03:00
|
|
|
memset((char *)&ssid, 0, len);
|
2006-03-31 02:57:56 +04:00
|
|
|
ssid.ns_ssidlen = ic->ic_des_esslen;
|
|
|
|
if (ssid.ns_ssidlen == 0) {
|
|
|
|
ssid.ns_ssidlen = 1;
|
|
|
|
} else
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ssid.ns_ssid, ic->ic_des_essid, ssid.ns_ssidlen);
|
2006-03-31 02:57:56 +04:00
|
|
|
rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
|
|
|
|
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "set ssid failed: %d\n", rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
|
|
|
|
{
|
|
|
|
struct ieee80211com *ic = (void *)ifp;
|
|
|
|
struct ieee80211_node *ni = NULL;
|
|
|
|
|
|
|
|
imr->ifm_status = IFM_AVALID;
|
|
|
|
imr->ifm_active = IFM_IEEE80211;
|
|
|
|
if (ic->ic_state == IEEE80211_S_RUN)
|
|
|
|
imr->ifm_status |= IFM_ACTIVE;
|
|
|
|
imr->ifm_active |= IFM_AUTO;
|
|
|
|
switch (ic->ic_opmode) {
|
|
|
|
case IEEE80211_M_STA:
|
|
|
|
ni = ic->ic_bss;
|
|
|
|
/* calculate rate subtype */
|
|
|
|
imr->ifm_active |= ieee80211_rate2media(ic,
|
|
|
|
ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
|
|
|
|
break;
|
|
|
|
case IEEE80211_M_IBSS:
|
|
|
|
ni = ic->ic_bss;
|
|
|
|
/* calculate rate subtype */
|
|
|
|
imr->ifm_active |= ieee80211_rate2media(ic,
|
|
|
|
ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
|
|
|
|
imr->ifm_active |= IFM_IEEE80211_ADHOC;
|
|
|
|
break;
|
|
|
|
case IEEE80211_M_AHDEMO:
|
|
|
|
/* should not come here */
|
|
|
|
break;
|
|
|
|
case IEEE80211_M_HOSTAP:
|
|
|
|
imr->ifm_active |= IFM_IEEE80211_HOSTAP;
|
|
|
|
break;
|
|
|
|
case IEEE80211_M_MONITOR:
|
|
|
|
imr->ifm_active |= IFM_IEEE80211_MONITOR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (ic->ic_curmode) {
|
|
|
|
case IEEE80211_MODE_11A:
|
|
|
|
imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A);
|
|
|
|
break;
|
|
|
|
case IEEE80211_MODE_11B:
|
|
|
|
imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B);
|
|
|
|
break;
|
|
|
|
case IEEE80211_MODE_11G:
|
|
|
|
imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G);
|
|
|
|
break;
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* TODO: is this correct? (IEEE80211_MODE_TURBO_A and IEEE80211_MODE_TURBO_G
|
|
|
|
* are defined in _ieee80211.h)
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
case IEEE80211_MODE_TURBO_A:
|
|
|
|
case IEEE80211_MODE_TURBO_G:
|
2006-03-31 02:57:56 +04:00
|
|
|
imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
|
|
|
|
| IFM_IEEE80211_TURBO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_get_assoc(struct ndis_softc *sc, ndis_wlan_bssid_ex **assoc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
ndis_80211_bssid_list_ex *bl;
|
|
|
|
ndis_wlan_bssid_ex *bs;
|
|
|
|
ndis_80211_macaddr bssid;
|
|
|
|
int i, len, error;
|
|
|
|
|
|
|
|
if (!sc->ndis_link)
|
|
|
|
return(ENOENT);
|
|
|
|
|
|
|
|
len = sizeof(bssid);
|
|
|
|
error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len);
|
|
|
|
if (error) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "failed to get bssid\n");
|
2006-03-31 02:57:56 +04:00
|
|
|
return(ENOENT);
|
|
|
|
}
|
|
|
|
len = 0;
|
|
|
|
error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
|
|
|
|
if (error != ENOSPC) {
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "bssid_list failed\n");
|
2006-03-31 02:57:56 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
bl = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
|
|
|
|
error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
|
|
|
|
if (error) {
|
|
|
|
free(bl, M_TEMP);
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "bssid_list failed\n");
|
2006-03-31 02:57:56 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0];
|
|
|
|
for (i = 0; i < bl->nblx_items; i++) {
|
2009-03-18 18:14:29 +03:00
|
|
|
if (memcmp(bs->nwbx_macaddr, bssid, sizeof(bssid)) == 0) {
|
2006-03-31 02:57:56 +04:00
|
|
|
*assoc = malloc(bs->nwbx_len, M_TEMP, M_NOWAIT);
|
|
|
|
if (*assoc == NULL) {
|
|
|
|
free(bl, M_TEMP);
|
|
|
|
return(ENOMEM);
|
|
|
|
}
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy((char *)*assoc, (char *)bs, bs->nwbx_len);
|
2006-03-31 02:57:56 +04:00
|
|
|
free(bl, M_TEMP);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(bl, M_TEMP);
|
|
|
|
return(ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_getstate_80211(struct ndis_softc *sc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ieee80211com *ic;
|
|
|
|
ndis_80211_ssid ssid;
|
|
|
|
ndis_80211_config config;
|
2006-09-12 01:17:18 +04:00
|
|
|
ndis_wlan_bssid_ex *bs = 0;
|
2006-03-31 02:57:56 +04:00
|
|
|
int rval, len, i = 0;
|
|
|
|
uint32_t arg;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
|
|
|
|
ic = &sc->ic;
|
2006-03-31 04:03:57 +04:00
|
|
|
/* TODO: are these equivelant? */
|
|
|
|
ifp = sc->ic.ic_ifp;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
if (!NDIS_INITIALIZED(sc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (sc->ndis_link)
|
|
|
|
ic->ic_state = IEEE80211_S_RUN;
|
|
|
|
else
|
|
|
|
ic->ic_state = IEEE80211_S_ASSOC;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're associated, retrieve info on the current bssid.
|
|
|
|
*/
|
|
|
|
if ((rval = ndis_get_assoc(sc, &bs)) == 0) {
|
|
|
|
switch(bs->nwbx_nettype) {
|
|
|
|
case NDIS_80211_NETTYPE_11FH:
|
|
|
|
case NDIS_80211_NETTYPE_11DS:
|
|
|
|
ic->ic_curmode = IEEE80211_MODE_11B;
|
|
|
|
break;
|
|
|
|
case NDIS_80211_NETTYPE_11OFDM5:
|
|
|
|
ic->ic_curmode = IEEE80211_MODE_11A;
|
|
|
|
break;
|
|
|
|
case NDIS_80211_NETTYPE_11OFDM24:
|
|
|
|
ic->ic_curmode = IEEE80211_MODE_11G;
|
|
|
|
break;
|
|
|
|
default:
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "unknown nettype %d\n",
|
|
|
|
arg);
|
2006-03-31 02:57:56 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(bs, M_TEMP);
|
|
|
|
} else
|
|
|
|
return;
|
|
|
|
|
|
|
|
len = sizeof(ssid);
|
2009-03-18 19:00:08 +03:00
|
|
|
memset((char *)&ssid, 0, len);
|
2006-03-31 02:57:56 +04:00
|
|
|
rval = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len);
|
|
|
|
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "get ssid failed: %d\n", rval);
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ic->ic_bss->ni_essid, ssid.ns_ssid, ssid.ns_ssidlen);
|
2006-03-31 02:57:56 +04:00
|
|
|
ic->ic_bss->ni_esslen = ssid.ns_ssidlen;
|
|
|
|
|
|
|
|
len = sizeof(arg);
|
|
|
|
rval = ndis_get_info(sc, OID_GEN_LINK_SPEED, &arg, &len);
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "get link speed failed: %d\n",
|
|
|
|
rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
|
|
|
|
ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];
|
|
|
|
for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
|
|
|
|
if ((ic->ic_bss->ni_rates.rs_rates[i] &
|
|
|
|
IEEE80211_RATE_VAL) == arg / 5000)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == ic->ic_bss->ni_rates.rs_nrates &&
|
|
|
|
ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
|
|
|
|
ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11G];
|
|
|
|
for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
|
|
|
|
if ((ic->ic_bss->ni_rates.rs_rates[i] &
|
|
|
|
IEEE80211_RATE_VAL) == arg / 5000)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == ic->ic_bss->ni_rates.rs_nrates)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "no matching rate for: %d\n",
|
|
|
|
arg / 5000);
|
2006-03-31 02:57:56 +04:00
|
|
|
else
|
|
|
|
ic->ic_bss->ni_txrate = i;
|
|
|
|
|
|
|
|
if (ic->ic_caps & IEEE80211_C_PMGT) {
|
|
|
|
len = sizeof(arg);
|
|
|
|
rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len);
|
|
|
|
|
|
|
|
if (rval)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "get power mode failed: %d\n",
|
|
|
|
rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
if (arg == NDIS_80211_POWERMODE_CAM)
|
|
|
|
ic->ic_flags &= ~IEEE80211_F_PMGTON;
|
|
|
|
else
|
|
|
|
ic->ic_flags |= IEEE80211_F_PMGTON;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = sizeof(config);
|
2009-03-18 19:00:08 +03:00
|
|
|
memset((char *)&config, 0, len);
|
2006-03-31 02:57:56 +04:00
|
|
|
config.nc_length = len;
|
|
|
|
config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
|
|
|
|
rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len);
|
|
|
|
if (rval == 0) {
|
|
|
|
int chan;
|
|
|
|
|
|
|
|
chan = ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0);
|
|
|
|
if (chan < 0 || chan >= IEEE80211_CHAN_MAX) {
|
|
|
|
if (ifp->if_flags & IFF_DEBUG)
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "current channel "
|
2006-04-24 02:53:43 +04:00
|
|
|
"(%uMHz) out of bounds\n",
|
|
|
|
config.nc_dsconfig / 1000);
|
2006-03-31 02:57:56 +04:00
|
|
|
ic->ic_bss->ni_chan = &ic->ic_channels[1];
|
|
|
|
} else
|
|
|
|
ic->ic_bss->ni_chan = &ic->ic_channels[chan];
|
|
|
|
} else
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "couldn't retrieve "
|
|
|
|
"channel info: %d\n", rval);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
len = sizeof(arg);
|
|
|
|
rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
|
|
|
|
|
|
|
|
if (rval)
|
|
|
|
device_printf (sc->ndis_dev,
|
|
|
|
"get wep status failed: %d\n", rval);
|
|
|
|
|
|
|
|
if (arg == NDIS_80211_WEPSTAT_ENABLED)
|
|
|
|
ic->ic_flags |= IEEE80211_F_WEPON;
|
|
|
|
else
|
|
|
|
ic->ic_flags &= ~IEEE80211_F_WEPON;
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
ndis_ioctl(struct ifnet *ifp, u_long command, void *data)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc = ifp->if_softc;
|
|
|
|
struct ifreq *ifr = (struct ifreq *) data;
|
|
|
|
int i, error = 0;
|
2006-03-31 04:03:57 +04:00
|
|
|
int s;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
/*NDIS_LOCK(sc);*/
|
2006-03-31 04:03:57 +04:00
|
|
|
s = splnet();
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
switch(command) {
|
|
|
|
case SIOCSIFFLAGS:
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
if ((error = ifioctl_common(ifp, command, data)) != 0)
|
|
|
|
break;
|
2006-03-31 02:57:56 +04:00
|
|
|
if (ifp->if_flags & IFF_UP) {
|
|
|
|
if (ifp->if_flags & IFF_RUNNING &&
|
|
|
|
ifp->if_flags & IFF_PROMISC &&
|
|
|
|
!(sc->ndis_if_flags & IFF_PROMISC)) {
|
|
|
|
sc->ndis_filter |=
|
|
|
|
NDIS_PACKET_TYPE_PROMISCUOUS;
|
|
|
|
i = sizeof(sc->ndis_filter);
|
|
|
|
error = ndis_set_info(sc,
|
|
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
|
|
&sc->ndis_filter, &i);
|
|
|
|
} else if (ifp->if_flags & IFF_RUNNING &&
|
|
|
|
!(ifp->if_flags & IFF_PROMISC) &&
|
|
|
|
sc->ndis_if_flags & IFF_PROMISC) {
|
|
|
|
sc->ndis_filter &=
|
|
|
|
~NDIS_PACKET_TYPE_PROMISCUOUS;
|
|
|
|
i = sizeof(sc->ndis_filter);
|
|
|
|
error = ndis_set_info(sc,
|
|
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
|
|
&sc->ndis_filter, &i);
|
|
|
|
} else
|
2006-03-31 04:03:57 +04:00
|
|
|
ndis_init(ifp);
|
2006-03-31 02:57:56 +04:00
|
|
|
} else {
|
|
|
|
if (ifp->if_flags & IFF_RUNNING)
|
|
|
|
ndis_stop(sc);
|
|
|
|
}
|
|
|
|
sc->ndis_if_flags = ifp->if_flags;
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
case SIOCADDMULTI:
|
|
|
|
case SIOCDELMULTI:
|
2006-04-23 06:55:04 +04:00
|
|
|
/*
|
|
|
|
* TODO: I'm really not sure this is the correct thing to do here, but multicast
|
|
|
|
* address lists weren't getting set in ether_ioctl because they SIOCADDMULTI
|
|
|
|
* is routed to ndis_setmulti here.
|
2006-03-31 04:03:57 +04:00
|
|
|
*/
|
|
|
|
error = ether_ioctl(ifp, command, data);
|
2006-03-31 02:57:56 +04:00
|
|
|
ndis_setmulti(sc);
|
|
|
|
error = 0;
|
2006-03-31 04:03:57 +04:00
|
|
|
break;
|
2006-03-31 02:57:56 +04:00
|
|
|
case SIOCGIFMEDIA:
|
|
|
|
case SIOCSIFMEDIA:
|
|
|
|
if (sc->ndis_80211) {
|
2006-04-23 06:55:04 +04:00
|
|
|
error = ieee80211_ioctl(&sc->ic, command, data);
|
2006-03-31 02:57:56 +04:00
|
|
|
if (error == ENETRESET) {
|
|
|
|
ndis_setstate_80211(sc);
|
|
|
|
/*ndis_init(sc);*/
|
|
|
|
error = 0;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
|
|
|
|
break;
|
|
|
|
case SIOCSIFCAP:
|
2009-08-03 00:22:34 +04:00
|
|
|
if ((error = ether_ioctl(ifp, command, data)) == ENETRESET) {
|
2008-02-07 04:21:52 +03:00
|
|
|
ndis_set_offload(sc);
|
|
|
|
error = 0;
|
|
|
|
}
|
2006-03-31 02:57:56 +04:00
|
|
|
break;
|
|
|
|
case SIOCGIFGENERIC:
|
|
|
|
case SIOCSIFGENERIC:
|
|
|
|
if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) {
|
|
|
|
if (command == SIOCGIFGENERIC)
|
|
|
|
error = ndis_wi_ioctl_get(ifp, command, data);
|
|
|
|
else
|
|
|
|
error = ndis_wi_ioctl_set(ifp, command, data);
|
|
|
|
} else
|
|
|
|
error = ENOTTY;
|
|
|
|
if (error != ENOTTY)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sc->ndis_skip = 1;
|
|
|
|
if (sc->ndis_80211) {
|
2006-03-31 04:03:57 +04:00
|
|
|
error = ieee80211_ioctl(&sc->ic, command, data);
|
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
if (error == ENETRESET) {
|
|
|
|
ndis_setstate_80211(sc);
|
|
|
|
error = 0;
|
|
|
|
}
|
2006-03-31 04:03:57 +04:00
|
|
|
} else {
|
2006-03-31 02:57:56 +04:00
|
|
|
error = ether_ioctl(ifp, command, data);
|
2006-03-31 04:03:57 +04:00
|
|
|
}
|
2006-03-31 02:57:56 +04:00
|
|
|
sc->ndis_skip = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*NDIS_UNLOCK(sc);*/
|
2006-03-31 04:03:57 +04:00
|
|
|
splx(s);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
return(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_wi_ioctl_get(struct ifnet *ifp, u_long command, void * data)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct wi_req wreq;
|
|
|
|
struct ifreq *ifr;
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
ndis_80211_bssid_list_ex *bl;
|
|
|
|
ndis_wlan_bssid_ex *wb;
|
|
|
|
struct wi_apinfo *api;
|
|
|
|
int error, i, j, len, maxaps;
|
|
|
|
|
|
|
|
sc = ifp->if_softc;
|
|
|
|
ifr = (struct ifreq *)data;
|
|
|
|
error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
switch (wreq.wi_type) {
|
|
|
|
case WI_RID_READ_APS:
|
|
|
|
len = 0;
|
|
|
|
error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN,
|
|
|
|
NULL, &len);
|
|
|
|
if (error == 0)
|
|
|
|
tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2);
|
|
|
|
len = 0;
|
|
|
|
error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
|
|
|
|
if (error != ENOSPC)
|
|
|
|
break;
|
|
|
|
bl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
|
|
|
|
error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
|
|
|
|
if (error) {
|
|
|
|
free(bl, M_DEVBUF);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
maxaps = (2 * wreq.wi_len - sizeof(int)) / sizeof(*api);
|
|
|
|
maxaps = MIN(maxaps, bl->nblx_items);
|
|
|
|
wreq.wi_len = (maxaps * sizeof(*api) + sizeof(int)) / 2;
|
|
|
|
*(int *)&wreq.wi_val = maxaps;
|
|
|
|
api = (struct wi_apinfo *)&((int *)&wreq.wi_val)[1];
|
|
|
|
wb = bl->nblx_bssid;
|
|
|
|
while (maxaps--) {
|
2009-03-18 19:00:08 +03:00
|
|
|
memset(api, 0, sizeof(*api));
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&api->bssid, &wb->nwbx_macaddr,
|
2006-03-31 02:57:56 +04:00
|
|
|
sizeof(api->bssid));
|
|
|
|
api->namelen = wb->nwbx_ssid.ns_ssidlen;
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&api->name, &wb->nwbx_ssid.ns_ssid, api->namelen);
|
2006-03-31 02:57:56 +04:00
|
|
|
if (wb->nwbx_privacy)
|
|
|
|
api->capinfo |= IEEE80211_CAPINFO_PRIVACY;
|
|
|
|
/* XXX Where can we get noise information? */
|
|
|
|
api->signal = wb->nwbx_rssi + 149; /* XXX */
|
|
|
|
api->quality = api->signal;
|
|
|
|
api->channel =
|
|
|
|
ieee80211_mhz2ieee(wb->nwbx_config.nc_dsconfig /
|
|
|
|
1000, 0);
|
|
|
|
/* In "auto" infrastructure mode, this is useless. */
|
|
|
|
if (wb->nwbx_netinfra == NDIS_80211_NET_INFRA_IBSS)
|
|
|
|
api->capinfo |= IEEE80211_CAPINFO_IBSS;
|
|
|
|
if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
|
|
|
|
j = sizeof(ndis_80211_rates_ex);
|
|
|
|
/* handle other extended things */
|
|
|
|
} else
|
|
|
|
j = sizeof(ndis_80211_rates);
|
|
|
|
for (i = api->rate = 0; i < j; i++)
|
|
|
|
api->rate = MAX(api->rate, 5 *
|
|
|
|
(wb->nwbx_supportedrates[i] & 0x7f));
|
|
|
|
api++;
|
|
|
|
wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
|
|
|
|
}
|
|
|
|
free(bl, M_DEVBUF);
|
|
|
|
error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error = ENOTTY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_wi_ioctl_set(struct ifnet *ifp, u_long command, void * data)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct wi_req wreq;
|
|
|
|
struct ifreq *ifr;
|
|
|
|
struct ndis_softc *sc;
|
|
|
|
uint32_t foo;
|
|
|
|
int error, len;
|
2009-04-16 00:44:24 +04:00
|
|
|
|
|
|
|
error = kauth_authorize_network(kauth_cred_get(),
|
|
|
|
KAUTH_NETWORK_INTERFACE, KAUTH_REQ_NETWORK_INTERFACE_SETPRIV,
|
|
|
|
ifp, KAUTH_ARG(command), NULL);
|
2006-03-31 02:57:56 +04:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
sc = ifp->if_softc;
|
|
|
|
ifr = (struct ifreq *)data;
|
|
|
|
error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
switch (wreq.wi_type) {
|
|
|
|
case WI_RID_SCAN_APS:
|
|
|
|
case WI_RID_SCAN_REQ: /* arguments ignored */
|
|
|
|
len = sizeof(foo);
|
|
|
|
foo = 0;
|
|
|
|
error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, &foo,
|
|
|
|
&len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error = ENOTTY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_watchdog(struct ifnet *ifp)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ndis_softc *sc;
|
2006-03-31 04:03:57 +04:00
|
|
|
int s;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
sc = ifp->if_softc;
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_LOCK(sc);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
ifp->if_oerrors++;
|
2008-04-08 10:12:21 +04:00
|
|
|
aprint_error_dev(sc->ndis_dev, "watchdog timeout\n");
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_UNLOCK(sc);
|
|
|
|
|
|
|
|
ndis_sched((void(*)(void *))ndis_reset_nic, sc, NDIS_TASKQUEUE);
|
|
|
|
ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stop the adapter and free any mbufs allocated to the
|
|
|
|
* RX and TX lists.
|
|
|
|
*/
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
ndis_stop(struct ndis_softc *sc)
|
2006-03-31 02:57:56 +04:00
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
2006-03-31 04:03:57 +04:00
|
|
|
int s;
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
ifp = &sc->arpcom.ac_if;
|
2006-03-31 04:03:57 +04:00
|
|
|
callout_stop(&sc->ndis_stat_ch);
|
2006-03-31 02:57:56 +04:00
|
|
|
|
|
|
|
ndis_halt_nic(sc);
|
|
|
|
|
|
|
|
NDIS_LOCK(sc);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
ifp->if_timer = 0;
|
|
|
|
sc->ndis_link = 0;
|
|
|
|
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
|
2006-03-31 04:03:57 +04:00
|
|
|
|
2006-03-31 02:57:56 +04:00
|
|
|
NDIS_UNLOCK(sc);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stop all chip I/O so that the kernel's probe routines don't
|
|
|
|
* get confused by errant DMAs when rebooting.
|
|
|
|
*/
|
2006-03-31 04:03:57 +04:00
|
|
|
/* TODO: remove this #ifdef once ndis_shutdown_nic() is working on NetBSD */
|