Sync 802.11 support with FreeBSD6:
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 18 May 2006 13:51:46 +0000 (13:51 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 18 May 2006 13:51:46 +0000 (13:51 +0000)
    "it includes completed 802.11g, WPA, 802.11i, 802.1x, WME/WMM, AP-side
     power-save, crypto plugin framework, authenticator plugin framework,
     and access control plugin frameowrk."

Reoriganize the layout of netproto/802_11: put generic 802.11 layer, crypto
modules, authentication module and access control module into their own
directories.  Header files are still in their original place.

Nuke all of the mutexing in generic 802.11, reorganize ieee80211_node table
scanning a little bit.

Rename FreeBSD's m_append() to ieee80211_mbuf_append(), rename FreeBSD's
m_unshare() to ieee80211_mbuf_clone() and put them into
netproto/802_11/wlan/ieee80211_dragonly.c
They are not generic enough for public using, at least for now.
Pointed-out-by: hsu
Expose ieee80211_add_{ssid, xrates, rates}() which are used by acx(4)

Keep using opencrypto's AES implmentation for 802.11 CCMP crypto module

Sync ifconfig(8)'s 802.11 support with FreeBSD6

Update acx(4) and ndis(4) for the new 802.11 support

Sync iwi(4), ipw(4), wi(4) and ray(4) with FreeBSD6

For iwi(4):
- Fix ieee80211_node leakage
- Use a bitmap instead of FreeBSD's "unit number alloctor" to allocate IBSS node

Add generic 802.11 layer and crypto modules into GENERIC and LINT,
authentication module and access module are only added to LINT

Unhook awi(4) from GENERIC and LINT temporarily, since as of this commit it
is broken :(  It will be fixed sometime later.

Thank Sam Leffler and many other people for their work on 802.11 support.

Thank Andrew Atrens and Adrian Michael Nida for submitting the patch.

Thank all the people that helped testing 802.11 patches for this commit

Based-on-Patch-Submitted-by:
  Andrew Atrens <atrens@nortelnetworks.com>
  Adrian Michael Nida <nida@musc.edu>

Tested-by:
  Thomas Schlesinger <schlesinger@netcologne.de>
  Johannes Hofmann <Johannes.Hofmann@gmx.de>
  Andrew Thompson <andrew@hijacked.us>
  Erik Wikström <erik-wikstrom@telia.com>

55 files changed:
sbin/ifconfig/ifieee80211.c
sys/conf/files
sys/config/GENERIC
sys/config/LINT
sys/dev/netif/acx/acx100.c
sys/dev/netif/acx/acx111.c
sys/dev/netif/acx/acxcmd.c
sys/dev/netif/acx/if_acx.c
sys/dev/netif/acx/if_acxvar.h
sys/dev/netif/ipw/if_ipw.c
sys/dev/netif/ipw/if_ipwvar.h
sys/dev/netif/iwi/if_iwi.c
sys/dev/netif/iwi/if_iwireg.h
sys/dev/netif/iwi/if_iwivar.h
sys/dev/netif/ndis/if_ndis.c
sys/dev/netif/ray/if_ray.c
sys/dev/netif/ray/if_rayvar.h
sys/dev/netif/wi/if_wi.c
sys/dev/netif/wi/if_wivar.h
sys/i386/conf/GENERIC
sys/i386/conf/LINT
sys/net/ethernet.h
sys/net/route.h
sys/net/rtsock.c
sys/netproto/802_11/Makefile
sys/netproto/802_11/_ieee80211.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211.h
sys/netproto/802_11/ieee80211_crypto.h
sys/netproto/802_11/ieee80211_dragonfly.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_ioctl.h
sys/netproto/802_11/ieee80211_node.h
sys/netproto/802_11/ieee80211_proto.h
sys/netproto/802_11/ieee80211_radiotap.h
sys/netproto/802_11/ieee80211_var.h
sys/netproto/802_11/wlan/Makefile
sys/netproto/802_11/wlan/ieee80211.c
sys/netproto/802_11/wlan/ieee80211_crypto.c
sys/netproto/802_11/wlan/ieee80211_crypto_none.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_dragonfly.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_input.c
sys/netproto/802_11/wlan/ieee80211_ioctl.c
sys/netproto/802_11/wlan/ieee80211_node.c
sys/netproto/802_11/wlan/ieee80211_output.c
sys/netproto/802_11/wlan/ieee80211_proto.c
sys/netproto/802_11/wlan_acl/Makefile [new file with mode: 0644]
sys/netproto/802_11/wlan_acl/ieee80211_acl.c [new file with mode: 0644]
sys/netproto/802_11/wlan_ccmp/Makefile [new file with mode: 0644]
sys/netproto/802_11/wlan_ccmp/ieee80211_crypto_ccmp.c [new file with mode: 0644]
sys/netproto/802_11/wlan_tkip/Makefile [new file with mode: 0644]
sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c [new file with mode: 0644]
sys/netproto/802_11/wlan_wep/Makefile [new file with mode: 0644]
sys/netproto/802_11/wlan_wep/ieee80211_crypto_wep.c [new file with mode: 0644]
sys/netproto/802_11/wlan_xauth/Makefile [new file with mode: 0644]
sys/netproto/802_11/wlan_xauth/ieee80211_xauth.c [new file with mode: 0644]
usr.sbin/iwicontrol/iwicontrol.c

index 38d3d1e..1ccffae 100644 (file)
@@ -24,8 +24,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * 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.10 2006/04/02 03:33:59 sephe Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.18.2.9 2006/03/07 17:50:23 sam Exp $
+ * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.11 2006/05/18 13:51:45 sephe Exp $
  */
 
 /*-
@@ -75,7 +75,9 @@
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
+#include <net/if_media.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 <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdarg.h>
 
 #include "ifconfig.h"
 
@@ -96,13 +100,19 @@ static const char *get_string(const char *val, const char *sep,
     u_int8_t *buf, int *lenp);
 static void print_string(const u_int8_t *buf, int len);
 
+static int
+isanyarg(const char *arg)
+{
+       return (strcmp(arg, "-") == 0 ||
+           strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
+}
+
 static void
-set80211ssid(const char *val, int d __unused, int s,
-            const struct afswtch *rafp __unused)
+set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
 {
        int             ssid;
        int             len;
-       u_int8_t        data[33];
+       u_int8_t        data[IEEE80211_NWID_LEN];
 
        ssid = 0;
        len = strlen(val);
@@ -113,14 +123,14 @@ set80211ssid(const char *val, int d __unused, int s,
 
        bzero(data, sizeof(data));
        len = sizeof(data);
-       get_string(val, NULL, data, &len);
+       if (get_string(val, NULL, data, &len) == NULL)
+               exit(1);
 
        set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
 }
 
 static void
-set80211stationname(const char *val, int d __unused, int s,
-                   const struct afswtch *rafp __unused)
+set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
 {
        int                     len;
        u_int8_t                data[33];
@@ -132,19 +142,50 @@ set80211stationname(const char *val, int d __unused, int s,
        set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
 }
 
+/*
+ * Convert IEEE channel number to MHz frequency.
+ */
+static u_int
+ieee80211_ieee2mhz(u_int chan)
+{
+       if (chan == 14)
+               return 2484;
+       if (chan < 14)                  /* 0-13 */
+               return 2407 + chan*5;
+       if (chan < 27)                  /* 15-26 */
+               return 2512 + ((chan-15)*20);
+       return 5000 + (chan*5);
+}
+
+/*
+ * Convert MHz frequency to IEEE channel number.
+ */
+static u_int
+ieee80211_mhz2ieee(u_int freq)
+{
+       if (freq == 2484)
+               return 14;
+       if (freq < 2484)
+               return (freq - 2407) / 5;
+       if (freq < 5000)
+               return 15 + ((freq - 2512) / 20);
+       return (freq - 5000) / 5;
+}
+
 static void
-set80211channel(const char *val, int d __unused, int s,
-               const struct afswtch *rafp __unused)
+set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
 {
-       if (strcmp(val, "-") == 0)
+       if (!isanyarg(val)) {
+               int v = atoi(val);
+               if (v > 255)            /* treat as frequency */
+                       v = ieee80211_mhz2ieee(v);
+               set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
+       } else
                set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
-       else
-               set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
 }
 
 static void
-set80211authmode(const char *val, int d __unused, int s,
-                const struct afswtch *rafp __unused)
+set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
 {
        int     mode;
 
@@ -154,16 +195,19 @@ set80211authmode(const char *val, int d __unused, int s,
                mode = IEEE80211_AUTH_OPEN;
        } else if (strcasecmp(val, "shared") == 0) {
                mode = IEEE80211_AUTH_SHARED;
+       } else if (strcasecmp(val, "8021x") == 0) {
+               mode = IEEE80211_AUTH_8021X;
+       } else if (strcasecmp(val, "wpa") == 0) {
+               mode = IEEE80211_AUTH_WPA;
        } else {
-               err(1, "unknown authmode");
+               errx(1, "unknown authmode");
        }
 
        set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
 }
 
 static void
-set80211powersavemode(const char *val, int d __unused, int s,
-                     const struct afswtch *rafp __unused)
+set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
 {
        int     mode;
 
@@ -178,15 +222,14 @@ set80211powersavemode(const char *val, int d __unused, int s,
        } else if (strcasecmp(val, "psp-cam") == 0) {
                mode = IEEE80211_POWERSAVE_PSP_CAM;
        } else {
-               err(1, "unknown powersavemode");
+               errx(1, "unknown powersavemode");
        }
 
        set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
 }
 
 static void
-set80211powersave(const char *val __unused, int d, int s,
-                 const struct afswtch *rafp __unused)
+set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
 {
        if (d == 0)
                set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
@@ -197,15 +240,13 @@ set80211powersave(const char *val __unused, int d, int s,
 }
 
 static void
-set80211powersavesleep(const char *val, int d __unused, int s,
-                      const struct afswtch *rafp __unused)
+set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
 {
        set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
 }
 
 static void
-set80211wepmode(const char *val, int d __unused, int s,
-               const struct afswtch *rafp __unused)
+set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
 {
        int     mode;
 
@@ -216,29 +257,35 @@ set80211wepmode(const char *val, int d __unused, int s,
        } else if (strcasecmp(val, "mixed") == 0) {
                mode = IEEE80211_WEP_MIXED;
        } else {
-               err(1, "unknown wep mode");
+               errx(1, "unknown wep mode");
        }
 
        set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
 }
 
 static void
-set80211wep(const char *val __unused, int d, int s,
-           const struct afswtch *rafp __unused)
+set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
 {
        set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
 }
 
+static int
+isundefarg(const char *arg)
+{
+       return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
+}
+
 static void
-set80211weptxkey(const char *val, int d __unused, int s,
-                const struct afswtch *rafp __unused)
+set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
 {
-       set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
+       if (isundefarg(val))
+               set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
+       else
+               set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
 }
 
 static void
-set80211wepkey(const char *val, int d __unused, int s,
-              const struct afswtch *rafp __unused)
+set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
 {
        int             key = 0;
        int             len;
@@ -257,13 +304,12 @@ set80211wepkey(const char *val, int d __unused, int s,
 }
 
 /*
- * This function is purly a NetBSD compatability interface.  The NetBSD
- * iterface is too inflexable, but it's there so we'll support it since
+ * This function is purely a NetBSD compatability interface.  The NetBSD
+ * interface is too inflexible, but it's there so we'll support it since
  * it's not all that hard.
  */
 static void
-set80211nwkey(const char *val, int d __unused, int s,
-             const struct afswtch *rafp __unused)
+set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
 {
        int             txkey;
        int             i, len;
@@ -279,6 +325,8 @@ set80211nwkey(const char *val, int d __unused, int s,
                        bzero(data, sizeof(data));
                        len = sizeof(data);
                        val = get_string(val, ",", data, &len);
+                       if (val == NULL)
+                               exit(1);
 
                        set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
                }
@@ -299,15 +347,14 @@ set80211nwkey(const char *val, int d __unused, int s,
 }
 
 static void
-set80211rtsthreshold(const char *val, int d __unused, int s,
-       const struct afswtch *rafp __unused)
+set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
 {
-       set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL);
+       set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
+               isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
 }
 
 static void
-set80211protmode(const char *val, int d __unused, int s,
-       const struct afswtch *rafp __unused)
+set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
 {
        int     mode;
 
@@ -318,166 +365,1183 @@ set80211protmode(const char *val, int d __unused, int s,
        } else if (strcasecmp(val, "rtscts") == 0) {
                mode = IEEE80211_PROTMODE_RTSCTS;
        } else {
-               err(1, "unknown protection mode");
+               errx(1, "unknown protection mode");
        }
 
        set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
 }
 
 static void
-set80211txpower(const char *val, int d __unused, int s,
-       const struct afswtch *rafp __unused)
+set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
 {
        set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
 }
 
+#define        IEEE80211_ROAMING_DEVICE        0
+#define        IEEE80211_ROAMING_AUTO          1
+#define        IEEE80211_ROAMING_MANUAL        2
+
 static void
-ieee80211_status (int s)
+set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
 {
-       int                     i;
-       int                     num;
-       struct ieee80211req     ireq;
-       u_int8_t                data[32];
-       char                    spacer;
+       int mode;
+
+       if (strcasecmp(val, "device") == 0) {
+               mode = IEEE80211_ROAMING_DEVICE;
+       } else if (strcasecmp(val, "auto") == 0) {
+               mode = IEEE80211_ROAMING_AUTO;
+       } else if (strcasecmp(val, "manual") == 0) {
+               mode = IEEE80211_ROAMING_MANUAL;
+       } else {
+               errx(1, "unknown roaming mode");
+       }
+       set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
+}
 
-       memset(&ireq, 0, sizeof(ireq));
-       strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-       ireq.i_data = &data;
+static void
+set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
+}
 
-       ireq.i_type = IEEE80211_IOC_SSID;
-       ireq.i_val = -1;
-       if (ioctl(s, SIOCG80211, &ireq) < 0) {
-               /* If we can't get the SSID, the this isn't an 802.11 device. */
-               return;
-       }
-       printf("\tssid ");
-       print_string(data, ireq.i_len);
-       num = 0;
-       ireq.i_type = IEEE80211_IOC_NUMSSIDS;
-       if (ioctl(s, SIOCG80211, &ireq) >= 0) {
-               num = ireq.i_val;
-       }
-       ireq.i_type = IEEE80211_IOC_SSID;
-       for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
-               if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
-                       printf(" %d:", ireq.i_val + 1);
-                       print_string(data, ireq.i_len);
+static void
+set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
+}
+
+static void
+set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
+}
+
+static void
+set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       struct ieee80211req_chanlist chanlist;
+#define        MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
+       char *temp, *cp, *tp;
+
+       temp = malloc(strlen(val) + 1);
+       if (temp == NULL)
+               errx(1, "malloc failed");
+       strcpy(temp, val);
+       memset(&chanlist, 0, sizeof(chanlist));
+       cp = temp;
+       for (;;) {
+               int first, last, f;
+
+               tp = strchr(cp, ',');
+               if (tp != NULL)
+                       *tp++ = '\0';
+               switch (sscanf(cp, "%u-%u", &first, &last)) {
+               case 1:
+                       if (first > MAXCHAN)
+                               errx(-1, "channel %u out of range, max %zu",
+                                       first, MAXCHAN);
+                       setbit(chanlist.ic_channels, first);
+                       break;
+               case 2:
+                       if (first > MAXCHAN)
+                               errx(-1, "channel %u out of range, max %zu",
+                                       first, MAXCHAN);
+                       if (last > MAXCHAN)
+                               errx(-1, "channel %u out of range, max %zu",
+                                       last, MAXCHAN);
+                       if (first > last)
+                               errx(-1, "void channel range, %u > %u",
+                                       first, last);
+                       for (f = first; f <= last; f++)
+                               setbit(chanlist.ic_channels, f);
+                       break;
                }
+               if (tp == NULL)
+                       break;
+               while (isspace(*tp))
+                       tp++;
+               if (!isdigit(*tp))
+                       break;
+               cp = tp;
        }
-       printf("\n");
+       set80211(s, IEEE80211_IOC_CHANLIST, 0,
+               sizeof(chanlist), (uint8_t *) &chanlist);
+#undef MAXCHAN
+}
 
-       ireq.i_type = IEEE80211_IOC_STATIONNAME;
-       if (ioctl(s, SIOCG80211, &ireq) != -1) {
-               printf("\tstationname ");
-               print_string(data, ireq.i_len);
-               printf("\n");
+static void
+set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+       if (!isanyarg(val)) {
+               char *temp;
+               struct sockaddr_dl sdl;
+
+               temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+               if (temp == NULL)
+                       errx(1, "malloc failed");
+               temp[0] = ':';
+               strcpy(temp + 1, val);
+               sdl.sdl_len = sizeof(sdl);
+               link_addr(temp, &sdl);
+               free(temp);
+               if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+                       errx(1, "malformed link-level address");
+               set80211(s, IEEE80211_IOC_BSSID, 0,
+                       IEEE80211_ADDR_LEN, LLADDR(&sdl));
+       } else {
+               uint8_t zerobssid[IEEE80211_ADDR_LEN];
+               memset(zerobssid, 0, sizeof(zerobssid));
+               set80211(s, IEEE80211_IOC_BSSID, 0,
+                       IEEE80211_ADDR_LEN, zerobssid);
        }
+}
 
