WPA support for ipw(4).
authordamien <damien@openbsd.org>
Thu, 28 Aug 2008 14:40:44 +0000 (14:40 +0000)
committerdamien <damien@openbsd.org>
Thu, 28 Aug 2008 14:40:44 +0000 (14:40 +0000)
Did a lot of cleanup while I was there.

share/man/man4/ipw.4
sys/dev/pci/if_ipw.c
sys/dev/pci/if_ipwreg.h

index ad9e17c..8bfd82c 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ipw.4,v 1.27 2008/07/29 17:03:35 jmc Exp $
+.\" $OpenBSD: ipw.4,v 1.28 2008/08/28 14:40:44 damien Exp $
 .\"
 .\" Copyright (c) 2004
 .\"    Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: July 29 2008 $
+.Dd $Mdocdate: August 28 2008 $
 .Os
 .Dt IPW 4
 .Sh NAME
@@ -70,12 +70,18 @@ or to scan for access points.
 .Pp
 The
 .Nm
-driver can be configured to use software
-Wireless Equivalent Privacy (WEP).
+driver can be configured to use
+Wireless Equivalent Privacy (WEP) or
+Wi-Fi Protected Access (WPA-PSK and WPA2-PSK).
+WPA is the de facto encryption standard for wireless networks.
 It is strongly recommended that WEP
 not be used as the sole mechanism
 to secure wireless communication,
 due to serious weaknesses in it.
+The
+.Nm
+driver relies on the software 802.11 stack for both encryption and decryption
+of data frames.
 .Pp
 The
 .Nm
@@ -118,16 +124,19 @@ channel 11, obtaining an IP address using DHCP:
 dhcp NONE NONE NONE nwkey 0x1deadbeef1 chan 11
 .Ed
 .Pp
-Configure ipw0 for WEP, using hex key
-.Dq 0x1deadbeef1 :
+Configure ipw0 to join network
+.Dq my_net
+using WPA-PSK with passphrase
+.Dq my_passphrase :
 .Bd -literal -offset indent
-# ifconfig ipw0 nwkey 0x1deadbeef1
+# ifconfig ipw0 nwid my_net wpa wpapsk \e
+       $(wpa-psk my_net my_passphrase)
 .Ed
 .Pp
 Return ipw0 to its default settings:
 .Bd -literal -offset indent
 # ifconfig ipw0 -bssid -chan media autoselect \e
-       nwid "" -nwkey
+       nwid "" -nwkey -wpa -wpapsk
 .Ed
 .Pp
 Join an existing BSS network,
index dec88cb..ce7e03c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_ipw.c,v 1.75 2008/08/27 09:28:38 damien Exp $      */
+/*     $OpenBSD: if_ipw.c,v 1.76 2008/08/28 14:40:44 damien Exp $      */
 
 /*-
  * Copyright (c) 2004-2008
@@ -36,6 +36,7 @@
 #include <sys/param.h>
 #include <sys/sockio.h>
 #include <sys/sysctl.h>
+#include <sys/workq.h>
 #include <sys/mbuf.h>
 #include <sys/kernel.h>
 #include <sys/socket.h>
@@ -106,6 +107,8 @@ int         ipw_reset(struct ipw_softc *);
 int            ipw_load_ucode(struct ipw_softc *, u_char *, int);
 int            ipw_load_firmware(struct ipw_softc *, u_char *, int);
 int            ipw_read_firmware(struct ipw_softc *, struct ipw_firmware *);
+void           ipw_scan(void *, void *);
+void           ipw_auth_and_assoc(void *, void *);
 int            ipw_config(struct ipw_softc *);
 int            ipw_init(struct ifnet *);
 void           ipw_stop(struct ifnet *, int);
@@ -235,6 +238,7 @@ ipw_attach(struct device *parent, struct device *self, void *aux)
            IEEE80211_C_TXPMGT |        /* tx power management */
            IEEE80211_C_SHPREAMBLE |    /* short preamble supported */
            IEEE80211_C_WEP |           /* s/w WEP */
