root/dev/ic/if_wi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wi_attach
  2. wi_intr_enable
  3. wi_intr_ack
  4. wi_intr
  5. wi_get_fid_io
  6. wi_rxeof
  7. wi_txeof
  8. wi_inquire
  9. wi_update_stats
  10. wi_cmd_io
  11. wi_reset
  12. wi_cor_reset
  13. wi_read_record_io
  14. wi_write_record_io
  15. wi_seek
  16. wi_read_data_io
  17. wi_write_data_io
  18. wi_alloc_nicmem_io
  19. wi_setmulti
  20. wi_setdef
  21. wi_ioctl
  22. wi_scan_timeout
  23. wi_init_io
  24. wi_do_hostencrypt
  25. wi_do_hostdecrypt
  26. wi_start
  27. wi_mgmt_xmit
  28. wi_stop
  29. wi_watchdog
  30. wi_detach
  31. wi_shutdown
  32. wi_get_id
  33. wi_sync_media
  34. wi_media_change
  35. wi_media_status
  36. wi_set_nwkey
  37. wi_get_nwkey
  38. wi_set_pm
  39. wi_get_pm
  40. wi_set_txpower
  41. wi_get_txpower
  42. wi_set_ssid
  43. wi_get_debug
  44. wi_set_debug

    1 /*      $OpenBSD: if_wi.c,v 1.137 2006/11/26 19:46:28 deraadt Exp $     */
    2 
    3 /*
    4  * Copyright (c) 1997, 1998, 1999
    5  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Bill Paul.
   18  * 4. Neither the name of the author nor the names of any co-contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   32  * THE POSSIBILITY OF SUCH DAMAGE.
   33  *
   34  *      From: if_wi.c,v 1.7 1999/07/04 14:40:22 wpaul Exp $
   35  */
   36 
   37 /*
   38  * Lucent WaveLAN/IEEE 802.11 driver for OpenBSD.
   39  *
   40  * Originally written by Bill Paul <wpaul@ctr.columbia.edu>
   41  * Electrical Engineering Department
   42  * Columbia University, New York City
   43  */
   44 
   45 /*
   46  * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
   47  * from Lucent. Unlike the older cards, the new ones are programmed
   48  * entirely via a firmware-driven controller called the Hermes.
   49  * Unfortunately, Lucent will not release the Hermes programming manual
   50  * without an NDA (if at all). What they do release is an API library
   51  * called the HCF (Hardware Control Functions) which is supposed to
   52  * do the device-specific operations of a device driver for you. The
   53  * publicly available version of the HCF library (the 'HCF Light') is
   54  * a) extremely gross, b) lacks certain features, particularly support
   55  * for 802.11 frames, and c) is contaminated by the GNU Public License.
   56  *
   57  * This driver does not use the HCF or HCF Light at all. Instead, it
   58  * programs the Hermes controller directly, using information gleaned
   59  * from the HCF Light code and corresponding documentation.
   60  */
   61 
   62 #define WI_HERMES_AUTOINC_WAR   /* Work around data write autoinc bug. */
   63 #define WI_HERMES_STATS_WAR     /* Work around stats counter bug. */
   64 
   65 #include "bpfilter.h"
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/sockio.h>
   70 #include <sys/mbuf.h>
   71 #include <sys/malloc.h>
   72 #include <sys/kernel.h>
   73 #include <sys/proc.h>
   74 #include <sys/socket.h>
   75 #include <sys/device.h>
   76 
   77 #include <net/if.h>
   78 #include <net/if_dl.h>
   79 #include <net/if_media.h>
   80 #include <net/if_types.h>
   81 
   82 #ifdef INET
   83 #include <netinet/in.h>
   84 #include <netinet/in_systm.h>
   85 #include <netinet/in_var.h>
   86 #include <netinet/ip.h>
   87 #include <netinet/if_ether.h>
   88 #endif
   89 
   90 #include <net80211/ieee80211_var.h>
   91 #include <net80211/ieee80211_ioctl.h>
   92 
   93 #if NBPFILTER > 0
   94 #include <net/bpf.h>
   95 #endif
   96 
   97 #include <machine/bus.h>
   98 
   99 #include <dev/rndvar.h>
  100 
  101 #include <dev/ic/if_wireg.h>
  102 #include <dev/ic/if_wi_ieee.h>
  103 #include <dev/ic/if_wivar.h>
  104 
  105 #include <crypto/arc4.h>
  106 
  107 #define BPFATTACH(if_bpf,if,dlt,sz)
  108 #define STATIC
  109 
  110 #ifdef WIDEBUG
  111 
  112 u_int32_t       widebug = WIDEBUG;
  113 
  114 #define WID_INTR        0x01
  115 #define WID_START       0x02
  116 #define WID_IOCTL       0x04
  117 #define WID_INIT        0x08
  118 #define WID_STOP        0x10
  119 #define WID_RESET       0x20
  120 
  121 #define DPRINTF(mask,args) if (widebug & (mask)) printf args;
  122 
  123 #else   /* !WIDEBUG */
  124 #define DPRINTF(mask,args)
  125 #endif  /* WIDEBUG */
  126 
  127 #if !defined(lint) && !defined(__OpenBSD__)
  128 static const char rcsid[] =
  129         "$OpenBSD: if_wi.c,v 1.137 2006/11/26 19:46:28 deraadt Exp $";
  130 #endif  /* lint */
  131 
  132 #ifdef foo
  133 static u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 };
  134 #endif
  135 
  136 STATIC void wi_reset(struct wi_softc *);
  137 STATIC int wi_ioctl(struct ifnet *, u_long, caddr_t);
  138 STATIC void wi_init_io(struct wi_softc *);
  139 STATIC void wi_start(struct ifnet *);
  140 STATIC void wi_watchdog(struct ifnet *);
  141 STATIC void wi_shutdown(void *);
  142 STATIC void wi_rxeof(struct wi_softc *);
  143 STATIC void wi_txeof(struct wi_softc *, int);
  144 STATIC void wi_update_stats(struct wi_softc *);
  145 STATIC void wi_setmulti(struct wi_softc *);
  146 
  147 STATIC int wi_cmd_io(struct wi_softc *, int, int, int, int);
  148 STATIC int wi_read_record_io(struct wi_softc *, struct wi_ltv_gen *);
  149 STATIC int wi_write_record_io(struct wi_softc *, struct wi_ltv_gen *);
  150 STATIC int wi_read_data_io(struct wi_softc *, int,
  151                                         int, caddr_t, int);
  152 STATIC int wi_write_data_io(struct wi_softc *, int,
  153                                         int, caddr_t, int);
  154 STATIC int wi_seek(struct wi_softc *, int, int, int);
  155 
  156 STATIC void wi_inquire(void *);
  157 STATIC int wi_setdef(struct wi_softc *, struct wi_req *);
  158 STATIC void wi_get_id(struct wi_softc *);
  159 
  160 STATIC int wi_media_change(struct ifnet *);
  161 STATIC void wi_media_status(struct ifnet *, struct ifmediareq *);
  162 
  163 STATIC int wi_set_ssid(struct ieee80211_nwid *, u_int8_t *, int);
  164 STATIC int wi_set_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
  165 STATIC int wi_get_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
  166 STATIC int wi_sync_media(struct wi_softc *, int, int);
  167 STATIC int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
  168 STATIC int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
  169 STATIC int wi_set_txpower(struct wi_softc *, struct ieee80211_txpower *);
  170 STATIC int wi_get_txpower(struct wi_softc *, struct ieee80211_txpower *);
  171 
  172 STATIC int wi_get_debug(struct wi_softc *, struct wi_req *);
  173 STATIC int wi_set_debug(struct wi_softc *, struct wi_req *);
  174 
  175 STATIC void wi_do_hostencrypt(struct wi_softc *, caddr_t, int);                
  176 STATIC int wi_do_hostdecrypt(struct wi_softc *, caddr_t, int);
  177 
  178 STATIC int wi_alloc_nicmem_io(struct wi_softc *, int, int *);
  179 STATIC int wi_get_fid_io(struct wi_softc *sc, int fid);
  180 STATIC void wi_intr_enable(struct wi_softc *sc, int mode);
  181 STATIC void wi_intr_ack(struct wi_softc *sc, int mode);
  182 void     wi_scan_timeout(void *);
  183 
  184 /* Autoconfig definition of driver back-end */
  185 struct cfdriver wi_cd = {
  186         NULL, "wi", DV_IFNET
  187 };
  188 
  189 const struct wi_card_ident wi_card_ident[] = {
  190         WI_CARD_IDS
  191 };
  192 
  193 struct wi_funcs wi_func_io = {
  194         wi_cmd_io,
  195         wi_read_record_io,
  196         wi_write_record_io,
  197         wi_alloc_nicmem_io,
  198         wi_read_data_io,
  199         wi_write_data_io,
  200         wi_get_fid_io,
  201         wi_init_io,
  202 
  203         wi_start,
  204         wi_ioctl,
  205         wi_watchdog,
  206         wi_inquire,
  207 };
  208 
  209 int
  210 wi_attach(struct wi_softc *sc, struct wi_funcs *funcs)
  211 {
  212         struct ieee80211com     *ic;
  213         struct ifnet            *ifp;
  214         struct wi_ltv_macaddr   mac;
  215         struct wi_ltv_rates     rates;
  216         struct wi_ltv_gen       gen;
  217         int                     error;
  218 
  219         ic = &sc->sc_ic;
  220         ifp = &ic->ic_if;
  221 
  222         sc->sc_funcs = funcs;
  223         sc->wi_cmd_count = 500;
  224 
  225         wi_reset(sc);
  226 
  227         /* Read the station address. */
  228         mac.wi_type = WI_RID_MAC_NODE;
  229         mac.wi_len = 4;
  230         error = wi_read_record(sc, (struct wi_ltv_gen *)&mac);
  231         if (error) {
  232                 printf(": unable to read station address\n");
  233                 return (error);
  234         }
  235         bcopy((char *)&mac.wi_mac_addr, (char *)&ic->ic_myaddr,
  236             IEEE80211_ADDR_LEN);
  237 
  238         wi_get_id(sc);
  239         printf("address %s", ether_sprintf(ic->ic_myaddr));
  240 
  241         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
  242         ifp->if_softc = sc;
  243         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  244         ifp->if_ioctl = funcs->f_ioctl;
  245         ifp->if_start = funcs->f_start;
  246         ifp->if_watchdog = funcs->f_watchdog;
  247         ifp->if_baudrate = 10000000;
  248         IFQ_SET_READY(&ifp->if_snd);
  249 
  250         (void)wi_set_ssid(&sc->wi_node_name, WI_DEFAULT_NODENAME,
  251             sizeof(WI_DEFAULT_NODENAME) - 1);
  252         (void)wi_set_ssid(&sc->wi_net_name, WI_DEFAULT_NETNAME,
  253             sizeof(WI_DEFAULT_NETNAME) - 1);
  254         (void)wi_set_ssid(&sc->wi_ibss_name, WI_DEFAULT_IBSS,
  255             sizeof(WI_DEFAULT_IBSS) - 1);
  256 
  257         sc->wi_portnum = WI_DEFAULT_PORT;
  258         sc->wi_ptype = WI_PORTTYPE_BSS;
  259         sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
  260         sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
  261         sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
  262         sc->wi_max_data_len = WI_DEFAULT_DATALEN;
  263         sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
  264         sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
  265         sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
  266         sc->wi_roaming = WI_DEFAULT_ROAMING;
  267         sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
  268         sc->wi_diversity = WI_DEFAULT_DIVERSITY;
  269         sc->wi_crypto_algorithm = WI_CRYPTO_FIRMWARE_WEP;
  270 
  271         /*
  272          * Read the default channel from the NIC. This may vary
  273          * depending on the country where the NIC was purchased, so
  274          * we can't hard-code a default and expect it to work for
  275          * everyone.
  276          */
  277         gen.wi_type = WI_RID_OWN_CHNL;
  278         gen.wi_len = 2;
  279         if (wi_read_record(sc, &gen) == 0)
  280                 sc->wi_channel = letoh16(gen.wi_val);
  281         else
  282                 sc->wi_channel = 3;
  283 
  284         /*
  285          * Set flags based on firmware version.
  286          */
  287         switch (sc->sc_firmware_type) {
  288         case WI_LUCENT:
  289                 sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
  290                 if (sc->sc_sta_firmware_ver >= 60000)
  291                         sc->wi_flags |= WI_FLAGS_HAS_MOR;
  292                 if (sc->sc_sta_firmware_ver >= 60006) {
  293                         sc->wi_flags |= WI_FLAGS_HAS_IBSS;
  294                         sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
  295                 }
  296                 sc->wi_ibss_port = htole16(1);
  297                 break;
  298         case WI_INTERSIL:
  299                 sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
  300                 /* older prism firmware is slow so crank the count */
  301                 if (sc->sc_sta_firmware_ver < 10000)
  302                         sc->wi_cmd_count = 5000;
  303                 else
  304                         sc->wi_cmd_count = 2000;
  305                 if (sc->sc_sta_firmware_ver >= 800) {
  306 #ifndef SMALL_KERNEL
  307                         /*
  308                          * USB hostap is more pain than it is worth
  309                          * for now, things would have to be overhauled
  310                          */
  311                         if ((sc->sc_sta_firmware_ver != 10402) &&
  312                             (!(sc->wi_flags & WI_FLAGS_BUS_USB)))
  313                                 sc->wi_flags |= WI_FLAGS_HAS_HOSTAP;
  314 #endif
  315                         sc->wi_flags |= WI_FLAGS_HAS_IBSS;
  316                         sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
  317                 }
  318                 if (sc->sc_sta_firmware_ver >= 10603)
  319                         sc->wi_flags |= WI_FLAGS_HAS_ENH_SECURITY;
  320                 sc->wi_ibss_port = htole16(0);
  321                 break;
  322         case WI_SYMBOL:
  323                 sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY;
  324                 if (sc->sc_sta_firmware_ver >= 20000)
  325                         sc->wi_flags |= WI_FLAGS_HAS_IBSS;
  326                 if (sc->sc_sta_firmware_ver >= 25000)
  327                         sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
  328                 sc->wi_ibss_port = htole16(4);
  329                 break;
  330         }
  331 
  332         /*
  333          * Find out if we support WEP on this card.
  334          */
  335         gen.wi_type = WI_RID_WEP_AVAIL;
  336         gen.wi_len = 2;
  337         if (wi_read_record(sc, &gen) == 0 && gen.wi_val != htole16(0))
  338                 sc->wi_flags |= WI_FLAGS_HAS_WEP;
  339         timeout_set(&sc->sc_timo, funcs->f_inquire, sc);
  340 
  341         bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats));
  342 
  343         /* Find supported rates. */
  344         rates.wi_type = WI_RID_DATA_RATES;
  345         rates.wi_len = sizeof(rates.wi_rates);
  346         if (wi_read_record(sc, (struct wi_ltv_gen *)&rates) == 0) {
  347                 int i, nrates;
  348 
  349                 nrates = letoh16(*(u_int16_t *)rates.wi_rates);
  350                 if (nrates > sizeof(rates.wi_rates) - 2)
  351                         nrates = sizeof(rates.wi_rates) - 2;
  352 
  353                 sc->wi_supprates = 0;
  354                 for (i = 0; i < nrates; i++)
  355                         sc->wi_supprates |= rates.wi_rates[2 + i];
  356         } else
  357                 sc->wi_supprates = WI_SUPPRATES_1M | WI_SUPPRATES_2M |
  358                     WI_SUPPRATES_5M | WI_SUPPRATES_11M;
  359 
  360         ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
  361 #define ADD(m, c)       ifmedia_add(&sc->sc_media, (m), (c), NULL)
  362         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
  363         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0);
  364         if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  365                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_IBSS,
  366                     0), 0);
  367         if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  368                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
  369                     IFM_IEEE80211_IBSSMASTER, 0), 0);
  370         if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  371                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
  372                     IFM_IEEE80211_HOSTAP, 0), 0);
  373         if (sc->wi_supprates & WI_SUPPRATES_1M) {
  374                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
  375                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
  376                     IFM_IEEE80211_ADHOC, 0), 0);
  377                 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  378                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
  379                             IFM_IEEE80211_IBSS, 0), 0);
  380                 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  381                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
  382                             IFM_IEEE80211_IBSSMASTER, 0), 0);
  383                 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  384                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
  385                             IFM_IEEE80211_HOSTAP, 0), 0);
  386         }
  387         if (sc->wi_supprates & WI_SUPPRATES_2M) {
  388                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
  389                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
  390                     IFM_IEEE80211_ADHOC, 0), 0);
  391                 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  392                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
  393                             IFM_IEEE80211_IBSS, 0), 0);
  394                 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  395                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
  396                             IFM_IEEE80211_IBSSMASTER, 0), 0);
  397                 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  398                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
  399                             IFM_IEEE80211_HOSTAP, 0), 0);
  400         }
  401         if (sc->wi_supprates & WI_SUPPRATES_5M) {
  402                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
  403                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
  404                     IFM_IEEE80211_ADHOC, 0), 0);
  405                 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  406                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
  407                             IFM_IEEE80211_IBSS, 0), 0);
  408                 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  409                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
  410                             IFM_IEEE80211_IBSSMASTER, 0), 0);
  411                 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  412                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
  413                             IFM_IEEE80211_HOSTAP, 0), 0);
  414         }
  415         if (sc->wi_supprates & WI_SUPPRATES_11M) {
  416                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
  417                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
  418                     IFM_IEEE80211_ADHOC, 0), 0);
  419                 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  420                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
  421                             IFM_IEEE80211_IBSS, 0), 0);
  422                 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  423                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
  424                             IFM_IEEE80211_IBSSMASTER, 0), 0);
  425                 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  426                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
  427                             IFM_IEEE80211_HOSTAP, 0), 0);
  428                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
  429         }
  430 #undef ADD
  431         ifmedia_set(&sc->sc_media,
  432             IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
  433 
  434         /*
  435          * Call MI attach routines.
  436          */
  437         if_attach(ifp);
  438         memcpy(((struct arpcom *)ifp)->ac_enaddr, ic->ic_myaddr,
  439             ETHER_ADDR_LEN);
  440         ether_ifattach(ifp);
  441         printf("\n");
  442 
  443         sc->wi_flags |= WI_FLAGS_ATTACHED;
  444 
  445 #if NBPFILTER > 0
  446         BPFATTACH(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
  447 #endif
  448 
  449         sc->sc_sdhook = shutdownhook_establish(wi_shutdown, sc);
  450 
  451         wi_init(sc);
  452         wi_stop(sc);
  453 
  454         return (0);
  455 }
  456 
  457 STATIC void
  458 wi_intr_enable(struct wi_softc *sc, int mode)
  459 {
  460         if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
  461                 CSR_WRITE_2(sc, WI_INT_EN, mode);
  462 }
  463 
  464 STATIC void
  465 wi_intr_ack(struct wi_softc *sc, int mode)
  466 {
  467         if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
  468                 CSR_WRITE_2(sc, WI_EVENT_ACK, mode);
  469 }
  470 
  471 int
  472 wi_intr(void *vsc)
  473 {
  474         struct wi_softc         *sc = vsc;
  475         struct ifnet            *ifp;
  476         u_int16_t               status;
  477 
  478         DPRINTF(WID_INTR, ("wi_intr: sc %p\n", sc));
  479 
  480         ifp = &sc->sc_ic.ic_if;
  481 
  482         if (!(sc->wi_flags & WI_FLAGS_ATTACHED) || !(ifp->if_flags & IFF_UP)) {
  483                 CSR_WRITE_2(sc, WI_INT_EN, 0);
  484                 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xffff);
  485                 return (0);
  486         }
  487 
  488         /* Disable interrupts. */
  489         CSR_WRITE_2(sc, WI_INT_EN, 0);
  490 
  491         status = CSR_READ_2(sc, WI_EVENT_STAT);
  492         CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
  493 
  494         if (status & WI_EV_RX) {
  495                 wi_rxeof(sc);
  496                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
  497         }
  498 
  499         if (status & WI_EV_TX) {
  500                 wi_txeof(sc, status);
  501                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
  502         }
  503 
  504         if (status & WI_EV_ALLOC) {
  505                 int                     id;
  506                 id = CSR_READ_2(sc, WI_ALLOC_FID);
  507                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
  508                 if (id == sc->wi_tx_data_id)
  509                         wi_txeof(sc, status);
  510         }
  511 
  512         if (status & WI_EV_INFO) {
  513                 wi_update_stats(sc);
  514                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
  515         }
  516 
  517         if (status & WI_EV_TX_EXC) {
  518                 wi_txeof(sc, status);
  519                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
  520         }
  521 
  522         if (status & WI_EV_INFO_DROP) {
  523                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
  524         }
  525 
  526         /* Re-enable interrupts. */
  527         CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
  528 
  529         if (!IFQ_IS_EMPTY(&ifp->if_snd))
  530                 wi_start(ifp);
  531 
  532         return (1);
  533 }
  534 
  535 STATIC int
  536 wi_get_fid_io(struct wi_softc *sc, int fid)
  537 {
  538         return CSR_READ_2(sc, fid);
  539 }
  540 
  541 
  542 void
  543 wi_rxeof(struct wi_softc *sc)
  544 {
  545         struct ifnet            *ifp;
  546         struct ether_header     *eh;
  547         struct mbuf             *m;
  548         caddr_t                 olddata;
  549         u_int16_t               ftype;
  550         int                     maxlen;
  551         int                     id;
  552 
  553         ifp = &sc->sc_ic.ic_if;
  554 
  555         id = wi_get_fid(sc, WI_RX_FID);
  556 
  557         if (sc->wi_procframe || sc->wi_debug.wi_monitor) {
  558                 struct wi_frame *rx_frame;
  559                 int             datlen, hdrlen;
  560 
  561                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  562                 if (m == NULL) {
  563                         ifp->if_ierrors++;
  564                         return;
  565                 }
  566                 MCLGET(m, M_DONTWAIT);
  567                 if (!(m->m_flags & M_EXT)) {
  568                         m_freem(m);
  569                         ifp->if_ierrors++;
  570                         return;
  571                 }
  572 
  573                 m->m_pkthdr.rcvif = ifp;
  574 
  575                 if (wi_read_data(sc, id, 0, mtod(m, caddr_t),
  576                     sizeof(struct wi_frame))) {
  577                         m_freem(m);
  578                         ifp->if_ierrors++;
  579                         return;
  580                 }
  581 
  582                 rx_frame = mtod(m, struct wi_frame *);
  583 
  584                 if (rx_frame->wi_status & htole16(WI_STAT_BADCRC)) {
  585                         m_freem(m);
  586                         ifp->if_ierrors++;
  587                         return;
  588                 }
  589 
  590                 switch ((letoh16(rx_frame->wi_status) & WI_STAT_MAC_PORT)
  591                     >> 8) {
  592                 case 7:
  593                         switch (letoh16(rx_frame->wi_frame_ctl) &
  594                             WI_FCTL_FTYPE) {
  595                         case WI_FTYPE_DATA:
  596                                 hdrlen = WI_DATA_HDRLEN;
  597                                 datlen = letoh16(rx_frame->wi_dat_len);
  598                                 break;
  599                         case WI_FTYPE_MGMT:
  600                                 hdrlen = WI_MGMT_HDRLEN;
  601                                 datlen = letoh16(rx_frame->wi_dat_len);
  602                                 break;
  603                         case WI_FTYPE_CTL:
  604                                 hdrlen = WI_CTL_HDRLEN;
  605                                 datlen = 0;
  606                                 break;
  607                         default:
  608                                 printf(WI_PRT_FMT ": received packet of "
  609                                     "unknown type on port 7\n", WI_PRT_ARG(sc));
  610                                 m_freem(m);
  611                                 ifp->if_ierrors++;
  612                                 return;
  613                         }
  614                         break;
  615                 case 0:
  616                         hdrlen = WI_DATA_HDRLEN;
  617                         datlen = letoh16(rx_frame->wi_dat_len);
  618                         break;
  619                 default:
  620                         printf(WI_PRT_FMT ": received packet on invalid port "
  621                             "(wi_status=0x%x)\n", WI_PRT_ARG(sc),
  622                             letoh16(rx_frame->wi_status));
  623                         m_freem(m);
  624                         ifp->if_ierrors++;
  625                         return;
  626                 }
  627 
  628                 if ((hdrlen + datlen + 2) > MCLBYTES) {
  629                         m_freem(m);
  630                         ifp->if_ierrors++;
  631                         return;
  632                 }
  633 
  634                 if (wi_read_data(sc, id, hdrlen, mtod(m, caddr_t) + hdrlen,
  635                     datlen + 2)) {
  636                         m_freem(m);
  637                         ifp->if_ierrors++;
  638                         return;
  639                 }
  640 
  641                 m->m_pkthdr.len = m->m_len = hdrlen + datlen;
  642         } else {
  643                 struct wi_frame rx_frame;
  644 
  645                 /* First read in the frame header */
  646                 if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame,
  647                     sizeof(rx_frame))) {
  648                         ifp->if_ierrors++;
  649                         return;
  650                 }
  651 
  652                 /* Drop undecryptable or packets with receive errors here */
  653                 if (rx_frame.wi_status & htole16(WI_STAT_ERRSTAT)) {
  654                         ifp->if_ierrors++;
  655                         return;
  656                 }
  657 
  658                 /* Stash frame type in host byte order for later use */
  659                 ftype = letoh16(rx_frame.wi_frame_ctl) & WI_FCTL_FTYPE;
  660 
  661                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  662                 if (m == NULL) {
  663                         ifp->if_ierrors++;
  664                         return;
  665                 }
  666                 MCLGET(m, M_DONTWAIT);
  667                 if (!(m->m_flags & M_EXT)) {
  668                         m_freem(m);
  669                         ifp->if_ierrors++;
  670                         return;
  671                 }
  672 
  673                 olddata = m->m_data;
  674                 /* Align the data after the ethernet header */
  675                 m->m_data = (caddr_t)ALIGN(m->m_data +
  676                     sizeof(struct ether_header)) - sizeof(struct ether_header);
  677 
  678                 eh = mtod(m, struct ether_header *);
  679                 maxlen = MCLBYTES - (m->m_data - olddata);
  680                 m->m_pkthdr.rcvif = ifp;
  681 
  682                 if (ftype == WI_FTYPE_MGMT &&
  683                     sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
  684 
  685                         u_int16_t rxlen = letoh16(rx_frame.wi_dat_len);
  686 
  687                         if ((WI_802_11_OFFSET_RAW + rxlen + 2) > maxlen) {
  688                                 printf("%s: oversized mgmt packet received in "
  689                                     "hostap mode (wi_dat_len=%d, "
  690                                     "wi_status=0x%x)\n", sc->sc_dev.dv_xname,
  691                                     rxlen, letoh16(rx_frame.wi_status));
  692                                 m_freem(m);
  693                                 ifp->if_ierrors++;  
  694                                 return;
  695                         }
  696 
  697                         /* Put the whole header in there. */
  698                         bcopy(&rx_frame, mtod(m, void *),
  699                             sizeof(struct wi_frame));
  700                         if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW,
  701                             mtod(m, caddr_t) + WI_802_11_OFFSET_RAW,
  702                             rxlen + 2)) {
  703                                 m_freem(m);
  704                                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  705                                         printf("wihap: failed to copy header\n");
  706                                 ifp->if_ierrors++;
  707                                 return;
  708                         }
  709 
  710                         m->m_pkthdr.len = m->m_len =
  711                             WI_802_11_OFFSET_RAW + rxlen;
  712 
  713                         /* XXX: consider giving packet to bhp? */
  714 
  715                         wihap_mgmt_input(sc, &rx_frame, m);
  716 
  717                         return;
  718                 }
  719 
  720                 switch (letoh16(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) {
  721                 case WI_STAT_1042:
  722                 case WI_STAT_TUNNEL:
  723                 case WI_STAT_WMP_MSG:
  724                         if ((letoh16(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN) >
  725                             maxlen) {
  726                                 printf(WI_PRT_FMT ": oversized packet received "
  727                                     "(wi_dat_len=%d, wi_status=0x%x)\n",
  728                                     WI_PRT_ARG(sc),
  729                                     letoh16(rx_frame.wi_dat_len),
  730                                     letoh16(rx_frame.wi_status));
  731                                 m_freem(m);
  732                                 ifp->if_ierrors++;
  733                                 return;
  734                         }
  735                         m->m_pkthdr.len = m->m_len =
  736                             letoh16(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN;
  737 
  738                         bcopy((char *)&rx_frame.wi_dst_addr,
  739                             (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
  740                         bcopy((char *)&rx_frame.wi_src_addr,
  741                             (char *)&eh->ether_shost, ETHER_ADDR_LEN);
  742                         bcopy((char *)&rx_frame.wi_type,
  743                             (char *)&eh->ether_type, ETHER_TYPE_LEN);
  744 
  745                         if (wi_read_data(sc, id, WI_802_11_OFFSET,
  746                             mtod(m, caddr_t) + sizeof(struct ether_header),
  747                             m->m_len + 2)) {
  748                                 ifp->if_ierrors++;
  749                                 m_freem(m);
  750                                 return;
  751                         }
  752                         break;
  753                 default:
  754                         if ((letoh16(rx_frame.wi_dat_len) +
  755                             sizeof(struct ether_header)) > maxlen) {
  756                                 printf(WI_PRT_FMT ": oversized packet received "
  757                                     "(wi_dat_len=%d, wi_status=0x%x)\n",
  758                                     WI_PRT_ARG(sc),
  759                                     letoh16(rx_frame.wi_dat_len),
  760                                     letoh16(rx_frame.wi_status));
  761                                 m_freem(m);
  762                                 ifp->if_ierrors++;
  763                                 return;
  764                         }
  765                         m->m_pkthdr.len = m->m_len =
  766                             letoh16(rx_frame.wi_dat_len) +
  767                             sizeof(struct ether_header);
  768 
  769                         if (wi_read_data(sc, id, WI_802_3_OFFSET,
  770                             mtod(m, caddr_t), m->m_len + 2)) {
  771                                 m_freem(m);
  772                                 ifp->if_ierrors++;
  773                                 return;
  774                         }
  775                         break;
  776                 }
  777 
  778                 ifp->if_ipackets++;
  779 
  780                 if (sc->wi_use_wep &&
  781                     rx_frame.wi_frame_ctl & htole16(WI_FCTL_WEP)) {
  782                         int len;
  783 
  784                         switch (sc->wi_crypto_algorithm) {
  785                         case WI_CRYPTO_FIRMWARE_WEP:
  786                                 break;
  787                         case WI_CRYPTO_SOFTWARE_WEP:
  788                                 m_copydata(m, 0, m->m_pkthdr.len,
  789                                     (caddr_t)sc->wi_rxbuf);
  790                                 len = m->m_pkthdr.len -
  791                                     sizeof(struct ether_header);
  792                                 if (wi_do_hostdecrypt(sc, sc->wi_rxbuf +
  793                                     sizeof(struct ether_header), len)) {
  794                                         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  795                                                 printf(WI_PRT_FMT ": Error decrypting incoming packet.\n", WI_PRT_ARG(sc));
  796                                         m_freem(m);
  797                                         ifp->if_ierrors++;  
  798                                         return;
  799                                 }
  800                                 len -= IEEE80211_WEP_IVLEN +
  801                                     IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
  802                                 /*
  803                                  * copy data back to mbufs:
  804                                  * we need to ditch the IV & most LLC/SNAP stuff
  805                                  * (except SNAP type, we're going use that to
  806                                  * overwrite the ethertype in the ether_header)
  807                                  */
  808                                 m_copyback(m, sizeof(struct ether_header) -
  809                                     WI_ETHERTYPE_LEN, WI_ETHERTYPE_LEN +
  810                                     (len - WI_SNAPHDR_LEN),
  811                                     sc->wi_rxbuf + sizeof(struct ether_header) +
  812                                     IEEE80211_WEP_IVLEN +
  813                                     IEEE80211_WEP_KIDLEN + WI_SNAPHDR_LEN);
  814                                 m_adj(m, -(WI_ETHERTYPE_LEN +
  815                                     IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
  816                                     WI_SNAPHDR_LEN));
  817                                 break;
  818                         }
  819                 }
  820 
  821                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
  822                         /*
  823                          * Give host AP code first crack at data packets.
  824                          * If it decides to handle it (or drop it), it will
  825                          * return a non-zero.  Otherwise, it is destined for
  826                          * this host.
  827                          */
  828                         if (wihap_data_input(sc, &rx_frame, m))
  829                                 return;
  830                 }
  831         }
  832 
  833 #if NBPFILTER > 0
  834         /* Handle BPF listeners. */
  835         if (ifp->if_bpf)
  836                 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
  837 #endif
  838 
  839         /* Receive packet unless in procframe or monitor mode. */
  840         if (sc->wi_procframe || sc->wi_debug.wi_monitor)
  841                 m_freem(m);
  842         else
  843                 ether_input_mbuf(ifp, m);
  844 
  845         return;
  846 }
  847 
  848 void
  849 wi_txeof(struct wi_softc *sc, int status)
  850 {
  851         struct ifnet            *ifp;
  852 
  853         ifp = &sc->sc_ic.ic_if;
  854 
  855         ifp->if_timer = 0;
  856         ifp->if_flags &= ~IFF_OACTIVE;
  857 
  858         if (status & WI_EV_TX_EXC)
  859                 ifp->if_oerrors++;
  860         else
  861                 ifp->if_opackets++;
  862 
  863         return;
  864 }
  865 
  866 void
  867 wi_inquire(void *xsc)
  868 {
  869         struct wi_softc         *sc;
  870         struct ifnet            *ifp;
  871         int s, rv;
  872 
  873         sc = xsc;
  874         ifp = &sc->sc_ic.ic_if;
  875 
  876         timeout_add(&sc->sc_timo, hz * 60);
  877 
  878         /* Don't do this while we're transmitting */
  879         if (ifp->if_flags & IFF_OACTIVE)
  880                 return;
  881 
  882         s = splnet();
  883         rv = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0);
  884         splx(s);
  885         if (rv)
  886                 printf(WI_PRT_FMT ": wi_cmd failed with %d\n", WI_PRT_ARG(sc),
  887                     rv);
  888 
  889         return;
  890 }
  891 
  892 void
  893 wi_update_stats(struct wi_softc *sc)
  894 {
  895         struct wi_ltv_gen       gen;
  896         u_int16_t               id;
  897         struct ifnet            *ifp;
  898         u_int32_t               *ptr;
  899         int                     len, i;
  900         u_int16_t               t;
  901 
  902         ifp = &sc->sc_ic.ic_if;
  903 
  904         id = wi_get_fid(sc, WI_INFO_FID);
  905 
  906         wi_read_data(sc, id, 0, (char *)&gen, 4);
  907 
  908         if (gen.wi_type == htole16(WI_INFO_SCAN_RESULTS)) {
  909                 sc->wi_scanbuf_len = letoh16(gen.wi_len);
  910                 wi_read_data(sc, id, 4, (caddr_t)sc->wi_scanbuf,
  911                     sc->wi_scanbuf_len * 2);
  912                 return;
  913         } else if (gen.wi_type != htole16(WI_INFO_COUNTERS))
  914                 return;
  915 
  916         /* Some card versions have a larger stats structure */
  917         len = (letoh16(gen.wi_len) - 1 < sizeof(sc->wi_stats) / 4) ?
  918             letoh16(gen.wi_len) - 1 : sizeof(sc->wi_stats) / 4;
  919 
  920         ptr = (u_int32_t *)&sc->wi_stats;
  921 
  922         for (i = 0; i < len; i++) {
  923                 if (sc->wi_flags & WI_FLAGS_BUS_USB) {
  924                         wi_read_data(sc, id, 4 + i*2, (char *)&t, 2);
  925                         t = letoh16(t);
  926                 } else 
  927                         t = CSR_READ_2(sc, WI_DATA1);
  928 #ifdef WI_HERMES_STATS_WAR
  929                 if (t > 0xF000)
  930                         t = ~t & 0xFFFF;
  931 #endif
  932                 ptr[i] += t;
  933         }
  934 
  935         ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
  936             sc->wi_stats.wi_tx_multi_retries +
  937             sc->wi_stats.wi_tx_retry_limit;
  938 
  939         return;
  940 }
  941 
  942 STATIC int
  943 wi_cmd_io(struct wi_softc *sc, int cmd, int val0, int val1, int val2)
  944 {
  945         int                     i, s = 0;
  946 
  947         /* Wait for the busy bit to clear. */
  948         for (i = sc->wi_cmd_count; i--; DELAY(1000)) {
  949                 if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
  950                         break;
  951         }
  952         if (i < 0) {
  953                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  954                         printf(WI_PRT_FMT ": wi_cmd_io: busy bit won't clear\n",
  955                             WI_PRT_ARG(sc));
  956                 return(ETIMEDOUT);
  957         }
  958 
  959         CSR_WRITE_2(sc, WI_PARAM0, val0);
  960         CSR_WRITE_2(sc, WI_PARAM1, val1);
  961         CSR_WRITE_2(sc, WI_PARAM2, val2);
  962         CSR_WRITE_2(sc, WI_COMMAND, cmd);
  963 
  964         for (i = WI_TIMEOUT; i--; DELAY(WI_DELAY)) {
  965                 /*
  966                  * Wait for 'command complete' bit to be
  967                  * set in the event status register.
  968                  */
  969                 s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD;
  970                 if (s) {
  971                         /* Ack the event and read result code. */
  972                         s = CSR_READ_2(sc, WI_STATUS);
  973                         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
  974                         if (s & WI_STAT_CMD_RESULT)
  975                                 return(EIO);
  976                         break;
  977                 }
  978         }
  979 
  980         if (i < 0) {
  981                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  982                         printf(WI_PRT_FMT
  983                             ": timeout in wi_cmd 0x%04x; event status 0x%04x\n",
  984                             WI_PRT_ARG(sc), cmd, s);
  985                 return(ETIMEDOUT);
  986         }
  987 
  988         return(0);
  989 }
  990 
  991 STATIC void
  992 wi_reset(struct wi_softc *sc)
  993 {
  994         int error, tries = 3;
  995 
  996         DPRINTF(WID_RESET, ("wi_reset: sc %p\n", sc));
  997 
  998         /* Symbol firmware cannot be initialized more than once. */
  999         if (sc->sc_firmware_type == WI_SYMBOL) {
 1000                 if (sc->wi_flags & WI_FLAGS_INITIALIZED)
 1001                         return;
 1002                 tries = 1;
 1003         }
 1004 
 1005         for (; tries--; DELAY(WI_DELAY * 1000)) {
 1006                 if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
 1007                         break;
 1008         }
 1009         if (tries < 0) {
 1010                 printf(WI_PRT_FMT ": init failed\n", WI_PRT_ARG(sc));
 1011                 return;
 1012         }
 1013         sc->wi_flags |= WI_FLAGS_INITIALIZED;
 1014 
 1015         wi_intr_enable(sc, 0);
 1016         wi_intr_ack(sc, 0xffff);
 1017 
 1018         /* Calibrate timer. */
 1019         WI_SETVAL(WI_RID_TICK_TIME, 8);
 1020 
 1021         return;
 1022 }
 1023 
 1024 STATIC void
 1025 wi_cor_reset(struct wi_softc *sc)
 1026 {
 1027         u_int8_t cor_value;
 1028 
 1029         DPRINTF(WID_RESET, ("wi_cor_reset: sc %p\n", sc));
 1030 
 1031         /*
 1032          * Do a soft reset of the card; this is required for Symbol cards.
 1033          * This shouldn't hurt other cards but there have been reports
 1034          * of the COR reset messing up old Lucent firmware revisions so
 1035          * we avoid soft reset on Lucent cards for now.
 1036          */
 1037         if (sc->sc_firmware_type != WI_LUCENT) {
 1038                 cor_value = bus_space_read_1(sc->wi_ltag, sc->wi_lhandle,
 1039                     sc->wi_cor_offset);
 1040                 bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
 1041                     sc->wi_cor_offset, (cor_value | WI_COR_SOFT_RESET));
 1042                 DELAY(1000);
 1043                 bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
 1044                     sc->wi_cor_offset, (cor_value & ~WI_COR_SOFT_RESET));
 1045                 DELAY(1000);
 1046         }
 1047 
 1048         return;
 1049 }
 1050 
 1051 /*
 1052  * Read an LTV record from the NIC.
 1053  */
 1054 STATIC int
 1055 wi_read_record_io(struct wi_softc *sc, struct wi_ltv_gen *ltv)
 1056 {
 1057         u_int8_t                *ptr;
 1058         int                     len, code;
 1059         struct wi_ltv_gen       *oltv, p2ltv;
 1060 
 1061         if (sc->sc_firmware_type != WI_LUCENT) {
 1062                 oltv = ltv;
 1063                 switch (ltv->wi_type) {
 1064                 case WI_RID_ENCRYPTION:
 1065                         p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
 1066                         p2ltv.wi_len = 2;
 1067                         ltv = &p2ltv;
 1068                         break;
 1069                 case WI_RID_TX_CRYPT_KEY:
 1070                         if (ltv->wi_val > WI_NLTV_KEYS)
 1071                                 return (EINVAL);
 1072                         p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
 1073                         p2ltv.wi_len = 2;
 1074                         ltv = &p2ltv;
 1075                         break;
 1076                 }
 1077         }
 1078 
 1079         /* Tell the NIC to enter record read mode. */
 1080         if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0))
 1081                 return(EIO);
 1082 
 1083         /* Seek to the record. */
 1084         if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
 1085                 return(EIO);
 1086 
 1087         /*
 1088          * Read the length and record type and make sure they
 1089          * match what we expect (this verifies that we have enough
 1090          * room to hold all of the returned data).
 1091          */
 1092         len = CSR_READ_2(sc, WI_DATA1);
 1093         if (len > ltv->wi_len)
 1094                 return(ENOSPC);
 1095         code = CSR_READ_2(sc, WI_DATA1);
 1096         if (code != ltv->wi_type)
 1097                 return(EIO);
 1098 
 1099         ltv->wi_len = len;
 1100         ltv->wi_type = code;
 1101 
 1102         /* Now read the data. */
 1103         ptr = (u_int8_t *)&ltv->wi_val;
 1104         if (ltv->wi_len > 1)
 1105                 CSR_READ_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1)*2);
 1106 
 1107         if (ltv->wi_type == WI_RID_PORTTYPE && sc->wi_ptype == WI_PORTTYPE_IBSS
 1108             && ltv->wi_val == sc->wi_ibss_port) {
 1109                 /*
 1110                  * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
 1111                  * Since Lucent uses port type 1 for BSS *and* IBSS we
 1112                  * have to rely on wi_ptype to distinguish this for us.
 1113                  */
 1114                 ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
 1115         } else if (sc->sc_firmware_type != WI_LUCENT) {
 1116                 int v;
 1117 
 1118                 switch (oltv->wi_type) {
 1119                 case WI_RID_TX_RATE:
 1120                 case WI_RID_CUR_TX_RATE:
 1121                         switch (letoh16(ltv->wi_val)) {
 1122                         case 1: v = 1; break;
 1123                         case 2: v = 2; break;
 1124                         case 3: v = 6; break;
 1125                         case 4: v = 5; break;
 1126                         case 7: v = 7; break;
 1127                         case 8: v = 11; break;
 1128                         case 15: v = 3; break;
 1129                         default: v = 0x100 + letoh16(ltv->wi_val); break;
 1130                         }
 1131                         oltv->wi_val = htole16(v);
 1132                         break;
 1133                 case WI_RID_ENCRYPTION:
 1134                         oltv->wi_len = 2;
 1135                         if (ltv->wi_val & htole16(0x01))
 1136                                 oltv->wi_val = htole16(1);
 1137                         else
 1138                                 oltv->wi_val = htole16(0);
 1139                         break;
 1140                 case WI_RID_TX_CRYPT_KEY:
 1141                 case WI_RID_CNFAUTHMODE:
 1142                         oltv->wi_len = 2;
 1143                         oltv->wi_val = ltv->wi_val;
 1144                         break;
 1145                 }
 1146         }
 1147 
 1148         return(0);
 1149 }
 1150 
 1151 /*
 1152  * Same as read, except we inject data instead of reading it.
 1153  */
 1154 STATIC int
 1155 wi_write_record_io(struct wi_softc *sc, struct wi_ltv_gen *ltv)
 1156 {
 1157         u_int8_t                *ptr;
 1158         u_int16_t               val = 0;
 1159         int                     i;
 1160         struct wi_ltv_gen       p2ltv;
 1161 
 1162         if (ltv->wi_type == WI_RID_PORTTYPE &&
 1163             letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
 1164                 /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
 1165                 p2ltv.wi_type = WI_RID_PORTTYPE;
 1166                 p2ltv.wi_len = 2;
 1167                 p2ltv.wi_val = sc->wi_ibss_port;
 1168                 ltv = &p2ltv;
 1169         } else if (sc->sc_firmware_type != WI_LUCENT) {
 1170                 int v;
 1171 
 1172                 switch (ltv->wi_type) {
 1173                 case WI_RID_TX_RATE:
 1174                         p2ltv.wi_type = WI_RID_TX_RATE;
 1175                         p2ltv.wi_len = 2;
 1176                         switch (letoh16(ltv->wi_val)) {
 1177                         case 1: v = 1; break;
 1178                         case 2: v = 2; break;
 1179                         case 3: v = 15; break;
 1180                         case 5: v = 4; break;
 1181                         case 6: v = 3; break;
 1182                         case 7: v = 7; break;
 1183                         case 11: v = 8; break;
 1184                         default: return EINVAL;
 1185                         }
 1186                         p2ltv.wi_val = htole16(v);
 1187                         ltv = &p2ltv;
 1188                         break;
 1189                 case WI_RID_ENCRYPTION:
 1190                         p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
 1191                         p2ltv.wi_len = 2;
 1192                         if (ltv->wi_val & htole16(0x01)) {
 1193                                 val = PRIVACY_INVOKED;
 1194                                 /*
 1195                                  * If using shared key WEP we must set the
 1196                                  * EXCLUDE_UNENCRYPTED bit.  Symbol cards
 1197                                  * need this bit set even when not using
 1198                                  * shared key. We can't just test for
 1199                                  * IEEE80211_AUTH_SHARED since Symbol cards
 1200                                  * have 2 shared key modes.
 1201                                  */
 1202                                 if (sc->wi_authtype != IEEE80211_AUTH_OPEN ||
 1203                                     sc->sc_firmware_type == WI_SYMBOL)
 1204                                         val |= EXCLUDE_UNENCRYPTED;
 1205 
 1206                                 switch (sc->wi_crypto_algorithm) {
 1207                                 case WI_CRYPTO_FIRMWARE_WEP:
 1208                                         /*
 1209                                          * TX encryption is broken in
 1210                                          * Host AP mode.
 1211                                          */
 1212                                         if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
 1213                                                 val |= HOST_ENCRYPT;
 1214                                         break;
 1215                                 case WI_CRYPTO_SOFTWARE_WEP:
 1216                                         val |= HOST_ENCRYPT|HOST_DECRYPT;
 1217                                         break;
 1218                                 }
 1219                                 p2ltv.wi_val = htole16(val);
 1220                         } else
 1221                                 p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
 1222                         ltv = &p2ltv;
 1223                         break;
 1224                 case WI_RID_TX_CRYPT_KEY:
 1225                         if (ltv->wi_val > WI_NLTV_KEYS)
 1226                                 return (EINVAL);
 1227                         p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
 1228                         p2ltv.wi_len = 2;
 1229                         p2ltv.wi_val = ltv->wi_val;
 1230                         ltv = &p2ltv;
 1231                         break;
 1232                 case WI_RID_DEFLT_CRYPT_KEYS: {
 1233                                 int error;
 1234                                 int keylen;
 1235                                 struct wi_ltv_str ws;
 1236                                 struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv;
 1237 
 1238                                 keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen;
 1239                                 keylen = letoh16(keylen);
 1240 
 1241                                 for (i = 0; i < 4; i++) {
 1242                                         bzero(&ws, sizeof(ws));
 1243                                         ws.wi_len = (keylen > 5) ? 8 : 4;
 1244                                         ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
 1245                                         bcopy(&wk->wi_keys[i].wi_keydat,
 1246                                             ws.wi_str, keylen);
 1247                                         error = wi_write_record(sc,
 1248                                             (struct wi_ltv_gen *)&ws);
 1249                                         if (error)
 1250                                                 return (error);
 1251                                 }
 1252                         }
 1253                         return (0);
 1254                 }
 1255         }
 1256 
 1257         if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
 1258                 return(EIO);
 1259 
 1260         CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
 1261         CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
 1262 
 1263         ptr = (u_int8_t *)&ltv->wi_val;
 1264         if (ltv->wi_len > 1)
 1265                 CSR_WRITE_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1) *2);
 1266 
 1267         if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0))
 1268                 return(EIO);
 1269 
 1270         return(0);
 1271 }
 1272 
 1273 STATIC int
 1274 wi_seek(struct wi_softc *sc, int id, int off, int chan)
 1275 {
 1276         int                     i;
 1277         int                     selreg, offreg;
 1278 
 1279         switch (chan) {
 1280         case WI_BAP0:
 1281                 selreg = WI_SEL0;
 1282                 offreg = WI_OFF0;
 1283                 break;
 1284         case WI_BAP1:
 1285                 selreg = WI_SEL1;
 1286                 offreg = WI_OFF1;
 1287                 break;
 1288         default:
 1289                 printf(WI_PRT_FMT ": invalid data path: %x\n", WI_PRT_ARG(sc),
 1290                     chan);
 1291                 return(EIO);
 1292         }
 1293 
 1294         CSR_WRITE_2(sc, selreg, id);
 1295         CSR_WRITE_2(sc, offreg, off);
 1296 
 1297         for (i = WI_TIMEOUT; i--; DELAY(1))
 1298                 if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR)))
 1299                         break;
 1300 
 1301         if (i < 0)
 1302                 return(ETIMEDOUT);
 1303 
 1304         return(0);
 1305 }
 1306 
 1307 STATIC int
 1308 wi_read_data_io(struct wi_softc *sc, int id, int off, caddr_t buf, int len)
 1309 {
 1310         u_int8_t                *ptr;
 1311 
 1312         if (wi_seek(sc, id, off, WI_BAP1))
 1313                 return(EIO);
 1314 
 1315         ptr = (u_int8_t *)buf;
 1316         CSR_READ_RAW_2(sc, WI_DATA1, ptr, len);
 1317 
 1318         return(0);
 1319 }
 1320 
 1321 /*
 1322  * According to the comments in the HCF Light code, there is a bug in
 1323  * the Hermes (or possibly in certain Hermes firmware revisions) where
 1324  * the chip's internal autoincrement counter gets thrown off during
 1325  * data writes: the autoincrement is missed, causing one data word to
 1326  * be overwritten and subsequent words to be written to the wrong memory
 1327  * locations. The end result is that we could end up transmitting bogus
 1328  * frames without realizing it. The workaround for this is to write a
 1329  * couple of extra guard words after the end of the transfer, then
 1330  * attempt to read then back. If we fail to locate the guard words where
 1331  * we expect them, we preform the transfer over again.
 1332  */
 1333 STATIC int
 1334 wi_write_data_io(struct wi_softc *sc, int id, int off, caddr_t buf, int len)
 1335 {
 1336         u_int8_t                *ptr;
 1337 
 1338 #ifdef WI_HERMES_AUTOINC_WAR
 1339 again:
 1340 #endif
 1341 
 1342         if (wi_seek(sc, id, off, WI_BAP0))
 1343                 return(EIO);
 1344 
 1345         ptr = (u_int8_t *)buf;
 1346         CSR_WRITE_RAW_2(sc, WI_DATA0, ptr, len);
 1347 
 1348 #ifdef WI_HERMES_AUTOINC_WAR
 1349         CSR_WRITE_2(sc, WI_DATA0, 0x1234);
 1350         CSR_WRITE_2(sc, WI_DATA0, 0x5678);
 1351 
 1352         if (wi_seek(sc, id, off + len, WI_BAP0))
 1353                 return(EIO);
 1354 
 1355         if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
 1356             CSR_READ_2(sc, WI_DATA0) != 0x5678)
 1357                 goto again;
 1358 #endif
 1359 
 1360         return(0);
 1361 }
 1362 
 1363 /*
 1364  * Allocate a region of memory inside the NIC and zero
 1365  * it out.
 1366  */
 1367 STATIC int
 1368 wi_alloc_nicmem_io(struct wi_softc *sc, int len, int *id)
 1369 {
 1370         int                     i;
 1371 
 1372         if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
 1373                 printf(WI_PRT_FMT ": failed to allocate %d bytes on NIC\n",
 1374                     WI_PRT_ARG(sc), len);
 1375                 return(ENOMEM);
 1376         }
 1377 
 1378         for (i = WI_TIMEOUT; i--; DELAY(1)) {
 1379                 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
 1380                         break;
 1381         }
 1382 
 1383         if (i < 0)
 1384                 return(ETIMEDOUT);
 1385 
 1386         *id = CSR_READ_2(sc, WI_ALLOC_FID);
 1387         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
 1388 
 1389         if (wi_seek(sc, *id, 0, WI_BAP0))
 1390                 return(EIO);
 1391 
 1392         for (i = 0; i < len / 2; i++)
 1393                 CSR_WRITE_2(sc, WI_DATA0, 0);
 1394 
 1395         return(0);
 1396 }
 1397 
 1398 STATIC void
 1399 wi_setmulti(struct wi_softc *sc)
 1400 {
 1401         struct ifnet            *ifp;
 1402         int                     i = 0;
 1403         struct wi_ltv_mcast     mcast;
 1404         struct ether_multistep  step;
 1405         struct ether_multi      *enm;
 1406 
 1407         ifp = &sc->sc_ic.ic_if;
 1408 
 1409         bzero((char *)&mcast, sizeof(mcast));
 1410 
 1411         mcast.wi_type = WI_RID_MCAST_LIST;
 1412         mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
 1413 
 1414 allmulti:
 1415         if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
 1416                 wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
 1417                 return;
 1418         }
 1419 
 1420         ETHER_FIRST_MULTI(step, &sc->sc_ic.ic_ac, enm);
 1421         while (enm != NULL) {
 1422                 if (i >= 16) {
 1423                         bzero((char *)&mcast, sizeof(mcast));
 1424                         break;
 1425                 }
 1426 
 1427                 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
 1428                         ifp->if_flags |= IFF_ALLMULTI;
 1429                         goto allmulti;
 1430                 }
 1431                 bcopy(enm->enm_addrlo, (char *)&mcast.wi_mcast[i],
 1432                     ETHER_ADDR_LEN);
 1433                 i++;
 1434                 ETHER_NEXT_MULTI(step, enm);
 1435         }
 1436 
 1437         mcast.wi_len = (i * 3) + 1;
 1438         wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
 1439 
 1440         return;
 1441 }
 1442 
 1443 STATIC int
 1444 wi_setdef(struct wi_softc *sc, struct wi_req *wreq)
 1445 {
 1446         struct ifnet            *ifp;
 1447         int error = 0;
 1448 
 1449         ifp = &sc->sc_ic.ic_if;
 1450 
 1451         switch(wreq->wi_type) {
 1452         case WI_RID_MAC_NODE:
 1453                 bcopy((char *)&wreq->wi_val, LLADDR(ifp->if_sadl),
 1454                     ETHER_ADDR_LEN);
 1455                 bcopy((char *)&wreq->wi_val, (char *)&sc->sc_ic.ic_myaddr,
 1456                     ETHER_ADDR_LEN);
 1457                 break;
 1458         case WI_RID_PORTTYPE:
 1459                 error = wi_sync_media(sc, letoh16(wreq->wi_val[0]),
 1460                     sc->wi_tx_rate);
 1461                 break;
 1462         case WI_RID_TX_RATE:
 1463                 error = wi_sync_media(sc, sc->wi_ptype,
 1464                     letoh16(wreq->wi_val[0]));
 1465                 break;
 1466         case WI_RID_MAX_DATALEN:
 1467                 sc->wi_max_data_len = letoh16(wreq->wi_val[0]);
 1468                 break;
 1469         case WI_RID_RTS_THRESH:
 1470                 sc->wi_rts_thresh = letoh16(wreq->wi_val[0]);
 1471                 break;
 1472         case WI_RID_SYSTEM_SCALE:
 1473                 sc->wi_ap_density = letoh16(wreq->wi_val[0]);
 1474                 break;
 1475         case WI_RID_CREATE_IBSS:
 1476                 sc->wi_create_ibss = letoh16(wreq->wi_val[0]);
 1477                 error = wi_sync_media(sc, sc->wi_ptype, sc->wi_tx_rate);
 1478                 break;
 1479         case WI_RID_OWN_CHNL:
 1480                 sc->wi_channel = letoh16(wreq->wi_val[0]);
 1481                 break;
 1482         case WI_RID_NODENAME:
 1483                 error = wi_set_ssid(&sc->wi_node_name,
 1484                     (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
 1485                 break;
 1486         case WI_RID_DESIRED_SSID:
 1487                 error = wi_set_ssid(&sc->wi_net_name,
 1488                     (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
 1489                 break;
 1490         case WI_RID_OWN_SSID:
 1491                 error = wi_set_ssid(&sc->wi_ibss_name,
 1492                     (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
 1493                 break;
 1494         case WI_RID_PM_ENABLED:
 1495                 sc->wi_pm_enabled = letoh16(wreq->wi_val[0]);
 1496                 break;
 1497         case WI_RID_MICROWAVE_OVEN:
 1498                 sc->wi_mor_enabled = letoh16(wreq->wi_val[0]);
 1499                 break;
 1500         case WI_RID_MAX_SLEEP:
 1501                 sc->wi_max_sleep = letoh16(wreq->wi_val[0]);
 1502                 break;
 1503         case WI_RID_CNFAUTHMODE:
 1504                 sc->wi_authtype = letoh16(wreq->wi_val[0]);
 1505                 break;
 1506         case WI_RID_ROAMING_MODE:
 1507                 sc->wi_roaming = letoh16(wreq->wi_val[0]);
 1508                 break;
 1509         case WI_RID_SYMBOL_DIVERSITY:
 1510                 sc->wi_diversity = letoh16(wreq->wi_val[0]);
 1511                 break;
 1512         case WI_RID_ENH_SECURITY:
 1513                 sc->wi_enh_security = letoh16(wreq->wi_val[0]);
 1514                 break;
 1515         case WI_RID_ENCRYPTION:
 1516                 sc->wi_use_wep = letoh16(wreq->wi_val[0]);
 1517                 break;
 1518         case WI_RID_TX_CRYPT_KEY:
 1519                 sc->wi_tx_key = letoh16(wreq->wi_val[0]);
 1520                 break;
 1521         case WI_RID_DEFLT_CRYPT_KEYS:
 1522                 bcopy((char *)wreq, (char *)&sc->wi_keys,
 1523                     sizeof(struct wi_ltv_keys));
 1524                 break;
 1525         case WI_FRID_CRYPTO_ALG:
 1526                 switch (letoh16(wreq->wi_val[0])) {
 1527                 case WI_CRYPTO_FIRMWARE_WEP:
 1528                         sc->wi_crypto_algorithm = WI_CRYPTO_FIRMWARE_WEP;
 1529                         break;
 1530                 case WI_CRYPTO_SOFTWARE_WEP:
 1531                         sc->wi_crypto_algorithm = WI_CRYPTO_SOFTWARE_WEP;
 1532                         break;
 1533                 default:
 1534                         printf(WI_PRT_FMT ": unsupported crypto algorithm %d\n",
 1535                             WI_PRT_ARG(sc), letoh16(wreq->wi_val[0]));
 1536                         error = EINVAL;
 1537                 }
 1538                 break;
 1539         default:
 1540                 error = EINVAL;
 1541                 break;
 1542         }
 1543 
 1544         return (error);
 1545 }
 1546 
 1547 STATIC int
 1548 wi_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 1549 {
 1550         int                     s, error = 0, i, j, len;
 1551         struct wi_softc         *sc;
 1552         struct ifreq            *ifr;
 1553         struct proc             *p = curproc;
 1554         struct ifaddr           *ifa = (struct ifaddr *)data;
 1555         struct wi_scan_res      *res;
 1556         struct wi_scan_p2_hdr   *p2;
 1557         struct wi_req           *wreq = NULL;
 1558         u_int32_t               flags;
 1559 
 1560         struct ieee80211_nwid           *nwidp = NULL;
 1561         struct ieee80211_nodereq_all    *na;
 1562         struct ieee80211_bssid          *bssid;
 1563 
 1564         s = splnet();
 1565 
 1566         sc = ifp->if_softc;
 1567         ifr = (struct ifreq *)data;
 1568 
 1569         if (!(sc->wi_flags & WI_FLAGS_ATTACHED)) {
 1570                 splx(s);
 1571                 return(ENODEV);
 1572         }
 1573 
 1574         DPRINTF (WID_IOCTL, ("wi_ioctl: command %lu data %p\n",
 1575             command, data));
 1576 
 1577         if ((error = ether_ioctl(ifp, &sc->sc_ic.ic_ac, command, data)) > 0) {
 1578                 splx(s);
 1579                 return error;
 1580         }
 1581 
 1582         switch(command) {
 1583         case SIOCSIFADDR:
 1584                 ifp->if_flags |= IFF_UP;
 1585                 switch (ifa->ifa_addr->sa_family) {
 1586 #ifdef INET
 1587                 case AF_INET:
 1588                         wi_init(sc);
 1589                         arp_ifinit(&sc->sc_ic.ic_ac, ifa);
 1590                         break;
 1591 #endif  /* INET */
 1592                 default:
 1593                         wi_init(sc);
 1594                         break;
 1595                 }
 1596                 break;
 1597 
 1598         case SIOCSIFMTU:
 1599                 if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
 1600                         error = EINVAL;
 1601                 } else if (ifp->if_mtu != ifr->ifr_mtu) {
 1602                         ifp->if_mtu = ifr->ifr_mtu;
 1603                 }
 1604                 break;
 1605 
 1606         case SIOCSIFFLAGS:
 1607                 if (ifp->if_flags & IFF_UP) {
 1608                         if (ifp->if_flags & IFF_RUNNING &&
 1609                             ifp->if_flags & IFF_PROMISC &&
 1610                             !(sc->wi_if_flags & IFF_PROMISC)) {
 1611                                 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
 1612                                         WI_SETVAL(WI_RID_PROMISC, 1);
 1613                         } else if (ifp->if_flags & IFF_RUNNING &&
 1614                             !(ifp->if_flags & IFF_PROMISC) &&
 1615                             sc->wi_if_flags & IFF_PROMISC) {
 1616                                 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
 1617                                         WI_SETVAL(WI_RID_PROMISC, 0);
 1618                         } else
 1619                                 wi_init(sc);
 1620                 } else if (ifp->if_flags & IFF_RUNNING)
 1621                         wi_stop(sc);
 1622                 sc->wi_if_flags = ifp->if_flags;
 1623                 error = 0;
 1624                 break;
 1625         case SIOCADDMULTI:
 1626         case SIOCDELMULTI:
 1627                 /* Update our multicast list. */
 1628                 error = (command == SIOCADDMULTI) ?
 1629                     ether_addmulti(ifr, &sc->sc_ic.ic_ac) :
 1630                     ether_delmulti(ifr, &sc->sc_ic.ic_ac);
 1631 
 1632                 if (error == ENETRESET) {
 1633                         /*
 1634                          * Multicast list has changed; set the hardware filter
 1635                          * accordingly.
 1636                          */
 1637                         if (ifp->if_flags & IFF_RUNNING)
 1638                                 wi_setmulti(sc);
 1639                         error = 0;
 1640                 }
 1641                 break;
 1642         case SIOCSIFMEDIA:
 1643         case SIOCGIFMEDIA:
 1644                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
 1645                 break;
 1646         case SIOCGWAVELAN:
 1647                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1648                 bzero(wreq, sizeof(*wreq));
 1649                 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
 1650                 if (error)
 1651                         break;
 1652                 if (wreq->wi_len > WI_MAX_DATALEN) {
 1653                         error = EINVAL;
 1654                         break;
 1655                 }
 1656                 switch (wreq->wi_type) {
 1657                 case WI_RID_IFACE_STATS:
 1658                         /* XXX native byte order */
 1659                         bcopy((char *)&sc->wi_stats, (char *)&wreq->wi_val,
 1660                             sizeof(sc->wi_stats));
 1661                         wreq->wi_len = (sizeof(sc->wi_stats) / 2) + 1;
 1662                         break;
 1663                 case WI_RID_DEFLT_CRYPT_KEYS:
 1664                         /* For non-root user, return all-zeroes keys */
 1665                         if (suser(p, 0))
 1666                                 bzero(wreq, sizeof(struct wi_ltv_keys));
 1667                         else
 1668                                 bcopy((char *)&sc->wi_keys, wreq,
 1669                                         sizeof(struct wi_ltv_keys));
 1670                         break;
 1671                 case WI_RID_PROCFRAME:
 1672                         wreq->wi_len = 2;
 1673                         wreq->wi_val[0] = htole16(sc->wi_procframe);
 1674                         break;
 1675                 case WI_RID_PRISM2:
 1676                         wreq->wi_len = 2;
 1677                         wreq->wi_val[0] = htole16(sc->sc_firmware_type ==
 1678                             WI_LUCENT ? 0 : 1);
 1679                         break;
 1680                 case WI_FRID_CRYPTO_ALG:
 1681                         wreq->wi_val[0] =
 1682                             htole16((u_int16_t)sc->wi_crypto_algorithm);
 1683                         wreq->wi_len = 1;
 1684                         break;
 1685                 case WI_RID_SCAN_RES:
 1686                         if (sc->sc_firmware_type == WI_LUCENT) {
 1687                                 memcpy((char *)wreq->wi_val,
 1688                                     (char *)sc->wi_scanbuf,
 1689                                     sc->wi_scanbuf_len * 2);
 1690                                 wreq->wi_len = sc->wi_scanbuf_len;
 1691                                 break;
 1692                         }
 1693                         /* FALLTHROUGH */
 1694                 default:
 1695                         if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1696                                 error = EINVAL;
 1697                         }
 1698                         break;
 1699                 }
 1700                 error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
 1701                 break;
 1702         case SIOCSWAVELAN:
 1703                 if ((error = suser(curproc, 0)) != 0)
 1704                         break;
 1705                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1706                 bzero(wreq, sizeof(*wreq));
 1707                 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
 1708                 if (error)
 1709                         break;
 1710                 error = EINVAL;
 1711                 if (wreq->wi_len > WI_MAX_DATALEN)
 1712                         break;
 1713                 switch (wreq->wi_type) {
 1714                 case WI_RID_IFACE_STATS:
 1715                         break;
 1716                 case WI_RID_MGMT_XMIT:
 1717                         error = wi_mgmt_xmit(sc, (caddr_t)&wreq->wi_val,
 1718                             wreq->wi_len);
 1719                         break;
 1720                 case WI_RID_PROCFRAME:
 1721                         sc->wi_procframe = letoh16(wreq->wi_val[0]);
 1722                         error = 0;
 1723                         break;
 1724                 case WI_RID_SCAN_REQ:
 1725                         error = 0;
 1726                         if (sc->sc_firmware_type == WI_LUCENT)
 1727                                 wi_cmd(sc, WI_CMD_INQUIRE,
 1728                                     WI_INFO_SCAN_RESULTS, 0, 0);
 1729                         else
 1730                                 error = wi_write_record(sc,
 1731                                     (struct wi_ltv_gen *)wreq);
 1732                         break;
 1733                 case WI_FRID_CRYPTO_ALG:
 1734                         if (sc->sc_firmware_type != WI_LUCENT) {
 1735                                 error = wi_setdef(sc, wreq);
 1736                                 if (!error && (ifp->if_flags & IFF_UP))
 1737                                         wi_init(sc);
 1738                         }
 1739                         break;
 1740                 case WI_RID_SYMBOL_DIVERSITY:
 1741                 case WI_RID_ROAMING_MODE:
 1742                 case WI_RID_CREATE_IBSS:
 1743                 case WI_RID_MICROWAVE_OVEN:
 1744                 case WI_RID_OWN_SSID:
 1745                 case WI_RID_ENH_SECURITY:
 1746                         /*
 1747                          * Check for features that may not be supported
 1748                          * (must be just before default case).
 1749                          */
 1750                         if ((wreq->wi_type == WI_RID_SYMBOL_DIVERSITY &&
 1751                             !(sc->wi_flags & WI_FLAGS_HAS_DIVERSITY)) ||
 1752                             (wreq->wi_type == WI_RID_ROAMING_MODE &&
 1753                             !(sc->wi_flags & WI_FLAGS_HAS_ROAMING)) ||
 1754                             (wreq->wi_type == WI_RID_CREATE_IBSS &&
 1755                             !(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)) ||
 1756                             (wreq->wi_type == WI_RID_MICROWAVE_OVEN &&
 1757                             !(sc->wi_flags & WI_FLAGS_HAS_MOR)) ||
 1758                             (wreq->wi_type == WI_RID_ENH_SECURITY &&
 1759                             !(sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY)) ||
 1760                             (wreq->wi_type == WI_RID_OWN_SSID &&
 1761                             wreq->wi_len != 0))
 1762                                 break;
 1763                         /* FALLTHROUGH */
 1764                 default:
 1765                         error = wi_write_record(sc, (struct wi_ltv_gen *)wreq);
 1766                         if (!error)
 1767                                 error = wi_setdef(sc, wreq);
 1768                         if (!error && (ifp->if_flags & IFF_UP))
 1769                                 wi_init(sc);
 1770                 }
 1771                 break;
 1772         case SIOCGPRISM2DEBUG:
 1773                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1774                 bzero(wreq, sizeof(*wreq));
 1775                 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
 1776                 if (error)
 1777                         break;
 1778                 if (!(ifp->if_flags & IFF_RUNNING) ||
 1779                     sc->sc_firmware_type == WI_LUCENT) {
 1780                         error = EIO;
 1781                         break;
 1782                 }
 1783                 error = wi_get_debug(sc, wreq);
 1784                 if (error == 0)
 1785                         error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
 1786                 break;
 1787         case SIOCSPRISM2DEBUG:
 1788                 if ((error = suser(curproc, 0)) != 0)
 1789                         break;
 1790                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1791                 bzero(wreq, sizeof(*wreq));
 1792                 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
 1793                 if (error)
 1794                         break;
 1795                 error = wi_set_debug(sc, wreq);
 1796                 break;
 1797         case SIOCG80211NWID:
 1798                 if ((ifp->if_flags & IFF_UP) && sc->wi_net_name.i_len > 0) {
 1799                         /* Return the desired ID */
 1800                         error = copyout(&sc->wi_net_name, ifr->ifr_data,
 1801                             sizeof(sc->wi_net_name));
 1802                 } else {
 1803                         wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1804                         bzero(wreq, sizeof(*wreq));
 1805                         wreq->wi_type = WI_RID_CURRENT_SSID;
 1806                         wreq->wi_len = WI_MAX_DATALEN;
 1807                         if (wi_read_record(sc, (struct wi_ltv_gen *)wreq) ||
 1808                             letoh16(wreq->wi_val[0]) > IEEE80211_NWID_LEN)
 1809                                 error = EINVAL;
 1810                         else {
 1811                                 nwidp = malloc(sizeof *nwidp, M_DEVBUF, M_WAITOK);
 1812                                 bzero(nwidp, sizeof(*nwidp));
 1813                                 wi_set_ssid(nwidp, (u_int8_t *)&wreq->wi_val[1],
 1814                                     letoh16(wreq->wi_val[0]));
 1815                                 error = copyout(nwidp, ifr->ifr_data,
 1816                                     sizeof(*nwidp));
 1817                         }
 1818                 }
 1819                 break;
 1820         case SIOCS80211NWID:
 1821                 if ((error = suser(curproc, 0)) != 0)
 1822                         break;
 1823                 nwidp = malloc(sizeof *nwidp, M_DEVBUF, M_WAITOK);
 1824                 error = copyin(ifr->ifr_data, nwidp, sizeof(*nwidp));
 1825                 if (error)
 1826                         break;
 1827                 if (nwidp->i_len > IEEE80211_NWID_LEN) {
 1828                         error = EINVAL;
 1829                         break;
 1830                 }
 1831                 if (sc->wi_net_name.i_len == nwidp->i_len &&
 1832                     memcmp(sc->wi_net_name.i_nwid, nwidp->i_nwid, nwidp->i_len) == 0)
 1833                         break;
 1834                 wi_set_ssid(&sc->wi_net_name, nwidp->i_nwid, nwidp->i_len);
 1835                 WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
 1836                 if (ifp->if_flags & IFF_UP)
 1837                         /* Reinitialize WaveLAN. */
 1838                         wi_init(sc);
 1839                 break;
 1840         case SIOCS80211NWKEY:
 1841                 if ((error = suser(curproc, 0)) != 0)
 1842                         break;
 1843                 error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
 1844                 break;
 1845         case SIOCG80211NWKEY:
 1846                 error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
 1847                 break;
 1848         case SIOCS80211POWER:
 1849                 if ((error = suser(curproc, 0)) != 0)
 1850                         break;
 1851                 error = wi_set_pm(sc, (struct ieee80211_power *)data);
 1852                 break;
 1853         case SIOCG80211POWER:
 1854                 error = wi_get_pm(sc, (struct ieee80211_power *)data);
 1855                 break;
 1856         case SIOCS80211TXPOWER:
 1857                 if ((error = suser(curproc, 0)) != 0)
 1858                         break;
 1859                 error = wi_set_txpower(sc, (struct ieee80211_txpower *)data);
 1860                 break;
 1861         case SIOCG80211TXPOWER:
 1862                 error = wi_get_txpower(sc, (struct ieee80211_txpower *)data);
 1863                 break;
 1864         case SIOCS80211CHANNEL:
 1865                 if ((error = suser(curproc, 0)) != 0)
 1866                         break;
 1867                 if (((struct ieee80211chanreq *)data)->i_channel > 14) {
 1868                         error = EINVAL;
 1869                         break;
 1870                 }
 1871                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1872                 bzero(wreq, sizeof(*wreq));
 1873                 wreq->wi_type = WI_RID_OWN_CHNL;
 1874                 wreq->wi_val[0] =
 1875                     htole16(((struct ieee80211chanreq *)data)->i_channel);
 1876                 error = wi_setdef(sc, wreq);
 1877                 if (!error && (ifp->if_flags & IFF_UP))
 1878                         wi_init(sc);
 1879                 break;
 1880         case SIOCG80211CHANNEL:
 1881                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1882                 bzero(wreq, sizeof(*wreq));
 1883                 wreq->wi_type = WI_RID_CURRENT_CHAN;
 1884                 wreq->wi_len = WI_MAX_DATALEN;
 1885                 if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1886                         error = EINVAL;
 1887                         break;
 1888                 }
 1889                 ((struct ieee80211chanreq *)data)->i_channel =
 1890                     letoh16(wreq->wi_val[0]);
 1891                 break;
 1892         case SIOCG80211BSSID:
 1893                 bssid = (struct ieee80211_bssid *)data;
 1894                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1895                 bzero(wreq, sizeof(*wreq));
 1896                 wreq->wi_type = WI_RID_CURRENT_BSSID;
 1897                 wreq->wi_len = WI_MAX_DATALEN;
 1898                 if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1899                         error = EINVAL;
 1900                         break;
 1901                 }
 1902                 IEEE80211_ADDR_COPY(bssid->i_bssid, wreq->wi_val);
 1903                 break;
 1904         case SIOCS80211SCAN:
 1905                 if ((error = suser(curproc, 0)) != 0)
 1906                         break;
 1907                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
 1908                         break;
 1909                 if ((ifp->if_flags & IFF_UP) == 0) {
 1910                         error = ENETDOWN;
 1911                         break;
 1912                 }
 1913                 if (sc->sc_firmware_type == WI_LUCENT) {
 1914                         wi_cmd(sc, WI_CMD_INQUIRE,
 1915                             WI_INFO_SCAN_RESULTS, 0, 0);
 1916                 } else {
 1917                         wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1918                         bzero(wreq, sizeof(*wreq));
 1919                         wreq->wi_len = 3;
 1920                         wreq->wi_type = WI_RID_SCAN_REQ;
 1921                         wreq->wi_val[0] = 0x3FFF;
 1922                         wreq->wi_val[1] = 0x000F;
 1923 
 1924                         error = wi_write_record(sc,
 1925                             (struct wi_ltv_gen *)wreq);
 1926                         if (error)
 1927                                 break;
 1928                 }
 1929                 sc->wi_scan_lock = 0;
 1930                 timeout_set(&sc->wi_scan_timeout, wi_scan_timeout, sc);
 1931                 len = WI_WAVELAN_RES_TIMEOUT;
 1932                 if (sc->wi_flags & WI_FLAGS_BUS_USB) {
 1933                         /* Use a longer timeout for wi@usb */
 1934                         len = WI_WAVELAN_RES_TIMEOUT * 4;
 1935                 }
 1936                 timeout_add(&sc->wi_scan_timeout, len);
 1937 
 1938                 /* Let the userspace process wait for completion */
 1939                 error = tsleep(&sc->wi_scan_lock, PCATCH, "wiscan",
 1940                     hz * IEEE80211_SCAN_TIMEOUT);
 1941                 break;
 1942         case SIOCG80211ALLNODES:
 1943             {
 1944                 struct ieee80211_nodereq        *nr = NULL;
 1945 
 1946                 if ((error = suser(curproc, 0)) != 0)
 1947                         break;
 1948                 na = (struct ieee80211_nodereq_all *)data;
 1949                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
 1950                         /* List all associated stations */
 1951                         error = wihap_ioctl(sc, command, data);
 1952                         break;
 1953                 }
 1954                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 1955                 bzero(wreq, sizeof(*wreq));
 1956                 wreq->wi_len = WI_MAX_DATALEN;
 1957                 wreq->wi_type = WI_RID_SCAN_RES;
 1958                 if (sc->sc_firmware_type == WI_LUCENT) {
 1959                         bcopy(sc->wi_scanbuf, wreq->wi_val,
 1960                             sc->wi_scanbuf_len * 2);
 1961                         wreq->wi_len = sc->wi_scanbuf_len;
 1962                         i = 0;
 1963                         len = WI_WAVELAN_RES_SIZE;
 1964                 } else {
 1965                         if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1966                                 error = EINVAL;
 1967                                 break;
 1968                         }
 1969                         p2 = (struct wi_scan_p2_hdr *)wreq->wi_val;
 1970                         if (p2->wi_reason == 0)
 1971                                 break;
 1972                         i = sizeof(*p2);
 1973                         len = WI_PRISM2_RES_SIZE;
 1974                 }
 1975 
 1976                 for (na->na_nodes = j = 0; (i < (wreq->wi_len * 2) - len) &&
 1977                     (na->na_size >= j + sizeof(struct ieee80211_nodereq));
 1978                     i += len) {
 1979 
 1980                         if (nr == NULL)
 1981                                 nr = malloc(sizeof *nr, M_DEVBUF, M_WAITOK);
 1982                         res = (struct wi_scan_res *)((char *)wreq->wi_val + i);
 1983                         if (res == NULL)
 1984                                 break;
 1985 
 1986                         bzero(nr, sizeof(*nr));
 1987                         IEEE80211_ADDR_COPY(nr->nr_macaddr, res->wi_bssid);
 1988                         IEEE80211_ADDR_COPY(nr->nr_bssid, res->wi_bssid);
 1989                         nr->nr_channel = letoh16(res->wi_chan);
 1990                         nr->nr_chan_flags = IEEE80211_CHAN_B;
 1991                         nr->nr_rssi = letoh16(res->wi_signal);
 1992                         nr->nr_max_rssi = 0; /* XXX */
 1993                         nr->nr_nwid_len = letoh16(res->wi_ssid_len);
 1994                         bcopy(res->wi_ssid, nr->nr_nwid, nr->nr_nwid_len);
 1995                         nr->nr_intval = letoh16(res->wi_interval);
 1996                         nr->nr_capinfo = letoh16(res->wi_capinfo);
 1997                         nr->nr_txrate = res->wi_rate == WI_WAVELAN_RES_1M ? 2 :
 1998                             (res->wi_rate == WI_WAVELAN_RES_2M ? 4 :
 1999                             (res->wi_rate == WI_WAVELAN_RES_5M ? 11 :
 2000                             (res->wi_rate == WI_WAVELAN_RES_11M ? 22 : 0)));
 2001                         nr->nr_nrates = 0;
 2002                         while (res->wi_srates[nr->nr_nrates] != 0) {
 2003                                 nr->nr_rates[nr->nr_nrates] =
 2004                                     res->wi_srates[nr->nr_nrates] &
 2005                                     WI_VAR_SRATES_MASK;
 2006                                 nr->nr_nrates++;
 2007                         }
 2008                         nr->nr_flags = 0;
 2009                         if (bcmp(nr->nr_macaddr, nr->nr_bssid,
 2010                             IEEE80211_ADDR_LEN) == 0)
 2011                                 nr->nr_flags |= IEEE80211_NODEREQ_AP;
 2012 
 2013                         error = copyout(nr, (caddr_t)na->na_node + j,
 2014                             sizeof(struct ieee80211_nodereq));
 2015                         if (error)
 2016                                 break;
 2017                         j += sizeof(struct ieee80211_nodereq);
 2018                         na->na_nodes++;
 2019                 }
 2020                 if (nr)
 2021                         free(nr, M_DEVBUF);
 2022                 break;
 2023             }
 2024         case SIOCG80211FLAGS:
 2025                 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
 2026                         break;
 2027                 ifr->ifr_flags = 0;
 2028                 if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY) {
 2029                         wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK);
 2030                         bzero(wreq, sizeof(*wreq));
 2031                         wreq->wi_len = WI_MAX_DATALEN;
 2032                         wreq->wi_type = WI_RID_ENH_SECURITY;
 2033                         if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 2034                                 error = EINVAL;
 2035                                 break;
 2036                         }
 2037                         sc->wi_enh_security = letoh16(wreq->wi_val[0]);
 2038                         if (sc->wi_enh_security == WI_HIDESSID_IGNPROBES)
 2039                                 ifr->ifr_flags |= IEEE80211_F_HIDENWID >>
 2040                                     IEEE80211_F_USERSHIFT;
 2041                 }
 2042                 break;
 2043         case SIOCS80211FLAGS:
 2044                 if ((error = suser(curproc, 0)) != 0)
 2045                         break;
 2046                 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP) {
 2047                         error = EINVAL;
 2048                         break;
 2049                 }
 2050                 flags = (u_int32_t)ifr->ifr_flags << IEEE80211_F_USERSHIFT;
 2051                 if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY) {
 2052                         sc->wi_enh_security = (flags & IEEE80211_F_HIDENWID) ?
 2053                             WI_HIDESSID_IGNPROBES : 0;
 2054                         WI_SETVAL(WI_RID_ENH_SECURITY, sc->wi_enh_security);
 2055                 }
 2056                 break;
 2057         case SIOCHOSTAP_ADD:
 2058         case SIOCHOSTAP_DEL:
 2059         case SIOCHOSTAP_GET:
 2060         case SIOCHOSTAP_GETALL:
 2061         case SIOCHOSTAP_GFLAGS:
 2062         case SIOCHOSTAP_SFLAGS:
 2063                 /* Send all Host AP specific ioctl's to Host AP code. */
 2064                 error = wihap_ioctl(sc, command, data);
 2065                 break;
 2066         default:
 2067                 error = EINVAL;
 2068                 break;
 2069         }
 2070 
 2071         if (wreq)
 2072                 free(wreq, M_DEVBUF);
 2073         if (nwidp)
 2074                 free(nwidp, M_DEVBUF);
 2075         splx(s);
 2076         return(error);
 2077 }
 2078 
 2079 void
 2080 wi_scan_timeout(void *arg)
 2081 {
 2082         struct wi_softc         *sc = (struct wi_softc *)arg;
 2083         struct wi_req           wreq;
 2084 
 2085         if (sc->wi_scan_lock++ < WI_WAVELAN_RES_TRIES &&
 2086             sc->sc_firmware_type != WI_LUCENT &&
 2087             (sc->wi_flags & WI_FLAGS_BUS_USB) == 0) {
 2088                 /*
 2089                  * The Prism2/2.5/3 chipsets will set an extra field in the
 2090                  * scan result if the scan request has been completed by the
 2091                  * firmware. This allows to poll for completion and to
 2092                  * wait for some more time if the scan is still in progress.
 2093                  *
 2094                  * XXX This doesn't work with wi@usb because it isn't safe
 2095                  * to call wi_read_record_usb() while beeing in the timeout
 2096                  * handler.
 2097                  */
 2098                 wreq.wi_len = WI_MAX_DATALEN;
 2099                 wreq.wi_type = WI_RID_SCAN_RES;
 2100 
 2101                 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
 2102                     ((struct wi_scan_p2_hdr *)wreq.wi_val)->wi_reason == 0) {
 2103                         /* Wait some more time for scan completion */
 2104                         timeout_add(&sc->wi_scan_timeout, WI_WAVELAN_RES_TIMEOUT);
 2105                         return;
 2106                 }
 2107         }
 2108 
 2109         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
 2110                 printf(WI_PRT_FMT ": wi_scan_timeout: %d tries\n",
 2111                     WI_PRT_ARG(sc), sc->wi_scan_lock);
 2112 
 2113         /* Wakeup the userland */
 2114         wakeup(&sc->wi_scan_lock);      
 2115         sc->wi_scan_lock = 0;
 2116 }
 2117 
 2118 STATIC void
 2119 wi_init_io(struct wi_softc *sc)
 2120 {
 2121         struct ifnet            *ifp = &sc->sc_ic.ic_ac.ac_if;
 2122         int                     s;
 2123         struct wi_ltv_macaddr   mac;
 2124         int                     id = 0;
 2125 
 2126         if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
 2127                 return;
 2128 
 2129         DPRINTF(WID_INIT, ("wi_init: sc %p\n", sc));
 2130 
 2131         s = splnet();
 2132 
 2133         if (ifp->if_flags & IFF_RUNNING)
 2134                 wi_stop(sc);
 2135 
 2136         wi_reset(sc);
 2137 
 2138         /* Program max data length. */
 2139         WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
 2140 
 2141         /* Set the port type. */
 2142         WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
 2143 
 2144         /* Enable/disable IBSS creation. */
 2145         WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
 2146 
 2147         /* Program the RTS/CTS threshold. */
 2148         WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
 2149 
 2150         /* Program the TX rate */
 2151         WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
 2152 
 2153         /* Access point density */
 2154         WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
 2155 
 2156         /* Power Management Enabled */
 2157         WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
 2158 
 2159         /* Power Management Max Sleep */
 2160         WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
 2161 
 2162         /* Set Enhanced Security if supported. */
 2163         if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY)
 2164                 WI_SETVAL(WI_RID_ENH_SECURITY, sc->wi_enh_security);
 2165 
 2166         /* Set Roaming Mode unless this is a Symbol card. */
 2167         if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
 2168                 WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
 2169 
 2170         /* Set Antenna Diversity if this is a Symbol card. */
 2171         if (sc->wi_flags & WI_FLAGS_HAS_DIVERSITY)
 2172                 WI_SETVAL(WI_RID_SYMBOL_DIVERSITY, sc->wi_diversity);
 2173 
 2174         /* Specify the network name */
 2175         WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
 2176 
 2177         /* Specify the IBSS name */
 2178         if (sc->wi_net_name.i_len != 0 && (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
 2179             (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
 2180                 WI_SETSTR(WI_RID_OWN_SSID, sc->wi_net_name);
 2181         else
 2182                 WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name);
 2183 
 2184         /* Specify the frequency to use */
 2185         WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
 2186 
 2187         /* Program the nodename. */
 2188         WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name);
 2189 
 2190         /* Set our MAC address. */
 2191         mac.wi_len = 4;
 2192         mac.wi_type = WI_RID_MAC_NODE;
 2193         bcopy(LLADDR(ifp->if_sadl),
 2194             (char *)&sc->sc_ic.ic_myaddr, ETHER_ADDR_LEN);
 2195         bcopy((char *)&sc->sc_ic.ic_myaddr,
 2196             (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN);
 2197         wi_write_record(sc, (struct wi_ltv_gen *)&mac);
 2198 
 2199         /*
 2200          * Initialize promisc mode.
 2201          *      Being in the Host-AP mode causes
 2202          *      great deal of pain if promisc mode is set.
 2203          *      Therefore we avoid confusing the firmware
 2204          *      and always reset promisc mode in Host-AP regime,
 2205          *      it shows us all the packets anyway.
 2206          */
 2207         if (sc->wi_ptype != WI_PORTTYPE_HOSTAP && ifp->if_flags & IFF_PROMISC)
 2208                 WI_SETVAL(WI_RID_PROMISC, 1);
 2209         else
 2210                 WI_SETVAL(WI_RID_PROMISC, 0);
 2211 
 2212         /* Configure WEP. */
 2213         if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
 2214                 WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
 2215                 WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
 2216                 sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
 2217                 sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
 2218                 wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
 2219                 if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
 2220                         /*
 2221                          * HWB3163 EVAL-CARD Firmware version less than 0.8.2.
 2222                          *
 2223                          * If promiscuous mode is disabled, the Prism2 chip
 2224                          * does not work with WEP .
 2225                          * I'm currently investigating the details of this.
 2226                          * (ichiro@netbsd.org)
 2227                          */
 2228                          if (sc->sc_firmware_type == WI_INTERSIL &&
 2229                             sc->sc_sta_firmware_ver < 802 ) {
 2230                                 /* firm ver < 0.8.2 */
 2231                                 WI_SETVAL(WI_RID_PROMISC, 1);
 2232                          }
 2233                          WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
 2234                 }
 2235         }
 2236 
 2237         /* Set multicast filter. */
 2238         wi_setmulti(sc);
 2239 
 2240         /* Enable desired port */
 2241         wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
 2242 
 2243         if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
 2244                 printf(WI_PRT_FMT ": tx buffer allocation failed\n",
 2245                     WI_PRT_ARG(sc));
 2246         sc->wi_tx_data_id = id;
 2247 
 2248         if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
 2249                 printf(WI_PRT_FMT ": mgmt. buffer allocation failed\n",
 2250                     WI_PRT_ARG(sc));
 2251         sc->wi_tx_mgmt_id = id;
 2252 
 2253         /* Set txpower */
 2254         if (sc->wi_flags & WI_FLAGS_TXPOWER)
 2255                 wi_set_txpower(sc, NULL);
 2256 
 2257         /* enable interrupts */
 2258         wi_intr_enable(sc, WI_INTRS);
 2259 
 2260         wihap_init(sc);
 2261 
 2262         splx(s);
 2263 
 2264         ifp->if_flags |= IFF_RUNNING;
 2265         ifp->if_flags &= ~IFF_OACTIVE;
 2266 
 2267         timeout_add(&sc->sc_timo, hz * 60);
 2268 
 2269         return;
 2270 }
 2271 
 2272 static const u_int32_t crc32tab[] = {
 2273         0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
 2274         0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
 2275         0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
 2276         0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
 2277         0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
 2278         0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
 2279         0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
 2280         0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
 2281         0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
 2282         0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
 2283         0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
 2284         0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
 2285         0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
 2286         0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
 2287         0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
 2288         0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
 2289         0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
 2290         0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
 2291         0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
 2292         0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
 2293         0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
 2294         0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
 2295         0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
 2296         0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
 2297         0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
 2298         0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
 2299         0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
 2300         0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
 2301         0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
 2302         0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
 2303         0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
 2304         0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
 2305         0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
 2306         0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
 2307         0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
 2308         0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
 2309         0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
 2310         0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
 2311         0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
 2312         0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
 2313         0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
 2314         0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
 2315         0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
 2316         0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
 2317         0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
 2318         0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
 2319         0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
 2320         0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
 2321         0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
 2322         0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
 2323         0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
 2324         0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
 2325         0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
 2326         0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
 2327         0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
 2328         0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
 2329         0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
 2330         0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
 2331         0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
 2332         0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
 2333         0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
 2334         0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
 2335         0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
 2336         0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
 2337 };
 2338 
 2339 STATIC void
 2340 wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
 2341 {
 2342         u_int32_t i, crc, klen;
 2343         u_int8_t key[RC4KEYLEN];
 2344         u_int8_t *dat;
 2345         struct rc4_ctx ctx;
 2346 
 2347         if (!sc->wi_icv_flag) {
 2348                 sc->wi_icv = arc4random();
 2349                 sc->wi_icv_flag++;
 2350         } else
 2351                 sc->wi_icv++;
 2352         /*
 2353          * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
 2354          * (B, 255, N) with 3 <= B < 8
 2355          */
 2356         if (sc->wi_icv >= 0x03ff00 &&
 2357             (sc->wi_icv & 0xf8ff00) == 0x00ff00)
 2358                 sc->wi_icv += 0x000100;
 2359 
 2360         /* prepend 24bit IV to tx key, byte order does not matter */
 2361         bzero(key, sizeof(key));
 2362         key[0] = sc->wi_icv >> 16;
 2363         key[1] = sc->wi_icv >> 8;
 2364         key[2] = sc->wi_icv;
 2365 
 2366         klen = letoh16(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen);
 2367         bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
 2368             (char *)key + IEEE80211_WEP_IVLEN, klen);
 2369         klen = (klen > IEEE80211_WEP_KEYLEN) ? RC4KEYLEN : RC4KEYLEN / 2;
 2370 
 2371         /* rc4 keysetup */
 2372         rc4_keysetup(&ctx, key, klen);
 2373 
 2374         /* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
 2375         dat = buf;
 2376         dat[0] = key[0];
 2377         dat[1] = key[1];
 2378         dat[2] = key[2];
 2379         dat[3] = sc->wi_tx_key << 6;            /* pad and keyid */
 2380         dat += 4;
 2381 
 2382         /* compute crc32 over data and encrypt */
 2383         crc = ~0;
 2384         for (i = 0; i < len; i++)
 2385                 crc = crc32tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
 2386         crc = ~crc;
 2387         rc4_crypt(&ctx, dat, dat, len);
 2388         dat += len;
 2389 
 2390         /* append little-endian crc32 and encrypt */
 2391         dat[0] = crc;
 2392         dat[1] = crc >> 8;
 2393         dat[2] = crc >> 16;
 2394         dat[3] = crc >> 24;
 2395         rc4_crypt(&ctx, dat, dat, IEEE80211_WEP_CRCLEN);
 2396 }
 2397 
 2398 STATIC int
 2399 wi_do_hostdecrypt(struct wi_softc *sc, caddr_t buf, int len)
 2400 {
 2401         u_int32_t i, crc, klen, kid;
 2402         u_int8_t key[RC4KEYLEN];
 2403         u_int8_t *dat;
 2404         struct rc4_ctx ctx;
 2405 
 2406         if (len < IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
 2407             IEEE80211_WEP_CRCLEN)
 2408                 return -1;
 2409         len -= (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
 2410             IEEE80211_WEP_CRCLEN);
 2411 
 2412         dat = buf;
 2413 
 2414         bzero(key, sizeof(key));
 2415         key[0] = dat[0];
 2416         key[1] = dat[1];
 2417         key[2] = dat[2];
 2418         kid = (dat[3] >> 6) % 4;
 2419         dat += 4;
 2420 
 2421         klen = letoh16(sc->wi_keys.wi_keys[kid].wi_keylen);
 2422         bcopy((char *)&sc->wi_keys.wi_keys[kid].wi_keydat,
 2423             (char *)key + IEEE80211_WEP_IVLEN, klen);
 2424         klen = (klen > IEEE80211_WEP_KEYLEN) ? RC4KEYLEN : RC4KEYLEN / 2;
 2425 
 2426         /* rc4 keysetup */
 2427         rc4_keysetup(&ctx, key, klen);
 2428 
 2429         /* decrypt and compute crc32 over data */
 2430         rc4_crypt(&ctx, dat, dat, len);
 2431         crc = ~0;
 2432         for (i = 0; i < len; i++)
 2433                 crc = crc32tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
 2434         crc = ~crc;
 2435         dat += len;
 2436 
 2437         /* decrypt little-endian crc32 and verify */
 2438         rc4_crypt(&ctx, dat, dat, IEEE80211_WEP_CRCLEN);
 2439 
 2440         if ((dat[0] != crc) && (dat[1] != crc >> 8) &&
 2441             (dat[2] != crc >> 16) && (dat[3] != crc >> 24)) {
 2442                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
 2443                         printf(WI_PRT_FMT ": wi_do_hostdecrypt: iv mismatch: "
 2444                             "0x%02x%02x%02x%02x vs. 0x%x\n", WI_PRT_ARG(sc),
 2445                             dat[3], dat[2], dat[1], dat[0], crc);
 2446                 return -1;
 2447         }
 2448 
 2449         return 0;
 2450 }
 2451 
 2452 void
 2453 wi_start(struct ifnet *ifp)
 2454 {
 2455         struct wi_softc         *sc;
 2456         struct mbuf             *m0;
 2457         struct wi_frame         tx_frame;
 2458         struct ether_header     *eh;
 2459         int                     id, hostencrypt = 0;
 2460 
 2461         sc = ifp->if_softc;
 2462 
 2463         DPRINTF(WID_START, ("wi_start: ifp %p sc %p\n", ifp, sc));
 2464 
 2465         if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
 2466                 return;
 2467 
 2468         if (ifp->if_flags & IFF_OACTIVE)
 2469                 return;
 2470 
 2471 nextpkt:
 2472         IFQ_DEQUEUE(&ifp->if_snd, m0);
 2473         if (m0 == NULL)
 2474                 return;
 2475 
 2476         bzero((char *)&tx_frame, sizeof(tx_frame));
 2477         tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA | WI_STYPE_DATA);
 2478         id = sc->wi_tx_data_id;
 2479         eh = mtod(m0, struct ether_header *);
 2480 
 2481         if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
 2482                 if (!wihap_check_tx(&sc->wi_hostap_info, eh->ether_dhost,
 2483                     &tx_frame.wi_tx_rate) && !(ifp->if_flags & IFF_PROMISC)) {
 2484                         if (ifp->if_flags & IFF_DEBUG)
 2485                                 printf(WI_PRT_FMT
 2486                                     ": wi_start: dropping unassoc dst %s\n",
 2487                                     WI_PRT_ARG(sc),
 2488                                     ether_sprintf(eh->ether_dhost));
 2489                         m_freem(m0);
 2490                         goto nextpkt;
 2491                 }
 2492         }
 2493 
 2494         /*
 2495          * Use RFC1042 encoding for IP and ARP datagrams,
 2496          * 802.3 for anything else.
 2497          */
 2498         if (eh->ether_type == htons(ETHERTYPE_IP) ||
 2499             eh->ether_type == htons(ETHERTYPE_ARP) ||
 2500             eh->ether_type == htons(ETHERTYPE_REVARP) ||
 2501             eh->ether_type == htons(ETHERTYPE_IPV6)) {
 2502                 bcopy((char *)&eh->ether_dhost,
 2503                     (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN);
 2504                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
 2505                         tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT); /* XXX */
 2506                         tx_frame.wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
 2507                         bcopy((char *)&sc->sc_ic.ic_myaddr,
 2508                             (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
 2509                         bcopy((char *)&eh->ether_shost,
 2510                             (char *)&tx_frame.wi_addr3, ETHER_ADDR_LEN);
 2511                         if (sc->wi_use_wep)
 2512                                 hostencrypt = 1;
 2513                 } else if (sc->wi_ptype == WI_PORTTYPE_BSS && sc->wi_use_wep &&
 2514                     sc->wi_crypto_algorithm != WI_CRYPTO_FIRMWARE_WEP) {
 2515                         tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT); /* XXX */
 2516                         tx_frame.wi_frame_ctl |= htole16(WI_FCTL_TODS);
 2517                         bcopy((char *)&sc->sc_ic.ic_myaddr,
 2518                             (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
 2519                         bcopy((char *)&eh->ether_dhost,
 2520                             (char *)&tx_frame.wi_addr3, ETHER_ADDR_LEN);
 2521                         hostencrypt = 1;
 2522                 } else
 2523                         bcopy((char *)&eh->ether_shost,
 2524                             (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
 2525                 bcopy((char *)&eh->ether_dhost,
 2526                     (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN);
 2527                 bcopy((char *)&eh->ether_shost,
 2528                     (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN);
 2529 
 2530                 tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN;
 2531                 tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
 2532                 tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
 2533                 tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
 2534                 tx_frame.wi_type = eh->ether_type;
 2535 
 2536                 if (hostencrypt) {
 2537 
 2538                         /* Do host encryption. */
 2539                         tx_frame.wi_frame_ctl |= htole16(WI_FCTL_WEP);
 2540                         bcopy(&tx_frame.wi_dat[0], &sc->wi_txbuf[4], 8);
 2541 
 2542                         m_copydata(m0, sizeof(struct ether_header),
 2543                             m0->m_pkthdr.len - sizeof(struct ether_header),
 2544                             (caddr_t)&sc->wi_txbuf[12]);
 2545 
 2546                         wi_do_hostencrypt(sc, (caddr_t)&sc->wi_txbuf,
 2547                             tx_frame.wi_dat_len);
 2548 
 2549                         tx_frame.wi_dat_len += IEEE80211_WEP_IVLEN +
 2550                             IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
 2551 
 2552                         tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
 2553                         wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
 2554                             sizeof(struct wi_frame));
 2555                         wi_write_data(sc, id, WI_802_11_OFFSET_RAW,
 2556                             (caddr_t)&sc->wi_txbuf,
 2557                             (m0->m_pkthdr.len -
 2558                              sizeof(struct ether_header)) + 18);
 2559                 } else {
 2560                         m_copydata(m0, sizeof(struct ether_header),
 2561                             m0->m_pkthdr.len - sizeof(struct ether_header),
 2562                             (caddr_t)&sc->wi_txbuf);
 2563 
 2564                         tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
 2565                         wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
 2566                             sizeof(struct wi_frame));
 2567                         wi_write_data(sc, id, WI_802_11_OFFSET,
 2568                             (caddr_t)&sc->wi_txbuf,
 2569                             (m0->m_pkthdr.len -
 2570                              sizeof(struct ether_header)) + 2);
 2571                 }
 2572         } else {
 2573                 tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len);
 2574 
 2575                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
 2576 
 2577                         /* Do host encryption. (XXX - not implemented) */
 2578                         printf(WI_PRT_FMT
 2579                             ": host encrypt not implemented for 802.3\n",
 2580                             WI_PRT_ARG(sc));
 2581                 } else {
 2582                         m_copydata(m0, 0, m0->m_pkthdr.len,
 2583                             (caddr_t)&sc->wi_txbuf);
 2584 
 2585                         wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
 2586                             sizeof(struct wi_frame));
 2587                         wi_write_data(sc, id, WI_802_3_OFFSET,
 2588                             (caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2);
 2589                 }
 2590         }
 2591 
 2592 #if NBPFILTER > 0
 2593         /*
 2594          * If there's a BPF listener, bounce a copy of
 2595          * this frame to him.
 2596          */
 2597         if (ifp->if_bpf)
 2598                 bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
 2599 #endif
 2600 
 2601         m_freem(m0);
 2602 
 2603         ifp->if_flags |= IFF_OACTIVE;
 2604 
 2605         /*
 2606          * Set a timeout in case the chip goes out to lunch.
 2607          */
 2608         ifp->if_timer = 5;
 2609 
 2610         if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
 2611                 printf(WI_PRT_FMT ": wi_start: xmit failed\n", WI_PRT_ARG(sc));
 2612 
 2613         return;
 2614 }
 2615 
 2616 STATIC int
 2617 wi_mgmt_xmit(struct wi_softc *sc, caddr_t data, int len)
 2618 {
 2619         struct wi_frame         tx_frame;
 2620         int                     id;
 2621         struct wi_80211_hdr     *hdr;
 2622         caddr_t                 dptr;
 2623 
 2624         if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
 2625                 return(ENODEV);
 2626 
 2627         hdr = (struct wi_80211_hdr *)data;
 2628         dptr = data + sizeof(struct wi_80211_hdr);
 2629 
 2630         bzero((char *)&tx_frame, sizeof(tx_frame));
 2631         id = sc->wi_tx_mgmt_id;
 2632 
 2633         bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl,
 2634            sizeof(struct wi_80211_hdr));
 2635 
 2636         tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT);
 2637         tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr);
 2638         tx_frame.wi_len = htole16(tx_frame.wi_dat_len);
 2639 
 2640         tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
 2641         wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
 2642         wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
 2643             (len - sizeof(struct wi_80211_hdr)) + 2);
 2644 
 2645         if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
 2646                 printf(WI_PRT_FMT ": wi_mgmt_xmit: xmit failed\n",
 2647                     WI_PRT_ARG(sc));
 2648                 /*
 2649                  * Hostile stations or corrupt frames may crash the card
 2650                  * and cause the kernel to get stuck printing complaints.
 2651                  * Reset the card and hope the problem goes away.
 2652                  */
 2653                 wi_reset(sc);
 2654                 return(EIO);
 2655         }
 2656 
 2657         return(0);
 2658 }
 2659 
 2660 void
 2661 wi_stop(struct wi_softc *sc)
 2662 {
 2663         struct ifnet            *ifp;
 2664 
 2665         wihap_shutdown(sc);
 2666 
 2667         if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
 2668                 return;
 2669 
 2670         DPRINTF(WID_STOP, ("wi_stop: sc %p\n", sc));
 2671 
 2672         timeout_del(&sc->sc_timo);
 2673 
 2674         ifp = &sc->sc_ic.ic_if;
 2675 
 2676         wi_intr_enable(sc, 0);
 2677         wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
 2678 
 2679         ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
 2680         ifp->if_timer = 0;
 2681 
 2682         return;
 2683 }
 2684 
 2685 
 2686 void
 2687 wi_watchdog(struct ifnet *ifp)
 2688 {
 2689         struct wi_softc         *sc;
 2690 
 2691         sc = ifp->if_softc;
 2692 
 2693         printf(WI_PRT_FMT ": device timeout\n", WI_PRT_ARG(sc));
 2694 
 2695         wi_cor_reset(sc);
 2696         wi_init(sc);
 2697 
 2698         ifp->if_oerrors++;
 2699 
 2700         return;
 2701 }
 2702 
 2703 void
 2704 wi_detach(struct wi_softc *sc)
 2705 {
 2706         struct ifnet *ifp;
 2707         ifp = &sc->sc_ic.ic_if;
 2708 
 2709         if (ifp->if_flags & IFF_RUNNING)
 2710                 wi_stop(sc);
 2711         
 2712         if (sc->wi_flags & WI_FLAGS_ATTACHED) {
 2713                 sc->wi_flags &= ~WI_FLAGS_ATTACHED;
 2714                 if (sc->sc_sdhook != NULL)
 2715                         shutdownhook_disestablish(sc->sc_sdhook);
 2716         }
 2717 }
 2718 
 2719 STATIC void
 2720 wi_shutdown(void *arg)
 2721 {
 2722         struct wi_softc         *sc;
 2723 
 2724         sc = arg;
 2725         wi_stop(sc);
 2726 
 2727         return;
 2728 }
 2729 
 2730 STATIC void
 2731 wi_get_id(struct wi_softc *sc)
 2732 {
 2733         struct wi_ltv_ver               ver;
 2734         const struct wi_card_ident      *id;
 2735         u_int16_t                       pri_fw_ver[3];
 2736         const char                      *card_name;
 2737         u_int16_t                       card_id;
 2738 
 2739         /* get chip identity */
 2740         bzero(&ver, sizeof(ver));
 2741         ver.wi_type = WI_RID_CARD_ID;
 2742         ver.wi_len = 5;
 2743         wi_read_record(sc, (struct wi_ltv_gen *)&ver);
 2744         card_id = letoh16(ver.wi_ver[0]);
 2745         for (id = wi_card_ident; id->firm_type != WI_NOTYPE; id++) {
 2746                 if (card_id == id->card_id)
 2747                         break;
 2748         }
 2749         if (id->firm_type != WI_NOTYPE) {
 2750                 sc->sc_firmware_type = id->firm_type;
 2751                 card_name = id->card_name;
 2752         } else if (ver.wi_ver[0] & htole16(0x8000)) {
 2753                 sc->sc_firmware_type = WI_INTERSIL;
 2754                 card_name = "Unknown PRISM2 chip";
 2755         } else {
 2756                 sc->sc_firmware_type = WI_LUCENT;
 2757         }
 2758 
 2759         /* get primary firmware version (XXX - how to do Lucent?) */
 2760         if (sc->sc_firmware_type != WI_LUCENT) {
 2761                 bzero(&ver, sizeof(ver));
 2762                 ver.wi_type = WI_RID_PRI_IDENTITY;
 2763                 ver.wi_len = 5;
 2764                 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
 2765                 pri_fw_ver[0] = letoh16(ver.wi_ver[2]);
 2766                 pri_fw_ver[1] = letoh16(ver.wi_ver[3]);
 2767                 pri_fw_ver[2] = letoh16(ver.wi_ver[1]);
 2768         }
 2769 
 2770         /* get station firmware version */
 2771         bzero(&ver, sizeof(ver));
 2772         ver.wi_type = WI_RID_STA_IDENTITY;
 2773         ver.wi_len = 5;
 2774         wi_read_record(sc, (struct wi_ltv_gen *)&ver);
 2775         ver.wi_ver[1] = letoh16(ver.wi_ver[1]);
 2776         ver.wi_ver[2] = letoh16(ver.wi_ver[2]);
 2777         ver.wi_ver[3] = letoh16(ver.wi_ver[3]);
 2778         sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
 2779             ver.wi_ver[3] * 100 + ver.wi_ver[1];
 2780 
 2781         if (sc->sc_firmware_type == WI_INTERSIL &&
 2782             (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
 2783                 struct wi_ltv_str sver;
 2784                 char *p;
 2785 
 2786                 bzero(&sver, sizeof(sver));
 2787                 sver.wi_type = WI_RID_SYMBOL_IDENTITY;
 2788                 sver.wi_len = 7;
 2789                 /* value should be something like "V2.00-11" */
 2790                 if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
 2791                     *(p = (char *)sver.wi_str) >= 'A' &&
 2792                     p[2] == '.' && p[5] == '-' && p[8] == '\0') {
 2793                         sc->sc_firmware_type = WI_SYMBOL;
 2794                         sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
 2795                             (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
 2796                             (p[6] - '0') * 10 + (p[7] - '0');
 2797                 }
 2798         }
 2799 
 2800         if (sc->sc_firmware_type == WI_LUCENT) {
 2801                 printf("%s: Firmware %d.%02d variant %d, ", WI_PRT_ARG(sc),
 2802                     ver.wi_ver[2], ver.wi_ver[3], ver.wi_ver[1]);
 2803         } else {
 2804                 printf("%s: %s%s (0x%04x), Firmware %d.%d.%d (primary), %d.%d.%d (station), ",
 2805                     WI_PRT_ARG(sc),
 2806                     sc->sc_firmware_type == WI_SYMBOL ? "Symbol " : "",
 2807                     card_name, card_id, pri_fw_ver[0], pri_fw_ver[1],
 2808                     pri_fw_ver[2], sc->sc_sta_firmware_ver / 10000,
 2809                     (sc->sc_sta_firmware_ver % 10000) / 100,
 2810                     sc->sc_sta_firmware_ver % 100);
 2811         }
 2812 }
 2813 
 2814 STATIC int
 2815 wi_sync_media(struct wi_softc *sc, int ptype, int txrate)
 2816 {
 2817         int media = sc->sc_media.ifm_cur->ifm_media;
 2818         int options = IFM_OPTIONS(media);
 2819         int subtype;
 2820 
 2821         switch (txrate) {
 2822         case 1:
 2823                 subtype = IFM_IEEE80211_DS1;
 2824                 break;
 2825         case 2:
 2826                 subtype = IFM_IEEE80211_DS2;
 2827                 break;
 2828         case 3:
 2829                 subtype = IFM_AUTO;
 2830                 break;
 2831         case 5:
 2832                 subtype = IFM_IEEE80211_DS5;
 2833                 break;
 2834         case 11:
 2835                 subtype = IFM_IEEE80211_DS11;
 2836                 break;
 2837         default:
 2838                 subtype = IFM_MANUAL;           /* Unable to represent */
 2839                 break;
 2840         }
 2841 
 2842         options &= ~IFM_OMASK;
 2843         switch (ptype) {
 2844         case WI_PORTTYPE_BSS:
 2845                 /* default port type */
 2846                 break;
 2847         case WI_PORTTYPE_ADHOC:
 2848                 options |= IFM_IEEE80211_ADHOC;
 2849                 break;
 2850         case WI_PORTTYPE_HOSTAP:
 2851                 options |= IFM_IEEE80211_HOSTAP;
 2852                 break;
 2853         case WI_PORTTYPE_IBSS:
 2854                 if (sc->wi_create_ibss)
 2855                         options |= IFM_IEEE80211_IBSSMASTER;
 2856                 else
 2857                         options |= IFM_IEEE80211_IBSS;
 2858                 break;
 2859         default:
 2860                 subtype = IFM_MANUAL;           /* Unable to represent */
 2861                 break;
 2862         }
 2863         media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
 2864         IFM_INST(media));
 2865         if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
 2866                 return (EINVAL);
 2867         ifmedia_set(&sc->sc_media, media);
 2868         sc->wi_ptype = ptype;
 2869         sc->wi_tx_rate = txrate;
 2870         return (0);
 2871 }
 2872 
 2873 STATIC int
 2874 wi_media_change(struct ifnet *ifp)
 2875 {
 2876         struct wi_softc *sc = ifp->if_softc;
 2877         int otype = sc->wi_ptype;
 2878         int orate = sc->wi_tx_rate;
 2879         int ocreate_ibss = sc->wi_create_ibss;
 2880 
 2881         if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) &&
 2882             sc->sc_firmware_type != WI_INTERSIL)
 2883                 return (EINVAL);
 2884 
 2885         sc->wi_create_ibss = 0;
 2886 
 2887         switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
 2888         case 0:
 2889                 sc->wi_ptype = WI_PORTTYPE_BSS;
 2890                 break;
 2891         case IFM_IEEE80211_ADHOC:
 2892                 sc->wi_ptype = WI_PORTTYPE_ADHOC;
 2893                 break;
 2894         case IFM_IEEE80211_HOSTAP:
 2895                 sc->wi_ptype = WI_PORTTYPE_HOSTAP;
 2896                 break;
 2897         case IFM_IEEE80211_IBSSMASTER:
 2898         case IFM_IEEE80211_IBSSMASTER|IFM_IEEE80211_IBSS:
 2899                 if (!(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS))
 2900                         return (EINVAL);
 2901                 sc->wi_create_ibss = 1;
 2902                 /* FALLTHROUGH */
 2903         case IFM_IEEE80211_IBSS:
 2904                 sc->wi_ptype = WI_PORTTYPE_IBSS;
 2905                 break;
 2906         default:
 2907                 /* Invalid combination. */
 2908                 return (EINVAL);
 2909         }
 2910 
 2911         switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
 2912         case IFM_IEEE80211_DS1:
 2913                 sc->wi_tx_rate = 1;
 2914                 break;
 2915         case IFM_IEEE80211_DS2:
 2916                 sc->wi_tx_rate = 2;
 2917                 break;
 2918         case IFM_AUTO:
 2919                 sc->wi_tx_rate = 3;
 2920                 break;
 2921         case IFM_IEEE80211_DS5:
 2922                 sc->wi_tx_rate = 5;
 2923                 break;
 2924         case IFM_IEEE80211_DS11:
 2925                 sc->wi_tx_rate = 11;
 2926                 break;
 2927         }
 2928 
 2929         if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
 2930                 if (otype != sc->wi_ptype || orate != sc->wi_tx_rate ||
 2931                     ocreate_ibss != sc->wi_create_ibss)
 2932                         wi_init(sc);
 2933         }
 2934 
 2935         ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
 2936 
 2937         return (0);
 2938 }
 2939 
 2940 STATIC void
 2941 wi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
 2942 {
 2943         struct wi_softc *sc = ifp->if_softc;
 2944         struct wi_req wreq;
 2945 
 2946         if (!(sc->sc_ic.ic_if.if_flags & IFF_UP)) {
 2947                 imr->ifm_active = IFM_IEEE80211|IFM_NONE;
 2948                 imr->ifm_status = 0;
 2949                 return;
 2950         }
 2951 
 2952         if (sc->wi_tx_rate == 3) {
 2953                 imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
 2954 
 2955                 wreq.wi_type = WI_RID_CUR_TX_RATE;
 2956                 wreq.wi_len = WI_MAX_DATALEN;
 2957                 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
 2958                         switch (letoh16(wreq.wi_val[0])) {
 2959                         case 1:
 2960                                 imr->ifm_active |= IFM_IEEE80211_DS1;
 2961                                 break;
 2962                         case 2:
 2963                                 imr->ifm_active |= IFM_IEEE80211_DS2;
 2964                                 break;
 2965                         case 6:
 2966                                 imr->ifm_active |= IFM_IEEE80211_DS5;
 2967                                 break;
 2968                         case 11:
 2969                                 imr->ifm_active |= IFM_IEEE80211_DS11;
 2970                                 break;
 2971                         }
 2972                 }
 2973         } else {
 2974                 imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
 2975         }
 2976 
 2977         imr->ifm_status = IFM_AVALID;
 2978         switch (sc->wi_ptype) {
 2979         case WI_PORTTYPE_ADHOC:
 2980         case WI_PORTTYPE_IBSS:
 2981                 /*
 2982                  * XXX: It would be nice if we could give some actually
 2983                  * useful status like whether we joined another IBSS or
 2984                  * created one ourselves.
 2985                  */
 2986                 /* FALLTHROUGH */
 2987         case WI_PORTTYPE_HOSTAP:
 2988                 imr->ifm_status |= IFM_ACTIVE;
 2989                 break;
 2990         default:
 2991                 wreq.wi_type = WI_RID_COMMQUAL;
 2992                 wreq.wi_len = WI_MAX_DATALEN;
 2993                 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
 2994                     letoh16(wreq.wi_val[0]) != 0)
 2995                         imr->ifm_status |= IFM_ACTIVE;
 2996         }
 2997 }
 2998 
 2999 STATIC int
 3000 wi_set_nwkey(struct wi_softc *sc, struct ieee80211_nwkey *nwkey)
 3001 {
 3002         int i, len, error;
 3003         struct wi_req wreq;
 3004         struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
 3005 
 3006         if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
 3007                 return ENODEV;
 3008         if (nwkey->i_defkid <= 0 || nwkey->i_defkid > IEEE80211_WEP_NKID)
 3009                 return EINVAL;
 3010         memcpy(wk, &sc->wi_keys, sizeof(*wk));
 3011         for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 3012                 if (nwkey->i_key[i].i_keydat == NULL)
 3013                         continue;
 3014                 len = nwkey->i_key[i].i_keylen;
 3015                 if (len > sizeof(wk->wi_keys[i].wi_keydat))
 3016                         return EINVAL;
 3017                 error = copyin(nwkey->i_key[i].i_keydat,
 3018                     wk->wi_keys[i].wi_keydat, len);
 3019                 if (error)
 3020                         return error;
 3021                 wk->wi_keys[i].wi_keylen = htole16(len);
 3022         }
 3023 
 3024         wk->wi_len = (sizeof(*wk) / 2) + 1;
 3025         wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
 3026         if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
 3027                 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
 3028                 if (error)
 3029                         return error;
 3030         }
 3031         if ((error = wi_setdef(sc, &wreq)))
 3032                 return (error);
 3033 
 3034         wreq.wi_len = 2;
 3035         wreq.wi_type = WI_RID_TX_CRYPT_KEY;
 3036         wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
 3037         if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
 3038                 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
 3039                 if (error)
 3040                         return error;
 3041         }
 3042         if ((error = wi_setdef(sc, &wreq)))
 3043                 return (error);
 3044 
 3045         wreq.wi_type = WI_RID_ENCRYPTION;
 3046         wreq.wi_val[0] = htole16(nwkey->i_wepon);
 3047         if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
 3048                 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
 3049                 if (error)
 3050                         return error;
 3051         }
 3052         if ((error = wi_setdef(sc, &wreq)))
 3053                 return (error);
 3054 
 3055         if (sc->sc_ic.ic_if.if_flags & IFF_UP)
 3056                 wi_init(sc);
 3057         return 0;
 3058 }
 3059 
 3060 STATIC int
 3061 wi_get_nwkey(struct wi_softc *sc, struct ieee80211_nwkey *nwkey)
 3062 {
 3063         int i, len, error;
 3064         struct wi_ltv_keys *wk = &sc->wi_keys;
 3065 
 3066         if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
 3067                 return ENODEV;
 3068         nwkey->i_wepon = sc->wi_use_wep;
 3069         nwkey->i_defkid = sc->wi_tx_key + 1;
 3070 
 3071         /* do not show any keys to non-root user */
 3072         error = suser(curproc, 0);
 3073         for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 3074                 if (nwkey->i_key[i].i_keydat == NULL)
 3075                         continue;
 3076                 /* error holds results of suser() for the first time */
 3077                 if (error)
 3078                         return error;
 3079                 len = letoh16(wk->wi_keys[i].wi_keylen);
 3080                 if (nwkey->i_key[i].i_keylen < len)
 3081                         return ENOSPC;
 3082                 nwkey->i_key[i].i_keylen = len;
 3083                 error = copyout(wk->wi_keys[i].wi_keydat,
 3084                     nwkey->i_key[i].i_keydat, len);
 3085                 if (error)
 3086                         return error;
 3087         }
 3088         return 0;
 3089 }
 3090 
 3091 STATIC int
 3092 wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
 3093 {
 3094 
 3095         sc->wi_pm_enabled = power->i_enabled;
 3096         sc->wi_max_sleep = power->i_maxsleep;
 3097 
 3098         if (sc->sc_ic.ic_if.if_flags & IFF_UP)
 3099                 wi_init(sc);
 3100 
 3101         return (0);
 3102 }
 3103 
 3104 STATIC int
 3105 wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
 3106 {
 3107 
 3108         power->i_enabled = sc->wi_pm_enabled;
 3109         power->i_maxsleep = sc->wi_max_sleep;
 3110 
 3111         return (0);
 3112 }
 3113 
 3114 STATIC int
 3115 wi_set_txpower(struct wi_softc *sc, struct ieee80211_txpower *txpower)
 3116 {
 3117         u_int16_t       cmd;
 3118         u_int16_t       power;
 3119         int8_t          tmp;
 3120         int             error;
 3121         int             alc;
 3122 
 3123         if (txpower == NULL) {
 3124                 if (!(sc->wi_flags & WI_FLAGS_TXPOWER))
 3125                         return (EINVAL);
 3126                 alc = 0;                /* disable ALC */
 3127         } else {
 3128                 if (txpower->i_mode == IEEE80211_TXPOWER_MODE_AUTO) {
 3129                         alc = 1;        /* enable ALC */
 3130                         sc->wi_flags &= ~WI_FLAGS_TXPOWER;
 3131                 } else {
 3132                         alc = 0;        /* disable ALC */
 3133                         sc->wi_flags |= WI_FLAGS_TXPOWER;
 3134                         sc->wi_txpower = txpower->i_val;
 3135                 }
 3136         }       
 3137 
 3138         /* Set ALC */
 3139         cmd = WI_CMD_DEBUG | (WI_DEBUG_CONFBITS << 8);
 3140         if ((error = wi_cmd(sc, cmd, alc, 0x8, 0)) != 0)
 3141                 return (error);
 3142 
 3143         /* No need to set the TX power value if ALC is enabled */
 3144         if (alc)
 3145                 return (0);
 3146 
 3147         /* Convert dBM to internal TX power value */
 3148         if (sc->wi_txpower > 20)
 3149                 power = 128;
 3150         else if (sc->wi_txpower < -43)
 3151                 power = 127;
 3152         else {
 3153                 tmp = sc->wi_txpower;
 3154                 tmp = -12 - tmp;
 3155                 tmp <<= 2;
 3156 
 3157                 power = (u_int16_t)tmp;
 3158         }
 3159 
 3160         /* Set manual TX power */
 3161         cmd = WI_CMD_WRITE_MIF;
 3162         if ((error = wi_cmd(sc, cmd,
 3163                  WI_HFA384X_CR_MANUAL_TX_POWER, power, 0)) != 0)
 3164                 return (error);
 3165 
 3166         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
 3167                 printf("%s: %u (%d dBm)\n", sc->sc_dev.dv_xname, power,
 3168                     sc->wi_txpower);
 3169 
 3170         return (0);
 3171 }
 3172 
 3173 STATIC int
 3174 wi_get_txpower(struct wi_softc *sc, struct ieee80211_txpower *txpower)
 3175 {
 3176         u_int16_t       cmd;
 3177         u_int16_t       power;
 3178         int8_t          tmp;
 3179         int             error;
 3180 
 3181         if (sc->wi_flags & WI_FLAGS_BUS_USB)
 3182                 return (EOPNOTSUPP);
 3183 
 3184         /* Get manual TX power */
 3185         cmd = WI_CMD_READ_MIF;
 3186         if ((error = wi_cmd(sc, cmd,
 3187                  WI_HFA384X_CR_MANUAL_TX_POWER, 0, 0)) != 0)
 3188                 return (error);
 3189 
 3190         power = CSR_READ_2(sc, WI_RESP0);
 3191 
 3192         /* Convert internal TX power value to dBM */
 3193         if (power > 255)
 3194                 txpower->i_val = 255;
 3195         else {
 3196                 tmp = power;
 3197                 tmp >>= 2;
 3198                 txpower->i_val = (u_int16_t)(-12 - tmp);
 3199         }
 3200 
 3201         if (sc->wi_flags & WI_FLAGS_TXPOWER)
 3202                 txpower->i_mode = IEEE80211_TXPOWER_MODE_FIXED;
 3203         else
 3204                 txpower->i_mode = IEEE80211_TXPOWER_MODE_AUTO;
 3205         
 3206         return (0);
 3207 }
 3208 
 3209 STATIC int
 3210 wi_set_ssid(struct ieee80211_nwid *ws, u_int8_t *id, int len)
 3211 {
 3212 
 3213         if (len > IEEE80211_NWID_LEN)
 3214                 return (EINVAL);
 3215         ws->i_len = len;
 3216         memcpy(ws->i_nwid, id, len);
 3217         return (0);
 3218 }
 3219 
 3220 STATIC int
 3221 wi_get_debug(struct wi_softc *sc, struct wi_req *wreq)
 3222 {
 3223         int                     error = 0;
 3224 
 3225         wreq->wi_len = 1;
 3226 
 3227         switch (wreq->wi_type) {
 3228         case WI_DEBUG_SLEEP:
 3229                 wreq->wi_len++;
 3230                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_sleep);
 3231                 break;
 3232         case WI_DEBUG_DELAYSUPP:
 3233                 wreq->wi_len++;
 3234                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_delaysupp);
 3235                 break;
 3236         case WI_DEBUG_TXSUPP:
 3237                 wreq->wi_len++;
 3238                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_txsupp);
 3239                 break;
 3240         case WI_DEBUG_MONITOR:
 3241                 wreq->wi_len++;
 3242                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_monitor);
 3243                 break;
 3244         case WI_DEBUG_LEDTEST:
 3245                 wreq->wi_len += 3;
 3246                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_ledtest);
 3247                 wreq->wi_val[1] = htole16(sc->wi_debug.wi_ledtest_param0);
 3248                 wreq->wi_val[2] = htole16(sc->wi_debug.wi_ledtest_param1);
 3249                 break;
 3250         case WI_DEBUG_CONTTX:
 3251                 wreq->wi_len += 2;
 3252                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_conttx);
 3253                 wreq->wi_val[1] = htole16(sc->wi_debug.wi_conttx_param0);
 3254                 break;
 3255         case WI_DEBUG_CONTRX:
 3256                 wreq->wi_len++;
 3257                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_contrx);
 3258                 break;
 3259         case WI_DEBUG_SIGSTATE:
 3260                 wreq->wi_len += 2;
 3261                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_sigstate);
 3262                 wreq->wi_val[1] = htole16(sc->wi_debug.wi_sigstate_param0);
 3263                 break;
 3264         case WI_DEBUG_CONFBITS:
 3265                 wreq->wi_len += 2;
 3266                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_confbits);
 3267                 wreq->wi_val[1] = htole16(sc->wi_debug.wi_confbits_param0);
 3268                 break;
 3269         default:
 3270                 error = EIO;
 3271                 break;
 3272         }
 3273 
 3274         return (error);
 3275 }
 3276 
 3277 STATIC int
 3278 wi_set_debug(struct wi_softc *sc, struct wi_req *wreq)
 3279 {
 3280         int                             error = 0;
 3281         u_int16_t                       cmd, param0 = 0, param1 = 0;
 3282 
 3283         switch (wreq->wi_type) {
 3284         case WI_DEBUG_RESET:
 3285         case WI_DEBUG_INIT:
 3286         case WI_DEBUG_CALENABLE:
 3287                 break;
 3288         case WI_DEBUG_SLEEP:
 3289                 sc->wi_debug.wi_sleep = 1;
 3290                 break;
 3291         case WI_DEBUG_WAKE:
 3292                 sc->wi_debug.wi_sleep = 0;
 3293                 break;
 3294         case WI_DEBUG_CHAN:
 3295                 param0 = letoh16(wreq->wi_val[0]);
 3296                 break;
 3297         case WI_DEBUG_DELAYSUPP:
 3298                 sc->wi_debug.wi_delaysupp = 1;
 3299                 break;
 3300         case WI_DEBUG_TXSUPP:
 3301                 sc->wi_debug.wi_txsupp = 1;
 3302                 break;
 3303         case WI_DEBUG_MONITOR:
 3304                 sc->wi_debug.wi_monitor = 1;
 3305                 break;
 3306         case WI_DEBUG_LEDTEST:
 3307                 param0 = letoh16(wreq->wi_val[0]);
 3308                 param1 = letoh16(wreq->wi_val[1]);
 3309                 sc->wi_debug.wi_ledtest = 1;
 3310                 sc->wi_debug.wi_ledtest_param0 = param0;
 3311                 sc->wi_debug.wi_ledtest_param1 = param1;
 3312                 break;
 3313         case WI_DEBUG_CONTTX:
 3314                 param0 = letoh16(wreq->wi_val[0]);
 3315                 sc->wi_debug.wi_conttx = 1;
 3316                 sc->wi_debug.wi_conttx_param0 = param0;
 3317                 break;
 3318         case WI_DEBUG_STOPTEST:
 3319                 sc->wi_debug.wi_delaysupp = 0;
 3320                 sc->wi_debug.wi_txsupp = 0;
 3321                 sc->wi_debug.wi_monitor = 0;
 3322                 sc->wi_debug.wi_ledtest = 0;
 3323                 sc->wi_debug.wi_ledtest_param0 = 0;
 3324                 sc->wi_debug.wi_ledtest_param1 = 0;
 3325                 sc->wi_debug.wi_conttx = 0;
 3326                 sc->wi_debug.wi_conttx_param0 = 0;
 3327                 sc->wi_debug.wi_contrx = 0;
 3328                 sc->wi_debug.wi_sigstate = 0;
 3329                 sc->wi_debug.wi_sigstate_param0 = 0;
 3330                 break;
 3331         case WI_DEBUG_CONTRX:
 3332                 sc->wi_debug.wi_contrx = 1;
 3333                 break;
 3334         case WI_DEBUG_SIGSTATE:
 3335                 param0 = letoh16(wreq->wi_val[0]);
 3336                 sc->wi_debug.wi_sigstate = 1;
 3337                 sc->wi_debug.wi_sigstate_param0 = param0;
 3338                 break;
 3339         case WI_DEBUG_CONFBITS:
 3340                 param0 = letoh16(wreq->wi_val[0]);
 3341                 param1 = letoh16(wreq->wi_val[1]);
 3342                 sc->wi_debug.wi_confbits = param0;
 3343                 sc->wi_debug.wi_confbits_param0 = param1;
 3344                 break;
 3345         default:
 3346                 error = EIO;
 3347                 break;
 3348         }
 3349 
 3350         if (error)
 3351                 return (error);
 3352 
 3353         cmd = WI_CMD_DEBUG | (wreq->wi_type << 8);
 3354         error = wi_cmd(sc, cmd, param0, param1, 0);
 3355 
 3356         return (error);
 3357 }

/* [<][>][^][v][top][bottom][index][help] */