-       ireq.i_type = IEEE80211_IOC_CHANNEL;
-       if (ioctl(s, SIOCG80211, &ireq) < 0) {
-               goto end;
+static int
+getac(const char *ac)
+{
+       if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
+               return WME_AC_BE;
+       if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
+               return WME_AC_BK;
+       if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
+               return WME_AC_VI;
+       if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
+               return WME_AC_VO;
+       errx(1, "unknown wme access class %s", ac);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmin, ac, val)
+{
+       set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmax, ac, val)
+{
+       set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211aifs, ac, val)
+{
+       set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211txoplimit, ac, val)
+{
+       set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211acm, ac, d)
+{
+       set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
+}
+static
+DECL_CMD_FUNC(set80211noacm, ac, d)
+{
+       set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ackpolicy, ac, d)
+{
+       set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
+}
+static
+DECL_CMD_FUNC(set80211noackpolicy, ac, d)
+{
+       set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
+{
+       set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
+               getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
+{
+       set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
+               getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bssaifs, ac, val)
+{
+       set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
+               getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
+{
+       set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
+               getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211dtimperiod, val, d)
+{
+       set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bintval, val, d)
+{
+       set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
+}
+
+static void
+set80211macmac(int s, int op, const char *val)
+{
+       char *temp;
+       struct sockaddr_dl sdl;
+
+       temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+       if (temp == NULL)
+               errx(1, "malloc failed");
+       temp[0] = ':';
+       strcpy(temp + 1, val);
+       sdl.sdl_len = sizeof(sdl);
+       link_addr(temp, &sdl);
+       free(temp);
+       if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+               errx(1, "malformed link-level address");
+       set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
+}
+
+static
+DECL_CMD_FUNC(set80211addmac, val, d)
+{
+       set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211delmac, val, d)
+{
+       set80211macmac(s, IEEE80211_IOC_DELMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211kickmac, val, d)
+{
+       char *temp;
+       struct sockaddr_dl sdl;
+       struct ieee80211req_mlme mlme;
+
+       temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+       if (temp == NULL)
+               errx(1, "malloc failed");
+       temp[0] = ':';
+       strcpy(temp + 1, val);
+       sdl.sdl_len = sizeof(sdl);
+       link_addr(temp, &sdl);
+       free(temp);
+       if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+               errx(1, "malformed link-level address");
+       memset(&mlme, 0, sizeof(mlme));
+       mlme.im_op = IEEE80211_MLME_DEAUTH;
+       mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
+       memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
+       set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
+}
+
+static
+DECL_CMD_FUNC(set80211maccmd, val, d)
+{
+       set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
+}
+
+static void
+set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
+}
+
+static void
+set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211mcastrate, val, d)
+{
+       set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211fragthreshold, val, d)
+{
+       set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
+               isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
+}
+
+static int
+getmaxrate(uint8_t rates[15], uint8_t nrates)
+{
+       int i, maxrate = -1;
+
+       for (i = 0; i < nrates; i++) {
+               int rate = rates[i] & IEEE80211_RATE_VAL;
+               if (rate > maxrate)
+                       maxrate = rate;
        }
-       printf("\tchannel %d", ireq.i_val);
+       return maxrate / 2;
+}
 
-       ireq.i_type = IEEE80211_IOC_AUTHMODE;
-       if (ioctl(s, SIOCG80211, &ireq) != -1) {
-               printf(" authmode");
-               switch (ireq.i_val) {
-                       case IEEE80211_AUTH_NONE:
-                               printf(" NONE");
-                               break;
-                       case IEEE80211_AUTH_OPEN:
-                               printf(" OPEN");
-                               break;
-                       case IEEE80211_AUTH_SHARED:
-                               printf(" SHARED");
-                               break;
-                       default:
-                               printf(" UNKNOWN");
+static const char *
+getcaps(int capinfo)
+{
+       static char capstring[32];
+       char *cp = capstring;
+
+       if (capinfo & IEEE80211_CAPINFO_ESS)
+               *cp++ = 'E';
+       if (capinfo & IEEE80211_CAPINFO_IBSS)
+               *cp++ = 'I';
+       if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
+               *cp++ = 'c';
+       if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
+               *cp++ = 'C';
+       if (capinfo & IEEE80211_CAPINFO_PRIVACY)
+               *cp++ = 'P';
+       if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
+               *cp++ = 'S';
+       if (capinfo & IEEE80211_CAPINFO_PBCC)
+               *cp++ = 'B';
+       if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
+               *cp++ = 'A';
+       if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
+               *cp++ = 's';
+       if (capinfo & IEEE80211_CAPINFO_RSN)
+               *cp++ = 'R';
+       if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
+               *cp++ = 'D';
+       *cp = '\0';
+       return capstring;
+}
+
+static void
+printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+       printf("%s", tag);
+       if (verbose) {
+               maxlen -= strlen(tag)+2;
+               if (2*ielen > maxlen)
+                       maxlen--;
+               printf("<");
+               for (; ielen > 0; ie++, ielen--) {
+                       if (maxlen-- <= 0)
                                break;
+                       printf("%02x", *ie);
                }
+               if (ielen != 0)
+                       printf("-");
+               printf(">");
        }
+}
 
-       ireq.i_type = IEEE80211_IOC_POWERSAVE;
-       if (ioctl(s, SIOCG80211, &ireq) != -1 &&
-           ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
-               printf(" powersavemode");
-               switch (ireq.i_val) {
-                       case IEEE80211_POWERSAVE_OFF:
-                               printf(" OFF");
-                               break;
-                       case IEEE80211_POWERSAVE_CAM:
-                               printf(" CAM");
-                               break;
-                       case IEEE80211_POWERSAVE_PSP:
-                               printf(" PSP");
+/*
+ * Copy the ssid string contents into buf, truncating to fit.  If the
+ * ssid is entirely printable then just copy intact.  Otherwise convert
+ * to hexadecimal.  If the result is truncated then replace the last
+ * three characters with "...".
+ */
+static int
+copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
+{
+       const u_int8_t *p; 
+       size_t maxlen;
+       int i;
+
+       if (essid_len > bufsize)
+               maxlen = bufsize;
+       else
+               maxlen = essid_len;
+       /* determine printable or not */
+       for (i = 0, p = essid; i < maxlen; i++, p++) {
+               if (*p < ' ' || *p > 0x7e)
+                       break;
+       }
+       if (i != maxlen) {              /* not printable, print as hex */
+               if (bufsize < 3)
+                       return 0;
+               strlcpy(buf, "0x", bufsize);
+               bufsize -= 2;
+               p = essid;
+               for (i = 0; i < maxlen && bufsize >= 2; i++) {
+                       sprintf(&buf[2+2*i], "%02x", p[i]);
+                       bufsize -= 2;
+               }
+               if (i != essid_len)
+                       memcpy(&buf[2+2*i-3], "...", 3);
+       } else {                        /* printable, truncate as needed */
+               memcpy(buf, essid, maxlen);
+               if (maxlen != essid_len)
+                       memcpy(&buf[maxlen-3], "...", 3);
+       }
+       return maxlen;
+}
+
+/* unaligned little endian access */     
+#define LE_READ_4(p)                                   \
+       ((u_int32_t)                                    \
+        ((((const u_int8_t *)(p))[0]      ) |          \
+         (((const u_int8_t *)(p))[1] <<  8) |          \
+         (((const u_int8_t *)(p))[2] << 16) |          \
+         (((const u_int8_t *)(p))[3] << 24)))
+
+static int __inline
+iswpaoui(const u_int8_t *frm)
+{
+       return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static int __inline
+iswmeoui(const u_int8_t *frm)
+{
+       return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
+}
+
+static int __inline
+isatherosoui(const u_int8_t *frm)
+{
+       return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
+}
+
+static void
+printies(const u_int8_t *vp, int ielen, int maxcols)
+{
+       while (ielen > 0) {
+               switch (vp[0]) {
+               case IEEE80211_ELEMID_VENDOR:
+                       if (iswpaoui(vp))
+                               printie(" WPA", vp, 2+vp[1], maxcols);
+                       else if (iswmeoui(vp))
+                               printie(" WME", vp, 2+vp[1], maxcols);
+                       else if (isatherosoui(vp))
+                               printie(" ATH", vp, 2+vp[1], maxcols);
+                       else
+                               printie(" VEN", vp, 2+vp[1], maxcols);
+                       break;
+               case IEEE80211_ELEMID_RSN:
+                       printie(" RSN", vp, 2+vp[1], maxcols);
+                       break;
+               default:
+                       printie(" ???", vp, 2+vp[1], maxcols);
+                       break;
+               }
+               ielen -= 2+vp[1];
+               vp += 2+vp[1];
+       }
+}
+
+static void
+list_scan(int s)
+{
+       uint8_t buf[24*1024];
+       struct ieee80211req ireq;
+       char ssid[IEEE80211_NWID_LEN+1];
+       uint8_t *cp;
+       int len, ssidmax;
+
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
+       ireq.i_data = buf;
+       ireq.i_len = sizeof(buf);
+       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               errx(1, "unable to get scan results");
+       len = ireq.i_len;
+       if (len < sizeof(struct ieee80211req_scan_result))
+               return;
+
+       ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
+       printf("%-*.*s  %-17.17s  %4s %4s  %-5s %3s %4s\n"
+               , ssidmax, ssidmax, "SSID"
+               , "BSSID"
+               , "CHAN"
+               , "RATE"
+               , "S:N"
+               , "INT"
+               , "CAPS"
+       );
+       cp = buf;
+       do {
+               struct ieee80211req_scan_result *sr;
+               uint8_t *vp;
+
+               sr = (struct ieee80211req_scan_result *) cp;
+               vp = (u_int8_t *)(sr+1);
+               printf("%-*.*s  %s  %3d  %3dM %2d:%-2d  %3d %-4.4s"
+                       , ssidmax
+                         , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
+                         , ssid
+                       , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
+                       , ieee80211_mhz2ieee(sr->isr_freq)
+                       , getmaxrate(sr->isr_rates, sr->isr_nrates)
+                       , sr->isr_rssi, sr->isr_noise
+                       , sr->isr_intval
+                       , getcaps(sr->isr_capinfo)
+               );
+               printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
+               printf("\n");
+               cp += sr->isr_len, len -= sr->isr_len;
+       } while (len >= sizeof(struct ieee80211req_scan_result));
+}
+
+#include <netproto/802_11/ieee80211_dragonfly.h>
+
+static void
+scan_and_wait(int s)
+{
+       struct ieee80211req ireq;
+       int sroute;
+
+       sroute = socket(PF_ROUTE, SOCK_RAW, 0);
+       if (sroute < 0) {
+               perror("socket(PF_ROUTE,SOCK_RAW)");
+               return;
+       }
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_type = IEEE80211_IOC_SCAN_REQ;
+       /* NB: only root can trigger a scan so ignore errors */
+       if (ioctl(s, SIOCS80211, &ireq) >= 0) {
+               char buf[2048];
+               struct if_announcemsghdr *ifan;
+               struct rt_msghdr *rtm;
+
+               do {
+                       if (read(sroute, buf, sizeof(buf)) < 0) {
+                               perror("read(PF_ROUTE)");
                                break;
-                       case IEEE80211_POWERSAVE_PSP_CAM:
-                               printf(" PSP-CAM");
+                       }
+                       rtm = (struct rt_msghdr *) buf;
+                       if (rtm->rtm_version != RTM_VERSION)
                                break;
+                       ifan = (struct if_announcemsghdr *) rtm;
+               } while (rtm->rtm_type != RTM_IEEE80211 ||
+                   ifan->ifan_what != RTM_IEEE80211_SCAN);
+       }
+       close(sroute);
+}
+
+static
+DECL_CMD_FUNC(set80211scan, val, d)
+{
+       scan_and_wait(s);
+       list_scan(s);
+}
+
+static void
+list_stations(int s)
+{
+       uint8_t buf[24*1024];
+       struct ieee80211req ireq;
+       uint8_t *cp;
+       int len;
+
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_type = IEEE80211_IOC_STA_INFO;
+       ireq.i_data = buf;
+       ireq.i_len = sizeof(buf);
+       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               errx(1, "unable to get station information");
+       len = ireq.i_len;
+       if (len < sizeof(struct ieee80211req_sta_info))
+               return;
+
+       printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
+               , "ADDR"
+               , "AID"
+               , "CHAN"
+               , "RATE"
+               , "RSSI"
+               , "IDLE"
+               , "TXSEQ"
+               , "RXSEQ"
+               , "CAPS"
+               , "ERP"
+       );
+       cp = buf;
+       do {
+               struct ieee80211req_sta_info *si;
+               uint8_t *vp;
+
+               si = (struct ieee80211req_sta_info *) cp;
+               vp = (u_int8_t *)(si+1);
+               printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
+                       , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
+                       , IEEE80211_AID(si->isi_associd)
+                       , ieee80211_mhz2ieee(si->isi_freq)
+                       , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
+                       , si->isi_rssi
+                       , si->isi_inact
+                       , si->isi_txseqs[0]
+                       , si->isi_rxseqs[0]
+                       , getcaps(si->isi_capinfo)
+                       , si->isi_erp
+               );
+               printies(vp, si->isi_ie_len, 24);
+               printf("\n");
+               cp += si->isi_len, len -= si->isi_len;
+       } while (len >= sizeof(struct ieee80211req_sta_info));
+}
+
+static void
+print_chaninfo(const struct ieee80211_channel *c)
+{
+#define        IEEE80211_IS_CHAN_PASSIVE(_c) \
+       (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
+       char buf[14];
+
+       buf[0] = '\0';
+       if (IEEE80211_IS_CHAN_FHSS(c))
+               strlcat(buf, " FHSS", sizeof(buf));
+       if (IEEE80211_IS_CHAN_A(c))
+               strlcat(buf, " 11a", sizeof(buf));
+       /* XXX 11g schizophrenia */
+       if (IEEE80211_IS_CHAN_G(c) ||
+           IEEE80211_IS_CHAN_PUREG(c))
+               strlcat(buf, " 11g", sizeof(buf));
+       else if (IEEE80211_IS_CHAN_B(c))
+               strlcat(buf, " 11b", sizeof(buf));
+       if (IEEE80211_IS_CHAN_T(c))
+               strlcat(buf, " Turbo", sizeof(buf));
+       printf("Channel %3u : %u%c Mhz%-14.14s",
+               ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
+               IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
+#undef IEEE80211_IS_CHAN_PASSIVE
+}
+
+static void
+list_channels(int s, int allchans)
+{
+       struct ieee80211req ireq;
+       struct ieee80211req_chaninfo chans;
+       struct ieee80211req_chaninfo achans;
+       const struct ieee80211_channel *c;
+       int i, half;
+
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_type = IEEE80211_IOC_CHANINFO;
+       ireq.i_data = &chans;
+       ireq.i_len = sizeof(chans);
+       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               errx(1, "unable to get channel information");
+       if (!allchans) {
+               struct ieee80211req_chanlist active;
+
+               ireq.i_type = IEEE80211_IOC_CHANLIST;
+               ireq.i_data = &active;
+               ireq.i_len = sizeof(active);
+               if (ioctl(s, SIOCG80211, &ireq) < 0)
+                       errx(1, "unable to get active channel list");
+               memset(&achans, 0, sizeof(achans));
+               for (i = 0; i < chans.ic_nchans; i++) {
+                       c = &chans.ic_chans[i];
+                       if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
+                               achans.ic_chans[achans.ic_nchans++] = *c;
                }
+       } else
+               achans = chans;
+       half = achans.ic_nchans / 2;
+       if (achans.ic_nchans % 2)
+               half++;
+       for (i = 0; i < achans.ic_nchans / 2; i++) {
+               print_chaninfo(&achans.ic_chans[i]);
+               print_chaninfo(&achans.ic_chans[half+i]);
+               printf("\n");
+       }
+       if (achans.ic_nchans % 2) {
+               print_chaninfo(&achans.ic_chans[i]);
+               printf("\n");
+       }
+}
+
+static void
+list_keys(int s)
+{
+}
+
+#define        IEEE80211_C_BITS \
+"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
+"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
+"\31WPA2\32BURST\33WME"
 
-               ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
+static void
+list_capabilities(int s)
+{
+       struct ieee80211req ireq;
+       u_int32_t caps;
+
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
+       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               errx(1, "unable to get driver capabilities");
+       caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
+       printb(name, caps, IEEE80211_C_BITS);
+       putchar('\n');
+}
+
+static void
+list_wme(int s)
+{
+       static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
+       struct ieee80211req ireq;
+       int ac;
+
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_len = 0;
+       for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
+again:
+               if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
+                       printf("\t%s", "     ");
+               else
+                       printf("\t%s", acnames[ac]);
+
+               ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
+
+               /* show WME BSS parameters */
+               ireq.i_type = IEEE80211_IOC_WME_CWMIN;
+               if (ioctl(s, SIOCG80211, &ireq) != -1)
+                       printf(" cwmin %2u", ireq.i_val);
+               ireq.i_type = IEEE80211_IOC_WME_CWMAX;
+               if (ioctl(s, SIOCG80211, &ireq) != -1)
+                       printf(" cwmax %2u", ireq.i_val);
+               ireq.i_type = IEEE80211_IOC_WME_AIFS;
+               if (ioctl(s, SIOCG80211, &ireq) != -1)
+                       printf(" aifs %2u", ireq.i_val);
+               ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
+               if (ioctl(s, SIOCG80211, &ireq) != -1)
+                       printf(" txopLimit %3u", ireq.i_val);
+               ireq.i_type = IEEE80211_IOC_WME_ACM;
                if (ioctl(s, SIOCG80211, &ireq) != -1) {
                        if (ireq.i_val)
-                               printf(" powersavesleep %d", ireq.i_val);
+                               printf(" acm");
+                       else if (verbose)
+                               printf(" -acm");
+               }
+               /* !BSS only */
+               if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
+                       ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
+                       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                               if (!ireq.i_val)
+                                       printf(" -ack");
+                               else if (verbose)
+                                       printf(" ack");
+                       }
                }
+               printf("\n");
+               if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
+                       ireq.i_len |= IEEE80211_WMEPARAM_BSS;
+                       goto again;
+               } else
+                       ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
        }
+}
 
-       printf("\n");
+static void
+list_mac(int s)
+{
+       struct ieee80211req ireq;
+       struct ieee80211req_maclist *acllist;
+       int i, nacls, policy;
+       char c;
+
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
+       ireq.i_type = IEEE80211_IOC_MACCMD;
+       ireq.i_val = IEEE80211_MACCMD_POLICY;
+       if (ioctl(s, SIOCG80211, &ireq) < 0) {
+               if (errno == EINVAL) {
+                       printf("No acl policy loaded\n");
+                       return;
+               }
+               err(1, "unable to get mac policy");
+       }
+       policy = ireq.i_val;
 
-       spacer = '\t';
-       ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
+       ireq.i_val = IEEE80211_MACCMD_LIST;
+       ireq.i_len = 0;
+       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               err(1, "unable to get mac acl list size");
+       if (ireq.i_len == 0)            /* NB: no acls */
+               return;
+
+       ireq.i_data = malloc(ireq.i_len);
+       if (ireq.i_data == NULL)
+               err(1, "out of memory for acl list");
+
+       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               err(1, "unable to get mac acl list");
+       if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
+               if (verbose)
+                       printf("policy: open\n");
+               c = '*';
+       } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
+               if (verbose)
+                       printf("policy: allow\n");
+               c = '+';
+       } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
+               if (verbose)
+                       printf("policy: deny\n");
+               c = '-';
+       } else {
+               printf("policy: unknown (%u)\n", policy);
+               c = '?';
+       }
+       nacls = ireq.i_len / sizeof(*acllist);
+       acllist = (struct ieee80211req_maclist *) ireq.i_data;
+       for (i = 0; i < nacls; i++)
+               printf("%c%s\n", c, ether_ntoa(
+                       (const struct ether_addr *) acllist[i].ml_macaddr));
+}
+
+static
+DECL_CMD_FUNC(set80211list, arg, d)
+{
+#define        iseq(a,b)       (strncasecmp(a,b,sizeof(b)-1) == 0)
+
+       if (iseq(arg, "sta"))
+               list_stations(s);
+       else if (iseq(arg, "scan") || iseq(arg, "ap"))
+               list_scan(s);
+       else if (iseq(arg, "chan") || iseq(arg, "freq"))
+               list_channels(s, 1);
+       else if (iseq(arg, "active"))
+               list_channels(s, 0);
+       else if (iseq(arg, "keys"))
+               list_keys(s);
+       else if (iseq(arg, "caps"))
+               list_capabilities(s);
+       else if (iseq(arg, "wme"))
+               list_wme(s);
+       else if (iseq(arg, "mac"))
+               list_mac(s);
+       else
+               errx(1, "Don't know how to list %s for %s", arg, name);
+#undef iseq
+}
+
+static enum ieee80211_opmode
+get80211opmode(int s)
+{
+       struct ifmediareq ifmr;
+
+       (void) memset(&ifmr, 0, sizeof(ifmr));
+       (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+               if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
+                       return IEEE80211_M_IBSS;        /* XXX ahdemo */
+               if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+                       return IEEE80211_M_HOSTAP;
+               if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+                       return IEEE80211_M_MONITOR;
+       }
+       return IEEE80211_M_STA;
+}
+
+static const struct ieee80211_channel *
+getchaninfo(int s, int chan)
+{
+       struct ieee80211req ireq;
+       static struct ieee80211req_chaninfo chans;
+       static struct ieee80211_channel undef;
+       const struct ieee80211_channel *c;
+       int i, freq;
+
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_type = IEEE80211_IOC_CHANINFO;
+       ireq.i_data = &chans;
+       ireq.i_len = sizeof(chans);
+       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               errx(1, "unable to get channel information");
+       freq = ieee80211_ieee2mhz(chan);
+       for (i = 0; i < chans.ic_nchans; i++) {
+               c = &chans.ic_chans[i];
+               if (c->ic_freq == freq)
+                       return c;
+       }
+       return &undef;
+}
+
+#if 0
+static void
+printcipher(int s, struct ieee80211req *ireq, int keylenop)
+{
+       switch (ireq->i_val) {
+       case IEEE80211_CIPHER_WEP:
+               ireq->i_type = keylenop;
+               if (ioctl(s, SIOCG80211, ireq) != -1)
+                       printf("WEP-%s", 
+                           ireq->i_len <= 5 ? "40" :
+                           ireq->i_len <= 13 ? "104" : "128");
+               else
+                       printf("WEP");
+               break;
+       case IEEE80211_CIPHER_TKIP:
+               printf("TKIP");
+               break;
+       case IEEE80211_CIPHER_AES_OCB:
+               printf("AES-OCB");
+               break;
+       case IEEE80211_CIPHER_AES_CCM:
+               printf("AES-CCM");
+               break;
+       case IEEE80211_CIPHER_CKIP:
+               printf("CKIP");
+               break;
+       case IEEE80211_CIPHER_NONE:
+               printf("NONE");
+               break;
+       default:
+               printf("UNKNOWN (0x%x)", ireq->i_val);
+               break;
+       }
+}
+#endif
+
+#define        MAXCOL  78
+static int col;
+static char spacer;
+
+static void
+LINE_BREAK(void)
+{
+       if (spacer != '\t') {
+               printf("\n");
+               spacer = '\t';
+       }
+       col = 8;        /* 8-col tab */
+}
+
+static void
+LINE_CHECK(const char *fmt, ...)
+{
+       char buf[80];
+       va_list ap;
+       int n;
+
+       va_start(ap, fmt);
+       n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
+       va_end(ap);
+       col += 1+n;
+       if (col > MAXCOL) {
+               LINE_BREAK();
+               col += n;
+       }
+       buf[0] = spacer;
+       printf("%s", buf);
+       spacer = ' ';
+}
+
+static void
+printkey(const struct ieee80211req_key *ik)
+{
+       static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
+       int keylen = ik->ik_keylen;
+       int printcontents;
+
+       printcontents = printkeys &&
+               (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
+       if (printcontents)
+               LINE_BREAK();
+       switch (ik->ik_type) {
+       case IEEE80211_CIPHER_WEP:
+               /* compatibility */
+               LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
+                   keylen <= 5 ? "40-bit" :
+                   keylen <= 13 ? "104-bit" : "128-bit");
+               break;
+       case IEEE80211_CIPHER_TKIP:
+               if (keylen > 128/8)
+                       keylen -= 128/8;        /* ignore MIC for now */
+               LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+               break;
+       case IEEE80211_CIPHER_AES_OCB:
+               LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+               break;
+       case IEEE80211_CIPHER_AES_CCM:
+               LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+               break;
+       case IEEE80211_CIPHER_CKIP:
+               LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+               break;
+       case IEEE80211_CIPHER_NONE:
+               LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+               break;
+       default:
+               LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
+                       ik->ik_type, ik->ik_keyix+1, 8*keylen);
+               break;
+       }
+       if (printcontents) {
+               int i;
+
+               printf(" <");
+               for (i = 0; i < keylen; i++)
+                       printf("%02x", ik->ik_keydata[i]);
+               printf(">");
+               if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+                   (ik->ik_keyrsc != 0 || verbose))
+                       printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
+               if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+                   (ik->ik_keytsc != 0 || verbose))
+                       printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
+               if (ik->ik_flags != 0 && verbose) {
+                       const char *sep = " ";
+
+                       if (ik->ik_flags & IEEE80211_KEY_XMIT)
+                               printf("%stx", sep), sep = "+";
+                       if (ik->ik_flags & IEEE80211_KEY_RECV)
+                               printf("%srx", sep), sep = "+";
+                       if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
+                               printf("%sdef", sep), sep = "+";
+               }
+               LINE_BREAK();
+       }
+}
+
+static void
+ieee80211_status(int s)
+{
+       static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
+       enum ieee80211_opmode opmode = get80211opmode(s);
+       int i, num, wpa, wme;
+       struct ieee80211req ireq;
+       u_int8_t data[32];
+       const struct ieee80211_channel *c;
+
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_data = &data;
+
+       wpa = 0;                /* unknown/not set */
+
+       ireq.i_type = IEEE80211_IOC_SSID;
+       ireq.i_val = -1;
+       if (ioctl(s, SIOCG80211, &ireq) < 0) {
+               /* If we can't get the SSID, this isn't an 802.11 device. */
+               return;
+       }
+       num = 0;
+       ireq.i_type = IEEE80211_IOC_NUMSSIDS;
+       if (ioctl(s, SIOCG80211, &ireq) >= 0)
+               num = ireq.i_val;
+       printf("\tssid ");
+       if (num > 1) {
+               ireq.i_type = IEEE80211_IOC_SSID;
+               for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
+                       if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
+                               printf(" %d:", ireq.i_val + 1);
+                               print_string(data, ireq.i_len);
+                       }
+               }
+       } else
+               print_string(data, ireq.i_len);
+
+       ireq.i_type = IEEE80211_IOC_CHANNEL;
+       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               goto end;
+       c = getchaninfo(s, ireq.i_val);
+       if (ireq.i_val != -1) {
+               printf(" channel %d", ireq.i_val);
+               if (verbose)
+                       printf(" (%u)", c->ic_freq);
+       } else if (verbose)
+               printf(" channel UNDEF");
+
+       ireq.i_type = IEEE80211_IOC_BSSID;
+       ireq.i_len = IEEE80211_ADDR_LEN;
+       if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
+           (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
+               printf(" bssid %s", ether_ntoa(ireq.i_data));
+
+       ireq.i_type = IEEE80211_IOC_STATIONNAME;
        if (ioctl(s, SIOCG80211, &ireq) != -1) {
-               printf("%crtsthreshold %d", spacer, ireq.i_val);
-               spacer = ' ';
+               printf("\n\tstationname ");
+               print_string(data, ireq.i_len);
        }
 
-       ireq.i_type = IEEE80211_IOC_PROTMODE;
+       spacer = ' ';           /* force first break */
+       LINE_BREAK();
+
+       ireq.i_type = IEEE80211_IOC_AUTHMODE;
        if (ioctl(s, SIOCG80211, &ireq) != -1) {
-               printf("%cprotmode", spacer);
                switch (ireq.i_val) {
-                       case IEEE80211_PROTMODE_OFF:
-                               printf(" OFF");
+                       case IEEE80211_AUTH_NONE:
+                               LINE_CHECK("authmode NONE");
+                               break;
+                       case IEEE80211_AUTH_OPEN:
+                               LINE_CHECK("authmode OPEN");
+                               break;
+                       case IEEE80211_AUTH_SHARED:
+                               LINE_CHECK("authmode SHARED");
                                break;
-                       case IEEE80211_PROTMODE_CTS:
-                               printf(" CTS");
+                       case IEEE80211_AUTH_8021X:
+                               LINE_CHECK("authmode 802.1x");
                                break;
-                       case IEEE80211_PROTMODE_RTSCTS:
-                               printf(" RTSCTS");
+                       case IEEE80211_AUTH_WPA:
+                               ireq.i_type = IEEE80211_IOC_WPA;
+                               if (ioctl(s, SIOCG80211, &ireq) != -1)
+                                       wpa = ireq.i_val;
+                               if (!wpa)
+                                       wpa = 1;        /* default to WPA1 */
+                               switch (wpa) {
+                               case 2:
+                                       LINE_CHECK("authmode WPA2/802.11i");
+                                       break;
+                               case 3:
+                                       LINE_CHECK("authmode WPA1+WPA2/802.11i");
+                                       break;
+                               default:
+                                       LINE_CHECK("authmode WPA");
+                                       break;
+                               }
+                               break;
+                       case IEEE80211_AUTH_AUTO:
+                               LINE_CHECK("authmode AUTO");
                                break;
                        default:
-                               printf(" UNKNOWN");
+                               LINE_CHECK("authmode UNKNOWN (0x%x)",
+                                       ireq.i_val);
                                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) {
-               printf("\twepmode");
-               switch (ireq.i_val) {
+               int firstkey, wepmode;
+
+               wepmode = ireq.i_val;
+               switch (wepmode) {
                        case IEEE80211_WEP_OFF:
-                               printf(" OFF");
+                               LINE_CHECK("privacy OFF");
                                break;
                        case IEEE80211_WEP_ON:
-                               printf(" ON");
+                               LINE_CHECK("privacy ON");
                                break;
                        case IEEE80211_WEP_MIXED:
-                               printf(" MIXED");
+                               LINE_CHECK("privacy MIXED");
                                break;
                        default:
-                               printf(" UNKNOWN");
+                               LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
                                break;
                }
 
@@ -491,7 +1555,10 @@ ieee80211_status (int s)
                        warn("WEP support, but no tx key!");
                        goto end;
                }
-               printf(" weptxkey %d", ireq.i_val+1);
+               if (ireq.i_val != -1)
+                       LINE_CHECK("deftxkey %d", ireq.i_val+1);
+               else if (wepmode != IEEE80211_WEP_OFF || verbose)
+                       LINE_CHECK("deftxkey UNDEF");
 
                ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
                if (ioctl(s, SIOCG80211, &ireq) < 0) {
@@ -500,28 +1567,227 @@ ieee80211_status (int s)
                }
                num = ireq.i_val;
 
-               printf("\n");
-
-               ireq.i_type = IEEE80211_IOC_WEPKEY;
-               spacer = '\t';
+               firstkey = 1;
                for (i = 0; i < num; i++) {
-                       ireq.i_val = i;
+                       struct ieee80211req_key ik;
+
+                       memset(&ik, 0, sizeof(ik));
+                       ik.ik_keyix = i;
+                       ireq.i_type = IEEE80211_IOC_WPAKEY;
+                       ireq.i_data = &ik;
+                       ireq.i_len = sizeof(ik);
                        if (ioctl(s, SIOCG80211, &ireq) < 0) {
                                warn("WEP support, but can get keys!");
                                goto end;
                        }
-                       if (ireq.i_len == 0 ||
-                           ireq.i_len > IEEE80211_KEYBUF_SIZE)
-                               continue;
-                       printf("%cwepkey %d:%s", spacer, i+1,
-                           ireq.i_len <= 5 ? "40-bit" :
-                           ireq.i_len <= 13 ? "104-bit" : "128-bit");
-                       if (spacer == '\t')
+                       if (ik.ik_keylen != 0) {
+                               if (verbose)
+                                       LINE_BREAK();
+                               printkey(&ik);
+                               firstkey = 0;
+                       }
+               }
+       }
+
+       ireq.i_type = IEEE80211_IOC_POWERSAVE;
+       if (ioctl(s, SIOCG80211, &ireq) != -1 &&
+           ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
+               if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
+                       switch (ireq.i_val) {
+                               case IEEE80211_POWERSAVE_OFF:
+                                       LINE_CHECK("powersavemode OFF");
+                                       break;
+                               case IEEE80211_POWERSAVE_CAM:
+                                       LINE_CHECK("powersavemode CAM");
+                                       break;
+                               case IEEE80211_POWERSAVE_PSP:
+                                       LINE_CHECK("powersavemode PSP");
+                                       break;
+                               case IEEE80211_POWERSAVE_PSP_CAM:
+                                       LINE_CHECK("powersavemode PSP-CAM");
+                                       break;
+                       }
+                       ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
+                       if (ioctl(s, SIOCG80211, &ireq) != -1)
+                               LINE_CHECK("powersavesleep %d", ireq.i_val);
+               }
+       }
+
+       ireq.i_type = IEEE80211_IOC_TXPOWMAX;
+       if (ioctl(s, SIOCG80211, &ireq) != -1)
+               LINE_CHECK("txpowmax %d", ireq.i_val);
+
+       if (verbose) {
+               ireq.i_type = IEEE80211_IOC_TXPOWER;
+               if (ioctl(s, SIOCG80211, &ireq) != -1)
+                       LINE_CHECK("txpower %d", ireq.i_val);
+       }
+
+       ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
+                       LINE_CHECK("rtsthreshold %d", ireq.i_val);
+       }
+
+       ireq.i_type = IEEE80211_IOC_MCAST_RATE;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               if (ireq.i_val != 2*1 || verbose) {
+                       if (ireq.i_val == 11)
+                               LINE_CHECK("mcastrate 5.5");
+                       else
+                               LINE_CHECK("mcastrate %d", ireq.i_val/2);
+               }
+       }
+
+       ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
+                       LINE_CHECK("fragthreshold %d", ireq.i_val);
+       }
+
+       if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
+               ireq.i_type = IEEE80211_IOC_PUREG;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                       if (ireq.i_val)
+                               LINE_CHECK("pureg");
+                       else if (verbose)
+                               LINE_CHECK("-pureg");
+               }
+               ireq.i_type = IEEE80211_IOC_PROTMODE;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                       switch (ireq.i_val) {
+                               case IEEE80211_PROTMODE_OFF:
+                                       LINE_CHECK("protmode OFF");
+                                       break;
+                               case IEEE80211_PROTMODE_CTS:
+                                       LINE_CHECK("protmode CTS");
+                                       break;
+                               case IEEE80211_PROTMODE_RTSCTS:
+                                       LINE_CHECK("protmode RTSCTS");
+                                       break;
+                               default:
+                                       LINE_CHECK("protmode UNKNOWN (0x%x)",
+                                               ireq.i_val);
+                                       break;
+                       }
+               }
+       }
+
+       ireq.i_type = IEEE80211_IOC_WME;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               wme = ireq.i_val;
+               if (wme)
+                       LINE_CHECK("wme");
+               else if (verbose)
+                       LINE_CHECK("-wme");
+       } else
+               wme = 0;
+
+       ireq.i_type = IEEE80211_IOC_BURST;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               if (ireq.i_val)
+                       LINE_CHECK("burst");
+               else if (verbose)
+                       LINE_CHECK("-burst");
+       }
+
+       if (opmode == IEEE80211_M_HOSTAP) {
+               ireq.i_type = IEEE80211_IOC_HIDESSID;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                       if (ireq.i_val)
+                               LINE_CHECK("ssid HIDE");
+                       else if (verbose)
+                               LINE_CHECK("ssid SHOW");
+               }
+
+               ireq.i_type = IEEE80211_IOC_APBRIDGE;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                       if (!ireq.i_val)
+                               LINE_CHECK("-apbridge");
+                       else if (verbose)
+                               LINE_CHECK("apbridge");
+               }
+
+               ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
+               if (ioctl(s, SIOCG80211, &ireq) != -1)
+                       LINE_CHECK("dtimperiod %u", ireq.i_val);
+       } else {
+               ireq.i_type = IEEE80211_IOC_ROAMING;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                       if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
+                               switch (ireq.i_val) {
+                               case IEEE80211_ROAMING_DEVICE:
+                                       LINE_CHECK("roaming DEVICE");
+                                       break;
+                               case IEEE80211_ROAMING_AUTO:
+                                       LINE_CHECK("roaming AUTO");
+                                       break;
+                               case IEEE80211_ROAMING_MANUAL:
+                                       LINE_CHECK("roaming MANUAL");
+                                       break;
+                               default:
+                                       LINE_CHECK("roaming UNKNOWN (0x%x)",
+                                               ireq.i_val);
+                                       break;
+                               }
+                       }
+               }
+       }
+       ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
+       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               if (ireq.i_val)
+                       LINE_CHECK("bintval %u", ireq.i_val);
+               else if (verbose)
+                       LINE_CHECK("bintval %u", ireq.i_val);
+       }
+
+       if (wme && verbose) {
+               LINE_BREAK();
+               list_wme(s);
+       }
+
+       if (wpa) {
+               ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                       if (ireq.i_val)
+                               LINE_CHECK("countermeasures");
+                       else if (verbose)
+                               LINE_CHECK("-countermeasures");
+               }
+#if 0
+               /* XXX not interesting with WPA done in user space */
+               ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+               }
+
+               ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                       LINE_CHECK("mcastcipher ");
+                       printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
+                       spacer = ' ';
+               }
+
+               ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                       LINE_CHECK("ucastcipher ");
+                       printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
+               }
+
+               if (wpa & 2) {
+                       ireq.i_type = IEEE80211_IOC_RSNCAPS;
+                       if (ioctl(s, SIOCG80211, &ireq) != -1) {
+                               LINE_CHECK("RSN caps 0x%x", ireq.i_val);
                                spacer = ' ';
+                       }
+               }
+
+               ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
+               if (ioctl(s, SIOCG80211, &ireq) != -1) {
                }