+           IEEE80211_C_RSN |           /* WPA/RSN */
            IEEE80211_C_SCANALL;        /* h/w scanning */
 
        /* read MAC address from EEPROM */
@@ -665,29 +669,25 @@ int
 ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
 {
        struct ipw_softc *sc = ic->ic_softc;
-       struct ieee80211_node *ni;
-       uint8_t macaddr[IEEE80211_ADDR_LEN];
-       uint32_t len;
+       int error;
 
        switch (nstate) {
-       case IEEE80211_S_RUN:
-               DELAY(100);     /* firmware needs a short delay here */
-
-               len = IEEE80211_ADDR_LEN;
-               ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, macaddr, &len);
-
-               ni = ieee80211_find_node(ic, macaddr);
-               if (ni == NULL)
-                       break;
+       case IEEE80211_S_SCAN:
+               error = workq_add_task(NULL, 0, ipw_scan, sc, NULL);
+               if (error != 0)
+                       return error;
+               break;
 
-               (*ic->ic_node_copy)(ic, ic->ic_bss, ni);
-               ieee80211_node_newstate(ni, IEEE80211_STA_BSS);
+       case IEEE80211_S_AUTH:
+               error = workq_add_task(NULL, 0, ipw_auth_and_assoc, sc, NULL);
+               if (error != 0)
+                       return error;
                break;
 
+       case IEEE80211_S_RUN:
        case IEEE80211_S_INIT:
-       case IEEE80211_S_SCAN:
-       case IEEE80211_S_AUTH:
        case IEEE80211_S_ASSOC:
+               /* nothing to do */
                break;
        }
 
@@ -761,11 +761,10 @@ ipw_command_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
 
        cmd = mtod(sbuf->m, struct ipw_cmd *);
 
-       DPRINTFN(2, ("RX!CMD!%u!%u!%u!%u!%u\n",
-           letoh32(cmd->type), letoh32(cmd->subtype), letoh32(cmd->seq),
-           letoh32(cmd->len), letoh32(cmd->status)));
+       DPRINTFN(2, ("received command ack type=%u,status=%u\n",
+           letoh32(cmd->type), letoh32(cmd->status)));
 
-       wakeup(sc);
+       wakeup(&sc->cmd);
 }
 
 void
@@ -780,29 +779,26 @@ ipw_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
 
        state = letoh32(*mtod(sbuf->m, uint32_t *));
 
-       DPRINTFN(2, ("RX!NEWSTATE!%u\n", state));
+       DPRINTFN(2, ("firmware state changed to 0x%x\n", state));
 
        switch (state) {
        case IPW_STATE_ASSOCIATED:
                ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
                break;
 
-       case IPW_STATE_SCANNING:
-               /* 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_ASCAN;
-               break;
-
        case IPW_STATE_SCAN_COMPLETE:
-               ic->ic_flags &= ~IEEE80211_F_ASCAN;
+               if (ic->ic_state == IEEE80211_S_SCAN)
+                       ieee80211_end_scan(ifp);
                break;
 
        case IPW_STATE_ASSOCIATION_LOST:
                ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
                break;
 
+       case IPW_STATE_DISABLED:
+               wakeup(sc);
+               break;
+
        case IPW_STATE_RADIO_DISABLED:
                ifp->if_flags &= ~IFF_UP;
                ipw_stop(&ic->ic_if, 1);
@@ -822,7 +818,8 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
        struct ieee80211_node *ni;
        int error;
 
-       DPRINTFN(5, ("RX!DATA!%u!%u\n", letoh32(status->len), status->rssi));
+       DPRINTFN(5, ("received data frame len=%u,rssi=%u\n",
+           letoh32(status->len), status->rssi));
 
        /*
         * Try to allocate a new mbuf for this ring element and load it before
@@ -907,7 +904,7 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
 void
 ipw_notification_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
 {
-       DPRINTFN(2, ("RX!NOTIFICATION\n"));
+       DPRINTFN(2, ("received notification\n"));
 }
 
 void
@@ -1043,8 +1040,6 @@ ipw_intr(void *arg)
        /* disable interrupts */
        CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
 
-       DPRINTFN(8, ("INTR!0x%08x\n", r));
-
        if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) {
                printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname);
                ifp->if_flags &= ~IFF_UP;
