*** 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
|
|
|
/* $NetBSD: awi.c,v 1.81 2008/11/07 00:20:02 dyoung Exp $ */
|
1999-11-05 08:13:36 +03:00
|
|
|
|
2000-06-09 18:36:25 +04:00
|
|
|
/*-
|
2001-09-18 13:09:57 +04:00
|
|
|
* Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc.
|
1999-11-04 20:10:53 +03:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
2000-06-09 18:36:25 +04:00
|
|
|
* by Bill Sommerfeld
|
1999-11-04 20:10:53 +03:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* 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.
|
|
|
|
*/
|
2000-06-09 18:36:25 +04:00
|
|
|
/*
|
|
|
|
* Driver for AMD 802.11 firmware.
|
|
|
|
* Uses am79c930 chip driver to talk to firmware running on the am79c930.
|
|
|
|
*
|
|
|
|
* More-or-less a generic ethernet-like if driver, with 802.11 gorp added.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* todo:
|
|
|
|
* - flush tx queue on resynch.
|
|
|
|
* - clear oactive on "down".
|
|
|
|
* - rewrite copy-into-mbuf code
|
|
|
|
* - mgmt state machine gets stuck retransmitting assoc requests.
|
|
|
|
* - multicast filter.
|
|
|
|
* - fix device reset so it's more likely to work
|
|
|
|
* - show status goo through ifmedia.
|
|
|
|
*
|
|
|
|
* more todo:
|
|
|
|
* - deal with more 802.11 frames.
|
|
|
|
* - send reassoc request
|
|
|
|
* - deal with reassoc response
|
|
|
|
* - send/deal with disassociation
|
|
|
|
* - deal with "full" access points (no room for me).
|
|
|
|
* - power save mode
|
|
|
|
*
|
|
|
|
* later:
|
|
|
|
* - SSID preferences
|
|
|
|
* - need ioctls for poking at the MIBs
|
|
|
|
* - implement ad-hoc mode (including bss creation).
|
|
|
|
* - decide when to do "ad hoc" vs. infrastructure mode (IFF_LINK flags?)
|
|
|
|
* (focus on inf. mode since that will be needed for ietf)
|
|
|
|
* - deal with DH vs. FH versions of the card
|
|
|
|
* - deal with faster cards (2mb/s)
|
|
|
|
* - ?WEP goo (mmm, rc4) (it looks not particularly useful).
|
|
|
|
* - ifmedia revision.
|
|
|
|
* - common 802.11 mibish things.
|
|
|
|
* - common 802.11 media layer.
|
|
|
|
*/
|
1999-11-04 20:10:53 +03:00
|
|
|
|
|
|
|
/*
|
2000-03-22 14:22:20 +03:00
|
|
|
* Driver for AMD 802.11 PCnetMobile firmware.
|
|
|
|
* Uses am79c930 chip driver to talk to firmware running on the am79c930.
|
1999-11-04 20:10:53 +03:00
|
|
|
*
|
2000-03-22 14:22:20 +03:00
|
|
|
* The initial version of the driver was written by
|
2003-12-04 16:57:30 +03:00
|
|
|
* Bill Sommerfeld <sommerfeld@NetBSD.org>.
|
2000-03-22 14:22:20 +03:00
|
|
|
* Then the driver module completely rewritten to support cards with DS phy
|
2003-12-04 16:57:30 +03:00
|
|
|
* and to support adhoc mode by Atsushi Onoe <onoe@NetBSD.org>
|
1999-11-04 20:10:53 +03:00
|
|
|
*/
|
|
|
|
|
2001-11-13 16:14:31 +03:00
|
|
|
#include <sys/cdefs.h>
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
*** 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
|
|
|
__KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.81 2008/11/07 00:20:02 dyoung Exp $");
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
2004-01-16 17:13:15 +03:00
|
|
|
__FBSDID("$FreeBSD: src/sys/dev/awi/awi.c,v 1.30 2004/01/15 13:30:06 onoe Exp $");
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
2001-11-13 16:14:31 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
#include "opt_inet.h"
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
2000-03-22 14:22:20 +03:00
|
|
|
#include "bpfilter.h"
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#define NBPFILTER 1
|
|
|
|
#endif
|
1999-11-04 20:10:53 +03:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/mbuf.h>
|
2000-03-22 14:22:20 +03:00
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/proc.h>
|
1999-11-04 20:10:53 +03:00
|
|
|
#include <sys/socket.h>
|
2000-03-22 14:22:20 +03:00
|
|
|
#include <sys/sockio.h>
|
1999-11-04 20:10:53 +03:00
|
|
|
#include <sys/errno.h>
|
2004-01-15 12:39:15 +03:00
|
|
|
#include <sys/endian.h>
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <sys/bus.h>
|
|
|
|
#endif
|
|
|
|
#ifdef __NetBSD__
|
1999-11-04 20:10:53 +03:00
|
|
|
#include <sys/device.h>
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
1999-11-04 20:10:53 +03:00
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_dl.h>
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
1999-11-04 20:10:53 +03:00
|
|
|
#include <net/if_ether.h>
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <net/ethernet.h>
|
|
|
|
#include <net/if_arp.h>
|
|
|
|
#endif
|
1999-11-04 20:10:53 +03:00
|
|
|
#include <net/if_media.h>
|
2000-03-22 14:22:20 +03:00
|
|
|
#include <net/if_llc.h>
|
2003-10-13 12:10:48 +04:00
|
|
|
|
2005-06-22 10:14:51 +04:00
|
|
|
#include <net80211/ieee80211_netbsd.h>
|
2003-10-13 12:10:48 +04:00
|
|
|
#include <net80211/ieee80211_var.h>
|
1999-11-04 20:10:53 +03:00
|
|
|
|
|
|
|
#if NBPFILTER > 0
|
|
|
|
#include <net/bpf.h>
|
|
|
|
#endif
|
|
|
|
|
2007-10-19 15:59:34 +04:00
|
|
|
#include <sys/cpu.h>
|
|
|
|
#include <sys/bus.h>
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
1999-11-04 20:10:53 +03:00
|
|
|
#include <dev/ic/am79c930reg.h>
|
|
|
|
#include <dev/ic/am79c930var.h>
|
|
|
|
#include <dev/ic/awireg.h>
|
|
|
|
#include <dev/ic/awivar.h>
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <dev/awi/am79c930reg.h>
|
|
|
|
#include <dev/awi/am79c930var.h>
|
|
|
|
#include <dev/awi/awireg.h>
|
|
|
|
#include <dev/awi/awivar.h>
|
|
|
|
#endif
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
static void awi_init0(void *);
|
|
|
|
#endif
|
2001-09-18 13:09:57 +04:00
|
|
|
static int awi_init(struct ifnet *);
|
|
|
|
static void awi_stop(struct ifnet *, int);
|
|
|
|
static void awi_start(struct ifnet *);
|
|
|
|
static void awi_watchdog(struct ifnet *);
|
2007-03-04 08:59:00 +03:00
|
|
|
static int awi_ioctl(struct ifnet *, u_long, void *);
|
2001-09-18 13:09:57 +04:00
|
|
|
static int awi_media_change(struct ifnet *);
|
|
|
|
static void awi_media_status(struct ifnet *, struct ifmediareq *);
|
|
|
|
static int awi_mode_init(struct awi_softc *);
|
|
|
|
static void awi_rx_int(struct awi_softc *);
|
|
|
|
static void awi_tx_int(struct awi_softc *);
|
|
|
|
static struct mbuf *awi_devget(struct awi_softc *, u_int32_t, u_int16_t);
|
|
|
|
static int awi_hw_init(struct awi_softc *);
|
|
|
|
static int awi_init_mibs(struct awi_softc *);
|
|
|
|
static int awi_mib(struct awi_softc *, u_int8_t, u_int8_t, int);
|
|
|
|
static int awi_cmd(struct awi_softc *, u_int8_t, int);
|
|
|
|
static int awi_cmd_wait(struct awi_softc *);
|
|
|
|
static void awi_cmd_done(struct awi_softc *);
|
|
|
|
static int awi_next_txd(struct awi_softc *, int, u_int32_t *, u_int32_t *);
|
|
|
|
static int awi_lock(struct awi_softc *);
|
|
|
|
static void awi_unlock(struct awi_softc *);
|
|
|
|
static int awi_intr_lock(struct awi_softc *);
|
|
|
|
static void awi_intr_unlock(struct awi_softc *);
|
2003-10-13 12:10:48 +04:00
|
|
|
static int awi_newstate(struct ieee80211com *, enum ieee80211_state, int);
|
|
|
|
static void awi_recv_mgmt(struct ieee80211com *, struct mbuf *,
|
|
|
|
struct ieee80211_node *, int, int, u_int32_t);
|
|
|
|
static int awi_send_mgmt(struct ieee80211com *, struct ieee80211_node *, int,
|
|
|
|
int);
|
2001-09-18 13:09:57 +04:00
|
|
|
static struct mbuf *awi_ether_encap(struct awi_softc *, struct mbuf *);
|
|
|
|
static struct mbuf *awi_ether_modcap(struct awi_softc *, struct mbuf *);
|
|
|
|
|
2005-02-27 03:26:58 +03:00
|
|
|
/* unaligned little endian access */
|
2001-09-18 13:09:57 +04:00
|
|
|
#define LE_READ_2(p) \
|
|
|
|
((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8))
|
|
|
|
#define LE_READ_4(p) \
|
|
|
|
((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \
|
|
|
|
(((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24))
|
|
|
|
#define LE_WRITE_2(p, v) \
|
|
|
|
((((u_int8_t *)(p))[0] = (((u_int32_t)(v) ) & 0xff)), \
|
|
|
|
(((u_int8_t *)(p))[1] = (((u_int32_t)(v) >> 8) & 0xff)))
|
|
|
|
#define LE_WRITE_4(p, v) \
|
|
|
|
((((u_int8_t *)(p))[0] = (((u_int32_t)(v) ) & 0xff)), \
|
|
|
|
(((u_int8_t *)(p))[1] = (((u_int32_t)(v) >> 8) & 0xff)), \
|
|
|
|
(((u_int8_t *)(p))[2] = (((u_int32_t)(v) >> 16) & 0xff)), \
|
|
|
|
(((u_int8_t *)(p))[3] = (((u_int32_t)(v) >> 24) & 0xff)))
|
|
|
|
|
|
|
|
struct awi_chanset awi_chanset[] = {
|
|
|
|
/* PHY type domain min max def */
|
|
|
|
{ AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_JP, 6, 17, 6 },
|
|
|
|
{ AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_ES, 0, 26, 1 },
|
|
|
|
{ AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_FR, 0, 32, 1 },
|
|
|
|
{ AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_US, 0, 77, 1 },
|
|
|
|
{ AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_CA, 0, 77, 1 },
|
|
|
|
{ AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_EU, 0, 77, 1 },
|
|
|
|
{ AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_JP, 14, 14, 14 },
|
|
|
|
{ AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_ES, 10, 11, 10 },
|
|
|
|
{ AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_FR, 10, 13, 10 },
|
|
|
|
{ AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_US, 1, 11, 3 },
|
|
|
|
{ AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_CA, 1, 11, 3 },
|
|
|
|
{ AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_EU, 1, 13, 3 },
|
2006-08-28 04:01:36 +04:00
|
|
|
{ 0, 0, 0, 0, 0 }
|
2001-09-18 13:09:57 +04:00
|
|
|
};
|
2000-03-22 14:22:20 +03:00
|
|
|
|
|
|
|
#ifdef AWI_DEBUG
|
2004-01-15 12:39:15 +03:00
|
|
|
int awi_debug = 0;
|
1999-11-09 17:58:07 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
#define DPRINTF(X) if (awi_debug) printf X
|
|
|
|
#define DPRINTF2(X) if (awi_debug > 1) printf X
|
2000-03-22 14:22:20 +03:00
|
|
|
#else
|
2001-09-18 13:09:57 +04:00
|
|
|
#define DPRINTF(X)
|
|
|
|
#define DPRINTF2(X)
|
1999-11-04 20:10:53 +03:00
|
|
|
#endif
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_attach(struct awi_softc *sc)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2001-09-18 13:09:57 +04:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
2001-09-18 13:09:57 +04:00
|
|
|
int s, i, error, nrate;
|
2000-03-22 14:22:20 +03:00
|
|
|
int mword;
|
2004-01-15 12:39:15 +03:00
|
|
|
enum ieee80211_phymode mode;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
s = splnet();
|
|
|
|
sc->sc_busy = 1;
|
2004-01-15 12:39:15 +03:00
|
|
|
sc->sc_attached = 0;
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
|
|
|
if ((error = awi_hw_init(sc)) != 0) {
|
2000-03-22 14:22:20 +03:00
|
|
|
sc->sc_invalid = 1;
|
|
|
|
splx(s);
|
|
|
|
return error;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
error = awi_init_mibs(sc);
|
2001-09-18 13:09:57 +04:00
|
|
|
if (error != 0) {
|
2000-03-22 14:22:20 +03:00
|
|
|
sc->sc_invalid = 1;
|
2001-09-18 13:09:57 +04:00
|
|
|
splx(s);
|
2000-03-22 14:22:20 +03:00
|
|
|
return error;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
ifp->if_softc = sc;
|
2001-09-18 13:09:57 +04:00
|
|
|
ifp->if_flags =
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef IFF_NOTRAILERS
|
|
|
|
IFF_NOTRAILERS |
|
|
|
|
#endif
|
|
|
|
IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
|
2000-03-22 14:22:20 +03:00
|
|
|
ifp->if_ioctl = awi_ioctl;
|
2001-09-18 13:09:57 +04:00
|
|
|
ifp->if_start = awi_start;
|
2004-01-15 12:39:15 +03:00
|
|
|
ifp->if_watchdog = awi_watchdog;
|
|
|
|
#ifdef __NetBSD__
|
2001-06-28 14:40:04 +04:00
|
|
|
ifp->if_init = awi_init;
|
|
|
|
ifp->if_stop = awi_stop;
|
2000-12-14 09:27:23 +03:00
|
|
|
IFQ_SET_READY(&ifp->if_snd);
|
2008-04-08 16:07:25 +04:00
|
|
|
memcpy(ifp->if_xname, device_xname(&sc->sc_dev), IFNAMSIZ);
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
ifp->if_init = awi_init0;
|
|
|
|
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
|
|
|
|
if_initname(ifp, device_get_name(sc->sc_dev),
|
|
|
|
device_get_unit(sc->sc_dev));
|
|
|
|
#endif
|
2001-09-18 13:09:57 +04:00
|
|
|
|
2005-06-22 10:14:51 +04:00
|
|
|
ic->ic_ifp = ifp;
|
2003-10-13 12:10:48 +04:00
|
|
|
ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_IBSS | IEEE80211_C_HOSTAP;
|
2004-01-15 12:39:15 +03:00
|
|
|
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
|
2002-09-27 09:36:04 +04:00
|
|
|
ic->ic_phytype = IEEE80211_T_FH;
|
2004-01-15 12:39:15 +03:00
|
|
|
mode = IEEE80211_MODE_FH;
|
|
|
|
} else {
|
2002-09-27 09:36:04 +04:00
|
|
|
ic->ic_phytype = IEEE80211_T_DS;
|
2003-10-13 12:10:48 +04:00
|
|
|
ic->ic_caps |= IEEE80211_C_AHDEMO;
|
2004-01-15 12:39:15 +03:00
|
|
|
mode = IEEE80211_MODE_11B;
|
2002-09-30 19:48:41 +04:00
|
|
|
}
|
2002-09-27 09:36:04 +04:00
|
|
|
ic->ic_opmode = IEEE80211_M_STA;
|
2001-09-18 13:09:57 +04:00
|
|
|
nrate = sc->sc_mib_phy.aSuprt_Data_Rates[1];
|
2004-01-15 12:39:15 +03:00
|
|
|
memcpy(ic->ic_sup_rates[mode].rs_rates,
|
2003-10-13 12:10:48 +04:00
|
|
|
sc->sc_mib_phy.aSuprt_Data_Rates + 2, nrate);
|
2004-01-15 12:39:15 +03:00
|
|
|
ic->ic_sup_rates[mode].rs_nrates = nrate;
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_mib_addr.aMAC_Address);
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
printf("%s: IEEE802.11 %s (firmware %s)\n", ifp->if_xname,
|
2003-07-07 00:01:17 +04:00
|
|
|
(ic->ic_phytype == IEEE80211_T_FH) ? "FH" : "DS", sc->sc_banner);
|
2004-01-15 12:39:15 +03:00
|
|
|
printf("%s: 802.11 address: %s\n", ifp->if_xname,
|
2001-09-18 13:09:57 +04:00
|
|
|
ether_sprintf(ic->ic_myaddr));
|
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
2003-07-07 00:01:17 +04:00
|
|
|
if_attach(ifp);
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_ifattach(ic);
|
2003-07-07 00:01:17 +04:00
|
|
|
|
2003-10-13 12:10:48 +04:00
|
|
|
sc->sc_newstate = ic->ic_newstate;
|
|
|
|
ic->ic_newstate = awi_newstate;
|
|
|
|
|
|
|
|
sc->sc_recv_mgmt = ic->ic_recv_mgmt;
|
|
|
|
ic->ic_recv_mgmt = awi_recv_mgmt;
|
|
|
|
|
|
|
|
sc->sc_send_mgmt = ic->ic_send_mgmt;
|
|
|
|
ic->ic_send_mgmt = awi_send_mgmt;
|
|
|
|
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_media_init(ic, awi_media_change, awi_media_status);
|
2003-10-13 12:10:48 +04:00
|
|
|
|
2003-07-07 00:01:17 +04:00
|
|
|
/* Melco compatibility mode. */
|
|
|
|
#define ADD(s, o) ifmedia_add(&ic->ic_media, \
|
2002-09-02 17:37:35 +04:00
|
|
|
IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
|
2003-07-07 00:01:17 +04:00
|
|
|
ADD(IFM_AUTO, IFM_FLAG0);
|
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
for (i = 0; i < nrate; i++) {
|
2003-10-13 12:10:48 +04:00
|
|
|
mword = ieee80211_rate2media(ic,
|
2004-01-15 12:39:15 +03:00
|
|
|
ic->ic_sup_rates[mode].rs_rates[i], mode);
|
2000-03-22 14:22:20 +03:00
|
|
|
if (mword == 0)
|
|
|
|
continue;
|
2002-09-02 17:37:35 +04:00
|
|
|
ADD(mword, IFM_FLAG0);
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2002-09-02 17:37:35 +04:00
|
|
|
#undef ADD
|
2003-07-07 00:01:17 +04:00
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((sc->sc_sdhook = shutdownhook_establish(awi_shutdown, sc)) == NULL)
|
|
|
|
printf("%s: WARNING: unable to establish shutdown hook\n",
|
2004-01-15 12:39:15 +03:00
|
|
|
ifp->if_xname);
|
2006-09-24 07:53:07 +04:00
|
|
|
if ((sc->sc_powerhook =
|
|
|
|
powerhook_establish(ifp->if_xname, awi_power, sc)) == NULL)
|
2001-09-18 13:09:57 +04:00
|
|
|
printf("%s: WARNING: unable to establish power hook\n",
|
2004-01-15 12:39:15 +03:00
|
|
|
ifp->if_xname);
|
|
|
|
#endif
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_attached = 1;
|
|
|
|
splx(s);
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
/* ready to accept ioctl */
|
|
|
|
awi_unlock(sc);
|
2000-05-29 21:37:12 +04:00
|
|
|
|
1999-11-04 20:10:53 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_detach(struct awi_softc *sc)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
2000-03-22 14:22:20 +03:00
|
|
|
int s;
|
|
|
|
|
2000-05-29 21:37:12 +04:00
|
|
|
if (!sc->sc_attached)
|
2001-09-18 13:09:57 +04:00
|
|
|
return 0;
|
2000-05-29 21:37:12 +04:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
s = splnet();
|
|
|
|
sc->sc_invalid = 1;
|
2001-06-28 14:40:04 +04:00
|
|
|
awi_stop(ifp, 1);
|
2004-01-15 12:39:15 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
while (sc->sc_sleep_cnt > 0) {
|
|
|
|
wakeup(sc);
|
|
|
|
(void)tsleep(sc, PWAIT, "awidet", 1);
|
|
|
|
}
|
2004-01-15 16:29:05 +03:00
|
|
|
sc->sc_attached = 0;
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_ifdetach(ic);
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
2000-03-22 14:22:20 +03:00
|
|
|
if_detach(ifp);
|
2001-09-18 13:09:57 +04:00
|
|
|
shutdownhook_disestablish(sc->sc_sdhook);
|
|
|
|
powerhook_disestablish(sc->sc_powerhook);
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
2000-03-22 14:22:20 +03:00
|
|
|
splx(s);
|
|
|
|
return 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
1999-11-04 20:10:53 +03:00
|
|
|
int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_activate(struct device *self, enum devact act)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
struct awi_softc *sc = (struct awi_softc *)self;
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
2000-03-22 14:22:20 +03:00
|
|
|
int s, error = 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
s = splnet();
|
|
|
|
switch (act) {
|
|
|
|
case DVACT_ACTIVATE:
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
case DVACT_DEACTIVATE:
|
|
|
|
sc->sc_invalid = 1;
|
2001-09-18 13:09:57 +04:00
|
|
|
if_deactivate(ifp);
|
2000-03-22 14:22:20 +03:00
|
|
|
break;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
splx(s);
|
|
|
|
return error;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_power(int why, void *arg)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2001-09-18 13:09:57 +04:00
|
|
|
struct awi_softc *sc = arg;
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
2000-03-22 14:22:20 +03:00
|
|
|
int s;
|
2000-06-09 09:31:15 +04:00
|
|
|
int ocansleep;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
DPRINTF(("awi_power: %d\n", why));
|
2000-03-22 14:22:20 +03:00
|
|
|
s = splnet();
|
2000-06-09 09:31:15 +04:00
|
|
|
ocansleep = sc->sc_cansleep;
|
|
|
|
sc->sc_cansleep = 0;
|
2000-11-26 14:08:57 +03:00
|
|
|
switch (why) {
|
|
|
|
case PWR_SUSPEND:
|
|
|
|
case PWR_STANDBY:
|
2001-06-28 14:40:04 +04:00
|
|
|
awi_stop(ifp, 1);
|
2000-11-26 14:08:57 +03:00
|
|
|
break;
|
|
|
|
case PWR_RESUME:
|
2001-06-28 14:40:04 +04:00
|
|
|
if (ifp->if_flags & IFF_UP) {
|
|
|
|
awi_init(ifp);
|
2001-09-18 13:09:57 +04:00
|
|
|
(void)awi_intr(sc); /* make sure */
|
2001-06-26 12:41:19 +04:00
|
|
|
}
|
2000-11-26 14:08:57 +03:00
|
|
|
break;
|
|
|
|
case PWR_SOFTSUSPEND:
|
|
|
|
case PWR_SOFTSTANDBY:
|
|
|
|
case PWR_SOFTRESUME:
|
|
|
|
break;
|
2000-06-09 09:31:15 +04:00
|
|
|
}
|
|
|
|
sc->sc_cansleep = ocansleep;
|
2000-03-22 14:22:20 +03:00
|
|
|
splx(s);
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif /* __NetBSD__ */
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
void
|
|
|
|
awi_shutdown(void *arg)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2001-09-18 13:09:57 +04:00
|
|
|
struct awi_softc *sc = arg;
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if (sc->sc_attached)
|
|
|
|
awi_stop(ifp, 1);
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_intr(void *arg)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
struct awi_softc *sc = arg;
|
|
|
|
u_int16_t status;
|
2003-10-30 04:58:17 +03:00
|
|
|
int handled = 0, ocansleep;
|
2001-09-18 13:09:57 +04:00
|
|
|
#ifdef AWI_DEBUG
|
|
|
|
static const char *intname[] = {
|
|
|
|
"CMD", "RX", "TX", "SCAN_CMPLT",
|
|
|
|
"CFP_START", "DTIM", "CFP_ENDING", "GROGGY",
|
|
|
|
"TXDATA", "TXBCAST", "TXPS", "TXCF",
|
|
|
|
"TXMGT", "#13", "RXDATA", "RXMGT"
|
|
|
|
};
|
|
|
|
#endif
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
if (!sc->sc_enabled || !sc->sc_enab_intr || sc->sc_invalid) {
|
|
|
|
DPRINTF(("awi_intr: stray interrupt: "
|
|
|
|
"enabled %d enab_intr %d invalid %d\n",
|
|
|
|
sc->sc_enabled, sc->sc_enab_intr, sc->sc_invalid));
|
2000-03-22 14:22:20 +03:00
|
|
|
return 0;
|
2004-01-15 12:39:15 +03:00
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
am79c930_gcr_setbits(&sc->sc_chip,
|
|
|
|
AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT);
|
|
|
|
awi_write_1(sc, AWI_DIS_PWRDN, 1);
|
|
|
|
ocansleep = sc->sc_cansleep;
|
|
|
|
sc->sc_cansleep = 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
for (;;) {
|
2003-10-30 04:58:17 +03:00
|
|
|
if (awi_intr_lock(sc) != 0)
|
2000-03-22 14:22:20 +03:00
|
|
|
break;
|
|
|
|
status = awi_read_1(sc, AWI_INTSTAT);
|
|
|
|
awi_write_1(sc, AWI_INTSTAT, 0);
|
|
|
|
awi_write_1(sc, AWI_INTSTAT, 0);
|
|
|
|
status |= awi_read_1(sc, AWI_INTSTAT2) << 8;
|
|
|
|
awi_write_1(sc, AWI_INTSTAT2, 0);
|
|
|
|
DELAY(10);
|
|
|
|
awi_intr_unlock(sc);
|
|
|
|
if (!sc->sc_cmd_inprog)
|
|
|
|
status &= ~AWI_INT_CMD; /* make sure */
|
|
|
|
if (status == 0)
|
|
|
|
break;
|
2001-09-18 13:09:57 +04:00
|
|
|
#ifdef AWI_DEBUG
|
|
|
|
if (awi_debug > 1) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf("awi_intr: status 0x%04x", status);
|
|
|
|
for (i = 0; i < sizeof(intname)/sizeof(intname[0]);
|
|
|
|
i++) {
|
|
|
|
if (status & (1 << i))
|
|
|
|
printf(" %s", intname[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
#endif
|
2000-03-22 14:22:20 +03:00
|
|
|
handled = 1;
|
|
|
|
if (status & AWI_INT_RX)
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_rx_int(sc);
|
2000-03-22 14:22:20 +03:00
|
|
|
if (status & AWI_INT_TX)
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_tx_int(sc);
|
2000-03-22 14:22:20 +03:00
|
|
|
if (status & AWI_INT_CMD)
|
|
|
|
awi_cmd_done(sc);
|
|
|
|
if (status & AWI_INT_SCAN_CMPLT) {
|
2002-08-05 10:55:05 +04:00
|
|
|
if (sc->sc_ic.ic_state == IEEE80211_S_SCAN &&
|
|
|
|
sc->sc_substate == AWI_ST_NONE)
|
2004-07-23 14:15:13 +04:00
|
|
|
ieee80211_next_scan(&sc->sc_ic);
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
sc->sc_cansleep = ocansleep;
|
|
|
|
am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN);
|
|
|
|
awi_write_1(sc, AWI_DIS_PWRDN, 0);
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
static void
|
|
|
|
awi_init0(void *arg)
|
|
|
|
{
|
|
|
|
struct awi_softc *sc = arg;
|
|
|
|
|
2005-06-22 10:14:51 +04:00
|
|
|
(void)awi_init(&sc->sc_if);
|
2004-01-15 12:39:15 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
static int
|
|
|
|
awi_init(struct ifnet *ifp)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2001-06-28 14:40:04 +04:00
|
|
|
struct awi_softc *sc = ifp->if_softc;
|
2001-09-18 13:09:57 +04:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2003-10-13 12:10:48 +04:00
|
|
|
struct ieee80211_node *ni = ic->ic_bss;
|
2004-01-15 16:29:05 +03:00
|
|
|
struct ieee80211_rateset *rs;
|
|
|
|
int error, rate, i;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
DPRINTF(("awi_init: enabled=%d\n", sc->sc_enabled));
|
|
|
|
if (sc->sc_enabled) {
|
|
|
|
awi_stop(ifp, 0);
|
|
|
|
} else {
|
2000-03-22 14:22:20 +03:00
|
|
|
if (sc->sc_enable)
|
|
|
|
(*sc->sc_enable)(sc);
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_enabled = 1;
|
|
|
|
if ((error = awi_hw_init(sc)) != 0) {
|
2004-01-15 12:39:15 +03:00
|
|
|
if (sc->sc_disable)
|
|
|
|
(*sc->sc_disable)(sc);
|
|
|
|
sc->sc_enabled = 0;
|
2000-03-22 14:22:20 +03:00
|
|
|
return error;
|
2001-06-28 14:40:04 +04:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
ic->ic_state = IEEE80211_S_INIT;
|
|
|
|
|
2002-09-30 19:48:41 +04:00
|
|
|
ic->ic_flags &= ~IEEE80211_F_IBSSON;
|
|
|
|
switch (ic->ic_opmode) {
|
|
|
|
case IEEE80211_M_STA:
|
|
|
|
sc->sc_mib_local.Network_Mode = 1;
|
|
|
|
sc->sc_mib_local.Acting_as_AP = 0;
|
|
|
|
break;
|
|
|
|
case IEEE80211_M_IBSS:
|
|
|
|
ic->ic_flags |= IEEE80211_F_IBSSON;
|
2004-01-15 12:39:15 +03:00
|
|
|
/* FALLTHRU */
|
2002-09-30 19:48:41 +04:00
|
|
|
case IEEE80211_M_AHDEMO:
|
|
|
|
sc->sc_mib_local.Network_Mode = 0;
|
|
|
|
sc->sc_mib_local.Acting_as_AP = 0;
|
|
|
|
break;
|
|
|
|
case IEEE80211_M_HOSTAP:
|
|
|
|
sc->sc_mib_local.Network_Mode = 1;
|
|
|
|
sc->sc_mib_local.Acting_as_AP = 1;
|
|
|
|
break;
|
2003-02-25 04:57:35 +03:00
|
|
|
case IEEE80211_M_MONITOR:
|
|
|
|
return ENODEV;
|
2002-09-30 19:48:41 +04:00
|
|
|
}
|
2004-01-15 12:39:15 +03:00
|
|
|
#if 0
|
2007-08-27 02:45:55 +04:00
|
|
|
IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl));
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
2002-07-25 11:15:50 +04:00
|
|
|
memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
|
|
|
|
sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
|
2002-09-03 18:54:00 +04:00
|
|
|
sc->sc_mib_mac.aDesired_ESS_ID[1] = ic->ic_des_esslen;
|
|
|
|
memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_essid,
|
|
|
|
ic->ic_des_esslen);
|
2001-09-18 13:09:57 +04:00
|
|
|
|
2004-01-15 16:29:05 +03:00
|
|
|
/* configure basic rate */
|
|
|
|
if (ic->ic_phytype == IEEE80211_T_FH)
|
|
|
|
rs = &ic->ic_sup_rates[IEEE80211_MODE_FH];
|
|
|
|
else
|
|
|
|
rs = &ic->ic_sup_rates[IEEE80211_MODE_11B];
|
|
|
|
if (ic->ic_fixed_rate != -1) {
|
|
|
|
rate = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
|
|
|
|
} else {
|
|
|
|
rate = 0;
|
|
|
|
for (i = 0; i < rs->rs_nrates; i++) {
|
|
|
|
if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
|
|
|
|
rate < (rs->rs_rates[i] & IEEE80211_RATE_VAL))
|
|
|
|
rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rate *= 5;
|
|
|
|
LE_WRITE_2(&sc->sc_mib_mac.aStation_Basic_Rate, rate);
|
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((error = awi_mode_init(sc)) != 0) {
|
|
|
|
DPRINTF(("awi_init: awi_mode_init failed %d\n", error));
|
2001-06-28 14:40:04 +04:00
|
|
|
awi_stop(ifp, 1);
|
2000-03-22 14:22:20 +03:00
|
|
|
return error;
|
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
/* start transmitter */
|
|
|
|
sc->sc_txdone = sc->sc_txnext = sc->sc_txbase;
|
|
|
|
awi_write_4(sc, sc->sc_txbase + AWI_TXD_START, 0);
|
|
|
|
awi_write_4(sc, sc->sc_txbase + AWI_TXD_NEXT, 0);
|
|
|
|
awi_write_4(sc, sc->sc_txbase + AWI_TXD_LENGTH, 0);
|
|
|
|
awi_write_1(sc, sc->sc_txbase + AWI_TXD_RATE, 0);
|
|
|
|
awi_write_4(sc, sc->sc_txbase + AWI_TXD_NDA, 0);
|
|
|
|
awi_write_4(sc, sc->sc_txbase + AWI_TXD_NRA, 0);
|
|
|
|
awi_write_1(sc, sc->sc_txbase + AWI_TXD_STATE, 0);
|
|
|
|
awi_write_4(sc, AWI_CA_TX_DATA, sc->sc_txbase);
|
|
|
|
awi_write_4(sc, AWI_CA_TX_MGT, 0);
|
|
|
|
awi_write_4(sc, AWI_CA_TX_BCAST, 0);
|
|
|
|
awi_write_4(sc, AWI_CA_TX_PS, 0);
|
|
|
|
awi_write_4(sc, AWI_CA_TX_CF, 0);
|
|
|
|
if ((error = awi_cmd(sc, AWI_CMD_INIT_TX, AWI_WAIT)) != 0) {
|
|
|
|
DPRINTF(("awi_init: failed to start transmitter: %d\n", error));
|
|
|
|
awi_stop(ifp, 1);
|
|
|
|
return error;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
/* start receiver */
|
|
|
|
if ((error = awi_cmd(sc, AWI_CMD_INIT_RX, AWI_WAIT)) != 0) {
|
|
|
|
DPRINTF(("awi_init: failed to start receiver: %d\n", error));
|
|
|
|
awi_stop(ifp, 1);
|
|
|
|
return error;
|
2000-06-09 09:31:15 +04:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_rxdoff = awi_read_4(sc, AWI_CA_IRX_DATA_DESC);
|
|
|
|
sc->sc_rxmoff = awi_read_4(sc, AWI_CA_IRX_PS_DESC);
|
|
|
|
|
|
|
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
|
ifp->if_flags &= ~IFF_OACTIVE;
|
2003-10-13 12:10:48 +04:00
|
|
|
ic->ic_state = IEEE80211_S_INIT;
|
2001-09-18 13:09:57 +04:00
|
|
|
|
2002-09-30 19:48:41 +04:00
|
|
|
if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
|
2002-09-27 09:36:04 +04:00
|
|
|
ic->ic_opmode == IEEE80211_M_HOSTAP) {
|
|
|
|
ni->ni_chan = ic->ic_ibss_chan;
|
|
|
|
ni->ni_intval = ic->ic_lintval;
|
|
|
|
ni->ni_rssi = 0;
|
|
|
|
ni->ni_rstamp = 0;
|
2005-06-22 10:14:51 +04:00
|
|
|
memset(&ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
|
2003-10-13 12:10:48 +04:00
|
|
|
ni->ni_rates =
|
|
|
|
ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
|
|
|
|
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
|
|
|
|
IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
|
|
|
|
ni->ni_esslen = ic->ic_des_esslen;
|
|
|
|
memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
|
|
|
|
ni->ni_capinfo = IEEE80211_CAPINFO_ESS;
|
|
|
|
if (ic->ic_phytype == IEEE80211_T_FH) {
|
|
|
|
ni->ni_fhdwell = 200; /* XXX */
|
|
|
|
ni->ni_fhindex = 1;
|
2002-09-02 17:37:35 +04:00
|
|
|
}
|
|
|
|
} else {
|
2002-09-27 09:36:04 +04:00
|
|
|
ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
|
|
|
|
memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN);
|
|
|
|
ni->ni_esslen = 0;
|
2002-09-02 17:37:35 +04:00
|
|
|
}
|
2004-07-23 12:31:39 +04:00
|
|
|
if (ic->ic_flags & IEEE80211_F_PRIVACY)
|
2002-09-27 09:36:04 +04:00
|
|
|
ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
|
2002-09-30 19:48:41 +04:00
|
|
|
if (ic->ic_opmode != IEEE80211_M_AHDEMO)
|
|
|
|
ic->ic_flags |= IEEE80211_F_SIBSS;
|
2001-09-18 13:09:57 +04:00
|
|
|
ic->ic_state = IEEE80211_S_SCAN; /*XXX*/
|
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
2003-10-13 12:10:48 +04:00
|
|
|
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
|
2001-09-18 13:09:57 +04:00
|
|
|
} else {
|
2003-10-13 12:10:48 +04:00
|
|
|
/* XXX check sc->sc_cur_chan */
|
|
|
|
ni->ni_chan = &ic->ic_channels[sc->sc_cur_chan];
|
|
|
|
ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
|
2001-06-28 14:40:04 +04:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
return 0;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_stop(struct ifnet *ifp, int disable)
|
2000-03-22 14:22:20 +03:00
|
|
|
{
|
|
|
|
struct awi_softc *sc = ifp->if_softc;
|
1999-11-08 18:45:00 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if (!sc->sc_enabled)
|
2000-03-22 14:22:20 +03:00
|
|
|
return;
|
1999-11-08 18:45:00 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
DPRINTF(("awi_stop(%d)\n", disable));
|
|
|
|
|
2003-10-13 12:10:48 +04:00
|
|
|
ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
if (!sc->sc_invalid) {
|
|
|
|
if (sc->sc_cmd_inprog)
|
|
|
|
(void)awi_cmd_wait(sc);
|
|
|
|
(void)awi_cmd(sc, AWI_CMD_KILL_RX, AWI_WAIT);
|
|
|
|
sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX;
|
|
|
|
awi_write_1(sc, AWI_CA_FTX_DATA, 1);
|
|
|
|
awi_write_1(sc, AWI_CA_FTX_MGT, 0);
|
|
|
|
awi_write_1(sc, AWI_CA_FTX_BCAST, 0);
|
|
|
|
awi_write_1(sc, AWI_CA_FTX_PS, 0);
|
|
|
|
awi_write_1(sc, AWI_CA_FTX_CF, 0);
|
|
|
|
(void)awi_cmd(sc, AWI_CMD_FLUSH_TX, AWI_WAIT);
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
|
|
|
|
ifp->if_timer = 0;
|
|
|
|
sc->sc_tx_timer = sc->sc_rx_timer = 0;
|
|
|
|
if (sc->sc_rxpend != NULL) {
|
|
|
|
m_freem(sc->sc_rxpend);
|
|
|
|
sc->sc_rxpend = NULL;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
IFQ_PURGE(&ifp->if_snd);
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if (disable) {
|
2004-01-15 12:39:15 +03:00
|
|
|
if (!sc->sc_invalid)
|
|
|
|
am79c930_gcr_setbits(&sc->sc_chip,
|
|
|
|
AM79C930_GCR_CORESET);
|
2001-09-18 13:09:57 +04:00
|
|
|
if (sc->sc_disable)
|
|
|
|
(*sc->sc_disable)(sc);
|
|
|
|
sc->sc_enabled = 0;
|
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_start(struct ifnet *ifp)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
struct awi_softc *sc = ifp->if_softc;
|
2001-09-18 13:09:57 +04:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ether_header *eh;
|
2003-10-13 12:10:48 +04:00
|
|
|
struct ieee80211_node *ni;
|
2002-09-27 09:36:04 +04:00
|
|
|
struct ieee80211_frame *wh;
|
2001-09-18 13:09:57 +04:00
|
|
|
struct mbuf *m, *m0;
|
2002-08-05 10:55:05 +04:00
|
|
|
int len, dowep;
|
2000-03-22 14:22:20 +03:00
|
|
|
u_int32_t txd, frame, ntxd;
|
|
|
|
u_int8_t rate;
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
if (!sc->sc_enabled || sc->sc_invalid)
|
|
|
|
return;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
for (;;) {
|
|
|
|
txd = sc->sc_txnext;
|
2001-09-18 13:09:57 +04:00
|
|
|
IF_POLL(&ic->ic_mgtq, m0);
|
2002-08-05 10:55:05 +04:00
|
|
|
dowep = 0;
|
2000-03-22 14:22:20 +03:00
|
|
|
if (m0 != NULL) {
|
2002-08-05 10:55:05 +04:00
|
|
|
len = m0->m_pkthdr.len;
|
|
|
|
if (awi_next_txd(sc, len, &frame, &ntxd)) {
|
2000-03-22 14:22:20 +03:00
|
|
|
ifp->if_flags |= IFF_OACTIVE;
|
|
|
|
break;
|
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
IF_DEQUEUE(&ic->ic_mgtq, m0);
|
2005-06-22 10:14:51 +04:00
|
|
|
ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
|
2000-03-22 14:22:20 +03:00
|
|
|
} else {
|
2001-09-18 13:09:57 +04:00
|
|
|
if (ic->ic_state != IEEE80211_S_RUN)
|
2000-03-22 14:22:20 +03:00
|
|
|
break;
|
2000-12-14 09:27:23 +03:00
|
|
|
IFQ_POLL(&ifp->if_snd, m0);
|
2000-03-22 14:22:20 +03:00
|
|
|
if (m0 == NULL)
|
|
|
|
break;
|
2001-09-18 13:09:57 +04:00
|
|
|
/*
|
|
|
|
* Need to calculate the real length to determine
|
|
|
|
* if the transmit buffer has a room for the packet.
|
|
|
|
*/
|
2000-06-09 09:31:15 +04:00
|
|
|
len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame);
|
2001-09-18 13:09:57 +04:00
|
|
|
if (!(ifp->if_flags & IFF_LINK0) && !sc->sc_adhoc_ap)
|
2000-06-09 09:31:15 +04:00
|
|
|
len += sizeof(struct llc) -
|
|
|
|
sizeof(struct ether_header);
|
2004-07-23 12:31:39 +04:00
|
|
|
if (ic->ic_flags & IEEE80211_F_PRIVACY) {
|
2002-08-05 10:55:05 +04:00
|
|
|
dowep = 1;
|
2000-06-09 09:31:15 +04:00
|
|
|
len += IEEE80211_WEP_IVLEN +
|
|
|
|
IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
|
2002-08-05 10:55:05 +04:00
|
|
|
}
|
2000-06-09 09:31:15 +04:00
|
|
|
if (awi_next_txd(sc, len, &frame, &ntxd)) {
|
2000-03-22 14:22:20 +03:00
|
|
|
ifp->if_flags |= IFF_OACTIVE;
|
|
|
|
break;
|
|
|
|
}
|
2000-12-14 09:27:23 +03:00
|
|
|
IFQ_DEQUEUE(&ifp->if_snd, m0);
|
2001-09-18 13:09:57 +04:00
|
|
|
ifp->if_opackets++;
|
|
|
|
#if NBPFILTER > 0
|
|
|
|
if (ifp->if_bpf)
|
|
|
|
bpf_mtap(ifp->if_bpf, m0);
|
2001-06-25 16:09:51 +04:00
|
|
|
#endif
|
2005-06-22 10:14:51 +04:00
|
|
|
eh = mtod(m0, struct ether_header *);
|
|
|
|
ni = ieee80211_find_txnode(ic, eh->ether_dhost);
|
|
|
|
if (ni == NULL) {
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
continue;
|
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((ifp->if_flags & IFF_LINK0) || sc->sc_adhoc_ap)
|
|
|
|
m0 = awi_ether_encap(sc, m0);
|
2005-06-22 10:14:51 +04:00
|
|
|
else {
|
|
|
|
m0 = ieee80211_encap(ic, m0, ni);
|
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
if (m0 == NULL) {
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_free_node(ni);
|
2000-03-22 14:22:20 +03:00
|
|
|
ifp->if_oerrors++;
|
|
|
|
continue;
|
|
|
|
}
|
2002-09-27 09:36:04 +04:00
|
|
|
wh = mtod(m0, struct ieee80211_frame *);
|
|
|
|
if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
|
2002-09-30 19:48:41 +04:00
|
|
|
(ic->ic_opmode == IEEE80211_M_HOSTAP ||
|
|
|
|
ic->ic_opmode == IEEE80211_M_IBSS) &&
|
2002-09-27 09:36:04 +04:00
|
|
|
sc->sc_adhoc_ap == 0 &&
|
|
|
|
(ifp->if_flags & IFF_LINK0) == 0 &&
|
|
|
|
(wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
|
2006-04-15 00:33:57 +04:00
|
|
|
IEEE80211_FC0_TYPE_DATA) {
|
2002-09-27 09:36:04 +04:00
|
|
|
m_freem(m0);
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_free_node(ni);
|
2002-09-27 09:36:04 +04:00
|
|
|
ifp->if_oerrors++;
|
|
|
|
continue;
|
|
|
|
}
|
2002-08-05 10:55:05 +04:00
|
|
|
}
|
2002-08-28 13:38:08 +04:00
|
|
|
#if NBPFILTER > 0
|
|
|
|
if (ic->ic_rawbpf)
|
|
|
|
bpf_mtap(ic->ic_rawbpf, m0);
|
|
|
|
#endif
|
2002-08-05 10:55:05 +04:00
|
|
|
if (dowep) {
|
2005-06-22 10:14:51 +04:00
|
|
|
if ((ieee80211_crypto_encap(ic, ni, m0)) == NULL) {
|
|
|
|
m_freem(m0);
|
|
|
|
ieee80211_free_node(ni);
|
2001-09-18 13:09:57 +04:00
|
|
|
ifp->if_oerrors++;
|
|
|
|
continue;
|
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_free_node(ni);
|
2002-08-05 10:55:05 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (m0->m_pkthdr.len != len) {
|
|
|
|
printf("%s: length %d should be %d\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname, m0->m_pkthdr.len, len);
|
2002-08-05 10:55:05 +04:00
|
|
|
m_freem(m0);
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
if ((ifp->if_flags & IFF_DEBUG) && (ifp->if_flags & IFF_LINK2))
|
|
|
|
ieee80211_dump_pkt(m0->m_data, m0->m_len,
|
2003-10-13 12:10:48 +04:00
|
|
|
ic->ic_bss->ni_rates.
|
|
|
|
rs_rates[ic->ic_bss->ni_txrate] &
|
2001-09-18 13:09:57 +04:00
|
|
|
IEEE80211_RATE_VAL, -1);
|
|
|
|
|
|
|
|
for (m = m0, len = 0; m != NULL; m = m->m_next) {
|
2000-03-22 14:22:20 +03:00
|
|
|
awi_write_bytes(sc, frame + len, mtod(m, u_int8_t *),
|
|
|
|
m->m_len);
|
|
|
|
len += m->m_len;
|
|
|
|
}
|
|
|
|
m_freem(m0);
|
2003-10-13 12:10:48 +04:00
|
|
|
rate = (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
|
2001-09-18 13:09:57 +04:00
|
|
|
IEEE80211_RATE_VAL) * 5;
|
2000-03-22 14:22:20 +03:00
|
|
|
awi_write_1(sc, ntxd + AWI_TXD_STATE, 0);
|
|
|
|
awi_write_4(sc, txd + AWI_TXD_START, frame);
|
|
|
|
awi_write_4(sc, txd + AWI_TXD_NEXT, ntxd);
|
|
|
|
awi_write_4(sc, txd + AWI_TXD_LENGTH, len);
|
|
|
|
awi_write_1(sc, txd + AWI_TXD_RATE, rate);
|
|
|
|
awi_write_4(sc, txd + AWI_TXD_NDA, 0);
|
|
|
|
awi_write_4(sc, txd + AWI_TXD_NRA, 0);
|
|
|
|
awi_write_1(sc, txd + AWI_TXD_STATE, AWI_TXD_ST_OWN);
|
|
|
|
sc->sc_txnext = ntxd;
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
sc->sc_tx_timer = 5;
|
2000-03-22 14:22:20 +03:00
|
|
|
ifp->if_timer = 1;
|
|
|
|
}
|
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_watchdog(struct ifnet *ifp)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2001-09-18 13:09:57 +04:00
|
|
|
struct awi_softc *sc = ifp->if_softc;
|
|
|
|
u_int32_t prevdone;
|
|
|
|
int ocansleep;
|
2000-03-22 14:22:20 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
ifp->if_timer = 0;
|
|
|
|
if (!sc->sc_enabled || sc->sc_invalid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ocansleep = sc->sc_cansleep;
|
|
|
|
sc->sc_cansleep = 0;
|
|
|
|
if (sc->sc_tx_timer) {
|
|
|
|
if (--sc->sc_tx_timer == 0) {
|
|
|
|
printf("%s: device timeout\n", ifp->if_xname);
|
|
|
|
prevdone = sc->sc_txdone;
|
|
|
|
awi_tx_int(sc);
|
|
|
|
if (sc->sc_txdone == prevdone) {
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
awi_init(ifp);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ifp->if_timer = 1;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
if (sc->sc_rx_timer) {
|
|
|
|
if (--sc->sc_rx_timer == 0) {
|
|
|
|
if (sc->sc_ic.ic_state == IEEE80211_S_RUN) {
|
2003-10-13 12:10:48 +04:00
|
|
|
ieee80211_new_state(&sc->sc_ic,
|
|
|
|
IEEE80211_S_SCAN, -1);
|
2001-09-18 13:09:57 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
ifp->if_timer = 1;
|
|
|
|
}
|
|
|
|
/* TODO: rate control */
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_watchdog(&sc->sc_ic);
|
2001-09-18 13:09:57 +04:00
|
|
|
out:
|
|
|
|
sc->sc_cansleep = ocansleep;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
static int
|
2007-03-04 08:59:00 +03:00
|
|
|
awi_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2001-09-18 13:09:57 +04:00
|
|
|
struct awi_softc *sc = ifp->if_softc;
|
|
|
|
struct ifreq *ifr = (struct ifreq *)data;
|
|
|
|
int s, error;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
s = splnet();
|
|
|
|
/* serialize ioctl, since we may sleep */
|
|
|
|
if ((error = awi_lock(sc)) != 0)
|
|
|
|
goto cantlock;
|
2000-03-22 14:22:20 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
switch (cmd) {
|
|
|
|
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, cmd, data)) != 0)
|
|
|
|
break;
|
2001-09-18 13:09:57 +04:00
|
|
|
if (ifp->if_flags & IFF_UP) {
|
|
|
|
if (sc->sc_enabled) {
|
|
|
|
/*
|
|
|
|
* To avoid rescanning another access point,
|
|
|
|
* do not call awi_init() here. Instead,
|
|
|
|
* only reflect promisc mode settings.
|
|
|
|
*/
|
|
|
|
error = awi_mode_init(sc);
|
|
|
|
} else
|
|
|
|
error = awi_init(ifp);
|
|
|
|
} else if (sc->sc_enabled)
|
|
|
|
awi_stop(ifp, 1);
|
|
|
|
break;
|
|
|
|
case SIOCSIFMEDIA:
|
|
|
|
case SIOCGIFMEDIA:
|
2003-07-07 00:01:17 +04:00
|
|
|
error = ifmedia_ioctl(ifp, ifr, &sc->sc_ic.ic_media, cmd);
|
2001-09-18 13:09:57 +04:00
|
|
|
break;
|
|
|
|
case SIOCADDMULTI:
|
|
|
|
case SIOCDELMULTI:
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
error = ENETRESET; /* XXX */
|
|
|
|
#else
|
2007-09-01 11:32:22 +04:00
|
|
|
error = ether_ioctl(ifp, cmd, data);
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
2001-09-18 13:09:57 +04:00
|
|
|
if (error == ENETRESET) {
|
|
|
|
/* do not rescan */
|
2004-10-30 22:08:34 +04:00
|
|
|
if (ifp->if_flags & IFF_RUNNING)
|
2001-09-18 13:09:57 +04:00
|
|
|
error = awi_mode_init(sc);
|
|
|
|
else
|
|
|
|
error = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2005-06-22 10:14:51 +04:00
|
|
|
error = ieee80211_ioctl(&sc->sc_ic, cmd, data);
|
2001-09-18 13:09:57 +04:00
|
|
|
if (error == ENETRESET) {
|
|
|
|
if (sc->sc_enabled)
|
|
|
|
error = awi_init(ifp);
|
|
|
|
else
|
|
|
|
error = 0;
|
|
|
|
}
|
|
|
|
break;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_unlock(sc);
|
|
|
|
cantlock:
|
|
|
|
splx(s);
|
|
|
|
return error;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
/*
|
|
|
|
* Called from ifmedia_ioctl via awi_ioctl with lock obtained.
|
2003-10-13 12:10:48 +04:00
|
|
|
*
|
|
|
|
* TBD factor with ieee80211_media_change
|
2001-09-18 13:09:57 +04:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
awi_media_change(struct ifnet *ifp)
|
2000-03-22 14:22:20 +03:00
|
|
|
{
|
2001-09-18 13:09:57 +04:00
|
|
|
struct awi_softc *sc = ifp->if_softc;
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
struct ifmedia_entry *ime;
|
2002-09-30 19:48:41 +04:00
|
|
|
enum ieee80211_opmode newmode;
|
|
|
|
int i, rate, newadhoc_ap, error = 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2003-07-07 00:01:17 +04:00
|
|
|
ime = ic->ic_media.ifm_cur;
|
2001-09-18 13:09:57 +04:00
|
|
|
if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
|
2002-09-30 19:48:41 +04:00
|
|
|
i = -1;
|
2001-09-18 13:09:57 +04:00
|
|
|
} else {
|
2003-10-13 12:10:48 +04:00
|
|
|
struct ieee80211_rateset *rs =
|
2004-01-15 12:39:15 +03:00
|
|
|
&ic->ic_sup_rates[(ic->ic_phytype == IEEE80211_T_FH)
|
|
|
|
? IEEE80211_MODE_FH : IEEE80211_MODE_11B];
|
2003-10-13 12:10:48 +04:00
|
|
|
rate = ieee80211_media2rate(ime->ifm_media);
|
2001-09-18 13:09:57 +04:00
|
|
|
if (rate == 0)
|
|
|
|
return EINVAL;
|
2003-10-13 12:10:48 +04:00
|
|
|
for (i = 0; i < rs->rs_nrates; i++) {
|
|
|
|
if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate)
|
2001-09-18 13:09:57 +04:00
|
|
|
break;
|
|
|
|
}
|
2003-10-13 12:10:48 +04:00
|
|
|
if (i == rs->rs_nrates)
|
2001-09-18 13:09:57 +04:00
|
|
|
return EINVAL;
|
2002-09-30 19:48:41 +04:00
|
|
|
}
|
|
|
|
if (ic->ic_fixed_rate != i) {
|
2001-09-18 13:09:57 +04:00
|
|
|
ic->ic_fixed_rate = i;
|
2002-09-30 19:48:41 +04:00
|
|
|
error = ENETRESET;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
/*
|
2002-09-27 09:36:04 +04:00
|
|
|
* combination of mediaopt
|
|
|
|
*
|
2002-09-30 19:48:41 +04:00
|
|
|
* hostap adhoc flag0 opmode adhoc_ap comment
|
|
|
|
* + - - HOSTAP 0 HostAP
|
|
|
|
* - + - IBSS 0 IBSS
|
|
|
|
* - + + AHDEMO 0 WaveLAN adhoc
|
|
|
|
* - - + IBSS 1 Melco old Sta
|
2002-09-27 09:36:04 +04:00
|
|
|
* also LINK0
|
2002-09-30 19:48:41 +04:00
|
|
|
* - - - STA 0 Infra Station
|
2001-09-18 13:09:57 +04:00
|
|
|
*/
|
2002-09-30 19:48:41 +04:00
|
|
|
newadhoc_ap = 0;
|
|
|
|
if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
|
|
|
|
newmode = IEEE80211_M_HOSTAP;
|
|
|
|
else if (ime->ifm_media & IFM_IEEE80211_ADHOC) {
|
2002-09-27 09:36:04 +04:00
|
|
|
if (ic->ic_phytype == IEEE80211_T_DS &&
|
2002-09-30 19:48:41 +04:00
|
|
|
(ime->ifm_media & IFM_FLAG0))
|
|
|
|
newmode = IEEE80211_M_AHDEMO;
|
|
|
|
else
|
|
|
|
newmode = IEEE80211_M_IBSS;
|
2002-09-02 17:37:35 +04:00
|
|
|
} else if (ime->ifm_media & IFM_FLAG0) {
|
2002-09-30 19:48:41 +04:00
|
|
|
newmode = IEEE80211_M_IBSS;
|
|
|
|
newadhoc_ap = 1;
|
|
|
|
} else
|
|
|
|
newmode = IEEE80211_M_STA;
|
|
|
|
if (ic->ic_opmode != newmode || sc->sc_adhoc_ap != newadhoc_ap) {
|
|
|
|
ic->ic_opmode = newmode;
|
|
|
|
sc->sc_adhoc_ap = newadhoc_ap;
|
|
|
|
error = ENETRESET;
|
2000-07-04 18:27:56 +04:00
|
|
|
}
|
2002-09-30 19:48:41 +04:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if (error == ENETRESET) {
|
|
|
|
if (sc->sc_enabled)
|
|
|
|
error = awi_init(ifp);
|
|
|
|
else
|
|
|
|
error = 0;
|
|
|
|
}
|
|
|
|
return error;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2001-09-18 13:09:57 +04:00
|
|
|
struct awi_softc *sc = ifp->if_softc;
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
int rate;
|
2004-01-15 12:39:15 +03:00
|
|
|
enum ieee80211_phymode mode;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
imr->ifm_status = IFM_AVALID;
|
|
|
|
if (ic->ic_state == IEEE80211_S_RUN)
|
|
|
|
imr->ifm_status |= IFM_ACTIVE;
|
|
|
|
imr->ifm_active = IFM_IEEE80211;
|
2004-01-15 12:39:15 +03:00
|
|
|
if (ic->ic_phytype == IEEE80211_T_FH)
|
|
|
|
mode = IEEE80211_MODE_FH;
|
|
|
|
else
|
|
|
|
mode = IEEE80211_MODE_11B;
|
2003-10-13 12:10:48 +04:00
|
|
|
if (ic->ic_state == IEEE80211_S_RUN) {
|
|
|
|
rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
|
2001-09-18 13:09:57 +04:00
|
|
|
IEEE80211_RATE_VAL;
|
2003-10-13 12:10:48 +04:00
|
|
|
} else {
|
2001-09-18 13:09:57 +04:00
|
|
|
if (ic->ic_fixed_rate == -1)
|
|
|
|
rate = 0;
|
|
|
|
else
|
2004-01-15 12:39:15 +03:00
|
|
|
rate = ic->ic_sup_rates[mode].
|
2003-10-13 12:10:48 +04:00
|
|
|
rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2004-01-15 12:39:15 +03:00
|
|
|
imr->ifm_active |= ieee80211_rate2media(ic, rate, mode);
|
2002-09-27 09:36:04 +04:00
|
|
|
switch (ic->ic_opmode) {
|
2003-02-25 04:57:35 +03:00
|
|
|
case IEEE80211_M_MONITOR: /* we should never reach here */
|
|
|
|
break;
|
2002-09-27 09:36:04 +04:00
|
|
|
case IEEE80211_M_STA:
|
|
|
|
break;
|
2002-09-30 19:48:41 +04:00
|
|
|
case IEEE80211_M_IBSS:
|
2001-09-18 13:09:57 +04:00
|
|
|
if (sc->sc_adhoc_ap)
|
|
|
|
imr->ifm_active |= IFM_FLAG0;
|
2002-09-30 19:48:41 +04:00
|
|
|
else
|
2001-09-18 13:09:57 +04:00
|
|
|
imr->ifm_active |= IFM_IEEE80211_ADHOC;
|
2002-09-30 19:48:41 +04:00
|
|
|
break;
|
|
|
|
case IEEE80211_M_AHDEMO:
|
|
|
|
imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
|
2002-09-27 09:36:04 +04:00
|
|
|
break;
|
|
|
|
case IEEE80211_M_HOSTAP:
|
|
|
|
imr->ifm_active |= IFM_IEEE80211_HOSTAP;
|
|
|
|
break;
|
2000-06-09 09:31:15 +04:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
static int
|
|
|
|
awi_mode_init(struct awi_softc *sc)
|
|
|
|
{
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
2001-09-18 13:09:57 +04:00
|
|
|
int n, error;
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct ifmultiaddr *ifma;
|
|
|
|
#else
|
2001-09-18 13:09:57 +04:00
|
|
|
struct ether_multi *enm;
|
|
|
|
struct ether_multistep step;
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
/* reinitialize muticast filter */
|
|
|
|
n = 0;
|
|
|
|
sc->sc_mib_local.Accept_All_Multicast_Dis = 0;
|
2002-09-27 09:36:04 +04:00
|
|
|
if (sc->sc_ic.ic_opmode != IEEE80211_M_HOSTAP &&
|
2002-09-03 18:54:00 +04:00
|
|
|
(ifp->if_flags & IFF_PROMISC)) {
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_mib_mac.aPromiscuous_Enable = 1;
|
|
|
|
goto set_mib;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_mib_mac.aPromiscuous_Enable = 0;
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (ifp->if_amcount != 0)
|
|
|
|
goto set_mib;
|
|
|
|
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
|
|
|
|
if (ifma->ifma_addr->sa_family != AF_LINK)
|
|
|
|
continue;
|
|
|
|
if (n == AWI_GROUP_ADDR_SIZE)
|
|
|
|
goto set_mib;
|
|
|
|
IEEE80211_ADDR_COPY(sc->sc_mib_addr.aGroup_Addresses[n],
|
2007-08-27 02:45:55 +04:00
|
|
|
CLLADDR(satocsdl(ifma->ifma_addr)));
|
2004-01-15 12:39:15 +03:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
#else
|
2005-06-22 10:14:51 +04:00
|
|
|
ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
|
2001-09-18 13:09:57 +04:00
|
|
|
while (enm != NULL) {
|
|
|
|
if (n == AWI_GROUP_ADDR_SIZE ||
|
2002-09-27 09:36:04 +04:00
|
|
|
!IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi))
|
2001-09-18 13:09:57 +04:00
|
|
|
goto set_mib;
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(sc->sc_mib_addr.aGroup_Addresses[n],
|
|
|
|
enm->enm_addrlo);
|
2001-09-18 13:09:57 +04:00
|
|
|
n++;
|
|
|
|
ETHER_NEXT_MULTI(step, enm);
|
|
|
|
}
|
2004-01-15 12:39:15 +03:00
|
|
|
#endif
|
2001-09-18 13:09:57 +04:00
|
|
|
for (; n < AWI_GROUP_ADDR_SIZE; n++)
|
2002-09-27 09:36:04 +04:00
|
|
|
memset(sc->sc_mib_addr.aGroup_Addresses[n], 0,
|
|
|
|
IEEE80211_ADDR_LEN);
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
|
|
|
|
|
|
|
|
set_mib:
|
|
|
|
if (sc->sc_mib_local.Accept_All_Multicast_Dis)
|
|
|
|
ifp->if_flags &= ~IFF_ALLMULTI;
|
|
|
|
else
|
|
|
|
ifp->if_flags |= IFF_ALLMULTI;
|
|
|
|
sc->sc_mib_mgt.Wep_Required =
|
2004-07-23 12:31:39 +04:00
|
|
|
(sc->sc_ic.ic_flags & IEEE80211_F_PRIVACY) ? AWI_WEP_ON : AWI_WEP_OFF;
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_LOCAL, AWI_WAIT)) ||
|
|
|
|
(error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_ADDR, AWI_WAIT)) ||
|
|
|
|
(error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MAC, AWI_WAIT)) ||
|
|
|
|
(error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT, AWI_WAIT)) ||
|
|
|
|
(error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_PHY, AWI_WAIT))) {
|
|
|
|
DPRINTF(("awi_mode_init: MIB set failed: %d\n", error));
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_rx_int(struct awi_softc *sc)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2003-10-13 12:10:48 +04:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
|
|
|
struct ieee80211_frame_min *wh;
|
2003-10-13 12:10:48 +04:00
|
|
|
struct ieee80211_node *ni;
|
2000-03-22 14:22:20 +03:00
|
|
|
u_int8_t state, rate, rssi;
|
|
|
|
u_int16_t len;
|
2002-08-05 10:55:05 +04:00
|
|
|
u_int32_t frame, next, rstamp, rxoff;
|
2000-03-22 14:22:20 +03:00
|
|
|
struct mbuf *m;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
rxoff = sc->sc_rxdoff;
|
|
|
|
for (;;) {
|
|
|
|
state = awi_read_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE);
|
|
|
|
if (state & AWI_RXD_ST_OWN)
|
|
|
|
break;
|
|
|
|
if (!(state & AWI_RXD_ST_CONSUMED)) {
|
2002-08-05 10:55:05 +04:00
|
|
|
if (sc->sc_substate != AWI_ST_NONE)
|
|
|
|
goto rx_next;
|
2001-09-18 13:09:57 +04:00
|
|
|
if (state & AWI_RXD_ST_RXERROR) {
|
|
|
|
ifp->if_ierrors++;
|
|
|
|
goto rx_next;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
len = awi_read_2(sc, rxoff + AWI_RXD_LEN);
|
|
|
|
rate = awi_read_1(sc, rxoff + AWI_RXD_RATE);
|
|
|
|
rssi = awi_read_1(sc, rxoff + AWI_RXD_RSSI);
|
|
|
|
frame = awi_read_4(sc, rxoff + AWI_RXD_START_FRAME) &
|
|
|
|
0x7fff;
|
2002-08-05 10:55:05 +04:00
|
|
|
rstamp = awi_read_4(sc, rxoff + AWI_RXD_LOCALTIME);
|
2001-09-18 13:09:57 +04:00
|
|
|
m = awi_devget(sc, frame, len);
|
|
|
|
if (m == NULL) {
|
|
|
|
ifp->if_ierrors++;
|
|
|
|
goto rx_next;
|
|
|
|
}
|
|
|
|
if (state & AWI_RXD_ST_LF) {
|
|
|
|
/* TODO check my bss */
|
|
|
|
if (!(sc->sc_ic.ic_flags & IEEE80211_F_SIBSS) &&
|
|
|
|
sc->sc_ic.ic_state == IEEE80211_S_RUN) {
|
|
|
|
sc->sc_rx_timer = 10;
|
|
|
|
ifp->if_timer = 1;
|
|
|
|
}
|
|
|
|
if ((ifp->if_flags & IFF_DEBUG) &&
|
|
|
|
(ifp->if_flags & IFF_LINK2))
|
|
|
|
ieee80211_dump_pkt(m->m_data, m->m_len,
|
|
|
|
rate / 5, rssi);
|
|
|
|
if ((ifp->if_flags & IFF_LINK0) ||
|
|
|
|
sc->sc_adhoc_ap)
|
|
|
|
m = awi_ether_modcap(sc, m);
|
2003-10-13 12:10:48 +04:00
|
|
|
else
|
|
|
|
m = m_pullup(m, sizeof(*wh));
|
|
|
|
if (m == NULL) {
|
2001-09-18 13:09:57 +04:00
|
|
|
ifp->if_ierrors++;
|
2003-10-13 12:10:48 +04:00
|
|
|
goto rx_next;
|
|
|
|
}
|
2005-06-22 10:14:51 +04:00
|
|
|
wh = mtod(m, struct ieee80211_frame_min *);
|
2003-11-02 04:55:40 +03:00
|
|
|
ni = ieee80211_find_rxnode(ic, wh);
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_input(ic, m, ni, rssi, rstamp);
|
2003-10-13 12:10:48 +04:00
|
|
|
/*
|
|
|
|
* The frame may have caused the
|
|
|
|
* node to be marked for reclamation
|
|
|
|
* (e.g. in response to a DEAUTH
|
2004-08-10 04:57:20 +04:00
|
|
|
* message) so use release_node here
|
2003-10-13 12:10:48 +04:00
|
|
|
* instead of unref_node.
|
|
|
|
*/
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_free_node(ni);
|
2001-09-18 13:09:57 +04:00
|
|
|
} else
|
|
|
|
sc->sc_rxpend = m;
|
|
|
|
rx_next:
|
2000-03-22 14:22:20 +03:00
|
|
|
state |= AWI_RXD_ST_CONSUMED;
|
|
|
|
awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state);
|
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
next = awi_read_4(sc, rxoff + AWI_RXD_NEXT);
|
2000-03-22 14:22:20 +03:00
|
|
|
if (next & AWI_RXD_NEXT_LAST)
|
|
|
|
break;
|
|
|
|
/* make sure the next pointer is correct */
|
|
|
|
if (next != awi_read_4(sc, rxoff + AWI_RXD_NEXT))
|
|
|
|
break;
|
|
|
|
state |= AWI_RXD_ST_OWN;
|
|
|
|
awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state);
|
|
|
|
rxoff = next & 0x7fff;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_rxdoff = rxoff;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
awi_tx_int(struct awi_softc *sc)
|
|
|
|
{
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
2001-09-18 13:09:57 +04:00
|
|
|
u_int8_t flags;
|
|
|
|
|
|
|
|
while (sc->sc_txdone != sc->sc_txnext) {
|
|
|
|
flags = awi_read_1(sc, sc->sc_txdone + AWI_TXD_STATE);
|
|
|
|
if ((flags & AWI_TXD_ST_OWN) || !(flags & AWI_TXD_ST_DONE))
|
|
|
|
break;
|
|
|
|
if (flags & AWI_TXD_ST_ERROR)
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
sc->sc_txdone = awi_read_4(sc, sc->sc_txdone + AWI_TXD_NEXT) &
|
|
|
|
0x7fff;
|
|
|
|
}
|
|
|
|
DPRINTF2(("awi_txint: txdone %d txnext %d txbase %d txend %d\n",
|
|
|
|
sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend));
|
|
|
|
sc->sc_tx_timer = 0;
|
|
|
|
ifp->if_flags &= ~IFF_OACTIVE;
|
|
|
|
awi_start(ifp);
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-06-09 09:31:15 +04:00
|
|
|
static struct mbuf *
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_devget(struct awi_softc *sc, u_int32_t off, u_int16_t len)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
2000-03-22 14:22:20 +03:00
|
|
|
struct mbuf *m;
|
2000-06-09 09:31:15 +04:00
|
|
|
struct mbuf *top, **mp;
|
2000-03-22 14:22:20 +03:00
|
|
|
u_int tlen;
|
|
|
|
|
|
|
|
top = sc->sc_rxpend;
|
2000-06-09 09:31:15 +04:00
|
|
|
mp = ⊤
|
2000-03-22 14:22:20 +03:00
|
|
|
if (top != NULL) {
|
|
|
|
sc->sc_rxpend = NULL;
|
|
|
|
top->m_pkthdr.len += len;
|
2000-07-04 18:27:56 +04:00
|
|
|
m = top;
|
2000-06-09 09:31:15 +04:00
|
|
|
while (*mp != NULL) {
|
|
|
|
m = *mp;
|
2000-03-22 14:22:20 +03:00
|
|
|
mp = &m->m_next;
|
2000-06-09 09:31:15 +04:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
if (m->m_flags & M_EXT)
|
|
|
|
tlen = m->m_ext.ext_size;
|
|
|
|
else if (m->m_flags & M_PKTHDR)
|
|
|
|
tlen = MHLEN;
|
|
|
|
else
|
|
|
|
tlen = MLEN;
|
|
|
|
tlen -= m->m_len;
|
|
|
|
if (tlen > len)
|
|
|
|
tlen = len;
|
|
|
|
awi_read_bytes(sc, off, mtod(m, u_int8_t *) + m->m_len, tlen);
|
|
|
|
off += tlen;
|
|
|
|
len -= tlen;
|
1999-11-09 17:58:07 +03:00
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
while (len > 0) {
|
|
|
|
if (top == NULL) {
|
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
|
|
|
if (m == NULL)
|
|
|
|
return NULL;
|
2001-09-18 13:09:57 +04:00
|
|
|
m->m_pkthdr.rcvif = ifp;
|
2000-03-22 14:22:20 +03:00
|
|
|
m->m_pkthdr.len = len;
|
|
|
|
m->m_len = MHLEN;
|
2001-09-18 13:09:57 +04:00
|
|
|
m->m_flags |= M_HASFCS;
|
2000-03-22 14:22:20 +03:00
|
|
|
} else {
|
|
|
|
MGET(m, M_DONTWAIT, MT_DATA);
|
|
|
|
if (m == NULL) {
|
|
|
|
m_freem(top);
|
|
|
|
return NULL;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
m->m_len = MLEN;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
if (len >= MINCLSIZE) {
|
|
|
|
MCLGET(m, M_DONTWAIT);
|
|
|
|
if (m->m_flags & M_EXT)
|
|
|
|
m->m_len = m->m_ext.ext_size;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-07-04 18:27:56 +04:00
|
|
|
if (top == NULL) {
|
|
|
|
int hdrlen = sizeof(struct ieee80211_frame) +
|
2001-09-18 13:09:57 +04:00
|
|
|
sizeof(struct llc);
|
2007-03-04 08:59:00 +03:00
|
|
|
char *newdata = (char *)
|
2000-07-04 18:27:56 +04:00
|
|
|
ALIGN(m->m_data + hdrlen) - hdrlen;
|
|
|
|
m->m_len -= newdata - m->m_data;
|
|
|
|
m->m_data = newdata;
|
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
if (m->m_len > len)
|
|
|
|
m->m_len = len;
|
|
|
|
awi_read_bytes(sc, off, mtod(m, u_int8_t *), m->m_len);
|
|
|
|
off += m->m_len;
|
|
|
|
len -= m->m_len;
|
|
|
|
*mp = m;
|
|
|
|
mp = &m->m_next;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
return top;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
/*
|
|
|
|
* Initialize hardware and start firmware to accept commands.
|
|
|
|
* Called everytime after power on firmware.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_hw_init(struct awi_softc *sc)
|
1999-11-09 17:58:07 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
u_int8_t status;
|
|
|
|
u_int16_t intmask;
|
|
|
|
int i, error;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-27 16:54:59 +04:00
|
|
|
sc->sc_enab_intr = 0;
|
2000-07-04 18:27:56 +04:00
|
|
|
sc->sc_invalid = 0; /* XXX: really? */
|
2000-03-22 14:22:20 +03:00
|
|
|
awi_drvstate(sc, AWI_DRV_RESET);
|
1999-11-09 17:58:07 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
/* reset firmware */
|
|
|
|
am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_CORESET);
|
|
|
|
DELAY(100);
|
|
|
|
awi_write_1(sc, AWI_SELFTEST, 0);
|
2000-07-04 18:27:56 +04:00
|
|
|
awi_write_1(sc, AWI_CMD, 0);
|
|
|
|
awi_write_1(sc, AWI_BANNER, 0);
|
2000-03-22 14:22:20 +03:00
|
|
|
am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_CORESET);
|
|
|
|
DELAY(100);
|
|
|
|
|
|
|
|
/* wait for selftest completion */
|
|
|
|
for (i = 0; ; i++) {
|
2004-01-15 12:39:15 +03:00
|
|
|
if (sc->sc_invalid)
|
|
|
|
return ENXIO;
|
2000-03-22 14:22:20 +03:00
|
|
|
if (i >= AWI_SELFTEST_TIMEOUT*hz/1000) {
|
|
|
|
printf("%s: failed to complete selftest (timeout)\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname);
|
2000-03-22 14:22:20 +03:00
|
|
|
return ENXIO;
|
|
|
|
}
|
|
|
|
status = awi_read_1(sc, AWI_SELFTEST);
|
|
|
|
if ((status & 0xf0) == 0xf0)
|
1999-11-09 17:58:07 +03:00
|
|
|
break;
|
2000-03-22 14:22:20 +03:00
|
|
|
if (sc->sc_cansleep) {
|
|
|
|
sc->sc_sleep_cnt++;
|
|
|
|
(void)tsleep(sc, PWAIT, "awitst", 1);
|
|
|
|
sc->sc_sleep_cnt--;
|
|
|
|
} else {
|
|
|
|
DELAY(1000*1000/hz);
|
1999-11-09 17:58:07 +03:00
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
if (status != AWI_SELFTEST_PASSED) {
|
|
|
|
printf("%s: failed to complete selftest (code %x)\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname, status);
|
2000-03-22 14:22:20 +03:00
|
|
|
return ENXIO;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
/* check banner to confirm firmware write it */
|
2000-06-09 09:31:15 +04:00
|
|
|
awi_read_bytes(sc, AWI_BANNER, sc->sc_banner, AWI_BANNER_LEN);
|
|
|
|
if (memcmp(sc->sc_banner, "PCnetMobile:", 12) != 0) {
|
2000-03-22 14:22:20 +03:00
|
|
|
printf("%s: failed to complete selftest (bad banner)\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname);
|
2000-03-22 14:22:20 +03:00
|
|
|
for (i = 0; i < AWI_BANNER_LEN; i++)
|
2000-06-09 09:31:15 +04:00
|
|
|
printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]);
|
2000-03-22 14:22:20 +03:00
|
|
|
printf("\n");
|
|
|
|
return ENXIO;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
/* initializing interrupt */
|
2000-03-27 16:54:59 +04:00
|
|
|
sc->sc_enab_intr = 1;
|
2000-03-22 14:22:20 +03:00
|
|
|
error = awi_intr_lock(sc);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
intmask = AWI_INT_GROGGY | AWI_INT_SCAN_CMPLT |
|
|
|
|
AWI_INT_TX | AWI_INT_RX | AWI_INT_CMD;
|
|
|
|
awi_write_1(sc, AWI_INTMASK, ~intmask & 0xff);
|
|
|
|
awi_write_1(sc, AWI_INTMASK2, 0);
|
|
|
|
awi_write_1(sc, AWI_INTSTAT, 0);
|
|
|
|
awi_write_1(sc, AWI_INTSTAT2, 0);
|
|
|
|
awi_intr_unlock(sc);
|
|
|
|
am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT);
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-07-27 02:55:12 +04:00
|
|
|
/* issuing interface test command */
|
2001-09-18 13:09:57 +04:00
|
|
|
error = awi_cmd(sc, AWI_CMD_NOP, AWI_WAIT);
|
2000-03-22 14:22:20 +03:00
|
|
|
if (error) {
|
2004-01-15 12:39:15 +03:00
|
|
|
printf("%s: failed to complete selftest",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname);
|
2000-07-04 18:27:56 +04:00
|
|
|
if (error == ENXIO)
|
|
|
|
printf(" (no hardware)\n");
|
|
|
|
else if (error != EWOULDBLOCK)
|
2000-03-22 14:22:20 +03:00
|
|
|
printf(" (error %d)\n", error);
|
|
|
|
else if (sc->sc_cansleep)
|
|
|
|
printf(" (lost interrupt)\n");
|
|
|
|
else
|
|
|
|
printf(" (command timeout)\n");
|
2002-09-03 18:54:00 +04:00
|
|
|
return error;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2002-09-03 18:54:00 +04:00
|
|
|
|
|
|
|
/* Initialize VBM */
|
|
|
|
awi_write_1(sc, AWI_VBM_OFFSET, 0);
|
|
|
|
awi_write_1(sc, AWI_VBM_LENGTH, 1);
|
|
|
|
awi_write_1(sc, AWI_VBM_BITMAP, 0);
|
|
|
|
return 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-03-22 14:22:20 +03:00
|
|
|
* Extract the factory default MIB value from firmware and assign the driver
|
|
|
|
* default value.
|
|
|
|
* Called once at attaching the interface.
|
1999-11-04 20:10:53 +03:00
|
|
|
*/
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_init_mibs(struct awi_softc *sc)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2003-10-13 12:10:48 +04:00
|
|
|
int chan, i, error;
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2001-09-18 13:09:57 +04:00
|
|
|
struct awi_chanset *cs;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_LOCAL, AWI_WAIT)) ||
|
|
|
|
(error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_ADDR, AWI_WAIT)) ||
|
|
|
|
(error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MAC, AWI_WAIT)) ||
|
|
|
|
(error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MGT, AWI_WAIT)) ||
|
|
|
|
(error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_PHY, AWI_WAIT))) {
|
|
|
|
printf("%s: failed to get default mib value (error %d)\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname, error);
|
2001-09-18 13:09:57 +04:00
|
|
|
return error;
|
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
memset(&sc->sc_ic.ic_chan_avail, 0, sizeof(sc->sc_ic.ic_chan_avail));
|
|
|
|
for (cs = awi_chanset; ; cs++) {
|
|
|
|
if (cs->cs_type == 0) {
|
|
|
|
printf("%s: failed to set available channel\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname);
|
2001-09-18 13:09:57 +04:00
|
|
|
return ENXIO;
|
|
|
|
}
|
|
|
|
if (cs->cs_type == sc->sc_mib_phy.IEEE_PHY_Type &&
|
|
|
|
cs->cs_region == sc->sc_mib_phy.aCurrent_Reg_Domain)
|
|
|
|
break;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2001-09-19 08:09:54 +04:00
|
|
|
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
|
|
|
|
for (i = cs->cs_min; i <= cs->cs_max; i++) {
|
2003-10-13 12:10:48 +04:00
|
|
|
chan = IEEE80211_FH_CHAN(i % 3 + 1, i);
|
|
|
|
setbit(sc->sc_ic.ic_chan_avail, chan);
|
|
|
|
/* XXX for FHSS, does frequency matter? */
|
|
|
|
ic->ic_channels[chan].ic_freq = 0;
|
|
|
|
ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_FHSS;
|
2001-09-19 08:09:54 +04:00
|
|
|
/*
|
|
|
|
* According to the IEEE 802.11 specification,
|
|
|
|
* hop pattern parameter for FH phy should be
|
|
|
|
* incremented by 3 for given hop chanset, i.e.,
|
|
|
|
* the chanset parameter is calculated for given
|
|
|
|
* hop patter. However, BayStack 650 Access Points
|
|
|
|
* apparently use fixed hop chanset parameter value
|
|
|
|
* 1 for any hop pattern. So we also try this
|
|
|
|
* combination of hop chanset and pattern.
|
|
|
|
*/
|
2003-10-13 12:10:48 +04:00
|
|
|
chan = IEEE80211_FH_CHAN(1, i);
|
|
|
|
setbit(sc->sc_ic.ic_chan_avail, chan);
|
|
|
|
ic->ic_channels[chan].ic_freq = 0; /* XXX */
|
|
|
|
ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_FHSS;
|
2001-09-19 08:09:54 +04:00
|
|
|
}
|
|
|
|
} else {
|
2003-10-13 12:10:48 +04:00
|
|
|
for (i = cs->cs_min; i <= cs->cs_max; i++) {
|
2001-09-19 08:09:54 +04:00
|
|
|
setbit(sc->sc_ic.ic_chan_avail, i);
|
2003-10-13 12:10:48 +04:00
|
|
|
ic->ic_channels[i].ic_freq =
|
|
|
|
ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
|
|
|
|
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
|
|
|
|
}
|
2001-09-19 08:09:54 +04:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_cur_chan = cs->cs_def;
|
2004-01-15 16:29:05 +03:00
|
|
|
ic->ic_ibss_chan = &ic->ic_channels[cs->cs_def];
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
sc->sc_mib_local.Fragmentation_Dis = 1;
|
2002-09-03 18:54:00 +04:00
|
|
|
sc->sc_mib_local.Add_PLCP_Dis = 0;
|
2004-01-15 16:29:05 +03:00
|
|
|
sc->sc_mib_local.MAC_Hdr_Prsv = 0;
|
2002-09-03 18:54:00 +04:00
|
|
|
sc->sc_mib_local.Rx_Mgmt_Que_En = 0;
|
|
|
|
sc->sc_mib_local.Re_Assembly_Dis = 1;
|
|
|
|
sc->sc_mib_local.Strip_PLCP_Dis = 0;
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_mib_local.Power_Saving_Mode_Dis = 1;
|
2002-09-03 18:54:00 +04:00
|
|
|
sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
|
2004-01-15 16:29:05 +03:00
|
|
|
sc->sc_mib_local.Check_Seq_Cntl_Dis = 0;
|
2002-09-03 18:54:00 +04:00
|
|
|
sc->sc_mib_local.Flush_CFP_Queue_On_CF_End = 0;
|
|
|
|
sc->sc_mib_local.Network_Mode = 1;
|
|
|
|
sc->sc_mib_local.PWD_Lvl = 0;
|
|
|
|
sc->sc_mib_local.CFP_Mode = 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
/* allocate buffers */
|
|
|
|
sc->sc_txbase = AWI_BUFFERS;
|
|
|
|
sc->sc_txend = sc->sc_txbase +
|
|
|
|
(AWI_TXD_SIZE + sizeof(struct ieee80211_frame) +
|
|
|
|
sizeof(struct ether_header) + ETHERMTU) * AWI_NTXBUFS;
|
|
|
|
LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Offset, sc->sc_txbase);
|
|
|
|
LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Size,
|
|
|
|
sc->sc_txend - sc->sc_txbase);
|
|
|
|
LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend);
|
|
|
|
LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size,
|
|
|
|
AWI_BUFFERS_END - sc->sc_txend);
|
|
|
|
sc->sc_mib_local.Acting_as_AP = 0;
|
2002-09-03 18:54:00 +04:00
|
|
|
sc->sc_mib_local.Fill_CFP = 0;
|
|
|
|
|
|
|
|
memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
|
|
|
|
sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
|
|
|
|
|
|
|
|
sc->sc_mib_mgt.aPower_Mgt_Mode = 0;
|
|
|
|
sc->sc_mib_mgt.aDTIM_Period = 1;
|
|
|
|
LE_WRITE_2(&sc->sc_mib_mgt.aATIM_Window, 0);
|
2001-09-18 13:09:57 +04:00
|
|
|
return 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_mib(struct awi_softc *sc, u_int8_t cmd, u_int8_t mib, int wflag)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
int error;
|
|
|
|
u_int8_t size, *ptr;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
switch (mib) {
|
|
|
|
case AWI_MIB_LOCAL:
|
|
|
|
ptr = (u_int8_t *)&sc->sc_mib_local;
|
|
|
|
size = sizeof(sc->sc_mib_local);
|
|
|
|
break;
|
|
|
|
case AWI_MIB_ADDR:
|
|
|
|
ptr = (u_int8_t *)&sc->sc_mib_addr;
|
|
|
|
size = sizeof(sc->sc_mib_addr);
|
|
|
|
break;
|
|
|
|
case AWI_MIB_MAC:
|
|
|
|
ptr = (u_int8_t *)&sc->sc_mib_mac;
|
|
|
|
size = sizeof(sc->sc_mib_mac);
|
|
|
|
break;
|
|
|
|
case AWI_MIB_STAT:
|
|
|
|
ptr = (u_int8_t *)&sc->sc_mib_stat;
|
|
|
|
size = sizeof(sc->sc_mib_stat);
|
|
|
|
break;
|
|
|
|
case AWI_MIB_MGT:
|
|
|
|
ptr = (u_int8_t *)&sc->sc_mib_mgt;
|
|
|
|
size = sizeof(sc->sc_mib_mgt);
|
|
|
|
break;
|
|
|
|
case AWI_MIB_PHY:
|
|
|
|
ptr = (u_int8_t *)&sc->sc_mib_phy;
|
|
|
|
size = sizeof(sc->sc_mib_phy);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return EINVAL;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
if (sc->sc_cmd_inprog) {
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((error = awi_cmd_wait(sc)) != 0) {
|
2006-10-04 19:36:23 +04:00
|
|
|
if (error == EWOULDBLOCK) {
|
2001-09-18 13:09:57 +04:00
|
|
|
DPRINTF(("awi_mib: cmd %d inprog",
|
|
|
|
sc->sc_cmd_inprog));
|
2006-10-04 19:36:23 +04:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
}
|
2000-07-04 18:27:56 +04:00
|
|
|
sc->sc_cmd_inprog = cmd;
|
2000-03-22 14:22:20 +03:00
|
|
|
if (cmd == AWI_CMD_SET_MIB)
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_write_bytes(sc, AWI_CA_MIB_DATA, ptr, size);
|
|
|
|
awi_write_1(sc, AWI_CA_MIB_TYPE, mib);
|
|
|
|
awi_write_1(sc, AWI_CA_MIB_SIZE, size);
|
|
|
|
awi_write_1(sc, AWI_CA_MIB_INDEX, 0);
|
|
|
|
if ((error = awi_cmd(sc, cmd, wflag)) != 0)
|
2000-03-22 14:22:20 +03:00
|
|
|
return error;
|
|
|
|
if (cmd == AWI_CMD_GET_MIB) {
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_read_bytes(sc, AWI_CA_MIB_DATA, ptr, size);
|
2000-03-22 14:22:20 +03:00
|
|
|
#ifdef AWI_DEBUG
|
2001-09-18 13:09:57 +04:00
|
|
|
if (awi_debug) {
|
2000-03-22 14:22:20 +03:00
|
|
|
int i;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
printf("awi_mib: #%d:", mib);
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
printf(" %02x", ptr[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
#endif
|
1999-11-08 18:45:00 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
return 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_cmd(struct awi_softc *sc, u_int8_t cmd, int wflag)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
u_int8_t status;
|
|
|
|
int error = 0;
|
2001-09-18 13:09:57 +04:00
|
|
|
#ifdef AWI_DEBUG
|
|
|
|
static const char *cmdname[] = {
|
|
|
|
"IDLE", "NOP", "SET_MIB", "INIT_TX", "FLUSH_TX", "INIT_RX",
|
|
|
|
"KILL_RX", "SLEEP", "WAKE", "GET_MIB", "SCAN", "SYNC", "RESUME"
|
|
|
|
};
|
|
|
|
#endif
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
#ifdef AWI_DEBUG
|
|
|
|
if (awi_debug > 1) {
|
|
|
|
if (cmd >= sizeof(cmdname)/sizeof(cmdname[0]))
|
|
|
|
printf("awi_cmd: #%d", cmd);
|
|
|
|
else
|
|
|
|
printf("awi_cmd: %s", cmdname[cmd]);
|
|
|
|
printf(" %s\n", wflag == AWI_NOWAIT ? "nowait" : "wait");
|
|
|
|
}
|
|
|
|
#endif
|
2000-07-04 18:27:56 +04:00
|
|
|
sc->sc_cmd_inprog = cmd;
|
2000-03-22 14:22:20 +03:00
|
|
|
awi_write_1(sc, AWI_CMD_STATUS, AWI_STAT_IDLE);
|
|
|
|
awi_write_1(sc, AWI_CMD, cmd);
|
2001-09-18 13:09:57 +04:00
|
|
|
if (wflag == AWI_NOWAIT)
|
|
|
|
return EINPROGRESS;
|
|
|
|
if ((error = awi_cmd_wait(sc)) != 0)
|
2000-03-22 14:22:20 +03:00
|
|
|
return error;
|
|
|
|
status = awi_read_1(sc, AWI_CMD_STATUS);
|
|
|
|
awi_write_1(sc, AWI_CMD, 0);
|
|
|
|
switch (status) {
|
|
|
|
case AWI_STAT_OK:
|
|
|
|
break;
|
|
|
|
case AWI_STAT_BADPARM:
|
|
|
|
return EINVAL;
|
|
|
|
default:
|
|
|
|
printf("%s: command %d failed %x\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname, cmd, status);
|
2000-03-22 14:22:20 +03:00
|
|
|
return ENXIO;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
return 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
static int
|
|
|
|
awi_cmd_wait(struct awi_softc *sc)
|
|
|
|
{
|
|
|
|
int i, error = 0;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (sc->sc_cmd_inprog) {
|
|
|
|
if (sc->sc_invalid)
|
|
|
|
return ENXIO;
|
|
|
|
if (awi_read_1(sc, AWI_CMD) != sc->sc_cmd_inprog) {
|
|
|
|
printf("%s: failed to access hardware\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname);
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_invalid = 1;
|
|
|
|
return ENXIO;
|
|
|
|
}
|
|
|
|
if (sc->sc_cansleep) {
|
|
|
|
sc->sc_sleep_cnt++;
|
|
|
|
error = tsleep(sc, PWAIT, "awicmd",
|
|
|
|
AWI_CMD_TIMEOUT*hz/1000);
|
|
|
|
sc->sc_sleep_cnt--;
|
|
|
|
} else {
|
|
|
|
if (awi_read_1(sc, AWI_CMD_STATUS) != AWI_STAT_IDLE) {
|
|
|
|
awi_cmd_done(sc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i++ >= AWI_CMD_TIMEOUT*1000/10)
|
|
|
|
error = EWOULDBLOCK;
|
|
|
|
else
|
|
|
|
DELAY(10);
|
|
|
|
}
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (error) {
|
|
|
|
DPRINTF(("awi_cmd_wait: cmd 0x%x, error %d\n",
|
|
|
|
sc->sc_cmd_inprog, error));
|
|
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_cmd_done(struct awi_softc *sc)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
u_int8_t cmd, status;
|
1999-11-09 17:58:07 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
status = awi_read_1(sc, AWI_CMD_STATUS);
|
|
|
|
if (status == AWI_STAT_IDLE)
|
|
|
|
return; /* stray interrupt */
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-07-04 18:27:56 +04:00
|
|
|
cmd = sc->sc_cmd_inprog;
|
2000-03-22 14:22:20 +03:00
|
|
|
sc->sc_cmd_inprog = 0;
|
2001-09-18 13:09:57 +04:00
|
|
|
wakeup(sc);
|
2000-03-22 14:22:20 +03:00
|
|
|
awi_write_1(sc, AWI_CMD, 0);
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
if (status != AWI_STAT_OK) {
|
|
|
|
printf("%s: command %d failed %x\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname, cmd, status);
|
2001-09-18 13:09:57 +04:00
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
1999-11-04 20:10:53 +03:00
|
|
|
return;
|
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
if (sc->sc_substate != AWI_ST_NONE)
|
2003-10-13 12:10:48 +04:00
|
|
|
(void)ieee80211_new_state(&sc->sc_ic, sc->sc_nstate, -1);
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_next_txd(struct awi_softc *sc, int len, u_int32_t *framep, u_int32_t *ntxdp)
|
2000-03-22 14:22:20 +03:00
|
|
|
{
|
|
|
|
u_int32_t txd, ntxd, frame;
|
|
|
|
|
|
|
|
txd = sc->sc_txnext;
|
|
|
|
frame = txd + AWI_TXD_SIZE;
|
|
|
|
if (frame + len > sc->sc_txend)
|
|
|
|
frame = sc->sc_txbase;
|
|
|
|
ntxd = frame + len;
|
|
|
|
if (ntxd + AWI_TXD_SIZE > sc->sc_txend)
|
|
|
|
ntxd = sc->sc_txbase;
|
|
|
|
*framep = frame;
|
|
|
|
*ntxdp = ntxd;
|
|
|
|
/*
|
|
|
|
* Determine if there are any room in ring buffer.
|
|
|
|
* --- send wait, === new data, +++ conflict (ENOBUFS)
|
|
|
|
* base........................end
|
|
|
|
* done----txd=====ntxd OK
|
|
|
|
* --txd=====done++++ntxd-- full
|
|
|
|
* --txd=====ntxd done-- OK
|
|
|
|
* ==ntxd done----txd=== OK
|
|
|
|
* ==done++++ntxd----txd=== full
|
|
|
|
* ++ntxd txd=====done++ full
|
|
|
|
*/
|
|
|
|
if (txd < ntxd) {
|
|
|
|
if (txd < sc->sc_txdone && ntxd + AWI_TXD_SIZE > sc->sc_txdone)
|
|
|
|
return ENOBUFS;
|
|
|
|
} else {
|
|
|
|
if (txd < sc->sc_txdone || ntxd + AWI_TXD_SIZE > sc->sc_txdone)
|
|
|
|
return ENOBUFS;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_lock(struct awi_softc *sc)
|
2000-03-22 14:22:20 +03:00
|
|
|
{
|
|
|
|
int error = 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2004-01-15 12:39:15 +03:00
|
|
|
#ifdef __NetBSD__
|
|
|
|
if (curlwp == NULL)
|
|
|
|
#else
|
|
|
|
if (curproc == NULL)
|
|
|
|
#endif
|
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
/*
|
|
|
|
* XXX
|
|
|
|
* Though driver ioctl should be called with context,
|
|
|
|
* KAME ipv6 stack calls ioctl in interrupt for now.
|
|
|
|
* We simply abort the request if there are other
|
|
|
|
* ioctl requests in progress.
|
|
|
|
*/
|
2000-07-04 18:27:56 +04:00
|
|
|
if (sc->sc_busy) {
|
|
|
|
if (sc->sc_invalid)
|
|
|
|
return ENXIO;
|
2003-10-15 11:18:17 +04:00
|
|
|
return EWOULDBLOCK;
|
2000-07-04 18:27:56 +04:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
sc->sc_busy = 1;
|
|
|
|
sc->sc_cansleep = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
while (sc->sc_busy) {
|
2000-07-04 18:27:56 +04:00
|
|
|
if (sc->sc_invalid)
|
|
|
|
return ENXIO;
|
2000-03-22 14:22:20 +03:00
|
|
|
sc->sc_sleep_cnt++;
|
|
|
|
error = tsleep(sc, PWAIT | PCATCH, "awilck", 0);
|
|
|
|
sc->sc_sleep_cnt--;
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
sc->sc_busy = 1;
|
|
|
|
sc->sc_cansleep = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_unlock(struct awi_softc *sc)
|
2000-03-22 14:22:20 +03:00
|
|
|
{
|
|
|
|
sc->sc_busy = 0;
|
|
|
|
sc->sc_cansleep = 0;
|
|
|
|
if (sc->sc_sleep_cnt)
|
|
|
|
wakeup(sc);
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static int
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_intr_lock(struct awi_softc *sc)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
u_int8_t status;
|
|
|
|
int i, retry;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
status = 1;
|
|
|
|
for (retry = 0; retry < 10; retry++) {
|
|
|
|
for (i = 0; i < AWI_LOCKOUT_TIMEOUT*1000/5; i++) {
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((status = awi_read_1(sc, AWI_LOCKOUT_HOST)) == 0)
|
2000-03-22 14:22:20 +03:00
|
|
|
break;
|
|
|
|
DELAY(5);
|
|
|
|
}
|
|
|
|
if (status != 0)
|
|
|
|
break;
|
|
|
|
awi_write_1(sc, AWI_LOCKOUT_MAC, 1);
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((status = awi_read_1(sc, AWI_LOCKOUT_HOST)) == 0)
|
2000-03-22 14:22:20 +03:00
|
|
|
break;
|
|
|
|
awi_write_1(sc, AWI_LOCKOUT_MAC, 0);
|
|
|
|
}
|
|
|
|
if (status != 0) {
|
|
|
|
printf("%s: failed to lock interrupt\n",
|
2005-06-22 10:14:51 +04:00
|
|
|
sc->sc_if.if_xname);
|
2000-03-22 14:22:20 +03:00
|
|
|
return ENXIO;
|
1999-11-08 18:45:00 +03:00
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
return 0;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static void
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_intr_unlock(struct awi_softc *sc)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2000-03-22 14:22:20 +03:00
|
|
|
|
|
|
|
awi_write_1(sc, AWI_LOCKOUT_MAC, 0);
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2000-03-22 14:22:20 +03:00
|
|
|
static int
|
2003-10-13 12:10:48 +04:00
|
|
|
awi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2005-06-22 10:14:51 +04:00
|
|
|
struct ifnet *ifp = ic->ic_ifp;
|
|
|
|
struct awi_softc *sc = ifp->if_softc;
|
2002-09-27 09:36:04 +04:00
|
|
|
struct ieee80211_node *ni;
|
2001-09-20 17:54:43 +04:00
|
|
|
int error;
|
2001-09-18 13:09:57 +04:00
|
|
|
u_int8_t newmode;
|
|
|
|
enum ieee80211_state ostate;
|
|
|
|
#ifdef AWI_DEBUG
|
|
|
|
static const char *stname[] =
|
|
|
|
{ "INIT", "SCAN", "AUTH", "ASSOC", "RUN" };
|
|
|
|
static const char *substname[] =
|
|
|
|
{ "NONE", "SCAN_INIT", "SCAN_SETMIB", "SCAN_SCCMD",
|
|
|
|
"SUB_INIT", "SUB_SETSS", "SUB_SYNC" };
|
|
|
|
#endif /* AWI_DEBUG */
|
|
|
|
|
|
|
|
ostate = ic->ic_state;
|
|
|
|
DPRINTF(("awi_newstate: %s (%s/%s) -> %s\n", stname[ostate],
|
|
|
|
stname[sc->sc_nstate], substname[sc->sc_substate], stname[nstate]));
|
|
|
|
|
|
|
|
/* set LED */
|
|
|
|
switch (nstate) {
|
|
|
|
case IEEE80211_S_INIT:
|
|
|
|
awi_drvstate(sc, AWI_DRV_RESET);
|
|
|
|
break;
|
|
|
|
case IEEE80211_S_SCAN:
|
2002-09-30 19:48:41 +04:00
|
|
|
if (ic->ic_opmode == IEEE80211_M_IBSS ||
|
|
|
|
ic->ic_opmode == IEEE80211_M_AHDEMO)
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_drvstate(sc, AWI_DRV_ADHSC);
|
|
|
|
else
|
|
|
|
awi_drvstate(sc, AWI_DRV_INFSY);
|
|
|
|
break;
|
|
|
|
case IEEE80211_S_AUTH:
|
|
|
|
awi_drvstate(sc, AWI_DRV_INFSY);
|
|
|
|
break;
|
|
|
|
case IEEE80211_S_ASSOC:
|
|
|
|
awi_drvstate(sc, AWI_DRV_INFAUTH);
|
|
|
|
break;
|
|
|
|
case IEEE80211_S_RUN:
|
2002-09-30 19:48:41 +04:00
|
|
|
if (ic->ic_opmode == IEEE80211_M_IBSS ||
|
|
|
|
ic->ic_opmode == IEEE80211_M_AHDEMO)
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_drvstate(sc, AWI_DRV_ADHSY);
|
|
|
|
else
|
|
|
|
awi_drvstate(sc, AWI_DRV_INFASSOC);
|
|
|
|
break;
|
|
|
|
}
|
2000-03-22 14:22:20 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if (nstate == IEEE80211_S_INIT) {
|
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
|
|
|
ic->ic_flags &= ~IEEE80211_F_SIBSS;
|
2003-10-13 12:10:48 +04:00
|
|
|
return (*sc->sc_newstate)(ic, nstate, arg);
|
2001-09-18 13:09:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* state transition */
|
|
|
|
if (nstate == IEEE80211_S_SCAN) {
|
|
|
|
/* SCAN substate */
|
|
|
|
if (sc->sc_substate == AWI_ST_NONE) {
|
|
|
|
sc->sc_nstate = nstate; /* next state in transition */
|
|
|
|
sc->sc_substate = AWI_ST_SCAN_INIT;
|
|
|
|
}
|
|
|
|
switch (sc->sc_substate) {
|
|
|
|
case AWI_ST_SCAN_INIT:
|
|
|
|
sc->sc_substate = AWI_ST_SCAN_SETMIB;
|
|
|
|
switch (ostate) {
|
|
|
|
case IEEE80211_S_RUN:
|
|
|
|
/* beacon miss */
|
|
|
|
if (ifp->if_flags & IFF_DEBUG)
|
|
|
|
printf("%s: no recent beacons from %s;"
|
|
|
|
" rescanning\n",
|
|
|
|
ifp->if_xname,
|
2003-10-13 12:10:48 +04:00
|
|
|
ether_sprintf(ic->ic_bss->ni_bssid));
|
2001-09-18 13:09:57 +04:00
|
|
|
/* FALLTHRU */
|
|
|
|
case IEEE80211_S_AUTH:
|
|
|
|
case IEEE80211_S_ASSOC:
|
|
|
|
case IEEE80211_S_INIT:
|
2005-06-22 10:14:51 +04:00
|
|
|
ieee80211_begin_scan(ic, 1);
|
2001-09-18 13:09:57 +04:00
|
|
|
/* FALLTHRU */
|
|
|
|
case IEEE80211_S_SCAN:
|
|
|
|
/* scan next */
|
2000-03-22 14:22:20 +03:00
|
|
|
break;
|
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
if (ic->ic_flags & IEEE80211_F_ASCAN)
|
|
|
|
newmode = AWI_SCAN_ACTIVE;
|
2000-03-22 14:22:20 +03:00
|
|
|
else
|
2001-09-18 13:09:57 +04:00
|
|
|
newmode = AWI_SCAN_PASSIVE;
|
|
|
|
if (sc->sc_mib_mgt.aScan_Mode != newmode) {
|
|
|
|
sc->sc_mib_mgt.aScan_Mode = newmode;
|
|
|
|
if ((error = awi_mib(sc, AWI_CMD_SET_MIB,
|
|
|
|
AWI_MIB_MGT, AWI_NOWAIT)) != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* FALLTHRU */
|
|
|
|
case AWI_ST_SCAN_SETMIB:
|
|
|
|
sc->sc_substate = AWI_ST_SCAN_SCCMD;
|
|
|
|
if (sc->sc_cmd_inprog) {
|
|
|
|
if ((error = awi_cmd_wait(sc)) != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sc->sc_cmd_inprog = AWI_CMD_SCAN;
|
2003-10-13 12:10:48 +04:00
|
|
|
ni = ic->ic_bss;
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_write_2(sc, AWI_CA_SCAN_DURATION,
|
|
|
|
(ic->ic_flags & IEEE80211_F_ASCAN) ?
|
|
|
|
AWI_ASCAN_DURATION : AWI_PSCAN_DURATION);
|
|
|
|
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
|
2001-09-19 08:09:54 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SCAN_SET,
|
2003-10-13 12:10:48 +04:00
|
|
|
IEEE80211_FH_CHANSET(
|
|
|
|
ieee80211_chan2ieee(ic, ni->ni_chan)));
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SCAN_PATTERN,
|
2003-10-13 12:10:48 +04:00
|
|
|
IEEE80211_FH_CHANPAT(
|
|
|
|
ieee80211_chan2ieee(ic, ni->ni_chan)));
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SCAN_IDX, 1);
|
|
|
|
} else {
|
2003-10-13 12:10:48 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SCAN_SET,
|
|
|
|
ieee80211_chan2ieee(ic, ni->ni_chan));
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SCAN_PATTERN, 0);
|
|
|
|
awi_write_1(sc, AWI_CA_SCAN_IDX, 0);
|
|
|
|
}
|
|
|
|
awi_write_1(sc, AWI_CA_SCAN_SUSP, 0);
|
2003-10-13 12:10:48 +04:00
|
|
|
sc->sc_cur_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((error = awi_cmd(sc, AWI_CMD_SCAN, AWI_NOWAIT))
|
|
|
|
!= 0)
|
|
|
|
break;
|
|
|
|
/* FALLTHRU */
|
|
|
|
case AWI_ST_SCAN_SCCMD:
|
|
|
|
ic->ic_state = nstate;
|
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
|
|
|
error = EINPROGRESS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DPRINTF(("awi_newstate: unexpected state %s/%s\n",
|
|
|
|
stname[nstate], substname[sc->sc_substate]));
|
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
|
|
|
error = EIO;
|
2000-03-22 14:22:20 +03:00
|
|
|
break;
|
2001-09-18 13:09:57 +04:00
|
|
|
}
|
2003-10-13 12:10:48 +04:00
|
|
|
goto out;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if (ostate == IEEE80211_S_SCAN) {
|
|
|
|
/* set SSID and channel */
|
|
|
|
/* substate */
|
|
|
|
if (sc->sc_substate == AWI_ST_NONE) {
|
|
|
|
sc->sc_nstate = nstate; /* next state in transition */
|
|
|
|
sc->sc_substate = AWI_ST_SUB_INIT;
|
|
|
|
}
|
2003-10-13 12:10:48 +04:00
|
|
|
ni = ic->ic_bss;
|
2001-09-18 13:09:57 +04:00
|
|
|
switch (sc->sc_substate) {
|
|
|
|
case AWI_ST_SUB_INIT:
|
|
|
|
sc->sc_substate = AWI_ST_SUB_SETSS;
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(&sc->sc_mib_mgt.aCurrent_BSS_ID,
|
|
|
|
ni->ni_bssid);
|
2001-09-18 13:09:57 +04:00
|
|
|
memset(&sc->sc_mib_mgt.aCurrent_ESS_ID, 0,
|
|
|
|
AWI_ESS_ID_SIZE);
|
|
|
|
sc->sc_mib_mgt.aCurrent_ESS_ID[0] =
|
|
|
|
IEEE80211_ELEMID_SSID;
|
2002-09-27 09:36:04 +04:00
|
|
|
sc->sc_mib_mgt.aCurrent_ESS_ID[1] = ni->ni_esslen;
|
2001-09-18 13:09:57 +04:00
|
|
|
memcpy(&sc->sc_mib_mgt.aCurrent_ESS_ID[2],
|
2002-09-27 09:36:04 +04:00
|
|
|
ni->ni_essid, ni->ni_esslen);
|
2001-09-18 13:09:57 +04:00
|
|
|
LE_WRITE_2(&sc->sc_mib_mgt.aBeacon_Period,
|
2002-09-27 09:36:04 +04:00
|
|
|
ni->ni_intval);
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT,
|
|
|
|
AWI_NOWAIT)) != 0)
|
|
|
|
break;
|
|
|
|
/* FALLTHRU */
|
|
|
|
case AWI_ST_SUB_SETSS:
|
|
|
|
sc->sc_substate = AWI_ST_SUB_SYNC;
|
|
|
|
if (sc->sc_cmd_inprog) {
|
2002-08-05 10:55:05 +04:00
|
|
|
if ((error = awi_cmd_wait(sc)) != 0)
|
2001-09-18 13:09:57 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
sc->sc_cmd_inprog = AWI_CMD_SYNC;
|
|
|
|
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
|
2001-09-19 08:09:54 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SYNC_SET,
|
2003-10-13 12:10:48 +04:00
|
|
|
IEEE80211_FH_CHANSET(
|
|
|
|
ieee80211_chan2ieee(ic, ni->ni_chan)));
|
2001-09-19 08:09:54 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SYNC_PATTERN,
|
2003-10-13 12:10:48 +04:00
|
|
|
IEEE80211_FH_CHANPAT(
|
|
|
|
ieee80211_chan2ieee(ic, ni->ni_chan)));
|
2001-09-20 17:54:43 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SYNC_IDX,
|
2002-09-27 09:36:04 +04:00
|
|
|
ni->ni_fhindex);
|
2001-09-20 17:54:43 +04:00
|
|
|
awi_write_2(sc, AWI_CA_SYNC_DWELL,
|
2002-09-27 09:36:04 +04:00
|
|
|
ni->ni_fhdwell);
|
2001-09-18 13:09:57 +04:00
|
|
|
} else {
|
2003-10-13 12:10:48 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SYNC_SET,
|
|
|
|
ieee80211_chan2ieee(ic, ni->ni_chan));
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SYNC_PATTERN, 0);
|
2001-09-20 17:54:43 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SYNC_IDX, 0);
|
|
|
|
awi_write_2(sc, AWI_CA_SYNC_DWELL, 0);
|
2001-09-18 13:09:57 +04:00
|
|
|
}
|
2004-01-15 16:29:05 +03:00
|
|
|
if (ic->ic_flags & IEEE80211_F_SIBSS) {
|
2005-06-22 10:14:51 +04:00
|
|
|
memset(&ni->ni_tstamp, 0,
|
|
|
|
sizeof(ni->ni_tstamp));
|
2004-01-15 16:29:05 +03:00
|
|
|
ni->ni_rstamp = 0;
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SYNC_STARTBSS, 1);
|
2004-01-15 16:29:05 +03:00
|
|
|
} else
|
2001-09-18 13:09:57 +04:00
|
|
|
awi_write_1(sc, AWI_CA_SYNC_STARTBSS, 0);
|
|
|
|
awi_write_2(sc, AWI_CA_SYNC_MBZ, 0);
|
|
|
|
awi_write_bytes(sc, AWI_CA_SYNC_TIMESTAMP,
|
2005-06-22 10:14:51 +04:00
|
|
|
ni->ni_tstamp.data, sizeof(ni->ni_tstamp.data));
|
2002-09-27 09:36:04 +04:00
|
|
|
awi_write_4(sc, AWI_CA_SYNC_REFTIME, ni->ni_rstamp);
|
2003-10-13 12:10:48 +04:00
|
|
|
sc->sc_cur_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
|
2001-09-18 13:09:57 +04:00
|
|
|
if ((error = awi_cmd(sc, AWI_CMD_SYNC, AWI_NOWAIT))
|
|
|
|
!= 0)
|
|
|
|
break;
|
|
|
|
/* FALLTHRU */
|
|
|
|
case AWI_ST_SUB_SYNC:
|
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
|
|
|
if (ic->ic_flags & IEEE80211_F_SIBSS) {
|
|
|
|
if ((error = awi_mib(sc, AWI_CMD_GET_MIB,
|
|
|
|
AWI_MIB_MGT, AWI_WAIT)) != 0)
|
|
|
|
break;
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(ni->ni_bssid,
|
|
|
|
&sc->sc_mib_mgt.aCurrent_BSS_ID);
|
2001-09-18 13:09:57 +04:00
|
|
|
} else {
|
|
|
|
if (nstate == IEEE80211_S_RUN) {
|
|
|
|
sc->sc_rx_timer = 10;
|
|
|
|
ifp->if_timer = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
error = 0;
|
2000-07-04 18:27:56 +04:00
|
|
|
break;
|
2001-09-18 13:09:57 +04:00
|
|
|
default:
|
|
|
|
DPRINTF(("awi_newstate: unexpected state %s/%s\n",
|
|
|
|
stname[nstate], substname[sc->sc_substate]));
|
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
|
|
|
error = EIO;
|
|
|
|
break;
|
|
|
|
}
|
2003-10-13 12:10:48 +04:00
|
|
|
goto out;
|
2000-07-04 18:27:56 +04:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
|
|
|
|
sc->sc_substate = AWI_ST_NONE;
|
|
|
|
|
2003-10-13 12:10:48 +04:00
|
|
|
return (*sc->sc_newstate)(ic, nstate, arg);
|
|
|
|
out:
|
2004-01-16 17:13:15 +03:00
|
|
|
if (error != 0) {
|
|
|
|
if (error == EINPROGRESS)
|
|
|
|
error = 0;
|
2003-10-13 12:10:48 +04:00
|
|
|
return error;
|
2004-01-16 17:13:15 +03:00
|
|
|
}
|
2003-10-13 12:10:48 +04:00
|
|
|
return (*sc->sc_newstate)(ic, nstate, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
awi_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
|
|
|
|
struct ieee80211_node *ni,
|
|
|
|
int subtype, int rssi, u_int32_t rstamp)
|
|
|
|
{
|
2005-06-22 10:14:51 +04:00
|
|
|
struct awi_softc *sc = ic->ic_ifp->if_softc;
|
2003-10-13 12:10:48 +04:00
|
|
|
|
|
|
|
/* probe request is handled by hardware */
|
|
|
|
if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_REQ)
|
|
|
|
return;
|
|
|
|
(*sc->sc_recv_mgmt)(ic, m0, ni, subtype, rssi, rstamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
awi_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
|
|
|
|
int type, int arg)
|
|
|
|
{
|
2005-06-22 10:14:51 +04:00
|
|
|
struct awi_softc *sc = ic->ic_ifp->if_softc;
|
2003-10-13 12:10:48 +04:00
|
|
|
|
|
|
|
/* probe request is handled by hardware */
|
|
|
|
if (type == IEEE80211_FC0_SUBTYPE_PROBE_REQ)
|
|
|
|
return 0;
|
|
|
|
return (*sc->sc_send_mgmt)(ic, ni, type, arg);
|
2000-07-04 18:27:56 +04:00
|
|
|
}
|
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
static struct mbuf *
|
|
|
|
awi_ether_encap(struct awi_softc *sc, struct mbuf *m)
|
1999-11-04 20:10:53 +03:00
|
|
|
{
|
2001-09-18 13:09:57 +04:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2003-10-13 12:10:48 +04:00
|
|
|
struct ieee80211_node *ni = ic->ic_bss;
|
2001-09-18 13:09:57 +04:00
|
|
|
struct ether_header *eh;
|
2000-03-22 14:22:20 +03:00
|
|
|
struct ieee80211_frame *wh;
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
if (m->m_len < sizeof(struct ether_header)) {
|
|
|
|
m = m_pullup(m, sizeof(struct ether_header));
|
|
|
|
if (m == NULL)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
eh = mtod(m, struct ether_header *);
|
|
|
|
M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
|
|
|
|
if (m == NULL)
|
|
|
|
return NULL;
|
2000-03-22 14:22:20 +03:00
|
|
|
wh = mtod(m, struct ieee80211_frame *);
|
2001-09-18 13:09:57 +04:00
|
|
|
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
|
|
|
|
*(u_int16_t *)wh->i_dur = 0;
|
|
|
|
*(u_int16_t *)wh->i_seq =
|
2005-06-22 10:14:51 +04:00
|
|
|
htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
|
|
|
|
ni->ni_txseqs[0]++;
|
2002-09-30 19:48:41 +04:00
|
|
|
if (ic->ic_opmode == IEEE80211_M_IBSS ||
|
|
|
|
ic->ic_opmode == IEEE80211_M_AHDEMO) {
|
2001-09-18 13:09:57 +04:00
|
|
|
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
|
|
|
|
if (sc->sc_adhoc_ap)
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
|
2001-09-18 13:09:57 +04:00
|
|
|
else
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(wh->i_addr1, eh->ether_dhost);
|
|
|
|
IEEE80211_ADDR_COPY(wh->i_addr2, eh->ether_shost);
|
|
|
|
IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
|
2001-09-18 13:09:57 +04:00
|
|
|
} else {
|
|
|
|
wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
|
|
|
|
IEEE80211_ADDR_COPY(wh->i_addr2, eh->ether_shost);
|
|
|
|
IEEE80211_ADDR_COPY(wh->i_addr3, eh->ether_dhost);
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2001-09-18 13:09:57 +04:00
|
|
|
return m;
|
|
|
|
}
|
1999-11-04 20:10:53 +03:00
|
|
|
|
2001-09-18 13:09:57 +04:00
|
|
|
static struct mbuf *
|
|
|
|
awi_ether_modcap(struct awi_softc *sc, struct mbuf *m)
|
|
|
|
{
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
struct ether_header eh;
|
|
|
|
struct ieee80211_frame wh;
|
|
|
|
struct llc *llc;
|
|
|
|
|
|
|
|
if (m->m_len < sizeof(wh) + sizeof(eh)) {
|
|
|
|
m = m_pullup(m, sizeof(wh) + sizeof(eh));
|
|
|
|
if (m == NULL)
|
|
|
|
return NULL;
|
2000-03-22 14:22:20 +03:00
|
|
|
}
|
2007-03-04 08:59:00 +03:00
|
|
|
memcpy(&wh, mtod(m, void *), sizeof(wh));
|
2001-09-18 13:09:57 +04:00
|
|
|
if (wh.i_fc[0] != (IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA))
|
|
|
|
return m;
|
2007-03-04 08:59:00 +03:00
|
|
|
memcpy(&eh, mtod(m, char *) + sizeof(wh), sizeof(eh));
|
2001-09-18 13:09:57 +04:00
|
|
|
m_adj(m, sizeof(eh) - sizeof(*llc));
|
2002-09-30 19:48:41 +04:00
|
|
|
if (ic->ic_opmode == IEEE80211_M_IBSS ||
|
|
|
|
ic->ic_opmode == IEEE80211_M_AHDEMO)
|
2002-09-27 09:36:04 +04:00
|
|
|
IEEE80211_ADDR_COPY(wh.i_addr2, eh.ether_shost);
|
2007-03-04 08:59:00 +03:00
|
|
|
memcpy(mtod(m, void *), &wh, sizeof(wh));
|
|
|
|
llc = (struct llc *)(mtod(m, char *) + sizeof(wh));
|
2001-09-18 13:09:57 +04:00
|
|
|
llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
|
|
|
|
llc->llc_control = LLC_UI;
|
|
|
|
llc->llc_snap.org_code[0] = 0;
|
|
|
|
llc->llc_snap.org_code[1] = 0;
|
|
|
|
llc->llc_snap.org_code[2] = 0;
|
|
|
|
llc->llc_snap.ether_type = eh.ether_type;
|
|
|
|
return m;
|
1999-11-04 20:10:53 +03:00
|
|
|
}
|