-               if (spacer == ' ')
-                       printf("\n");
+#endif
+               LINE_BREAK();
        }
+       LINE_BREAK();
 
 end:
        return;
@@ -532,8 +1798,8 @@ 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;
@@ -645,8 +1911,47 @@ static struct cmd ieee80211_cmds[] = {
        DEF_CMD_ARG("rtsthreshold",     set80211rtsthreshold),
        DEF_CMD_ARG("protmode",         set80211protmode),
        DEF_CMD_ARG("txpower",          set80211txpower),
+       DEF_CMD_ARG("roaming",          set80211roaming),
+       DEF_CMD("wme",          1,      set80211wme),
+       DEF_CMD("-wme",         0,      set80211wme),
+       DEF_CMD("hidessid",     1,      set80211hidessid),
+       DEF_CMD("-hidessid",    0,      set80211hidessid),
+       DEF_CMD("apbridge",     1,      set80211apbridge),
+       DEF_CMD("-apbridge",    0,      set80211apbridge),
+       DEF_CMD_ARG("chanlist",         set80211chanlist),
+       DEF_CMD_ARG("bssid",            set80211bssid),
+       DEF_CMD_ARG("ap",               set80211bssid),
+       DEF_CMD("scan", 0,              set80211scan),
+       DEF_CMD_ARG("list",             set80211list),
+       DEF_CMD_ARG2("cwmin",           set80211cwmin),
+       DEF_CMD_ARG2("cwmax",           set80211cwmax),
+       DEF_CMD_ARG2("aifs",            set80211aifs),
+       DEF_CMD_ARG2("txoplimit",       set80211txoplimit),
+       DEF_CMD_ARG("acm",              set80211acm),
+       DEF_CMD_ARG("-acm",             set80211noacm),
+       DEF_CMD_ARG("ack",              set80211ackpolicy),
+       DEF_CMD_ARG("-ack",             set80211noackpolicy),
+       DEF_CMD_ARG2("bss:cwmin",       set80211bsscwmin),
+       DEF_CMD_ARG2("bss:cwmax",       set80211bsscwmax),
+       DEF_CMD_ARG2("bss:aifs",        set80211bssaifs),
+       DEF_CMD_ARG2("bss:txoplimit",   set80211bsstxoplimit),
+       DEF_CMD_ARG("dtimperiod",       set80211dtimperiod),
+       DEF_CMD_ARG("bintval",          set80211bintval),
+       DEF_CMD("mac:open",     IEEE80211_MACCMD_POLICY_OPEN,   set80211maccmd),
+       DEF_CMD("mac:allow",    IEEE80211_MACCMD_POLICY_ALLOW,  set80211maccmd),
+       DEF_CMD("mac:deny",     IEEE80211_MACCMD_POLICY_DENY,   set80211maccmd),
+       DEF_CMD("mac:flush",    IEEE80211_MACCMD_FLUSH,         set80211maccmd),
+       DEF_CMD("mac:detach",   IEEE80211_MACCMD_DETACH,        set80211maccmd),
+       DEF_CMD_ARG("mac:add",          set80211addmac),
+       DEF_CMD_ARG("mac:del",          set80211delmac),
+       DEF_CMD_ARG("mac:kick",         set80211kickmac),
+       DEF_CMD("pureg",        1,      set80211pureg),
+       DEF_CMD("-pureg",       0,      set80211pureg),
+       DEF_CMD_ARG("mcastrate",        set80211mcastrate),
+       DEF_CMD_ARG("fragthreshold",    set80211fragthreshold),
+       DEF_CMD("burst",        1,      set80211burst),
+       DEF_CMD("-burst",       0,      set80211burst),
 };
-
 static struct afswtch af_ieee80211 = {
        .af_name        = "af_ieee80211",
        .af_af          = AF_UNSPEC,
index b7c0818..5cf83d8 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/sys/conf/files,v 1.120 2006/05/12 22:07:21 dillon Exp $
+# $DragonFly: src/sys/conf/files,v 1.121 2006/05/18 13:51:45 sephe Exp $
 #
 # The long compile-with and dependency lines are required because of
 # limitations in config: backslash-newline doesn't work in strings, and
@@ -709,13 +709,20 @@ net/route.c               standard
 net/rtsock.c           standard
 net/zlib.c             optional ppp_deflate
 net/zlib.c             optional ipsec
-netproto/802_11/ieee80211.c            optional wlan
-netproto/802_11/ieee80211_crypto.c     optional wlan
-netproto/802_11/ieee80211_input.c      optional wlan
-netproto/802_11/ieee80211_ioctl.c      optional wlan
-netproto/802_11/ieee80211_node.c       optional wlan
-netproto/802_11/ieee80211_output.c     optional wlan
-netproto/802_11/ieee80211_proto.c      optional wlan
+netproto/802_11/wlan/ieee80211.c                       optional wlan
+netproto/802_11/wlan/ieee80211_crypto.c                        optional wlan
+netproto/802_11/wlan/ieee80211_crypto_none.c           optional wlan
+netproto/802_11/wlan/ieee80211_dragonfly.c             optional wlan
+netproto/802_11/wlan/ieee80211_input.c                 optional wlan
+netproto/802_11/wlan/ieee80211_ioctl.c                 optional wlan
+netproto/802_11/wlan/ieee80211_node.c                  optional wlan
+netproto/802_11/wlan/ieee80211_output.c                        optional wlan
+netproto/802_11/wlan/ieee80211_proto.c                 optional wlan
+netproto/802_11/wlan_acl/ieee80211_acl.c               optional wlan_acl
+netproto/802_11/wlan_ccmp/ieee80211_crypto_ccmp.c      optional wlan_ccmp
+netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c      optional wlan_tkip
+netproto/802_11/wlan_wep/ieee80211_crypto_wep.c                optional wlan_wep
+netproto/802_11/wlan_xauth/ieee80211_xauth.c           optional wlan_xauth
 netproto/atalk/aarp.c          optional netatalk
 netproto/atalk/at_control.c    optional netatalk
 netproto/atalk/at_proto.c      optional netatalk
index a2d8229..5366114 100644 (file)
@@ -4,7 +4,7 @@
 # Check the LINT configuration file in sys/i386/conf, for an
 # exhaustive list of options.
 #
-# $DragonFly: src/sys/config/GENERIC,v 1.33 2006/05/11 08:23:20 swildner Exp $
+# $DragonFly: src/sys/config/GENERIC,v 1.34 2006/05/18 13:51:45 sephe Exp $
 
 machine                i386
 cpu            I386_CPU
@@ -214,20 +214,24 @@ device            ep
 device         fe0     at isa? disable port 0x300
 # Xircom Ethernet
 device         xe
-# Generic 802.11 stack, used by wi
-device         wlan
-# PRISM I IEEE 802.11b wireless NIC.
-device         awi
-# WaveLAN/IEEE 802.11 wireless NICs. Note: the WaveLAN/IEEE really
-# exists only as a PCMCIA device, so there is no ISA attachment needed
-# and resources will always be dynamically assigned by the pccard code.
-device         wi
-# Aironet 4500/4800 802.11 wireless NICs. Note: the declaration below will
+
+# Wireless NIC cards
+device         wlan            # 802.11 support
+device         wlan_ccmp       # 802.11 CCMP support
+device         wlan_tkip       # 802.11 TKIP support
+device         wlan_wep        # 802.11 WEP support
+# Aironet 4500/4800 802.11 wireless NICs.  Note: the declaration below will
 # work for PCMCIA and PCI cards, as well as ISA cards set to ISA PnP
 # mode (the factory default). If you set the switches on your ISA
 # card for a manually chosen I/O address and IRQ, you must specify
 # those parameters here.
 device         an
+#device                awi             # PRISM I IEEE 802.11b wireless NIC
+# WaveLAN/IEEE 802.11 wireless NICs.  Note: the WaveLAN/IEEE really
+# exists only as a PCMCIA device, so there is no ISA attachment needed
+# and resources will always be dynamically assigned by the pccard code.
+device         wi
+
 # The probe order of these is presently determined by i386/isa/isa_compat.c.
 device         ie0     at isa? disable port 0x300 irq 10 iomem 0xd0000
 #device                le0     at isa? disable port 0x300 irq 5 iomem 0xd0000
index 3faa1e3..ed15334 100644 (file)
@@ -3,7 +3,7 @@
 #      as much of the source tree as it can.
 #
 # $FreeBSD: src/sys/i386/conf/LINT,v 1.749.2.144 2003/06/04 17:56:59 sam Exp $
-# $DragonFly: src/sys/config/LINT,v 1.75 2006/05/14 18:07:29 swildner Exp $
+# $DragonFly: src/sys/config/LINT,v 1.76 2006/05/18 13:51:45 sephe Exp $
 #
 # NB: You probably don't want to try running a kernel built from this
 # file.  Instead, you should start from GENERIC, and add options from
@@ -1411,10 +1411,15 @@ device sr0 at isa? port 0x300 irq 5 iomem 0xd0000
 device sn0 at isa? port 0x300 irq 10
 
 # Wlan support is mandatory for some wireless LAN devices.
-device         wlan            # Wireless LAN support
+device         wlan            # 802.11 support
+device         wlan_acl        # 802.11 MAC-based access control for AP
+device         wlan_ccmp       # 802.11 CCMP support
+device         wlan_tkip       # 802.11 TKIP support
+device         wlan_wep        # 802.11 WEP support
+device         wlan_xauth      # 802.11 WPA or 802.1x authentication for AP
 options        WLCACHE         # enables the signal-strength cache
 options        WLDEBUG         # enables verbose debugging output
-device         awi             # AMD PCnetMobile
+#device                awi             # AMD PCnetMobile
 device         an              # Aironet Communications 4500/4800
 device         ipw             # Intel PRO/Wireless 2100
 device         iwi             # Intel PRO/Wireless 2200BG/2915ABG
index bd72442..a43f49c 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/dev/netif/acx/acx100.c,v 1.1 2006/04/01 02:55:36 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/acx/acx100.c,v 1.2 2006/05/18 13:51:45 sephe Exp $
  */
 
 #include <sys/param.h>
@@ -260,8 +260,8 @@ static void acx100_set_fw_txdesc_rate(struct acx_softc *,
                                          struct acx_txbuf *, int);
 static void    acx100_set_bss_join_param(struct acx_softc *, void *, int);
 
-static int     acx100_set_wepkey(struct acx_softc *,
-                                 struct ieee80211_wepkey *, int);
+static int     acx100_set_wepkey(struct acx_softc *, struct ieee80211_key *,
+                                 int);
 
 static void    acx100_proc_wep_rxbuf(struct acx_softc *, struct mbuf *, int *);
 
@@ -696,20 +696,20 @@ acx100_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
 }
 
 static int