@@ -1074,25 +1069,27 @@ int
 ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len)
 {
        struct ipw_soft_bd *sbd;
-       int error;
+       int s, error;
 
-       sbd = &sc->stbd_list[sc->txcur];
+       s = splnet();
+
+       sc->cmd.type = htole32(type);
+       sc->cmd.subtype = htole32(0);
+       sc->cmd.len = htole32(len);
+       sc->cmd.seq = htole32(0);
+       if (data != NULL)
+               bcopy(data, sc->cmd.data, len);
 
        error = bus_dmamap_load(sc->sc_dmat, sc->cmd_map, &sc->cmd,
            sizeof (struct ipw_cmd), NULL, BUS_DMA_NOWAIT);
        if (error != 0) {
                printf("%s: could not map command DMA memory\n",
                    sc->sc_dev.dv_xname);
+               splx(s);
                return error;
        }
 
-       sc->cmd.type = htole32(type);
-       sc->cmd.subtype = htole32(0);
-       sc->cmd.len = htole32(len);
-       sc->cmd.seq = htole32(0);
-       if (data != NULL)
-               bcopy(data, sc->cmd.data, len);
-
+       sbd = &sc->stbd_list[sc->txcur];
        sbd->type = IPW_SBD_TYPE_COMMAND;
        sbd->bd->physaddr = htole32(sc->cmd_map->dm_segs[0].ds_addr);
        sbd->bd->len = htole32(sizeof (struct ipw_cmd));
@@ -1102,7 +1099,6 @@ ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len)
 
        bus_dmamap_sync(sc->sc_dmat, sc->cmd_map, 0, sizeof (struct ipw_cmd),
            BUS_DMASYNC_PREWRITE);
-
        bus_dmamap_sync(sc->sc_dmat, sc->tbd_map,
            sc->txcur * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
            BUS_DMASYNC_PREWRITE);
@@ -1111,10 +1107,13 @@ ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len)
        sc->txfree--;
        CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, sc->txcur);
 
-       DPRINTFN(2, ("TX!CMD!%u!%u!%u!%u\n", type, 0, 0, len));
+       DPRINTFN(2, ("sending command type=%u,len=%u\n", type, len));
 
        /* wait at most one second for command to complete */
-       return tsleep(sc, 0, "ipwcmd", hz);
+       error = tsleep(&sc->cmd, 0, "ipwcmd", hz);
+       splx(s);
+
+       return error;
 }
 
 int
@@ -1241,11 +1240,6 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
        sbd->bd->flags = IPW_BD_FLAG_TX_FRAME_802_3 |
            IPW_BD_FLAG_TX_NOT_LAST_FRAGMENT;
 
-       DPRINTFN(5, ("TX!HDR!%u!%u!%u!%u", shdr->hdr.type, shdr->hdr.subtype,
-           shdr->hdr.encrypted, shdr->hdr.encrypt));
-       DPRINTFN(5, ("!%s", ether_sprintf(shdr->hdr.src_addr)));
-       DPRINTFN(5, ("!%s\n", ether_sprintf(shdr->hdr.dst_addr)));
-
        bus_dmamap_sync(sc->sc_dmat, sc->tbd_map,
            sc->txcur * sizeof (struct ipw_bd),
            sizeof (struct ipw_bd), BUS_DMASYNC_PREWRITE);
@@ -1271,9 +1265,6 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
                        sbd->bd->flags |= IPW_BD_FLAG_TX_NOT_LAST_FRAGMENT;
                }
 
-               DPRINTFN(5, ("TX!FRAG!%d!%d\n", i,
-                   sbuf->map->dm_segs[i].ds_len));
-
                bus_dmamap_sync(sc->sc_dmat, sc->tbd_map,
                    sc->txcur * sizeof (struct ipw_bd),
                    sizeof (struct ipw_bd), BUS_DMASYNC_PREWRITE);
