Bring in the IWI driver from FreeBSD and merge in ALTQ support.
authorMatthew Dillon <dillon@dragonflybsd.org>
Sun, 6 Mar 2005 05:02:03 +0000 (05:02 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sun, 6 Mar 2005 05:02:03 +0000 (05:02 +0000)
Bring in a number of ifconfig updates from FreeBSD.

Submitted-by: Andrew Atrens <atrens@nortel.com>
Original-Author: Damien Bergamini <damien.bergamini@free.fr> (IWI)

16 files changed:
sbin/ifconfig/ifconfig.8
sbin/ifconfig/ifconfig.c
sbin/ifconfig/ifconfig.h
sbin/ifconfig/ifieee80211.c
sbin/ifconfig/ifmedia.c
sbin/ifconfig/ifvlan.c
share/man/man4/Makefile
sys/dev/netif/Makefile
sys/dev/netif/iwi/Makefile [new file with mode: 0644]
sys/dev/netif/iwi/if_iwi.c [new file with mode: 0644]
sys/dev/netif/iwi/if_iwireg.h [new file with mode: 0644]
sys/dev/netif/iwi/if_iwivar.h [new file with mode: 0644]
usr.sbin/Makefile
usr.sbin/iwicontrol/Makefile [new file with mode: 0644]
usr.sbin/iwicontrol/iwicontrol.8 [new file with mode: 0644]
usr.sbin/iwicontrol/iwicontrol.c [new file with mode: 0644]

index 1edfd60..c42b9bd 100644 (file)
@@ -9,10 +9,6 @@
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\"    must display the following acknowledgment:
-.\"    This product includes software developed by the University of
-.\"    California, Berkeley and its contributors.
 .\" 4. Neither the name of the University nor the names of its contributors
 .\"    may be used to endorse or promote products derived from this software
 .\"    without specific prior written permission.
 .\" SUCH DAMAGE.
 .\"
 .\"     From: @(#)ifconfig.8   8.3 (Berkeley) 1/5/94
-.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.27.2.22 2003/01/26 03:33:56 keramida Exp $
-.\" $DragonFly: src/sbin/ifconfig/ifconfig.8,v 1.4 2004/11/13 04:13:22 cpressey Exp $
+.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.85 2004/07/27 09:51:49 yar Exp $
+.\" $DragonFly: src/sbin/ifconfig/ifconfig.8,v 1.5 2005/03/06 05:01:59 dillon Exp $
 .\"
-.Dd July 2, 2001
+.Dd July 26, 2004
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -140,7 +136,7 @@ The link-level
 address
 is specified as a series of colon-separated hex digits.
 This can be used to
-e.g. set a new MAC address on an ethernet interface, though the
+e.g.\& set a new MAC address on an ethernet interface, though the
 mechanism used is not ethernet-specific.
 If the interface is already
 up when this option is used, it will be briefly brought down and
@@ -201,9 +197,7 @@ Usually
 .Li 0xffffffff
 is most appropriate.
 .It Fl alias
-Remove the specified network address from this interface
-(if none is specified, all network addresses for the interface
-are removed.)
+Remove the network address specified.
 This would be used if you incorrectly specified an alias, or it
 was no longer needed.
 If you have incorrectly set an NS address having the side effect
@@ -271,6 +265,12 @@ automatically.
 .\" IP encapsulation of
 .\" .Tn CLNP
 .\" packets is done differently.
+ .It Cm maclabel Ar label
+ If Mandatory Access Control support is enabled in the kernel,
+ set the MAC label to
+ .Ar label .
+.\" (see
+.\" .Xr maclabel 7 ) .
 .It Cm media Ar type
 If the driver supports the media selection system, set the media type
 of the interface to
@@ -282,10 +282,10 @@ interface might support the use of either
 .Tn AUI
 or twisted pair connectors.
 Setting the media type to
-.Dq 10base5/AUI
+.Dq Li 10base5/AUI
 would change the currently active connector to the AUI port.
 Setting it to
-.Dq 10baseT/UTP
+.Dq Li 10baseT/UTP
 would activate twisted pair.
 Refer to the interfaces' driver
 specific documentation or man page for a complete list of the
@@ -302,6 +302,40 @@ list of available options.
 .It Fl mediaopt Ar opts
 If the driver supports the media selection system, disable the
 specified media options on the interface.
+.It Cm mode Ar mode
+If the driver supports the media selection system, set the specified
+operating mode on the interface to
+.Ar mode .
+For IEEE 802.11 wireless interfaces that support multiple operating modes
+this directive is used to select between 802.11a
+.Pq Dq Li 11a ,
+802.11b
+.Pq Dq Li 11b ,
+and 802.11g
+.Pq Dq Li 11g
+operating modes.
+.It Cm name Ar name
+Set the interface name to
+.Ar name .
+.It Cm rxcsum , txcsum
+If the driver supports user-configurable checksum offloading,
+enable receive (or transmit) checksum offloading on the interface.
+Some drivers may not be able to enable these flags independently
+of each other, so setting one may also set the other.
+The driver will offload as much checksum work as it can reliably
+support, the exact level of offloading varies between drivers.
+.\".It Fl rxcsum , Fl txcsum
+.\"If the driver supports user-configurable checksum offloading,
+.\"disable receive (or transmit) checksum offloading on the interface.
+.\"These settings may not always be independent of each other.
+.\".It Cm polling
+.\"If the driver has user-configurable
+.\".Xr polling 4
+.\"support, select the polling mode on the interface.
+.\".It Fl polling
+.\"If the driver has user-configurable
+.\".Xr polling 4
+.\"support, select the interrupt mode on the interface.
 .It Cm tunnel Ar src_addr dest_addr
 (IP tunnel devices only.)
 Configure the physical source and destination address for IP tunnel
@@ -340,55 +374,88 @@ Included for
 .Tn Solaris
 compatibility.
 .It Cm vlan Ar vlan_tag
-If the interface is a vlan pseudo interface, set the vlan tag value
+If the interface is a
+.Xr vlan 4
+pseudo interface, set the VLAN tag value
 to
 .Ar vlan_tag .
 This value is a 16-bit number which is used to create an 802.1Q
-vlan header for packets sent from the vlan interface.
+VLAN header for packets sent from the
+.Xr vlan 4
+interface.
 Note that
 .Cm vlan
 and
 .Cm vlandev
 must both be set at the same time.
 .It Cm vlandev Ar iface
-If the interface is a vlan pseudo device, associate physical interface
+If the interface is a
+.Xr vlan 4
+pseudo device, associate physical interface
 .Ar iface
 with it.
-Packets transmitted through the vlan interface will be
+Packets transmitted through the
+.Xr vlan 4
+interface will be
 diverted to the specified physical interface
 .Ar iface
-with 802.1Q vlan encapsulation.
+with 802.1Q VLAN encapsulation.
 Packets with 802.1Q encapsulation received
-by the parent interface with the correct vlan tag will be diverted to
-the associated vlan pseudo-interface.
-The vlan interface is assigned a
+by the parent interface with the correct VLAN tag will be diverted to
+the associated
+.Xr vlan 4
+pseudo-interface.
+The
+.Xr vlan 4
+interface is assigned a
 copy of the parent interface's flags and the parent's ethernet address.
 The
 .Cm vlandev
 and
 .Cm vlan
 must both be set at the same time.
-If the vlan interface already has
+If the
+.Xr vlan 4
+interface already has
 a physical interface associated with it, this command will fail.
 To
 change the association to another physical interface, the existing
 association must be cleared first.
 .Pp
-Note: if the
-.Cm link0
-flag is set on the vlan interface, the vlan pseudo
-interface's behavior changes: the
-.Cm link0
-tells the vlan interface that the
-parent interface supports insertion and extraction of vlan tags on its
+Note: if the hardware tagging capability
+is set on the parent interface, the
+.Xr vlan 4
+pseudo
+interface's behavior changes:
+the
+.Xr vlan 4
+interface recognizes that the
+parent interface supports insertion and extraction of VLAN tags on its
 own (usually in firmware) and that it should pass packets to and from
 the parent unaltered.
 .It Fl vlandev Ar iface
-If the driver is a vlan pseudo device, disassociate the physical interface
+If the driver is a
+.Xr vlan 4
+pseudo device, disassociate the physical interface
 .Ar iface
 from it.
-This breaks the link between the vlan interface and its parent,
-clears its vlan tag, flags and its link address and shuts the interface down.
+This breaks the link between the
+.Xr vlan 4
+interface and its parent,
+clears its VLAN tag, flags and its link address and shuts the interface down.
+.It Cm vlanmtu , vlanhwtag
+If the driver offers user-configurable VLAN support, enable
+reception of extended frames or tag processing in hardware,
+respectively.
+Note that this must be issued on a physical interface associated with
+.Xr vlan 4 ,
+not on a
+.Xr vlan 4
+interface itself.
+.It Fl vlanmtu , Fl vlanhwtag
+If the driver offers user-configurable VLAN support, disable
+reception of extended frames or tag processing in hardware,
+respectively.
 .It Cm metric Ar n
 Set the routing metric of the interface to
 .Ar n ,
@@ -479,7 +546,7 @@ of the form
 .Ar startnet Ns - Ns Ar endnet .
 Appletalk uses this scheme instead of
 netmasks though
-.Dx
+.Fx
 implements it internally as a set of netmasks.
 .It Cm remove
 Another name for the
@@ -507,6 +574,13 @@ for more information.
 .It Fl link Op Cm 0 No - Cm 2
 .Sm on
 Disable special processing at the link level with the specified interface.
+.\".It Cm monitor
+.\"Put the interface in monitor mode.
+.\"No packets are transmitted, and received packets are discarded after
+.\".Xr bpf 4
+.\"processing.
+.\".It Fl monitor
+.\"Take the interface out of monitor mode.
 .It Cm up
 Mark an interface
 .Dq up .
@@ -559,10 +633,10 @@ in infrastructure mode.
 Not all adaptors support all modes.
 The set of
 valid modes is
-.Dq none ,
-.Dq open ,
+.Dq Li none ,
+.Dq Li open ,
 and
-.Dq shared .
+.Dq Li shared .
 Modes are case insensitive.
 .It Cm powersave
 For IEEE 802.11 wireless interfaces, enable powersave mode.
@@ -571,24 +645,58 @@ For IEEE 802.11 wireless interfaces, disable powersave mode.
 .It Cm powersavesleep Ar sleep
 For IEEE 802.11 wireless interfaces, set the desired max powersave sleep
 time in milliseconds.
+.It Cm protmode Ar technique
+For IEEE 802.11 wireless interfaces operating in 11g, use the specified
+.Ar technique
+for protecting OFDM frames in a mixed 11b/11g network.
+The set of valid techniques is
+.Dq Li off ,
+.Dq Li cts
+(CTS to self),
+and
+.Dq Li rtscts
+(RTS/CTS).
+Technique names are case insensitive.
+.It Cm rtsthreshold Ar length
+For IEEE 802.11 wireless interfaces, set the threshold for which
+transmitted frames are preceded by transmission of an
+RTS
+control frame.
+The
+.Ar length
+argument
+is the frame size in bytes and must be in the range 1 to 2312.
+Not all adaptors support setting the RTS threshold.
+.It Cm txpower Ar power
+For IEEE 802.11 wireless interfaces, set the power used to transmit frames.
+The
+.Ar power
+argument
+is a unitless value in the range 0 to 100 that is interpreted
+by drivers to derive a device-specific value.
+Out of range values are truncated.
+Typically only a few discreet power settings are available and
+the driver will use the setting closest to the specified value.
+Not all adaptors support changing the transmit power.
 .It Cm wepmode Ar mode
 For IEEE 802.11 wireless interfaces, set the desired WEP mode.
 Not all adaptors support all modes.
 The set of valid modes is
-.Dq off ,
-.Dq on ,
+.Dq Li off ,
+.Dq Li on ,
 and
-.Dq mixed .
-.Dq Mixed
+.Dq Li mixed .
+The
+.Dq Li mixed
 mode explicitly tells the adaptor to allow association with access
 points which allow both encrypted and unencrypted traffic.
 On these adaptors,
-.Dq on
+.Dq Li on
 means that the access point must only allow encrypted connections.
 On other adaptors,
-.Dq on
+.Dq Li on
 is generally another name for
-.Dq mixed .
+.Dq Li mixed .
 Modes are case insensitive.
 .It Cm weptxkey Ar index
 For IEEE 802.11 wireless interfaces, set the WEP key to be used for
@@ -609,7 +717,7 @@ the mapping of text keys to WEP encryption is usually driver-specific.
 In particular, the
 .Tn Windows
 drivers do this mapping differently to
-.Dx .
+.Fx .
 A key may be cleared by setting it to
 .Ql - .
 If WEP is supported then there are at least four keys.
@@ -673,7 +781,7 @@ If the
 .Fl m
 flag is passed before an interface name,
 .Nm
-will display all
+will display the capability list and all
 of the supported media for the specified interface.
 If
 .Fl L
@@ -722,18 +830,26 @@ Messages indicating the specified interface does not exist, the
 requested address is unknown, or the user is not privileged and
 tried to alter an interface's configuration.
 .Sh BUGS
-IPv6 link-local addresses are required for several basic communication
-between IPv6 node.
-If they are deleted by
-.Nm
-manually, the kernel might show very strange behavior.
-So, such manual deletions are strongly discouraged.
+Basic IPv6 node operation requires a link-local address on each
+interface configured for IPv6.
+Normally, such an address is automatically configured by the
+kernel on each interface added to the system; this behaviour may
+be disabled by setting the sysctl MIB variable
+.Va net.inet6.ip6.auto_linklocal
+to 0.
+.Pp
+If you delete such an address using
+.Nm ,
+the kernel may act very oddly.
+Do this at your own risk.
 .Sh SEE ALSO
 .Xr netstat 1 ,
 .Xr netintro 4 ,
+.Xr vlan 4 ,
 .\" .Xr eon 5 ,
 .Xr rc 8 ,
-.Xr routed 8
+.Xr routed 8 ,
+.Xr sysctl 8
 .Sh HISTORY
 The
 .Nm
index da0562a..0c17588 100644 (file)
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
@@ -33,7 +29,7 @@
  * @(#) Copyright (c) 1983, 1993 The Regents of the University of California.  All rights reserved.
  * @(#)ifconfig.c      8.2 (Berkeley) 2/16/94
  * $FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.96 2004/02/27 06:43:14 kan Exp $
- * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.19 2005/03/04 02:37:44 cpressey Exp $
+ * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.20 2005/03/06 05:01:59 dillon Exp $
  */
 
 #include <sys/param.h>
 #define        NI_WITHSCOPEID  0
 #endif
 
+/*
+ * Since "struct ifreq" is composed of various union members, callers
+ * should pay special attention to interprete the value.
+ * (.e.g. little/big endian difference in the structure.)
+ */
 struct ifreq           ifr, ridreq;
 struct ifaliasreq      addreq;
 #ifdef INET6
@@ -235,8 +236,16 @@ struct     cmd {
        { "-link1",     -IFF_LINK1,     setifflags,     NULL },
        { "link2",      IFF_LINK2,      setifflags,     NULL },
        { "-link2",     -IFF_LINK2,     setifflags,     NULL },
+#if notyet
+       { "monitor",    IFF_MONITOR,    setifflags,     NULL },
+       { "-monitor",   -IFF_MONITOR,   setifflags,     NULL },
+       { "staticarp",  IFF_STATICARP,  setifflags,     NULL },
+       { "-staticarp", -IFF_STATICARP, setifflags,     NULL },
+#endif
+
 #ifdef USE_IF_MEDIA
        { "media",      NEXTARG,        setmedia,       NULL },
+       { "mode",       NEXTARG,        setmediamode,   NULL },
        { "mediaopt",   NEXTARG,        setmediaopt,    NULL },
        { "-mediaopt",  NEXTARG,        unsetmediaopt,  NULL },
 #endif
@@ -255,21 +264,27 @@ struct    cmd {
 #ifdef USE_IEEE80211
        { "ssid",       NEXTARG,        set80211ssid,   NULL },
        { "nwid",       NEXTARG,        set80211ssid,   NULL },
-       { "stationname", NEXTARG,       set80211stationname, NULL },
-       { "station",    NEXTARG,        set80211stationname, NULL },/* BSD/OS */
-       { "channel",    NEXTARG,        set80211channel, NULL },
-       { "authmode",   NEXTARG,        set80211authmode, NULL },
-       { "powersavemode", NEXTARG,     set80211powersavemode, NULL },
-       { "powersave",  1,              set80211powersave, NULL },
-       { "-powersave", 0,              set80211powersave, NULL },
-       { "powersavesleep", NEXTARG,    set80211powersavesleep, NULL },
-       { "wepmode",    NEXTARG,        set80211wepmode, NULL },
+       { "stationname", NEXTARG,       set80211stationname,    NULL },
+       { "station",    NEXTARG,        set80211stationname,    NULL }, /* BSD/OS */
+       { "channel",    NEXTARG,        set80211channel,        NULL },
+       { "authmode",   NEXTARG,        set80211authmode,       NULL },
+       { "powersavemode", NEXTARG,     set80211powersavemode,  NULL },
+       { "powersave",  1,              set80211powersave,      NULL },
+       { "-powersave", 0,              set80211powersave,      NULL },
+       { "powersavesleep", NEXTARG,    set80211powersavesleep, NULL },
+       { "wepmode",    NEXTARG,        set80211wepmode,        NULL },
        { "wep",        1,              set80211wep,    NULL },
        { "-wep",       0,              set80211wep,    NULL },
-       { "weptxkey",   NEXTARG,        set80211weptxkey, NULL },
+       { "weptxkey",   NEXTARG,        set80211weptxkey,       NULL },
        { "wepkey",     NEXTARG,        set80211wepkey, NULL },
        { "nwkey",      NEXTARG,        set80211nwkey,  NULL }, /* NetBSD */
-       { "-nwkey",     0,              set80211wep,    NULL }, /* NetBSD */
+       { "-nwkey",     0,              set80211wep,    NULL },         /* NetBSD */
+       { "rtsthreshold",NEXTARG,       set80211rtsthreshold,   NULL },
+       { "protmode",   NEXTARG,        set80211protmode,       NULL },
+       { "txpower",    NEXTARG,        set80211txpower,        NULL },
+#endif
+#ifdef USE_MAC
+       { "maclabel",   NEXTARG,        setifmaclabel,  NULL },
 #endif
        { "rxcsum",     IFCAP_RXCSUM,   setifcap,       NULL },
        { "-rxcsum",    -IFCAP_RXCSUM,  setifcap,       NULL },
@@ -279,6 +294,10 @@ struct     cmd {
        { "-netcons",   -IFCAP_NETCONS, setifcap,       NULL },
        { "polling",    IFCAP_POLLING,  setifcap,       NULL },
        { "-polling",   -IFCAP_POLLING, setifcap,       NULL },
+       { "vlanmtu",    IFCAP_VLAN_MTU,         setifcap,       NULL },
+       { "-vlanmtu",   -IFCAP_VLAN_MTU,        setifcap,       NULL },
+       { "vlanhwtag",  IFCAP_VLAN_HWTAGGING,   setifcap,       NULL },
+       { "-vlanhwtag", -IFCAP_VLAN_HWTAGGING,  setifcap,       NULL },
        { "normal",     -IFF_LINK0,     setifflags,     NULL },
        { "compress",   IFF_LINK0,      setifflags,     NULL },
        { "noicmp",     IFF_LINK1,      setifflags,     NULL },
@@ -351,17 +370,6 @@ struct     afswtch {
             0, SIOCSIFLLADDR, NULL, C(ridreq) },
        { "lladdr", AF_LINK, link_status, link_getaddr, NULL,
             0, SIOCSIFLLADDR, NULL, C(ridreq) },
-#if 0  /* XXX conflicts with the media command */
-#ifdef USE_IF_MEDIA
-       { "media", AF_UNSPEC, media_status, NULL, NULL, }, /* XXX not real!! */
-#endif
-#ifdef USE_VLANS
-       { "vlan", AF_UNSPEC, vlan_status, NULL, NULL, },  /* XXX not real!! */
-#endif
-#ifdef USE_IEEE80211
-       { "ieee80211", AF_UNSPEC, ieee80211_status, NULL, NULL, },  /* XXX not real!! */
-#endif
-#endif
        { NULL, 0,      NULL, NULL, NULL,       0, 0,   NULL, NULL }
 };
 
@@ -371,22 +379,22 @@ struct    afswtch {
  */
 
 #define ROUNDUP(a) \
-       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
 
 void
 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
 {
-       struct sockaddr *sa;
-       int i;
-
-       memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
-       for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
-               if ((rtinfo->rti_addrs & (1 << i)) == 0)
-                       continue;
-               rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
-               ADVANCE(cp, sa);
-       }
+        struct sockaddr *sa;
+        int i;
+
+        memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+        for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+                if ((rtinfo->rti_addrs & (1 << i)) == 0)
+                        continue;
+                rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+                ADVANCE(cp, sa);
+        }
 }
 
 
@@ -420,7 +428,7 @@ main(int argc, char * const *argv)
 {
        int c;
        int all, namesonly, downonly, uponly;
-       int need_nl = 0;
+       int need_nl = 0, count = 0;
        const struct afswtch *afp = 0;
        int addrcount, ifindex;
        struct  if_msghdr *ifm, *nextifm;
@@ -547,12 +555,13 @@ main(int argc, char * const *argv)
                        afp = NULL;     /* not a family, NULL */
        }
 
+retry:
        mib[0] = CTL_NET;
        mib[1] = PF_ROUTE;
        mib[2] = 0;
-       mib[3] = 0;             /* address family */
+       mib[3] = 0;                     /* address family */
        mib[4] = NET_RT_IFLIST;
-       mib[5] = ifindex;       /* interface index */
+       mib[5] = ifindex;               /* interface index */
 
        /* if particular family specified, only ask about it */
        if (afp)
@@ -562,8 +571,15 @@ main(int argc, char * const *argv)
                errx(1, "iflist-sysctl-estimate");
        if ((buf = malloc(needed)) == NULL)
                errx(1, "malloc");
-       if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+       if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+               if (errno == ENOMEM && count++ < 10) {
+                       warnx("Routing table grew, retrying");
+                       free(buf);
+                       sleep(1);
+                       goto retry;
+               }
                errx(1, "actual retrieval of interface table");
+       }
        lim = buf + needed;
 
        next = buf;
@@ -572,7 +588,14 @@ main(int argc, char * const *argv)
                ifm = (struct if_msghdr *)next;
                
                if (ifm->ifm_type == RTM_IFINFO) {
-                       sdl = (struct sockaddr_dl *)(ifm + 1);
+#if  notyet
+                       if (ifm->ifm_data.ifi_datalen == 0)
+                               ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
+                       sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
+                            sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
+#else
+                       sdl = (struct sockaddr_dl *)(ifm + 1);
+#endif
                        flags = ifm->ifm_flags;
                } else {
                        fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n");
@@ -600,8 +623,11 @@ main(int argc, char * const *argv)
                        addrcount++;
                        next += nextifm->ifm_msglen;
                }
-               strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
-               name[sdl->sdl_nlen] = '\0';
+               memcpy(name, sdl->sdl_data,
+                   sizeof(name) < sdl->sdl_nlen ?
+                   sizeof(name)-1 : sdl->sdl_nlen);
+               name[sizeof(name) < sdl->sdl_nlen ?
+                   sizeof(name)-1 : sdl->sdl_nlen] = '\0';
 
                if (all || namesonly) {
                        size_t len;
@@ -842,7 +868,6 @@ void
 deletetunnel(const char *vname __unused, int param __unused, int s,
             const struct afswtch *afp __unused)
 {
-
        if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
                err(1, "SIOCDIFPHYADDR");
 }
@@ -976,9 +1001,10 @@ notealias(const char *addr __unused, int param, int s __unused,
          const struct afswtch *afp)
 {
        if (setaddr && doalias == 0 && param < 0)
-               bcopy((caddr_t)rqtosa(af_addreq),
-                     (caddr_t)rqtosa(af_ridreq),
-                     rqtosa(af_addreq)->sa_len);
+               if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
+                       bcopy((caddr_t)rqtosa(af_addreq),
+                             (caddr_t)rqtosa(af_ridreq),
+                             rqtosa(af_addreq)->sa_len);
        doalias = param;
        if (param < 0) {
                clearaddr = 1;
@@ -1096,10 +1122,10 @@ setifname(const char *val, int dummy __unused, int s,
 #define        IFFBITS \
 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
-"\20MULTICAST"
+"\20MULTICAST\21POLLING\23MONITOR\24STATICARP"
 
 #define        IFCAPBITS \
-"\003\1rxcsum\2txcsum\3netcons\7polling"
+"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING"
 
 /*
  * Print the status of the interface.  If an address family was
@@ -1181,12 +1207,19 @@ status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl,
 #ifdef USE_IEEE80211
        if (allfamilies || afp->af_status == ieee80211_status)
                ieee80211_status(s, NULL);
+#endif
+#ifdef USE_MAC
+       if (allfamilies || afp->af_status == maclabel_status)
+               maclabel_status(s, NULL);
 #endif
        strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
        if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
                printf("%s", ifs.ascii);
 
-       if (!allfamilies && !p && afp->af_status != media_status &&
+       if (!allfamilies && !p &&
+#ifdef USE_IF_MEDIA
+           afp->af_status != media_status &&
+#endif
            afp->af_status != link_status
 #ifdef USE_VLANS
            && afp->af_status != vlan_status
@@ -1300,7 +1333,7 @@ in_status(int s __unused, struct rt_addrinfo *info)
 #ifdef INET6
 #if defined(__KAME__) && defined(KAME_SCOPEID)
 void
-in6_fillscopeid(struct sockaddr_in6 *sin6)
+in6_fillscopeid(struct sockaddr_in6 *sin6 __unused)
 {
        if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
                sin6->sin6_scope_id =
@@ -1760,9 +1793,9 @@ void
 setatrange(const char *range, int dummy __unused, int s __unused,
            const struct afswtch *afp __unused)
 {
-       u_short first = 123, last = 123;
+       u_int   first = 123, last = 123;
 
-       if (sscanf(range, "%hu-%hu", &first, &last) != 2
+       if (sscanf(range, "%u-%u", &first, &last) != 2
            || first == 0 || first > 0xffff
            || last == 0 || last > 0xffff || first > last)
                errx(1, "%s: illegal net range: %u-%u", range, first, last);
@@ -1972,7 +2005,7 @@ clone_create(void)
                err(1, "socket");
 
        memset(&ifr, 0, sizeof(ifr));
-       strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+       (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
        if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
                err(1, "SIOCIFCREATE");
 
@@ -1994,7 +2027,7 @@ clone_destroy(const char *val __unused, int d __unused, int s,
              const struct afswtch *rafp __unused)
 {
 
-       strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+       (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
        if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
                err(1, "SIOCIFDESTROY");
        /*
index de90fba..01c5ee9 100644 (file)
@@ -31,8 +31,8 @@
  *
  * so there!
  *
- * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.5.2.2 2001/07/04 20:49:20 brooks Exp $
- * $DragonFly: src/sbin/ifconfig/ifconfig.h,v 1.3 2004/03/15 22:39:37 hmp Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.12 2004/03/30 22:59:22 sam Exp $
+ * $DragonFly: src/sbin/ifconfig/ifconfig.h,v 1.4 2005/03/06 05:01:59 dillon Exp $
  */
 
 extern struct ifreq ifr;
@@ -43,6 +43,7 @@ extern int supmedia;
 struct afswtch;
 
 extern void setmedia(const char *, int, int, const struct afswtch *rafp);
+extern void setmediamode(const char *, int, int, const struct afswtch *rafp);
 extern void setmediaopt(const char *, int, int, const struct afswtch *rafp);
 extern void unsetmediaopt(const char *, int, int, const struct afswtch *rafp);
 extern void media_status(int s, struct rt_addrinfo *);
@@ -64,4 +65,9 @@ extern void set80211wep(const char *, int, int, const struct afswtch *rafp);
 extern void set80211weptxkey(const char *, int, int, const struct afswtch *rafp);
 extern void set80211wepkey(const char *, int, int, const struct afswtch *rafp);
 extern void set80211nwkey(const char *, int, int, const struct afswtch *rafp);
+extern void set80211rtsthreshold(const char *, int, int, const struct afswtch *rafp);
+extern void set80211protmode(const char *, int, int, const struct afswtch *rafp);
+extern void set80211txpower(const char *, int, int, const struct afswtch *rafp);
 extern void ieee80211_status(int s, struct rt_addrinfo *);
+extern void maclabel_status(int s, struct rt_addrinfo *);
+extern void setifmaclabel(const char *, int, int, const struct afswtch *rafp);
index ec1be43..0ff8f20 100644 (file)
@@ -9,6 +9,8 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
+ * 3. The name of The Aerospace Corporation may not be used to endorse or
+ *    promote products derived from this software.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -23,7 +25,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.1.2.3 2002/02/07 15:12:37 ambrisko Exp $
- * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.7 2005/03/04 00:11:11 cpressey Exp $
+ * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.8 2005/03/06 05:01:59 dillon Exp $
  */
 
 /*-
@@ -75,6 +77,7 @@
 #include <net/if_types.h>
 #include <net/route.h>
 #include <netproto/802_11/ieee80211.h>
+#include <netproto/802_11/ieee80211_crypto.h>
 #include <netproto/802_11/ieee80211_ioctl.h>
 
 #include <ctype.h>
@@ -102,7 +105,7 @@ set80211ssid(const char *val, int d __unused, int s,
        u_int8_t        data[33];
 
        ssid = 0;
-       len = sizeof(val);
+       len = strlen(val);
        if (len > 2 && isdigit(val[0]) && val[1] == ':') {
                ssid = atoi(val)-1;
                val += 2;
@@ -133,7 +136,10 @@ void
 set80211channel(const char *val, int d __unused, int s,
                const struct afswtch *rafp __unused)
 {
-       set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
+       if (strcmp(val, "-") == 0)
+               set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
+       else
+               set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
 }
 
 void
@@ -142,11 +148,11 @@ set80211authmode(const char *val, int d __unused, int s,
 {
        int     mode;
 
-       if(strcasecmp(val, "none") == 0) {
+       if (strcasecmp(val, "none") == 0) {
                mode = IEEE80211_AUTH_NONE;
-       } else if(strcasecmp(val, "open") == 0) {
+       } else if (strcasecmp(val, "open") == 0) {
                mode = IEEE80211_AUTH_OPEN;
-       } else if(strcasecmp(val, "shared") == 0) {
+       } else if (strcasecmp(val, "shared") == 0) {
                mode = IEEE80211_AUTH_SHARED;
        } else {
                err(1, "unknown authmode");
@@ -161,15 +167,15 @@ set80211powersavemode(const char *val, int d __unused, int s,
 {
        int     mode;
 
-       if(strcasecmp(val, "off") == 0) {
+       if (strcasecmp(val, "off") == 0) {
                mode = IEEE80211_POWERSAVE_OFF;
-       } else if(strcasecmp(val, "on") == 0) {
+       } else if (strcasecmp(val, "on") == 0) {
                mode = IEEE80211_POWERSAVE_ON;
-       } else if(strcasecmp(val, "cam") == 0) {
+       } else if (strcasecmp(val, "cam") == 0) {
                mode = IEEE80211_POWERSAVE_CAM;
-       } else if(strcasecmp(val, "psp") == 0) {
+       } else if (strcasecmp(val, "psp") == 0) {
                mode = IEEE80211_POWERSAVE_PSP;
-       } else if(strcasecmp(val, "psp-cam") == 0) {
+       } else if (strcasecmp(val, "psp-cam") == 0) {
                mode = IEEE80211_POWERSAVE_PSP_CAM;
        } else {
                err(1, "unknown powersavemode");
@@ -203,11 +209,11 @@ set80211wepmode(const char *val, int d __unused, int s,
 {
        int     mode;
 
-       if(strcasecmp(val, "off") == 0) {
+       if (strcasecmp(val, "off") == 0) {
                mode = IEEE80211_WEP_OFF;
-       } else if(strcasecmp(val, "on") == 0) {
+       } else if (strcasecmp(val, "on") == 0) {
                mode = IEEE80211_WEP_ON;
-       } else if(strcasecmp(val, "mixed") == 0) {
+       } else if (strcasecmp(val, "mixed") == 0) {
                mode = IEEE80211_WEP_MIXED;
        } else {
                err(1, "unknown wep mode");
@@ -236,9 +242,9 @@ set80211wepkey(const char *val, int d __unused, int s,
 {
        int             key = 0;
        int             len;
-       u_int8_t        data[14];
+       u_int8_t        data[IEEE80211_KEYBUF_SIZE];
 
-       if(isdigit(val[0]) && val[1] == ':') {
+       if (isdigit(val[0]) && val[1] == ':') {
                key = atoi(val)-1;
                val += 2;
        }
@@ -251,7 +257,7 @@ set80211wepkey(const char *val, int d __unused, int s,
 }
 
 /*
- * This function is purly a NetBSD compatibility interface.  The NetBSD
+ * This function is purly a NetBSD compatability interface.  The NetBSD
  * iterface is too inflexable, but it's there so we'll support it since
  * it's not all that hard.
  */
@@ -261,15 +267,15 @@ set80211nwkey(const char *val, int d __unused, int s,
 {
        int             txkey;
        int             i, len;
-       u_int8_t        data[14];
+       u_int8_t        data[IEEE80211_KEYBUF_SIZE];
 
        set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
 
-       if(isdigit(val[0]) && val[1] == ':') {
+       if (isdigit(val[0]) && val[1] == ':') {
                txkey = val[0]-'0'-1;
                val += 2;
 
-               for(i = 0; i < 4; i++) {
+               for (i = 0; i < 4; i++) {
                        bzero(data, sizeof(data));
                        len = sizeof(data);
                        val = get_string(val, ",", data, &len);
@@ -285,13 +291,46 @@ set80211nwkey(const char *val, int d __unused, int s,
                set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
 
                bzero(data, sizeof(data));
-               for(i = 1; i < 4; i++)
+               for (i = 1; i < 4; i++)
                        set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
        }
 
        set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
 }
 
+void
+set80211rtsthreshold(const char *val, int d __unused, int s,
+       const struct afswtch *rafp __unused)
+{
+       set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL);
+}
+
+void
+set80211protmode(const char *val, int d __unused, int s,
+       const struct afswtch *rafp __unused)
+{
+       int     mode;
+
+       if (strcasecmp(val, "off") == 0) {
+               mode = IEEE80211_PROTMODE_OFF;
+       } else if (strcasecmp(val, "cts") == 0) {
+               mode = IEEE80211_PROTMODE_CTS;
+       } else if (strcasecmp(val, "rtscts") == 0) {
+               mode = IEEE80211_PROTMODE_RTSCTS;
+       } else {
+               err(1, "unknown protection mode");
+       }
+
+       set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
+}
+
+void
+set80211txpower(const char *val, int d __unused, int s,
+       const struct afswtch *rafp __unused)
+{
+       set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
+}
+
 void
 ieee80211_status (int s, struct rt_addrinfo *info __unused)
 {
@@ -301,8 +340,8 @@ ieee80211_status (int s, struct rt_addrinfo *info __unused)
        u_int8_t                data[32];
        char                    spacer;
 
-       memset(&ireq, 0, sizeof(ireq));
-       strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
        ireq.i_data = &data;
 
        ireq.i_type = IEEE80211_IOC_SSID;
@@ -380,13 +419,49 @@ ieee80211_status (int s, struct rt_addrinfo *info __unused)
 
                ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
                if (ioctl(s, SIOCG80211, &ireq) != -1) {
-                       if(ireq.i_val)
+                       if (ireq.i_val)
                                printf(" powersavesleep %d", ireq.i_val);
                }
        }
 
        printf("\n");
 
+       spacer = '\t';
+       ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               printf("%crtsthreshold %d", spacer, ireq.i_val);
+               spacer = ' ';
+       }
+
+       ireq.i_type = IEEE80211_IOC_PROTMODE;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               printf("%cprotmode", spacer);
+               switch (ireq.i_val) {
+                       case IEEE80211_PROTMODE_OFF:
+                               printf(" OFF");
+                               break;
+                       case IEEE80211_PROTMODE_CTS:
+                               printf(" CTS");
+                               break;
+                       case IEEE80211_PROTMODE_RTSCTS:
+                               printf(" RTSCTS");
+                               break;
+                       default:
+                               printf(" UNKNOWN");
+                               break;
+               }
+               spacer = ' ';
+       }
+
+       ireq.i_type = IEEE80211_IOC_TXPOWER;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               printf("%ctxpower %d", spacer, ireq.i_val);
+               spacer = ' ';
+       }
+
+       if (spacer != '\t')
+               printf("\n");
+
        ireq.i_type = IEEE80211_IOC_WEP;
        if (ioctl(s, SIOCG80211, &ireq) != -1 &&
            ireq.i_val != IEEE80211_WEP_NOSUP) {
@@ -409,7 +484,7 @@ ieee80211_status (int s, struct rt_addrinfo *info __unused)
                /*
                 * If we get here then we've got WEP support so we need
                 * to print WEP status.
-                */ 
+                */
 
                ireq.i_type = IEEE80211_IOC_WEPTXKEY;
                if (ioctl(s, SIOCG80211, &ireq) < 0) {
@@ -429,17 +504,19 @@ ieee80211_status (int s, struct rt_addrinfo *info __unused)
 
                ireq.i_type = IEEE80211_IOC_WEPKEY;
                spacer = '\t';
-               for(i = 0; i < num; i++) {
+               for (i = 0; i < num; i++) {
                        ireq.i_val = i;
                        if (ioctl(s, SIOCG80211, &ireq) < 0) {
                                warn("WEP support, but can get keys!");
                                goto end;
                        }
-                       if(ireq.i_len == 0 || ireq.i_len > 13)
+                       if (ireq.i_len == 0 ||
+                           ireq.i_len > IEEE80211_KEYBUF_SIZE)
                                continue;
                        printf("%cwepkey %d:%s", spacer, i+1,
-                           ireq.i_len <= 5 ? "64-bit" : "128-bit");
-                       if(spacer == '\t')
+                           ireq.i_len <= 5 ? "40-bit" :
+                           ireq.i_len <= 13 ? "104-bit" : "128-bit");
+                       if (spacer == '\t')
                                spacer = ' ';
                }
                if (spacer == ' ')
@@ -455,13 +532,13 @@ set80211(int s, int type, int val, int len, u_int8_t *data)
 {
        struct ieee80211req     ireq;
 
-       memset(&ireq, 0, sizeof(ireq));
-       strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
        ireq.i_type = type;
        ireq.i_val = val;
        ireq.i_len = len;
        ireq.i_data = data;
-       if(ioctl(s, SIOCS80211, &ireq) < 0)
+       if (ioctl(s, SIOCS80211, &ireq) < 0)
                err(1, "SIOCS80211");
 }
 
@@ -485,17 +562,20 @@ get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
                        break;
                }
                if (hexstr) {
-                       if (!isxdigit((u_char)val[0]) ||
-                           !isxdigit((u_char)val[1])) {
+                       if (!isxdigit((u_char)val[0])) {
                                warnx("bad hexadecimal digits");
                                return NULL;
                        }
+                       if (!isxdigit((u_char)val[1])) {
+                               warnx("odd count hexadecimal digits");
+                               return NULL;
+                       }
                }
-               if (p > buf + len) {
+               if (p >= buf + len) {
                        if (hexstr)
                                warnx("hexadecimal digits too long");
                        else
-                               warnx("strings too long");
+                               warnx("string too long");
                        return NULL;
                }
                if (hexstr) {
@@ -525,7 +605,7 @@ print_string(const u_int8_t *buf, int len)
 
        i = 0;
        hasspc = 0;
-       for(; i < len; i++) {
+       for (; i < len; i++) {
                if (!isprint(buf[i]) && buf[i] != '\0')
                        break;
                if (isspace(buf[i]))
index 9cf1db6..e95f8c3 100644 (file)
@@ -1,6 +1,6 @@
 /*     $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $      */
 /* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.6.2.3 2001/11/14 04:35:07 yar Exp $ */
-/* $DragonFly: src/sbin/ifconfig/ifmedia.c,v 1.7 2005/03/04 00:11:11 cpressey Exp $ */
+/* $DragonFly: src/sbin/ifconfig/ifmedia.c,v 1.8 2005/03/06 05:01:59 dillon Exp $ */
 
 /*
  * Copyright (c) 1997 Jason R. Thorpe.
 
 #include "ifconfig.h"
 
+#ifndef IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS
+  #define IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS {                       \
+        { IFM_AUTO, "autoselect" },                                     \
+        { IFM_IEEE80211_11A, "11a" },                                   \
+        { IFM_IEEE80211_11B, "11b" },                                   \
+        { IFM_IEEE80211_11G, "11g" },                                   \
+        { IFM_IEEE80211_FH, "fh" },                                     \
+        { 0, NULL },                                                    \
+}
+#endif
+
+#ifndef IFM_SUBTYPE_IEEE80211_MODE_ALIASES
+  #define IFM_SUBTYPE_IEEE80211_MODE_ALIASES {                            \
+        { IFM_AUTO, "auto" },                                           \
+        { 0, NULL },                                                    \
+}
+#endif
+
 static void    domediaopt(const char *, int, int);
 static int     get_media_subtype(int, const char *);
+static int     get_media_mode(int, const char *);
 static int     get_media_options(int, const char *);
 static int     lookup_media_word(struct ifmedia_description *, const char *);
 static void    print_media_word(int, int);
@@ -108,8 +127,8 @@ media_status(int s, struct rt_addrinfo *info __unused)
        struct ifmediareq ifmr;
        int *media_list, i;
 
-       memset(&ifmr, 0, sizeof(ifmr));
-       strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+       (void) memset(&ifmr, 0, sizeof(ifmr));
+       (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
 
        if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
                /*
@@ -159,6 +178,16 @@ media_status(int s, struct rt_addrinfo *info __unused)
                        else
                                printf("no ring");
                        break;
+
+#if notyet
+               case IFM_ATM:
+                       if (ifmr.ifm_status & IFM_ACTIVE)
+                               printf("active");
+                       else
+                               printf("no carrier");
+                       break;
+#endif
+
                case IFM_IEEE80211:
                        /* XXX: Different value for adhoc? */
                        if (ifmr.ifm_status & IFM_ACTIVE)
@@ -189,8 +218,8 @@ setmedia(const char *val, int d __unused, int s,
        struct ifmediareq ifmr;
        int first_type, subtype;
 
-       memset(&ifmr, 0, sizeof(ifmr));
-       strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+       (void) memset(&ifmr, 0, sizeof(ifmr));
+       (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
 
        ifmr.ifm_count = 1;
        ifmr.ifm_ulist = &first_type;
@@ -222,7 +251,7 @@ setmedia(const char *val, int d __unused, int s,
            IFM_TYPE(first_type) | subtype;
 
        if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
-               err(1, "SIOCSIFMEDIA");
+               err(1, "SIOCSIFMEDIA (media)");
 }
 
 void
@@ -247,8 +276,8 @@ domediaopt(const char *val, int clear, int s)
        struct ifmediareq ifmr;
        int *mwords, options;
 
-       memset(&ifmr, 0, sizeof(ifmr));
-       strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+       (void) memset(&ifmr, 0, sizeof(ifmr));
+       (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
 
        /*
         * We must go through the motions of reading all
@@ -282,7 +311,49 @@ domediaopt(const char *val, int clear, int s)
                ifr.ifr_media |= options;
 
        if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
-               err(1, "SIOCSIFMEDIA");
+               err(1, "SIOCSIFMEDIA (mediaopt)");
+}
+
+
+void
+setmediamode(const char *val, int d __unused, int s,
+       const struct afswtch *afp __unused)
+{
+       struct ifmediareq ifmr;
+       int *mwords, mode;
+
+       (void) memset(&ifmr, 0, sizeof(ifmr));
+       (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+       /*
+        * We must go through the motions of reading all
+        * supported media because we need to know both
+        * the current media type and the top-level type.
+        */
+
+       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+               err(1, "SIOCGIFMEDIA");
+
+       if (ifmr.ifm_count == 0)
+               errx(1, "%s: no media types?", name);
+
+       mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
+       if (mwords == NULL)
+               err(1, "malloc");
+
+       ifmr.ifm_ulist = mwords;
+       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+               err(1, "SIOCGIFMEDIA");
+
+       mode = get_media_mode(IFM_TYPE(mwords[0]), val);
+
+       free(mwords);
+
+       strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+       ifr.ifr_media = (ifmr.ifm_current & ~IFM_MMASK) | mode;
+
+       if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
+               err(1, "SIOCSIFMEDIA (mode)");
 }
 
 /**********************************************************************
@@ -328,6 +399,23 @@ static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
 
+struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
+    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
+
+#if notyet
+static struct ifmedia_description ifm_subtype_atm_descriptions[] =
+    IFM_SUBTYPE_ATM_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_atm_aliases[] =
+    IFM_SUBTYPE_ATM_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
+    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
+#endif
+
 static struct ifmedia_description ifm_subtype_shared_descriptions[] =
     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
 
@@ -346,6 +434,10 @@ struct ifmedia_type_to_subtype {
                struct ifmedia_description *desc;
                int alias;
        } options[3];
+       struct {
+               struct ifmedia_description *desc;
+               int alias;
+       } modes[3];
 };
 
 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
@@ -363,6 +455,9 @@ static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
                        { &ifm_subtype_ethernet_option_descriptions[0], 0 },
                        { NULL, 0 },
                },
+               {
+                       { NULL, 0 },
+               },
        },
        {
                {
@@ -377,6 +472,9 @@ static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
                        { &ifm_subtype_tokenring_option_descriptions[0], 0 },
                        { NULL, 0 },
                },
+               {
+                       { NULL, 0 },
+               },
        },
        {
                {
@@ -391,6 +489,9 @@ static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
                        { &ifm_subtype_fddi_option_descriptions[0], 0 },
                        { NULL, 0 },
                },
+               {
+                       { NULL, 0 },
+               },
        },
        {
                {
@@ -405,6 +506,32 @@ static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
                        { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
                        { NULL, 0 },
                },
+               {
+                       { &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
+                       { &ifm_subtype_ieee80211_mode_aliases[0], 0 },
+                       { NULL, 0 },
+               },
+       },
+       {
+               {
+                       { &ifm_subtype_shared_descriptions[0], 0 },
+                       { &ifm_subtype_shared_aliases[0], 1 },
+#if notyet
+                       { &ifm_subtype_atm_descriptions[0], 0 },
+                       { &ifm_subtype_atm_aliases[0], 1 },
+#endif
+                       { NULL, 0 },
+               },
+               {
+                       { &ifm_shared_option_descriptions[0], 0 },
+#if notyet
+                       { &ifm_subtype_atm_option_descriptions[0], 0 },
+#endif
+                       { NULL, 0 },
+               },
+               {
+                       { NULL, 0 },
+               },
        },
 };
 
@@ -429,7 +556,30 @@ get_media_subtype(int type, const char *val)
                        return (rval);
        }
        errx(1, "unknown media subtype: %s", val);
-       /* NOTREACHED */
+       /*NOTREACHED*/
+}
+
+static int
+get_media_mode(int type, const char *val)
+{
+       struct ifmedia_description *desc;
+       struct ifmedia_type_to_subtype *ttos;
+       int rval, i;
+
+       /* Find the top-level interface type. */
+       for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+           desc->ifmt_string != NULL; desc++, ttos++)
+               if (type == desc->ifmt_word)
+                       break;
+       if (desc->ifmt_string == NULL)
+               errx(1, "unknown media mode 0x%x", type);
+
+       for (i = 0; ttos->modes[i].desc != NULL; i++) {
+               rval = lookup_media_word(ttos->modes[i].desc, val);
+               if (rval != -1)
+                       return (rval);
+       }
+       return -1;
 }
 
 static int
@@ -508,8 +658,8 @@ static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
        return ttos;
 }
 
-static struct ifmedia_description *get_subtype_desc(int ifmw,
-                                  struct ifmedia_type_to_subtype *ttos)
+static struct ifmedia_description *get_subtype_desc(int ifmw, 
+    struct ifmedia_type_to_subtype *ttos)
 {
        int i;
        struct ifmedia_description *desc;
@@ -527,6 +677,25 @@ static struct ifmedia_description *get_subtype_desc(int ifmw,
        return NULL;
 }
 
+static struct ifmedia_description *get_mode_desc(int ifmw, 
+    struct ifmedia_type_to_subtype *ttos)
+{
+       int i;
+       struct ifmedia_description *desc;
+
+       for (i = 0; ttos->modes[i].desc != NULL; i++) {
+               if (ttos->modes[i].alias)
+                       continue;
+               for (desc = ttos->modes[i].desc;
+                   desc->ifmt_string != NULL; desc++) {
+                       if (IFM_MODE(ifmw) == desc->ifmt_word)
+                               return desc;
+               }
+       }
+
+       return NULL;
+}
+
 static void
 print_media_word(int ifmw, int print_toptype)
 {
@@ -564,6 +733,12 @@ print_media_word(int ifmw, int print_toptype)
 
        printf("%s", desc->ifmt_string);
 
+       if (print_toptype) {
+               desc = get_mode_desc(ifmw, ttos);
+               if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
+                       printf(" mode %s", desc->ifmt_string);
+       }
+
        /* Find options. */
        for (i = 0; ttos->options[i].desc != NULL; i++) {
                if (ttos->options[i].alias)
@@ -613,6 +788,10 @@ print_media_word_ifconfig(int ifmw)
  got_subtype:
        printf("media %s", desc->ifmt_string);
 
+       desc = get_mode_desc(ifmw, ttos);
+       if (desc != NULL)
+               printf(" mode %s", desc->ifmt_string);
+
        /* Find options. */
        for (i = 0; ttos->options[i].desc != NULL; i++) {
                if (ttos->options[i].alias)
index a85c425..931beb8 100644 (file)
@@ -30,9 +30,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sbin/ifconfig/ifvlan.c,v 1.2 1999/08/28 00:13:09 peter Exp $
- * $DragonFly: src/sbin/ifconfig/ifvlan.c,v 1.5 2005/03/04 00:11:11 cpressey Exp $
- *
- * $FreeBSD: src/sbin/ifconfig/ifvlan.c,v 1.2 1999/08/28 00:13:09 peter Exp $
+ * $DragonFly: src/sbin/ifconfig/ifvlan.c,v 1.6 2005/03/06 05:01:59 dillon Exp $
  */
 
 #include <sys/param.h>
index 3dcaa85..a501fcf 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/18/93
 # $FreeBSD: src/share/man/man4/Makefile,v 1.83.2.66 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/share/man/man4/Makefile,v 1.15 2005/02/26 12:00:54 swildner Exp $
+# $DragonFly: src/share/man/man4/Makefile,v 1.16 2005/03/06 05:02:01 dillon Exp $
 
 MAN=   aac.4 \
        adv.4 \
@@ -83,6 +83,7 @@ MAN=  aac.4 \
        ips.4 \
        isp.4 \
        ispfw.4 \
+       iwi.4 \
        joy.4 \
        kame.4 \
        keyboard.4 \
index 9bbb79b..768d3ca 100644 (file)
@@ -1,7 +1,7 @@
-# $DragonFly: src/sys/dev/netif/Makefile,v 1.11 2005/01/10 19:37:23 joerg Exp $
+# $DragonFly: src/sys/dev/netif/Makefile,v 1.12 2005/03/06 05:01:52 dillon Exp $
 #
 
-SUBDIR= an ar aue axe bfe bge cue dc ed em ep fwe fxp gx kue lge lnc \
+SUBDIR= an ar aue axe bfe bge cue dc ed em ep fwe fxp gx iwi kue lge lnc \
        mii_layer my nge nv owi pcn ray re rl sbni sbsh sf sis sk snc \
        sr ste ti tl tx txp vr vx wb wi xe xl
 
diff --git a/sys/dev/netif/iwi/Makefile b/sys/dev/netif/iwi/Makefile
new file mode 100644 (file)
index 0000000..3326aac
--- /dev/null
@@ -0,0 +1,17 @@
+# $DragonFly: src/sys/dev/netif/iwi/Makefile,v 1.1 2005/03/06 05:02:02 dillon Exp $
+#
+KMOD    = if_iwi
+SRCS    = if_iwi.c \
+          device_if.h \
+          bus_if.h \
+          pci_if.h \
+          opt_inet.h
+
+CFLAGS +=  -DIWI_DEBUG -DNBPFILTER=1 -DALTQ
+
+#WARNS?=6
+
+opt_inet.h:
+       echo "#define INET 1" > ${.TARGET}
+
+.include <bsd.kmod.mk>
diff --git a/sys/dev/netif/iwi/if_iwi.c b/sys/dev/netif/iwi/if_iwi.c
new file mode 100644 (file)
index 0000000..49f282f
--- /dev/null
@@ -0,0 +1,3053 @@
+/*
+ * Copyright (c) 2004, 2005
+ *      Damien Bergamini <damien.bergamini@free.fr>.
+ * Copyright (c) 2004, 2005
+ *      Andrew Atrens <atrens@nortelnetworks.com>.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $DragonFly: src/sys/dev/netif/iwi/if_iwi.c,v 1.1 2005/03/06 05:02:02 dillon Exp $
+ */
+
+#include "opt_inet.h"
+
+#include <sys/cdefs.h>
+
+/*-
+ * Intel(R) PRO/Wireless 2200BG/2915ABG driver
+ * http://www.intel.com/network/connectivity/products/wireless/prowireless_mobile.htm
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/thread2.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/clock.h>
+#include <sys/rman.h>
+
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ifq_var.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/ifq_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+
+#ifdef IPX
+#include <netproto/ipx/ipx.h>
+#include <netproto/ipx/ipx_if.h>
+#endif
+
+#include <netproto/802_11/ieee80211_var.h>
+#include <netproto/802_11/ieee80211_ioctl.h>
+#include <netproto/802_11/ieee80211_radiotap.h>
+#include <netproto/802_11/if_wavelan_ieee.h>
+
+#include "if_iwireg.h"
+#include "if_iwivar.h"
+
+#ifdef IWI_DEBUG
+#define DPRINTF(x)     if (sc->debug_level > 0) printf x
+#define DPRINTFN(n, x) if (sc->debug_level >= (n)) printf x
+
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n, x)
+#endif
+
+MODULE_DEPEND(iwi, pci,  1, 1, 1);
+MODULE_DEPEND(iwi, wlan, 1, 1, 1);
+
+struct iwi_dump_buffer {
+       u_int32_t buf[128];
+};
+
+struct iwi_ident {
+       u_int16_t       vendor;
+       u_int16_t       device;
+       const char      *name;
+};
+
+static const struct iwi_ident iwi_ident_table[] = {
+       { 0x8086, 0x4220, "Intel(R) PRO/Wireless 2200BG MiniPCI" },
+       { 0x8086, 0x4223, "Intel(R) PRO/Wireless 2915ABG MiniPCI" },
+       { 0x8086, 0x4224, "Intel(R) PRO/Wireless 2915ABG MiniPCI" },
+
+       { 0, 0, NULL }
+};
+
+static const struct ieee80211_rateset iwi_rateset_11a =
+       { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
+
+static const struct ieee80211_rateset iwi_rateset_11b =
+       { 4, { 2, 4, 11, 22 } };
+
+static const struct ieee80211_rateset iwi_rateset_11g =
+       { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
+
+static int             iwi_dma_alloc(struct iwi_softc *);
+static void            iwi_release(struct iwi_softc *);
+static int             iwi_media_change(struct ifnet *);
+static void            iwi_media_status(struct ifnet *, struct ifmediareq *);
+static u_int16_t       iwi_read_prom_word(struct iwi_softc *, u_int8_t);
+static int             iwi_newstate(struct ieee80211com *,
+                           enum ieee80211_state, int);
+static void            iwi_fix_channel(struct iwi_softc *, struct mbuf *);
+static void            iwi_frame_intr(struct iwi_softc *,
+                           struct iwi_rx_buf *, int, struct iwi_frame *);
+static void            iwi_notification_intr(struct iwi_softc *,
+                           struct iwi_notif *);
+static void            iwi_rx_intr(struct iwi_softc *);
+static void            iwi_tx_intr(struct iwi_softc *);
+static void            iwi_intr(void *);
+static void            iwi_dma_map_buf(void *, bus_dma_segment_t *, int,
+                           bus_size_t, int);
+static void            iwi_dma_map_addr(void *, bus_dma_segment_t *, int, int);
+static int             iwi_cmd(struct iwi_softc *, u_int8_t, void *, u_int8_t,
+                           int);
+static int             iwi_tx_start(struct ifnet *, struct mbuf *,
+                           struct ieee80211_node *);
+static void            iwi_start(struct ifnet *);
+static void            iwi_watchdog(struct ifnet *);
+static int             iwi_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *cr);
+static void            iwi_stop_master(struct iwi_softc *);
+static int             iwi_reset(struct iwi_softc *);
+static int             iwi_load_ucode(struct iwi_softc *, void *, int);
+static int             iwi_load_firmware(struct iwi_softc *, void *, int);
+static int             iwi_cache_firmware(struct iwi_softc *, void *, int);
+static void            iwi_free_firmware(struct iwi_softc *);
+static int             iwi_config(struct iwi_softc *);
+static int             iwi_scan(struct iwi_softc *);
+static int             iwi_auth_and_assoc(struct iwi_softc *);
+static void            iwi_init(void *);
+static void            iwi_init_locked(void *);
+static void            iwi_stop(void *);
+static void            iwi_dump_fw_event_log(struct iwi_softc *sc);
+static void            iwi_dump_fw_error_log(struct iwi_softc *sc);
+static u_int8_t        iwi_find_station(struct iwi_softc *sc, u_int8_t *mac);
+static int8_t          iwi_cache_station(struct iwi_softc *sc, u_int8_t *mac);
+static int             iwi_adapter_config(struct iwi_softc *sc, int is_a, int cmd_wait);
+
+static int             iwi_sysctl_bt_coexist(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_bg_autodetect(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_cts_to_self(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_antenna_diversity(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_radio(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_stats(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_dump_logs(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_neg_best_rates_first(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_disable_unicast_decryption(SYSCTL_HANDLER_ARGS);
+static int             iwi_sysctl_disable_multicast_decryption(SYSCTL_HANDLER_ARGS);
+
+static __inline u_int8_t MEM_READ_1(struct iwi_softc *sc, u_int32_t addr)
+{
+       CSR_WRITE_4(sc, IWI_CSR_INDIRECT_ADDR, addr);
+       return CSR_READ_1(sc, IWI_CSR_INDIRECT_DATA);
+}
+
+static __inline u_int32_t MEM_READ_4(struct iwi_softc *sc, u_int32_t addr)
+{
+       CSR_WRITE_4(sc, IWI_CSR_INDIRECT_ADDR, addr);
+       return CSR_READ_4(sc, IWI_CSR_INDIRECT_DATA);
+}
+
+static int iwi_probe(device_t);
+static int iwi_attach(device_t);
+static int iwi_detach(device_t);
+static int iwi_shutdown(device_t);
+static int iwi_suspend(device_t);
+static int iwi_resume(device_t);
+
+static device_method_t iwi_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         iwi_probe),
+       DEVMETHOD(device_attach,        iwi_attach),
+       DEVMETHOD(device_detach,        iwi_detach),
+       DEVMETHOD(device_shutdown,      iwi_shutdown),
+       DEVMETHOD(device_suspend,       iwi_suspend),
+       DEVMETHOD(device_resume,        iwi_resume),
+
+       { 0, 0 }
+};
+
+static driver_t iwi_driver = {
+       "iwi",
+       iwi_methods,
+       sizeof (struct iwi_softc),
+       0, /* baseclasses */
+       0, /* refs */
+       0  /* ops */
+};
+
+static devclass_t iwi_devclass;
+
+DRIVER_MODULE(iwi, pci, iwi_driver, iwi_devclass, 0, 0);
+
+static int
+iwi_probe(device_t dev)
+{
+       const struct iwi_ident *ident;
+
+       for (ident = iwi_ident_table; ident->name != NULL; ident++) {
+               if (pci_get_vendor(dev) == ident->vendor &&
+                   pci_get_device(dev) == ident->device) {
+                       device_set_desc(dev, ident->name);
+                       return 0;
+               }
+       }
+       return ENXIO;
+}
+
+static void
+iwi_fw_monitor(void *arg)
+{
+       struct iwi_softc *sc = (struct iwi_softc *)arg;
+       int error, boff;
+       for ( ;; ) {
+               error = tsleep(IWI_FW_WAKE_MONITOR(sc), 0, "iwifwm", 0 );
+               if ( error == 0 ) {
+                       if ( sc->flags & IWI_FLAG_EXIT ) {
+                               sc->flags &= ~( IWI_FLAG_EXIT );
+                               break;
+                       } else if ( sc->flags & IWI_FLAG_RESET ) {
+                               device_printf(sc->sc_dev, "firmware reset\n");
+                               for ( boff = 1; sc->flags & IWI_FLAG_RESET ; boff++ ) {
+                                       if ( sc->debug_level > 0 )
+                                               iwi_dump_fw_error_log(sc);
+                                       iwi_init_locked(sc);
+                                       if ((sc->flags & IWI_FLAG_FW_INITED))
+                                               sc->flags &= ~( IWI_FLAG_RESET );
+                                       error = tsleep( IWI_FW_CMD_ACKED(sc), 0,
+                                                      "iwirun", boff * hz );
+                               }
+                       }
+               }
+       }
+       wakeup(IWI_FW_MON_EXIT(sc));
+       kthread_exit();
+}
+
+static int
+iwi_start_fw_monitor_thread( struct iwi_softc *sc )
+{
+       if (kthread_create(iwi_fw_monitor, sc, &sc->event_thread,
+               "%s%d:fw-monitor", device_get_name(sc->sc_dev),
+               device_get_unit(sc->sc_dev))) {
+               device_printf (sc->sc_dev,
+                  "unable to create firmware monitor thread.\n");
+               return -1;
+       }
+       return 0;
+}
+
+/* Base Address Register */
+#define IWI_PCI_BAR0   0x10
+
+static int
+iwi_attach(device_t dev)
+{
+       struct iwi_softc *sc = device_get_softc(dev);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       u_int16_t val;
+       int error, rid, i;
+
+       sc->sc_dev = dev;
+
+       IWI_LOCK_INIT( &sc->sc_lock );
+       IWI_LOCK_INIT( &sc->sc_intrlock );
+
+       if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+               device_printf(dev, "chip is in D%d power mode "
+                   "-- setting to D0\n", pci_get_powerstate(dev));
+               pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+       }
+
+       pci_write_config(dev, 0x41, 0, 1);
+
+       /* enable bus-mastering */
+       pci_enable_busmaster(dev);
+
+       sc->num_stations = 0;
+
+       /* map the register window */
+       rid = IWI_PCI_BAR0;
+       sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+       if (sc->mem == NULL) {
+               device_printf(dev, "could not allocate memory resource\n");
+               goto fail;
+       }
+
+       sc->sc_st = rman_get_bustag(sc->mem);
+       sc->sc_sh = rman_get_bushandle(sc->mem);
+
+       rid = 0;
+       sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE |
+           RF_SHAREABLE);
+       if (sc->irq == NULL) {
+               device_printf(dev, "could not allocate interrupt resource\n");
+               goto fail;
+       }
+
+       if (iwi_reset(sc) != 0) {
+               device_printf(dev, "could not reset adapter\n");
+               goto fail;
+       }
+
+       if (iwi_start_fw_monitor_thread(sc) ) {
+               device_printf(dev, "could not start f/w reset thread\n");
+               goto fail;
+       }
+
+       if (iwi_dma_alloc(sc) != 0) {
+               device_printf(dev, "could not allocate DMA resources\n");
+               goto fail;
+       }
+
+       ic->ic_phytype = IEEE80211_T_OFDM;
+       ic->ic_opmode  = IEEE80211_M_STA;
+       ic->ic_state   = IEEE80211_S_INIT;
+
+       /* set device capabilities */
+       ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_PMGT | IEEE80211_C_WEP |
+           IEEE80211_C_TXPMGT | IEEE80211_C_SHPREAMBLE;
+
+       /* read MAC address from EEPROM */
+       val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0);
+       ic->ic_myaddr[0] = val >> 8;
+       ic->ic_myaddr[1] = val & 0xff;
+       val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 1);
+       ic->ic_myaddr[2] = val >> 8;
+       ic->ic_myaddr[3] = val & 0xff;
+       val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2);
+       ic->ic_myaddr[4] = val >> 8;
+       ic->ic_myaddr[5] = val & 0xff;
+
+       if (pci_get_device(dev) != 0x4220) {
+               /* set supported .11a rates */
+               ic->ic_sup_rates[IEEE80211_MODE_11A] = iwi_rateset_11a;
+
+               /* set supported .11a channels */
+               for (i = 36; i <= 64; i += 4) {
+                       ic->ic_channels[i].ic_freq =
+                           ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
+                       ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
+               }
+               for (i = 149; i <= 165; i += 4) {
+                       ic->ic_channels[i].ic_freq =
+                           ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
+                       ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
+               }
+       }
+
+       /* set supported .11b and .11g rates */
+       ic->ic_sup_rates[IEEE80211_MODE_11B] = iwi_rateset_11b;
+       ic->ic_sup_rates[IEEE80211_MODE_11G] = iwi_rateset_11g;
+
+       /* set supported .11b and .11g channels (1 through 14) */
+       for (i = 1; i <= 14; i++) {
+               ic->ic_channels[i].ic_freq =
+                   ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
+               ic->ic_channels[i].ic_flags =
+                   IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
+                   IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
+       }
+
+       /* default to authmode OPEN */
+       sc->authmode = IEEE80211_AUTH_OPEN;
+
+       /* IBSS channel undefined for now */
+       ic->ic_ibss_chan = &ic->ic_channels[0];
+
+       ifp->if_softc = sc;
+       if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_init = iwi_init_locked;
+       ifp->if_ioctl = iwi_ioctl;
+       ifp->if_start = iwi_start;
+       ifp->if_watchdog = iwi_watchdog;
+       ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
+       ifq_set_ready(&ifp->if_snd);
+
+       ieee80211_ifattach(ifp);
+       /* override state transition machine */
+       sc->sc_newstate = ic->ic_newstate;
+       ic->ic_newstate = iwi_newstate;
+       ieee80211_media_init(ifp, iwi_media_change, iwi_media_status);
+
+       bpfattach_dlt(ifp, DLT_IEEE802_11_RADIO,
+           sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf);
+
+       sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
+       sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
+       sc->sc_rxtap.wr_ihdr.it_present = htole32(IWI_RX_RADIOTAP_PRESENT);
+
+       sc->sc_txtap_len = sizeof sc->sc_txtapu;
+       sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
+       sc->sc_txtap.wt_ihdr.it_present = htole32(IWI_TX_RADIOTAP_PRESENT);
+
+       /*
+        * Hook our interrupt after all initialization is complete
+        */
+       error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
+           iwi_intr, sc, &sc->sc_ih);
+       if (error != 0) {
+               device_printf(dev, "could not set up interrupt\n");
+               goto fail;
+       }
+
+       /*
+        * Add sysctl knobs
+        * 
+        * use -1 to indicate 'default / not set'
+        */
+
+       sc->enable_bg_autodetect         = -1;
+       sc->enable_bt_coexist            = -1;
+       sc->enable_cts_to_self           = -1;
+       sc->antenna_diversity            = -1;
+       sc->enable_neg_best_first        = -1;
+       sc->disable_unicast_decryption   = -1;
+       sc->disable_multicast_decryption = -1;
+
+       sysctl_ctx_init(&sc->sysctl_ctx);
+       sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+                               SYSCTL_STATIC_CHILDREN(_hw),
+                               OID_AUTO,
+                               device_get_nameunit(dev),
+                               CTLFLAG_RD,
+                               0, "");
+
+       if (sc->sysctl_tree == NULL) {
+               error = EIO;
+               goto fail;
+       }
+
+       SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
+                      OID_AUTO, "debug", CTLFLAG_RW, &sc->debug_level, 0,
+                     "Set driver debug level (0 = off)");
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree),
+                       OID_AUTO, "cts_to_self", CTLTYPE_INT|CTLFLAG_RW,
+                       (void *)sc, 0, iwi_sysctl_cts_to_self, "I", 
+                       "Enable cts to self [0 = Off] [1 = On] [-1 = Auto]" );
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree),
+                       OID_AUTO, "antenna_diversity", CTLTYPE_INT|CTLFLAG_RW,
+                       (void *)sc, 0, iwi_sysctl_antenna_diversity,
+                       "I", "Set antenna diversity [0 = Both] "
+                       "[1 = Antenna A] [3 = Antenna B] [-1 = Auto]" );
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree),
+                       OID_AUTO, "bluetooth_coexist", CTLTYPE_INT|CTLFLAG_RW,
+                       (void *)sc, 0, iwi_sysctl_bt_coexist,
+                       "I", "Enable bluetooth coexistence heuristics "
+                       "[0 = Off] [1 = On] [-1 = Auto]" );
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree),
+                       OID_AUTO, "bg_autodetect", CTLTYPE_INT|CTLFLAG_RW,
+                       (void *)sc, 0, iwi_sysctl_bg_autodetect,
+                       "I", "Set b/g autodetect [0 = Off] [1 = On] [-1 = Auto]" );
+
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "radio",
+                       CTLTYPE_INT | CTLFLAG_RD, sc, 0, iwi_sysctl_radio, "I",
+                       "Radio transmitter switch");
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "stats",
+                       CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, iwi_sysctl_stats, 
+                       "S,iwi_dump_buffer", "statistics");
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree),
+                       OID_AUTO, "firmware_logs", CTLTYPE_INT|CTLFLAG_RW,
+                       (void *)sc, 0, iwi_sysctl_dump_logs, "I", "Dump firmware logs");
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+                       "neg_best_rates_first",
+                       CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+                       iwi_sysctl_neg_best_rates_first, "I",
+                        "Negotiate highest rates first.");
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+                       "disable_unicast_decrypt",
+                       CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+                       iwi_sysctl_disable_unicast_decryption, "I",
+                        "Disable unicast decryption.");
+
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                       SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+                       "disable_multicast_decrypt",
+                       CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+                       iwi_sysctl_disable_multicast_decryption, "I",
+                        "Disable multicast decryption.");
+
+       return 0;
+
+fail:  iwi_detach(dev);
+       return ENXIO;
+}
+
+static int
+iwi_detach(device_t dev)
+{
+       struct iwi_softc *sc = device_get_softc(dev);
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
+       IWI_LOCK_INFO;
+       IWI_IPLLOCK_INFO;
+
+       sc->flags |= IWI_FLAG_EXIT;
+       wakeup(IWI_FW_WAKE_MONITOR(sc)); /* Stop firmware monitor. */
+
+       (void) tsleep(IWI_FW_MON_EXIT(sc), 0, "iwiexi", 10 * hz );
+
+       IWI_LOCK(sc);
+       IWI_IPLLOCK(sc);
+
+       iwi_stop(sc);
+       iwi_free_firmware(sc);
+
+       if ( sc->sysctl_tree ) {
+               crit_enter();
+               sysctl_ctx_free(&sc->sysctl_ctx);
+               crit_exit();
+               sc->sysctl_tree = 0;
+       }
+
+       IWI_IPLUNLOCK(sc);
+       IWI_UNLOCK(sc);
+
+       bpfdetach(ifp);
+
+       ieee80211_ifdetach(ifp);
+
+       iwi_release(sc);
+
+       if (sc->irq != NULL) {
+               bus_teardown_intr(dev, sc->irq, sc->sc_ih);
+               bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+       }
+
+       if (sc->mem != NULL)
+               bus_release_resource(dev, SYS_RES_MEMORY, IWI_PCI_BAR0,
+                   sc->mem);
+
+       IWI_LOCK_DESTROY(&(sc->sc_lock));
+       IWI_LOCK_DESTROY(&(sc->sc_intrlock));
+
+       return 0;
+}
+
+static int
+iwi_dma_alloc(struct iwi_softc *sc)
+{
+       int i, error;
+
+       error = bus_dma_tag_create(NULL, /* parent */
+                                  1, 0,
+                                  BUS_SPACE_MAXADDR_32BIT,
+                                  BUS_SPACE_MAXADDR,
+                                  NULL, NULL,
+                                  MAXBSIZE, 128,
+                                  BUS_SPACE_MAXSIZE_32BIT,
+                                  BUS_DMA_ALLOCNOW,
+                                  &sc->iwi_parent_tag );
+       if (error != 0) {
+               device_printf(sc->sc_dev, "could not create parent tag\n");
+               goto fail;
+       }
+       /*
+        * Allocate and map Tx ring
+        */
+       error = bus_dma_tag_create(sc->iwi_parent_tag, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL,
+           sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE, 1,
+           sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE,
+           BUS_DMA_ALLOCNOW, &sc->tx_ring_dmat);
+       if (error != 0) {
+               device_printf(sc->sc_dev, "could not create tx ring DMA tag\n");
+               goto fail;
+       }
+
+       error = bus_dmamem_alloc(sc->tx_ring_dmat,(void **) &sc->tx_desc,
+           BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->tx_ring_map);
+       if (error != 0) {
+               device_printf(sc->sc_dev,
+                   "could not allocate tx ring DMA memory\n");
+               goto fail;
+       }
+
+       error = bus_dmamap_load(sc->tx_ring_dmat, sc->tx_ring_map,
+           sc->tx_desc, sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE,
+           iwi_dma_map_addr, &sc->tx_ring_pa, 0);
+       if (error != 0) {
+               device_printf(sc->sc_dev, "could not load tx ring DMA map\n");
+               goto fail;
+       }
+
+       /*
+        * Allocate and map command ring
+        */
+       error = bus_dma_tag_create(sc->iwi_parent_tag, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL,
+           sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, 1,
+           sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, 
+           BUS_DMA_ALLOCNOW,
+           &sc->cmd_ring_dmat);
+       if (error != 0) {
+               device_printf(sc->sc_dev,
+                   "could not create command ring DMA tag\n");
+               goto fail;
+       }
+
+       error = bus_dmamem_alloc(sc->cmd_ring_dmat, (void **)&sc->cmd_desc,
+           BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->cmd_ring_map);
+       if (error != 0) {
+               device_printf(sc->sc_dev,
+                   "could not allocate command ring DMA memory\n");
+               goto fail;
+       }
+
+       error = bus_dmamap_load(sc->cmd_ring_dmat, sc->cmd_ring_map,
+           sc->cmd_desc, sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE,
+           iwi_dma_map_addr, &sc->cmd_ring_pa, 0);
+       if (error != 0) {
+               device_printf(sc->sc_dev,
+                   "could not load command ring DMA map\n");
+               goto fail;
+       }
+
+       /*
+        * Allocate Tx buffers DMA maps
+        */
+       error = bus_dma_tag_create(sc->iwi_parent_tag, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, IWI_MAX_NSEG, MCLBYTES,
+           BUS_DMA_ALLOCNOW, &sc->tx_buf_dmat);
+       if (error != 0) {
+               device_printf(sc->sc_dev, "could not create tx buf DMA tag\n");
+               goto fail;
+       }
+
+       for (i = 0; i < IWI_TX_RING_SIZE; i++) {
+               error = bus_dmamap_create(sc->tx_buf_dmat, 0,
+                   &sc->tx_buf[i].map);
+               if (error != 0) {
+                       device_printf(sc->sc_dev,
+                           "could not create tx buf DMA map");
+                       goto fail;
+               }
+       }
+
+       /*
+        * Allocate and map Rx buffers
+        */
+       error = bus_dma_tag_create(sc->iwi_parent_tag, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES,
+           BUS_DMA_ALLOCNOW, &sc->rx_buf_dmat);
+       if (error != 0) {
+               device_printf(sc->sc_dev, "could not create rx buf DMA tag\n");
+               goto fail;
+       }
+
+       for (i = 0; i < IWI_RX_RING_SIZE; i++) {
+
+               error = bus_dmamap_create(sc->rx_buf_dmat, 0,
+                   &sc->rx_buf[i].map);
+               if (error != 0) {
+                       device_printf(sc->sc_dev,
+                           "could not create rx buf DMA map");
+                       goto fail;
+               }
+
+               sc->rx_buf[i].m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
+               if (sc->rx_buf[i].m == NULL) {
+                       device_printf(sc->sc_dev,
+                           "could not allocate rx mbuf\n");
+                       error = ENOMEM;
+                       goto fail;
+               }
+
+               error = bus_dmamap_load(sc->rx_buf_dmat, sc->rx_buf[i].map,
+                   mtod(sc->rx_buf[i].m, void *), MCLBYTES, iwi_dma_map_addr,
+                   &sc->rx_buf[i].physaddr, 0);
+               if (error != 0) {
+                       device_printf(sc->sc_dev,
+                           "could not load rx buf DMA map");
+                       goto fail;
+               }
+       }
+
+       return 0;
+
+fail:  iwi_release(sc);
+       return error;
+}
+
+static void
+iwi_release(struct iwi_softc *sc)
+{
+       int i;
+
+       if (sc->tx_ring_dmat != NULL) {
+               if (sc->tx_desc != NULL) {
+                       bus_dmamap_sync(sc->tx_ring_dmat, sc->tx_ring_map,
+                           BUS_DMASYNC_POSTWRITE);
+                       bus_dmamap_unload(sc->tx_ring_dmat, sc->tx_ring_map);
+                       bus_dmamem_free(sc->tx_ring_dmat, sc->tx_desc,
+                           sc->tx_ring_map);
+               }
+               bus_dma_tag_destroy(sc->tx_ring_dmat);
+       }
+
+       if (sc->cmd_ring_dmat != NULL) {
+               if (sc->cmd_desc != NULL) {
+                       bus_dmamap_sync(sc->cmd_ring_dmat, sc->cmd_ring_map,
+                           BUS_DMASYNC_POSTWRITE);
+                       bus_dmamap_unload(sc->cmd_ring_dmat, sc->cmd_ring_map);
+                       bus_dmamem_free(sc->cmd_ring_dmat, sc->cmd_desc,
+                           sc->cmd_ring_map);
+               }
+               bus_dma_tag_destroy(sc->cmd_ring_dmat);
+       }
+
+       if (sc->tx_buf_dmat != NULL) {
+               for (i = 0; i < IWI_TX_RING_SIZE; i++) {
+                       if (sc->tx_buf[i].m != NULL) {
+                               bus_dmamap_sync(sc->tx_buf_dmat,
+                                   sc->tx_buf[i].map, BUS_DMASYNC_POSTWRITE);
+                               bus_dmamap_unload(sc->tx_buf_dmat,
+                                   sc->tx_buf[i].map);
+                               m_freem(sc->tx_buf[i].m);
+                       }
+                       bus_dmamap_destroy(sc->tx_buf_dmat, sc->tx_buf[i].map);
+               }
+               bus_dma_tag_destroy(sc->tx_buf_dmat);
+       }
+
+       if (sc->rx_buf_dmat != NULL) {
+               for (i = 0; i < IWI_RX_RING_SIZE; i++) {
+                       if (sc->rx_buf[i].m != NULL) {
+                               bus_dmamap_sync(sc->rx_buf_dmat,
+                                   sc->rx_buf[i].map, BUS_DMASYNC_POSTREAD);
+                               bus_dmamap_unload(sc->rx_buf_dmat,
+                                   sc->rx_buf[i].map);
+                               m_freem(sc->rx_buf[i].m);
+                       }
+                       bus_dmamap_destroy(sc->rx_buf_dmat, sc->rx_buf[i].map);
+               }
+               bus_dma_tag_destroy(sc->rx_buf_dmat);
+       }
+       if ( sc->iwi_parent_tag != NULL ) {
+               bus_dma_tag_destroy(sc->iwi_parent_tag);
+       }
+}
+
+static int
+iwi_shutdown(device_t dev)
+{
+       struct iwi_softc *sc = device_get_softc(dev);
+       IWI_LOCK_INFO;
+
+       IWI_LOCK(sc);
+
+       iwi_stop(sc);
+
+       IWI_UNLOCK(sc);
+
+       return 0;
+}
+
+static int
+iwi_suspend(device_t dev)
+{
+       struct iwi_softc *sc = device_get_softc(dev);
+
+       IWI_LOCK_INFO;
+
+       IWI_LOCK(sc);
+
+       iwi_stop(sc);
+
+       IWI_UNLOCK(sc);
+
+       return 0;
+}
+
+static int
+iwi_resume(device_t dev)
+{
+       struct iwi_softc *sc = device_get_softc(dev);
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
+       IWI_LOCK_INFO;
+
+       IWI_LOCK(sc);
+
+       pci_write_config(dev, 0x41, 0, 1);
+
+       if (ifp->if_flags & IFF_UP) {
+               ifp->if_init(ifp->if_softc);
+               if (ifp->if_flags & IFF_RUNNING)
+                       ifp->if_start(ifp);
+       }
+
+       IWI_UNLOCK(sc);
+
+       return 0;
+}
+
+static int
+iwi_media_change(struct ifnet *ifp)
+{
+       struct iwi_softc *sc = ifp->if_softc;
+       int error = 0;
+       IWI_LOCK_INFO;
+
+       IWI_LOCK(sc);
+
+       error = ieee80211_media_change(ifp);
+       if (error != ENETRESET) {
+               IWI_UNLOCK(sc);
+               return error;
+       }
+       error = 0; /* clear ENETRESET */
+
+       if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)){
+               iwi_init(sc);
+               error = tsleep( IWI_FW_CMD_ACKED(sc), 0, "iwirun", hz );
+       }
+
+
+       IWI_UNLOCK(sc);
+
+       return error;
+}
+
+static void
+iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
+{
+       struct iwi_softc *sc = ifp->if_softc;
+       struct ieee80211com *ic = &sc->sc_ic;
+#define N(a)   (sizeof (a) / sizeof (a[0]))
+       static const struct {
+               u_int32_t       val;
+               int             rate;
+       } rates[] = {
+               { IWI_RATE_DS1,      2 },
+               { IWI_RATE_DS2,      4 },
+               { IWI_RATE_DS5,     11 },
+               { IWI_RATE_DS11,    22 },
+               { IWI_RATE_OFDM6,   12 },
+               { IWI_RATE_OFDM9,   18 },
+               { IWI_RATE_OFDM12,  24 },
+               { IWI_RATE_OFDM18,  36 },
+               { IWI_RATE_OFDM24,  48 },
+               { IWI_RATE_OFDM36,  72 },
+               { IWI_RATE_OFDM48,  96 },
+               { IWI_RATE_OFDM54, 108 },
+       };
+       u_int32_t val, i;
+       int rate;
+
+       imr->ifm_status = IFM_AVALID;
+       imr->ifm_active = IFM_IEEE80211;
+       if (ic->ic_state == IEEE80211_S_RUN)
+               imr->ifm_status |= IFM_ACTIVE;
+
+       /* read current transmission rate from adapter */
+       val = CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE);
+
+       /* convert rate to 802.11 rate */
+       for (i = 0; i < N(rates) && rates[i].val != val ; i++);
+       rate = (i < N(rates)) ? rates[i].rate : 0;
+
+       imr->ifm_active |= ieee80211_rate2media(ic, rate, ic->ic_curmode);
+       switch (ic->ic_opmode) {
+       case IEEE80211_M_STA:
+               break;
+
+       case IEEE80211_M_IBSS:
+               imr->ifm_active |= IFM_IEEE80211_ADHOC;
+               break;
+
+       case IEEE80211_M_MONITOR:
+               imr->ifm_active |= IFM_IEEE80211_MONITOR;
+               break;
+
+       case IEEE80211_M_AHDEMO:
+       case IEEE80211_M_HOSTAP:
+               /* should not get there */
+               break;
+       }
+#undef N
+}
+
+static int
+iwi_disassociate( struct iwi_softc *sc  )
+{
+       sc->assoc.type = 2; /* DISASSOCIATE */
+       return iwi_cmd(sc, IWI_CMD_ASSOCIATE, &sc->assoc, sizeof sc->assoc, 0);
+}
+
+
+static int
+iwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg __unused)
+{
+       struct iwi_softc *sc = ic->ic_softc;
+
+       switch (nstate) {
+       case IEEE80211_S_SCAN:
+               if ( sc->flags & IWI_FLAG_ASSOCIATED ) {
+                       sc->flags &= ~( IWI_FLAG_ASSOCIATED );
+                       iwi_disassociate(sc);
+                       (void) tsleep( IWI_FW_DEASSOCIATED(sc), 
+                                       0, "iwisca", hz );
+                       
+               }
+               if ( !(sc->flags & IWI_FLAG_SCANNING) &&
+                    !(sc->flags & IWI_FLAG_RF_DISABLED) ) {
+                       iwi_scan(sc);
+               }
+               break;
+
+       case IEEE80211_S_AUTH:
+               if ( sc->flags & IWI_FLAG_ASSOCIATED ) {
+                       sc->flags &= ~( IWI_FLAG_ASSOCIATED );
+                       iwi_disassociate(sc);
+                       (void) tsleep( IWI_FW_DEASSOCIATED(sc), 0,
+                                      "iwiaut", hz );
+                       
+               }
+               if ( iwi_auth_and_assoc(sc) != 0 )
+                       ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+               break;
+
+       case IEEE80211_S_RUN:
+               if (sc->flags & IWI_FLAG_SCAN_COMPLETE) {
+                       sc->flags &= ~(IWI_FLAG_SCAN_COMPLETE);
+                       if (ic->ic_opmode == IEEE80211_M_IBSS ||
+                           ic->ic_opmode == IEEE80211_M_MONITOR ) {
+                               /* 
+                                * In IBSS mode, following an end_scan
+                                * the ieee80211 stack state machine transitions
+                                * straight to 'run' state. This is out of
+                                * step with the firmware which requires
+                                * an association first. Flip our state from
+                                * RUN back to AUTH to allow us to tell the
+                                * firmware to associate.
+                                */
+                               ieee80211_new_state(ic, IEEE80211_S_AUTH, -1);
+                       }
+               }
+               break;
+
+       case IEEE80211_S_ASSOC:
+               break;
+       case IEEE80211_S_INIT:
+               sc->flags &= ~( IWI_FLAG_SCANNING | IWI_FLAG_ASSOCIATED );
+               break;
+       }
+
+       ic->ic_state = nstate;
+       return 0;
+}
+
+/*
+ * Read 16 bits at address 'addr' from the serial EEPROM.
+ * DON'T PLAY WITH THIS CODE UNLESS YOU KNOW *EXACTLY* WHAT YOU'RE DOING!
+ */
+static u_int16_t
+iwi_read_prom_word(struct iwi_softc *sc, u_int8_t addr)
+{
+       u_int32_t tmp;
+       u_int16_t val;
+       int n;
+
+       /* Clock C once before the first command */
+       IWI_EEPROM_CTL(sc, 0);
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S);
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C);
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S);
+
+       /* Write start bit (1) */
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D);
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D | IWI_EEPROM_C);
+
+       /* Write READ opcode (10) */
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D);
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D | IWI_EEPROM_C);
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S);
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C);
+
+       /* Write address A7-A0 */
+       for (n = 7; n >= 0; n--) {
+               IWI_EEPROM_CTL(sc, IWI_EEPROM_S |
+                   (((addr >> n) & 1) << IWI_EEPROM_SHIFT_D));
+               IWI_EEPROM_CTL(sc, IWI_EEPROM_S |
+                   (((addr >> n) & 1) << IWI_EEPROM_SHIFT_D) | IWI_EEPROM_C);
+       }
+
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S);
+
+       /* Read data Q15-Q0 */
+       val = 0;
+       for (n = 15; n >= 0; n--) {
+               IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C);
+               IWI_EEPROM_CTL(sc, IWI_EEPROM_S);
+               tmp = MEM_READ_4(sc, IWI_MEM_EEPROM_CTL);
+               val |= ((tmp & IWI_EEPROM_Q) >> IWI_EEPROM_SHIFT_Q) << n;
+       }
+
+       IWI_EEPROM_CTL(sc, 0);
+
+       /* Clear Chip Select and clock C */
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_S);
+       IWI_EEPROM_CTL(sc, 0);
+       IWI_EEPROM_CTL(sc, IWI_EEPROM_C);
+
+       return be16toh(val);
+}
+
+/*
+ * XXX: Hack to set the current channel to the value advertised in beacons or
+ * probe responses. Only used during AP detection.
+ */
+static void
+iwi_fix_channel(struct iwi_softc *sc, struct mbuf *m)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ieee80211_frame *wh;
+       u_int8_t subtype;
+       u_int8_t *frm, *efrm;
+
+       wh = mtod(m, struct ieee80211_frame *);
+
+       if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
+               return;
+
+       subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+       if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
+           subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
+               return;
+
+       /*
+        * Cache station entries from beacons and probes.
+        */
+       if ( iwi_find_station(sc, wh->i_addr2) == 0xff )
+               iwi_cache_station(sc, wh->i_addr2);
+
+       frm = (u_int8_t *)(wh + 1);
+       efrm = mtod(m, u_int8_t *) + m->m_len;
+
+       frm += 12;      /* skip tstamp, bintval and capinfo fields */
+#if 0
+       { /* XXX - debugging code */
+               u_int8_t *ptr;
+               u_int32_t cnt;
+               printf("Frame -->");
+               for ( ptr = frm, cnt = 0 ; ptr < efrm ; ptr++, cnt++ ) {
+                       if ( cnt % 8 == 0 )
+                               printf("\n");
+                       printf("0x%-2.2x ", *ptr);
+               }
+               printf("<-- End Frame\n");
+       }
+#endif
+
+       while (frm < efrm) {
+               if (*frm == IEEE80211_ELEMID_DSPARMS)
+#if IEEE80211_CHAN_MAX < 255
+               if (frm[2] <= IEEE80211_CHAN_MAX)
+#endif
+                       ic->ic_bss->ni_chan = &ic->ic_channels[frm[2]];
+
+               frm += frm[1] + 2; /* advance to the next tag */
+       }
+}
+
+static void
+iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i,
+    struct iwi_frame *frame)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       struct mbuf *m;
+       struct ieee80211_frame *wh;
+       struct ieee80211_node *ni;
+       int error;
+
+       DPRINTFN(5, ("RX!DATA!%u!%u!%u\n", le16toh(frame->len), frame->chan,
+           frame->rssi_dbm));
+
+       if (le16toh(frame->len) < sizeof (struct ieee80211_frame_min) ||
+           le16toh(frame->len) > MCLBYTES) {
+               device_printf(sc->sc_dev, "bad frame length\n");
+               return;
+       }
+
+       bus_dmamap_unload(sc->rx_buf_dmat, buf->map);
+
+       /* Finalize mbuf */
+       m = buf->m;
+       m->m_pkthdr.rcvif = ifp;
+       m->m_pkthdr.len = m->m_len = sizeof (struct iwi_hdr) +
+           sizeof (struct iwi_frame) + le16toh(frame->len);
+
+       m_adj(m, sizeof (struct iwi_hdr) + sizeof (struct iwi_frame));
+
+       wh = mtod(m, struct ieee80211_frame *);
+       if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+               /*
+                * Hardware decrypts the frame itself but leaves the WEP bit
+                * set in the 802.11 header and don't remove the iv and crc
+                * fields
+                */
+               wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+               bcopy(wh, (char *)wh + IEEE80211_WEP_IVLEN +
+                   IEEE80211_WEP_KIDLEN, sizeof (struct ieee80211_frame));
+               m_adj(m, IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN);
+               m_adj(m, -IEEE80211_WEP_CRCLEN);
+               wh = mtod(m, struct ieee80211_frame *);
+       }
+
+       if (sc->sc_drvbpf != NULL) {
+               struct iwi_rx_radiotap_header *tap = &sc->sc_rxtap;
+
+               tap->wr_flags = 0;
+               tap->wr_rate = frame->rate;
+               tap->wr_chan_freq =
+                   htole16(ic->ic_channels[frame->chan].ic_freq);
+               tap->wr_chan_flags =
+                   htole16(ic->ic_channels[frame->chan].ic_flags);
+               tap->wr_antsignal = frame->signal;
+               tap->wr_antnoise = frame->noise;
+               tap->wr_antenna = frame->antenna;
+
+               bpf_ptap(sc->sc_drvbpf, m, tap, sc->sc_rxtap_len);
+       }
+
+       if (ic->ic_state == IEEE80211_S_SCAN)
+               iwi_fix_channel(sc, m);
+
+       if (ic->ic_opmode != IEEE80211_M_STA) {
+               ni = ieee80211_find_node(ic, wh->i_addr2);
+               if (ni == NULL)
+                       ni = ieee80211_ref_node(ic->ic_bss);
+       } else
+               ni = ieee80211_ref_node(ic->ic_bss);
+
+       /* Send the frame to the upper layer */
+       ieee80211_input(ifp, m, ni, IWI_RSSIDBM2RAW(frame->rssi_dbm), 0);
+
+       if (ni == ic->ic_bss)
+               ieee80211_unref_node(&ni);
+       else
+               ieee80211_free_node(ic, ni);
+
+       buf->m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
+       if (buf->m == NULL) {
+               device_printf(sc->sc_dev, "could not allocate rx mbuf\n");
+               return;
+       }
+
+       error = bus_dmamap_load(sc->rx_buf_dmat, buf->map, mtod(buf->m, void *),
+           MCLBYTES, iwi_dma_map_addr, &buf->physaddr, 0);
+       if (error != 0) {
+               device_printf(sc->sc_dev, "could not load rx buf DMA map\n");
+               m_freem(buf->m);
+               buf->m = NULL;
+               return;
+       }
+
+       CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4, buf->physaddr);
+}
+
+static void
+iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       struct iwi_notif_scan_channel *chan;
+       struct iwi_notif_scan_complete *scan;
+       struct iwi_notif_authentication *auth;
+       struct iwi_notif_association *assoc;
+
+       switch (notif->type) {
+       case IWI_NOTIF_TYPE_SCAN_CHANNEL:
+               chan = (struct iwi_notif_scan_channel *)(notif + 1);
+
+               DPRINTFN(2, ("Scan channel (%u)\n", chan->nchan));
+               break;
+
+       case IWI_NOTIF_TYPE_SCAN_COMPLETE:
+               scan = (struct iwi_notif_scan_complete *)(notif + 1);
+
+               DPRINTFN(2, ("Scan completed (%u, %u)\n", scan->nchan,
+                   scan->status));
+
+               sc->flags &= ~(IWI_FLAG_SCANNING);
+               sc->flags |= IWI_FLAG_SCAN_COMPLETE;
+
+               if ( sc->flags & IWI_FLAG_SCAN_ABORT ) {
+                       sc->flags &= ~(IWI_FLAG_SCAN_ABORT);
+                       wakeup(IWI_FW_SCAN_COMPLETED(sc));
+               } else {
+                       ieee80211_end_scan(ifp);
+                       wakeup(IWI_FW_SCAN_COMPLETED(sc));
+               }
+               break;
+
+       case IWI_NOTIF_TYPE_AUTHENTICATION:
+               auth = (struct iwi_notif_authentication *)(notif + 1);
+
+               DPRINTFN(2, ("Authentication (%u)\n", auth->state));
+
+               switch (auth->state) {
+               case IWI_AUTHENTICATED:
+                       ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
+                       break;
+
+               case IWI_DEAUTHENTICATED:
+                       ieee80211_begin_scan(ifp);/* not necessary */
+                       break;
+
+               default:
+                       device_printf(sc->sc_dev,
+                           "unknown authentication state %u\n", auth->state);
+               }
+               break;
+
+       case IWI_NOTIF_TYPE_ASSOCIATION:
+               assoc = (struct iwi_notif_association *)(notif + 1);
+
+               DPRINTFN(2, ("Association (%u, %u)\n", assoc->state,
+                   assoc->status));
+
+               switch (assoc->state) {
+               case IWI_ASSOCIATED:
+                       sc->flags |= IWI_FLAG_ASSOCIATED;
+                       ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+                       break;
+
+               case IWI_DEASSOCIATED:
+                       sc->flags &= ~(IWI_FLAG_ASSOCIATED);
+                       wakeup(IWI_FW_DEASSOCIATED(sc));
+                       ieee80211_begin_scan(ifp);/* probably not necessary */
+                       break;
+
+               default:
+                       device_printf(sc->sc_dev,
+                           "unknown association state %u\n", assoc->state);
+               }
+               break;
+
+       case IWI_NOTIF_TYPE_CALIBRATION:
+               DPRINTFN(5, ("Notification calib (%u)\n", notif->type));
+               break;
+       case IWI_NOTIF_TYPE_BEACON:
+               DPRINTFN(5, ("Notification beacon (%u)\n", notif->type));
+               break;
+       case IWI_NOTIF_TYPE_NOISE:
+               DPRINTFN(5, ("Notification noise (%u)\n", notif->type));
+               break;
+
+       default:
+               device_printf(sc->sc_dev, "unknown notification type %u\n",
+                   notif->type);
+       }
+}
+
+static void
+iwi_rx_intr(struct iwi_softc *sc)
+{
+       struct iwi_rx_buf *buf;
+       struct iwi_hdr *hdr;
+       u_int32_t r, i;
+
+       r = CSR_READ_4(sc, IWI_CSR_RX_READ_INDEX);
+
+       for (i = (sc->rx_cur + 1) % IWI_RX_RING_SIZE; i != r;
+            i = (i + 1) % IWI_RX_RING_SIZE) {
+
+               buf = &sc->rx_buf[i];
+
+               bus_dmamap_sync(sc->rx_buf_dmat, buf->map,
+                   BUS_DMASYNC_POSTREAD);
+
+               hdr = mtod(buf->m, struct iwi_hdr *);
+
+               switch (hdr->type) {
+               case IWI_HDR_TYPE_FRAME:
+                       iwi_frame_intr(sc, buf, i,
+                           (struct iwi_frame *)(hdr + 1));
+                       break;
+
+               case IWI_HDR_TYPE_NOTIF:
+                       iwi_notification_intr(sc,
+                           (struct iwi_notif *)(hdr + 1));
+                       break;
+
+               default:
+                       device_printf(sc->sc_dev, "unknown hdr type %u\n",
+                           hdr->type);
+               }
+       }
+
+       /* Tell the firmware what we have processed */
+       sc->rx_cur = (r == 0) ? IWI_RX_RING_SIZE - 1 : r - 1;
+       CSR_WRITE_4(sc, IWI_CSR_RX_WRITE_INDEX, sc->rx_cur);
+}
+
+static void
+iwi_tx_intr(struct iwi_softc *sc)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       struct iwi_tx_buf *buf;
+       u_int32_t r, i;
+
+       r = CSR_READ_4(sc, IWI_CSR_TX1_READ_INDEX);
+#if  notyet
+       bus_dmamap_sync(sc->tx_ring_dmat, sc->tx_ring_map, BUS_DMASYNC_POSTWRITE);
+#endif
+
+       for (i = (sc->tx_old + 1) % IWI_TX_RING_SIZE; i != r;
+            i = (i + 1) % IWI_TX_RING_SIZE) {
+
+               buf = &sc->tx_buf[i];
+
+               bus_dmamap_sync(sc->tx_buf_dmat, buf->map,
+                   BUS_DMASYNC_POSTWRITE);
+               bus_dmamap_unload(sc->tx_buf_dmat, buf->map);
+               m_freem(buf->m);
+               buf->m = NULL;
+               if (buf->ni != ic->ic_bss)
+                       ieee80211_free_node(ic, buf->ni);
+               buf->ni = NULL;
+
+               sc->tx_queued--;
+
+               /* kill watchdog timer */
+               sc->sc_tx_timer = 0;
+       }
+
+       /* Remember what the firmware has processed */
+       sc->tx_old = (r == 0) ? IWI_TX_RING_SIZE - 1 : r - 1;
+
+       /* Call start() since some buffer descriptors have been released */
+       ifp->if_flags &= ~IFF_OACTIVE;
+       (*ifp->if_start)(ifp);
+}
+
+static void
+iwi_intr(void *arg)
+{
+       struct iwi_softc *sc = arg;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       u_int32_t r;
+       IWI_LOCK_INFO;
+       IWI_IPLLOCK_INFO;
+
+       IWI_IPLLOCK(sc);
+
+       if ((r = CSR_READ_4(sc, IWI_CSR_INTR)) == 0 || r == 0xffffffff) {
+               IWI_IPLUNLOCK(sc);
+               return;
+       }
+
+       /* Disable interrupts */
+       CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0);
+
+       DPRINTFN(8, ("INTR!0x%08x\n", r));
+
+       sc->flags &= ~(IWI_FLAG_RF_DISABLED);
+
+       if ( r & IWI_INTR_FATAL_ERROR ) {
+               if ( !(sc->flags & (IWI_FLAG_RESET | IWI_FLAG_EXIT))) {
+                       sc->flags |= IWI_FLAG_RESET;
+                       wakeup(IWI_FW_WAKE_MONITOR(sc));
+               }
+       }
+
+       if (r & IWI_INTR_PARITY_ERROR) {
+                       device_printf(sc->sc_dev, "fatal error\n");
+                       sc->sc_ic.ic_if.if_flags &= ~IFF_UP;
+                       IWI_LOCK(sc);
+                       iwi_stop(sc);
+                       IWI_UNLOCK(sc);
+       }
+
+       if (r & IWI_INTR_FW_INITED) {
+               if (!(r & (IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR)))
+                       wakeup(IWI_FW_INITIALIZED(sc));
+       }
+
+       if (r & IWI_INTR_RADIO_OFF) {
+               DPRINTF(("radio transmitter off\n"));
+               sc->sc_ic.ic_if.if_flags &= ~IFF_UP;
+               IWI_LOCK(sc);
+               iwi_stop(sc);
+               IWI_UNLOCK(sc);
+               sc->flags |= IWI_FLAG_RF_DISABLED;
+       }
+
+       if (r & IWI_INTR_RX_TRANSFER)
+               iwi_rx_intr(sc);
+
+       if (r & IWI_INTR_CMD_TRANSFER)
+               wakeup(IWI_FW_CMD_ACKED(sc));
+
+       if (r & IWI_INTR_TX1_TRANSFER)
+               iwi_tx_intr(sc);
+
+       if (r & ~(IWI_HANDLED_INTR_MASK))
+               device_printf(sc->sc_dev, 
+                             "unhandled interrupt(s) INTR!0x%08x\n",
+                             r & ~(IWI_HANDLED_INTR_MASK));
+
+       /* Acknowledge interrupts */
+       CSR_WRITE_4(sc, IWI_CSR_INTR, r);
+
+       /* Re-enable interrupts */
+       CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK);
+
+       IWI_IPLUNLOCK(sc);
+
+       if ((ifp->if_flags & IFF_RUNNING) && !ifq_is_empty(&ifp->if_snd))
+               iwi_start(ifp);
+}
+
+struct iwi_dma_mapping {
+       bus_dma_segment_t segs[IWI_MAX_NSEG];
+       int nseg;
+       bus_size_t mapsize;
+};
+
+static void
+iwi_dma_map_buf(void *arg, bus_dma_segment_t *segs, int nseg,
+    bus_size_t mapsize, int error)
+{
+       struct iwi_dma_mapping *map = arg;
+
+       if (error != 0)
+               return;
+
+       KASSERT(nseg <= IWI_MAX_NSEG, ("too many DMA segments %d", nseg));
+
+       bcopy(segs, map->segs, nseg * sizeof (bus_dma_segment_t));
+       map->nseg = nseg;
+       map->mapsize = mapsize;
+}
+
+static void
+iwi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg __unused, int error)
+{
+       if (error != 0) {
+               printf("iwi: fatal DMA mapping error !!!\n");
+               return;
+       }
+
+       KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+
+       *(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+static int
+iwi_cmd(struct iwi_softc *sc, u_int8_t type, void *data, u_int8_t len,
+    int async)
+{
+       struct iwi_cmd_desc *desc;
+
+       DPRINTFN(2, ("TX!CMD!%u!%u\n", type, len));
+
+       desc = &sc->cmd_desc[sc->cmd_cur];
+       desc->hdr.type = IWI_HDR_TYPE_COMMAND;
+       desc->hdr.flags = IWI_HDR_FLAG_IRQ;
+       desc->type = type;
+       desc->len = len;
+       bcopy(data, desc->data, len);
+
+       bus_dmamap_sync(sc->cmd_ring_dmat, sc->cmd_ring_map,
+           BUS_DMASYNC_PREWRITE);
+
+       sc->cmd_cur = (sc->cmd_cur + 1) % IWI_CMD_RING_SIZE;
+       CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur);
+
+       return async ? 0 : tsleep( IWI_FW_CMD_ACKED(sc), 0, "iwicmd", hz);
+}
+
+static int
+iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
+{
+       struct iwi_softc *sc = ifp->if_softc;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ieee80211_frame *wh;
+       struct iwi_tx_buf *buf;
+       struct iwi_tx_desc *desc;
+       struct iwi_dma_mapping map;
+       struct mbuf *mnew;
+       u_int32_t id = 0;
+       int error, i;
+       IWI_IPLLOCK_INFO; /* XXX still need old ipl locking mech. here */
+       IWI_IPLLOCK(sc);
+
+       if (sc->sc_drvbpf != NULL) {
+               struct iwi_tx_radiotap_header *tap = &sc->sc_txtap;
+
+               tap->wt_flags = 0;
+               tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
+               tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
+
+               bpf_ptap(sc->sc_drvbpf, m0, tap, sc->sc_txtap_len);
+       }
+
+       buf = &sc->tx_buf[sc->tx_cur];
+       desc = &sc->tx_desc[sc->tx_cur];
+
+       wh = mtod(m0, struct ieee80211_frame *);
+
+       if ( (id = iwi_find_station( sc, wh->i_addr1 ) ) == 0xff )
+               id = iwi_cache_station( sc, wh->i_addr1 );
+
+       bzero( desc, sizeof (struct iwi_tx_desc) );
+       desc->station_number = id;
+
+       /* trim IEEE802.11 header */
+       m_adj(m0, sizeof (struct ieee80211_frame));
+
+       error = bus_dmamap_load_mbuf(sc->tx_buf_dmat, buf->map, m0,
+           iwi_dma_map_buf, &map, BUS_DMA_NOWAIT);
+       if (error != 0 && error != EFBIG) {
+               device_printf(sc->sc_dev, "could not map mbuf (error %d)\n",
+                   error);
+               m_freem(m0);
+               IWI_IPLUNLOCK(sc);
+               return error;
+       }
+       if (error != 0) {
+               mnew = m_defrag(m0, MB_DONTWAIT);
+               if (mnew == NULL) {
+                       device_printf(sc->sc_dev,
+                           "could not defragment mbuf\n");
+                       m_freem(m0);
+                       IWI_IPLUNLOCK(sc);
+                       return ENOBUFS;
+               }
+               m0 = mnew;
+
+               error = bus_dmamap_load_mbuf(sc->tx_buf_dmat, buf->map, m0,
+                   iwi_dma_map_buf, &map, BUS_DMA_NOWAIT);
+               if (error != 0) {
+                       device_printf(sc->sc_dev,
+                           "could not map mbuf (error %d)\n", error);
+                       m_freem(m0);
+                       IWI_IPLUNLOCK(sc);
+                       return error;
+               }
+       }
+
+       buf->m = m0;
+       buf->ni = ni;
+
+       desc->hdr.type = IWI_HDR_TYPE_DATA;
+       desc->hdr.flags = IWI_HDR_FLAG_IRQ;
+       desc->cmd = IWI_DATA_CMD_TX;
+       desc->len = htole16(m0->m_pkthdr.len);
+       desc->flags = 0;
+       if (ic->ic_opmode == IEEE80211_M_IBSS) {
+               if (!IEEE80211_IS_MULTICAST(wh->i_addr1))
+                       desc->flags |= IWI_DATA_FLAG_NEED_ACK;
+       } else if (!IEEE80211_IS_MULTICAST(wh->i_addr3))
+               desc->flags |= IWI_DATA_FLAG_NEED_ACK;
+
+       if (ic->ic_flags & IEEE80211_F_WEPON) {
+               wh->i_fc[1] |= IEEE80211_FC1_WEP;
+               desc->wep_txkey = ic->ic_wep_txkey;
+       } else
+               desc->flags |= IWI_DATA_FLAG_NO_WEP;
+
+       if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+               desc->flags |= IWI_DATA_FLAG_SHPREAMBLE;
+
+       bcopy(wh, &desc->wh, sizeof (struct ieee80211_frame));
+       desc->nseg = htole32(map.nseg);
+       for (i = 0; i < map.nseg; i++) {
+               desc->seg_addr[i] = htole32(map.segs[i].ds_addr);
+               desc->seg_len[i]  = htole32(map.segs[i].ds_len);
+       }
+
+       bus_dmamap_sync(sc->tx_buf_dmat, buf->map, BUS_DMASYNC_PREWRITE);
+       bus_dmamap_sync(sc->tx_ring_dmat, sc->tx_ring_map,
+           BUS_DMASYNC_PREWRITE);
+
+       DPRINTFN(5, ("TX!DATA!%u!%u\n", desc->len, desc->nseg));
+
+       /* Inform firmware about this new packet */
+       sc->tx_queued++;
+       sc->tx_cur = (sc->tx_cur + 1) % IWI_TX_RING_SIZE;
+       CSR_WRITE_4(sc, IWI_CSR_TX1_WRITE_INDEX, sc->tx_cur);
+
+       IWI_IPLUNLOCK(sc);
+       return 0;
+}
+
+static void
+iwi_start(struct ifnet *ifp)
+{
+       struct iwi_softc *sc = ifp->if_softc;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct mbuf *m0;
+       struct ieee80211_node *ni;
+
+       if (ic->ic_state != IEEE80211_S_RUN) {
+               return;
+       }
+
+       for (;;) {
+               m0 = ifq_poll(&ifp->if_snd);
+               if (m0 == NULL)
+                       break;
+               m0 = ifq_dequeue(&ifp->if_snd);
+
+               if (sc->tx_queued >= IWI_TX_RING_SIZE - 4) {
+                       IF_PREPEND(&ifp->if_snd, m0);
+                       ifp->if_flags |= IFF_OACTIVE;
+                       break;
+               }
+
+#if NBPFILTER > 0
+               BPF_MTAP(ifp, m0);
+#endif
+
+               m0 = ieee80211_encap(ifp, m0, &ni);
+               if (m0 == NULL)
+                       continue;
+
+               if (ic->ic_rawbpf != NULL)
+                       bpf_mtap(ic->ic_rawbpf, m0);
+
+               if (iwi_tx_start(ifp, m0, ni) != 0) {
+                       if (ni != NULL && ni != ic->ic_bss)
+                               ieee80211_free_node(ic, ni);
+                       break;
+               }
+
+               /* start watchdog timer */
+               sc->sc_tx_timer = 5;
+               ifp->if_timer = 1;
+       }
+
+}
+
+static void
+iwi_watchdog(struct ifnet *ifp)
+{
+       struct iwi_softc *sc = ifp->if_softc;
+
+       ifp->if_timer = 0;
+
+       if (sc->sc_tx_timer > 0) {
+               if (--sc->sc_tx_timer == 0) {
+                       if_printf(ifp, "device timeout\n");
+                       wakeup(IWI_FW_WAKE_MONITOR(sc));
+                       return;
+               }
+               ifp->if_timer = 1;
+       }
+
+       ieee80211_watchdog(ifp);
+}
+
+
+static int
+iwi_wi_ioctl_get(struct ifnet *ifp, caddr_t data)
+{
+       struct wi_req           wreq;
+       struct ifreq            *ifr;
+       struct iwi_softc        *sc;
+       int                     error;
+
+       sc = ifp->if_softc;
+       ifr = (struct ifreq *)data;
+       error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
+       if (error)
+               return (error);
+
+       switch (wreq.wi_type) {
+       case WI_RID_READ_APS:
+               ieee80211_begin_scan(ifp);
+               (void) tsleep(IWI_FW_SCAN_COMPLETED(sc), 
+                       PPAUSE|PCATCH, "ssidscan", hz * 2);
+               ieee80211_end_scan(ifp);
+               break;
+       default:
+               error = ENOTTY;
+               break;
+       }
+       return (error);
+}
+
+
+
+
+static int
+iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
+{
+       struct iwi_softc *sc = ifp->if_softc;
+       struct ifreq *ifr;
+       struct ieee80211req *ireq;
+       struct ifaddr *ifa;
+       int error = 0;
+       IWI_LOCK_INFO;
+
+       IWI_LOCK(sc);
+
+       switch (cmd) {
+       case SIOCSIFADDR:
+               /*
+                * Handle this here instead of in net80211_ioctl.c
+                * so that we can lock (IWI_LOCK) the call to
+                * iwi_init().
+                */
+               ifa = (struct ifaddr *) data;
+               switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       if ((ifp->if_flags & IFF_UP) == 0) {
+                               ifp->if_flags |= IFF_UP;
+                               ifp->if_init(ifp->if_softc);
+                       }
+                       arp_ifinit(ifp, ifa);
+                       break;
+#endif
+#ifdef IPX
+#warning "IPX support has not been tested"
+               /*
+                * XXX - This code is probably wrong,
+                *       but has been copied many times.
+                */
+               case AF_IPX: {
+                       struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+                       struct arpcom *ac = (struct arpcom *)ifp;
+
+                       if (ipx_nullhost(*ina))
+                               ina->x_host = *(union ipx_host *) ac->ac_enaddr;
+                       else
+                               bcopy((caddr_t) ina->x_host.c_host,
+                                     (caddr_t) ac->ac_enaddr,
+                                     sizeof(ac->ac_enaddr));
+                       /* fall thru... */
+               }
+#endif
+               default:
+                       if ((ifp->if_flags & IFF_UP) == 0) {
+                               ifp->if_flags |= IFF_UP;
+                               ifp->if_init(ifp->if_softc);
+                       }
+                       break;
+               }
+               break;
+
+       case SIOCSIFFLAGS:
+               if (ifp->if_flags & IFF_UP) {
+                       if (!(ifp->if_flags & IFF_RUNNING)) {
+                               iwi_init(sc);
+                               error = tsleep(IWI_FW_CMD_ACKED(sc), 0,
+                                                "iwirun", hz);
+                       }
+               } else {
+                       if (ifp->if_flags & IFF_RUNNING) {
+                               iwi_stop(sc);
+                       }
+               }
+               break;
+
+       case SIOCSLOADFW:
+       case SIOCSLOADIBSSFW:
+               /* only super-user can do that! */
+               if ((error = suser(curthread)) != 0)
+                       break;
+
+               ifr = (struct ifreq *)data;
+               error = iwi_cache_firmware(sc, ifr->ifr_data,
+                               (cmd == SIOCSLOADIBSSFW) ? 1 : 0);
+               break;
+
+       case SIOCSKILLFW:
+               /* only super-user can do that! */
+               if ((error = suser(curthread)) != 0)
+                       break;
+
+               ifp->if_flags &= ~IFF_UP;
+               iwi_stop(sc);
+               iwi_free_firmware(sc);
+               break;
+
+       case SIOCG80211:
+               ireq = (struct ieee80211req *)data;
+               switch (ireq->i_type) {
+               case IEEE80211_IOC_AUTHMODE:
+                       ireq->i_val = sc->authmode;
+                       break;
+
+               default:
+                       error = ieee80211_ioctl(ifp, cmd, data, cr);
+               }
+               break;
+
+       case SIOCS80211:
+               /* only super-user can do that! */
+               if ((error = suser(curthread)) != 0)
+                       break;
+
+               ireq = (struct ieee80211req *)data;
+               switch (ireq->i_type) {
+               case IEEE80211_IOC_AUTHMODE:
+                       sc->authmode = ireq->i_val;
+                       break;
+
+               default:
+                       error = ieee80211_ioctl(ifp, cmd, data, cr);
+               }
+               break;
+       case SIOCGIFGENERIC:
+               if (sc->flags & IWI_FLAG_FW_INITED) {
+                       error = iwi_wi_ioctl_get(ifp, data);
+                       if (! error)
+                               error = ieee80211_ioctl(ifp, cmd, data, cr);
+               } else
+                       error = ENOTTY;
+               if (error != ENOTTY)
+                       break;
+
+       default:
+               error = ieee80211_ioctl(ifp, cmd, data, cr);
+       }
+
+       if (error == ENETRESET) {
+               error = 0;
+               if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
+                   (IFF_UP | IFF_RUNNING)) {
+                       iwi_init(sc);
+                       error = tsleep(IWI_FW_CMD_ACKED(sc), 0, "iwirun", hz);
+               }
+       }
+
+       IWI_UNLOCK(sc);
+
+       return error;
+}
+
+static int
+iwi_abort_scan( struct iwi_softc *sc  )
+{
+       sc->flags |= IWI_FLAG_SCAN_ABORT;
+       return iwi_cmd(sc, IWI_CMD_SCAN_ABORT, NULL, 0, 1);
+}
+
+static void
+iwi_stop_master(struct iwi_softc *sc)
+{
+       int ntries;
+
+       /*
+        * If the master is busy scanning, we will occasionally 
+        * timeout waiting for it (the master) to stop. Make the
+        * 'stopping' process more robust by ceasing all scans
+        * prior to asking for the stop.
+        */
+       if ( ( sc->flags & IWI_FLAG_SCANNING ) && 
+            !( sc->flags & IWI_FLAG_RF_DISABLED ) ) {
+               iwi_abort_scan(sc);
+               if (( sc->flags & IWI_FLAG_SCAN_ABORT ) && 
+                   !( sc->flags & IWI_FLAG_RF_DISABLED )) {
+                       (void) tsleep(IWI_FW_SCAN_COMPLETED(sc), 0,
+                                        "iwiabr", hz);
+               }
+       }
+       /* Disable interrupts */
+
+       CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0);
+
+       CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_STOP_MASTER);
+       for (ntries = 0; ntries < 5; ntries++) {
+               if (CSR_READ_4(sc, IWI_CSR_RST) & IWI_RST_MASTER_DISABLED)
+                       break;
+               DELAY(10);
+       }
+       if (ntries == 5 && sc->debug_level > 0) 
+               device_printf(sc->sc_dev, "timeout waiting for master\n");
+
+       CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
+           IWI_RST_PRINCETON_RESET);
+
+       sc->flags &= ~IWI_FLAG_FW_INITED;
+}
+
+static int
+iwi_reset(struct iwi_softc *sc)
+{
+       int i, ntries;
+
+       iwi_stop_master(sc);
+
+       /* Move adapter to D0 state */
+       CSR_WRITE_4(sc, IWI_CSR_CTL, CSR_READ_4(sc, IWI_CSR_CTL) |
+           IWI_CTL_INIT);
+
+       /* Initialize Phase-Locked Level  (PLL) */
+       CSR_WRITE_4(sc, IWI_CSR_READ_INT, IWI_READ_INT_INIT_HOST);
+
+       /* Wait for clock stabilization */
+       for (ntries = 0; ntries < 1000; ntries++) {
+               if (CSR_READ_4(sc, IWI_CSR_CTL) & IWI_CTL_CLOCK_READY)
+                       break;
+               DELAY(200);
+       }
+       if (ntries == 1000) {
+               return EIO;
+       }
+
+       CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
+           IWI_RST_SW_RESET);
+
+       DELAY(10);
+
+       CSR_WRITE_4(sc, IWI_CSR_CTL, CSR_READ_4(sc, IWI_CSR_CTL) |
+           IWI_CTL_INIT);
+
+
+       /* Clear NIC memory */
+       CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0);
+
+       for (i = 0; i < 0xc000; i++) {
+               CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, 0);
+       }
+
+       sc->num_stations = 0;
+       return 0;
+}
+
+static int
+iwi_load_ucode(struct iwi_softc *sc, void *uc, int size)
+{
+       u_int16_t *w;
+       int ntries, i;
+
+       CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
+           IWI_RST_STOP_MASTER);
+       for (ntries = 0; ntries < 5; ntries++) {
+               if (CSR_READ_4(sc, IWI_CSR_RST) & IWI_RST_MASTER_DISABLED)
+                       break;
+               DELAY(10);
+       }
+       if (ntries == 5) {
+               device_printf(sc->sc_dev, "timeout waiting for master\n");
+               return EIO;
+       }
+
+       MEM_WRITE_4(sc, 0x3000e0, 0x80000000);
+       DELAY(5000);
+       CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) &
+           ~IWI_RST_PRINCETON_RESET);
+       DELAY(5000);
+       MEM_WRITE_4(sc, 0x3000e0, 0);
+       DELAY(1000);
+       MEM_WRITE_4(sc, 0x300004, 1);
+       DELAY(1000);
+       MEM_WRITE_4(sc, 0x300004, 0);
+       DELAY(1000);
+       MEM_WRITE_1(sc, 0x200000, 0x00);
+       MEM_WRITE_1(sc, 0x200000, 0x40);
+       DELAY(1000);
+
+       /* Adapter is buggy, we must set the address for each word */
+       for (w = uc; size > 0; w++, size -= 2)
+               MEM_WRITE_2(sc, 0x200010, *w);
+
+       MEM_WRITE_1(sc, 0x200000, 0x00);
+       MEM_WRITE_1(sc, 0x200000, 0x80);
+
+       /* Wait until we get a response in the uc queue */
+       for (ntries = 0; ntries < 100; ntries++) {
+               if (MEM_READ_1(sc, 0x200000) & 1)
+                       break;
+               DELAY(100);
+       }
+       if (ntries == 100) {
+               device_printf(sc->sc_dev,
+                   "timeout waiting for ucode to initialize\n");
+               return EIO;
+       }
+
+       /* Empty the uc queue or the firmware will not initialize properly */
+       for (i = 0; i < 7; i++)
+               MEM_READ_4(sc, 0x200004);
+
+       MEM_WRITE_1(sc, 0x200000, 0x00);
+
+       return 0;
+}
+
+/* macro to handle unaligned little endian data in firmware image */
+#define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24)
+static int
+iwi_load_firmware(struct iwi_softc *sc, void *fw, int size)
+{
+       bus_dma_tag_t dmat;
+       bus_dmamap_t map;
+       bus_addr_t physaddr;
+       void *virtaddr;
+       u_char *p, *end;
+       u_int32_t sentinel, ctl, src, dst, sum, len, mlen;
+       int ntries, error = 0;
+
+       sc->flags &= ~(IWI_FLAG_FW_INITED);
+
+       /* Allocate DMA memory for storing firmware image */
+       error = bus_dma_tag_create(sc->iwi_parent_tag, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, BUS_DMA_ALLOCNOW, &dmat);
+       if (error != 0) {
+               device_printf(sc->sc_dev,
+                   "could not create firmware DMA tag\n");
+               goto fail1;
+       }
+
+       /*
+        * We cannot map fw directly because of some hardware constraints on
+        * the mapping address.
+        */
+       error = bus_dmamem_alloc(dmat, &virtaddr, BUS_DMA_WAITOK, &map);
+       if (error != 0) {
+               device_printf(sc->sc_dev,
+                   "could not allocate firmware DMA memory\n");
+               goto fail2;
+       }
+
+       error = bus_dmamap_load(dmat, map, virtaddr, size, iwi_dma_map_addr,
+           &physaddr, 0);
+       if (error != 0) {
+               device_printf(sc->sc_dev, "could not load firmware DMA map\n");
+               goto fail3;
+       }
+
+       /* Copy firmware image to DMA memory */
+       bcopy(fw, virtaddr, size);
+
+       /* Make sure the adapter will get up-to-date values */
+       bus_dmamap_sync(dmat, map, BUS_DMASYNC_PREWRITE);
+
+       /* Tell the adapter where the command blocks are stored */
+       MEM_WRITE_4(sc, 0x3000a0, 0x27000);
+
+       /*
+        * Store command blocks into adapter's internal memory using register
+        * indirections. The adapter will read the firmware image through DMA
+        * using information stored in command blocks.
+        */
+       src = physaddr;
+       p = virtaddr;
+       end = p + size;
+       CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0x27000);
+
+       while (p < end) {
+               dst = GETLE32(p); p += 4; src += 4;
+               len = GETLE32(p); p += 4; src += 4;
+               p += len;
+
+               while (len > 0) {
+                       mlen = min(len, IWI_CB_MAXDATALEN);
+
+                       ctl = IWI_CB_DEFAULT_CTL | mlen;
+                       sum = ctl ^ src ^ dst;
+
+                       /* Write a command block */
+                       CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, ctl);
+                       CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, src);
+                       CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, dst);
+                       CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, sum);
+
+                       src += mlen;
+                       dst += mlen;
+                       len -= mlen;
+               }
+       }
+
+       /* Write a fictive final command block (sentinel) */
+       sentinel = CSR_READ_4(sc, IWI_CSR_AUTOINC_ADDR);
+       CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, 0);
+
+       CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) &
+           ~(IWI_RST_MASTER_DISABLED | IWI_RST_STOP_MASTER));
+
+       /* Tell the adapter to start processing command blocks */
+       MEM_WRITE_4(sc, 0x3000a4, 0x540100);
+
+       /* Wait until the adapter has processed all command blocks */
+       for (ntries = 0; ntries < 400; ntries++) {
+               if (MEM_READ_4(sc, 0x3000d0) >= sentinel)
+                       break;
+               DELAY(100);
+       }
+       if (ntries == 400) {
+               device_printf(sc->sc_dev,
+                   "timeout processing command blocks\n");
+               error = EIO;
+               goto fail4;
+       }
+
+
+       /* We're done with command blocks processing */
+       MEM_WRITE_4(sc, 0x3000a4, 0x540c00);
+
+       /* Allow interrupts so we know when the firmware is inited */
+       CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK);
+
+       /* Tell the adapter to initialize the firmware */
+       CSR_WRITE_4(sc, IWI_CSR_RST, 0);
+       CSR_WRITE_4(sc, IWI_CSR_CTL, CSR_READ_4(sc, IWI_CSR_CTL) |
+           IWI_CTL_ALLOW_STANDBY);
+
+       /* Wait at most one second for firmware initialization to complete */
+       if ((error = tsleep(IWI_FW_INITIALIZED(sc), 0, "iwiini", hz)) != 0) {
+               device_printf(sc->sc_dev, "timeout waiting for firmware "
+                   "initialization to complete\n");
+               goto fail4;
+       }
+
+fail4:  bus_dmamap_sync(dmat, map, BUS_DMASYNC_POSTWRITE);
+       bus_dmamap_unload(dmat, map);
+fail3: bus_dmamem_free(dmat, virtaddr, map);
+fail2: bus_dma_tag_destroy(dmat);
+fail1:
+       return error;
+}
+
+/*
+ * Store firmware into kernel memory so we can download it when we need to,
+ * e.g when the adapter wakes up from suspend mode.
+ */
+static int
+iwi_cache_firmware(struct iwi_softc *sc, void *data, int is_ibss)
+{
+       struct iwi_firmware *kfw = &sc->fw;
+       struct iwi_firmware ufw;
+       int error;
+
+       iwi_free_firmware(sc);
+
+       /*
+        * mutex(9): no mutexes should be held across functions which access
+        * memory in userspace, such as copyin(9) [...]
+        */
+
+       if ((error = copyin(data, &ufw, sizeof ufw)) != 0)
+               goto fail1;
+
+       kfw->boot_size  = ufw.boot_size;
+       kfw->ucode_size = ufw.ucode_size;
+       kfw->main_size  = ufw.main_size;
+
+       kfw->boot = malloc(kfw->boot_size, M_DEVBUF, M_WAITOK);
+       if (kfw->boot == NULL) {
+               error = ENOMEM;
+               goto fail1;
+       }
+
+       kfw->ucode = malloc(kfw->ucode_size, M_DEVBUF, M_WAITOK);
+       if (kfw->ucode == NULL) {
+               error = ENOMEM;
+               goto fail2;
+       }
+
+       kfw->main = malloc(kfw->main_size, M_DEVBUF, M_WAITOK);
+       if (kfw->main == NULL) {
+               error = ENOMEM;
+               goto fail3;
+       }
+
+       if ((error = copyin(ufw.boot, kfw->boot, kfw->boot_size)) != 0)
+               goto fail4;
+
+       if ((error = copyin(ufw.ucode, kfw->ucode, kfw->ucode_size)) != 0)
+               goto fail4;
+
+       if ((error = copyin(ufw.main, kfw->main, kfw->main_size)) != 0)
+               goto fail4;
+
+       DPRINTF(("Firmware cached: boot %u, ucode %u, main %u\n",
+           kfw->boot_size, kfw->ucode_size, kfw->main_size));
+
+
+       sc->flags |= IWI_FLAG_FW_CACHED;
+       sc->flags |= is_ibss ? IWI_FLAG_FW_IBSS : 0;
+       return 0;
+
+fail4: free(kfw->boot, M_DEVBUF);
+fail3: free(kfw->ucode, M_DEVBUF);
+fail2: free(kfw->main, M_DEVBUF);
+fail1:
+
+       return error;
+}
+
+static void
+iwi_free_firmware(struct iwi_softc *sc)
+{
+       if (!(sc->flags & IWI_FLAG_FW_CACHED))
+               return;
+
+       free(sc->fw.boot, M_DEVBUF);
+       free(sc->fw.ucode, M_DEVBUF);
+       free(sc->fw.main, M_DEVBUF);
+
+       sc->flags &= ~( IWI_FLAG_FW_CACHED | IWI_FLAG_FW_IBSS );
+}
+
+static int
+iwi_adapter_config(struct iwi_softc *sc, int is_a, int cmd_wait)
+{
+       struct iwi_configuration config;
+
+       bzero(&config, sizeof config);
+       config.enable_multicast = 1;
+       config.noise_reported = 1;
+
+       config.bg_autodetect = 
+               ( !(is_a) &&
+                 ( sc->enable_bg_autodetect != 0 ) ) ? 1 : 0;  /* default: on  */
+
+       config.bluetooth_coexistence =
+               ( sc->enable_bt_coexist != 0 ) ? 1 : 0;         /* default: on  */
+
+       config.enable_cts_to_self =
+               ( sc->enable_cts_to_self > 0 ) ? 1 : 0;         /* default: off */
+
+       if (sc->antenna_diversity > 0 ) {                       /* default: BOTH */
+               switch( sc->antenna_diversity ) {
+                       case 1: case 3:
+                               config.antenna_diversity = sc->antenna_diversity;
+               }
+       }
+
+       config.disable_unicast_decryption =
+               ( sc->disable_unicast_decryption != 0 ) ? 1 : 0; /* default: on */
+
+       config.disable_multicast_decryption =
+               ( sc->disable_multicast_decryption != 0 ) ? 1 : 0;/* default: on */
+
+
+       if ( sc->debug_level > 0 ) {
+               printf("config.bluetooth_coexistence = %d\n",
+                        config.bluetooth_coexistence );
+               printf("config.bg_autodetect = %d\n",
+                        config.bg_autodetect );
+               printf("config.enable_cts_to_self = %d\n",
+                        config.enable_cts_to_self );
+               printf("config.antenna_diversity = %d\n",
+                        config.antenna_diversity );
+               printf("config.disable_unicast_decryption = %d\n",
+                        config.disable_unicast_decryption );
+               printf("config.disable_multicast_decryption = %d\n",
+                        config.disable_multicast_decryption );
+               printf("config.neg_best_rates_first = %d\n",
+                        sc->enable_neg_best_first );
+       }
+
+       return iwi_cmd(sc, IWI_CMD_SET_CONFIGURATION, &config,
+                sizeof config, cmd_wait );
+}
+
+static int
+iwi_config(struct iwi_softc *sc)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       struct iwi_rateset rs;
+       struct iwi_txpower power;
+       struct ieee80211_wepkey *k;
+       struct iwi_wep_key wepkey;
+       u_int32_t data;
+       int error, i;
+
+       IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
+       DPRINTF(("Setting MAC address to %6D\n", ic->ic_myaddr, ":"));
+       error = iwi_cmd(sc, IWI_CMD_SET_MAC_ADDRESS, ic->ic_myaddr,
+           IEEE80211_ADDR_LEN, 0);
+       if (error != 0)
+               return error;
+
+       DPRINTF(("Configuring adapter\n"));
+       if ((error = iwi_adapter_config(sc, 1, 0)) != 0)
+               return error;
+
+       data = htole32(IWI_POWER_MODE_CAM);
+       DPRINTF(("Setting power mode to %u\n", le32toh(data)));
+       error = iwi_cmd(sc, IWI_CMD_SET_POWER_MODE, &data, sizeof data, 0);
+       if (error != 0)
+               return error;
+
+       data = htole32(ic->ic_rtsthreshold);
+       DPRINTF(("Setting RTS threshold to %u\n", le32toh(data)));
+       error = iwi_cmd(sc, IWI_CMD_SET_RTS_THRESHOLD, &data, sizeof data, 0);
+       if (error != 0)
+               return error;
+
+       if (ic->ic_opmode == IEEE80211_M_IBSS) {
+               power.mode = IWI_MODE_11B;
+               power.nchan = 11;
+               for (i = 0; i < 11; i++) {
+                       power.chan[i].chan = i + 1;
+                       power.chan[i].power = IWI_TXPOWER_MAX;
+               }
+               DPRINTF(("Setting .11b channels tx power\n"));
+               error = iwi_cmd(sc, IWI_CMD_SET_TX_POWER, &power, sizeof power,
+                   0);
+               if (error != 0)
+                       return error;
+
+               power.mode = IWI_MODE_11G;
+               DPRINTF(("Setting .11g channels tx power\n"));
+               error = iwi_cmd(sc, IWI_CMD_SET_TX_POWER, &power, sizeof power,
+                   0);
+               if (error != 0)
+                       return error;
+       }
+
+       rs.mode = IWI_MODE_11G;
+       rs.type = IWI_RATESET_TYPE_SUPPORTED;
+       rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates;
+       bcopy(ic->ic_sup_rates[IEEE80211_MODE_11G].rs_rates, rs.rates,
+           rs.nrates);
+       DPRINTF(("Setting .11bg supported rates (%u)\n", rs.nrates));
+       error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 0);
+       if (error != 0)
+               return error;
+
+       rs.mode = IWI_MODE_11A;
+       rs.type = IWI_RATESET_TYPE_SUPPORTED;
+       rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates;
+       bcopy(ic->ic_sup_rates[IEEE80211_MODE_11A].rs_rates, rs.rates,
+           rs.nrates);
+       DPRINTF(("Setting .11a supported rates (%u)\n", rs.nrates));
+       error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 0);
+       if (error != 0)
+               return error;
+
+       data = htole32(arc4random());
+       DPRINTF(("Setting initialization vector to %u\n", le32toh(data)));
+       error = iwi_cmd(sc, IWI_CMD_SET_IV, &data, sizeof data, 0);
+       if (error != 0)
+               return error;
+
+       if (ic->ic_flags & IEEE80211_F_WEPON) {
+               k = ic->ic_nw_keys;
+               for (i = 0; i < IEEE80211_WEP_NKID; i++, k++) {
+                       wepkey.cmd = IWI_WEP_KEY_CMD_SETKEY;
+                       wepkey.idx = i;
+                       wepkey.len = k->wk_len;
+                       bzero(wepkey.key, sizeof wepkey.key);
+                       bcopy(k->wk_key, wepkey.key, k->wk_len);
+                       DPRINTF(("Setting wep key index %u len %u\n",
+                           wepkey.idx, wepkey.len));
+                       error = iwi_cmd(sc, IWI_CMD_SET_WEP_KEY, &wepkey,
+                           sizeof wepkey, 0);
+                       if (error != 0)
+                               return error;
+               }
+       }
+
+       /* Enable adapter */
+       DPRINTF(("Enabling adapter\n"));
+       return iwi_cmd(sc, IWI_CMD_ENABLE, NULL, 0, 0);
+}
+
+static int
+iwi_scan(struct iwi_softc *sc)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct iwi_scan scan;
+       u_int8_t *p;
+       int i, count;
+       int do_5ghz_scan = 0;
+
+       sc->scan_counter++; /* track the number of scans started */
+
+       sc->flags |= IWI_FLAG_SCANNING;
+
+       bzero(&scan, sizeof scan);
+
+       /*
+        * Alternate two broadcast scans with
+        * two broadcast/direct scans.
+        */
+       if ( sc->scan_counter & 2 ) {
+               scan.type = IWI_SCAN_TYPE_BROADCAST_AND_DIRECT;
+               scan.intval = htole16(100);
+       } else {
+               scan.type = IWI_SCAN_TYPE_BROADCAST;
+               scan.intval = htole16(40);
+       }
+
+       p = scan.channels;
+
+       /*
+        * If we have .11a capable adapter, and
+        *      - we are in .11a mode, or
+        *      - we are in auto mode and this is an odd numbered scan
+        * then do a 5GHz scan, otherwise do a 2GHz scan.
+        */
+       if ( ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates > 0 ) {
+               if (( ic->ic_curmode == IEEE80211_MODE_11A ) ||
+                   (( ic->ic_curmode == IEEE80211_MODE_AUTO ) &&
+                    ( sc->scan_counter & 1)))
+                       do_5ghz_scan = 1;
+       }
+       count = 0;
+       if ( do_5ghz_scan ) {
+               DPRINTF(("Scanning 5GHz band\n"));
+               for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
+                       if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_channels[i]) &&
+                                       isset(ic->ic_chan_active, i)) {
+                               *++p = i;
+                               count++;
+                       }
+               }
+               *(p - count) = IWI_CHAN_5GHZ | count;
+       } else {
+               DPRINTF(("Scanning 2GHz band\n"));
+               for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
+                       if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_channels[i]) &&
+                                       isset(ic->ic_chan_active, i)) {
+                               *++p = i;
+                               count++;
+                       }
+               }
+               *(p - count) = IWI_CHAN_2GHZ | count;
+       }
+       return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1);
+}
+
+static int
+iwi_auth_and_assoc(struct iwi_softc *sc)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       struct ieee80211_node *ni = ic->ic_bss;
+       struct iwi_rateset rs;
+       u_int32_t data;
+       int error, x;
+
+       if ( ( sc->flags & IWI_FLAG_FW_IBSS ) &&
+            !( ni->ni_capinfo & IEEE80211_CAPINFO_IBSS ) ) {
+               return -1; /* IBSS F/W requires network ibss capability */
+       }
+
+       DPRINTF(("Configuring adapter\n"));
+       if ((error = iwi_adapter_config(sc, 
+               IEEE80211_IS_CHAN_5GHZ(ni->ni_chan), 1)) != 0)
+                       return error;
+
+#ifdef IWI_DEBUG
+       if (sc->debug_level > 0) {
+               printf("Setting ESSID to ");
+               ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
+               printf("\n");
+       }
+#endif
+       error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ni->ni_essid, ni->ni_esslen, 1);
+       if (error != 0)
+               return error;
+
+       /* the rate set has already been "negotiated" */
+       rs.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A :
+           IWI_MODE_11G;
+       rs.type = IWI_RATESET_TYPE_NEGOTIATED;
+       rs.nrates = ni->ni_rates.rs_nrates;
+       if ( sc->enable_neg_best_first != 1 ) {
+               bcopy(ni->ni_rates.rs_rates, rs.rates, rs.nrates);
+       } else {
+               for ( x = 0 ; x < rs.nrates; x++ ) {
+                       /*
+                        * Present the firmware with the most favourable
+                        * of the negotiated rates first. 
+                        */
+                       rs.rates[rs.nrates-x-1] = ni->ni_rates.rs_rates[x];
+               }
+       }
+
+       if ( sc->debug_level > 0 ) {
+               printf("Setting negotiated rates (%u) : ", rs.nrates);
+               for ( x = 0 ; x < rs.nrates; x++ ) {
+                       printf("%d ", rs.rates[x]);
+               }
+               printf("\n");
+       }
+
+       error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 1);
+       if (error != 0)
+               return error;
+
+       data = htole32(ni->ni_rssi);
+       DPRINTF(("Setting sensitivity to %d\n", (int8_t)ni->ni_rssi));
+       error = iwi_cmd(sc, IWI_CMD_SET_SENSITIVITY, &data, sizeof data, 1);
+       if (error != 0)
+               return error;
+
+       bzero(&sc->assoc, sizeof sc->assoc);
+       sc->assoc.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A :
+           IWI_MODE_11G;
+       sc->assoc.chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+       if (sc->authmode == IEEE80211_AUTH_SHARED)
+               sc->assoc.auth = (ic->ic_wep_txkey << 4) | IWI_AUTH_SHARED;
+       bcopy(ni->ni_tstamp, sc->assoc.tstamp, 8);
+       sc->assoc.capinfo = htole16(ni->ni_capinfo);
+       sc->assoc.lintval = htole16(ic->ic_lintval);
+       sc->assoc.intval = htole16(ni->ni_intval);
+       IEEE80211_ADDR_COPY(sc->assoc.bssid, ni->ni_bssid);
+       if ( ic->ic_opmode == IEEE80211_M_IBSS )
+               IEEE80211_ADDR_COPY(sc->assoc.dst, ifp->if_broadcastaddr);
+       else
+               IEEE80211_ADDR_COPY(sc->assoc.dst, ni->ni_bssid);
+
+       DPRINTF(("Trying to associate to %6D channel %u auth %u\n",
+           sc->assoc.bssid, ":", sc->assoc.chan, sc->assoc.auth));
+       return iwi_cmd(sc, IWI_CMD_ASSOCIATE, &sc->assoc, sizeof sc->assoc, 1);
+}
+
+static void
+iwi_init(void *priv)
+{
+       struct iwi_softc *sc = priv;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       struct iwi_firmware *fw = &sc->fw;
+       int i;
+
+       /* exit immediately if firmware has not been ioctl'd */
+       if (!(sc->flags & IWI_FLAG_FW_CACHED)) {
+               ifp->if_flags &= ~IFF_UP;
+               return;
+       }
+
+       iwi_stop(sc);
+
+       if (iwi_reset(sc) != 0) {
+               device_printf(sc->sc_dev, "could not reset adapter\n");
+               goto fail;
+       }
+
+       if (iwi_load_firmware(sc, fw->boot, fw->boot_size) != 0) {
+               device_printf(sc->sc_dev, "could not load boot firmware\n");
+               goto fail;
+       }
+
+       if (iwi_load_ucode(sc, fw->ucode, fw->ucode_size) != 0) {
+               device_printf(sc->sc_dev, "could not load microcode\n");
+               goto fail;
+       }
+
+       iwi_stop_master(sc);
+
+       sc->tx_cur = 0;
+       sc->tx_queued = 0;
+       sc->tx_old = IWI_TX_RING_SIZE - 1;
+       sc->cmd_cur = 0;
+       sc->rx_cur = IWI_RX_RING_SIZE - 1;
+
+       CSR_WRITE_4(sc, IWI_CSR_CMD_BASE, sc->cmd_ring_pa);
+       CSR_WRITE_4(sc, IWI_CSR_CMD_SIZE, IWI_CMD_RING_SIZE);
+       CSR_WRITE_4(sc, IWI_CSR_CMD_READ_INDEX, 0);
+       CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur);
+
+       CSR_WRITE_4(sc, IWI_CSR_TX1_BASE, sc->tx_ring_pa);
+       CSR_WRITE_4(sc, IWI_CSR_TX1_SIZE, IWI_TX_RING_SIZE);
+       CSR_WRITE_4(sc, IWI_CSR_TX1_READ_INDEX, 0);
+       CSR_WRITE_4(sc, IWI_CSR_TX1_WRITE_INDEX, sc->tx_cur);
+
+       CSR_WRITE_4(sc, IWI_CSR_TX2_BASE, sc->tx_ring_pa);
+       CSR_WRITE_4(sc, IWI_CSR_TX2_SIZE, IWI_TX_RING_SIZE);
+       CSR_WRITE_4(sc, IWI_CSR_TX2_READ_INDEX, 0);
+       CSR_WRITE_4(sc, IWI_CSR_TX2_WRITE_INDEX, 0);
+
+       CSR_WRITE_4(sc, IWI_CSR_TX3_BASE, sc->tx_ring_pa);
+       CSR_WRITE_4(sc, IWI_CSR_TX3_SIZE, IWI_TX_RING_SIZE);
+       CSR_WRITE_4(sc, IWI_CSR_TX3_READ_INDEX, 0);
+       CSR_WRITE_4(sc, IWI_CSR_TX3_WRITE_INDEX, 0);
+
+       CSR_WRITE_4(sc, IWI_CSR_TX4_BASE, sc->tx_ring_pa);
+       CSR_WRITE_4(sc, IWI_CSR_TX4_SIZE, IWI_TX_RING_SIZE);
+       CSR_WRITE_4(sc, IWI_CSR_TX4_READ_INDEX, 0);
+       CSR_WRITE_4(sc, IWI_CSR_TX4_WRITE_INDEX, 0);
+
+       for (i = 0; i < IWI_RX_RING_SIZE; i++)
+               CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4,
+                   sc->rx_buf[i].physaddr);
+
+       /*
+        * Kick Rx
+        */
+       CSR_WRITE_4(sc, IWI_CSR_RX_WRITE_INDEX, sc->rx_cur);
+       CSR_WRITE_4(sc, IWI_CSR_RX_READ_INDEX, 0);
+
+       if (iwi_load_firmware(sc, fw->main, fw->main_size) != 0) {
+               device_printf(sc->sc_dev, "could not load main firmware\n");
+               goto fail;
+       }
+
+       /*
+        * Force the opmode based on what firmware is loaded. This
+        * stops folks from killing the firmware by asking it to
+        * do something it doesn't support.
+        */
+       if ( ic->ic_opmode != IEEE80211_M_MONITOR ) {
+               ic->ic_opmode = ( sc->flags & IWI_FLAG_FW_IBSS )
+                       ? IEEE80211_M_IBSS : IEEE80211_M_STA;
+       }
+
+       sc->flags |= IWI_FLAG_FW_INITED;
+
+       sc->flags &= ~( IWI_FLAG_SCANNING |
+                       IWI_FLAG_SCAN_COMPLETE |
+                       IWI_FLAG_SCAN_ABORT |
+                       IWI_FLAG_ASSOCIATED );
+
+       if (iwi_config(sc) != 0) {
+               device_printf(sc->sc_dev, "device configuration failed\n");
+               goto fail;
+       }
+
+       if ( ic->ic_opmode != IEEE80211_M_MONITOR ) {
+               ieee80211_begin_scan(ifp);
+               ifp->if_flags &= ~IFF_OACTIVE;
+               ifp->if_flags |= IFF_RUNNING;
+       } else {
+               ieee80211_begin_scan(ifp);
+               ifp->if_flags &= ~IFF_OACTIVE;
+               ifp->if_flags |= IFF_RUNNING;
+       }
+
+       return;
+
+fail:  
+       if ( !(sc->flags & IWI_FLAG_RESET) )
+               ifp->if_flags &= ~IFF_UP;
+       iwi_stop(sc);
+}
+
+static void
+iwi_init_locked(void *priv) 
+{
+       struct iwi_softc *sc = priv;
+       IWI_LOCK_INFO;
+       IWI_LOCK(sc);
+       iwi_init(sc);
+       IWI_UNLOCK(sc);
+}
+
+static void
+iwi_stop(void *priv)
+{
+       struct iwi_softc *sc = priv;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       struct iwi_tx_buf *buf;
+       int i;
+
+       iwi_stop_master(sc);
+       CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_SW_RESET);
+
+       /*
+        * Release Tx buffers
+        */
+       for (i = 0; i < IWI_TX_RING_SIZE; i++) {
+               buf = &sc->tx_buf[i];
+
+               if (buf->m != NULL) {
+                       bus_dmamap_sync(sc->tx_buf_dmat, buf->map,
+                           BUS_DMASYNC_POSTWRITE);
+                       bus_dmamap_unload(sc->tx_buf_dmat, buf->map);
+                       m_freem(buf->m);
+                       buf->m = NULL;
+
+                       if (buf->ni != NULL) {
+                               if (buf->ni != ic->ic_bss)
+                                       ieee80211_free_node(ic, buf->ni);
+                               buf->ni = NULL;
+                       }
+               }
+       }
+
+       ifp->if_timer = 0;
+       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+       ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+}
+
+static int8_t
+iwi_cache_station(struct iwi_softc *sc, u_int8_t *mac)
+{
+       int i, x, base, elemsize = sizeof(struct iwi_fw_station);
+       for (i = 0; i < sc->num_stations; i++)
+               if (!memcmp(sc->stations[i], mac, IEEE80211_ADDR_LEN))
+                       break;
+       if (i == IWI_FW_MAX_STATIONS)
+               return 0xff;
+       memcpy(sc->stations[i], mac, IEEE80211_ADDR_LEN);
+       for (x = 0, base = IWI_STATION_TABLE + (i * elemsize) ; 
+            x < IEEE80211_ADDR_LEN ; x++ ) {
+               CSR_WRITE_1(sc, base + x, mac[x]);
+       }
+       if ( (i + 1) > sc->num_stations )
+               sc->num_stations++;
+       return i;
+}
+
+static u_int8_t
+iwi_find_station(struct iwi_softc *sc, u_int8_t *mac)
+{
+       u_int8_t i;
+       for (i = 0; i < sc->num_stations; i++)
+               if (!memcmp(sc->stations[i], mac, IEEE80211_ADDR_LEN))
+                       return i;
+       return 0xff;
+}
+
+static const char *
+iwi_error_desc(u_int32_t val)
+{
+       switch (val) {
+       case IWI_FW_ERROR_OK:
+               return "OK";
+       case IWI_FW_ERROR_FAIL:
+               return "FAIL";
+       case IWI_FW_ERROR_MEMORY_UNDERFLOW:
+               return "MEMORY_UNDERFLOW";
+       case IWI_FW_ERROR_MEMORY_OVERFLOW:
+               return "MEMORY_OVERFLOW";
+       case IWI_FW_ERROR_BAD_PARAM:
+               return "BAD_PARAMETER";
+       case IWI_FW_ERROR_BAD_CHECKSUM:
+               return "BAD_CHECKSUM";
+       case IWI_FW_ERROR_NMI_INTERRUPT:
+               return "NMI_INTERRUPT";
+       case IWI_FW_ERROR_BAD_DATABASE:
+               return "BAD_DATABASE";
+       case IWI_FW_ERROR_ALLOC_FAIL:
+               return "ALLOC_FAIL";
+       case IWI_FW_ERROR_DMA_UNDERRUN:
+               return "DMA_UNDERRUN";
+       case IWI_FW_ERROR_DMA_STATUS:
+               return "DMA_STATUS";
+       case IWI_FW_ERROR_DINOSTATUS_ERROR:
+               return "DINOSTATUS_ERROR";
+       case IWI_FW_ERROR_EEPROMSTATUS_ERROR:
+               return "EEPROMSTATUS_ERROR";
+       case IWI_FW_ERROR_SYSASSERT:
+               return "SYSASSERT";
+       case IWI_FW_ERROR_FATAL_ERROR:
+               return "FATAL";
+       default:
+               return "UNKNOWN_ERROR";
+       }
+}
+
+static void
+iwi_dump_fw_event_log(struct iwi_softc *sc)
+{
+       u_int32_t ev, time, data, i, count, base;
+       base = CSR_READ_4(sc, IWI_FW_EVENT_LOG);
+       count = MEM_READ_4(sc, base);
+       if ( count > 0 && (sc->flags & IWI_FLAG_FW_INITED) ) {
+               printf("Reading %d event log entries from base address 0x%x.\n",
+                       count,  base);
+               if (IWI_FW_EVENT_START_OFFSET <= count * IWI_FW_EVENT_ELEM_SIZE)
+                       device_printf(sc->sc_dev,"Start IWI Event Log Dump:\n");
+               for (i = IWI_FW_EVENT_START_OFFSET;
+                               i <= count * IWI_FW_EVENT_ELEM_SIZE;
+                               i += IWI_FW_EVENT_ELEM_SIZE) {
+                       ev = MEM_READ_4(sc, base + i);
+                       time  = MEM_READ_4(sc, base + i + 1 * sizeof(u_int32_t));
+                       data  = MEM_READ_4(sc, base + i + 2 * sizeof(u_int32_t));
+                       printf("%d %8p %8.8d\n", time, (void *) data, ev);
+               }
+       } else {
+               printf("There are no entries in the firmware event log.\n");
+       }
+}
+
+static void
+iwi_dump_fw_error_log(struct iwi_softc *sc)
+{
+       u_int32_t i = 0;
+       int32_t count, base;
+       base = CSR_READ_4(sc, IWI_FW_ERROR_LOG);
+       count = MEM_READ_4(sc, base);
+       if ( count > 0 && (sc->flags & IWI_FLAG_FW_INITED) ) {
+               printf("Reading %d error log entries "
+                   "from base address 0x%p.\n", count,  (void *)base);
+               for ( i = IWI_FW_ERROR_START_OFFSET; 
+                       i <= count * IWI_FW_EVENT_ELEM_SIZE;
+                       i += IWI_FW_ERROR_ELEM_SIZE ) {
+                       u_int32_t elems;
+                       printf("%15.15s",
+                           iwi_error_desc(MEM_READ_4(sc, base + i)));
+                       printf(" time(%8.8d)", MEM_READ_4(sc, base + i + 4));
+                       for ( elems = 2 ; elems < 7 ; elems++ ) {
+                               printf(" %8p", (void *)
+                                   MEM_READ_4(sc, base + i + (4 * elems)));
+                       }
+                       printf("\n");
+               }
+       } 
+}
+
+static int
+iwi_sysctl_cts_to_self(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = (void *)arg1;
+       int cts_to_self = sc->enable_cts_to_self;
+       int error = sysctl_handle_int(oidp, &cts_to_self, 0, req);
+
+       (void)arg2; /* silence WARNS == 6 */
+
+       if ( !error && req->newptr && cts_to_self != sc->enable_cts_to_self ) {
+               switch ( cts_to_self ) {
+                       case -1: case 0: case 1:
+                               sc->enable_cts_to_self = cts_to_self;
+                               error = iwi_adapter_config(sc, 0, 0);
+                       break;
+               }
+       }
+       return error;
+}
+
+
+static int
+iwi_sysctl_antenna_diversity(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = (void *)arg1;
+       int antenna_diversity = sc->antenna_diversity;
+       int error = sysctl_handle_int(oidp, &antenna_diversity, 0, req);
+
+       (void)arg2; /* silence WARNS == 6 */
+
+       if ( !error && req->newptr && antenna_diversity != sc->antenna_diversity ) {
+               switch ( antenna_diversity ) {
+                       case 1: case 3: case 0: case -1:
+                               sc->antenna_diversity = antenna_diversity;
+                               error = iwi_adapter_config(sc, 0, 0);
+                       break;
+               }
+       }
+       return error;
+}
+
+static int
+iwi_sysctl_bg_autodetect(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = (void *)arg1;
+       int bg_autodetect = sc->enable_bg_autodetect;
+       int error = sysctl_handle_int(oidp, &bg_autodetect, 0, req);
+
+       (void)arg2; /* silence WARNS == 6 */
+
+       if ( !error && req->newptr && bg_autodetect != sc->enable_bg_autodetect ) {
+               switch ( bg_autodetect ) {
+                       case 1: case 0: case -1:
+                               sc->enable_bg_autodetect = bg_autodetect;
+                               error = iwi_adapter_config(sc, 0, 0);
+                       break;
+               }
+       }
+       return error;
+}
+
+static int
+iwi_sysctl_bt_coexist(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = (void *)arg1;
+       int bt_coexist = sc->enable_bt_coexist;
+       int error = sysctl_handle_int(oidp, &bt_coexist, 0, req);
+
+       (void)arg2; /* silence WARNS == 6 */
+
+       if ( !error && req->newptr && bt_coexist != sc->enable_bt_coexist ) {
+               switch ( bt_coexist ) {
+                       case 1: case 0: case -1:
+                               sc->enable_bt_coexist = bt_coexist;
+                               error = iwi_adapter_config(sc, 0, 0);
+                       break;
+               }
+       }
+       return error;
+}
+
+static int
+iwi_sysctl_dump_logs(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = arg1;
+       int result = -1;
+       int error = sysctl_handle_int(oidp, &result, 0, req);
+
+       (void)arg2; /* silence WARNS == 6 */
+
+       if (!error && req->newptr && result == 1) {
+               iwi_dump_fw_event_log(sc);
+               iwi_dump_fw_error_log(sc);
+       }
+       return error;
+}
+
+static int
+iwi_sysctl_stats(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = arg1;
+       u_int32_t size;
+       struct iwi_dump_buffer dump;
+
+       (void)arg2; /* silence WARNS == 6 */
+       (void)oidp; /* silence WARNS == 6 */
+
+       if (!(sc->flags & IWI_FLAG_FW_INITED)) {
+               bzero(dump.buf, sizeof dump.buf);
+               return SYSCTL_OUT(req, &dump, sizeof dump);
+       }
+
+       size = min(CSR_READ_4(sc, IWI_CSR_TABLE0_SIZE), 128 - 1);
+       CSR_READ_REGION_4(sc, IWI_CSR_TABLE0_BASE, &dump.buf[1], size);
+
+       return SYSCTL_OUT(req, &dump, sizeof dump);
+}
+
+static int
+iwi_sysctl_radio(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = arg1;
+       int val;
+
+       (void)arg2; /* silence WARNS == 6 */
+       (void)oidp; /* silence WARNS == 6 */
+
+       val = (CSR_READ_4(sc, IWI_CSR_IO) & IWI_IO_RADIO_ENABLED) ? 1 : 0;
+       return SYSCTL_OUT(req, &val, sizeof val);
+}
+
+static int
+iwi_sysctl_neg_best_rates_first(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = arg1;
+       int best_first = sc->enable_neg_best_first;
+       int error = sysctl_handle_int(oidp, &best_first, 0, req);
+
+       (void)arg2; /* silence WARNS == 6 */
+       (void)oidp; /* silence WARNS == 6 */
+
+       if ( !error && req->newptr && best_first != sc->enable_neg_best_first ) {
+               switch ( best_first ) {
+                       case 1: case 0: case -1:
+                               sc->enable_neg_best_first = best_first;
+                       break;
+               }
+       }
+       return error;
+}
+
+static int
+iwi_sysctl_disable_unicast_decryption(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = arg1;
+       int disable_uni = sc->disable_unicast_decryption;
+       int error = sysctl_handle_int(oidp, &disable_uni, 0, req);
+
+       (void)arg2; /* silence WARNS == 6 */
+       (void)oidp; /* silence WARNS == 6 */
+
+       if (!error && req->newptr && disable_uni != sc->disable_unicast_decryption) {
+               switch ( disable_uni ) {
+                       case 1: case 0: case -1:
+                               sc->disable_unicast_decryption = disable_uni;
+                       break;
+               }
+       }
+       return error;
+}
+
+static int
+iwi_sysctl_disable_multicast_decryption(SYSCTL_HANDLER_ARGS)
+{
+       struct iwi_softc *sc = arg1;
+       int disable_mul = sc->disable_multicast_decryption;
+       int error = sysctl_handle_int(oidp, &disable_mul, 0, req);
+
+       (void)arg2; /* silence WARNS == 6 */
+       (void)oidp; /* silence WARNS == 6 */
+
+       if (!error && req->newptr && disable_mul!=sc->disable_multicast_decryption){
+               switch ( disable_mul ) {
+                       case 1: case 0: case -1:
+                               sc->disable_multicast_decryption = disable_mul;
+                       break;
+               }
+       }
+       return error;
+}
+
+
diff --git a/sys/dev/netif/iwi/if_iwireg.h b/sys/dev/netif/iwi/if_iwireg.h
new file mode 100644 (file)
index 0000000..b5ba825
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 2004, 2005
+ *      Damien Bergamini <damien.bergamini@free.fr>.
+ * Copyright (c) 2004, 2005
+ *     Andrew Atrens <atrens@nortelnetworks.com>.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $DragonFly: src/sys/dev/netif/iwi/if_iwireg.h,v 1.1 2005/03/06 05:02:02 dillon Exp $
+ */
+
+#define IWI_TX_RING_SIZE       64
+#define IWI_CMD_RING_SIZE      16
+#define IWI_RX_RING_SIZE       32
+
+#define IWI_CSR_INTR           0x0008
+#define IWI_CSR_INTR_MASK      0x000c
+#define IWI_CSR_INDIRECT_ADDR  0x0010
+#define IWI_CSR_INDIRECT_DATA  0x0014
+#define IWI_CSR_AUTOINC_ADDR   0x0018
+#define IWI_CSR_AUTOINC_DATA   0x001c
+#define IWI_CSR_RST            0x0020
+#define IWI_CSR_CTL            0x0024
+#define IWI_CSR_IO             0x0030
+#define IWI_CSR_CMD_BASE       0x0200
+#define IWI_CSR_CMD_SIZE       0x0204
+#define IWI_CSR_TX1_BASE       0x0208
+#define IWI_CSR_TX1_SIZE       0x020c
+#define IWI_CSR_TX2_BASE       0x0210
+#define IWI_CSR_TX2_SIZE       0x0214
+#define IWI_CSR_TX3_BASE       0x0218
+#define IWI_CSR_TX3_SIZE       0x021c
+#define IWI_CSR_TX4_BASE       0x0220
+#define IWI_CSR_TX4_SIZE       0x0224
+#define IWI_CSR_CMD_READ_INDEX 0x0280
+#define IWI_CSR_TX1_READ_INDEX 0x0284
+#define IWI_CSR_TX2_READ_INDEX 0x0288
+#define IWI_CSR_TX3_READ_INDEX 0x028c
+#define IWI_CSR_TX4_READ_INDEX 0x0290
+#define IWI_CSR_RX_READ_INDEX  0x02a0
+#define IWI_CSR_RX_BASE                0x0500
+#define IWI_CSR_TABLE0_SIZE    0x0700
+#define IWI_CSR_TABLE0_BASE    0x0704
+#define IWI_CSR_CURRENT_TX_RATE        IWI_CSR_TABLE0_BASE
+
+#define IWI_CSR_GET_TABLE0_BASE 0x0380
+#define IWI_CSR_GET_TABLE1_BASE 0x0384
+#define IWI_CSR_GET_TABLE2_BASE 0x0388
+#define IWI_CSR_GET_TABLE3_BASE 0x038C
+
+#define IWI_CSR_CMD_WRITE_INDEX        0x0f80
+#define IWI_CSR_TX1_WRITE_INDEX        0x0f84
+#define IWI_CSR_TX2_WRITE_INDEX        0x0f88
+#define IWI_CSR_TX3_WRITE_INDEX        0x0f8c
+#define IWI_CSR_TX4_WRITE_INDEX        0x0f90
+#define IWI_CSR_RX_WRITE_INDEX 0x0fa0
+#define IWI_CSR_READ_INT       0x0ff4
+
+#define IWI_STATION_TABLE       0x0c0c
+
+#define IWI_FW_ERROR_LOG        0x0610
+#define IWI_FW_EVENT_LOG        0x0614
+
+
+/* possible flags for IWI_CSR_INTR */
+#define IWI_INTR_RX_TRANSFER   0x00000002
+#define IWI_INTR_STATUS_CHG     0x00000010
+#define IWI_INTR_BEACON_EXP     0x00000020
+#define IWI_INTR_CMD_TRANSFER  0x00000800
+#define IWI_INTR_TX1_TRANSFER  0x00001000
+#define IWI_INTR_TX2_TRANSFER  0x00002000
+#define IWI_INTR_TX3_TRANSFER  0x00004000
+#define IWI_INTR_TX4_TRANSFER  0x00008000
+#define IWI_INTR_SLMODE_CDONE   0x00010000
+#define IWI_INTR_PREP_PWDOWN    0x00100000
+#define IWI_INTR_PWDOWN         0x00200000
+#define IWI_INTR_FW_INITED     0x01000000
+#define IWI_INTR_DIS_PHY_DONE   0x02000000
+#define IWI_INTR_RADIO_OFF      0x04000000
+#define IWI_INTR_FATAL_ERROR   0x40000000
+#define IWI_INTR_PARITY_ERROR  0x80000000
+
+#define IWI_HANDLED_INTR_MASK                                          \
+       (IWI_INTR_RX_TRANSFER | IWI_INTR_CMD_TRANSFER |                 \
+        IWI_INTR_TX1_TRANSFER | IWI_INTR_TX2_TRANSFER |                \
+        IWI_INTR_TX3_TRANSFER | IWI_INTR_TX4_TRANSFER |                \
+        IWI_INTR_FW_INITED | IWI_INTR_FATAL_ERROR |                    \
+        IWI_INTR_RADIO_OFF | IWI_INTR_PARITY_ERROR)
+
+#define IWI_INTR_MASK                                                  \
+       (IWI_INTR_RX_TRANSFER | IWI_INTR_CMD_TRANSFER |                 \
+        IWI_INTR_TX1_TRANSFER | IWI_INTR_TX2_TRANSFER |                \
+        IWI_INTR_TX3_TRANSFER | IWI_INTR_TX4_TRANSFER |                \
+        IWI_INTR_FW_INITED | IWI_INTR_FATAL_ERROR |                    \
+        IWI_INTR_PARITY_ERROR | IWI_INTR_STATUS_CHG |                  \
+        IWI_INTR_BEACON_EXP | IWI_INTR_SLMODE_CDONE |                  \
+        IWI_INTR_PREP_PWDOWN | IWI_INTR_PWDOWN |                       \
+        IWI_INTR_DIS_PHY_DONE | IWI_INTR_RADIO_OFF)
+
+/* possible flags for register IWI_CSR_RST */
+#define IWI_RST_PRINCETON_RESET        0x00000001
+#define IWI_RST_SW_RESET       0x00000080
+#define IWI_RST_MASTER_DISABLED        0x00000100
+#define IWI_RST_STOP_MASTER    0x00000200
+
+/* possible flags for register IWI_CSR_CTL */
+#define IWI_CTL_CLOCK_READY    0x00000001
+#define IWI_CTL_ALLOW_STANDBY  0x00000002
+#define IWI_CTL_INIT           0x00000004
+
+/* possible flags for register IWI_CSR_IO */
+#define IWI_IO_RADIO_ENABLED   0x00010000
+
+/* possible flags for IWI_CSR_READ_INT */
+#define IWI_READ_INT_INIT_HOST 0x20000000
+
+/* table2 offsets */
+#define IWI_INFO_ADAPTER_MAC   40
+
+/* constants for command blocks */
+#define IWI_CB_DEFAULT_CTL     0x8cea0000
+#define IWI_CB_MAXDATALEN      8191
+
+/* supported rates */
+#define IWI_RATE_DS1   10
+#define IWI_RATE_DS2   20
+#define IWI_RATE_DS5   55
+#define IWI_RATE_DS11  110
+#define IWI_RATE_OFDM6 13
+#define IWI_RATE_OFDM9 15
+#define IWI_RATE_OFDM12        5
+#define IWI_RATE_OFDM18        7
+#define IWI_RATE_OFDM24        9
+#define IWI_RATE_OFDM36        11
+#define IWI_RATE_OFDM48        1
+#define IWI_RATE_OFDM54        3
+
+struct iwi_hdr {
+       u_int8_t        type;
+#define IWI_HDR_TYPE_DATA      0
+#define IWI_HDR_TYPE_COMMAND   1
+#define IWI_HDR_TYPE_NOTIF     3
+#define IWI_HDR_TYPE_FRAME     9
+       u_int8_t        seq;
+       u_int8_t        flags;
+#define IWI_HDR_FLAG_IRQ       0x04
+       u_int8_t        reserved;
+} __packed;
+
+struct iwi_notif {
+       u_int32_t       reserved[2];
+       u_int8_t        type;
+#define IWI_NOTIF_TYPE_ASSOCIATION     10
+#define IWI_NOTIF_TYPE_AUTHENTICATION  11
+#define IWI_NOTIF_TYPE_SCAN_CHANNEL    12
+#define IWI_NOTIF_TYPE_SCAN_COMPLETE   13
+#define IWI_NOTIF_TYPE_BEACON          17
+#define IWI_NOTIF_TYPE_CALIBRATION     20
+#define IWI_NOTIF_TYPE_NOISE           25
+       u_int8_t        flags;
+       u_int16_t       len;
+} __packed;
+
+/* structure for notification IWI_NOTIF_TYPE_NOISE */
+struct iwi_notif_noise {
+       u_int32_t       value;
+} __packed;
+
+/* structure for notification IWI_NOTIF_TYPE_AUTHENTICATION */
+struct iwi_notif_authentication {
+       u_int8_t        state;
+#define IWI_DEAUTHENTICATED    0
+#define IWI_AUTHENTICATED      9
+} __packed;
+
+/* structure for notification IWI_NOTIF_TYPE_ASSOCIATION */
+struct iwi_notif_association {
+       u_int8_t                state;
+#define IWI_DEASSOCIATED       0
+#define IWI_ASSOCIATED         12
+       struct ieee80211_frame  frame;
+       u_int16_t               capinfo;
+       u_int16_t               status;
+       u_int16_t               associd;
+} __packed;
+
+/* structure for notification IWI_NOTIF_TYPE_SCAN_CHANNEL */
+struct iwi_notif_scan_channel {
+       u_int8_t        nchan;
+       u_int8_t        reserved[47];
+} __packed;
+
+/* structure for notification IWI_NOTIF_TYPE_SCAN_COMPLETE */
+struct iwi_notif_scan_complete {
+       u_int8_t        type;
+       u_int8_t        nchan;
+       u_int8_t        status;
+       u_int8_t        reserved;
+} __packed;
+
+/* received frame header */
+struct iwi_frame {
+       u_int32_t       reserved1;
+       u_int8_t        parent_tsf[4];
+       u_int8_t        chan;
+       u_int8_t        status;
+       u_int8_t        rate;
+       u_int8_t        rssi;   /* receiver signal strength indicator */
+       u_int8_t        agc;    /* automatic gain control */
+       u_int8_t        rssi_dbm;
+       u_int16_t       signal;
+       u_int16_t       noise;
+       u_int8_t        antenna;
+       u_int8_t        control;
+       u_int8_t        rtscts_rate;
+       u_int8_t        rtscts_seen;
+       u_int16_t       len;
+} __packed;
+
+/* header for transmission */
+struct iwi_tx_desc {
+       struct iwi_hdr  hdr;
+       u_int32_t       work_area_ptr;
+       u_int8_t        station_number; /* 0 for BSS */
+       u_int8_t        reserved1[3];
+       u_int8_t        cmd;
+#define IWI_DATA_CMD_TX        0x0b
+       u_int8_t        seq;
+       u_int16_t       len;
+       u_int8_t        priority;
+       u_int8_t        flags;
+#define IWI_DATA_FLAG_SHPREAMBLE       0x04
+#define IWI_DATA_FLAG_NO_WEP           0x20
+#define IWI_DATA_FLAG_NEED_ACK         0x80
+       u_int8_t        xflags;
+       u_int8_t        wep_txkey;
+       u_int8_t        wepkey[IEEE80211_KEYBUF_SIZE];
+       u_int8_t        rate;
+       u_int8_t        antenna;
+       u_int8_t        reserved2[10];
+
+       struct ieee80211_qosframe_addr4 wh;
+       u_int32_t       iv[2];
+
+       u_int32_t       nseg;
+#define IWI_MAX_NSEG   6
+       u_int32_t       seg_addr[IWI_MAX_NSEG];
+       u_int16_t       seg_len[IWI_MAX_NSEG];
+} __packed;
+
+/* command */
+struct iwi_cmd_desc {
+       struct iwi_hdr  hdr;
+       u_int8_t        type;
+#define IWI_CMD_ENABLE                         2
+#define IWI_CMD_SET_CONFIGURATION              6
+#define IWI_CMD_SET_ESSID                      8
+#define IWI_CMD_SET_MAC_ADDRESS                        11
+#define IWI_CMD_SET_RTS_THRESHOLD              15
+#define IWI_CMD_SET_POWER_MODE                 17
+#define IWI_CMD_SET_WEP_KEY                    18
+#define IWI_CMD_SCAN                           20
+#define IWI_CMD_ASSOCIATE                      21
+#define IWI_CMD_SET_RATES                      22
+#define IWI_CMD_SCAN_ABORT                     23
+#define IWI_CMD_DISABLE                                33
+#define IWI_CMD_SET_IV                         34
+#define IWI_CMD_SET_TX_POWER                   35
+#define IWI_CMD_SET_SENSITIVITY                        42
+       u_int8_t        len;
+       u_int16_t       reserved;
+       u_int8_t        data[120];
+} __packed;
+
+/* constants for 'mode' fields */
+#define IWI_MODE_11A   0
+#define IWI_MODE_11B   1
+#define IWI_MODE_11G   2
+
+/* macro for command IWI_CMD_SET_SENSITIVITY */
+#define IWI_RSSIDBM2RAW(rssi)  ((rssi) - 112)
+
+/* possible values for command IWI_CMD_SET_POWER_MODE */
+#define IWI_POWER_MODE_CAM     0
+
+/* structure for command IWI_CMD_SET_RATES */
+struct iwi_rateset {
+       u_int8_t        mode;
+       u_int8_t        nrates;
+       u_int8_t        type;
+#define IWI_RATESET_TYPE_NEGOTIATED    0
+#define IWI_RATESET_TYPE_SUPPORTED     1
+       u_int8_t        reserved;
+       u_int8_t        rates[12];
+} __packed;
+
+/* structure for command IWI_CMD_SET_TX_POWER */
+struct iwi_txpower {
+       u_int8_t        nchan;
+       u_int8_t        mode;
+       struct {
+               u_int8_t        chan;
+               u_int8_t        power;
+#define IWI_TXPOWER_MAX                20
+#define IWI_TXPOWER_RATIO      (IEEE80211_TXPOWER_MAX / IWI_TXPOWER_MAX)
+       } __packed chan[37];
+} __packed;
+
+/* structure for command IWI_CMD_ASSOCIATE */
+struct iwi_associate {
+       u_int8_t        chan;
+       u_int8_t        auth;
+#define IWI_AUTH_OPEN  0
+#define IWI_AUTH_SHARED        1
+#define IWI_AUTH_NONE  3
+       u_int8_t        type;
+       u_int8_t        reserved;
+       u_int16_t       policy_support;
+       u_int8_t        plen;
+       u_int8_t        mode;
+       u_int8_t        bssid[IEEE80211_ADDR_LEN];
+       u_int8_t        tstamp[8];
+       u_int16_t       capinfo;
+       u_int16_t       lintval;
+       u_int16_t       intval;
+       u_int8_t        dst[IEEE80211_ADDR_LEN];
+       u_int16_t       atim_window;
+       u_int8_t        smr;
+       u_int8_t        reserved1;
+       u_int16_t       reserved2;
+} __packed;
+
+/* structure for command IWI_CMD_SCAN */
+struct iwi_scan {
+       u_int8_t        type;
+#define IWI_SCAN_PASSIVE_TILL_FIRST_BEACON     0
+#define IWI_SCAN_PASSIVE_FULL_DWELL            1
+#define IWI_SCAN_TYPE_DIRECT                   2
+#define IWI_SCAN_TYPE_BROADCAST                        3
+#define IWI_SCAN_TYPE_BROADCAST_AND_DIRECT     4
+       u_int16_t       intval;
+       u_int8_t        channels[54];
+#define IWI_CHAN_5GHZ  (0 << 6)
+#define IWI_CHAN_2GHZ  (1 << 6)
+       u_int8_t        reserved[3];
+} __packed;
+
+/* structure for command IWI_CMD_SET_CONFIGURATION */
+struct iwi_configuration {
+       u_int8_t        bluetooth_coexistence;
+       u_int8_t        reserved1;
+       u_int8_t        answer_broadcast_probe_req;
+       u_int8_t        allow_invalid_frames;
+       u_int8_t        enable_multicast;
+       u_int8_t        exclude_unicast_unencrypted;
+       u_int8_t        disable_unicast_decryption;
+       u_int8_t        exclude_multicast_unencrypted;
+       u_int8_t        disable_multicast_decryption;
+       u_int8_t        antenna_diversity;
+       u_int8_t        pass_crc_to_host;
+       u_int8_t        bg_autodetect;
+       u_int8_t        enable_cts_to_self;
+       u_int8_t        enable_multicast_filtering;
+       u_int8_t        bluetooth_threshold;
+       u_int8_t        reserved2;
+       u_int8_t        allow_beacon_and_probe_resp;
+       u_int8_t        allow_mgt;
+       u_int8_t        noise_reported;
+       u_int8_t        reserved3;
+} __packed;
+
+/* structure for command IWI_CMD_SET_WEP_KEY */
+struct iwi_wep_key {
+       u_int8_t        cmd;
+#define IWI_WEP_KEY_CMD_SETKEY 0x08
+       u_int8_t        seq;
+       u_int8_t        idx;
+       u_int8_t        len;
+       u_int8_t        key[IEEE80211_KEYBUF_SIZE];
+} __packed;
+
+/* EEPROM = Electrically Erasable Programmable Read-Only Memory */
+
+#define IWI_MEM_EEPROM_CTL     0x00300040
+
+#define IWI_EEPROM_MAC 0x21
+
+#define IWI_EEPROM_DELAY       1       /* minimum hold time (microsecond) */
+
+#define IWI_EEPROM_C       (1 << 0)        /* Serial Clock */
+#define IWI_EEPROM_S       (1 << 1)        /* Chip Select */
+#define IWI_EEPROM_D       (1 << 2)        /* Serial data input */
+#define IWI_EEPROM_Q       (1 << 4)        /* Serial data output */
+
+#define IWI_EEPROM_SHIFT_D    2
+#define IWI_EEPROM_SHIFT_Q    4
+
+/*
+ * control and status registers access macros
+ */
+#define CSR_READ_1(sc, reg)                                            \
+       bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg))
+
+#define CSR_READ_2(sc, reg)                                            \
+       bus_space_read_2((sc)->sc_st, (sc)->sc_sh, (reg))
+
+#define CSR_READ_4(sc, reg)                                            \
+       bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
+
+#define CSR_READ_REGION_4(sc, offset, datap, count)                    \
+       bus_space_read_region_4((sc)->sc_st, (sc)->sc_sh, (offset),     \
+           (datap), (count))
+
+#define CSR_WRITE_1(sc, reg, val)                                      \
+       bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+
+#define CSR_WRITE_2(sc, reg, val)                                      \
+       bus_space_write_2((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+
+#define CSR_WRITE_4(sc, reg, val)                                      \
+       bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+
+/*
+ * indirect memory space access macros
+ */
+#define MEM_WRITE_1(sc, addr, val) do {                                        \
+       CSR_WRITE_4((sc), IWI_CSR_INDIRECT_ADDR, (addr));               \
+       CSR_WRITE_1((sc), IWI_CSR_INDIRECT_DATA, (val));                \
+} while (/* CONSTCOND */0)
+
+#define MEM_WRITE_2(sc, addr, val) do {                                        \
+       CSR_WRITE_4((sc), IWI_CSR_INDIRECT_ADDR, (addr));               \
+       CSR_WRITE_2((sc), IWI_CSR_INDIRECT_DATA, (val));                \
+} while (/* CONSTCOND */0)
+
+#define MEM_WRITE_4(sc, addr, val) do {                                        \
+       CSR_WRITE_4((sc), IWI_CSR_INDIRECT_ADDR, (addr));               \
+       CSR_WRITE_4((sc), IWI_CSR_INDIRECT_DATA, (val));                \
+} while (/* CONSTCOND */0)
+
+#define MEM_WRITE_MULTI_1(sc, addr, buf, len) do {                     \
+       CSR_WRITE_4((sc), IWI_CSR_INDIRECT_ADDR, (addr));               \
+       CSR_WRITE_MULTI_1((sc), IWI_CSR_INDIRECT_DATA, (buf), (len));   \
+} while (/* CONSTCOND */0)
+
+
+#define IWI_FW_ERROR_OK                        0
+#define IWI_FW_ERROR_FAIL                      1
+#define IWI_FW_ERROR_MEMORY_UNDERFLOW          2
+#define IWI_FW_ERROR_MEMORY_OVERFLOW           3
+#define IWI_FW_ERROR_BAD_PARAM                 4
+#define IWI_FW_ERROR_BAD_CHECKSUM              5
+#define IWI_FW_ERROR_NMI_INTERRUPT             6
+#define IWI_FW_ERROR_BAD_DATABASE              7
+#define IWI_FW_ERROR_ALLOC_FAIL                        8
+#define IWI_FW_ERROR_DMA_UNDERRUN              9
+#define IWI_FW_ERROR_DMA_STATUS                        10
+#define IWI_FW_ERROR_DINOSTATUS_ERROR          11
+#define IWI_FW_ERROR_EEPROMSTATUS_ERROR                12
+#define IWI_FW_ERROR_SYSASSERT                 13
+#define IWI_FW_ERROR_FATAL_ERROR               14
+
+
+#define IWI_FW_EVENT_ELEM_SIZE         (3 * sizeof(u_int32_t))
+#define IWI_FW_EVENT_START_OFFSET       (sizeof(u_int32_t) + 2 * sizeof(u_int16_t))
+#define IWI_FW_ERROR_ELEM_SIZE         (7 * sizeof(u_int32_t))
+#define IWI_FW_ERROR_START_OFFSET      (1 * sizeof(u_int32_t))
+
+
+#define IWI_FW_MAX_STATIONS 32
+
+struct iwi_fw_station {
+       u_int8_t mac[ETHER_ADDR_LEN];
+       u_int8_t reserved;
+       u_int8_t support_mode;
+} __packed;
+
+
+
+/*
+ * EEPROM access macro
+ */
+#define IWI_EEPROM_CTL(sc, val) do {                                   \
+       MEM_WRITE_4((sc), IWI_MEM_EEPROM_CTL, (val));                   \
+       DELAY(IWI_EEPROM_DELAY);                                        \
+} while (/* CONSTCOND */0)
diff --git a/sys/dev/netif/iwi/if_iwivar.h b/sys/dev/netif/iwi/if_iwivar.h
new file mode 100644 (file)
index 0000000..18fc4fd
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2004, 2005
+ *      Damien Bergamini <damien.bergamini@free.fr>.
+ * Copyright (c) 2004, 2005
+ *     Andrew Atrens <atrens@nortelnetworks.com>.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $DragonFly: src/sys/dev/netif/iwi/if_iwivar.h,v 1.1 2005/03/06 05:02:02 dillon Exp $
+ */
+
+struct iwi_firmware {
+       void    *boot;
+       int     boot_size;
+       void    *ucode;
+       int     ucode_size;
+       void    *main;
+       int     main_size;
+};
+
+struct iwi_rx_radiotap_header {
+       struct ieee80211_radiotap_header wr_ihdr;
+       u_int8_t        wr_flags;
+       u_int8_t        wr_rate;
+       u_int16_t       wr_chan_freq;
+       u_int16_t       wr_chan_flags;
+       u_int8_t        wr_antsignal;
+       u_int8_t        wr_antnoise;
+       u_int8_t        wr_antenna;
+};
+
+#define IWI_RX_RADIOTAP_PRESENT                                                \
+       ((1 << IEEE80211_RADIOTAP_FLAGS) |                              \
+        (1 << IEEE80211_RADIOTAP_RATE) |                               \
+        (1 << IEEE80211_RADIOTAP_CHANNEL) |                            \
+        (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |                       \
+        (1 << IEEE80211_RADIOTAP_DB_ANTNOISE) |                        \
+        (1 << IEEE80211_RADIOTAP_ANTENNA))
+
+struct iwi_tx_radiotap_header {
+       struct ieee80211_radiotap_header wt_ihdr;
+       u_int8_t        wt_flags;
+       u_int16_t       wt_chan_freq;
+       u_int16_t       wt_chan_flags;
+};
+
+#define IWI_TX_RADIOTAP_PRESENT                                                \
+       ((1 << IEEE80211_RADIOTAP_FLAGS) |                              \
+        (1 << IEEE80211_RADIOTAP_CHANNEL))
+
+struct iwi_softc {
+       struct ieee80211com     sc_ic;
+       int                     (*sc_newstate)(struct ieee80211com *,
+                                   enum ieee80211_state, int);
+       device_t                sc_dev;
+
+
+       struct iwi_firmware     fw;
+       u_int32_t               flags;
+#define IWI_FLAG_FW_CACHED     (1 << 0)
+#define IWI_FLAG_FW_IBSS       (1 << 1)
+#define IWI_FLAG_FW_INITED     (1 << 2)
+#define IWI_FLAG_SCANNING       (1 << 3)
+#define IWI_FLAG_SCAN_COMPLETE  (1 << 4)
+#define IWI_FLAG_SCAN_ABORT     (1 << 5)
+#define IWI_FLAG_ASSOCIATED     (1 << 6)
+#define IWI_FLAG_RF_DISABLED    (1 << 7)
+#define IWI_FLAG_RESET          (1 << 8)
+#define IWI_FLAG_EXIT           (1 << 9)
+
+       struct iwi_tx_desc      *tx_desc;
+       bus_dma_tag_t           iwi_parent_tag;
+       bus_dma_tag_t           tx_ring_dmat;
+       bus_dmamap_t            tx_ring_map;
+       bus_addr_t              tx_ring_pa;
+       bus_dma_tag_t           tx_buf_dmat;
+
+       struct iwi_tx_buf {
+               bus_dmamap_t            map;
+               struct mbuf             *m;
+               struct ieee80211_node   *ni;
+       } tx_buf[IWI_TX_RING_SIZE];
+
+       int                     tx_cur;
+       int                     tx_old;
+       int                     tx_queued;
+
+       struct iwi_cmd_desc     *cmd_desc;
+       bus_dma_tag_t           cmd_ring_dmat;
+       bus_dmamap_t            cmd_ring_map;
+       bus_addr_t              cmd_ring_pa;
+       int                     cmd_cur;
+
+       bus_dma_tag_t           rx_buf_dmat;
+
+       struct iwi_rx_buf {
+               bus_dmamap_t    map;
+               bus_addr_t      physaddr;
+               struct mbuf     *m;
+       } rx_buf[IWI_RX_RING_SIZE];
+
+       int                     rx_cur;
+
+       struct resource         *irq;
+       struct resource         *mem;
+       bus_space_tag_t         sc_st;
+       bus_space_handle_t      sc_sh;
+       void                    *sc_ih;
+
+       int                     authmode;
+
+       int                     sc_tx_timer;
+
+#if NBPFILTER > 0
+       struct bpf_if           *sc_drvbpf;
+
+       union {
+               struct iwi_rx_radiotap_header th;
+               u_int8_t        pad[64];
+       } sc_rxtapu;
+#define sc_rxtap       sc_rxtapu.th
+       int                     sc_rxtap_len;
+
+       union {
+               struct iwi_tx_radiotap_header th;
+               u_int8_t        pad[64];
+       } sc_txtapu;
+#define sc_txtap       sc_txtapu.th
+       int                     sc_txtap_len;
+#endif
+       int                     num_stations;
+       u_int8_t                stations[IWI_FW_MAX_STATIONS][ETHER_ADDR_LEN];
+
+       struct lwkt_token       sc_lock;
+       struct lwkt_token       sc_intrlock;
+
+       struct sysctl_ctx_list  sysctl_ctx;
+       struct sysctl_oid       *sysctl_tree;
+
+       int                     debug_level;
+
+       int                     enable_bg_autodetect;
+       int                     enable_bt_coexist;
+       int                     enable_cts_to_self;
+       int                     antenna_diversity; /* 1 = A, 3 = B, 0 = A + B */
+       int                     enable_neg_best_first;
+       int                     disable_unicast_decryption;
+       int                     disable_multicast_decryption;
+
+       struct thread           *event_thread;
+
+       struct iwi_associate    assoc;
+
+       int                     scan_counter;
+
+};
+
+#define SIOCSLOADFW     _IOW('i', 137, struct ifreq)
+#define SIOCSLOADIBSSFW         _IOW('i', 138, struct ifreq)
+#define SIOCSKILLFW     _IOW('i', 139, struct ifreq)
+
+#define IWI_LOCK_INIT(tok)     lwkt_token_init(tok)
+#define IWI_LOCK_DESTROY(tok)  lwkt_token_uninit(tok)
+
+#define IWI_LOCK_INFO          struct lwkt_tokref tokinfo
+#define IWI_INTRLOCK_INFO      struct lwkt_tokref intrtokinfo
+#define IWI_INTRLOCK(_sc)      lwkt_gettoken(&intrtokinfo,(&(_sc)->sc_intrlock))
+#define IWI_INTRUNLOCK(SC)     lwkt_reltoken(&intrtokinfo)
+#define IWI_LOCK(_sc)          lwkt_gettoken(&tokinfo,&((_sc)->sc_lock))
+#define IWI_UNLOCK(SC)         lwkt_reltoken(&tokinfo)
+
+/*
+ * Holding a token is not enough for iwi_tx_start() the DMA send
+ * routine. Revert back to the old ipl mechanism for now.
+ */
+
+#define IWI_IPLLOCK_INFO       int saved_ipl_level
+#define IWI_IPLLOCK(_sc)       saved_ipl_level =  splimp()
+#define IWI_IPLUNLOCK(_sc)     splx(saved_ipl_level)
+
+/* tsleepable events */
+#define IWI_FW_WAKE_MONITOR(sc)      (sc + 1)
+#define IWI_FW_INITIALIZED(sc)       (sc + 2)
+#define IWI_FW_CMD_ACKED(sc)         (sc + 3)
+#define IWI_FW_SCAN_COMPLETED(sc)    (sc + 4)
+#define IWI_FW_DEASSOCIATED(sc)      (sc + 5)
+#define IWI_FW_MON_EXIT(sc)          (sc + 6)
+
index b90fed7..2b8a8fe 100644 (file)
@@ -1,6 +1,6 @@
 #      From: @(#)Makefile      5.20 (Berkeley) 6/12/93
 # $FreeBSD: src/usr.sbin/Makefile,v 1.183.2.14 2003/04/16 11:01:51 ru Exp $
-# $DragonFly: src/usr.sbin/Makefile,v 1.21 2005/02/19 01:46:12 swildner Exp $
+# $DragonFly: src/usr.sbin/Makefile,v 1.22 2005/03/06 05:01:53 dillon Exp $
 
 # XXX MISSING:         mkproto
 SUBDIR=        IPXrouted \
@@ -40,6 +40,7 @@ SUBDIR=       IPXrouted \
        ifmcstat \
        inetd \
        iostat \
+       iwicontrol \
        jail \
        jexec \
        jls \
diff --git a/usr.sbin/iwicontrol/Makefile b/usr.sbin/iwicontrol/Makefile
new file mode 100644 (file)
index 0000000..6091c6f
--- /dev/null
@@ -0,0 +1,8 @@
+# $DragonFly: src/usr.sbin/iwicontrol/Makefile,v 1.1 2005/03/06 05:02:03 dillon Exp $
+#
+PROG   = iwicontrol
+MAN    = iwicontrol.8
+
+WARNS?= 6
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/iwicontrol/iwicontrol.8 b/usr.sbin/iwicontrol/iwicontrol.8
new file mode 100644 (file)
index 0000000..ca5e52d
--- /dev/null
@@ -0,0 +1,102 @@
+.\"
+.\" Copyright (c) 2004, 2005
+.\"    Damien Bergamini <damien.bergamini@free.fr>.
+.\"    Andrew Atrens <atrens@nortelnetworks.com>.
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice unmodified, 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 AUTHOR 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 AUTHOR 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.
+.\"
+.\" $DragonFly: src/usr.sbin/iwicontrol/iwicontrol.8,v 1.1 2005/03/06 05:02:03 dillon Exp $
+.\"
+.Dd September 26, 2004
+.Os
+.Dt IWICONTROL 8
+.Sh NAME
+.Nm iwicontrol
+.Nd configure Intel(R) PRO/Wireless 2200BG/2915ABG network adapters
+.Sh SYNOPSIS
+.Nm
+.Op Fl i
+.Ar iface
+.Nm
+.Op Fl i
+.Ar iface Fl d Ar directory
+.Op Fl m Ar bss|ibss
+.Nm
+.Op Fl i
+.Ar iface Fl k
+(kill firmware)
+.Nm
+.Op Fl i
+.Ar iface Fl r
+(display radio transmitter state)
+.Nm
+.Op Fl i
+.Ar iface Fl D
+(dump firmware event and error logs)
+.Sh DESCRIPTION
+The
+.Nm
+utility controls the operation of Intel(R) PRO/Wireless 2200BG/2915ABG
+networking devices via
+.Xr iwi 4
+driver.
+.Pp
+You should not use this program to configure IEEE 802.11 parameters. Use
+.Xr ifconfig 8
+instead.
+.Sh OPTIONS
+The options are as follows:
+.Bl -tag -width indent
+.It Oo Fl i Oc Ar iface
+Displays adapter's internal statistics.
+.It Oo Fl i Oc Ar iface Fl d Ar directory Oo Fl m Ar bss|ibss Oc
+Download firmware binary image to the adapter. The image is read from the
+.Ar directory
+directory. By default, the firmware binary image for BSS (aka infrastructure
+mode) mode is downloaded unless the
+.Fl m
+flag is given.
+.It Oo Fl i Oc Ar iface Fl k
+Kill the firmware and reset the adapter.
+.It Oo Fl i Oc Ar iface Fl r
+Displays the radio transmitter state (on or off).
+.It Oo Fl i Oc Ar iface Fl D
+Dumps the contents of the firmware event and error logs. Information is
+mostly in hexadecimal form and as such isn't overly useful (yet).
+.El
+.Sh SEE ALSO
+.Xr iwi 4 ,
+.Xr ifconfig 8
+.Sh AUTHORS
+The
+.Nm
+utility and this man page were written by
+.An Damien Bergamini Aq damien.bergamini@free.fr .
+.Pp
+The not-so-useful-yet
+.Fl D
+option and its write up were added by 
+.An Andrew Atrens Aq atrens@nortelnetworks.com .
+
diff --git a/usr.sbin/iwicontrol/iwicontrol.c b/usr.sbin/iwicontrol/iwicontrol.c
new file mode 100644 (file)
index 0000000..78fae47
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2004, 2005
+ *     Damien Bergamini <damien.bergamini@free.fr>.
+ * Copyright (c) 2004, 2005
+ *     Andrew Atrens <atrens@nortelnetworks.com>.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $DragonFly: src/usr.sbin/iwicontrol/iwicontrol.c,v 1.1 2005/03/06 05:02:03 dillon Exp $
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#define SIOCSLOADFW     _IOW('i', 137, struct ifreq)
+#define SIOCSLOADIBSSFW         _IOW('i', 138, struct ifreq)
+#define SIOCSKILLFW     _IOW('i', 139, struct ifreq)
+
+struct firmware {
+       char    *boot;
+       int     boot_size;
+       char    *ucode;
+       int     ucode_size;
+       char    *main;
+       int     main_size;
+};
+
+struct header {
+       u_int32_t       version;
+       u_int32_t       mode;
+} __attribute__((__packed__));
+
+static void usage(void);
+static int do_req(const char *, unsigned long, void *);
+static void mmap_file(const char *, char **, size_t *);
+static void load_firmware(const char *, const char *, const char *);
+static void kill_firmware(const char *);
+static void get_radio_state(const char *);
+static void get_statistics(const char *);
+static void dump_debug(const char *);
+
+int
+main(int argc, char **argv)
+{
+       int ch;
+       const char *iface = NULL, *mode = "bss", *path = NULL;
+       int noflag = 1, kflag = 0, rflag = 0, dflag = 0;
+
+       if (argc > 1 && argv[1][0] != '-') {
+               iface = argv[1];
+               optind++;
+       }
+
+       while ((ch = getopt(argc, argv, "d:i:km:rD")) != -1) {
+               if (ch != 'i')
+                       noflag = 0;
+
+               switch (ch) {
+               case 'd':
+                       path = optarg;
+                       break;
+
+               case 'i':
+                       iface = optarg;
+                       break;
+
+               case 'k':
+                       kflag = 1;
+                       break;
+
+               case 'm':
+                       mode = optarg;
+                       break;
+
+               case 'r':
+                       rflag = 1;
+                       break;
+
+               case 'D':
+                       dflag = 1;
+                       break;
+
+               default:
+                       usage();
+               }
+       }
+
+       if (iface == NULL)
+               usage();
+
+       if (kflag && (path != NULL || rflag))
+               usage();
+
+       if (kflag)
+               kill_firmware(iface);
+
+       if (path != NULL)
+               load_firmware(iface, path, mode);
+
+       if (rflag)
+               get_radio_state(iface);
+
+       if (dflag)
+               dump_debug(iface);
+
+       if (noflag)
+               get_statistics(iface);
+
+       return EX_OK;
+}
+
+extern char *__progname;
+
+static void
+usage(void)
+{
+       (void)fprintf(stderr, "usage:  %s iface\n"
+           "\t%s iface -d path [-m bss|ibss]\n"
+           "\t%s iface -k\n"
+           "\t%s iface -r\n", __progname, __progname, __progname,
+           __progname);
+
+       exit(EX_USAGE);
+}
+
+static int
+do_req(const char *iface, unsigned long req, void *data)
+{
+       int s;
+       struct ifreq ifr;
+       int error;
+
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+               err(EX_OSERR, "Can't create socket");
+
+       (void)memset(&ifr, 0, sizeof ifr);
+       (void)strncpy(ifr.ifr_name, iface, sizeof ifr.ifr_name);
+       ifr.ifr_data = data;
+       error = ioctl(s, req, &ifr);
+
+       (void)close(s);
+
+       return error;
+}
+
+static void
+mmap_file(const char *filename, char **addr, size_t *len)
+{
+       int fd;
+       struct stat st;
+
+       if ((fd = open(filename, O_RDONLY)) == -1)
+               err(EX_OSERR, "%s", filename);
+
+       if (fstat(fd, &st) == -1)
+               err(EX_OSERR, "Unable to stat %s", filename);
+
+       *len = st.st_size;
+
+       if ((*addr = mmap(NULL, st.st_size, PROT_READ, 0, fd, 0)) == NULL)
+               err(EX_OSERR, "Can't map %s into memory", filename);
+
+       *addr += sizeof (struct header);
+       *len -= sizeof (struct header);
+
+       (void)close(fd);
+}
+
+static void
+load_firmware(const char *iface, const char *path, const char *mode)
+{
+       char filename[FILENAME_MAX];
+       struct firmware fw;
+
+       (void)snprintf(filename, sizeof filename, "%s/iwi-boot.fw", path);
+       mmap_file(filename, &fw.boot, &fw.boot_size);
+
+       (void)snprintf(filename, sizeof filename, "%s/iwi-ucode-%s.fw", path,
+           mode);
+       mmap_file(filename, &fw.ucode, &fw.ucode_size);
+
+       (void)snprintf(filename, sizeof filename, "%s/iwi-%s.fw", path, mode);
+       mmap_file(filename, &fw.main, &fw.main_size);
+
+       if (do_req(iface, strstr(mode,"ibss") 
+                           ? SIOCSLOADIBSSFW : SIOCSLOADFW, &fw) == -1)
+               err(EX_OSERR, "Can't load firmware to driver");
+}
+
+static void
+kill_firmware(const char *iface)
+{
+       if (do_req(iface, SIOCSKILLFW, NULL) == -1)
+               err(EX_OSERR, "Can't kill firmware");
+}
+
+static void
+dump_debug(const char *iface)
+{
+       int dump = 1, len = sizeof dump;
+       char oid_name[128];
+       snprintf(oid_name, sizeof oid_name, "hw.%s.firmware_logs", iface );
+       if (sysctlbyname(oid_name, 0, 0, &dump, len) == -1)
+               err(EX_OSERR, "Can't dump firmware logs");
+       (void)printf("All firmware logs dumped.\n");
+}
+
+
+static void
+get_radio_state(const char *iface)
+{
+       int radio, len;
+       char oid_name[128];
+
+       snprintf(oid_name, sizeof oid_name, "hw.%s.radio", iface );
+       len = sizeof radio;
+       if (sysctlbyname(oid_name, &radio, &len, NULL, 0) == -1)
+               err(EX_OSERR, "Can't get radio transmitter state");
+
+       (void)printf("Radio is %s\n", radio ? "ON" : "OFF");
+}
+
+struct statistic {
+       int             index;
+       const char      *desc;
+};
+
+static const struct statistic tbl[] = {
+       {  1, "Current transmission rate" },
+       {  2, "Fragmentation threshold" },
+       {  3, "RTS threshold" },
+       {  4, "Number of frames submitted for transfer" },
+       {  5, "Number of frames transmitted" },
+       {  6, "Number of unicast frames transmitted" },
+       {  7, "Number of unicast 802.11b frames transmitted at 1Mb/s" },
+       {  8, "Number of unicast 802.11b frames transmitted at 2Mb/s" },
+       {  9, "Number of unicast 802.11b frames transmitted at 5.5Mb/s" },
+       { 10, "Number of unicast 802.11b frames transmitted at 11Mb/s" },
+
+       { 19, "Number of unicast 802.11g frames transmitted at 1Mb/s" },
+       { 20, "Number of unicast 802.11g frames transmitted at 2Mb/s" },
+       { 21, "Number of unicast 802.11g frames transmitted at 5.5Mb/s" },
+       { 22, "Number of unicast 802.11g frames transmitted at 6Mb/s" },
+       { 23, "Number of unicast 802.11g frames transmitted at 9Mb/s" },
+       { 24, "Number of unicast 802.11g frames transmitted at 11Mb/s" },
+       { 25, "Number of unicast 802.11g frames transmitted at 12Mb/s" },
+       { 26, "Number of unicast 802.11g frames transmitted at 18Mb/s" },
+       { 27, "Number of unicast 802.11g frames transmitted at 24Mb/s" },
+       { 28, "Number of unicast 802.11g frames transmitted at 36Mb/s" },
+       { 29, "Number of unicast 802.11g frames transmitted at 48Mb/s" },
+       { 30, "Number of unicast 802.11g frames transmitted at 54Mb/s" },
+       { 31, "Number of multicast frames transmitted" },
+       { 32, "Number of multicast 802.11b frames transmitted at 1Mb/s" },
+       { 33, "Number of multicast 802.11b frames transmitted at 2Mb/s" },
+       { 34, "Number of multicast 802.11b frames transmitted at 5.5Mb/s" },
+       { 35, "Number of multicast 802.11b frames transmitted at 11Mb/s" },
+
+       { 44, "Number of multicast 802.11g frames transmitted at 1Mb/s" },
+       { 45, "Number of multicast 802.11g frames transmitted at 2Mb/s" },
+       { 46, "Number of multicast 802.11g frames transmitted at 5.5Mb/s" },
+       { 47, "Number of multicast 802.11g frames transmitted at 6Mb/s" },
+       { 48, "Number of multicast 802.11g frames transmitted at 9Mb/s" },
+       { 49, "Number of multicast 802.11g frames transmitted at 11Mb/s" },
+       { 50, "Number of multicast 802.11g frames transmitted at 12Mb/s" },
+       { 51, "Number of multicast 802.11g frames transmitted at 18Mb/s" },
+       { 52, "Number of multicast 802.11g frames transmitted at 24Mb/s" },
+       { 53, "Number of multicast 802.11g frames transmitted at 36Mb/s" },
+       { 54, "Number of multicast 802.11g frames transmitted at 48Mb/s" },
+       { 55, "Number of multicast 802.11g frames transmitted at 54Mb/s" },
+       { 56, "Number of transmission retries" },
+       { 57, "Number of transmission failures" },
+       { 58, "Number of frames with a bad CRC received" },
+
+       { 61, "Number of full scans" },
+       { 62, "Number of partial scans" },
+
+       { 64, "Number of bytes transmitted" },
+       { 65, "Current RSSI" },
+       { 66, "Number of beacons received" },
+       { 67, "Number of beacons missed" },
+
+       { 0, NULL }
+};
+
+static void
+get_statistics(const char *iface)
+{
+       static u_int32_t stats[256];
+       char oid_name[128];
+       const struct statistic *stt;
+       int len;
+
+       snprintf(oid_name, sizeof oid_name, "hw.%s.stats", iface );
+       len = sizeof stats;
+       if (sysctlbyname(oid_name, stats, &len, NULL, 0) == -1)
+               err(EX_OSERR, "Can't retrieve statistics");
+
+       for (stt = tbl; stt->index != 0; stt++)
+               (void)printf("%-60s[%u]\n", stt->desc, stats[stt->index]);
+}
+