-acx100_set_wepkey(struct acx_softc *sc, struct ieee80211_wepkey *wk, int wk_idx)
+acx100_set_wepkey(struct acx_softc *sc, struct ieee80211_key *wk, int wk_idx)
 {
        struct acx100_conf_wepkey conf_wk;
 
-       if (wk->wk_len > ACX100_WEPKEY_LEN) {
+       if (wk->wk_keylen > ACX100_WEPKEY_LEN) {
                if_printf(&sc->sc_ic.ic_if, "%dth WEP key size beyond %d\n",
                          wk_idx, ACX100_WEPKEY_LEN);
                return EINVAL;
        }
 
        conf_wk.action = ACX100_WEPKEY_ACT_ADD;
-       conf_wk.key_len = wk->wk_len;
+       conf_wk.key_len = wk->wk_keylen;
        conf_wk.key_idx = wk_idx;
-       bcopy(wk->wk_key, conf_wk.key, wk->wk_len);
+       bcopy(wk->wk_key, conf_wk.key, wk->wk_keylen);
        if (acx100_set_wepkey_conf(sc, &conf_wk) != 0) {
                if_printf(&sc->sc_ic.ic_if, "%s set %dth WEP key failed\n",
                          __func__, wk_idx);
index e381c2d..84549a3 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/dev/netif/acx/acx111.c,v 1.1 2006/04/01 02:55:36 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/acx/acx111.c,v 1.2 2006/05/18 13:51:45 sephe Exp $
  */
 
 #include <sys/param.h>
@@ -274,8 +274,8 @@ static void acx111_set_fw_txdesc_rate(struct acx_softc *,
                                          struct acx_txbuf *, int);
 static void    acx111_set_bss_join_param(struct acx_softc *, void *, int);
 
-static int     acx111_set_wepkey(struct acx_softc *,
-                                 struct ieee80211_wepkey *, int);
+static int     acx111_set_wepkey(struct acx_softc *, struct ieee80211_key *,
+                                 int);
 
 void
 acx111_set_param(device_t dev)
@@ -478,11 +478,11 @@ acx111_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
 }
 
 static int
-acx111_set_wepkey(struct acx_softc *sc, struct ieee80211_wepkey *wk, int wk_idx)
+acx111_set_wepkey(struct acx_softc *sc, struct ieee80211_key *wk, int wk_idx)
 {
        struct acx111_wepkey wepkey;
 
-       if (wk->wk_len > ACX111_WEPKEY_LEN) {
+       if (wk->wk_keylen > ACX111_WEPKEY_LEN) {
                if_printf(&sc->sc_ic.ic_if, "%dth WEP key size beyond %d\n",
                          wk_idx, ACX111_WEPKEY_LEN);
                return EINVAL;
@@ -492,9 +492,9 @@ acx111_set_wepkey(struct acx_softc *sc, struct ieee80211_wepkey *wk, int wk_idx)
        wepkey.action = htole16(ACX111_WEPKEY_ACT_ADD);
        wepkey.key_type = ACX111_WEPKEY_TYPE_DEFAULT;
        wepkey.index = 0; /* XXX ignored? */
-       wepkey.key_len = wk->wk_len;
+       wepkey.key_len = wk->wk_keylen;
        wepkey.key_idx = wk_idx;
-       bcopy(wk->wk_key, wepkey.key, wk->wk_len);
+       bcopy(wk->wk_key, wepkey.key, wk->wk_keylen);
        if (acx_exec_command(sc, ACXCMD_WEP_MGMT, &wepkey, sizeof(wepkey),
                             NULL, 0) != 0) {
                if_printf(&sc->sc_ic.ic_if, "%s set %dth WEP key failed\n",
index 62824bb..caef1a4 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/dev/netif/acx/acxcmd.c,v 1.1 2006/04/01 02:55:36 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/acx/acxcmd.c,v 1.2 2006/05/18 13:51:45 sephe Exp $
  */
 
 #include <sys/param.h>
@@ -155,6 +155,7 @@ acx_join_bss(struct acx_softc *sc, uint8_t mode, struct ieee80211_node *node)
        bj->esslen = node->ni_esslen;
        bcopy(node->ni_essid, bj->essid, node->ni_esslen);
 
+       DPRINTF((&sc->sc_ic.ic_if, "join BSS/IBSS on channel %d\n", bj->channel));
        return acx_exec_command(sc, ACXCMD_JOIN_BSS,
                                bj, BSS_JOIN_PARAM_SIZE(bj), NULL, 0);
 }
index 2b14dd0..975987f 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/dev/netif/acx/if_acx.c,v 1.1 2006/04/01 02:55:36 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/acx/if_acx.c,v 1.2 2006/05/18 13:51:45 sephe Exp $
  */
 
 /*
@@ -142,7 +142,9 @@ static int  acx_config(struct acx_softc *);
 static int     acx_read_config(struct acx_softc *, struct acx_config *);
 static int     acx_write_config(struct acx_softc *, struct acx_config *);
 static int     acx_set_wepkeys(struct acx_softc *);
+#ifdef foo
 static void    acx_begin_scan(struct acx_softc *);
+#endif
 static void    acx_next_scan(void *);
 
 static void    acx_start(struct ifnet *);
@@ -163,7 +165,7 @@ static int  acx_init_tx_ring(struct acx_softc *);
 static int     acx_init_rx_ring(struct acx_softc *);
 static int     acx_newbuf(struct acx_softc *, struct acx_rxbuf *, int);
 static int     acx_encap(struct acx_softc *, struct acx_txbuf *,
-                         struct mbuf *, struct acx_node *, int);
+                         struct mbuf *, struct ieee80211_node *, int);
 
 static int     acx_reset(struct acx_softc *);
 
@@ -186,16 +188,12 @@ static int        acx_load_radio_firmware(struct acx_softc *, const uint8_t *,
 static int     acx_load_base_firmware(struct acx_softc *, const uint8_t *,
                                       uint32_t);
 
-static struct ieee80211_node *acx_node_alloc(struct ieee80211com *);
-static void    acx_node_free(struct ieee80211com *, struct ieee80211_node *);
+static struct ieee80211_node *acx_node_alloc(struct ieee80211_node_table *);
 static void    acx_node_init(struct acx_softc *, struct acx_node *);
 static void    acx_node_update(struct acx_softc *, struct acx_node *,
                                uint8_t, uint8_t);
 static int     acx_newstate(struct ieee80211com *, enum ieee80211_state, int);
 
-/* XXX */
-static void    acx_media_status(struct ifnet *, struct ifmediareq *);
-
 static int     acx_sysctl_txrate_upd_intvl_min(SYSCTL_HANDLER_ARGS);
 static int     acx_sysctl_txrate_upd_intvl_max(SYSCTL_HANDLER_ARGS);
 static int     acx_sysctl_txrate_sample_thresh(SYSCTL_HANDLER_ARGS);
@@ -425,17 +423,16 @@ acx_attach(device_t dev)
                                        &ic->ic_myaddr[i]);
        }
 
-       ieee80211_ifattach(ifp);
+       ieee80211_ifattach(ic);
 
-       /* Override alloc/free */
+       /* Override node alloc */
        ic->ic_node_alloc = acx_node_alloc;
-       ic->ic_node_free = acx_node_free;
 
        /* Override newstate */
        sc->sc_newstate = ic->ic_newstate;
        ic->ic_newstate = acx_newstate;
 
-       ieee80211_media_init(ifp, ieee80211_media_change, acx_media_status);
+       ieee80211_media_init(ic, ieee80211_media_change, ieee80211_media_status);
 
        sc->sc_txrate_upd_intvl_min = 10;       /* 10 seconds */
        sc->sc_txrate_upd_intvl_max = 300;      /* 5 minutes */
@@ -503,9 +500,12 @@ acx_attach(device_t dev)
                goto fail1;
        }
 
+       if (bootverbose)
+               ieee80211_announce(ic);
+
        return 0;
 fail1:
-       ieee80211_ifdetach(ifp);
+       ieee80211_ifdetach(ic);
 fail:
        acx_detach(dev);
        return error;
@@ -517,7 +517,8 @@ acx_detach(device_t dev)
        struct acx_softc *sc = device_get_softc(dev);
 
        if (device_is_attached(dev)) {
-               struct ifnet *ifp = &sc->sc_ic.ic_if;
+               struct ieee80211com *ic = &sc->sc_ic;
+               struct ifnet *ifp = &ic->ic_if;
 
                lwkt_serialize_enter(ifp->if_serializer);
 
@@ -527,7 +528,7 @@ acx_detach(device_t dev)
 
                lwkt_serialize_exit(ifp->if_serializer);
 
-               ieee80211_ifdetach(ifp);
+               ieee80211_ifdetach(ic);
        }
 
        if (sc->sc_sysctl_tree != NULL)
@@ -629,10 +630,11 @@ acx_init(void *arg)
                goto back;
 
        /* Setup WEP */
-       if (sc->sc_ic.ic_flags & IEEE80211_WEP_ON) {
+       if (sc->sc_ic.ic_flags & IEEE80211_F_PRIVACY) {
                error = acx_set_wepkeys(sc);
                if (error)
                        goto back;
+               sc->sc_ic.ic_flags &= ~IEEE80211_F_DROPUNENC;
        }
 
        /* Turn on power led */
@@ -644,7 +646,12 @@ acx_init(void *arg)
        ifp->if_flags &= ~IFF_OACTIVE;
 
        /* Begin background scanning */
+#ifdef foo
        acx_begin_scan(sc);
+#else
+       ieee80211_new_state(&sc->sc_ic, IEEE80211_S_SCAN, -1);
+#endif
+
 back:
        if (error)
                acx_stop(sc);
@@ -662,21 +669,28 @@ acx_set_wepkeys(struct acx_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct acx_conf_wep_txkey wep_txkey;
-       int i, error;
+       int i, error, got_wk = 0;
 
        for (i = 0; i < IEEE80211_WEP_NKID; ++i) {
-               struct ieee80211_wepkey *wk = &ic->ic_nw_keys[i];
+               struct ieee80211_key *wk = &ic->ic_nw_keys[i];
 
-               if (wk->wk_len == 0)
+               if (wk->wk_keylen == 0)
                        continue;
 
                error = sc->chip_set_wepkey(sc, wk, i);
                if (error)
                        return error;
+
+               if (sc->sc_softwep && (wk->wk_flags & IEEE80211_KEY_XMIT))
+                       wk->wk_flags |= IEEE80211_KEY_SWCRYPT;
+               got_wk = 1;
        }
 
+       if (!got_wk || ic->ic_def_txkey == IEEE80211_KEYIX_NONE)
+               return 0;
+
        /* Set current WEP key index */
-       wep_txkey.wep_txkey = ic->ic_wep_txkey;
+       wep_txkey.wep_txkey = ic->ic_def_txkey;
        if (acx_set_wep_txkey_conf(sc, &wep_txkey) != 0) {
                if_printf(&ic->ic_if, "set WEP txkey failed\n");
                return ENXIO;
@@ -684,13 +698,14 @@ acx_set_wepkeys(struct acx_softc *sc)
        return 0;
 }
 
+#ifdef foo
 static void
 acx_begin_scan(struct acx_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        uint8_t chan;
 
-       ieee80211_begin_scan(&ic->ic_if);
+       ieee80211_begin_scan(ic, 1);
 
        chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
 
@@ -701,6 +716,7 @@ acx_begin_scan(struct acx_softc *sc)
        callout_reset(&sc->sc_chanscan_timer, hz / acx_chanscan_rate,
                      acx_next_scan, sc);
 }
+#endif
 
 static void
 acx_next_scan(void *arg)
@@ -712,10 +728,13 @@ acx_next_scan(void *arg)
        lwkt_serialize_enter(ifp->if_serializer);
 
        if (ic->ic_state == IEEE80211_S_SCAN) {
+#if 0
                uint8_t chan;
+#endif
 
-               ieee80211_next_scan(ifp);
+               ieee80211_next_scan(ic);
 
+#if 0
                chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
 
                ACX_ENABLE_TXCHAN(sc, chan);
@@ -723,6 +742,7 @@ acx_next_scan(void *arg)
 
                callout_reset(&sc->sc_chanscan_timer, hz / acx_chanscan_rate,
                              acx_next_scan, sc);
+#endif
        }
 
        lwkt_serialize_exit(ifp->if_serializer);
@@ -768,13 +788,13 @@ acx_stop(struct acx_softc *sc)
                if (buf->tb_mbuf != NULL) {
                        bus_dmamap_unload(bd->mbuf_dma_tag,
                                          buf->tb_mbuf_dmamap);
-                       m_free(buf->tb_mbuf);
+                       m_freem(buf->tb_mbuf);
                        buf->tb_mbuf = NULL;
                }
 
                ni = (struct ieee80211_node *)buf->tb_node;
-               if (ni != NULL && ni != ic->ic_bss)
-                       ieee80211_free_node(ic, ni);
+               if (ni != NULL)
+                       ieee80211_free_node(ni);
                buf->tb_node = NULL;
        }
 
@@ -786,7 +806,7 @@ acx_stop(struct acx_softc *sc)
                if (bd->rx_buf[i].rb_mbuf != NULL) {
                        bus_dmamap_unload(bd->mbuf_dma_tag,
                                          bd->rx_buf[i].rb_mbuf_dmamap);
-                       m_free(bd->rx_buf[i].rb_mbuf);
+                       m_freem(bd->rx_buf[i].rb_mbuf);
                        bd->rx_buf[i].rb_mbuf = NULL;
                }
        }
@@ -1021,14 +1041,14 @@ acx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
 
        switch (cmd) {
        case SIOCSLOADFW:
-               error = suser(curthread);
+               error = suser_cred(cr, NULL_CRED_OKAY);
                if (error)
                        break;
 
                error = acx_copyin_firmware(sc, req);
                break;
        case SIOCSKILLFW:
-               error = suser(curthread);
+               error = suser_cred(cr, NULL_CRED_OKAY);
                if (error)
                        break;
                acx_free_firmware(sc);
@@ -1063,7 +1083,7 @@ acx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                /* TODO */
                break;
        default:
-               error = ieee80211_ioctl(ifp, cmd, data, cr);
+               error = ieee80211_ioctl(&sc->sc_ic, cmd, data, cr);
                break;
        }
 
@@ -1076,18 +1096,6 @@ acx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
        return error;
 }
 
-static __inline struct mbuf *
-acx_softwep(struct ieee80211com *ic, struct mbuf *m, struct acx_node *node)
-{
-       m = ieee80211_wep_crypt(&ic->ic_if, m, 1);
-       if (m != NULL)
-               return m;
-
-       if (node != NULL && (struct ieee80211_node *)node != ic->ic_bss)
-               ieee80211_free_node(ic, (struct ieee80211_node *)node);
-       return NULL;
-}
-
 static void
 acx_start(struct ifnet *ifp)
 {
@@ -1114,70 +1122,70 @@ acx_start(struct ifnet *ifp)
        trans = 0;
        for (buf = &bd->tx_buf[idx]; buf->tb_mbuf == NULL;
             buf = &bd->tx_buf[idx]) {
-               struct acx_node *node;
+               struct ieee80211_frame *f;
+               struct ieee80211_node *ni = NULL;
                struct mbuf *m;
                int rate;
 
-               node = NULL;
                if (!IF_QEMPTY(&ic->ic_mgtq)) {
-                       struct ieee80211_node *ni;
-
                        IF_DEQUEUE(&ic->ic_mgtq, m);
 
                        ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
                        m->m_pkthdr.rcvif = NULL;
 
+#if 0
                        /*
                         * Since mgmt data are transmitted at fixed rate
                         * they will not be used to do rate control.
                         */
-                       if (ni && ni != ic->ic_bss)
-                               ieee80211_free_node(ic, ni);
-
+                       if (ni != NULL)
+                               ieee80211_free_node(ni);
+#endif
                        rate = 4;       /* XXX 2Mb/s for mgmt packet */
                } else if (!ifq_is_empty(&ifp->if_snd)) {
-                       struct ieee80211_frame *f;
+                       struct ether_header *eh;
+                       struct acx_node *node;
 
-                       /* XXX */
-#if 0
                        if (ic->ic_state != IEEE80211_S_RUN) {
                                if_printf(ifp, "data packet dropped due to "
                                          "not RUN.  Current state %d\n",
                                          ic->ic_state);
                                break;
                        }
-#endif
 
                        m = ifq_dequeue(&ifp->if_snd, NULL);
                        if (m == NULL)
                                break;
 
-                       m = ieee80211_encap(ifp, m,
-                                           (struct ieee80211_node **)&node);
-                       if (m == NULL) {
+                       if (m->m_len < sizeof(struct ether_header)) {
+                               m = m_pullup(m, sizeof(struct ether_header));
+                               if (m == NULL) {
+                                       ifp->if_oerrors++;
+                                       continue;
+                               }
+                       }
+                       eh = mtod(m, struct ether_header *);
+
+                       ni = ieee80211_find_txnode(ic, eh->ether_dhost);
+                       if (ni == NULL) {
+                               m_freem(m);
                                ifp->if_oerrors++;
                                continue;
                        }
-                       f = mtod(m, struct ieee80211_frame *);
 
-                       if (ic->ic_flags & IEEE80211_F_WEPON) {
-                               f->i_fc[1] |= IEEE80211_FC1_WEP;
-                               if (sc->sc_softwep) {
-                                       m = acx_softwep(ic, m, node);
-                                       if (m == NULL) {
-                                               /*
-                                                * axc_softwep() will free
-                                                * `node' for us if it fails
-                                                */
-                                               ifp->if_oerrors++;
-                                               node = NULL;
-                                               continue;
-                                       }
-                               }
+                       /* TODO power save */
+
+                       m = ieee80211_encap(ic, m, ni);
+                       if (m == NULL) {
+                               ieee80211_free_node(ni);
+                               ifp->if_oerrors++;
+                               continue;
                        }
 
+                       node = (struct acx_node *)ni;
                        if (node->nd_txrate < 0) {
                                acx_node_init(sc, node);
+#if 0
                                if (ic->ic_opmode == IEEE80211_M_IBSS) {
                                        /* XXX
                                         * Add extra reference here,
@@ -1186,9 +1194,9 @@ acx_start(struct ifnet *ifp)
                                         * they are allocated, which
                                         * make TX rate control impossible
                                         */
-                                       ieee80211_ref_node(
-                                               (struct ieee80211_node *)node);
+                                       ieee80211_ref_node(ni);
                                }
+#endif
                        }
 
                        rate = node->nd_rates.rs_rates[node->nd_txrate];
@@ -1198,16 +1206,27 @@ acx_start(struct ifnet *ifp)
                        break;
                }
 
+               f = mtod(m, struct ieee80211_frame *);
+               if ((f->i_fc[1] & IEEE80211_FC1_WEP) && sc->sc_softwep) {
+                       KASSERT(ni != NULL, ("TX node is NULL (WEP)\n"));
+                       if (ieee80211_crypto_encap(ic, ni, m) == NULL) {
+                               ieee80211_free_node(ni);
+                               m_freem(m);
+                               ifp->if_oerrors++;
+                               continue;
+                       }
+               }
+
                if (ic->ic_rawbpf != NULL)
                        bpf_mtap(ic->ic_rawbpf, m);
 
-               if (acx_encap(sc, buf, m, node, rate) != 0) {
-                       struct ieee80211_node *ni;
-
-                       ni = (struct ieee80211_node *)node;
-                       if (ni != NULL && ni != ic->ic_bss)
-                               ieee80211_free_node(ic, ni);
-
+               if (acx_encap(sc, buf, m, ni, rate) != 0) {
+                       /*
+                        * NOTE: `m' will be freed in acx_encap()
+                        * if we reach here.
+                        */
+                       if (ni != NULL)
+                               ieee80211_free_node(ni);
                        ifp->if_oerrors++;
                        continue;
                }
@@ -1310,7 +1329,7 @@ acx_txeof(struct acx_softc *sc)
                        break;
 
                bus_dmamap_unload(bd->mbuf_dma_tag, buf->tb_mbuf_dmamap);
-               m_free(buf->tb_mbuf);
+               m_freem(buf->tb_mbuf);
                buf->tb_mbuf = NULL;
 
                error = FW_TXDESC_GETFIELD_1(sc, buf, f_tx_error);
@@ -1329,8 +1348,7 @@ acx_txeof(struct acx_softc *sc)
                        ni = (struct ieee80211_node *)buf->tb_node;
 
                        acx_node_update(sc, buf->tb_node, buf->tb_rate, error);
-                       if (ni != ic->ic_bss)
-                               ieee80211_free_node(ic, ni);
+                       ieee80211_free_node(ni);
                        buf->tb_node = NULL;
                }
 
@@ -1497,37 +1515,30 @@ acx_rxeof(struct acx_softc *sc)
                                 sc->chip_rxbuf_exhdr);
                        f = mtod(m, struct ieee80211_frame *);
 
-                       if (ic->ic_opmode == IEEE80211_M_STA) {
-                               ni = ieee80211_ref_node(ic->ic_bss);
-                       } else {
-                               ni = ieee80211_find_node(ic, f->i_addr2);
-                               if (ni == NULL)
-                                       ni = ieee80211_ref_node(ic->ic_bss);
-                       }
-
                        if (f->i_fc[1] & IEEE80211_FC1_WEP) {
                                /* Short circuit software WEP */
                                f->i_fc[1] &= ~IEEE80211_FC1_WEP;
 
                                /* Do chip specific RX buffer processing */
-                               if (sc->chip_proc_wep_rxbuf != NULL)
+                               if (sc->chip_proc_wep_rxbuf != NULL) {
                                        sc->chip_proc_wep_rxbuf(sc, m, &len);
+                                       f = mtod(m, struct ieee80211_frame *);
+                               }
                        }
 
+                       ni = ieee80211_find_rxnode(ic,
+                               (struct ieee80211_frame_min *)f);
+
                        m->m_len = m->m_pkthdr.len = len;
                        m->m_pkthdr.rcvif = &ic->ic_if;
 
-                       ieee80211_input(&ic->ic_if, m, ni, head->rbh_level,
+                       ieee80211_input(ic, m, ni, head->rbh_level,
                                        le32toh(head->rbh_time));
 
-                       if (ni == ic->ic_bss)
-                               ieee80211_unref_node(&ni);
-                       else
-                               ieee80211_free_node(ic, ni);
-
+                       ieee80211_free_node(ni);
                        ifp->if_ipackets++;
                } else {
-                       m_free(m);
+                       m_freem(m);
                        ifp->if_ierrors++;
                }
 
@@ -1842,15 +1853,12 @@ acx_load_firmware(struct acx_softc *sc, uint32_t offset, const uint8_t *data,
        return 0;
 }
 
-MALLOC_DECLARE(ACX_NODE);
-MALLOC_DEFINE(ACX_NODE, "acx_node", "acx(4) wrapper for ieee80211_node");
-
 static struct ieee80211_node *
-acx_node_alloc(struct ieee80211com *ic)
+acx_node_alloc(struct ieee80211_node_table *nt __unused)
 {
        struct acx_node *node;
 
-       node = malloc(sizeof(struct acx_node), ACX_NODE, M_NOWAIT | M_ZERO);
+       node = malloc(sizeof(struct acx_node), M_80211_NODE, M_NOWAIT | M_ZERO);
        node->nd_txrate = -1;
        return (struct ieee80211_node *)node;
 }
@@ -2008,12 +2016,6 @@ acx_node_update(struct acx_softc *sc, struct acx_node *node, uint8_t rate,
 #undef IEEERATE
 }
 
-static void
-acx_node_free(struct ieee80211com *ic, struct ieee80211_node *n)
-{
-       free(n, ACX_NODE);
-}
-
 static int
 acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
 {
@@ -2023,6 +2025,19 @@ acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
        ASSERT_SERIALIZED(ic->ic_if.if_serializer);
 
        switch (nstate) {
+       case IEEE80211_S_SCAN:
+               if (ic->ic_state != IEEE80211_S_INIT) {
+                       uint8_t chan;
+
+                       chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
+                       ACX_ENABLE_TXCHAN(sc, chan);
+                       ACX_ENABLE_RXCHAN(sc, chan);
+
+                       callout_reset(&sc->sc_chanscan_timer,
+                                     hz / acx_chanscan_rate,
+                                     acx_next_scan, sc);
+               }
+               break;
        case IEEE80211_S_AUTH:
                if (ic->ic_opmode == IEEE80211_M_STA) {
                        struct ieee80211_node *ni;
@@ -2301,7 +2316,7 @@ acx_dma_free(struct acx_softc *sc)
                        if (bd->rx_buf[i].rb_mbuf != NULL) {
                                bus_dmamap_unload(bd->mbuf_dma_tag,
                                                  bd->rx_buf[i].rb_mbuf_dmamap);
-                               m_free(bd->rx_buf[i].rb_mbuf);
+                               m_freem(bd->rx_buf[i].rb_mbuf);
                        }
                        bus_dmamap_destroy(bd->mbuf_dma_tag,
                                           bd->rx_buf[i].rb_mbuf_dmamap);
@@ -2313,7 +2328,7 @@ acx_dma_free(struct acx_softc *sc)
                        if (bd->tx_buf[i].tb_mbuf != NULL) {
                                bus_dmamap_unload(bd->mbuf_dma_tag,
                                                  bd->tx_buf[i].tb_mbuf_dmamap);
-                               m_free(bd->tx_buf[i].tb_mbuf);
+                               m_freem(bd->tx_buf[i].tb_mbuf);
                        }
                        bus_dmamap_destroy(bd->mbuf_dma_tag,
                                           bd->tx_buf[i].tb_mbuf_dmamap);
@@ -2425,7 +2440,7 @@ acx_newbuf(struct acx_softc *sc, struct acx_rxbuf *rb, int wait)
                                     m, acx_buf_dma_addr, &paddr,
                                     wait ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT);
        if (error) {
-               m_free(m);
+               m_freem(m);
                if_printf(&sc->sc_ic.ic_if, "can't map rx mbuf %d\n", error);
                return error;
        }
@@ -2449,10 +2464,11 @@ acx_newbuf(struct acx_softc *sc, struct acx_rxbuf *rb, int wait)
 
 static int
 acx_encap(struct acx_softc *sc, struct acx_txbuf *txbuf, struct mbuf *m,
-         struct acx_node *node, int rate)
+         struct ieee80211_node *ni, int rate)
 {
        struct acx_buf_data *bd = &sc->sc_buf_data;
        struct acx_ring_data *rd = &sc->sc_ring_data;
+       struct acx_node *node = (struct acx_node *)ni;
        uint32_t paddr;
        uint8_t ctrl;
        int error;
@@ -2567,20 +2583,10 @@ acx_encap(struct acx_softc *sc, struct acx_txbuf *txbuf, struct mbuf *m,
        CSR_WRITE_2(sc, ACXREG_INTR_TRIG, ACXRV_TRIG_TX_FINI);
 back:
        if (error)
-               m_free(m);
+               m_freem(m);
        return error;
 }
 
-/* XXX C&P of ieee80211_add_ssid() */
-static uint8_t *
-my_ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len)
-{
-       *frm++ = IEEE80211_ELEMID_SSID;
-       *frm++ = len;
-       memcpy(frm, ssid, len);
-       return frm + len;
-}
-
 static int
 acx_set_null_tmplt(struct acx_softc *sc)
 {
@@ -2615,7 +2621,7 @@ acx_set_probe_req_tmplt(struct acx_softc *sc, const char *ssid, int ssid_len)
        IEEE80211_ADDR_COPY(f->i_addr3, etherbroadcastaddr);
 
        v = req.data.u_data.var;
-       v = my_ieee80211_add_ssid(v, ssid, ssid_len);
+       v = ieee80211_add_ssid(v, ssid, ssid_len);
        v = ieee80211_add_rates(v, &sc->sc_ic.ic_sup_rates[sc->chip_phymode]);
        v = ieee80211_add_xrates(v, &sc->sc_ic.ic_sup_rates[sc->chip_phymode]);
        vlen = v - req.data.u_data.var;
@@ -2648,7 +2654,7 @@ acx_set_probe_resp_tmplt(struct acx_softc *sc, const char *ssid, int ssid_len,
        resp.data.u_data.cap = htole16(IEEE80211_CAPINFO_IBSS);
 
        v = resp.data.u_data.var;
-       v = my_ieee80211_add_ssid(v, ssid, ssid_len);
+       v = ieee80211_add_ssid(v, ssid, ssid_len);
        v = ieee80211_add_rates(v, &ic->ic_sup_rates[sc->chip_phymode]);
 
        *v++ = IEEE80211_ELEMID_DSPARMS;
@@ -2694,7 +2700,7 @@ acx_set_beacon_tmplt(struct acx_softc *sc, const char *ssid, int ssid_len,
        beacon.data.u_data.cap = htole16(IEEE80211_CAPINFO_IBSS);
 
        v = beacon.data.u_data.var;
-       v = my_ieee80211_add_ssid(v, ssid, ssid_len);
+       v = ieee80211_add_ssid(v, ssid, ssid_len);
        v = ieee80211_add_rates(v, &ic->ic_sup_rates[sc->chip_phymode]);
 
        *v++ = IEEE80211_ELEMID_DSPARMS;
@@ -2714,64 +2720,6 @@ acx_set_beacon_tmplt(struct acx_softc *sc, const char *ssid, int ssid_len,
        return _acx_set_beacon_tmplt(sc, &beacon, ACX_TMPLT_BEACON_SIZ(vlen));
 }
 
-/*
- * XXX
- * C&P of ieee80211_media_status(), only
- * imr->ifm_status |= IFM_ACTIVE; is added
- */
-static void
-acx_media_status(struct ifnet *ifp, struct ifmediareq *imr)
-{
-       struct ieee80211com *ic = (void *)ifp;
-       struct ieee80211_node *ni = NULL;
-
-       imr->ifm_status = IFM_AVALID;
-       imr->ifm_active = IFM_IEEE80211;
-
-       if (ic->ic_state == IEEE80211_S_RUN)
-               imr->ifm_status |= IFM_ACTIVE;
-
-       imr->ifm_active |= IFM_AUTO;
-       switch (ic->ic_opmode) {
-       case IEEE80211_M_STA:
-               ni = ic->ic_bss;
-               /* calculate rate subtype */
-               imr->ifm_active |= ieee80211_rate2media(ic,
-                       ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
-               break;
-       case IEEE80211_M_IBSS:
-               imr->ifm_active |= IFM_IEEE80211_ADHOC;
-               break;
-       case IEEE80211_M_AHDEMO:
-               /* should not come here */
-               break;
-       case IEEE80211_M_HOSTAP:
-               imr->ifm_active |= IFM_IEEE80211_HOSTAP;
-               break;
-       case IEEE80211_M_MONITOR:
-               imr->ifm_active |= IFM_IEEE80211_MONITOR;
-               break;
-       }
-       switch (ic->ic_curmode) {
-       case IEEE80211_MODE_11A:
-               imr->ifm_active |= IFM_IEEE80211_11A;
-               break;
-       case IEEE80211_MODE_11B:
-               imr->ifm_active |= IFM_IEEE80211_11B;
-               break;
-       case IEEE80211_MODE_11G:
-               imr->ifm_active |= IFM_IEEE80211_11G;
-               break;
-       case IEEE80211_MODE_FH:
-               imr->ifm_active |= IFM_IEEE80211_FH;
-               break;
-       case IEEE80211_MODE_TURBO:
-               imr->ifm_active |= IFM_IEEE80211_11A
-                               |  IFM_IEEE80211_TURBO;
-               break;
-       }
-}
-
 static int
 acx_sysctl_txrate_upd_intvl_min(SYSCTL_HANDLER_ARGS)
 {
index f1a1110..e6900a2 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/dev/netif/acx/if_acxvar.h,v 1.1 2006/04/01 02:55:36 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/acx/if_acxvar.h,v 1.2 2006/05/18 13:51:45 sephe Exp $
  */
 
 #ifndef _IF_ACXVAR_H
@@ -406,7 +406,7 @@ struct acx_softc {
 
        int                     (*chip_set_wepkey)      /* non-NULL */
                                (struct acx_softc *,
-                                struct ieee80211_wepkey *, int);
+                                struct ieee80211_key *, int);
 
        int                     (*chip_read_config)
                                (struct acx_softc *, struct acx_config *);
index 1b0e723..5c95a8b 100644 (file)
@@ -26,7 +26,8 @@
  *
  *
  * $Id: if_ipw.c,v 1.7.2.1 2005/01/13 20:01:03 damien Exp $
- * $DragonFly: src/sys/dev/netif/ipw/Attic/if_ipw.c,v 1.13 2005/12/31 14:07:59 sephe Exp $
+ * $FreeBSD: src/sys/dev/ipw/if_ipw.c,v 1.7.2.4 2006/01/29 15:13:01 damien Exp $
+ * $DragonFly: src/sys/dev/netif/ipw/Attic/if_ipw.c,v 1.14 2006/05/18 13:51:45 sephe Exp $
  */
 
 /*-
@@ -57,6 +58,7 @@
 
 #include <bus/pci/pcireg.h>
 #include <bus/pci/pcivar.h>
+#include <bus/pci/pcidevs.h>
 
 #include <net/bpf.h>
 #include <net/if.h>
@@ -78,8 +80,8 @@
 #include <netproto/802_11/ieee80211_radiotap.h>
 #include <netproto/802_11/if_wavelan_ieee.h>
 
-#include "if_ipwreg.h"
-#include "if_ipwvar.h"
+#include <dev/netif/ipw/if_ipwreg.h>
+#include <dev/netif/ipw/if_ipwvar.h>
 
 #ifdef IPW_DEBUG
 #define DPRINTF(x)     if (ipw_debug > 0) printf x
@@ -101,7 +103,8 @@ struct ipw_ident {
 };
 
 static const struct ipw_ident ipw_ident_table[] = {
-       { 0x8086, 0x1043, "Intel(R) PRO/Wireless 2100 MiniPCI" },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PRO_WL_2100,
+         "Intel(R) PRO/Wireless 2100 MiniPCI" },
 
        { 0, 0, NULL }
 };
@@ -223,7 +226,7 @@ ipw_attach(device_t dev)
        struct ifnet *ifp = &ic->ic_if;
        struct sysctl_oid *sysctl_tree;
        u_int16_t val;
-       int error, rid, i;
+       int error, i;
 
        if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
                device_printf(dev, "chip is in D%d power mode "
@@ -237,8 +240,9 @@ ipw_attach(device_t dev)
        pci_enable_busmaster(dev);
 
        /* map the register window */
-       rid = IPW_PCI_BAR0;
-       sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+       sc->mem_rid = IPW_PCI_BAR0;
+       sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
+                                        RF_ACTIVE);
        if (sc->mem == NULL) {
                device_printf(dev, "could not allocate memory resource\n");
                goto fail;
@@ -247,9 +251,9 @@ ipw_attach(device_t dev)
        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);
+       sc->irq_rid = 0;
+       sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
+                                        RF_ACTIVE | RF_SHAREABLE);
        if (sc->irq == NULL) {
                device_printf(dev, "could not allocate interrupt resource\n");
                goto fail;
@@ -314,9 +318,6 @@ ipw_attach(device_t dev)
         if (!(ipw_read_prom_word(sc, IPW_EEPROM_RADIO) & 8))
                 sc->flags |= IPW_FLAG_HAS_RADIO_SWITCH;
 
-       /* default to authmode OPEN */
-       sc->authmode = IEEE80211_AUTH_OPEN;
-
        /* IBSS channel undefined for now */
        ic->ic_ibss_chan = &ic->ic_channels[0];
 
@@ -329,11 +330,11 @@ ipw_attach(device_t dev)
        ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
        ifq_set_ready(&ifp->if_snd);
 
-       ieee80211_ifattach(ifp);
+       ieee80211_ifattach(ic);
        /* override state transition machine */
        sc->sc_newstate = ic->ic_newstate;
        ic->ic_newstate = ipw_newstate;
-       ieee80211_media_init(ifp, ipw_media_change, ipw_media_status);
+       ieee80211_media_init(ic, ipw_media_change, ipw_media_status);
 
        bpfattach_dlt(ifp, DLT_IEEE802_11_RADIO,
            sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf);
@@ -346,6 +347,8 @@ ipw_attach(device_t dev)
        sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
        sc->sc_txtap.wt_ihdr.it_present = htole32(IPW_TX_RADIOTAP_PRESENT);
 
+       sc->dwelltime = 100;
+
        SYSCTL_ADD_PROC(&sc->sysctl_ctx,
            SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "radio",
            CTLTYPE_INT | CTLFLAG_RD, sc, 0, ipw_sysctl_radio, "I",
@@ -356,6 +359,11 @@ ipw_attach(device_t dev)
            CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, ipw_sysctl_stats, "S",
            "Statistics");
 
+       SYSCTL_ADD_INT(&sc->sysctl_ctx,
+           SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "dwell",
+           CTLFLAG_RW, &sc->dwelltime, 0,
+           "Channel dwell time (ms) for AP/station scanning");
+
        /*
         * Hook our interrupt after all initialization is complete
         */
@@ -364,10 +372,13 @@ ipw_attach(device_t dev)
        if (error != 0) {
                device_printf(dev, "could not set up interrupt\n");
                bpfdetach(ifp);
-               ieee80211_ifdetach(ifp);
+               ieee80211_ifdetach(ic);
                goto fail;
        }
 
+       if (bootverbose)
+               ieee80211_announce(ic);
+
        return 0;
 
 fail:
@@ -389,18 +400,16 @@ ipw_detach(device_t dev)
                lwkt_serialize_exit(ifp->if_serializer);
 
                bpfdetach(ifp);
-               ieee80211_ifdetach(ifp);
+               ieee80211_ifdetach(&sc->sc_ic);
        }
 
        ipw_release(sc);
 
        if (sc->irq != NULL)
-               bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+               bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
 
-       if (sc->mem != NULL) {
-               bus_release_resource(dev, SYS_RES_MEMORY, IPW_PCI_BAR0,
-                                    sc->mem);
-       }
+       if (sc->mem != NULL)
+               bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
 
        sysctl_ctx_free(&sc->sysctl_ctx);
 
@@ -808,25 +817,27 @@ ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
 static int
 ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg __unused)
 {
-       struct ipw_softc *sc = ic->ic_softc;
-       struct ieee80211_node *ni = ic->ic_bss;
-       u_int32_t len;
-       u_int8_t val;
+       struct ipw_softc *sc = ic->ic_if.if_softc;
+       struct ieee80211_node *ni;
+       uint8_t macaddr[IEEE80211_ADDR_LEN];
+       uint32_t len;
 
        switch (nstate) {
        case IEEE80211_S_RUN:
-               len = IEEE80211_NWID_LEN;
-               ipw_read_table2(sc, IPW_INFO_CURRENT_SSID, ni->ni_essid, &len);
-               ni->ni_esslen = len;
+               DELAY(200); /* firmware needs a short delay here */
 
-               val = ipw_read_table1(sc, IPW_INFO_CURRENT_CHANNEL);
-               ni->ni_chan = &ic->ic_channels[val];
+               len = IEEE80211_ADDR_LEN;
+               ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, macaddr, &len);
+               ni = ieee80211_find_node(&ic->ic_scan, macaddr);
+               if (ni == NULL)
+                       break;
 
-               DELAY(100); /* firmware needs a short delay here */
+               ieee80211_ref_node(ni);
+               ieee80211_sta_join(ic, ni);
+               ieee80211_node_authorize(ni);
 
-               len = IEEE80211_ADDR_LEN;
-               ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, ni->ni_bssid, &len);
-               IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
+               if (ic->ic_opmode == IEEE80211_M_STA)
+                       ieee80211_notify_node_join(ic, ni, 1);
                break;
 
        case IEEE80211_S_INIT:
@@ -896,62 +907,13 @@ ipw_read_prom_word(struct ipw_softc *sc, u_int8_t addr)
        return le16toh(val);
 }
 
-static void
-ipw_scan_result(struct ipw_softc *sc)
-{
-       struct ieee80211com *ic = &sc->sc_ic;
-       struct ieee80211_node *ni;
-       u_int32_t i, cnt, off;
-       struct ipw_node ap;
-
-       /* flush previously seen access points */
-       ieee80211_free_allnodes(ic);
-
-       cnt = ipw_read_table1(sc, IPW_INFO_APS_CNT);
-       off = ipw_read_table1(sc, IPW_INFO_APS_BASE);
-
-       DPRINTF(("Found %u APs\n", cnt));
-
-       for (i = 0; i < cnt; i++) {
-               ipw_read_mem_1(sc, off, (u_int8_t *)&ap, sizeof ap);
-               off += sizeof ap;
-
-#ifdef IPW_DEBUG
-               if (ipw_debug >= 2) {
-                       u_char *p = (u_char *)&ap;
-                       int j;
-
-                       printf("AP%u\n", i);
-                       for (j = 0; j < sizeof ap; j++)
-                               printf("%02x", *p++);
-                       printf("\n");
-               }
-#endif
-
-               ni = ieee80211_lookup_node(ic, ap.bssid,
-                   &ic->ic_channels[ap.chan]);
-               if (ni != NULL)
-                       continue;
-
-               ni = ieee80211_alloc_node(ic, ap.bssid);
-               if (ni == NULL)
-                       return;
-
-               IEEE80211_ADDR_COPY(ni->ni_bssid, ap.bssid);
-               ni->ni_rssi = ap.rssi;
-               ni->ni_intval = le16toh(ap.intval);
-               ni->ni_capinfo = le16toh(ap.capinfo);
-               ni->ni_chan = &ic->ic_channels[ap.chan];
-               ni->ni_esslen = ap.esslen;
-               bcopy(ap.essid, ni->ni_essid, IEEE80211_NWID_LEN);
-       }
-}
-
 static void
 ipw_command_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
 {
        struct ipw_cmd *cmd;
 
+       bus_dmamap_sync(sc->rxbuf_dmat, sbuf->map, BUS_DMASYNC_POSTREAD);
+
        cmd = mtod(sbuf->m, struct ipw_cmd *);
 
        DPRINTFN(2, ("RX!CMD!%u!%u!%u!%u!%u\n",
@@ -967,6 +929,8 @@ ipw_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
        struct ieee80211com *ic = &sc->sc_ic;
        u_int32_t state;
 
+       bus_dmamap_sync(sc->rxbuf_dmat, sbuf->map, BUS_DMASYNC_POSTREAD);
+
        state = le32toh(*mtod(sbuf->m, u_int32_t *));
 
        DPRINTFN(2, ("RX!NEWSTATE!%u\n", state));
@@ -980,10 +944,13 @@ ipw_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
                /* don't leave run state on background scan */
                if (ic->ic_state != IEEE80211_S_RUN)
                        ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+
+               ic->ic_flags |= IEEE80211_F_SCAN;
                break;
 
        case IPW_STATE_SCAN_COMPLETE:
-               ipw_scan_result(sc);
+               ieee80211_notify_scan_done(ic);
+               ic->ic_flags &= ~IEEE80211_F_SCAN;
                break;
 
        case IPW_STATE_ASSOCIATION_LOST:
@@ -991,19 +958,56 @@ ipw_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
                break;
 
        case IPW_STATE_RADIO_DISABLED:
-               sc->sc_ic.ic_if.if_flags &= ~IFF_UP;
+               ic->ic_if.if_flags &= ~IFF_UP;
                ipw_stop(sc);
                break;
        }
 }
 
+/*
+ * XXX: Hack to set the current channel to the value advertised in beacons or
+ * probe responses. Only used during AP detection.
+ */
+static void
+ipw_fix_channel(struct ieee80211com *ic, struct mbuf *m)
+{
+       struct ieee80211_frame *wh;
+       uint8_t subtype;
+       uint8_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;
+
+       frm = (uint8_t *)(wh + 1);
+       efrm = mtod(m, uint8_t *) + m->m_len;
+
+       frm += 12;      /* skip tstamp, bintval and capinfo fields */
+       while (frm < efrm) {
+               if (*frm == IEEE80211_ELEMID_DSPARMS)
+#if IEEE80211_CHAN_MAX < 255
+               if (frm[2] <= IEEE80211_CHAN_MAX)
+#endif
+                       ic->ic_curchan = &ic->ic_channels[frm[2]];
+
+               frm += frm[1] + 2;
+       }
+}
+
 static void
 ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
     struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
-       struct mbuf *m;
+       struct mbuf *mnew, *m;
        struct ieee80211_frame *wh;
        struct ieee80211_node *ni;
        bus_addr_t physaddr;
@@ -1017,10 +1021,45 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
                return;
        }
 
+       /*
+        * Try to allocate a new mbuf for this ring element and load it before
+        * processing the current mbuf. If the ring element cannot be loaded,
+        * drop the received packet and reuse the old mbuf. In the unlikely
+        * case that the old mbuf can't be reloaded either, explicitly panic.
+        */
+       mnew = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
+       if (mnew == NULL) {
+               ifp->if_ierrors++;
+               return;
+       }
+       bus_dmamap_sync(sc->rxbuf_dmat, sbuf->map, BUS_DMASYNC_POSTREAD);
        bus_dmamap_unload(sc->rxbuf_dmat, sbuf->map);
 
-       /* Finalize mbuf */
+       error = bus_dmamap_load(sc->rxbuf_dmat, sbuf->map, mtod(mnew, void *),
+           MCLBYTES, ipw_dma_map_addr, &physaddr, 0);
+       if (error != 0) {
+               m_freem(mnew);
+
+               /* try to reload the old mbuf */
+               error = bus_dmamap_load(sc->rxbuf_dmat, sbuf->map,
+                   mtod(sbuf->m, void *), MCLBYTES, ipw_dma_map_addr,
+                   &physaddr, 0);
+               if (error != 0) /* XXX very unlikely that it will fail... */
+                       panic("%s: could not load old rx mbuf", ifp->if_xname);
+               ifp->if_ierrors++;
+               return;
+       }
+
+       /*
+        * New mbuf successfully loaded, update Rx ring and continue
+        * processing.
+        */
        m = sbuf->m;
+       sbuf->m = mnew;
+       sbd->bd->physaddr = htole32(physaddr);
+
+       /* finalize mbuf */
        m->m_pkthdr.rcvif = ifp;
        m->m_pkthdr.len = m->m_len = le32toh(status->len);
 
@@ -1029,47 +1068,25 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
 
                tap->wr_flags = 0;
                tap->wr_antsignal = status->rssi;
-               tap->wr_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
-               tap->wr_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
+               tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
+               tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
 
                bpf_ptap(sc->sc_drvbpf, m, tap, sc->sc_rxtap_len);
        }
 
-       wh = mtod(m, struct ieee80211_frame *);
-
-       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);
+       if (ic->ic_state == IEEE80211_S_SCAN)
+               ipw_fix_channel(ic, m);
 
-       /* Send the frame to the upper layer */
-       ieee80211_input(ifp, m, ni, status->rssi, 0);
-
-       if (ni == ic->ic_bss)
-               ieee80211_unref_node(&ni);
-       else
-               ieee80211_free_node(ic, ni);
+       wh = mtod(m, struct ieee80211_frame *);
+       ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
 
-       m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
-       if (m == NULL) {
-               if_printf(ifp, "could not allocate rx mbuf\n");
-               sbuf->m = NULL;
-               return;
-       }
+       /* send the frame to the 802.11 layer */
+       ieee80211_input(ic, m, ni, status->rssi, 0);
 
-       error = bus_dmamap_load(sc->rxbuf_dmat, sbuf->map, mtod(m, void *),
-           MCLBYTES, ipw_dma_map_addr, &physaddr, 0);
-       if (error != 0) {
-               if_printf(ifp, "could not map rx DMA memory\n");
-               m_freem(m);
-               sbuf->m = NULL;
-               return;
-       }
+       /* node is no longer needed */
+       ieee80211_free_node(ni);
 
-       sbuf->m = m;
-       sbd->bd->physaddr = htole32(physaddr);
+       bus_dmamap_sync(sc->rbd_dmat, sc->rbd_map, BUS_DMASYNC_PREWRITE);
 }
 
 static void
@@ -1099,9 +1116,6 @@ ipw_rx_intr(struct ipw_softc *sc)
                sbd = &sc->srbd_list[i];
                sbuf = sbd->priv;
 
-               bus_dmamap_sync(sc->rxbuf_dmat, sbuf->map,
-                   BUS_DMASYNC_POSTREAD);
-
                switch (le16toh(status->code) & 0xf) {
                case IPW_STATUS_CODE_COMMAND:
                        ipw_command_intr(sc, sbuf);
@@ -1142,7 +1156,6 @@ ipw_rx_intr(struct ipw_softc *sc)
 static void
 ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd)
 {
-       struct ieee80211com *ic = &sc->sc_ic;
        struct ipw_soft_hdr *shdr;
        struct ipw_soft_buf *sbuf;
 
@@ -1168,9 +1181,7 @@ ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd)
                SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next);
 
                m_freem(sbuf->m);
-
-               if (sbuf->ni != NULL && sbuf->ni != ic->ic_bss)
-                       ieee80211_free_node(ic, sbuf->ni);
+               ieee80211_free_node(sbuf->ni);
 
                /* kill watchdog timer */
                sc->sc_tx_timer = 0;
@@ -1191,7 +1202,13 @@ ipw_tx_intr(struct ipw_softc *sc)
        r = CSR_READ_4(sc, IPW_CSR_TX_READ_INDEX);
 
        for (i = (sc->txold + 1) % IPW_NTBD; i != r; i = (i + 1) % IPW_NTBD) {
-               ipw_release_sbd(sc, &sc->stbd_list[i]);
+               struct ipw_soft_bd *sbd;
+
+               sbd = &sc->stbd_list[i];
+               if (sbd->type == IPW_SBD_TYPE_DATA)
+                       ifp->if_opackets++;
+
+               ipw_release_sbd(sc, sbd);
                sc->txfree++;
        }
 
@@ -1303,8 +1320,10 @@ ipw_cmd(struct ipw_softc *sc, u_int32_t type, void *data, u_int32_t len)
        bus_dmamap_sync(sc->cmd_dmat, sc->cmd_map, BUS_DMASYNC_PREWRITE);
        bus_dmamap_sync(sc->tbd_dmat, sc->tbd_map, BUS_DMASYNC_PREWRITE);
 
+       /* kick firmware */
        sc->txcur = (sc->txcur + 1) % IPW_NTBD;
        sc->txfree--;
+       CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, sc->txcur);
 
        /*
         * This is kinda messy.  Since we may be MP, a combination of
@@ -1336,24 +1355,27 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
        bus_addr_t physaddr;
        int error, i;
 
-       if (ic->ic_flags & IEEE80211_F_WEPON) {
-               m0 = ieee80211_wep_crypt(ifp, m0, 1);
-               if (m0 == NULL)
+       wh = mtod(m0, struct ieee80211_frame *);
+       if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+               if (ieee80211_crypto_encap(ic, ni, m0) == NULL) {
+                       m_freem(m0);
                        return ENOBUFS;
-       }
+               }
+
+               /* packet header may have moved, reset our local pointer */
+               wh = mtod(m0, struct ieee80211_frame *);
+       }
 
        if (sc->sc_drvbpf != NULL) {
                struct ipw_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);
+               tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
+               tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
 
                bpf_ptap(sc->sc_drvbpf, m0, tap, sc->sc_txtap_len);
        }
 