@@ -1301,11 +1292,10 @@ ipw_start(struct ifnet *ifp)
        struct ieee80211_node *ni;
        struct mbuf *m;
 
-       for (;;) {
-               IF_PURGE(&ic->ic_mgtq);
+       if (ic->ic_state != IEEE80211_S_RUN)
+               return;
 
-               if (ic->ic_state != IEEE80211_S_RUN)
-                       return;
+       for (;;) {
                IFQ_POLL(&ifp->if_snd, m);
                if (m == NULL)
                        break;
@@ -1671,18 +1661,174 @@ fail:  free(fw->data, M_DEVBUF);
        return error;
 }
 
+void
+ipw_scan(void *arg1, void *arg2)
+{
+       struct ipw_softc *sc = arg1;
+       struct ifnet *ifp = &sc->sc_ic.ic_if;
+       struct ipw_scan_options scan;
+       uint8_t ssid[IEEE80211_NWID_LEN];
+       int error;
+
+       /*
+        * Firmware has a bug and does not honour the ``do not associate
+        * after scan'' bit in the scan command.  To prevent the firmware
+        * from associating after the scan, we set the ESSID to something
+        * unlikely to be used by a real AP.
+        * XXX would setting the BSSID to a multicast address work?
+        */
+       memset(ssid, '\r', sizeof ssid);
+       error = ipw_cmd(sc, IPW_CMD_SET_ESSID, ssid, sizeof ssid);
+       if (error != 0)
+               goto fail;
+
+       /* no mandatory BSSID */
+       DPRINTF(("Setting mandatory BSSID to null\n"));
+       error = ipw_cmd(sc, IPW_CMD_SET_MANDATORY_BSSID, NULL, 0);
+       if (error != 0)
+               goto fail;
+
+       scan.flags = htole32(IPW_SCAN_DO_NOT_ASSOCIATE | IPW_SCAN_MIXED_CELL);
+       scan.channels = htole32(0x3fff);        /* scan channels 1-14 */
+       DPRINTF(("Setting scan options to 0x%x\n", letoh32(scan.flags)));
+       error = ipw_cmd(sc, IPW_CMD_SET_SCAN_OPTIONS, &scan, sizeof scan);
+       if (error != 0)
+               goto fail;
+
+       /* start scanning */
+       DPRINTF(("Enabling adapter\n"));
+       error = ipw_cmd(sc, IPW_CMD_ENABLE, NULL, 0);
+       if (error != 0)
+               goto fail;
+
+       return;
+ fail:
+       printf("%s: scan request failed (error=%d)\n", sc->sc_dev.dv_xname,
+           error);
+       ieee80211_end_scan(ifp);
+}
+
+void
+ipw_auth_and_assoc(void *arg1, void *arg2)
+{
+       struct ipw_softc *sc = arg1;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ieee80211_node *ni = ic->ic_bss;
+       struct ipw_scan_options scan;
+       struct ipw_security security;
+       struct ipw_assoc_req assoc;
+       uint32_t data;
+       uint8_t chan;
+       int s, error;
+
+       DPRINTF(("Disabling adapter\n"));
+       error = ipw_cmd(sc, IPW_CMD_DISABLE, NULL, 0);
+       if (error != 0)
+               goto fail;
+#if 1
+       /* wait at most one second for card to be disabled */
+       s = splnet();
+       error = tsleep(sc, 0, "ipwdis", hz);
+       splx(s);
+       if (error != 0) {
+               printf("%s: timeout waiting for disabled state\n",
+                   sc->sc_dev.dv_xname);
+               goto fail;
+       }
+#else
+       /* Intel's Linux driver polls for the DISABLED state instead.. */
+       for (ntries = 0; ntries < 1000; ntries++) {
+               if (ipw_read_table1(sc, IPW_INFO_CARD_DISABLED) == 1)
+                       break;
+               DELAY(10);
+       }
+       if (ntries == 1000) {
+               printf("%s: timeout waiting for disabled state\n",
+                   sc->sc_dev.dv_xname);
+               goto fail;
+       }
+#endif
+
+       bzero(&security, sizeof security);
+       security.authmode = IPW_AUTH_OPEN;
+       security.ciphers = htole32(IPW_CIPHER_NONE);
+       DPRINTF(("Setting authmode to %u\n", security.authmode));
+       error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFORMATION, &security,
+           sizeof security);
+       if (error != 0)
+               goto fail;
+
+#ifdef IPW_DEBUG
+       if (ipw_debug > 0) {
+               printf("Setting ESSID to ");
+               ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
+               printf("\n");
+       }
+#endif
+       error = ipw_cmd(sc, IPW_CMD_SET_ESSID, ni->ni_essid, ni->ni_esslen);
+       if (error != 0)
+               goto fail;
+
+       DPRINTF(("Setting BSSID to %s\n", ether_sprintf(ni->ni_bssid)));
+       error = ipw_cmd(sc, IPW_CMD_SET_MANDATORY_BSSID, ni->ni_bssid,
+           IEEE80211_ADDR_LEN);
+       if (error != 0)
+               goto fail;
+
+       data = htole32((ic->ic_flags & (IEEE80211_F_WEPON |
+           IEEE80211_F_RSNON)) ? IPW_PRIVACYON : 0);
+       DPRINTF(("Setting privacy flags to 0x%x\n", letoh32(data)));
+       error = ipw_cmd(sc, IPW_CMD_SET_PRIVACY_FLAGS, &data, sizeof data);
+       if (error != 0)
+               goto fail;
+
+       /* let firmware set the capinfo, lintval, and bssid fixed fields */
+       bzero(&assoc, sizeof assoc);
+       if (ic->ic_flags & IEEE80211_F_RSNON) {
+               uint8_t *frm = assoc.optie;
+
+               /* tell firmware to add a WPA or RSN IE in (Re)Assoc req */
+               if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)
+                       frm = ieee80211_add_rsn(frm, ic, ni);
+               else if (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)
+                       frm = ieee80211_add_wpa(frm, ic, ni);
+               assoc.optie_len = htole32(frm - assoc.optie);
+       }
+       DPRINTF(("Preparing assocation request (optional IE length=%d)\n",
+           letoh32(assoc.optie_len)));
+       error = ipw_cmd(sc, IPW_CMD_SET_ASSOC_REQ, &assoc, sizeof assoc);
+       if (error != 0)
+               goto fail;
+
+       scan.flags = htole32(IPW_SCAN_MIXED_CELL);
+       chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+       scan.channels = htole32(1 << (chan - 1));
+       DPRINTF(("Setting scan options to 0x%x\n", letoh32(scan.flags)));
+       error = ipw_cmd(sc, IPW_CMD_SET_SCAN_OPTIONS, &scan, sizeof scan);
+       if (error != 0)
+               goto fail;
+
+       /* trigger scan+association */
+       DPRINTF(("Enabling adapter\n"));
+       error = ipw_cmd(sc, IPW_CMD_ENABLE, NULL, 0);
+       if (error != 0)
+               goto fail;
+
+       return;
+ fail:
+       printf("%s: association failed (error=%d)\n", sc->sc_dev.dv_xname,
+           error);
+       ieee80211_begin_scan(&ic->ic_if);
+}
+
 int
 ipw_config(struct ipw_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
-       struct ipw_security security;
-       struct ieee80211_key *k;
-       struct ipw_wep_key wepkey;
-       struct ipw_scan_options options;
        struct ipw_configuration config;
        uint32_t data;
-       int error, i;
+       int error;
 
        switch (ic->ic_opmode) {
        case IEEE80211_M_STA:
@@ -1730,7 +1876,7 @@ ipw_config(struct ipw_softc *sc)
                return error;
 
        config.flags = htole32(IPW_CFG_BSS_MASK | IPW_CFG_IBSS_MASK |
-           IPW_CFG_PREAMBLE_AUTO | IPW_CFG_802_1x_ENABLE);
+           IPW_CFG_PREAMBLE_AUTO | IPW_CFG_802_1X_ENABLE);
 #ifndef IEEE80211_STA_ONLY
        if (ic->ic_opmode == IEEE80211_M_IBSS)
                config.flags |= htole32(IPW_CFG_IBSS_AUTO_START);
@@ -1744,6 +1890,18 @@ ipw_config(struct ipw_softc *sc)
        if (error != 0)
                return error;
 
+       data = htole32(ic->ic_rtsthreshold);
+       DPRINTF(("Setting RTS threshold to %u\n", letoh32(data)));
+       error = ipw_cmd(sc, IPW_CMD_SET_RTS_THRESHOLD, &data, sizeof data);
+       if (error != 0)
+               return error;
+
+       data = htole32(ic->ic_fragthreshold);
+       DPRINTF(("Setting frag threshold to %u\n", letoh32(data)));
+       error = ipw_cmd(sc, IPW_CMD_SET_FRAG_THRESHOLD, &data, sizeof data);
+       if (error != 0)
+               return error;
+
        data = htole32(0x3);    /* 1, 2 */
        DPRINTF(("Setting basic tx rates to 0x%x\n", letoh32(data)));
        error = ipw_cmd(sc, IPW_CMD_SET_BASIC_TX_RATES, &data, sizeof data);
@@ -1756,6 +1914,12 @@ ipw_config(struct ipw_softc *sc)
        if (error != 0)
                return error;
 
+       data = htole32(0xf);    /* 1, 2, 5.5, 11 */
+       DPRINTF(("Setting MSDU tx rates to 0x%x\n", letoh32(data)));
+       error = ipw_cmd(sc, IPW_CMD_SET_MSDU_TX_RATES, &data, sizeof data);
+       if (error != 0)
+               return error;
+
        data = htole32(IPW_POWER_MODE_CAM);
        DPRINTF(("Setting power mode to %u\n", letoh32(data)));
        error = ipw_cmd(sc, IPW_CMD_SET_POWER_MODE, &data, sizeof data);
@@ -1770,92 +1934,7 @@ ipw_config(struct ipw_softc *sc)
                    sizeof data);
                if (error != 0)
                        return error;