-       wh = mtod(m0, struct ieee80211_frame *);
-
        shdr = SLIST_FIRST(&sc->free_shdr);
        sbuf = SLIST_FIRST(&sc->free_sbuf);
        KASSERT(shdr != NULL && sbuf != NULL, ("empty sw hdr/buf pool"));
@@ -1474,6 +1496,8 @@ ipw_start(struct ifnet *ifp)
        }
 
        for (;;) {
+               struct ether_header *eh;
+
                m0 = ifq_poll(&ifp->if_snd);
                if (m0 == NULL)
                        break;
@@ -1483,18 +1507,31 @@ ipw_start(struct ifnet *ifp)
                }
                ifq_dequeue(&ifp->if_snd, m0);
 
+               if (m0->m_len < sizeof (struct ether_header) &&
+                   (m0 = m_pullup(m0, sizeof (struct ether_header))) == NULL)
+                       continue;
+
+               eh = mtod(m0, struct ether_header *);
+               ni = ieee80211_find_txnode(ic, eh->ether_dhost);
+               if (ni == NULL) {
+                       m_freem(m0);
+                       continue;
+               }
+
                BPF_MTAP(ifp, m0);
 
-               m0 = ieee80211_encap(ifp, m0, &ni);
-               if (m0 == NULL)
+               m0 = ieee80211_encap(ic, m0, ni);
+               if (m0 == NULL) {
+                       ieee80211_free_node(ni);
                        continue;
+               }
 
                if (ic->ic_rawbpf != NULL)
                        bpf_mtap(ic->ic_rawbpf, m0);
 
                if (ipw_tx_start(ifp, m0, ni) != 0) {
-                       if (ni != NULL && ni != ic->ic_bss)
-                               ieee80211_free_node(ic, ni);
+                       ieee80211_free_node(ni);
+                       ifp->if_oerrors++;
                        break;
                }
 
@@ -1514,6 +1551,7 @@ ipw_watchdog(struct ifnet *ifp)
        if (sc->sc_tx_timer > 0) {
                if (--sc->sc_tx_timer == 0) {
                        if_printf(ifp, "device timeout\n");
+                       ifp->if_oerrors++;
                        ifp->if_flags &= ~IFF_UP;
                        ipw_stop(sc);
                        return;
@@ -1521,7 +1559,7 @@ ipw_watchdog(struct ifnet *ifp)
                ifp->if_timer = 1;
        }
 
-       ieee80211_watchdog(ifp);
+       ieee80211_watchdog(&sc->sc_ic);
 }
 
 static int
@@ -1530,7 +1568,6 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
        struct ipw_softc *sc = ifp->if_softc;
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifreq *ifr;
-       struct ieee80211req *ireq;
        int error = 0;
 
        switch (cmd) {
@@ -1563,41 +1600,8 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                ipw_free_firmware(sc);
                break;
 
-       case SIOCG80211:
-               ireq = (struct ieee80211req *)data;
-               switch (ireq->i_type) {
-               case IEEE80211_IOC_AUTHMODE:
-                       ireq->i_val = sc->authmode;
-                       break;
-
-               case IEEE80211_IOC_TXPOWER:
-                       ireq->i_val = (CSR_READ_4(sc, IPW_CSR_IO) &
-                           IPW_IO_RADIO_DISABLED) ? 0 : ic->ic_txpower;
-                       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;
-
        default:
-               error = ieee80211_ioctl(ifp, cmd, data, cr);
+               error = ieee80211_ioctl(ic, cmd, data, cr);
        }
 
        if (error == ENETRESET) {
@@ -1619,12 +1623,12 @@ ipw_stop_master(struct ipw_softc *sc)
        CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
 
        CSR_WRITE_4(sc, IPW_CSR_RST, IPW_RST_STOP_MASTER);
-       for (ntries = 0; ntries < 5; ntries++) {
+       for (ntries = 0; ntries < 50; ntries++) {
                if (CSR_READ_4(sc, IPW_CSR_RST) & IPW_RST_MASTER_DISABLED)
                        break;
                DELAY(10);
        }
-       if (ntries == 5)
+       if (ntries == 50)
                if_printf(&sc->sc_ic.ic_if, "timeout waiting for master\n");
 
        CSR_WRITE_4(sc, IPW_CSR_RST, CSR_READ_4(sc, IPW_CSR_RST) |
@@ -1854,7 +1858,7 @@ ipw_config(struct ipw_softc *sc)
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
        struct ipw_security security;
-       struct ieee80211_wepkey *k;
+       struct ieee80211_key *k;
        struct ipw_wep_key wepkey;
        struct ipw_scan_options options;
        struct ipw_configuration config;
@@ -1983,7 +1987,7 @@ ipw_config(struct ipw_softc *sc)
        }
 
        bzero(&security, sizeof security);
-       security.authmode = (sc->authmode == IEEE80211_AUTH_SHARED) ?
+       security.authmode = (ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED) ?
            IPW_AUTH_SHARED : IPW_AUTH_OPEN;
        security.ciphers = htole32(IPW_CIPHER_NONE);
        DPRINTF(("Setting authmode to %u\n", security.authmode));
@@ -1992,16 +1996,16 @@ ipw_config(struct ipw_softc *sc)
        if (error != 0)
                return error;
 
-       if (ic->ic_flags & IEEE80211_F_WEPON) {
-               k = ic->ic_nw_keys;
+       if (ic->ic_flags & IEEE80211_F_PRIVACY) {
+               k = ic->ic_crypto.cs_nw_keys;
                for (i = 0; i < IEEE80211_WEP_NKID; i++, k++) {
-                       if (k->wk_len == 0)
+                       if (k->wk_keylen == 0)
                                continue;
 
                        wepkey.idx = i;
-                       wepkey.len = k->wk_len;
+                       wepkey.len = k->wk_keylen;
                        bzero(wepkey.key, sizeof wepkey.key);
-                       bcopy(k->wk_key, wepkey.key, k->wk_len);
+                       bcopy(k->wk_key, wepkey.key, k->wk_keylen);
                        DPRINTF(("Setting wep key index %u len %u\n",
                            wepkey.idx, wepkey.len));
                        error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY, &wepkey,
@@ -2010,7 +2014,7 @@ ipw_config(struct ipw_softc *sc)
                                return error;
                }
 
-               data = htole32(ic->ic_wep_txkey);
+               data = htole32(ic->ic_crypto.cs_def_txkey);
                DPRINTF(("Setting wep tx key index to %u\n", le32toh(data)));
                error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
                    sizeof data);
@@ -2018,15 +2022,26 @@ ipw_config(struct ipw_softc *sc)
                        return error;
        }
 
-       data = htole32((ic->ic_flags & IEEE80211_F_WEPON) ? IPW_WEPON : 0);
+       data = htole32((ic->ic_flags & IEEE80211_F_PRIVACY) ? IPW_WEPON : 0);
        DPRINTF(("Setting wep flags to 0x%x\n", le32toh(data)));
        error = ipw_cmd(sc, IPW_CMD_SET_WEP_FLAGS, &data, sizeof data);
        if (error != 0)
                return error;
 
+#if 0
+       struct ipw_wpa_ie ie;
+
+       memset(&ie, 0, sizeof ie);
+       ie.len = htole32(sizeof (struct ieee80211_ie_wpa));
+       DPRINTF(("Setting wpa ie\n"));
+       error = ipw_cmd(sc, IPW_CMD_SET_WPA_IE, &ie, sizeof ie);
+       if (error != 0)
+               return error;
+#endif
+
        if (ic->ic_opmode == IEEE80211_M_IBSS ||
            ic->ic_opmode == IEEE80211_M_HOSTAP) {
-               data = htole32(ic->ic_lintval);
+               data = htole32(ic->ic_bintval);
                DPRINTF(("Setting beacon interval to %u\n", le32toh(data)));
                error = ipw_cmd(sc, IPW_CMD_SET_BEACON_INTERVAL, &data,
                    sizeof data);
@@ -2056,6 +2071,9 @@ ipw_init(void *priv)
 
        /* exit immediately if firmware has not been ioctl'd */
        if (!(sc->flags & IPW_FLAG_FW_CACHED)) {
+               if (!(sc->flags & IPW_FLAG_FW_WARNED))
+                       if_printf(ifp, "Please load firmware\n");
+               sc->flags |= IPW_FLAG_FW_WARNED;
                ifp->if_flags &= ~IFF_UP;
                return;
        }
@@ -2137,6 +2155,7 @@ ipw_stop(void *priv)
        for (i = 0; i < IPW_NTBD; i++)
                ipw_release_sbd(sc, &sc->stbd_list[i]);
 
+       sc->sc_tx_timer = 0;
        ifp->if_timer = 0;
        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
@@ -2147,14 +2166,17 @@ static int
 ipw_sysctl_stats(SYSCTL_HANDLER_ARGS)
 {
        struct ipw_softc *sc = arg1;
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
        u_int32_t i, size, buf[256];
 
        (void)arg2; /* silence WARNS == 6 */
        (void)oidp; /* silence WARNS == 6 */
 
+       lwkt_serialize_enter(ifp->if_serializer);
+
        if (!(sc->flags & IPW_FLAG_FW_INITED)) {
                bzero(buf, sizeof buf);
-               return SYSCTL_OUT(req, buf, sizeof buf);
+               goto back;
        }
 
        CSR_WRITE_4(sc, IPW_CSR_AUTOINC_ADDR, sc->table1_base);
@@ -2162,7 +2184,8 @@ ipw_sysctl_stats(SYSCTL_HANDLER_ARGS)
        size = min(CSR_READ_4(sc, IPW_CSR_AUTOINC_DATA), 256);
        for (i = 1; i < size; i++)
                buf[i] = MEM_READ_4(sc, CSR_READ_4(sc, IPW_CSR_AUTOINC_DATA));
-
+back:
+       lwkt_serialize_exit(ifp->if_serializer);
        return SYSCTL_OUT(req, buf, sizeof buf);
 }
 
@@ -2170,13 +2193,16 @@ static int
 ipw_sysctl_radio(SYSCTL_HANDLER_ARGS)
 {
        struct ipw_softc *sc = arg1;
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
        int val;
 
        (void)arg2; /* silence WARNS == 6 */
        (void)oidp; /* silence WARNS == 6 */
 
+       lwkt_serialize_enter(ifp->if_serializer);
        val = !((sc->flags & IPW_FLAG_HAS_RADIO_SWITCH) &&
                (CSR_READ_4(sc, IPW_CSR_IO) & IPW_IO_RADIO_DISABLED));
+       lwkt_serialize_exit(ifp->if_serializer);
 
        return SYSCTL_OUT(req, &val, sizeof val);
 }
index 18cf0e2..7281ba0 100644 (file)
@@ -25,7 +25,8 @@
  * SUCH DAMAGE.
  *
  * $Id: if_ipwvar.h,v 1.2.2.1 2005/01/13 20:01:04 damien Exp $
- * $DragonFly: src/sys/dev/netif/ipw/Attic/if_ipwvar.h,v 1.5 2005/11/29 17:15:56 dillon Exp $
+ * $FreeBSD: src/sys/dev/ipw/if_ipwvar.h,v 1.3 2005/06/10 16:49:11 brooks Exp $
+ * $DragonFly: src/sys/dev/netif/ipw/Attic/if_ipwvar.h,v 1.6 2006/05/18 13:51:45 sephe Exp $
  */
 
 struct ipw_firmware {
@@ -98,14 +99,16 @@ struct ipw_softc {
 #define IPW_FLAG_FW_CACHED          (1 << 0)
 #define IPW_FLAG_FW_INITED          (1 << 1)
 #define IPW_FLAG_HAS_RADIO_SWITCH   (1 << 2)
+#define IPW_FLAG_FW_WARNED         (1 << 3)
 
+       int                             irq_rid;
+       int                             mem_rid;
        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;
 
        bus_dma_tag_t                   tbd_dmat;
@@ -147,6 +150,8 @@ struct ipw_softc {
        int                             txfree;
        u_int32_t                       rxcur;
 
+       int                             dwelltime;
+
        struct bpf_if                   *sc_drvbpf;
 
        union {
index 7ad6a43..e9c695f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005
+ * Copyright (c) 2004-2006
  *      Damien Bergamini <damien.bergamini@free.fr>.
  * Copyright (c) 2004, 2005
  *      Andrew Atrens <atrens@nortelnetworks.com>.
  * 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.10 2005/12/31 14:07:59 sephe Exp $
+ * $FreeBSD: src/sys/dev/iwi/if_iwi.c,v 1.8.2.6 2006/02/23 02:06:46 sam Exp $
+ * $DragonFly: src/sys/dev/netif/iwi/if_iwi.c,v 1.11 2006/05/18 13:51:45 sephe Exp $
  */
 
-#include "opt_inet.h"
-
-#include <sys/cdefs.h>
-
 /*-
- * Intel(R) PRO/Wireless 2200BG/2915ABG driver
+ * Intel(R) PRO/Wireless 2200BG/2225BG/2915ABG driver
  * http://www.intel.com/network/connectivity/products/wireless/prowireless_mobile.htm
  */
 
 #include <sys/endian.h>
 #include <sys/proc.h>
 #include <sys/ucred.h>
-#include <sys/thread2.h>
+#include <sys/serialize.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
-#include <machine/clock.h>
 #include <sys/rman.h>
 
 #include <bus/pci/pcireg.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 <netproto/802_11/ieee80211_var.h>
+#include <netproto/802_11/ieee80211_radiotap.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"
+#include <dev/netif/iwi/if_iwireg.h>
+#include <dev/netif/iwi/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
-
+#define DPRINTF(x)     do { if (iwi_debug > 0) printf x; } while (0)
+#define DPRINTFN(n, x) do { if (iwi_debug >= (n)) printf x; } while (0)
+int iwi_debug = 0;
+SYSCTL_INT(_debug, OID_AUTO, iwi, CTLFLAG_RW, &iwi_debug, 0, "iwi debug level");
 #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;
+       uint16_t        vendor;
+       uint16_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" },
+       { 0x8086, 0x4220, "Intel(R) PRO/Wireless 2200BG" },
+       { 0x8086, 0x4221, "Intel(R) PRO/Wireless 2225BG" },
+       { 0x8086, 0x4223, "Intel(R) PRO/Wireless 2915ABG" },
+       { 0x8086, 0x4224, "Intel(R) PRO/Wireless 2915ABG" },
 
        { 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_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 void    iwi_dma_map_addr(void *, bus_dma_segment_t *, int, int);
+static void    iwi_dma_map_mbuf(void *, bus_dma_segment_t *, int, bus_size_t,
+                                int);
+static int     iwi_alloc_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *,
+                   int);
+static void    iwi_reset_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *);
+static void    iwi_free_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *);
+static int     iwi_alloc_tx_ring(struct iwi_softc *, struct iwi_tx_ring *,
+                   int, bus_addr_t, bus_addr_t);
+static void    iwi_reset_tx_ring(struct iwi_softc *, struct iwi_tx_ring *);
+static void    iwi_free_tx_ring(struct iwi_softc *, struct iwi_tx_ring *);
+static int     iwi_alloc_rx_ring(struct iwi_softc *, struct iwi_rx_ring *,
+                   int);
+static void    iwi_reset_rx_ring(struct iwi_softc *, struct iwi_rx_ring *);
+static void    iwi_free_rx_ring(struct iwi_softc *, struct iwi_rx_ring *);
+static struct  ieee80211_node *iwi_node_alloc(struct ieee80211_node_table *);
+static void    iwi_node_free(struct ieee80211_node *);
+static int     iwi_media_change(struct ifnet *);
+static void    iwi_media_status(struct ifnet *, struct ifmediareq *);
+static int     iwi_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static int     iwi_wme_update(struct ieee80211com *);
+static uint16_t        iwi_read_prom_word(struct iwi_softc *, uint8_t);
+static void    iwi_fix_channel(struct ieee80211com *, struct mbuf *);
+static void    iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, 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 *, struct iwi_tx_ring *);
+static void    iwi_intr(void *);
+static int     iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t, int);
+static void    iwi_write_ibssnode(struct iwi_softc *, const struct iwi_node *);
+static int     iwi_tx_start(struct ifnet *, struct mbuf *,
+                   struct ieee80211_node *, int);
+static void    iwi_start(struct ifnet *);
+static void    iwi_watchdog(struct ifnet *);
+static int     iwi_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
+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 *);
+static void    iwi_free_firmware(struct iwi_softc *);
+static int     iwi_config(struct iwi_softc *);
+static int     iwi_set_chan(struct iwi_softc *, struct ieee80211_channel *);
+static int     iwi_scan(struct iwi_softc *);
+static int     iwi_auth_and_assoc(struct iwi_softc *);
+static void    iwi_init(void *);
+static void    iwi_stop(void *);
+static int     iwi_sysctl_stats(SYSCTL_HANDLER_ARGS);
+static int     iwi_sysctl_radio(SYSCTL_HANDLER_ARGS);
+
+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 int     iwi_alloc_ibss_node(struct iwi_softc *);
+static void    iwi_free_ibss_node(struct iwi_softc *, int);
 
 static device_method_t iwi_methods[] = {
        /* Device interface */
@@ -219,24 +182,38 @@ static device_method_t iwi_methods[] = {
 static driver_t iwi_driver = {
        "iwi",
        iwi_methods,
-       sizeof (struct iwi_softc),
-       0, /* baseclasses */
-       0, /* refs */
-       0  /* ops */
+       sizeof (struct iwi_softc)
 };
 
 static devclass_t iwi_devclass;
 
 DRIVER_MODULE(iwi, pci, iwi_driver, iwi_devclass, 0, 0);
 
+MODULE_DEPEND(iwi, pci,  1, 1, 1);
+MODULE_DEPEND(iwi, wlan, 1, 1, 1);
+
+/*
+ * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
+ */
+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_probe(device_t dev)
 {
        const struct iwi_ident *ident;
+       uint16_t vid, did;
 
+       vid = pci_get_vendor(dev);
+       did = pci_get_device(dev);
        for (ident = iwi_ident_table; ident->name != NULL; ident++) {
-               if (pci_get_vendor(dev) == ident->vendor &&
-                   pci_get_device(dev) == ident->device) {
+               if (vid == ident->vendor && did == ident->device) {
                        device_set_desc(dev, ident->name);
                        return 0;
                }
@@ -244,59 +221,6 @@ iwi_probe(device_t dev)
        return ENXIO;
 }
 
-static void
-iwi_fw_monitor(void *arg)
-{
-       struct iwi_softc *sc = (struct iwi_softc *)arg;
-       struct ifnet *ifp = &sc->sc_ic.ic_if;
-       int error, boff;
-
-       for ( ;; ) {
-               crit_enter();
-               tsleep_interlock(IWI_FW_WAKE_MONITOR(sc));
-               error = tsleep(IWI_FW_WAKE_MONITOR(sc), 0, "iwifwm", 0 );
-               crit_exit();
-
-               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);
-                                       lwkt_serialize_enter(ifp->if_serializer);
-                                       iwi_init(sc);
-                                       lwkt_serialize_exit(ifp->if_serializer);
-                                       if ((sc->flags & IWI_FLAG_FW_INITED))
-                                               sc->flags &= ~( IWI_FLAG_RESET );
-                                       crit_enter();
-                                       tsleep_interlock(IWI_FW_CMD_ACKED(sc));
-                                       error = tsleep(IWI_FW_CMD_ACKED(sc), 0,
-                                                      "iwirun", boff * hz );
-                                       crit_exit();
-                               }
-                       }
-               }
-       }
-       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
 
@@ -306,10 +230,11 @@ 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;
+       uint16_t val;
+       int error, i;
 
        sc->sc_dev = dev;
+       if_initname(ifp, device_get_name(dev), device_get_unit(dev));
 
        if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
                device_printf(dev, "chip is in D%d power mode "
@@ -322,68 +247,122 @@ iwi_attach(device_t dev)
        /* 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);
+       sc->mem_rid = IWI_PCI_BAR0;
+       sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
+                                        RF_ACTIVE);
        if (sc->mem == NULL) {
                device_printf(dev, "could not allocate memory resource\n");
-               error = ENXIO;
-               goto fail;
+               return ENXIO;
        }
-
        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);
+       sc->irq_rid = 0;
+       sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
+                                        RF_ACTIVE | RF_SHAREABLE);
        if (sc->irq == NULL) {
                device_printf(dev, "could not allocate interrupt resource\n");
-               error = ENXIO;
                goto fail;
        }
 
-       error = iwi_reset(sc);
-       if (error != 0) {
+       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");
-               error = ENXIO;
+       /*
+        * Allocate rings.
+        */
+       error = iwi_alloc_cmd_ring(sc, &sc->cmdq, IWI_CMD_RING_COUNT);
+       if (error != 0) {
+               device_printf(dev, "could not allocate Cmd ring\n");
+               goto fail;
+       }
+
+       error = iwi_alloc_tx_ring(sc, &sc->txq[0], IWI_TX_RING_COUNT,
+                                 IWI_CSR_TX1_RIDX, IWI_CSR_TX1_WIDX);
+       if (error != 0) {
+               device_printf(dev, "could not allocate Tx ring 1\n");
+               goto fail;
+       }
+
+       error = iwi_alloc_tx_ring(sc, &sc->txq[1], IWI_TX_RING_COUNT,
+                                 IWI_CSR_TX2_RIDX, IWI_CSR_TX2_WIDX);
+       if (error != 0) {
+               device_printf(dev, "could not allocate Tx ring 2\n");
                goto fail;
        }
 
-       error = iwi_dma_alloc(sc);
+       error = iwi_alloc_tx_ring(sc, &sc->txq[2], IWI_TX_RING_COUNT,
+                                 IWI_CSR_TX3_RIDX, IWI_CSR_TX3_WIDX);
        if (error != 0) {
-               device_printf(dev, "could not allocate DMA resources\n");
+               device_printf(dev, "could not allocate Tx ring 3\n");
                goto fail;
        }
 
-       ic->ic_phytype = IEEE80211_T_OFDM;
-       ic->ic_opmode  = IEEE80211_M_STA;
-       ic->ic_state   = IEEE80211_S_INIT;
+       error = iwi_alloc_tx_ring(sc, &sc->txq[3], IWI_TX_RING_COUNT,
+                                 IWI_CSR_TX4_RIDX, IWI_CSR_TX4_WIDX);
+       if (error != 0) {
+               device_printf(dev, "could not allocate Tx ring 4\n");
+               goto fail;
+       }
+
+       error = iwi_alloc_rx_ring(sc, &sc->rxq, IWI_RX_RING_COUNT);
+       if (error != 0) {
+               device_printf(dev, "could not allocate Rx ring\n");
+               goto fail;
+       }
+
+       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) {
+               device_printf(dev, "sysctl add node failed\n");
+               error = EIO;
+               goto fail;
+       }
+
+       ifp->if_softc = sc;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_init = iwi_init;
+       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);
+
+       ic->ic_wme.wme_update = iwi_wme_update;
+       ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
+       ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
+       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;
+       ic->ic_caps =
+           IEEE80211_C_IBSS |          /* IBSS mode supported */
+           IEEE80211_C_MONITOR |       /* monitor mode supported */
+           IEEE80211_C_TXPMGT |        /* tx power management */
+           IEEE80211_C_SHPREAMBLE |    /* short preamble supported */
+           IEEE80211_C_WEP |           /* WEP */
+           IEEE80211_C_WPA |           /* 802.11i */
+           IEEE80211_C_WME;            /* 802.11e */
 
        /* 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;
+       ic->ic_myaddr[0] = val & 0xff;
+       ic->ic_myaddr[1] = val >> 8;
        val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 1);
-       ic->ic_myaddr[2] = val >> 8;
-       ic->ic_myaddr[3] = val & 0xff;
+       ic->ic_myaddr[2] = val & 0xff;
+       ic->ic_myaddr[3] = val >> 8;
        val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2);
-       ic->ic_myaddr[4] = val >> 8;
-       ic->ic_myaddr[5] = val & 0xff;
+       ic->ic_myaddr[4] = val & 0xff;
+       ic->ic_myaddr[5] = val >> 8;
 
-       if (pci_get_device(dev) != 0x4220) {
-               /* set supported .11a rates */
+       if (pci_get_device(dev) >= 0x4223) {
+               /* set supported .11a rates (2915ABG only) */
                ic->ic_sup_rates[IEEE80211_MODE_11A] = iwi_rateset_11a;
 
                /* set supported .11a channels */
@@ -412,27 +391,15 @@ iwi_attach(device_t dev)
                    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;
-       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);
+       ieee80211_ifattach(ic);
+       /* override default methods */
+       ic->ic_node_alloc = iwi_node_alloc;
+       sc->sc_node_free = ic->ic_node_free;
+       ic->ic_node_free = iwi_node_free;
        /* 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);
+       ieee80211_media_init(ic, iwi_media_change, iwi_media_status);
 
        bpfattach_dlt(ifp, DLT_IEEE802_11_RADIO,
            sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf);
@@ -446,361 +413,407 @@ iwi_attach(device_t dev)
        sc->sc_txtap.wt_ihdr.it_present = htole32(IWI_TX_RADIOTAP_PRESENT);
 
        /*
-        * Add sysctl knobs
-        * 
-        * use -1 to indicate 'default / not set'
+        * Add a few sysctl knobs.
         */
-
-       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) {
-               device_printf(dev, "sysctl add node failed\n");
-               error = EIO;
-               goto fail2;
-       }
-
-       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]" );
+       sc->dwelltime = 100;
+       sc->bluetooth = 1;
+       sc->antenna = 0;
 
        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_CHILDREN(sc->sysctl_tree), OID_AUTO, "radio",
+           CTLTYPE_INT | CTLFLAG_RD, sc, 0, iwi_sysctl_radio, "I",
+           "radio transmitter switch state (0=off, 1=on)");
 
        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_CHILDREN(sc->sysctl_tree), OID_AUTO, "stats",
+           CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, iwi_sysctl_stats, "S",
+           "statistics");
 
+       SYSCTL_ADD_INT(&sc->sysctl_ctx,
+           SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "dwell",
+           CTLFLAG_RW, &sc->dwelltime, 0,
+           "channel dwell time (ms) for AP/station scanning");
 
-       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_INT(&sc->sysctl_ctx,
+           SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "bluetooth",
+           CTLFLAG_RW, &sc->bluetooth, 0, "bluetooth coexistence");
 
-       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.");
+       SYSCTL_ADD_INT(&sc->sysctl_ctx,
+           SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "antenna",
+           CTLFLAG_RW, &sc->antenna, 0, "antenna (0=auto)");
 
        /*
-        * Hook our interrupt after all initialization is complete
+        * Hook our interrupt after all initialization is complete.
         */
-       error = bus_setup_intr(dev, sc->irq, INTR_MPSAFE,
-                              iwi_intr, sc, &sc->sc_ih, ifp->if_serializer);
+       error = bus_setup_intr(dev, sc->irq, INTR_MPSAFE, iwi_intr, sc,
+                              &sc->sc_ih, ifp->if_serializer);
        if (error != 0) {
                device_printf(dev, "could not set up interrupt\n");
-               goto fail2;
+
+               bpfdetach(ifp);
+               ieee80211_ifdetach(ic);
+               goto fail;
        }
 
-       return 0;
+       if (bootverbose)
+               ieee80211_announce(ic);
 
-fail2:
-       bpfdetach(ifp);
-       ieee80211_ifdetach(ifp);
+       return 0;
 fail:
        iwi_detach(dev);
-       return error;
+       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;
-
-       sc->flags |= IWI_FLAG_EXIT;
-       wakeup(IWI_FW_WAKE_MONITOR(sc)); /* Stop firmware monitor. */
-
-       tsleep(IWI_FW_MON_EXIT(sc), 0, "iwiexi", 10 * hz);
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = ic->ic_ifp;
 
        if (device_is_attached(dev)) {
                lwkt_serialize_enter(ifp->if_serializer);
+
                iwi_stop(sc);
-               iwi_free_firmware(sc);
                bus_teardown_intr(dev, sc->irq, sc->sc_ih);
+               iwi_free_firmware(sc);
+
                lwkt_serialize_exit(ifp->if_serializer);
 
                bpfdetach(ifp);
-               ieee80211_ifdetach(ifp);
+               ieee80211_ifdetach(ic);
        }
 
-       if (sc->sysctl_tree) {
-               sysctl_ctx_free(&sc->sysctl_ctx);
-               sc->sysctl_tree = 0;
-       }
+       iwi_free_cmd_ring(sc, &sc->cmdq);
+       iwi_free_tx_ring(sc, &sc->txq[0]);
+       iwi_free_tx_ring(sc, &sc->txq[1]);
+       iwi_free_tx_ring(sc, &sc->txq[2]);
+       iwi_free_tx_ring(sc, &sc->txq[3]);
+       iwi_free_rx_ring(sc, &sc->rxq);
 
        if (sc->irq != NULL)
-               bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+               bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
 
-       if (sc->mem != NULL) {
-               bus_release_resource(dev, SYS_RES_MEMORY, IWI_PCI_BAR0,
-                   sc->mem);
-       }
+       if (sc->mem != NULL)
+               bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
 
-       iwi_release(sc);
+       if (sc->sysctl_tree != NULL)
+               sysctl_ctx_free(&sc->sysctl_ctx);
 
        return 0;
 }
 
+static void
+iwi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+       if (error != 0)
+               return;
+
+       KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+
+       *(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
 static int
-iwi_dma_alloc(struct iwi_softc *sc)
+iwi_alloc_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring, int count)
 {
-       int i, error;
+       int 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 );
+       ring->count = count;
+       ring->queued = 0;
+       ring->cur = ring->next = 0;
+
+       error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL, count * IWI_CMD_DESC_SIZE, 1,
+           count * IWI_CMD_DESC_SIZE, 0, &ring->desc_dmat);
        if (error != 0) {
-               device_printf(sc->sc_dev, "could not create parent tag\n");
+               device_printf(sc->sc_dev, "could not create desc DMA 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);
+
+       error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc,
+           BUS_DMA_WAITOK | BUS_DMA_ZERO, &ring->desc_map);
        if (error != 0) {
-               device_printf(sc->sc_dev, "could not create tx ring DMA tag\n");
+               device_printf(sc->sc_dev, "could not allocate DMA memory\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);
+       error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc,
+           count * IWI_CMD_DESC_SIZE, iwi_dma_map_addr, &ring->physaddr, 0);
        if (error != 0) {
-               device_printf(sc->sc_dev,
-                   "could not allocate tx ring DMA memory\n");
-               goto fail;
+               device_printf(sc->sc_dev, "could not load desc DMA map\n");
+               bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
+               ring->desc = NULL;
+               return error;
        }
 
-       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;
+       return 0;
+
+fail:  iwi_free_cmd_ring(sc, ring);
+       return error;
+}
+
+static void
+iwi_reset_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring)
+{
+       ring->queued = 0;
+       ring->cur = ring->next = 0;
+}
+
+static void
+iwi_free_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring)
+{
+       if (ring->desc != NULL) {
+               bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+                   BUS_DMASYNC_POSTWRITE);
+               bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
+               bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
+               ring->desc = NULL;
        }
 
-       /*
-        * 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 (ring->desc_dmat != NULL) {
+               bus_dma_tag_destroy(ring->desc_dmat);   
+               ring->desc_dmat = NULL;
+       }
+}
+
+static int
+iwi_alloc_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring, int count,
+    bus_addr_t csr_ridx, bus_addr_t csr_widx)
+{
+       int i, error;
+
+       ring->count = count;
+       ring->queued = 0;
+       ring->cur = ring->next = 0;
+       ring->csr_ridx = csr_ridx;
+       ring->csr_widx = csr_widx;
+
+       error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL, count * IWI_TX_DESC_SIZE, 1,
+           count * IWI_TX_DESC_SIZE, 0, &ring->desc_dmat);
        if (error != 0) {
-               device_printf(sc->sc_dev,
-                   "could not create command ring DMA tag\n");
+               device_printf(sc->sc_dev, "could not create desc 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);
+       error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc,
+           BUS_DMA_WAITOK | BUS_DMA_ZERO, &ring->desc_map);
        if (error != 0) {
-               device_printf(sc->sc_dev,
-                   "could not allocate command ring DMA memory\n");
+               device_printf(sc->sc_dev, "could not allocate 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);
+       error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc,
+           count * IWI_TX_DESC_SIZE, iwi_dma_map_addr, &ring->physaddr, 0);
        if (error != 0) {
-               device_printf(sc->sc_dev,
-                   "could not load command ring DMA map\n");
+               device_printf(sc->sc_dev, "could not load desc DMA map\n");
+
+               bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
+               ring->desc = NULL;
                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);
+       ring->data = malloc(count * sizeof (struct iwi_tx_data), M_DEVBUF,
+           M_WAITOK | M_ZERO);
+
+       error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, IWI_MAX_NSEG - 2,
+           MCLBYTES, 0, &ring->data_dmat);
        if (error != 0) {
-               device_printf(sc->sc_dev, "could not create tx buf DMA tag\n");
+               device_printf(sc->sc_dev, "could not create data 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);
+       for (i = 0; i < count; i++) {
+               error = bus_dmamap_create(ring->data_dmat, 0,
+                   &ring->data[i].map);
                if (error != 0) {
-                       device_printf(sc->sc_dev,
-                           "could not create tx buf DMA map");
+                       device_printf(sc->sc_dev, "could not create DMA map\n");
                        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);
+       return 0;
+
+fail:  iwi_free_tx_ring(sc, ring);
+       return error;
+}
+
+static void
+iwi_reset_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring)
+{
+       struct iwi_tx_data *data;
+       int i;
+
+       for (i = 0; i < ring->count; i++) {
+               data = &ring->data[i];
+
+               if (data->m != NULL) {
+                       bus_dmamap_sync(ring->data_dmat, data->map,
+                           BUS_DMASYNC_POSTWRITE);
+                       bus_dmamap_unload(ring->data_dmat, data->map);
+                       m_freem(data->m);
+                       data->m = NULL;
+               }
+
+               if (data->ni != NULL) {
+                       ieee80211_free_node(data->ni);
+                       data->ni = NULL;
+               }
+       }
+
+       ring->queued = 0;
+       ring->cur = ring->next = 0;
+}
+
+static void
+iwi_free_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring)
+{
+       struct iwi_tx_data *data;
+       int i;
+
+       if (ring->desc != NULL) {
+               bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+                   BUS_DMASYNC_POSTWRITE);
+               bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
+               bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
+               ring->desc = NULL;
+       }
+
+       if (ring->desc_dmat != NULL) {
+               bus_dma_tag_destroy(ring->desc_dmat);
+               ring->desc_dmat = NULL;
+       }
+
+       if (ring->data != NULL) {
+               for (i = 0; i < ring->count; i++) {
+                       data = &ring->data[i];
+
+                       if (data->m != NULL) {
+                               bus_dmamap_sync(ring->data_dmat, data->map,
+                                   BUS_DMASYNC_POSTWRITE);
+                               bus_dmamap_unload(ring->data_dmat, data->map);
+                               m_freem(data->m);
+                               data->m = NULL;
+                       }
+
+                       if (data->ni != NULL) {
+                               ieee80211_free_node(data->ni);
+                               data->ni = NULL;
+                       }
+
+                       if (data->map != NULL) {
+                               bus_dmamap_destroy(ring->data_dmat, data->map);
+                               data->map = NULL;
+                       }
+               }
+
+               free(ring->data, M_DEVBUF);
+               ring->data = NULL;
+       }
+
+       if (ring->data_dmat != NULL) {
+               bus_dma_tag_destroy(ring->data_dmat);
+               ring->data_dmat = NULL;
+       }
+}
+
+static int
+iwi_alloc_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring, int count)
+{
+       struct iwi_rx_data *data;
+       int i, error;
+
+       ring->count = count;
+       ring->cur = 0;
+
+       ring->data = malloc(count * sizeof (struct iwi_rx_data), M_DEVBUF,
+           M_WAITOK | M_ZERO);
+
+       error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0,
+           &ring->data_dmat);
        if (error != 0) {
-               device_printf(sc->sc_dev, "could not create rx buf DMA tag\n");
+               device_printf(sc->sc_dev, "could not create data DMA tag\n");
                goto fail;
        }
 
-       for (i = 0; i < IWI_RX_RING_SIZE; i++) {
+       for (i = 0; i < count; i++) {
+               data = &ring->data[i];
 
-               error = bus_dmamap_create(sc->rx_buf_dmat, 0,
-                   &sc->rx_buf[i].map);
+               error = bus_dmamap_create(ring->data_dmat, 0, &data->map);
                if (error != 0) {
-                       device_printf(sc->sc_dev,
-                           "could not create rx buf DMA map");
+                       device_printf(sc->sc_dev, "could not create DMA map\n");
                        goto fail;
                }
 
-               sc->rx_buf[i].m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
-               if (sc->rx_buf[i].m == NULL) {
+               data->m = m_getcl(MB_WAIT, MT_DATA, M_PKTHDR);
+               if (data->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);
+               error = bus_dmamap_load(ring->data_dmat, data->map,
+                   mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr,
+                   &data->physaddr, 0);
                if (error != 0) {
                        device_printf(sc->sc_dev,
                            "could not load rx buf DMA map");
+
+                       m_freem(data->m);
+                       data->m = NULL;
                        goto fail;
                }
+
+               data->reg = IWI_CSR_RX_BASE + i * 4;
        }
 
        return 0;
 
-fail:  iwi_release(sc);
+fail:  iwi_free_rx_ring(sc, ring);
        return error;
 }
 
 static void
-iwi_release(struct iwi_softc *sc)
+iwi_reset_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring)
 {
-       int i;
+       ring->cur = 0;
+}
 
-       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);
-       }
+static void
+iwi_free_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring)
+{
+       struct iwi_rx_data *data;
+       int i;
 
-       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 (ring->data != NULL) {
+               for (i = 0; i < ring->count; i++) {
+                       data = &ring->data[i];
 
-       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);
+                       if (data->m != NULL) {
+                               bus_dmamap_sync(ring->data_dmat, data->map,
+                                   BUS_DMASYNC_POSTREAD);
+                               bus_dmamap_unload(ring->data_dmat, data->map);
+                               m_freem(data->m);
+                               data->m = NULL;
                        }
-                       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);
+                       if (data->map != NULL) {
+                               bus_dmamap_destroy(ring->data_dmat, data->map);
+                               data->map = NULL;
                        }
-                       bus_dmamap_destroy(sc->rx_buf_dmat, sc->rx_buf[i].map);
                }
-               bus_dma_tag_destroy(sc->rx_buf_dmat);
+
+               free(ring->data, M_DEVBUF);
+               ring->data = NULL;
        }
-       if ( sc->iwi_parent_tag != NULL ) {
-               bus_dma_tag_destroy(sc->iwi_parent_tag);
+
+       if (ring->data_dmat != NULL) {
+               bus_dma_tag_destroy(ring->data_dmat);
+               ring->data_dmat = NULL;
        }
 }
 
@@ -834,9 +847,10 @@ static int
 iwi_resume(device_t dev)
 {
        struct iwi_softc *sc = device_get_softc(dev);
-       struct ifnet *ifp = &sc->sc_ic.ic_if;
+       struct ifnet *ifp = sc->sc_ic.ic_ifp;
 
        lwkt_serialize_enter(ifp->if_serializer);
+
        pci_write_config(dev, 0x41, 0, 1);
 
        if (ifp->if_flags & IFF_UP) {
@@ -844,29 +858,60 @@ iwi_resume(device_t dev)
                if (ifp->if_flags & IFF_RUNNING)
                        ifp->if_start(ifp);
        }
+
        lwkt_serialize_exit(ifp->if_serializer);
+
        return 0;
 }
 
+static struct ieee80211_node *
+iwi_node_alloc(struct ieee80211_node_table *nt)
+{
+       struct iwi_node *in;
+
+       in = malloc(sizeof (struct iwi_node), M_80211_NODE, M_NOWAIT | M_ZERO);
+       if (in == NULL)
+               return NULL;
+
+       in->in_station = -1;
+
+       return &in->in_node;
+}
+
+static void
+iwi_node_free(struct ieee80211_node *ni)
+{
+       struct ieee80211com *ic = ni->ni_ic;
+       struct iwi_softc *sc = ic->ic_ifp->if_softc;
+       struct iwi_node *in = (struct iwi_node *)ni;
+
+       if (in->in_station != -1)
+               iwi_free_ibss_node(sc, in->in_station);
+
+       sc->sc_node_free(ni);
+}
+
 static int
 iwi_media_change(struct ifnet *ifp)
 {
        struct iwi_softc *sc = ifp->if_softc;
-       int error = 0;
+       int error;
+
+       ASSERT_SERIALIZED(ifp->if_serializer);
 
        error = ieee80211_media_change(ifp);
-       if (error != ENETRESET) {
+       if (error != ENETRESET)
                return error;
-       }
-       error = 0; /* clear ENETRESET */
 