-       }
-#endif
-
-       data = htole32(ic->ic_rtsthreshold);
-       DPRINTF(("Setting RTS threshold to %u\n", letoh32(data)));
-       error = ipw_cmd(sc, IPW_CMD_SET_RTS_THRESHOLD, &data, sizeof data);
-       if (error != 0)
-               return error;
-
-       data = htole32(ic->ic_fragthreshold);
-       DPRINTF(("Setting frag threshold to %u\n", letoh32(data)));
-       error = ipw_cmd(sc, IPW_CMD_SET_FRAG_THRESHOLD, &data, sizeof data);
-       if (error != 0)
-               return error;
-
-#ifdef IPW_DEBUG
-       if (ipw_debug > 0) {
-               printf("Setting ESSID to ");
-               ieee80211_print_essid(ic->ic_des_essid, ic->ic_des_esslen);
-               printf("\n");
-       }
-#endif
-       error = ipw_cmd(sc, IPW_CMD_SET_ESSID, ic->ic_des_essid,
-           ic->ic_des_esslen);
-       if (error != 0)
-               return error;
-
-       /* no mandatory BSSID */
-       DPRINTF(("Setting mandatory BSSID to null\n"));
-       error = ipw_cmd(sc, IPW_CMD_SET_MANDATORY_BSSID, NULL, 0);
-       if (error != 0)
-               return error;
-
-       if (ic->ic_flags & IEEE80211_F_DESBSSID) {
-               DPRINTF(("Setting adapter BSSID to %s\n",
-                   ether_sprintf(ic->ic_des_bssid)));
-               error = ipw_cmd(sc, IPW_CMD_SET_DESIRED_BSSID,
-                   ic->ic_des_bssid, IEEE80211_ADDR_LEN);
-               if (error != 0)
-                       return error;
-       }
-
-       bzero(&security, sizeof security);
-       security.authmode = IPW_AUTH_OPEN;      /* XXX shared mode */
-       security.ciphers = htole32(IPW_CIPHER_NONE);
-       DPRINTF(("Setting authmode to %u\n", security.authmode));
-       error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFORMATION, &security,
-           sizeof security);
-       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++) {
-                       if (k->k_len == 0)
-                               continue;
-
-                       wepkey.idx = i;
-                       wepkey.len = k->k_len;
-                       bzero(wepkey.key, sizeof wepkey.key);
-                       bcopy(k->k_key, wepkey.key, k->k_len);
-                       DPRINTF(("Setting wep key index %u len %u\n",
-                           wepkey.idx, wepkey.len));
-                       error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY, &wepkey,
-                           sizeof wepkey);
-                       if (error != 0)
-                               return error;
-               }
-
-               data = htole32(ic->ic_wep_txkey);
-               DPRINTF(("Setting wep tx key index to %u\n", letoh32(data)));
-               error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
-                   sizeof data);
-               if (error != 0)
-                       return error;
-       }
-
-       data = htole32((ic->ic_flags & IEEE80211_F_WEPON) ? IPW_WEPON : 0);
-       DPRINTF(("Setting wep flags to 0x%x\n", letoh32(data)));
-       error = ipw_cmd(sc, IPW_CMD_SET_WEP_FLAGS, &data, sizeof data);
-       if (error != 0)
-               return error;
 