-       if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)){
+       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 );
-       }
-       return error;
+       return 0;
 }
 
+/*
+ * The firmware automatically adapts the transmit speed.  We report its current
+ * value here.
+ */
 static void
 iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
 {
@@ -874,7 +919,7 @@ iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
        struct ieee80211com *ic = &sc->sc_ic;
 #define N(a)   (sizeof (a) / sizeof (a[0]))
        static const struct {
-               u_int32_t       val;
+               uint32_t        val;
                int             rate;
        } rates[] = {
                { IWI_RATE_DS1,      2 },
@@ -890,8 +935,8 @@ iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
                { IWI_RATE_OFDM48,  96 },
                { IWI_RATE_OFDM54, 108 },
        };
-       u_int32_t val, i;
-       int rate;
+       uint32_t val;
+       int rate, i;
 
        imr->ifm_status = IFM_AVALID;
        imr->ifm_active = IFM_IEEE80211;
@@ -902,7 +947,7 @@ iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
        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++);
+       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);
@@ -927,95 +972,139 @@ iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
 }
 
 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)
+iwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
 {
-       struct iwi_softc *sc = ic->ic_softc;
-       struct ifnet *ifp = &ic->ic_if;
+       struct ifnet *ifp = ic->ic_ifp;
+       struct iwi_softc *sc = ifp->if_softc;
+       enum ieee80211_state ostate;
+       uint32_t tmp;
 
-       ASSERT_SERIALIZED(ifp->if_serializer);
+       ostate = ic->ic_state;
 
        switch (nstate) {
        case IEEE80211_S_SCAN:
-               if (sc->flags & IWI_FLAG_ASSOCIATED) {
-                       sc->flags &= ~( IWI_FLAG_ASSOCIATED );
-                       iwi_disassociate(sc);
-
-                       crit_enter();
-                       tsleep_interlock(IWI_FW_DEASSOCIATED(sc));
-                       lwkt_serialize_exit(ifp->if_serializer);
-                       tsleep(IWI_FW_DEASSOCIATED(sc), 0, "iwisca", hz );
-                       crit_exit();
-                       lwkt_serialize_enter(ifp->if_serializer);
-               }
-               if ( !(sc->flags & IWI_FLAG_SCANNING) &&
-                    !(sc->flags & IWI_FLAG_RF_DISABLED) ) {
-                       iwi_scan(sc);
-               }
+               if (sc->flags & IWI_FLAG_SCANNING)
+                       break;
+
+               ieee80211_node_table_reset(&ic->ic_scan);
+               ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN;
+               sc->flags |= IWI_FLAG_SCANNING;
+               iwi_scan(sc);
                break;
 
        case IEEE80211_S_AUTH:
-               if ( sc->flags & IWI_FLAG_ASSOCIATED ) {
-                       sc->flags &= ~( IWI_FLAG_ASSOCIATED );
-                       iwi_disassociate(sc);
-
-                       crit_enter();
-                       tsleep_interlock(IWI_FW_DEASSOCIATED(sc));
-                       lwkt_serialize_exit(ifp->if_serializer);
-                       tsleep(IWI_FW_DEASSOCIATED(sc), 0, "iwiaut", hz );
-                       crit_exit();
-                       lwkt_serialize_enter(ifp->if_serializer);
-               }
-               if ( iwi_auth_and_assoc(sc) != 0 )
-                       ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+               iwi_auth_and_assoc(sc);
                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;
+               if (ic->ic_opmode == IEEE80211_M_IBSS)
+                       iwi_auth_and_assoc(sc);
+               else if (ic->ic_opmode == IEEE80211_M_MONITOR)
+                       iwi_set_chan(sc, ic->ic_ibss_chan);
+
+               /* assoc led on */
+               tmp = MEM_READ_4(sc, IWI_MEM_EVENT_CTL) & IWI_LED_MASK;
+               MEM_WRITE_4(sc, IWI_MEM_EVENT_CTL, tmp | IWI_LED_ASSOC);
+
+               return sc->sc_newstate(ic, nstate,
+                   IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
 
        case IEEE80211_S_ASSOC:
                break;
+
        case IEEE80211_S_INIT:
-               sc->flags &= ~( IWI_FLAG_SCANNING | IWI_FLAG_ASSOCIATED );
+               sc->flags &= ~IWI_FLAG_SCANNING;
+
+               if (ostate != IEEE80211_S_RUN)
+                       break;
+
+               /* assoc led off */
+               tmp = MEM_READ_4(sc, IWI_MEM_EVENT_CTL) & IWI_LED_MASK;
+               MEM_WRITE_4(sc, IWI_MEM_EVENT_CTL, tmp & ~IWI_LED_ASSOC);
                break;
        }
 
        ic->ic_state = nstate;
+
        return 0;
 }
 
+/*
+ * WME parameters coming from IEEE 802.11e specification.  These values are
+ * already declared in ieee80211_proto.c, but they are static so they can't
+ * be reused here.
+ */
+static const struct wmeParams iwi_wme_cck_params[WME_NUM_AC] = {
+       { 0, 3, 5,  7,   0 },   /* WME_AC_BE */
+       { 0, 3, 5, 10,   0 },   /* WME_AC_BK */
+       { 0, 2, 4,  5, 188 },   /* WME_AC_VI */
+       { 0, 2, 3,  4, 102 }    /* WME_AC_VO */
+};
+
+static const struct wmeParams iwi_wme_ofdm_params[WME_NUM_AC] = {
+       { 0, 3, 4,  6,   0 },   /* WME_AC_BE */
+       { 0, 3, 4, 10,   0 },   /* WME_AC_BK */
+       { 0, 2, 3,  4,  94 },   /* WME_AC_VI */
+       { 0, 2, 2,  3,  47 }    /* WME_AC_VO */
+};
+
+static int
+iwi_wme_update(struct ieee80211com *ic)
+{
+#define IWI_EXP2(v)    htole16((1 << (v)) - 1)
+#define IWI_USEC(v)    htole16(IEEE80211_TXOP_TO_US(v))
+       struct iwi_softc *sc = ic->ic_ifp->if_softc;
+       struct iwi_wme_params wme[3];
+       const struct wmeParams *wmep;
+       int ac;
+
+       /*
+        * We shall not override firmware default WME values if WME is not
+        * actually enabled.
+        */
+       if (!(ic->ic_flags & IEEE80211_F_WME))
+               return 0;
+
+       for (ac = 0; ac < WME_NUM_AC; ac++) {
+               /* set WME values for current operating mode */
+               wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac];
+               wme[0].aifsn[ac] = wmep->wmep_aifsn;
+               wme[0].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin);
+               wme[0].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax);
+               wme[0].burst[ac] = IWI_USEC(wmep->wmep_txopLimit);
+               wme[0].acm[ac]   = wmep->wmep_acm;
+
+               /* set WME values for CCK modulation */
+               wmep = &iwi_wme_cck_params[ac];
+               wme[1].aifsn[ac] = wmep->wmep_aifsn;
+               wme[1].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin);
+               wme[1].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax);
+               wme[1].burst[ac] = IWI_USEC(wmep->wmep_txopLimit);
+               wme[1].acm[ac]   = wmep->wmep_acm;
+
+               /* set WME values for OFDM modulation */
+               wmep = &iwi_wme_ofdm_params[ac];
+               wme[2].aifsn[ac] = wmep->wmep_aifsn;
+               wme[2].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin);
+               wme[2].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax);
+               wme[2].burst[ac] = IWI_USEC(wmep->wmep_txopLimit);
+               wme[2].acm[ac]   = wmep->wmep_acm;
+       }
+
+       DPRINTF(("Setting WME parameters\n"));
+       return iwi_cmd(sc, IWI_CMD_SET_WME_PARAMS, wme, sizeof wme, 1);
+#undef IWI_USEC
+#undef IWI_EXP2
+}
+
 /*
  * 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)
+static uint16_t
+iwi_read_prom_word(struct iwi_softc *sc, uint8_t addr)
 {
-       u_int32_t tmp;
-       u_int16_t val;
+       uint32_t tmp;
+       uint16_t val;
        int n;
 
        /* Clock C once before the first command */
@@ -1060,7 +1149,7 @@ iwi_read_prom_word(struct iwi_softc *sc, u_int8_t addr)
        IWI_EEPROM_CTL(sc, 0);
        IWI_EEPROM_CTL(sc, IWI_EEPROM_C);
 
-       return be16toh(val);
+       return val;
 }
 
 /*
@@ -1068,12 +1157,11 @@ iwi_read_prom_word(struct iwi_softc *sc, u_int8_t addr)
  * probe responses. Only used during AP detection.
  */
 static void
-iwi_fix_channel(struct iwi_softc *sc, struct mbuf *m)
+iwi_fix_channel(struct ieee80211com *ic, struct mbuf *m)
 {
-       struct ieee80211com *ic = &sc->sc_ic;
        struct ieee80211_frame *wh;
-       u_int8_t subtype;
-       u_int8_t *frm, *efrm;
+       uint8_t subtype;
+       uint8_t *frm, *efrm;
 
        wh = mtod(m, struct ieee80211_frame *);
 
@@ -1083,88 +1171,91 @@ iwi_fix_channel(struct iwi_softc *sc, struct mbuf *m)
        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);
+           subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
+               return;
 
-       frm = (u_int8_t *)(wh + 1);
-       efrm = mtod(m, u_int8_t *) + m->m_len;
+       frm = (uint8_t *)(wh + 1);
+       efrm = mtod(m, uint8_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]];
+                       ic->ic_curchan = &ic->ic_channels[frm[2]];
 
-               frm += frm[1] + 2; /* advance to the next tag */
+               frm += frm[1] + 2;
        }
 }
 
 static void
-iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i,
+iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i,
     struct iwi_frame *frame)
 {
        struct ieee80211com *ic = &sc->sc_ic;
-       struct ifnet *ifp = &ic->ic_if;
-       struct mbuf *m;
+       struct ifnet *ifp = ic->ic_ifp;
+       struct mbuf *mnew, *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));
+       DPRINTFN(5, ("received frame len=%u chan=%u rssi=%u\n",
+           le16toh(frame->len), frame->chan, frame->rssi_dbm));
+
+       if (le16toh(frame->len) < sizeof (struct ieee80211_frame))
+               return;
+
+       /*
+        * Try to allocate a new mbuf for this ring element and load it before
+        * processing the current mbuf. If the ring element cannot be loaded,
+        * drop the received packet and reuse the old mbuf. In the unlikely
+        * case that the old mbuf can't be reloaded either, explicitly panic.
+        */
+       mnew = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
+       if (mnew == NULL) {
+               ifp->if_ierrors++;
+               return;
+       }
+
+       bus_dmamap_unload(sc->rxq.data_dmat, data->map);
 
-       if (le16toh(frame->len) < sizeof (struct ieee80211_frame_min) ||
-           le16toh(frame->len) > MCLBYTES) {
-               device_printf(sc->sc_dev, "bad frame length\n");
+       error = bus_dmamap_load(sc->rxq.data_dmat, data->map,
+           mtod(mnew, void *), MCLBYTES, iwi_dma_map_addr, &data->physaddr,
+           0);
+       if (error != 0) {
+               m_freem(mnew);
+
+               /* try to reload the old mbuf */
+               error = bus_dmamap_load(sc->rxq.data_dmat, data->map,
+                   mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr,
+                   &data->physaddr, 0);
+               if (error != 0) {
+                       /* very unlikely that it will fail... */
+                       panic("%s: could not load old rx mbuf",
+                           device_get_name(sc->sc_dev));
+               }
+               ifp->if_ierrors++;
                return;
        }
 
-       bus_dmamap_unload(sc->rx_buf_dmat, buf->map);
+       /*
+        * New mbuf successfully loaded, update Rx ring and continue
+        * processing.
+        */
+       m = data->m;
+       data->m = mnew;
+       CSR_WRITE_4(sc, data->reg, data->physaddr);
 
        /* 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 (ic->ic_state == IEEE80211_S_SCAN)
+               iwi_fix_channel(ic, m);
 
        if (sc->sc_drvbpf != NULL) {
                struct iwi_rx_radiotap_header *tap = &sc->sc_rxtap;
@@ -1176,53 +1267,25 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i,
                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;
-       }
+       wh = mtod(m, struct ieee80211_frame *);
+       ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
 
-       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;
-       }
+       /* send the frame to the 802.11 layer */
+       ieee80211_input(ic, m, ni, frame->rssi_dbm, 0);
 
-       CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4, buf->physaddr);
+       /* node is no longer needed */
+       ieee80211_free_node(ni);
 }
 
 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;
@@ -1232,7 +1295,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
        case IWI_NOTIF_TYPE_SCAN_CHANNEL:
                chan = (struct iwi_notif_scan_channel *)(notif + 1);
 
-               DPRINTFN(2, ("Scan channel (%u)\n", chan->nchan));
+               DPRINTFN(2, ("Scanning channel (%u)\n", chan->nchan));
                break;
 
        case IWI_NOTIF_TYPE_SCAN_COMPLETE:
@@ -1241,14 +1304,12 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
                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);
-               else
-                       ieee80211_end_scan(ifp);
-               wakeup(IWI_FW_SCAN_COMPLETED(sc));
+               /* monitor mode uses scan to set the channel ... */
+               if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+                       sc->flags &= ~IWI_FLAG_SCANNING;
+                       ieee80211_end_scan(ic);
+               } else
+                       iwi_set_chan(sc, ic->ic_ibss_chan);
                break;
 
        case IWI_NOTIF_TYPE_AUTHENTICATION:
@@ -1258,11 +1319,11 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
 
                switch (auth->state) {
                case IWI_AUTHENTICATED:
+                       ieee80211_node_authorize(ic->ic_bss);
                        ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
                        break;
 
                case IWI_DEAUTHENTICATED:
-                       ieee80211_begin_scan(ifp);/* not necessary */
                        break;
 
                default:
@@ -1278,15 +1339,16 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
                    assoc->status));
 
                switch (assoc->state) {
+               case IWI_AUTHENTICATED:
+                       /* re-association, do nothing */
+                       break;
+
                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 */
+                       ieee80211_begin_scan(ic, 1);
                        break;
 
                default:
@@ -1295,44 +1357,31 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
                }
                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);
+               DPRINTFN(5, ("Notification (%u)\n", notif->type));
        }
 }
 
 static void
 iwi_rx_intr(struct iwi_softc *sc)
 {
-       struct iwi_rx_buf *buf;
+       struct iwi_rx_data *data;
        struct iwi_hdr *hdr;
-       u_int32_t r, i;
-
-       r = CSR_READ_4(sc, IWI_CSR_RX_READ_INDEX);
+       uint32_t hw;
 
-       for (i = (sc->rx_cur + 1) % IWI_RX_RING_SIZE; i != r;
-            i = (i + 1) % IWI_RX_RING_SIZE) {
+       hw = CSR_READ_4(sc, IWI_CSR_RX_RIDX);
 
-               buf = &sc->rx_buf[i];
+       for (; sc->rxq.cur != hw;) {
+               data = &sc->rxq.data[sc->rxq.cur];
 
-               bus_dmamap_sync(sc->rx_buf_dmat, buf->map,
+               bus_dmamap_sync(sc->rxq.data_dmat, data->map,
                    BUS_DMASYNC_POSTREAD);
 
-               hdr = mtod(buf->m, struct iwi_hdr *);
+               hdr = mtod(data->m, struct iwi_hdr *);
 
                switch (hdr->type) {
                case IWI_HDR_TYPE_FRAME:
-                       iwi_frame_intr(sc, buf, i,
+                       iwi_frame_intr(sc, data, sc->rxq.cur,
                            (struct iwi_frame *)(hdr + 1));
                        break;
 
@@ -1345,82 +1394,67 @@ iwi_rx_intr(struct iwi_softc *sc)
                        device_printf(sc->sc_dev, "unknown hdr type %u\n",
                            hdr->type);
                }
+
+               DPRINTFN(15, ("rx done idx=%u\n", sc->rxq.cur));
+
+               sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
        }
 
        /* 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);
+       hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
+       CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, hw);
 }
 
 static void
-iwi_tx_intr(struct iwi_softc *sc)
+iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq)
 {
        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
+       struct ifnet *ifp = ic->ic_ifp;
+       struct iwi_tx_data *data;
+       uint32_t hw;
 
-       for (i = (sc->tx_old + 1) % IWI_TX_RING_SIZE; i != r;
-            i = (i + 1) % IWI_TX_RING_SIZE) {
+       hw = CSR_READ_4(sc, txq->csr_ridx);
 
-               buf = &sc->tx_buf[i];
+       for (; txq->next != hw;) {
+               data = &txq->data[txq->next];
 
-               bus_dmamap_sync(sc->tx_buf_dmat, buf->map,
+               bus_dmamap_sync(txq->data_dmat, data->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;
+               bus_dmamap_unload(txq->data_dmat, data->map);
+               m_freem(data->m);
+               data->m = NULL;
+               ieee80211_free_node(data->ni);
+               data->ni = NULL;
 
-               sc->tx_queued--;
+               DPRINTFN(15, ("tx done idx=%u\n", txq->next));
 
-               /* kill watchdog timer */
-               sc->sc_tx_timer = 0;
-       }
+               ifp->if_opackets++;
 
-       /* Remember what the firmware has processed */
-       sc->tx_old = (r == 0) ? IWI_TX_RING_SIZE - 1 : r - 1;
+               txq->queued--;
+               txq->next = (txq->next + 1) % IWI_TX_RING_COUNT;
+       }
 
-       /* Call start() since some buffer descriptors have been released */
+       sc->sc_tx_timer = 0;
        ifp->if_flags &= ~IFF_OACTIVE;
-       (*ifp->if_start)(ifp);
+       iwi_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;
+       uint32_t r;
 
-       if ((r = CSR_READ_4(sc, IWI_CSR_INTR)) == 0 || r == 0xffffffff)
+       r = CSR_READ_4(sc, IWI_CSR_INTR);
+       if (r == 0 || r == 0xffffffff)
                return;
 
-       /* Disable interrupts */
+       /* 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) {
+       if (r & (IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR)) {
                device_printf(sc->sc_dev, "fatal error\n");
-               sc->sc_ic.ic_if.if_flags &= ~IFF_UP;
+               sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
                iwi_stop(sc);
        }
 
@@ -1430,149 +1464,184 @@ iwi_intr(void *arg)
        }
 
        if (r & IWI_INTR_RADIO_OFF) {
-               DPRINTF(("radio transmitter off\n"));
-               sc->sc_ic.ic_if.if_flags &= ~IFF_UP;
+               DPRINTF(("radio transmitter turned off\n"));
+               sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
                iwi_stop(sc);
-               sc->flags |= IWI_FLAG_RF_DISABLED;
        }
 
-       if (r & IWI_INTR_RX_TRANSFER)
-               iwi_rx_intr(sc);
-
-       if (r & IWI_INTR_CMD_TRANSFER)
+       if (r & IWI_INTR_CMD_DONE)
                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);
-
-       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 (r & IWI_INTR_TX1_DONE)
+               iwi_tx_intr(sc, &sc->txq[0]);
 
-       if (error != 0)
-               return;
+       if (r & IWI_INTR_TX2_DONE)
+               iwi_tx_intr(sc, &sc->txq[1]);
 
-       KASSERT(nseg <= IWI_MAX_NSEG, ("too many DMA segments %d", nseg));
+       if (r & IWI_INTR_TX3_DONE)
+               iwi_tx_intr(sc, &sc->txq[2]);
 
-       bcopy(segs, map->segs, nseg * sizeof (bus_dma_segment_t));
-       map->nseg = nseg;
-       map->mapsize = mapsize;
-}
+       if (r & IWI_INTR_TX4_DONE)
+               iwi_tx_intr(sc, &sc->txq[3]);
 
-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;
-       }
+       if (r & IWI_INTR_RX_DONE)
+               iwi_rx_intr(sc);
 
-       KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+       /* acknowledge interrupts */
+       CSR_WRITE_4(sc, IWI_CSR_INTR, r);
 
-       *(bus_addr_t *)arg = segs[0].ds_addr;
+       /* re-enable interrupts */
+       CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK);
 }
 
 static int
-iwi_cmd(struct iwi_softc *sc, u_int8_t type, void *data, u_int8_t len,
-    int async)
+iwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len, int async)
 {
        struct iwi_cmd_desc *desc;
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
        int ret;
 
-       DPRINTFN(2, ("TX!CMD!%u!%u\n", type, len));
+       desc = &sc->cmdq.desc[sc->cmdq.cur];
 
-       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);
+       memcpy(desc->data, data, len);
 
-       bus_dmamap_sync(sc->cmd_ring_dmat, sc->cmd_ring_map,
+       bus_dmamap_sync(sc->cmdq.desc_dmat, sc->cmdq.desc_map,
            BUS_DMASYNC_PREWRITE);
 
-       sc->cmd_cur = (sc->cmd_cur + 1) % IWI_CMD_RING_SIZE;
+       DPRINTFN(2, ("sending command idx=%u type=%u len=%u\n", sc->cmdq.cur,
+           type, len));
+
+       sc->cmdq.cur = (sc->cmdq.cur + 1) % IWI_CMD_RING_COUNT;
+       CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur);
+
        if (!async) {
-               struct ifnet *ifp = &sc->sc_ic.ic_if;
+               ASSERT_SERIALIZED(ifp->if_serializer);
 
                crit_enter();
-               CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur);
                tsleep_interlock(IWI_FW_CMD_ACKED(sc));
                lwkt_serialize_exit(ifp->if_serializer);
                ret = tsleep(IWI_FW_CMD_ACKED(sc), 0, "iwicmd", hz);
                crit_exit();
                lwkt_serialize_enter(ifp->if_serializer);
        } else {
-               CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur);
                ret = 0;
        }
 
-       return ret; 
+       return ret;
+}
+
+static void
+iwi_write_ibssnode(struct iwi_softc *sc, const struct iwi_node *in)
+{
+       struct iwi_ibssnode node;
+
+       /* write node information into NIC memory */
+       memset(&node, 0, sizeof node);
+       IEEE80211_ADDR_COPY(node.bssid, in->in_node.ni_macaddr);
+
+       CSR_WRITE_REGION_1(sc,
+           IWI_CSR_NODE_BASE + in->in_station * sizeof node,
+           (uint8_t *)&node, sizeof node);
+}
+
+struct iwi_dma_mapping {
+       bus_dma_segment_t segs[IWI_MAX_NSEG];
+       int nseg;
+       bus_size_t mapsize;
+};
+
+static void
+iwi_dma_map_mbuf(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 int
-iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
+iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni,
+    int ac)
 {
        struct iwi_softc *sc = ifp->if_softc;
        struct ieee80211com *ic = &sc->sc_ic;
+       struct iwi_node *in = (struct iwi_node *)ni;
        struct ieee80211_frame *wh;
-       struct iwi_tx_buf *buf;
+       struct ieee80211_key *k;
+       const struct chanAccParams *cap;
+       struct iwi_tx_ring *txq = &sc->txq[ac];
+       struct iwi_tx_data *data;
        struct iwi_tx_desc *desc;
-       struct iwi_dma_mapping map;
        struct mbuf *mnew;
-       u_int32_t id = 0;
-       int error, i;
+       struct iwi_dma_mapping map;
+       int error, hdrlen, i, noack = 0;
+
+       wh = mtod(m0, struct ieee80211_frame *);
+
+       if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
+               hdrlen = sizeof (struct ieee80211_qosframe);
+               cap = &ic->ic_wme.wme_chanParams;
+               noack = cap->cap_wmeParams[ac].wmep_noackPolicy;
+       } else
+               hdrlen = sizeof (struct ieee80211_frame);
+
+       /*
+        * This is only used in IBSS mode where the firmware expect an index
+        * in a h/w table instead of a destination address.
+        */
+       if (ic->ic_opmode == IEEE80211_M_IBSS && in->in_station == -1) {
+               in->in_station = iwi_alloc_ibss_node(sc);
+               if (in->in_station == -1) {     /* h/w table is full */
+                       m_freem(m0);
+                       ieee80211_free_node(ni);
+                       ifp->if_oerrors++;
+                       if_printf(ifp, "ibss table is full\n");
+                       return 0;
+               }
+               iwi_write_ibssnode(sc, in);
+       }
+
+       if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+               k = ieee80211_crypto_encap(ic, ni, m0);
+               if (k == NULL) {
+                       m_freem(m0);
+                       return ENOBUFS;
+               }
+
+               /* packet header may have moved, reset our local pointer */
+               wh = mtod(m0, struct ieee80211_frame *);
+       }
 
        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);