-#ifndef IEEE80211_STA_ONLY
-       if (ic->ic_opmode == IEEE80211_M_IBSS ||
-           ic->ic_opmode == IEEE80211_M_HOSTAP) {
                data = htole32(ic->ic_lintval);
                DPRINTF(("Setting beacon interval to %u\n", letoh32(data)));
                error = ipw_cmd(sc, IPW_CMD_SET_BEACON_INTERVAL, &data,
@@ -1864,23 +1943,14 @@ ipw_config(struct ipw_softc *sc)
                        return error;
        }
 #endif
-
-       options.flags = htole32(0);
-       options.channels = htole32(0x3fff);     /* scan channels 1-14 */
-       DPRINTF(("Setting scan options to 0x%x\n", letoh32(options.flags)));
-       error = ipw_cmd(sc, IPW_CMD_SET_SCAN_OPTIONS, &options, sizeof options);
-       if (error != 0)
-               return error;
-
-       /* finally, enable adapter (start scanning for an access point) */
-       DPRINTF(("Enabling adapter\n"));
-       return ipw_cmd(sc, IPW_CMD_ENABLE, NULL, 0);
+       return 0;
 }
 
 int
 ipw_init(struct ifnet *ifp)
 {
        struct ipw_softc *sc = ifp->if_softc;
+       struct ieee80211com *ic = &sc->sc_ic;
        struct ipw_firmware fw;
        int error;
 
@@ -1941,14 +2011,19 @@ ipw_init(struct ifnet *ifp)
                    sc->sc_dev.dv_xname);
                goto fail2;
        }