+               tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
+               tap->wt_chan_flags = htole16(ic->ic_ibss_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;
+       data = &txq->data[txq->cur];
+       desc = &txq->desc[txq->cur];
 
-       /* trim IEEE802.11 header */
-       m_adj(m0, sizeof (struct ieee80211_frame));
+       /* save and trim IEEE802.11 header */
+       m_copydata(m0, 0, hdrlen, (caddr_t)&desc->wh);
+       m_adj(m0, hdrlen);
 
-       error = bus_dmamap_load_mbuf(sc->tx_buf_dmat, buf->map, m0,
-           iwi_dma_map_buf, &map, BUS_DMA_NOWAIT);
+       error = bus_dmamap_load_mbuf(txq->data_dmat, data->map, m0,
+                                    iwi_dma_map_mbuf, &map, BUS_DMA_NOWAIT);
        if (error != 0 && error != EFBIG) {
                device_printf(sc->sc_dev, "could not map mbuf (error %d)\n",
                    error);
@@ -1589,8 +1658,9 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
                }
                m0 = mnew;
 
-               error = bus_dmamap_load_mbuf(sc->tx_buf_dmat, buf->map, m0,
-                   iwi_dma_map_buf, &map, BUS_DMA_NOWAIT);
+               error = bus_dmamap_load_mbuf(txq->data_dmat, data->map, m0,
+                                            iwi_dma_map_mbuf, &map,
+                                            BUS_DMA_NOWAIT);
                if (error != 0) {
                        device_printf(sc->sc_dev,
                            "could not map mbuf (error %d)\n", error);
@@ -1599,46 +1669,50 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
                }
        }
 
-       buf->m = m0;
-       buf->ni = ni;
+       data->m = m0;
+       data->ni = ni;
 
        desc->hdr.type = IWI_HDR_TYPE_DATA;
        desc->hdr.flags = IWI_HDR_FLAG_IRQ;
+       desc->station =
+           (ic->ic_opmode == IEEE80211_M_IBSS) ? in->in_station : 0;
        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->xflags = 0;
+
+       if (!noack && !IEEE80211_IS_MULTICAST(desc->wh.i_addr1))
                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;
+#if 0
+       if (ic->ic_flags & IEEE80211_F_PRIVACY) {
+               desc->wh.i_fc[1] |= IEEE80211_FC1_WEP;
+               desc->weptxkey = ic->ic_crypto.cs_def_txkey;
        } else
+#endif
                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));
+       if (desc->wh.i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS)
+               desc->xflags |= IWI_DATA_XFLAG_QOS;
+
        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);
+               desc->seg_len[i]  = htole16(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);
+       bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
+       bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE);
 
-       DPRINTFN(5, ("TX!DATA!%u!%u\n", desc->len, desc->nseg));
+       DPRINTFN(5, ("sending data frame txq=%u idx=%u len=%u nseg=%u\n",
+           ac, txq->cur, le16toh(desc->len), nsegs));
 
-       /* 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);
+       txq->queued++;
+       txq->cur = (txq->cur + 1) % IWI_TX_RING_COUNT;
+       CSR_WRITE_4(sc, txq->csr_widx, txq->cur);
 
        return 0;
 }
@@ -1649,185 +1723,129 @@ iwi_start(struct ifnet *ifp)
        struct iwi_softc *sc = ifp->if_softc;
        struct ieee80211com *ic = &sc->sc_ic;
        struct mbuf *m0;
+       struct ether_header *eh;
        struct ieee80211_node *ni;
+       int ac;
 
-       if (ic->ic_state != IEEE80211_S_RUN) {
+       if (ic->ic_state != IEEE80211_S_RUN)
                return;
-       }
 
        for (;;) {
-               m0 = ifq_poll(&ifp->if_snd);
+               m0 = ifq_dequeue(&ifp->if_snd, NULL);
                if (m0 == NULL)
                        break;
 
-               if (sc->tx_queued >= IWI_TX_RING_SIZE - 4) {
+               if (m0->m_len < sizeof (struct ether_header) &&
+                   (m0 = m_pullup(m0, sizeof (struct ether_header))) == NULL) {
+                       ifp->if_oerrors++;
+                       continue;
+               }
+               eh = mtod(m0, struct ether_header *);
+               ni = ieee80211_find_txnode(ic, eh->ether_dhost);
+               if (ni == NULL) {
+                       m_freem(m0);
+                       ifp->if_oerrors++;
+                       continue;
+               }
+
+               /* classify mbuf so we can find which tx ring to use */
+               if (ieee80211_classify(ic, m0, ni) != 0) {
+                       m_freem(m0);
+                       ieee80211_free_node(ni);
+                       ifp->if_oerrors++;
+                       continue;
+               }
+
+               /* no QoS encapsulation for EAPOL frames */
+               ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ?
+                   M_WME_GETAC(m0) : WME_AC_BE;
+
+               if (sc->txq[ac].queued > IWI_TX_RING_COUNT - 8) {
+                       /* there is no place left in this ring */
+                       m_freem(m0);
+                       ieee80211_free_node(ni);
                        ifp->if_flags |= IFF_OACTIVE;
                        break;
                }
-               ifq_dequeue(&ifp->if_snd, m0);
 
                BPF_MTAP(ifp, m0);
 
-               m0 = ieee80211_encap(ifp, m0, &ni);
-               if (m0 == NULL)
+               m0 = ieee80211_encap(ic, m0, ni);
+               if (m0 == NULL) {
+                       ieee80211_free_node(ni);
+                       ifp->if_oerrors++;
                        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);
+               if (iwi_tx_start(ifp, m0, ni, ac) != 0) {
+                       ieee80211_free_node(ni);
+                       ifp->if_oerrors++;
                        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;
+       struct ieee80211com *ic = &sc->sc_ic;
 
        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));
+                       ifp->if_oerrors++;
+                       ifp->if_flags &= ~IFF_UP;
+                       iwi_stop(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);
-
-               crit_enter();
-               tsleep_interlock(IWI_FW_SCAN_COMPLETED(sc));
-               lwkt_serialize_exit(ifp->if_serializer);
-               tsleep(IWI_FW_SCAN_COMPLETED(sc), PCATCH, "ssidscan", hz * 2);
-               crit_exit();
-               lwkt_serialize_enter(ifp->if_serializer);
-
-               ieee80211_end_scan(ifp);
-               break;
-       default:
-               error = ENOTTY;
-               break;
-       }
-       return (error);
+       ieee80211_watchdog(ic);
 }
 
-
-
-
 static int
 iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
 {
        struct iwi_softc *sc = ifp->if_softc;
+       struct ieee80211com *ic = &sc->sc_ic;
        struct ifreq *ifr;
-       struct ieee80211req *ireq;
-       struct ifaddr *ifa;
        int error = 0;
 
        switch (cmd) {
-       case SIOCSIFADDR:
-               /*
-                * Handle this here instead of in net80211_ioctl.c
-                * so that we can 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)) {
+                       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) {
+                       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)
+               error = suser_cred(cr, NULL_CRED_OKAY);
+               if (error != 0)
                        break;
 
                ifr = (struct ifreq *)data;
-               error = iwi_cache_firmware(sc, ifr->ifr_data,
-                               (cmd == SIOCSLOADIBSSFW) ? 1 : 0);
+               error = iwi_cache_firmware(sc, ifr->ifr_data);
                break;
 
        case SIOCSKILLFW:
                /* only super-user can do that! */
-               if ((error = suser(curthread)) != 0)
+               error = suser_cred(cr, NULL_CRED_OKAY);
+               if (error != 0)
                        break;
 
                ifp->if_flags &= ~IFF_UP;
@@ -1835,95 +1853,28 @@ iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                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);
+               error = ieee80211_ioctl(ic, cmd, data, cr);
        }
 
        if (error == ENETRESET) {
-               error = 0;
                if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
-                   (IFF_UP | IFF_RUNNING)) {
+                   (IFF_UP | IFF_RUNNING) &&
+                   (ic->ic_roaming != IEEE80211_ROAMING_MANUAL))
                        iwi_init(sc);
-                       error = tsleep(IWI_FW_CMD_ACKED(sc), 0, "iwirun", hz);
-               }
+               error = 0;
        }
-       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);
+       return error;
 }
 
 static void
 iwi_stop_master(struct iwi_softc *sc)
 {
+       uint32_t tmp;
        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 ) ) {
-               struct ifnet *ifp = &sc->sc_ic.ic_if;
-
-               ASSERT_SERIALIZED(ifp->if_serializer);
-
-               iwi_abort_scan(sc);
-               if (( sc->flags & IWI_FLAG_SCAN_ABORT ) && 
-                   !( sc->flags & IWI_FLAG_RF_DISABLED )) {
-                       crit_enter();
-                       tsleep_interlock(IWI_FW_SCAN_COMPLETED(sc));
-                       lwkt_serialize_exit(ifp->if_serializer);
-                       tsleep(IWI_FW_SCAN_COMPLETED(sc), 0, "iwiabr", hz);
-                       crit_exit();
-                       lwkt_serialize_enter(ifp->if_serializer);
-               }
-       }
-       /* Disable interrupts */
-
+       /* disable interrupts */
        CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0);
 
        CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_STOP_MASTER);
@@ -1932,11 +1883,11 @@ iwi_stop_master(struct iwi_softc *sc)
                        break;
                DELAY(10);
        }
-       if (ntries == 5 && sc->debug_level > 0) 
-               device_printf(sc->sc_dev, "timeout waiting for master\n");
+       if (ntries == 5)
+               if_printf(&sc->sc_ic.ic_if, "timeout waiting for master\n");
 
-       CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
-           IWI_RST_PRINCETON_RESET);
+       tmp = CSR_READ_4(sc, IWI_CSR_RST);
+       CSR_WRITE_4(sc, IWI_CSR_RST, tmp | IWI_RST_PRINCETON_RESET);
 
        sc->flags &= ~IWI_FLAG_FW_INITED;
 }
@@ -1944,15 +1895,14 @@ iwi_stop_master(struct iwi_softc *sc)
 static int
 iwi_reset(struct iwi_softc *sc)
 {
+       uint32_t tmp;
        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);
+       tmp = CSR_READ_4(sc, IWI_CSR_CTL);
+       CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | 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 */
@@ -1962,33 +1912,32 @@ iwi_reset(struct iwi_softc *sc)
                DELAY(200);
        }
        if (ntries == 1000) {
+               if_printf(&sc->sc_ic.ic_if,
+                         "timeout waiting for clock stabilization\n");
                return EIO;
        }
 
-       CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
-           IWI_RST_SW_RESET);
+       tmp = CSR_READ_4(sc, IWI_CSR_RST);
+       CSR_WRITE_4(sc, IWI_CSR_RST, tmp | IWI_RST_SOFT_RESET);
 
        DELAY(10);
 
-       CSR_WRITE_4(sc, IWI_CSR_CTL, CSR_READ_4(sc, IWI_CSR_CTL) |
-           IWI_CTL_INIT);
-
+       tmp = CSR_READ_4(sc, IWI_CSR_CTL);
+       CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_INIT);
 
        /* Clear NIC memory */
        CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0);
-
-       for (i = 0; i < 0xc000; i++) {
+       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;
+       uint32_t tmp;
+       uint16_t *w;
        int ntries, i;
 
        CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
@@ -2005,27 +1954,30 @@ iwi_load_ucode(struct iwi_softc *sc, void *uc, int size)
 
        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);
+
+       tmp = CSR_READ_4(sc, IWI_CSR_RST);
+       tmp &= ~IWI_RST_PRINCETON_RESET;
+       CSR_WRITE_4(sc, IWI_CSR_RST, tmp);
+
        DELAY(5000);
        MEM_WRITE_4(sc, 0x3000e0, 0);
        DELAY(1000);
-       MEM_WRITE_4(sc, 0x300004, 1);
+       MEM_WRITE_4(sc, IWI_MEM_EVENT_CTL, 1);
        DELAY(1000);
-       MEM_WRITE_4(sc, 0x300004, 0);
+       MEM_WRITE_4(sc, IWI_MEM_EVENT_CTL, 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 */
+       /* write microcode into adapter memory */
        for (w = uc; size > 0; w++, size -= 2)
-               MEM_WRITE_2(sc, 0x200010, *w);
+               MEM_WRITE_2(sc, 0x200010, htole16(*w));
 
        MEM_WRITE_1(sc, 0x200000, 0x00);
        MEM_WRITE_1(sc, 0x200000, 0x80);
 
-       /* Wait until we get a response in the uc queue */
+       /* wait until we get an answer */
        for (ntries = 0; ntries < 100; ntries++) {
                if (MEM_READ_1(sc, 0x200000) & 1)
                        break;
@@ -2037,7 +1989,7 @@ iwi_load_ucode(struct iwi_softc *sc, void *uc, int size)
                return EIO;
        }
 
-       /* Empty the uc queue or the firmware will not initialize properly */
+       /* read the answer or the firmware will not initialize properly */
        for (i = 0; i < 7; i++)
                MEM_READ_4(sc, 0x200004);
 
@@ -2048,6 +2000,7 @@ iwi_load_ucode(struct iwi_softc *sc, void *uc, int size)
 
 /* 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)
 {
@@ -2056,25 +2009,21 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size)
        bus_addr_t physaddr;
        void *virtaddr;
        u_char *p, *end;
-       u_int32_t sentinel, ctl, src, dst, sum, len, mlen;
+       uint32_t sentinel, ctl, src, dst, sum, len, mlen, tmp;
        int ntries, error = 0;
        struct ifnet *ifp = &sc->sc_ic.ic_if;
 
-       sc->flags &= ~(IWI_FLAG_FW_INITED);
+       ASSERT_SERIALIZED(ifp->if_serializer);
 
-       /* 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);
+       /* Allocate DMA memory for mapping firmware image */
+       error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+           BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, &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,
@@ -2090,7 +2039,7 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size)
        }
 
        /* Copy firmware image to DMA memory */
-       bcopy(fw, virtaddr, size);
+       memcpy(virtaddr, fw, size);
 
        /* Make sure the adapter will get up-to-date values */
        bus_dmamap_sync(dmat, map, BUS_DMASYNC_PREWRITE);
@@ -2135,13 +2084,14 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size)
        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));
+       tmp = CSR_READ_4(sc, IWI_CSR_RST);
+       tmp &= ~(IWI_RST_MASTER_DISABLED | IWI_RST_STOP_MASTER);
+       CSR_WRITE_4(sc, IWI_CSR_RST, tmp);
 
        /* Tell the adapter to start processing command blocks */
        MEM_WRITE_4(sc, 0x3000a4, 0x540100);
 
-       /* Wait until the adapter has processed all command blocks */
+       /* Wait until the adapter reaches the sentinel */
        for (ntries = 0; ntries < 400; ntries++) {
                if (MEM_READ_4(sc, 0x3000d0) >= sentinel)
                        break;
@@ -2154,22 +2104,23 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size)
                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 */
+       /* Allow interrupts so we know when the firmware is ready */
        CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK);
 
        /* Tell the adapter to initialize the firmware */
-       crit_enter();
        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);
 
+       tmp = CSR_READ_4(sc, IWI_CSR_CTL);
+       CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_ALLOW_STANDBY);
+
+       /* wait at most one second for firmware initialization to complete */
+       crit_enter();
        tsleep_interlock(IWI_FW_INITIALIZED(sc));
        lwkt_serialize_exit(ifp->if_serializer);
-       error = tsleep(IWI_FW_INITIALIZED(sc), 0, "iwiini", hz);
+       error = tsleep(IWI_FW_INITIALIZED(sc), 0, "iwiinit", hz);
        crit_exit();
        lwkt_serialize_enter(ifp->if_serializer);
        if (error != 0) {
@@ -2178,7 +2129,7 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size)
                goto fail4;
        }
 
-fail4:  bus_dmamap_sync(dmat, map, BUS_DMASYNC_POSTWRITE);
+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);
@@ -2191,7 +2142,7 @@ fail1:
  * e.g when the adapter wakes up from suspend mode.
  */
 static int
-iwi_cache_firmware(struct iwi_softc *sc, void *data, int is_ibss)
+iwi_cache_firmware(struct iwi_softc *sc, void *data)
 {
        struct iwi_firmware *kfw = &sc->fw;
        struct iwi_firmware ufw;
@@ -2199,57 +2150,37 @@ iwi_cache_firmware(struct iwi_softc *sc, void *data, int is_ibss)
 
        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;
+               return error;
 
        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;
+               goto fail;
 
        if ((error = copyin(ufw.ucode, kfw->ucode, kfw->ucode_size)) != 0)
-               goto fail4;
+               goto fail;
 
        if ((error = copyin(ufw.main, kfw->main, kfw->main_size)) != 0)
-               goto fail4;
+               goto fail;
 
        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:
+fail:
+       free(kfw->boot, M_DEVBUF);
+       free(kfw->ucode, M_DEVBUF);
+       free(kfw->main, M_DEVBUF);
 
        return error;
 }
@@ -2264,73 +2195,20 @@ iwi_free_firmware(struct iwi_softc *sc)
        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 );
+       sc->flags &= ~IWI_FLAG_FW_CACHED;
 }
 
 static int
 iwi_config(struct iwi_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
-       struct ifnet *ifp = &ic->ic_if;
+       struct ifnet *ifp = ic->ic_ifp;
+       struct iwi_configuration config;
        struct iwi_rateset rs;
        struct iwi_txpower power;
-       struct ieee80211_wepkey *k;
+       struct ieee80211_key *wk;
        struct iwi_wep_key wepkey;
-       u_int32_t data;
+       uint32_t data;
        int error, i;
 
        IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
@@ -2340,8 +2218,16 @@ iwi_config(struct iwi_softc *sc)
        if (error != 0)
                return error;
 
+       memset(&config, 0, sizeof config);
+       config.bluetooth_coexistence = sc->bluetooth;
+       config.antenna = sc->antenna;
+       config.multicast_enabled = 1;
+       config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0;
+       config.disable_unicast_decryption = 1;
+       config.disable_multicast_decryption = 1;
        DPRINTF(("Configuring adapter\n"));
-       if ((error = iwi_adapter_config(sc, 1, 0)) != 0)
+       error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, 0);
+       if (error != 0)
                return error;
 
        data = htole32(IWI_POWER_MODE_CAM);
@@ -2356,6 +2242,12 @@ iwi_config(struct iwi_softc *sc)
        if (error != 0)
                return error;
 
+       data = htole32(ic->ic_fragthreshold);
+       DPRINTF(("Setting fragmentation threshold to %u\n", le32toh(data)));
+       error = iwi_cmd(sc, IWI_CMD_SET_FRAG_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;
@@ -2380,7 +2272,7 @@ iwi_config(struct iwi_softc *sc)
        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,
+       memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11G].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);
@@ -2390,34 +2282,49 @@ iwi_config(struct iwi_softc *sc)
        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,
+       memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11A].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;
 
+       /* if we have a desired ESSID, set it now */
+       if (ic->ic_des_esslen != 0) {
+#ifdef IWI_DEBUG
+               if (iwi_debug > 0) {
+                       printf("Setting desired ESSID to ");
+                       ieee80211_print_essid(ic->ic_des_essid,
+                           ic->ic_des_esslen);
+                       printf("\n");
+               }
+#endif
+               error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ic->ic_des_essid,
+                   ic->ic_des_esslen, 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;
-               }
+       for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+               wk = &ic->ic_crypto.cs_nw_keys[i];
+
+               wepkey.cmd = IWI_WEP_KEY_CMD_SETKEY;
+               wepkey.idx = i;
+               wepkey.len = wk->wk_keylen;
+               memset(wepkey.key, 0, sizeof wepkey.key);
+               memcpy(wepkey.key, wk->wk_key, wk->wk_keylen);
+               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 */
@@ -2426,68 +2333,63 @@ iwi_config(struct iwi_softc *sc)
 }
 
 static int
-iwi_scan(struct iwi_softc *sc)
+iwi_set_chan(struct iwi_softc *sc, struct ieee80211_channel *chan)
 {
        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 */
+       memset(&scan, 0, sizeof scan);
+       memset(scan.type, IWI_SCAN_TYPE_PASSIVE, sizeof scan.type);
+       scan.passive = htole16(2000);
+       scan.channels[0] = 1 |
+           (IEEE80211_IS_CHAN_5GHZ(chan) ? IWI_CHAN_5GHZ : IWI_CHAN_2GHZ);
+       scan.channels[1] = ieee80211_chan2ieee(ic, chan);
+
+       DPRINTF(("Setting channel to %u\n", ieee80211_chan2ieee(ic, chan)));
+       return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1);
+}
 
-       sc->flags |= IWI_FLAG_SCANNING;
+static int
+iwi_scan(struct iwi_softc *sc)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct iwi_scan scan;
+       uint8_t *p;
+       int i, count;
 
-       bzero(&scan, sizeof scan);
+       memset(&scan, 0, 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);
+       if (ic->ic_des_esslen != 0) {
+               scan.bdirected = htole16(sc->dwelltime);
+               memset(scan.type, IWI_SCAN_TYPE_BDIRECTED, sizeof scan.type);
        } else {
-               scan.type = IWI_SCAN_TYPE_BROADCAST;
-               scan.intval = htole16(40);
+               scan.broadcast = htole16(sc->dwelltime);
+               memset(scan.type, IWI_SCAN_TYPE_BROADCAST, sizeof scan.type);
        }
 
        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++;
-                       }
+       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_5GHZ | count;
+
+       p = (count > 0) ? p + 1 : scan.channels;
+       count = 0;
+       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;
        }
+       *(p - count) = IWI_CHAN_2GHZ | count;
+
+       DPRINTF(("Start scanning\n"));
        return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1);
 }
 
@@ -2495,24 +2397,35 @@ static int
 iwi_auth_and_assoc(struct iwi_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
-       struct ifnet *ifp = &ic->ic_if;
+       struct ifnet *ifp = ic->ic_ifp;
        struct ieee80211_node *ni = ic->ic_bss;
+       struct ieee80211_wme_info wme;
+       struct iwi_configuration config;
+       struct iwi_associate assoc;
        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 */
-       }
+       uint16_t capinfo;
+       uint32_t data;
+       int error;
 
-       DPRINTF(("Configuring adapter\n"));
-       if ((error = iwi_adapter_config(sc, 
-               IEEE80211_IS_CHAN_5GHZ(ni->ni_chan), 1)) != 0)
+       if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
+               memset(&config, 0, sizeof config);
+               config.bluetooth_coexistence = sc->bluetooth;
+               config.antenna = sc->antenna;
+               config.multicast_enabled = 1;
+               config.use_protection = 1;
+               config.answer_pbreq =
+                   (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0;
+               config.disable_unicast_decryption = 1;
+               config.disable_multicast_decryption = 1;
+               DPRINTF(("Configuring adapter\n"));
+               error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config,
+                   1);
+               if (error != 0)
                        return error;
+       }
 
 #ifdef IWI_DEBUG
-       if (sc->debug_level > 0) {
+       if (iwi_debug > 0) {
                printf("Setting ESSID to ");
                ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
                printf("\n");
@@ -2527,55 +2440,79 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
            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");
-       }
-
+       memcpy(rs.rates, ni->ni_rates.rs_rates, rs.nrates);
+       DPRINTF(("Setting negociated rates (%u)\n", rs.nrates));
        error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 1);
        if (error != 0)
                return error;
 
+       if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) {
+               wme.wme_id = IEEE80211_ELEMID_VENDOR;
+               wme.wme_len = sizeof (struct ieee80211_wme_info) - 2;
+               wme.wme_oui[0] = 0x00;
+               wme.wme_oui[1] = 0x50;
+               wme.wme_oui[2] = 0xf2;
+               wme.wme_type = WME_OUI_TYPE;
+               wme.wme_subtype = WME_INFO_OUI_SUBTYPE;
+               wme.wme_version = WME_VERSION;
+               wme.wme_info = 0;
+
+               DPRINTF(("Setting WME IE (len=%u)\n", wme.wme_len));
+               error = iwi_cmd(sc, IWI_CMD_SET_WMEIE, &wme, sizeof wme, 1);
+               if (error != 0)
+                       return error;
+       }
+
+       if (ic->ic_opt_ie != NULL) {
+               DPRINTF(("Setting optional IE (len=%u)\n", ic->ic_opt_ie_len));
+               error = iwi_cmd(sc, IWI_CMD_SET_OPTIE, ic->ic_opt_ie,
+                   ic->ic_opt_ie_len, 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 :
+       memset(&assoc, 0, sizeof assoc);
+       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);
+       assoc.chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+       if (ni->ni_authmode == IEEE80211_AUTH_SHARED)
+               assoc.auth = ic->ic_crypto.cs_def_txkey << 4 | IWI_AUTH_SHARED;
+       if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL)
+               assoc.policy |= htole16(IWI_POLICY_WME);
+       if (ic->ic_flags & IEEE80211_F_WPA)
+               assoc.policy |= htole16(IWI_POLICY_WPA);
+       memcpy(assoc.tstamp, ni->ni_tstamp.data, 8);
+
+       if (ic->ic_opmode == IEEE80211_M_IBSS)
+               capinfo = IEEE80211_CAPINFO_IBSS;
+       else
+               capinfo = IEEE80211_CAPINFO_ESS;
+       if (ic->ic_flags & IEEE80211_F_PRIVACY)
+               capinfo |= IEEE80211_CAPINFO_PRIVACY;
+       if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
+           IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+               capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
+       if (ic->ic_flags & IEEE80211_F_SHSLOT)
+               capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
+       assoc.capinfo = htole16(capinfo);
+
+       assoc.lintval = htole16(ic->ic_lintval);
+       assoc.intval = htole16(ni->ni_intval);
+       IEEE80211_ADDR_COPY(assoc.bssid, ni->ni_bssid);
+       if (ic->ic_opmode == IEEE80211_M_IBSS)
+               IEEE80211_ADDR_COPY(assoc.dst, ifp->if_broadcastaddr);
        else
-               IEEE80211_ADDR_COPY(sc->assoc.dst, ni->ni_bssid);
+               IEEE80211_ADDR_COPY(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);
+           assoc.bssid, ":", assoc.chan, assoc.auth));
+       return iwi_cmd(sc, IWI_CMD_ASSOCIATE, &assoc, sizeof assoc, 1);
 }
 
 static void
@@ -2583,12 +2520,16 @@ iwi_init(void *priv)
 {
        struct iwi_softc *sc = priv;
        struct ieee80211com *ic = &sc->sc_ic;
-       struct ifnet *ifp = &ic->ic_if;
+       struct ifnet *ifp = ic->ic_ifp;
        struct iwi_firmware *fw = &sc->fw;
+       struct iwi_rx_data *data;
        int i;
 
        /* exit immediately if firmware has not been ioctl'd */
        if (!(sc->flags & IWI_FLAG_FW_CACHED)) {
+               if (!(sc->flags & IWI_FLAG_FW_WARNED))
+                       device_printf(sc->sc_dev, "Please load firmware\n");
+               sc->flags |= I