+
        ifp->if_flags &= ~IFF_OACTIVE;
        ifp->if_flags |= IFF_RUNNING;
 
+       if (ic->ic_opmode != IEEE80211_M_MONITOR)
+               ieee80211_begin_scan(ifp);
+       else
+               ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+
        return 0;
 
 fail2: free(fw.data, M_DEVBUF);
 fail1: ipw_stop(ifp, 0);
-
        return error;
 }
 
index 54521f8..a048b56 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_ipwreg.h,v 1.14 2006/02/26 19:14:40 damien Exp $   */
+/*     $OpenBSD: if_ipwreg.h,v 1.15 2008/08/28 14:40:44 damien Exp $   */
 
 /*-
  * Copyright (c) 2004-2006
@@ -182,7 +182,7 @@ struct ipw_cmd {
 #define IPW_CMD_SET_BASIC_TX_RATES             19
 #define IPW_CMD_SET_WEP_KEY                    20
 #define IPW_CMD_SET_WEP_KEY_INDEX              25
-#define IPW_CMD_SET_WEP_FLAGS                  26
+#define IPW_CMD_SET_PRIVACY_FLAGS              26
 #define IPW_CMD_ADD_MULTICAST                  27
 #define IPW_CMD_SET_BEACON_INTERVAL            29
 #define IPW_CMD_SET_TX_POWER_INDEX             36
@@ -192,7 +192,9 @@ struct ipw_cmd {
 #define IPW_CMD_SET_SCAN_OPTIONS               46
 #define IPW_CMD_PREPARE_POWER_DOWN             58
 #define IPW_CMD_DISABLE_PHY                    61
+#define IPW_CMD_SET_MSDU_TX_RATES              62
 #define IPW_CMD_SET_SECURITY_INFORMATION       67
+#define IPW_CMD_SET_ASSOC_REQ                  69
        uint32_t        subtype;
        uint32_t        seq;
        uint32_t        len;
@@ -210,8 +212,8 @@ struct ipw_cmd {
 #define IPW_MODE_IBSS          1
 #define IPW_MODE_MONITOR       2
 
-/* possible flags for command IPW_CMD_SET_WEP_FLAGS */
-#define IPW_WEPON      0x8
+/* possible flags for command IPW_CMD_SET_PRIVACY_FLAGS */
+#define IPW_PRIVACYON  0x8
 
 /* structure for command IPW_CMD_SET_WEP_KEY */
 struct ipw_wep_key {
@@ -225,6 +227,8 @@ struct ipw_security {
        uint32_t        ciphers;
 #define IPW_CIPHER_NONE                0x00000001
 #define IPW_CIPHER_WEP40       0x00000002
+#define IPW_CIPHER_TKIP                0x00000004
+#define IPW_CIPHER_CCMP                0x00000010
 #define IPW_CIPHER_WEP104      0x00000020
        uint16_t        reserved1;
        uint8_t         authmode;
@@ -237,6 +241,7 @@ struct ipw_security {
 struct ipw_scan_options {
        uint32_t        flags;
 #define IPW_SCAN_DO_NOT_ASSOCIATE      0x00000001
+#define IPW_SCAN_MIXED_CELL            0x00000002
 #define IPW_SCAN_PASSIVE               0x00000008
        uint32_t        channels;
 } __packed;
@@ -247,14 +252,25 @@ struct ipw_configuration {
 #define IPW_CFG_PROMISCUOUS    0x00000004
 #define IPW_CFG_PREAMBLE_AUTO  0x00000010
 #define IPW_CFG_IBSS_AUTO_START        0x00000020
-#define IPW_CFG_802_1x_ENABLE  0x00004000
+#define IPW_CFG_802_1X_ENABLE  0x00004000
 #define IPW_CFG_BSS_MASK       0x00008000
 #define IPW_CFG_IBSS_MASK      0x00010000
        uint32_t        bss_chan;
        uint32_t        ibss_chan;
 } __packed;
 
-/* EEPROM = Electrically Erasable Programmable Read-Only Memory */
+/* structure for command IPW_CMD_SET_ASSOC_REQ */
+struct ipw_assoc_req {
+       uint16_t        flags;
+#define IPW_ASSOC_CAPINFO      0x0001
+#define IPW_ASSOC_LINTVAL      0x0002
+#define IPW_ASSOC_BSSID                0x0004  /* reassoc */
+       uint16_t        capinfo;
+       uint16_t        lintval;
+       uint8_t         bssid[IEEE80211_ADDR_LEN];
+       uint32_t        optie_len;
+       uint8_t         optie[384];
+} __packed;
 
 #define IPW_MEM_EEPROM_CTL     0x00300040
 
@@ -324,5 +340,5 @@ struct ipw_configuration {
 #define IPW_EEPROM_CTL(sc, val) do {                                   \
        MEM_WRITE_4((sc), IPW_MEM_EEPROM_CTL, (val));                   \
        DELAY(IPW_EEPROM_DELAY);                                        \
-} while (0)
+} while (/* CONSTCOND */0)