[BACK]Return to ieee80211_ioctl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / net80211

Annotation of src/sys/net80211/ieee80211_ioctl.c, Revision 1.49

1.49    ! mlelstv     1: /*     $NetBSD: ieee80211_ioctl.c,v 1.48 2008/02/07 01:22:02 dyoung Exp $      */
1.1       dyoung      2: /*-
                      3:  * Copyright (c) 2001 Atsushi Onoe
1.19      dyoung      4:  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
1.1       dyoung      5:  * 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. The name of the author may not be used to endorse or promote products
                     16:  *    derived from this software without specific prior written permission.
                     17:  *
                     18:  * Alternatively, this software may be distributed under the terms of the
                     19:  * GNU General Public License ("GPL") version 2 as published by the Free
                     20:  * Software Foundation.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     32:  */
                     33:
                     34: #include <sys/cdefs.h>
1.3       dyoung     35: #ifdef __FreeBSD__
1.26      skrll      36: __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.35 2005/08/30 14:27:47 avatar Exp $");
1.19      dyoung     37: #endif
                     38: #ifdef __NetBSD__
1.49    ! mlelstv    39: __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.48 2008/02/07 01:22:02 dyoung Exp $");
1.3       dyoung     40: #endif
1.1       dyoung     41:
                     42: /*
                     43:  * IEEE 802.11 ioctl support (FreeBSD-specific)
                     44:  */
                     45:
1.10      dyoung     46: #include "opt_inet.h"
1.46      christos   47: #include "opt_compat_netbsd.h"
1.10      dyoung     48:
1.1       dyoung     49: #include <sys/endian.h>
                     50: #include <sys/param.h>
                     51: #include <sys/kernel.h>
                     52: #include <sys/socket.h>
                     53: #include <sys/sockio.h>
                     54: #include <sys/systm.h>
1.4       dyoung     55: #include <sys/proc.h>
1.32      elad       56: #include <sys/kauth.h>
1.19      dyoung     57:
1.1       dyoung     58: #include <net/if.h>
                     59: #include <net/if_arp.h>
                     60: #include <net/if_media.h>
1.4       dyoung     61: #include <net/if_ether.h>
1.1       dyoung     62:
1.10      dyoung     63: #ifdef INET
                     64: #include <netinet/in.h>
                     65: #include <netinet/if_inarp.h>
                     66: #endif
                     67:
1.1       dyoung     68: #include <net80211/ieee80211_var.h>
                     69: #include <net80211/ieee80211_ioctl.h>
                     70:
1.4       dyoung     71: #include <dev/ic/wi_ieee.h>
1.19      dyoung     72:
1.46      christos   73: #if defined(COMPAT_09) || defined(COMPAT_10) || defined(COMPAT_11) || \
                     74:     defined(COMPAT_12) || defined(COMPAT_13) || defined(COMPAT_14) || \
                     75:     defined(COMPAT_15) || defined(COMPAT_16) || defined(COMPAT_20) || \
                     76:     defined(COMPAT_30) || defined(COMPAT_40)
                     77: #include <compat/sys/sockio.h>
                     78: #endif
                     79:
1.26      skrll      80: #ifdef __FreeBSD__
                     81: #define        IS_UP(_ic) \
                     82:        (((_ic)->ic_ifp->if_flags & IFF_UP) &&                  \
                     83:            ((_ic)->ic_ifp->if_drv_flags & IFF_DRV_RUNNING))
                     84: #endif
                     85: #ifdef __NetBSD__
1.19      dyoung     86: #define        IS_UP(_ic) \
1.26      skrll      87:        (((_ic)->ic_ifp->if_flags & IFF_UP) &&                  \
                     88:            ((_ic)->ic_ifp->if_flags & IFF_RUNNING))
                     89: #endif
1.19      dyoung     90: #define        IS_UP_AUTO(_ic) \
                     91:        (IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
1.1       dyoung     92:
                     93: /*
                     94:  * XXX
                     95:  * Wireless LAN specific configuration interface, which is compatible
                     96:  * with wicontrol(8).
                     97:  */
                     98:
1.19      dyoung     99: struct wi_read_ap_args {
                    100:        int     i;              /* result count */
                    101:        struct wi_apinfo *ap;   /* current entry in result buffer */
1.45      christos  102:        void *  max;            /* result buffer bound */
1.19      dyoung    103: };
                    104:
                    105: static void
                    106: wi_read_ap_result(void *arg, struct ieee80211_node *ni)
                    107: {
                    108:        struct ieee80211com *ic = ni->ni_ic;
                    109:        struct wi_read_ap_args *sa = arg;
                    110:        struct wi_apinfo *ap = sa->ap;
                    111:        struct ieee80211_rateset *rs;
                    112:        int j;
                    113:
1.45      christos  114:        if ((void *)(ap + 1) > sa->max)
1.19      dyoung    115:                return;
                    116:        memset(ap, 0, sizeof(struct wi_apinfo));
                    117:        if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
                    118:                IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
                    119:                ap->namelen = ic->ic_des_esslen;
                    120:                if (ic->ic_des_esslen)
                    121:                        memcpy(ap->name, ic->ic_des_essid,
                    122:                            ic->ic_des_esslen);
                    123:        } else {
                    124:                IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
                    125:                ap->namelen = ni->ni_esslen;
                    126:                if (ni->ni_esslen)
                    127:                        memcpy(ap->name, ni->ni_essid,
                    128:                            ni->ni_esslen);
                    129:        }
                    130:        ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
                    131:        ap->signal = ic->ic_node_getrssi(ni);
                    132:        ap->capinfo = ni->ni_capinfo;
                    133:        ap->interval = ni->ni_intval;
                    134:        rs = &ni->ni_rates;
                    135:        for (j = 0; j < rs->rs_nrates; j++) {
                    136:                if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
                    137:                        ap->rate = (rs->rs_rates[j] &
                    138:                            IEEE80211_RATE_VAL) * 5; /* XXX */
                    139:                }
                    140:        }
                    141:        sa->i++;
                    142:        sa->ap++;
                    143: }
                    144:
                    145: struct wi_read_prism2_args {
                    146:        int     i;              /* result count */
                    147:        struct wi_scan_res *res;/* current entry in result buffer */
1.45      christos  148:        void *  max;            /* result buffer bound */
1.19      dyoung    149: };
                    150:
                    151: #if 0
                    152: static void
                    153: wi_read_prism2_result(void *arg, struct ieee80211_node *ni)
                    154: {
                    155:        struct ieee80211com *ic = ni->ni_ic;
                    156:        struct wi_read_prism2_args *sa = arg;
                    157:        struct wi_scan_res *res = sa->res;
                    158:
1.45      christos  159:        if ((void *)(res + 1) > sa->max)
1.19      dyoung    160:                return;
                    161:        res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
                    162:        res->wi_noise = 0;
                    163:        res->wi_signal = ic->ic_node_getrssi(ni);
                    164:        IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
                    165:        res->wi_interval = ni->ni_intval;
                    166:        res->wi_capinfo = ni->ni_capinfo;
                    167:        res->wi_ssid_len = ni->ni_esslen;
                    168:        memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
                    169:        /* NB: assumes wi_srates holds <= ni->ni_rates */
                    170:        memcpy(res->wi_srates, ni->ni_rates.rs_rates,
                    171:                sizeof(res->wi_srates));
                    172:        if (ni->ni_rates.rs_nrates < 10)
                    173:                res->wi_srates[ni->ni_rates.rs_nrates] = 0;
                    174:        res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
                    175:        res->wi_rsvd = 0;
                    176:
                    177:        sa->i++;
                    178:        sa->res++;
                    179: }
                    180:
                    181: struct wi_read_sigcache_args {
                    182:        int     i;              /* result count */
                    183:        struct wi_sigcache *wsc;/* current entry in result buffer */
1.45      christos  184:        void *  max;            /* result buffer bound */
1.19      dyoung    185: };
                    186:
                    187: static void
                    188: wi_read_sigcache(void *arg, struct ieee80211_node *ni)
                    189: {
                    190:        struct ieee80211com *ic = ni->ni_ic;
                    191:        struct wi_read_sigcache_args *sa = arg;
                    192:        struct wi_sigcache *wsc = sa->wsc;
                    193:
1.45      christos  194:        if ((void *)(wsc + 1) > sa->max)
1.19      dyoung    195:                return;
                    196:        memset(wsc, 0, sizeof(struct wi_sigcache));
                    197:        IEEE80211_ADDR_COPY(wsc->macsrc, ni->ni_macaddr);
                    198:        wsc->signal = ic->ic_node_getrssi(ni);
                    199:
                    200:        sa->wsc++;
                    201:        sa->i++;
                    202: }
                    203: #endif
                    204:
1.1       dyoung    205: int
1.45      christos  206: ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, void *data)
1.1       dyoung    207: {
1.19      dyoung    208:        struct ifnet *ifp = ic->ic_ifp;
1.1       dyoung    209:        int i, j, error;
                    210:        struct ifreq *ifr = (struct ifreq *)data;
1.34      christos  211:        struct wi_req *wreq;
1.1       dyoung    212:        struct wi_ltv_keys *keys;
                    213:
1.34      christos  214:        wreq = malloc(sizeof(*wreq), M_TEMP, M_WAITOK);
                    215:        error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
1.1       dyoung    216:        if (error)
1.34      christos  217:                goto out;
                    218:        wreq->wi_len = 0;
                    219:        switch (wreq->wi_type) {
1.1       dyoung    220:        case WI_RID_SERIALNO:
1.8       onoe      221:        case WI_RID_STA_IDENTITY:
1.1       dyoung    222:                /* nothing appropriate */
                    223:                break;
                    224:        case WI_RID_NODENAME:
1.34      christos  225:                strlcpy((char *)&wreq->wi_val[1], hostname,
                    226:                    sizeof(wreq->wi_val) - sizeof(wreq->wi_val[0]));
                    227:                wreq->wi_val[0] = htole16(strlen(hostname));
                    228:                wreq->wi_len = (1 + strlen(hostname) + 1) / 2;
1.1       dyoung    229:                break;
                    230:        case WI_RID_CURRENT_SSID:
                    231:                if (ic->ic_state != IEEE80211_S_RUN) {
1.34      christos  232:                        wreq->wi_val[0] = 0;
                    233:                        wreq->wi_len = 1;
1.1       dyoung    234:                        break;
                    235:                }
1.34      christos  236:                wreq->wi_val[0] = htole16(ic->ic_bss->ni_esslen);
                    237:                memcpy(&wreq->wi_val[1], ic->ic_bss->ni_essid,
1.1       dyoung    238:                    ic->ic_bss->ni_esslen);
1.34      christos  239:                wreq->wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
1.1       dyoung    240:                break;
                    241:        case WI_RID_OWN_SSID:
                    242:        case WI_RID_DESIRED_SSID:
1.34      christos  243:                wreq->wi_val[0] = htole16(ic->ic_des_esslen);
                    244:                memcpy(&wreq->wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
                    245:                wreq->wi_len = (1 + ic->ic_des_esslen + 1) / 2;
1.1       dyoung    246:                break;
                    247:        case WI_RID_CURRENT_BSSID:
                    248:                if (ic->ic_state == IEEE80211_S_RUN)
1.34      christos  249:                        IEEE80211_ADDR_COPY(wreq->wi_val, ic->ic_bss->ni_bssid);
1.1       dyoung    250:                else
1.34      christos  251:                        memset(wreq->wi_val, 0, IEEE80211_ADDR_LEN);
                    252:                wreq->wi_len = IEEE80211_ADDR_LEN / 2;
1.1       dyoung    253:                break;
                    254:        case WI_RID_CHANNEL_LIST:
1.34      christos  255:                memset(wreq->wi_val, 0, sizeof(wreq->wi_val));
1.1       dyoung    256:                /*
                    257:                 * Since channel 0 is not available for DS, channel 1
                    258:                 * is assigned to LSB on WaveLAN.
                    259:                 */
                    260:                if (ic->ic_phytype == IEEE80211_T_DS)
                    261:                        i = 1;
                    262:                else
                    263:                        i = 0;
                    264:                for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
                    265:                        if (isset(ic->ic_chan_active, i)) {
1.34      christos  266:                                setbit((u_int8_t *)wreq->wi_val, j);
                    267:                                wreq->wi_len = j / 16 + 1;
1.1       dyoung    268:                        }
                    269:                break;
                    270:        case WI_RID_OWN_CHNL:
1.34      christos  271:                wreq->wi_val[0] = htole16(
1.1       dyoung    272:                        ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
1.34      christos  273:                wreq->wi_len = 1;
1.1       dyoung    274:                break;
                    275:        case WI_RID_CURRENT_CHAN:
1.34      christos  276:                wreq->wi_val[0] = htole16(
1.26      skrll     277:                        ieee80211_chan2ieee(ic, ic->ic_curchan));
1.34      christos  278:                wreq->wi_len = 1;
1.1       dyoung    279:                break;
                    280:        case WI_RID_COMMS_QUALITY:
1.34      christos  281:                wreq->wi_val[0] = 0;                            /* quality */
                    282:                wreq->wi_val[1] = htole16(ic->ic_node_getrssi(ic->ic_bss));
                    283:                wreq->wi_val[2] = 0;                            /* noise */
                    284:                wreq->wi_len = 3;
1.1       dyoung    285:                break;
                    286:        case WI_RID_PROMISC:
1.34      christos  287:                wreq->wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
                    288:                wreq->wi_len = 1;
1.1       dyoung    289:                break;
                    290:        case WI_RID_PORTTYPE:
1.34      christos  291:                wreq->wi_val[0] = htole16(ic->ic_opmode);
                    292:                wreq->wi_len = 1;
1.1       dyoung    293:                break;
                    294:        case WI_RID_MAC_NODE:
1.34      christos  295:                IEEE80211_ADDR_COPY(wreq->wi_val, ic->ic_myaddr);
                    296:                wreq->wi_len = IEEE80211_ADDR_LEN / 2;
1.1       dyoung    297:                break;
                    298:        case WI_RID_TX_RATE:
1.26      skrll     299:                if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
1.34      christos  300:                        wreq->wi_val[0] = 0;    /* auto */
1.1       dyoung    301:                else
1.34      christos  302:                        wreq->wi_val[0] = htole16(
1.1       dyoung    303:                            (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
                    304:                            IEEE80211_RATE_VAL) / 2);
1.34      christos  305:                wreq->wi_len = 1;
1.1       dyoung    306:                break;
                    307:        case WI_RID_CUR_TX_RATE:
1.34      christos  308:                wreq->wi_val[0] = htole16(
1.1       dyoung    309:                    (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
                    310:                    IEEE80211_RATE_VAL) / 2);
1.34      christos  311:                wreq->wi_len = 1;
1.1       dyoung    312:                break;
1.6       dyoung    313:        case WI_RID_FRAG_THRESH:
1.34      christos  314:                wreq->wi_val[0] = htole16(ic->ic_fragthreshold);
                    315:                wreq->wi_len = 1;
1.6       dyoung    316:                break;
1.1       dyoung    317:        case WI_RID_RTS_THRESH:
1.34      christos  318:                wreq->wi_val[0] = htole16(ic->ic_rtsthreshold);
                    319:                wreq->wi_len = 1;
1.1       dyoung    320:                break;
                    321:        case WI_RID_CREATE_IBSS:
1.34      christos  322:                wreq->wi_val[0] =
1.1       dyoung    323:                    htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
1.34      christos  324:                wreq->wi_len = 1;
1.1       dyoung    325:                break;
                    326:        case WI_RID_MICROWAVE_OVEN:
1.34      christos  327:                wreq->wi_val[0] = 0;    /* no ... not supported */
                    328:                wreq->wi_len = 1;
1.1       dyoung    329:                break;
                    330:        case WI_RID_ROAMING_MODE:
1.34      christos  331:                wreq->wi_val[0] = htole16(ic->ic_roaming);      /* XXX map */
                    332:                wreq->wi_len = 1;
1.1       dyoung    333:                break;
                    334:        case WI_RID_SYSTEM_SCALE:
1.34      christos  335:                wreq->wi_val[0] = htole16(1);   /* low density ... not supp */
                    336:                wreq->wi_len = 1;
1.1       dyoung    337:                break;
                    338:        case WI_RID_PM_ENABLED:
1.34      christos  339:                wreq->wi_val[0] =
1.1       dyoung    340:                    htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
1.34      christos  341:                wreq->wi_len = 1;
1.1       dyoung    342:                break;
                    343:        case WI_RID_MAX_SLEEP:
1.34      christos  344:                wreq->wi_val[0] = htole16(ic->ic_lintval);
                    345:                wreq->wi_len = 1;
1.1       dyoung    346:                break;
                    347:        case WI_RID_CUR_BEACON_INT:
1.34      christos  348:                wreq->wi_val[0] = htole16(ic->ic_bss->ni_intval);
                    349:                wreq->wi_len = 1;
1.1       dyoung    350:                break;
                    351:        case WI_RID_WEP_AVAIL:
1.34      christos  352:                wreq->wi_val[0] = htole16(1);   /* always available */
                    353:                wreq->wi_len = 1;
1.1       dyoung    354:                break;
                    355:        case WI_RID_CNFAUTHMODE:
1.34      christos  356:                wreq->wi_val[0] = htole16(1);   /* TODO: open system only */
                    357:                wreq->wi_len = 1;
1.1       dyoung    358:                break;
                    359:        case WI_RID_ENCRYPTION:
1.34      christos  360:                wreq->wi_val[0] =
1.16      mycroft   361:                    htole16((ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0);
1.34      christos  362:                wreq->wi_len = 1;
1.1       dyoung    363:                break;
                    364:        case WI_RID_TX_CRYPT_KEY:
1.34      christos  365:                wreq->wi_val[0] = htole16(ic->ic_def_txkey);
                    366:                wreq->wi_len = 1;
1.1       dyoung    367:                break;
                    368:        case WI_RID_DEFLT_CRYPT_KEYS:
1.37      drochner  369:                keys = (struct wi_ltv_keys *)wreq;
1.1       dyoung    370:                /* do not show keys to non-root user */
1.41      elad      371:                error = kauth_authorize_network(curlwp->l_cred,
                    372:                    KAUTH_NETWORK_INTERFACE,
                    373:                    KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp,
                    374:                    NULL, NULL);
1.1       dyoung    375:                if (error) {
                    376:                        memset(keys, 0, sizeof(*keys));
                    377:                        error = 0;
                    378:                        break;
                    379:                }
                    380:                for (i = 0; i < IEEE80211_WEP_NKID; i++) {
                    381:                        keys->wi_keys[i].wi_keylen =
1.19      dyoung    382:                            htole16(ic->ic_nw_keys[i].wk_keylen);
1.1       dyoung    383:                        memcpy(keys->wi_keys[i].wi_keydat,
1.19      dyoung    384:                            ic->ic_nw_keys[i].wk_key,
                    385:                            ic->ic_nw_keys[i].wk_keylen);
1.1       dyoung    386:                }
1.34      christos  387:                wreq->wi_len = sizeof(*keys) / 2;
1.1       dyoung    388:                break;
                    389:        case WI_RID_MAX_DATALEN:
1.34      christos  390:                wreq->wi_val[0] = htole16(ic->ic_fragthreshold);
                    391:                wreq->wi_len = 1;
1.1       dyoung    392:                break;
1.8       onoe      393:        case WI_RID_DBM_ADJUST:
                    394:                /* not supported, we just pass rssi value from driver. */
                    395:                break;
1.1       dyoung    396:        case WI_RID_IFACE_STATS:
                    397:                /* XXX: should be implemented in lower drivers */
                    398:                break;
                    399:        case WI_RID_READ_APS:
1.19      dyoung    400:                /*
                    401:                 * Don't return results until active scan completes.
                    402:                 */
                    403:                if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
                    404:                        struct wi_read_ap_args args;
                    405:
                    406:                        args.i = 0;
1.34      christos  407:                        args.ap = (void *)((char *)wreq->wi_val + sizeof(i));
1.37      drochner  408:                        args.max = (void *)(wreq + 1);
1.19      dyoung    409:                        ieee80211_iterate_nodes(&ic->ic_scan,
                    410:                                wi_read_ap_result, &args);
1.34      christos  411:                        memcpy(wreq->wi_val, &args.i, sizeof(args.i));
                    412:                        wreq->wi_len = (sizeof(int) +
1.19      dyoung    413:                                sizeof(struct wi_apinfo) * args.i) / 2;
                    414:                } else
                    415:                        error = EINPROGRESS;
1.1       dyoung    416:                break;
1.4       dyoung    417: #if 0
1.1       dyoung    418:        case WI_RID_SCAN_RES:                   /* compatibility interface */
1.19      dyoung    419:                if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
                    420:                        struct wi_read_prism2_args args;
                    421:                        struct wi_scan_p2_hdr *p2;
                    422:
                    423:                        /* NB: use Prism2 format so we can include rate info */
1.34      christos  424:                        p2 = (struct wi_scan_p2_hdr *)wreq->wi_val;
1.19      dyoung    425:                        args.i = 0;
                    426:                        args.res = (void *)&p2[1];
1.37      drochner  427:                        args.max = (void *)(wreq + 1);
1.19      dyoung    428:                        ieee80211_iterate_nodes(&ic->ic_scan,
                    429:                                wi_read_prism2_result, &args);
                    430:                        p2->wi_rsvd = 0;
                    431:                        p2->wi_reason = args.i;
1.34      christos  432:                        wreq->wi_len = (sizeof(*p2) +
1.19      dyoung    433:                                sizeof(struct wi_scan_res) * args.i) / 2;
                    434:                } else
1.1       dyoung    435:                        error = EINPROGRESS;
                    436:                break;
1.19      dyoung    437:        case WI_RID_READ_CACHE: {
                    438:                struct wi_read_sigcache_args args;
                    439:                args.i = 0;
1.34      christos  440:                args.wsc = (struct wi_sigcache *) wreq->wi_val;
1.37      drochner  441:                args.max = (void *)(wreq + 1);
1.19      dyoung    442:                ieee80211_iterate_nodes(&ic->ic_scan, wi_read_sigcache, &args);
1.34      christos  443:                wreq->wi_len = sizeof(struct wi_sigcache) * args.i / 2;
1.1       dyoung    444:                break;
1.19      dyoung    445:        }
                    446: #endif
1.1       dyoung    447:        default:
                    448:                error = EINVAL;
                    449:                break;
                    450:        }
                    451:        if (error == 0) {
1.34      christos  452:                wreq->wi_len++;
1.36      christos  453:                error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
1.1       dyoung    454:        }
1.34      christos  455: out:
                    456:        free(wreq, M_TEMP);
1.1       dyoung    457:        return error;
                    458: }
                    459:
                    460: static int
                    461: findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
                    462: {
                    463: #define        IEEERATE(_ic,_m,_i) \
                    464:        ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
                    465:        int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
                    466:        for (i = 0; i < nrates; i++)
                    467:                if (IEEERATE(ic, mode, i) == rate)
                    468:                        return i;
                    469:        return -1;
                    470: #undef IEEERATE
                    471: }
                    472:
1.7       dyoung    473: /*
                    474:  * Prepare to do a user-initiated scan for AP's.  If no
                    475:  * current/default channel is setup or the current channel
                    476:  * is invalid then pick the first available channel from
                    477:  * the active list as the place to start the scan.
                    478:  */
                    479: static int
1.19      dyoung    480: ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[])
1.7       dyoung    481: {
                    482:
1.19      dyoung    483:        /*
                    484:         * XXX don't permit a scan to be started unless we
                    485:         * know the device is ready.  For the moment this means
                    486:         * the device is marked up as this is the required to
                    487:         * initialize the hardware.  It would be better to permit
                    488:         * scanning prior to being up but that'll require some
                    489:         * changes to the infrastructure.
                    490:         */
                    491:        if (!IS_UP(ic))
                    492:                return EINVAL;
                    493:        memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
1.7       dyoung    494:        /*
1.19      dyoung    495:         * We force the state to INIT before calling ieee80211_new_state
                    496:         * to get ieee80211_begin_scan called.  We really want to scan w/o
                    497:         * altering the current state but that's not possible right now.
1.7       dyoung    498:         */
1.19      dyoung    499:        /* XXX handle proberequest case */
                    500:        ic->ic_state = IEEE80211_S_INIT;        /* XXX bypass state machine */
                    501:        return 0;
1.7       dyoung    502: }
                    503:
1.1       dyoung    504: int
1.45      christos  505: ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, void *data)
1.1       dyoung    506: {
1.19      dyoung    507:        struct ifnet *ifp = ic->ic_ifp;
1.1       dyoung    508:        int i, j, len, error, rate;
                    509:        struct ifreq *ifr = (struct ifreq *)data;
                    510:        struct wi_ltv_keys *keys;
1.34      christos  511:        struct wi_req *wreq;
1.33      christos  512:        u_int8_t chanlist[IEEE80211_CHAN_BYTES];
1.1       dyoung    513:
1.34      christos  514:        wreq = malloc(sizeof(*wreq), M_TEMP, M_WAITOK);
                    515:        error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
1.1       dyoung    516:        if (error)
1.34      christos  517:                goto out;
                    518:        len = wreq->wi_len ? (wreq->wi_len - 1) * 2 : 0;
                    519:        switch (wreq->wi_type) {
1.1       dyoung    520:        case WI_RID_SERIALNO:
                    521:        case WI_RID_NODENAME:
                    522:        case WI_RID_CURRENT_SSID:
1.34      christos  523:                error = EPERM;
                    524:                goto out;
1.1       dyoung    525:        case WI_RID_OWN_SSID:
                    526:        case WI_RID_DESIRED_SSID:
1.34      christos  527:                if (le16toh(wreq->wi_val[0]) * 2 > len ||
                    528:                    le16toh(wreq->wi_val[0]) > IEEE80211_NWID_LEN) {
1.1       dyoung    529:                        error = ENOSPC;
                    530:                        break;
                    531:                }
                    532:                memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
1.34      christos  533:                ic->ic_des_esslen = le16toh(wreq->wi_val[0]) * 2;
                    534:                memcpy(ic->ic_des_essid, &wreq->wi_val[1], ic->ic_des_esslen);
1.1       dyoung    535:                error = ENETRESET;
                    536:                break;
                    537:        case WI_RID_CURRENT_BSSID:
1.34      christos  538:                error = EPERM;
                    539:                goto out;
1.1       dyoung    540:        case WI_RID_OWN_CHNL:
                    541:                if (len != 2)
1.34      christos  542:                        goto invalid;
                    543:                i = le16toh(wreq->wi_val[0]);
1.1       dyoung    544:                if (i < 0 ||
                    545:                    i > IEEE80211_CHAN_MAX ||
                    546:                    isclr(ic->ic_chan_active, i))
1.34      christos  547:                        goto invalid;
1.1       dyoung    548:                ic->ic_ibss_chan = &ic->ic_channels[i];
1.19      dyoung    549:                if (ic->ic_opmode == IEEE80211_M_MONITOR)
                    550:                        error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
                    551:                else
1.1       dyoung    552:                        error = ENETRESET;
                    553:                break;
                    554:        case WI_RID_CURRENT_CHAN:
                    555:        case WI_RID_COMMS_QUALITY:
1.34      christos  556:                error = EPERM;
                    557:                goto out;
1.1       dyoung    558:        case WI_RID_PROMISC:
                    559:                if (len != 2)
1.34      christos  560:                        goto invalid;
1.1       dyoung    561:                if (ifp->if_flags & IFF_PROMISC) {
1.34      christos  562:                        if (wreq->wi_val[0] == 0) {
1.1       dyoung    563:                                ifp->if_flags &= ~IFF_PROMISC;
                    564:                                error = ENETRESET;
                    565:                        }
                    566:                } else {
1.34      christos  567:                        if (wreq->wi_val[0] != 0) {
1.1       dyoung    568:                                ifp->if_flags |= IFF_PROMISC;
                    569:                                error = ENETRESET;
                    570:                        }
                    571:                }
                    572:                break;
                    573:        case WI_RID_PORTTYPE:
                    574:                if (len != 2)
1.34      christos  575:                        goto invalid;
                    576:                switch (le16toh(wreq->wi_val[0])) {
1.1       dyoung    577:                case IEEE80211_M_STA:
                    578:                        break;
                    579:                case IEEE80211_M_IBSS:
                    580:                        if (!(ic->ic_caps & IEEE80211_C_IBSS))
1.34      christos  581:                                goto invalid;
1.1       dyoung    582:                        break;
                    583:                case IEEE80211_M_AHDEMO:
                    584:                        if (ic->ic_phytype != IEEE80211_T_DS ||
                    585:                            !(ic->ic_caps & IEEE80211_C_AHDEMO))
1.34      christos  586:                                goto invalid;
1.1       dyoung    587:                        break;
                    588:                case IEEE80211_M_HOSTAP:
                    589:                        if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
1.34      christos  590:                                goto invalid;
1.1       dyoung    591:                        break;
                    592:                default:
1.34      christos  593:                        goto invalid;
1.1       dyoung    594:                }
1.34      christos  595:                if (le16toh(wreq->wi_val[0]) != ic->ic_opmode) {
                    596:                        ic->ic_opmode = le16toh(wreq->wi_val[0]);
1.19      dyoung    597:                        error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
1.1       dyoung    598:                }
                    599:                break;
                    600: #if 0
                    601:        case WI_RID_MAC_NODE:
                    602:                if (len != IEEE80211_ADDR_LEN)
1.34      christos  603:                        goto invalid;
                    604:                IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq->wi_val);
1.1       dyoung    605:                /* if_init will copy lladdr into ic_myaddr */
                    606:                error = ENETRESET;
                    607:                break;
                    608: #endif
                    609:        case WI_RID_TX_RATE:
                    610:                if (len != 2)
1.34      christos  611:                        goto invalid;
                    612:                if (wreq->wi_val[0] == 0) {
1.1       dyoung    613:                        /* auto */
1.26      skrll     614:                        ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
1.1       dyoung    615:                        break;
                    616:                }
1.34      christos  617:                rate = 2 * le16toh(wreq->wi_val[0]);
1.1       dyoung    618:                if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
                    619:                        /*
                    620:                         * In autoselect mode search for the rate.  We take
                    621:                         * the first instance which may not be right, but we
                    622:                         * are limited by the interface.  Note that we also
                    623:                         * lock the mode to insure the rate is meaningful
                    624:                         * when it is used.
                    625:                         */
                    626:                        for (j = IEEE80211_MODE_11A;
                    627:                             j < IEEE80211_MODE_MAX; j++) {
                    628:                                if ((ic->ic_modecaps & (1<<j)) == 0)
                    629:                                        continue;
                    630:                                i = findrate(ic, j, rate);
                    631:                                if (i != -1) {
                    632:                                        /* lock mode too */
                    633:                                        ic->ic_curmode = j;
                    634:                                        goto setrate;
                    635:                                }
                    636:                        }
                    637:                } else {
                    638:                        i = findrate(ic, ic->ic_curmode, rate);
                    639:                        if (i != -1)
                    640:                                goto setrate;
                    641:                }
1.34      christos  642:                goto invalid;
1.1       dyoung    643:        setrate:
                    644:                ic->ic_fixed_rate = i;
1.19      dyoung    645:                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
1.1       dyoung    646:                break;
                    647:        case WI_RID_CUR_TX_RATE:
1.34      christos  648:                error = EPERM;
                    649:                goto out;
1.6       dyoung    650:        case WI_RID_FRAG_THRESH:
                    651:                if (len != 2)
1.34      christos  652:                        goto invalid;
                    653:                ic->ic_fragthreshold = le16toh(wreq->wi_val[0]);
1.6       dyoung    654:                error = ENETRESET;
                    655:                break;
1.1       dyoung    656:        case WI_RID_RTS_THRESH:
                    657:                if (len != 2)
1.34      christos  658:                        goto invalid;
                    659:                ic->ic_rtsthreshold = le16toh(wreq->wi_val[0]);
1.6       dyoung    660:                error = ENETRESET;
1.1       dyoung    661:                break;
                    662:        case WI_RID_CREATE_IBSS:
                    663:                if (len != 2)
1.34      christos  664:                        goto invalid;
                    665:                if (wreq->wi_val[0] != 0) {
1.1       dyoung    666:                        if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
1.34      christos  667:                                goto invalid;
1.1       dyoung    668:                        if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
                    669:                                ic->ic_flags |= IEEE80211_F_IBSSON;
                    670:                                if (ic->ic_opmode == IEEE80211_M_IBSS &&
                    671:                                    ic->ic_state == IEEE80211_S_SCAN)
1.19      dyoung    672:                                        error = IS_UP_AUTO(ic) ? ENETRESET : 0;
1.1       dyoung    673:                        }
                    674:                } else {
                    675:                        if (ic->ic_flags & IEEE80211_F_IBSSON) {
                    676:                                ic->ic_flags &= ~IEEE80211_F_IBSSON;
                    677:                                if (ic->ic_flags & IEEE80211_F_SIBSS) {
                    678:                                        ic->ic_flags &= ~IEEE80211_F_SIBSS;
1.19      dyoung    679:                                        error = IS_UP_AUTO(ic) ? ENETRESET : 0;
1.1       dyoung    680:                                }
                    681:                        }
                    682:                }
                    683:                break;
                    684:        case WI_RID_MICROWAVE_OVEN:
                    685:                if (len != 2)
1.34      christos  686:                        goto invalid;
                    687:                if (wreq->wi_val[0] != 0)
                    688:                        goto invalid;           /* not supported */
1.1       dyoung    689:                break;
                    690:        case WI_RID_ROAMING_MODE:
                    691:                if (len != 2)
1.34      christos  692:                        goto invalid;
                    693:                i = le16toh(wreq->wi_val[0]);
1.19      dyoung    694:                if (i > IEEE80211_ROAMING_MANUAL)
1.34      christos  695:                        goto invalid;           /* not supported */
1.19      dyoung    696:                ic->ic_roaming = i;
1.1       dyoung    697:                break;
                    698:        case WI_RID_SYSTEM_SCALE:
                    699:                if (len != 2)
1.34      christos  700:                        goto invalid;
                    701:                if (le16toh(wreq->wi_val[0]) != 1)
                    702:                        goto invalid;           /* not supported */
1.1       dyoung    703:                break;
                    704:        case WI_RID_PM_ENABLED:
                    705:                if (len != 2)
1.34      christos  706:                        goto invalid;
                    707:                if (wreq->wi_val[0] != 0) {
1.1       dyoung    708:                        if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
1.34      christos  709:                                goto invalid;
1.1       dyoung    710:                        if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
                    711:                                ic->ic_flags |= IEEE80211_F_PMGTON;
1.19      dyoung    712:                                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
1.1       dyoung    713:                        }
                    714:                } else {
                    715:                        if (ic->ic_flags & IEEE80211_F_PMGTON) {
                    716:                                ic->ic_flags &= ~IEEE80211_F_PMGTON;
1.19      dyoung    717:                                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
1.1       dyoung    718:                        }
                    719:                }
                    720:                break;
                    721:        case WI_RID_MAX_SLEEP:
                    722:                if (len != 2)
1.34      christos  723:                        goto invalid;
                    724:                ic->ic_lintval = le16toh(wreq->wi_val[0]);
1.1       dyoung    725:                if (ic->ic_flags & IEEE80211_F_PMGTON)
1.19      dyoung    726:                        error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
1.1       dyoung    727:                break;
                    728:        case WI_RID_CUR_BEACON_INT:
                    729:        case WI_RID_WEP_AVAIL:
1.34      christos  730:                error = EPERM;
                    731:                goto out;
1.1       dyoung    732:        case WI_RID_CNFAUTHMODE:
                    733:                if (len != 2)
1.34      christos  734:                        goto invalid;
                    735:                i = le16toh(wreq->wi_val[0]);
1.19      dyoung    736:                if (i > IEEE80211_AUTH_WPA)
1.34      christos  737:                        goto invalid;
1.19      dyoung    738:                ic->ic_bss->ni_authmode = i;            /* XXX ENETRESET? */
                    739:                error = ENETRESET;
1.1       dyoung    740:                break;
                    741:        case WI_RID_ENCRYPTION:
                    742:                if (len != 2)
1.34      christos  743:                        goto invalid;
                    744:                if (wreq->wi_val[0] != 0) {
1.1       dyoung    745:                        if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
1.34      christos  746:                                goto invalid;
1.16      mycroft   747:                        if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
                    748:                                ic->ic_flags |= IEEE80211_F_PRIVACY;
1.1       dyoung    749:                                error = ENETRESET;
                    750:                        }
                    751:                } else {
1.16      mycroft   752:                        if (ic->ic_flags & IEEE80211_F_PRIVACY) {
                    753:                                ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1.1       dyoung    754:                                error = ENETRESET;
                    755:                        }
                    756:                }
                    757:                break;
                    758:        case WI_RID_TX_CRYPT_KEY:
                    759:                if (len != 2)
1.34      christos  760:                        goto invalid;
                    761:                i = le16toh(wreq->wi_val[0]);
1.1       dyoung    762:                if (i >= IEEE80211_WEP_NKID)
1.34      christos  763:                        goto invalid;
1.19      dyoung    764:                ic->ic_def_txkey = i;
                    765:                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
1.1       dyoung    766:                break;
                    767:        case WI_RID_DEFLT_CRYPT_KEYS:
                    768:                if (len != sizeof(struct wi_ltv_keys))
1.34      christos  769:                        goto invalid;
1.37      drochner  770:                keys = (struct wi_ltv_keys *)wreq;
1.1       dyoung    771:                for (i = 0; i < IEEE80211_WEP_NKID; i++) {
                    772:                        len = le16toh(keys->wi_keys[i].wi_keylen);
                    773:                        if (len != 0 && len < IEEE80211_WEP_KEYLEN)
1.34      christos  774:                                goto invalid;
1.19      dyoung    775:                        if (len > IEEE80211_KEYBUF_SIZE)
1.34      christos  776:                                goto invalid;
1.1       dyoung    777:                }
                    778:                for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1.19      dyoung    779:                        struct ieee80211_key *k = &ic->ic_nw_keys[i];
                    780:
1.1       dyoung    781:                        len = le16toh(keys->wi_keys[i].wi_keylen);
1.19      dyoung    782:                        k->wk_keylen = len;
                    783:                        k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
                    784:                        memset(k->wk_key, 0, sizeof(k->wk_key));
                    785:                        memcpy(k->wk_key, keys->wi_keys[i].wi_keydat, len);
                    786: #if 0
                    787:                        k->wk_type = IEEE80211_CIPHER_WEP;
                    788: #endif
1.1       dyoung    789:                }
                    790:                error = ENETRESET;
                    791:                break;
                    792:        case WI_RID_MAX_DATALEN:
                    793:                if (len != 2)
1.34      christos  794:                        goto invalid;
                    795:                len = le16toh(wreq->wi_val[0]);
1.1       dyoung    796:                if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
1.34      christos  797:                        goto invalid;
1.1       dyoung    798:                ic->ic_fragthreshold = len;
1.19      dyoung    799:                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
1.1       dyoung    800:                break;
                    801:        case WI_RID_IFACE_STATS:
                    802:                error = EPERM;
                    803:                break;
                    804:        case WI_RID_SCAN_REQ:                   /* XXX wicontrol */
                    805:                if (ic->ic_opmode == IEEE80211_M_HOSTAP)
                    806:                        break;
1.19      dyoung    807:                error = ieee80211_setupscan(ic, ic->ic_chan_avail);
1.7       dyoung    808:                if (error == 0)
                    809:                        error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1.1       dyoung    810:                break;
                    811:        case WI_RID_SCAN_APS:
                    812:                if (ic->ic_opmode == IEEE80211_M_HOSTAP)
                    813:                        break;
                    814:                len--;                  /* XXX: tx rate? */
                    815:                /* FALLTHRU */
                    816:        case WI_RID_CHANNEL_LIST:
                    817:                memset(chanlist, 0, sizeof(chanlist));
                    818:                /*
                    819:                 * Since channel 0 is not available for DS, channel 1
                    820:                 * is assigned to LSB on WaveLAN.
                    821:                 */
                    822:                if (ic->ic_phytype == IEEE80211_T_DS)
                    823:                        i = 1;
                    824:                else
                    825:                        i = 0;
                    826:                for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
                    827:                        if ((j / 8) >= len)
                    828:                                break;
1.34      christos  829:                        if (isclr((u_int8_t *)wreq->wi_val, j))
1.1       dyoung    830:                                continue;
                    831:                        if (isclr(ic->ic_chan_active, i)) {
1.34      christos  832:                                if (wreq->wi_type != WI_RID_CHANNEL_LIST)
1.1       dyoung    833:                                        continue;
1.34      christos  834:                                if (isclr(ic->ic_chan_avail, i)) {
                    835:                                        error = EPERM;
                    836:                                        goto out;
                    837:                                }
1.1       dyoung    838:                        }
                    839:                        setbit(chanlist, i);
                    840:                }
1.19      dyoung    841:                error = ieee80211_setupscan(ic, chanlist);
1.34      christos  842:                if (wreq->wi_type == WI_RID_CHANNEL_LIST) {
1.7       dyoung    843:                        /* NB: ignore error from ieee80211_setupscan */
1.1       dyoung    844:                        error = ENETRESET;
1.7       dyoung    845:                } else if (error == 0)
1.1       dyoung    846:                        error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
                    847:                break;
                    848:        default:
1.34      christos  849:                goto invalid;
1.1       dyoung    850:        }
1.19      dyoung    851:        if (error == ENETRESET && !IS_UP_AUTO(ic))
                    852:                error = 0;
1.34      christos  853: out:
                    854:        free(wreq, M_TEMP);
1.19      dyoung    855:        return error;
1.34      christos  856: invalid:
                    857:        free(wreq, M_TEMP);
                    858:        return EINVAL;
1.19      dyoung    859: }
                    860:
                    861: static int
                    862: cap2cipher(int flag)
                    863: {
                    864:        switch (flag) {
                    865:        case IEEE80211_C_WEP:           return IEEE80211_CIPHER_WEP;
                    866:        case IEEE80211_C_AES:           return IEEE80211_CIPHER_AES_OCB;
                    867:        case IEEE80211_C_AES_CCM:       return IEEE80211_CIPHER_AES_CCM;
                    868:        case IEEE80211_C_CKIP:          return IEEE80211_CIPHER_CKIP;
                    869:        case IEEE80211_C_TKIP:          return IEEE80211_CIPHER_TKIP;
                    870:        }
                    871:        return -1;
                    872: }
                    873:
                    874: static int
                    875: ieee80211_ioctl_getkey(struct ieee80211com *ic, struct ieee80211req *ireq)
                    876: {
                    877:        struct ieee80211_node *ni;
                    878:        struct ieee80211req_key ik;
                    879:        struct ieee80211_key *wk;
                    880:        const struct ieee80211_cipher *cip;
                    881:        u_int kid;
                    882:        int error;
                    883:
                    884:        if (ireq->i_len != sizeof(ik))
                    885:                return EINVAL;
                    886:        error = copyin(ireq->i_data, &ik, sizeof(ik));
                    887:        if (error)
                    888:                return error;
                    889:        kid = ik.ik_keyix;
                    890:        if (kid == IEEE80211_KEYIX_NONE) {
                    891:                ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
                    892:                if (ni == NULL)
                    893:                        return EINVAL;          /* XXX */
                    894:                wk = &ni->ni_ucastkey;
                    895:        } else {
                    896:                if (kid >= IEEE80211_WEP_NKID)
                    897:                        return EINVAL;
                    898:                wk = &ic->ic_nw_keys[kid];
                    899:                IEEE80211_ADDR_COPY(&ik.ik_macaddr, ic->ic_bss->ni_macaddr);
                    900:                ni = NULL;
                    901:        }
                    902:        cip = wk->wk_cipher;
                    903:        ik.ik_type = cip->ic_cipher;
                    904:        ik.ik_keylen = wk->wk_keylen;
                    905:        ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
                    906:        if (wk->wk_keyix == ic->ic_def_txkey)
                    907:                ik.ik_flags |= IEEE80211_KEY_DEFAULT;
1.41      elad      908:        if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE,
                    909:            KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ic->ic_ifp, NULL, NULL) == 0) {
1.19      dyoung    910:                /* NB: only root can read key data */
                    911:                ik.ik_keyrsc = wk->wk_keyrsc;
                    912:                ik.ik_keytsc = wk->wk_keytsc;
                    913:                memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
                    914:                if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
                    915:                        memcpy(ik.ik_keydata+wk->wk_keylen,
                    916:                                wk->wk_key + IEEE80211_KEYBUF_SIZE,
                    917:                                IEEE80211_MICBUF_SIZE);
                    918:                        ik.ik_keylen += IEEE80211_MICBUF_SIZE;
                    919:                }
                    920:        } else {
                    921:                ik.ik_keyrsc = 0;
                    922:                ik.ik_keytsc = 0;
                    923:                memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
                    924:        }
                    925:        if (ni != NULL)
                    926:                ieee80211_free_node(ni);
                    927:        return copyout(&ik, ireq->i_data, sizeof(ik));
                    928: }
                    929:
                    930: static int
                    931: ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
                    932: {
1.27      christos  933:        size_t len = ireq->i_len;
1.19      dyoung    934:
1.27      christos  935:        if (sizeof(ic->ic_chan_active) < len) {
                    936:                len = sizeof(ic->ic_chan_active);
                    937:        }
                    938:        return copyout(&ic->ic_chan_active, ireq->i_data, len);
1.19      dyoung    939: }
                    940:
                    941: static int
                    942: ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq)
                    943: {
1.35      christos  944:        struct ieee80211req_chaninfo *chans;
                    945:        int i, space, error;
1.19      dyoung    946:
                    947:        /*
                    948:         * Since channel 0 is not available for DS, channel 1
                    949:         * is assigned to LSB on WaveLAN.
                    950:         */
                    951:        if (ic->ic_phytype == IEEE80211_T_DS)
                    952:                i = 1;
                    953:        else
                    954:                i = 0;
1.35      christos  955:
                    956:        chans = malloc(sizeof(*chans), M_TEMP, M_WAITOK|M_ZERO);
                    957:
1.19      dyoung    958:        for (; i <= IEEE80211_CHAN_MAX; i++)
                    959:                if (isset(ic->ic_chan_avail, i)) {
                    960:                        struct ieee80211_channel *c = &ic->ic_channels[i];
1.35      christos  961:                        chans->ic_chans[chans->ic_nchans].ic_freq = c->ic_freq;
                    962:                        chans->ic_chans[chans->ic_nchans].ic_flags = c->ic_flags;
                    963:                        chans->ic_nchans++;
1.19      dyoung    964:                }
                    965:        space = __offsetof(struct ieee80211req_chaninfo,
1.35      christos  966:            ic_chans[chans->ic_nchans]);
1.19      dyoung    967:        if (space > ireq->i_len)
                    968:                space = ireq->i_len;
1.35      christos  969:        error = copyout(chans, ireq->i_data, space);
                    970:        free(chans, M_TEMP);
                    971:        return error;
1.19      dyoung    972: }
                    973:
                    974: static int
                    975: ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq)
                    976: {
                    977:        struct ieee80211_node *ni;
                    978:        struct ieee80211req_wpaie wpaie;
                    979:        int error;
                    980:
                    981:        if (ireq->i_len < IEEE80211_ADDR_LEN)
                    982:                return EINVAL;
                    983:        error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
                    984:        if (error != 0)
                    985:                return error;
                    986:        ni = ieee80211_find_node(&ic->ic_sta, wpaie.wpa_macaddr);
                    987:        if (ni == NULL)
                    988:                return EINVAL;          /* XXX */
                    989:        memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
                    990:        if (ni->ni_wpa_ie != NULL) {
                    991:                int ielen = ni->ni_wpa_ie[1] + 2;
                    992:                if (ielen > sizeof(wpaie.wpa_ie))
                    993:                        ielen = sizeof(wpaie.wpa_ie);
                    994:                memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen);
                    995:        }
                    996:        ieee80211_free_node(ni);
                    997:        if (ireq->i_len > sizeof(wpaie))
                    998:                ireq->i_len = sizeof(wpaie);
                    999:        return copyout(&wpaie, ireq->i_data, ireq->i_len);
                   1000: }
                   1001:
                   1002: static int
                   1003: ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1004: {
                   1005:        struct ieee80211_node *ni;
                   1006:        u_int8_t macaddr[IEEE80211_ADDR_LEN];
                   1007:        const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
                   1008:        int error;
                   1009:
                   1010:        if (ireq->i_len < off)
                   1011:                return EINVAL;
                   1012:        error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
                   1013:        if (error != 0)
                   1014:                return error;
                   1015:        ni = ieee80211_find_node(&ic->ic_sta, macaddr);
                   1016:        if (ni == NULL)
                   1017:                return EINVAL;          /* XXX */
                   1018:        if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
                   1019:                ireq->i_len = sizeof(struct ieee80211req_sta_stats);
                   1020:        /* NB: copy out only the statistics */
                   1021:        error = copyout(&ni->ni_stats, (u_int8_t *) ireq->i_data + off,
                   1022:                        ireq->i_len - off);
                   1023:        ieee80211_free_node(ni);
                   1024:        return error;
                   1025: }
                   1026:
                   1027: static void
                   1028: get_scan_result(struct ieee80211req_scan_result *sr,
                   1029:        const struct ieee80211_node *ni)
                   1030: {
                   1031:        struct ieee80211com *ic = ni->ni_ic;
1.28      christos 1032:        u_int ielen = 0;
1.19      dyoung   1033:
                   1034:        memset(sr, 0, sizeof(*sr));
                   1035:        sr->isr_ssid_len = ni->ni_esslen;
                   1036:        if (ni->ni_wpa_ie != NULL)
1.28      christos 1037:                ielen += 2+ni->ni_wpa_ie[1];
1.19      dyoung   1038:        if (ni->ni_wme_ie != NULL)
1.28      christos 1039:                ielen += 2+ni->ni_wme_ie[1];
                   1040:
                   1041:        /*
                   1042:         * The value sr->isr_ie_len is defined as a uint8_t, so we
                   1043:         * need to be careful to avoid an integer overflow.  If the
                   1044:         * value would overflow, we will set isr_ie_len to zero, and
                   1045:         * ieee80211_ioctl_getscanresults (below) will avoid copying
                   1046:         * the (overflowing) data.
                   1047:         */
                   1048:        if (ielen > 255)
                   1049:                ielen = 0;
                   1050:        sr->isr_ie_len = ielen;
1.19      dyoung   1051:        sr->isr_len = sizeof(*sr) + sr->isr_ssid_len + sr->isr_ie_len;
                   1052:        sr->isr_len = roundup(sr->isr_len, sizeof(u_int32_t));
                   1053:        if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
                   1054:                sr->isr_freq = ni->ni_chan->ic_freq;
                   1055:                sr->isr_flags = ni->ni_chan->ic_flags;
                   1056:        }
                   1057:        sr->isr_rssi = ic->ic_node_getrssi(ni);
                   1058:        sr->isr_intval = ni->ni_intval;
                   1059:        sr->isr_capinfo = ni->ni_capinfo;
                   1060:        sr->isr_erp = ni->ni_erp;
                   1061:        IEEE80211_ADDR_COPY(sr->isr_bssid, ni->ni_bssid);
                   1062:        sr->isr_nrates = ni->ni_rates.rs_nrates;
                   1063:        if (sr->isr_nrates > 15)
                   1064:                sr->isr_nrates = 15;
                   1065:        memcpy(sr->isr_rates, ni->ni_rates.rs_rates, sr->isr_nrates);
                   1066: }
                   1067:
                   1068: static int
                   1069: ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1070: {
                   1071:        union {
                   1072:                struct ieee80211req_scan_result res;
1.27      christos 1073:                char data[sizeof(struct ieee80211req_scan_result) + IEEE80211_NWID_LEN + 256 * 2];
1.19      dyoung   1074:        } u;
                   1075:        struct ieee80211req_scan_result *sr = &u.res;
                   1076:        struct ieee80211_node_table *nt;
                   1077:        struct ieee80211_node *ni;
                   1078:        int error, space;
                   1079:        u_int8_t *p, *cp;
                   1080:
                   1081:        p = ireq->i_data;
                   1082:        space = ireq->i_len;
                   1083:        error = 0;
                   1084:        /* XXX locking */
                   1085:        nt =  &ic->ic_scan;
                   1086:        TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
                   1087:                /* NB: skip pre-scan node state */
                   1088:                if (ni->ni_chan == IEEE80211_CHAN_ANYC)
                   1089:                        continue;
                   1090:                get_scan_result(sr, ni);
                   1091:                if (sr->isr_len > sizeof(u))
                   1092:                        continue;               /* XXX */
                   1093:                if (space < sr->isr_len)
                   1094:                        break;
                   1095:                cp = (u_int8_t *)(sr+1);
                   1096:                memcpy(cp, ni->ni_essid, ni->ni_esslen);
                   1097:                cp += ni->ni_esslen;
1.28      christos 1098:                if (sr->isr_ie_len > 0 && ni->ni_wpa_ie != NULL) {
1.19      dyoung   1099:                        memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
                   1100:                        cp += 2+ni->ni_wpa_ie[1];
                   1101:                }
1.28      christos 1102:                if (sr->isr_ie_len > 0 && ni->ni_wme_ie != NULL) {
1.19      dyoung   1103:                        memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
                   1104:                        cp += 2+ni->ni_wme_ie[1];
                   1105:                }
                   1106:                error = copyout(sr, p, sr->isr_len);
                   1107:                if (error)
                   1108:                        break;
                   1109:                p += sr->isr_len;
                   1110:                space -= sr->isr_len;
                   1111:        }
                   1112:        ireq->i_len -= space;
                   1113:        return error;
                   1114: }
                   1115:
1.26      skrll    1116: struct stainforeq {
                   1117:        struct ieee80211com *ic;
                   1118:        struct ieee80211req_sta_info *si;
                   1119:        size_t  space;
                   1120: };
                   1121:
                   1122: static size_t
                   1123: sta_space(const struct ieee80211_node *ni, size_t *ielen)
                   1124: {
                   1125:        *ielen = 0;
                   1126:        if (ni->ni_wpa_ie != NULL)
                   1127:                *ielen += 2+ni->ni_wpa_ie[1];
                   1128:        if (ni->ni_wme_ie != NULL)
                   1129:                *ielen += 2+ni->ni_wme_ie[1];
                   1130:        return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
                   1131:                      sizeof(u_int32_t));
                   1132: }
                   1133:
1.19      dyoung   1134: static void
1.26      skrll    1135: get_sta_space(void *arg, struct ieee80211_node *ni)
1.19      dyoung   1136: {
1.26      skrll    1137:        struct stainforeq *req = arg;
1.19      dyoung   1138:        struct ieee80211com *ic = ni->ni_ic;
1.26      skrll    1139:        size_t ielen;
1.19      dyoung   1140:
1.26      skrll    1141:        if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
                   1142:            ni->ni_associd == 0)        /* only associated stations */
                   1143:                return;
                   1144:        req->space += sta_space(ni, &ielen);
                   1145: }
                   1146:
                   1147: static void
                   1148: get_sta_info(void *arg, struct ieee80211_node *ni)
                   1149: {
                   1150:        struct stainforeq *req = arg;
                   1151:        struct ieee80211com *ic = ni->ni_ic;
                   1152:        struct ieee80211req_sta_info *si;
                   1153:        size_t ielen, len;
                   1154:        u_int8_t *cp;
                   1155:
                   1156:        if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
                   1157:            ni->ni_associd == 0)        /* only associated stations */
                   1158:                return;
                   1159:        if (ni->ni_chan == IEEE80211_CHAN_ANYC) /* XXX bogus entry */
                   1160:                return;
                   1161:        len = sta_space(ni, &ielen);
                   1162:        if (len > req->space)
                   1163:                return;
                   1164:        si = req->si;
                   1165:        si->isi_len = len;
                   1166:        si->isi_ie_len = ielen;
1.19      dyoung   1167:        si->isi_freq = ni->ni_chan->ic_freq;
                   1168:        si->isi_flags = ni->ni_chan->ic_flags;
                   1169:        si->isi_state = ni->ni_flags;
                   1170:        si->isi_authmode = ni->ni_authmode;
                   1171:        si->isi_rssi = ic->ic_node_getrssi(ni);
                   1172:        si->isi_capinfo = ni->ni_capinfo;
                   1173:        si->isi_erp = ni->ni_erp;
                   1174:        IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
                   1175:        si->isi_nrates = ni->ni_rates.rs_nrates;
                   1176:        if (si->isi_nrates > 15)
                   1177:                si->isi_nrates = 15;
                   1178:        memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
                   1179:        si->isi_txrate = ni->ni_txrate;
                   1180:        si->isi_associd = ni->ni_associd;
                   1181:        si->isi_txpower = ni->ni_txpower;
                   1182:        si->isi_vlan = ni->ni_vlan;
                   1183:        if (ni->ni_flags & IEEE80211_NODE_QOS) {
                   1184:                memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
                   1185:                memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
                   1186:        } else {
                   1187:                si->isi_txseqs[0] = ni->ni_txseqs[0];
                   1188:                si->isi_rxseqs[0] = ni->ni_rxseqs[0];
                   1189:        }
1.26      skrll    1190:        /* NB: leave all cases in case we relax ni_associd == 0 check */
                   1191:        if (ieee80211_node_is_authorized(ni))
1.19      dyoung   1192:                si->isi_inact = ic->ic_inact_run;
1.26      skrll    1193:        else if (ni->ni_associd != 0)
1.19      dyoung   1194:                si->isi_inact = ic->ic_inact_auth;
                   1195:        else
                   1196:                si->isi_inact = ic->ic_inact_init;
                   1197:        si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
1.26      skrll    1198:
                   1199:        cp = (u_int8_t *)(si+1);
                   1200:        if (ni->ni_wpa_ie != NULL) {
                   1201:                memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
                   1202:                cp += 2+ni->ni_wpa_ie[1];
                   1203:        }
                   1204:        if (ni->ni_wme_ie != NULL) {
                   1205:                memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
                   1206:                cp += 2+ni->ni_wme_ie[1];
                   1207:        }
                   1208:
                   1209:        req->si = (struct ieee80211req_sta_info *)(((u_int8_t *)si) + len);
                   1210:        req->space -= len;
1.19      dyoung   1211: }
                   1212:
                   1213: static int
                   1214: ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1215: {
1.26      skrll    1216:        struct stainforeq req;
                   1217:        int error;
                   1218:
                   1219:        if (ireq->i_len < sizeof(struct stainforeq))
                   1220:                return EFAULT;
1.19      dyoung   1221:
                   1222:        error = 0;
1.26      skrll    1223:        req.space = 0;
                   1224:        ieee80211_iterate_nodes(&ic->ic_sta, get_sta_space, &req);
                   1225:        if (req.space > ireq->i_len)
                   1226:                req.space = ireq->i_len;
                   1227:        if (req.space > 0) {
                   1228:                size_t space;
                   1229:                void *p;
                   1230:
                   1231:                space = req.space;
                   1232:                /* XXX M_WAITOK after driver lock released */
1.31      christos 1233:                p = malloc(space, M_TEMP, M_NOWAIT);
1.26      skrll    1234:                if (p == NULL)
                   1235:                        return ENOMEM;
                   1236:                req.si = p;
                   1237:                ieee80211_iterate_nodes(&ic->ic_sta, get_sta_info, &req);
                   1238:                ireq->i_len = space - req.space;
                   1239:                error = copyout(p, ireq->i_data, ireq->i_len);
                   1240:                FREE(p, M_TEMP);
                   1241:        } else
                   1242:                ireq->i_len = 0;
                   1243:
1.19      dyoung   1244:        return error;
                   1245: }
                   1246:
                   1247: static int
                   1248: ieee80211_ioctl_getstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1249: {
                   1250:        struct ieee80211_node *ni;
                   1251:        struct ieee80211req_sta_txpow txpow;
                   1252:        int error;
                   1253:
                   1254:        if (ireq->i_len != sizeof(txpow))
                   1255:                return EINVAL;
                   1256:        error = copyin(ireq->i_data, &txpow, sizeof(txpow));
                   1257:        if (error != 0)
                   1258:                return error;
                   1259:        ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
                   1260:        if (ni == NULL)
                   1261:                return EINVAL;          /* XXX */
                   1262:        txpow.it_txpow = ni->ni_txpower;
                   1263:        error = copyout(&txpow, ireq->i_data, sizeof(txpow));
                   1264:        ieee80211_free_node(ni);
1.1       dyoung   1265:        return error;
                   1266: }
                   1267:
1.19      dyoung   1268: static int
                   1269: ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1270: {
                   1271:        struct ieee80211_wme_state *wme = &ic->ic_wme;
                   1272:        struct wmeParams *wmep;
                   1273:        int ac;
                   1274:
                   1275:        if ((ic->ic_caps & IEEE80211_C_WME) == 0)
                   1276:                return EINVAL;
                   1277:
                   1278:        ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
                   1279:        if (ac >= WME_NUM_AC)
                   1280:                ac = WME_AC_BE;
                   1281:        if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
                   1282:                wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
                   1283:        else
                   1284:                wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
                   1285:        switch (ireq->i_type) {
                   1286:        case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
                   1287:                ireq->i_val = wmep->wmep_logcwmin;
                   1288:                break;
                   1289:        case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
                   1290:                ireq->i_val = wmep->wmep_logcwmax;
                   1291:                break;
                   1292:        case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
                   1293:                ireq->i_val = wmep->wmep_aifsn;
                   1294:                break;
                   1295:        case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
                   1296:                ireq->i_val = wmep->wmep_txopLimit;
                   1297:                break;
                   1298:        case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
                   1299:                wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
                   1300:                ireq->i_val = wmep->wmep_acm;
                   1301:                break;
                   1302:        case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (!bss only)*/
                   1303:                wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
                   1304:                ireq->i_val = !wmep->wmep_noackPolicy;
                   1305:                break;
                   1306:        }
                   1307:        return 0;
                   1308: }
                   1309:
1.26      skrll    1310: static int
                   1311: ieee80211_ioctl_getmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1312: {
                   1313:        const struct ieee80211_aclator *acl = ic->ic_acl;
                   1314:
                   1315:        return (acl == NULL ? EINVAL : acl->iac_getioctl(ic, ireq));
                   1316: }
                   1317:
1.44      dyoung   1318: #if defined(COMPAT_FREEBSD_NET80211)
1.19      dyoung   1319: static int
1.44      dyoung   1320: ieee80211_ioctl_get80211_fbsd(struct ieee80211com *ic, u_long cmd,
1.40      christos 1321:     struct ieee80211req *ireq)
1.1       dyoung   1322: {
1.23      dyoung   1323:        u_int kid, len;
1.1       dyoung   1324:        u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
                   1325:        char tmpssid[IEEE80211_NWID_LEN];
1.47      degroote 1326:        struct ifnet *ifp = ic->ic_ifp;
1.44      dyoung   1327:
                   1328:        int error = 0;
1.1       dyoung   1329:
1.19      dyoung   1330:        switch (ireq->i_type) {
                   1331:        case IEEE80211_IOC_SSID:
                   1332:                switch (ic->ic_state) {
                   1333:                case IEEE80211_S_INIT:
                   1334:                case IEEE80211_S_SCAN:
                   1335:                        ireq->i_len = ic->ic_des_esslen;
                   1336:                        memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
1.1       dyoung   1337:                        break;
1.19      dyoung   1338:                default:
                   1339:                        ireq->i_len = ic->ic_bss->ni_esslen;
                   1340:                        memcpy(tmpssid, ic->ic_bss->ni_essid,
                   1341:                                ireq->i_len);
1.1       dyoung   1342:                        break;
1.19      dyoung   1343:                }
                   1344:                error = copyout(tmpssid, ireq->i_data, ireq->i_len);
                   1345:                break;
                   1346:        case IEEE80211_IOC_NUMSSIDS:
                   1347:                ireq->i_val = 1;
                   1348:                break;
                   1349:        case IEEE80211_IOC_WEP:
                   1350:                if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0)
                   1351:                        ireq->i_val = IEEE80211_WEP_OFF;
                   1352:                else if (ic->ic_flags & IEEE80211_F_DROPUNENC)
                   1353:                        ireq->i_val = IEEE80211_WEP_ON;
                   1354:                else
                   1355:                        ireq->i_val = IEEE80211_WEP_MIXED;
                   1356:                break;
                   1357:        case IEEE80211_IOC_WEPKEY:
                   1358:                kid = (u_int) ireq->i_val;
                   1359:                if (kid >= IEEE80211_WEP_NKID)
                   1360:                        return EINVAL;
                   1361:                len = (u_int) ic->ic_nw_keys[kid].wk_keylen;
                   1362:                /* NB: only root can read WEP keys */
1.41      elad     1363:                if (kauth_authorize_network(curlwp->l_cred,
                   1364:                    KAUTH_NETWORK_INTERFACE,
1.42      elad     1365:                    KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp, NULL,
1.41      elad     1366:                    NULL) == 0) {
1.19      dyoung   1367:                        bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
                   1368:                } else {
                   1369:                        bzero(tmpkey, len);
                   1370:                }
                   1371:                ireq->i_len = len;
                   1372:                error = copyout(tmpkey, ireq->i_data, len);
                   1373:                break;
                   1374:        case IEEE80211_IOC_NUMWEPKEYS:
                   1375:                ireq->i_val = IEEE80211_WEP_NKID;
                   1376:                break;
                   1377:        case IEEE80211_IOC_WEPTXKEY:
                   1378:                ireq->i_val = ic->ic_def_txkey;
                   1379:                break;
                   1380:        case IEEE80211_IOC_CHANNEL:
1.26      skrll    1381:                ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan);
1.19      dyoung   1382:                break;
                   1383:        case IEEE80211_IOC_POWERSAVE:
                   1384:                if (ic->ic_flags & IEEE80211_F_PMGTON)
                   1385:                        ireq->i_val = IEEE80211_POWERSAVE_ON;
                   1386:                else
                   1387:                        ireq->i_val = IEEE80211_POWERSAVE_OFF;
                   1388:                break;
                   1389:        case IEEE80211_IOC_POWERSAVESLEEP:
                   1390:                ireq->i_val = ic->ic_lintval;
                   1391:                break;
1.44      dyoung   1392:        case IEEE80211_IOC_BSSID:
                   1393:                if (ireq->i_len != IEEE80211_ADDR_LEN)
                   1394:                        return EINVAL;
                   1395:                error = copyout(ic->ic_state == IEEE80211_S_RUN ?
                   1396:                                        ic->ic_bss->ni_bssid :
                   1397:                                        ic->ic_des_bssid,
                   1398:                                ireq->i_data, ireq->i_len);
                   1399:                break;
                   1400:        default:
                   1401:                error = EINVAL;
                   1402:                break;
                   1403:        }
                   1404:        return error;
                   1405: }
                   1406: #endif /* COMPAT_FREEBSD_NET80211 */
                   1407:
                   1408: /*
                   1409:  * When building the kernel with -O2 on the i386 architecture, gcc
                   1410:  * seems to want to inline this function into ieee80211_ioctl()
                   1411:  * (which is the only routine that calls it). When this happens,
                   1412:  * ieee80211_ioctl() ends up consuming an additional 2K of stack
                   1413:  * space. (Exactly why it needs so much is unclear.) The problem
                   1414:  * is that it's possible for ieee80211_ioctl() to invoke other
                   1415:  * routines (including driver init functions) which could then find
                   1416:  * themselves perilously close to exhausting the stack.
                   1417:  *
                   1418:  * To avoid this, we deliberately prevent gcc from inlining this
                   1419:  * routine. Another way to avoid this is to use less agressive
                   1420:  * optimization when compiling this file (i.e. -O instead of -O2)
                   1421:  * but special-casing the compilation of this one module in the
                   1422:  * build system would be awkward.
                   1423:  */
                   1424: #ifdef __GNUC__
                   1425: __attribute__ ((__noinline__))
                   1426: #endif
                   1427: static int
                   1428: ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd,
                   1429:     struct ieee80211req *ireq)
                   1430: {
                   1431:        const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
                   1432:        int error = 0;
                   1433:        u_int m;
                   1434:
                   1435:        switch (ireq->i_type) {
                   1436:        case IEEE80211_IOC_AUTHMODE:
                   1437:                if (ic->ic_flags & IEEE80211_F_WPA)
                   1438:                        ireq->i_val = IEEE80211_AUTH_WPA;
                   1439:                else
                   1440:                        ireq->i_val = ic->ic_bss->ni_authmode;
                   1441:                break;
1.19      dyoung   1442:        case IEEE80211_IOC_RTSTHRESHOLD:
                   1443:                ireq->i_val = ic->ic_rtsthreshold;
                   1444:                break;
                   1445:        case IEEE80211_IOC_PROTMODE:
                   1446:                ireq->i_val = ic->ic_protmode;
                   1447:                break;
                   1448:        case IEEE80211_IOC_TXPOWER:
                   1449:                if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
                   1450:                        return EINVAL;
                   1451:                ireq->i_val = ic->ic_txpowlimit;
                   1452:                break;
                   1453:        case IEEE80211_IOC_MCASTCIPHER:
                   1454:                ireq->i_val = rsn->rsn_mcastcipher;
                   1455:                break;
                   1456:        case IEEE80211_IOC_MCASTKEYLEN:
                   1457:                ireq->i_val = rsn->rsn_mcastkeylen;
                   1458:                break;
                   1459:        case IEEE80211_IOC_UCASTCIPHERS:
                   1460:                ireq->i_val = 0;
                   1461:                for (m = 0x1; m != 0; m <<= 1)
                   1462:                        if (rsn->rsn_ucastcipherset & m)
                   1463:                                ireq->i_val |= 1<<cap2cipher(m);
                   1464:                break;
                   1465:        case IEEE80211_IOC_UCASTCIPHER:
                   1466:                ireq->i_val = rsn->rsn_ucastcipher;
                   1467:                break;
                   1468:        case IEEE80211_IOC_UCASTKEYLEN:
                   1469:                ireq->i_val = rsn->rsn_ucastkeylen;
                   1470:                break;
                   1471:        case IEEE80211_IOC_KEYMGTALGS:
                   1472:                ireq->i_val = rsn->rsn_keymgmtset;
                   1473:                break;
                   1474:        case IEEE80211_IOC_RSNCAPS:
                   1475:                ireq->i_val = rsn->rsn_caps;
                   1476:                break;
                   1477:        case IEEE80211_IOC_WPA:
                   1478:                switch (ic->ic_flags & IEEE80211_F_WPA) {
                   1479:                case IEEE80211_F_WPA1:
                   1480:                        ireq->i_val = 1;
                   1481:                        break;
                   1482:                case IEEE80211_F_WPA2:
                   1483:                        ireq->i_val = 2;
                   1484:                        break;
                   1485:                case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
                   1486:                        ireq->i_val = 3;
                   1487:                        break;
                   1488:                default:
                   1489:                        ireq->i_val = 0;
                   1490:                        break;
                   1491:                }
                   1492:                break;
                   1493:        case IEEE80211_IOC_CHANLIST:
                   1494:                error = ieee80211_ioctl_getchanlist(ic, ireq);
                   1495:                break;
                   1496:        case IEEE80211_IOC_ROAMING:
                   1497:                ireq->i_val = ic->ic_roaming;
                   1498:                break;
                   1499:        case IEEE80211_IOC_PRIVACY:
                   1500:                ireq->i_val = (ic->ic_flags & IEEE80211_F_PRIVACY) != 0;
                   1501:                break;
                   1502:        case IEEE80211_IOC_DROPUNENCRYPTED:
                   1503:                ireq->i_val = (ic->ic_flags & IEEE80211_F_DROPUNENC) != 0;
                   1504:                break;
                   1505:        case IEEE80211_IOC_COUNTERMEASURES:
                   1506:                ireq->i_val = (ic->ic_flags & IEEE80211_F_COUNTERM) != 0;
                   1507:                break;
                   1508:        case IEEE80211_IOC_DRIVER_CAPS:
                   1509:                ireq->i_val = ic->ic_caps>>16;
                   1510:                ireq->i_len = ic->ic_caps&0xffff;
                   1511:                break;
                   1512:        case IEEE80211_IOC_WME:
                   1513:                ireq->i_val = (ic->ic_flags & IEEE80211_F_WME) != 0;
                   1514:                break;
                   1515:        case IEEE80211_IOC_HIDESSID:
                   1516:                ireq->i_val = (ic->ic_flags & IEEE80211_F_HIDESSID) != 0;
                   1517:                break;
                   1518:        case IEEE80211_IOC_APBRIDGE:
                   1519:                ireq->i_val = (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0;
                   1520:                break;
                   1521:        case IEEE80211_IOC_OPTIE:
                   1522:                if (ic->ic_opt_ie == NULL)
                   1523:                        return EINVAL;
                   1524:                /* NB: truncate, caller can check length */
                   1525:                if (ireq->i_len > ic->ic_opt_ie_len)
                   1526:                        ireq->i_len = ic->ic_opt_ie_len;
                   1527:                error = copyout(ic->ic_opt_ie, ireq->i_data, ireq->i_len);
                   1528:                break;
                   1529:        case IEEE80211_IOC_WPAKEY:
                   1530:                error = ieee80211_ioctl_getkey(ic, ireq);
                   1531:                break;
                   1532:        case IEEE80211_IOC_CHANINFO:
                   1533:                error = ieee80211_ioctl_getchaninfo(ic, ireq);
                   1534:                break;
                   1535:        case IEEE80211_IOC_WPAIE:
                   1536:                error = ieee80211_ioctl_getwpaie(ic, ireq);
                   1537:                break;
                   1538:        case IEEE80211_IOC_SCAN_RESULTS:
                   1539:                error = ieee80211_ioctl_getscanresults(ic, ireq);
                   1540:                break;
                   1541:        case IEEE80211_IOC_STA_STATS:
                   1542:                error = ieee80211_ioctl_getstastats(ic, ireq);
                   1543:                break;
                   1544:        case IEEE80211_IOC_TXPOWMAX:
                   1545:                ireq->i_val = ic->ic_bss->ni_txpower;
                   1546:                break;
                   1547:        case IEEE80211_IOC_STA_TXPOW:
                   1548:                error = ieee80211_ioctl_getstatxpow(ic, ireq);
                   1549:                break;
                   1550:        case IEEE80211_IOC_STA_INFO:
                   1551:                error = ieee80211_ioctl_getstainfo(ic, ireq);
                   1552:                break;
                   1553:        case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
                   1554:        case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
                   1555:        case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
                   1556:        case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
                   1557:        case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
                   1558:        case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (bss only) */
                   1559:                error = ieee80211_ioctl_getwmeparam(ic, ireq);
                   1560:                break;
                   1561:        case IEEE80211_IOC_DTIM_PERIOD:
                   1562:                ireq->i_val = ic->ic_dtim_period;
                   1563:                break;
                   1564:        case IEEE80211_IOC_BEACON_INTERVAL:
                   1565:                /* NB: get from ic_bss for station mode */
                   1566:                ireq->i_val = ic->ic_bss->ni_intval;
                   1567:                break;
1.21      dyoung   1568:        case IEEE80211_IOC_PUREG:
                   1569:                ireq->i_val = (ic->ic_flags & IEEE80211_F_PUREG) != 0;
                   1570:                break;
1.30      dyoung   1571:        case IEEE80211_IOC_MCAST_RATE:
                   1572:                ireq->i_val = ic->ic_mcast_rate;
                   1573:                break;
1.26      skrll    1574:        case IEEE80211_IOC_FRAGTHRESHOLD:
                   1575:                ireq->i_val = ic->ic_fragthreshold;
                   1576:                break;
                   1577:        case IEEE80211_IOC_MACCMD:
                   1578:                error = ieee80211_ioctl_getmaccmd(ic, ireq);
                   1579:                break;
1.19      dyoung   1580:        default:
1.44      dyoung   1581: #if defined(COMPAT_FREEBSD_NET80211)
                   1582:                error = ieee80211_ioctl_get80211_fbsd(ic, cmd, ireq);
                   1583: #else
1.19      dyoung   1584:                error = EINVAL;
1.44      dyoung   1585: #endif /* COMPAT_FREEBSD_NET80211 */
1.19      dyoung   1586:                break;
                   1587:        }
                   1588:        return error;
                   1589: }
                   1590:
                   1591: static int
                   1592: ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1593: {
                   1594:        int error;
                   1595:        void *ie;
                   1596:
                   1597:        /*
                   1598:         * NB: Doing this for ap operation could be useful (e.g. for
                   1599:         *     WPA and/or WME) except that it typically is worthless
                   1600:         *     without being able to intervene when processing
                   1601:         *     association response frames--so disallow it for now.
                   1602:         */
                   1603:        if (ic->ic_opmode != IEEE80211_M_STA)
                   1604:                return EINVAL;
                   1605:        if (ireq->i_len > IEEE80211_MAX_OPT_IE)
                   1606:                return EINVAL;
                   1607:        /* NB: data.length is validated by the wireless extensions code */
1.31      christos 1608:        ie = malloc(ireq->i_len, M_DEVBUF, M_WAITOK);
1.19      dyoung   1609:        if (ie == NULL)
                   1610:                return ENOMEM;
                   1611:        error = copyin(ireq->i_data, ie, ireq->i_len);
                   1612:        /* XXX sanity check data? */
                   1613:        if (ic->ic_opt_ie != NULL)
                   1614:                FREE(ic->ic_opt_ie, M_DEVBUF);
                   1615:        ic->ic_opt_ie = ie;
                   1616:        ic->ic_opt_ie_len = ireq->i_len;
                   1617:        return 0;
                   1618: }
                   1619:
                   1620: static int
                   1621: ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1622: {
                   1623:        struct ieee80211req_key ik;
                   1624:        struct ieee80211_node *ni;
                   1625:        struct ieee80211_key *wk;
                   1626:        u_int16_t kid;
                   1627:        int error;
                   1628:
                   1629:        if (ireq->i_len != sizeof(ik))
                   1630:                return EINVAL;
                   1631:        error = copyin(ireq->i_data, &ik, sizeof(ik));
                   1632:        if (error)
                   1633:                return error;
                   1634:        /* NB: cipher support is verified by ieee80211_crypt_newkey */
                   1635:        /* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
                   1636:        if (ik.ik_keylen > sizeof(ik.ik_keydata))
                   1637:                return E2BIG;
                   1638:        kid = ik.ik_keyix;
                   1639:        if (kid == IEEE80211_KEYIX_NONE) {
                   1640:                /* XXX unicast keys currently must be tx/rx */
                   1641:                if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
                   1642:                        return EINVAL;
                   1643:                if (ic->ic_opmode == IEEE80211_M_STA) {
1.21      dyoung   1644:                        ni = ieee80211_ref_node(ic->ic_bss);
                   1645:                        if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) {
                   1646:                                ieee80211_free_node(ni);
1.19      dyoung   1647:                                return EADDRNOTAVAIL;
1.21      dyoung   1648:                        }
1.19      dyoung   1649:                } else {
                   1650:                        ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
                   1651:                        if (ni == NULL)
                   1652:                                return ENOENT;
                   1653:                }
                   1654:                wk = &ni->ni_ucastkey;
                   1655:        } else {
                   1656:                if (kid >= IEEE80211_WEP_NKID)
                   1657:                        return EINVAL;
                   1658:                wk = &ic->ic_nw_keys[kid];
                   1659:                ni = NULL;
                   1660:        }
                   1661:        error = 0;
                   1662:        ieee80211_key_update_begin(ic);
                   1663:        if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) {
                   1664:                wk->wk_keylen = ik.ik_keylen;
                   1665:                /* NB: MIC presence is implied by cipher type */
                   1666:                if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
                   1667:                        wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
                   1668:                wk->wk_keyrsc = ik.ik_keyrsc;
                   1669:                wk->wk_keytsc = 0;                      /* new key, reset */
                   1670:                memset(wk->wk_key, 0, sizeof(wk->wk_key));
                   1671:                memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
                   1672:                if (!ieee80211_crypto_setkey(ic, wk,
                   1673:                    ni != NULL ? ni->ni_macaddr : ik.ik_macaddr))
                   1674:                        error = EIO;
                   1675:                else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
                   1676:                        ic->ic_def_txkey = kid;
                   1677:        } else
                   1678:                error = ENXIO;
                   1679:        ieee80211_key_update_end(ic);
                   1680:        if (ni != NULL)
                   1681:                ieee80211_free_node(ni);
                   1682:        return error;
                   1683: }
                   1684:
                   1685: static int
                   1686: ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1687: {
                   1688:        struct ieee80211req_del_key dk;
                   1689:        int kid, error;
                   1690:
                   1691:        if (ireq->i_len != sizeof(dk))
                   1692:                return EINVAL;
                   1693:        error = copyin(ireq->i_data, &dk, sizeof(dk));
                   1694:        if (error)
                   1695:                return error;
                   1696:        kid = dk.idk_keyix;
                   1697:        /* XXX u_int8_t -> u_int16_t */
                   1698:        if (dk.idk_keyix == (u_int8_t) IEEE80211_KEYIX_NONE) {
                   1699:                struct ieee80211_node *ni;
                   1700:
1.21      dyoung   1701:                if (ic->ic_opmode == IEEE80211_M_STA) {
                   1702:                        ni = ieee80211_ref_node(ic->ic_bss);
                   1703:                        if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) {
                   1704:                                ieee80211_free_node(ni);
                   1705:                                return EADDRNOTAVAIL;
                   1706:                        }
                   1707:                } else {
                   1708:                        ni = ieee80211_find_node(&ic->ic_sta, dk.idk_macaddr);
                   1709:                        if (ni == NULL)
                   1710:                                return ENOENT;
                   1711:                }
1.19      dyoung   1712:                /* XXX error return */
1.26      skrll    1713:                ieee80211_node_delucastkey(ni);
1.19      dyoung   1714:                ieee80211_free_node(ni);
                   1715:        } else {
                   1716:                if (kid >= IEEE80211_WEP_NKID)
                   1717:                        return EINVAL;
                   1718:                /* XXX error return */
                   1719:                ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]);
                   1720:        }
                   1721:        return 0;
                   1722: }
                   1723:
1.20      dyoung   1724: #ifndef IEEE80211_NO_HOSTAP
1.19      dyoung   1725: static void
                   1726: domlme(void *arg, struct ieee80211_node *ni)
                   1727: {
                   1728:        struct ieee80211com *ic = ni->ni_ic;
                   1729:        struct ieee80211req_mlme *mlme = arg;
                   1730:
                   1731:        if (ni->ni_associd != 0) {
                   1732:                IEEE80211_SEND_MGMT(ic, ni,
                   1733:                        mlme->im_op == IEEE80211_MLME_DEAUTH ?
                   1734:                                IEEE80211_FC0_SUBTYPE_DEAUTH :
                   1735:                                IEEE80211_FC0_SUBTYPE_DISASSOC,
                   1736:                        mlme->im_reason);
                   1737:        }
                   1738:        ieee80211_node_leave(ic, ni);
                   1739: }
1.20      dyoung   1740: #endif /* !IEEE80211_NO_HOSTAP */
1.19      dyoung   1741:
                   1742: static int
                   1743: ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1744: {
                   1745:        struct ieee80211req_mlme mlme;
                   1746:        struct ieee80211_node *ni;
                   1747:        int error;
                   1748:
                   1749:        if (ireq->i_len != sizeof(mlme))
                   1750:                return EINVAL;
                   1751:        error = copyin(ireq->i_data, &mlme, sizeof(mlme));
                   1752:        if (error)
                   1753:                return error;
                   1754:        switch (mlme.im_op) {
                   1755:        case IEEE80211_MLME_ASSOC:
                   1756:                if (ic->ic_opmode != IEEE80211_M_STA)
                   1757:                        return EINVAL;
                   1758:                /* XXX must be in S_SCAN state? */
                   1759:
1.21      dyoung   1760:                if (mlme.im_ssid_len != 0) {
1.19      dyoung   1761:                        /*
                   1762:                         * Desired ssid specified; must match both bssid and
                   1763:                         * ssid to distinguish ap advertising multiple ssid's.
                   1764:                         */
                   1765:                        ni = ieee80211_find_node_with_ssid(&ic->ic_scan,
                   1766:                                mlme.im_macaddr,
1.21      dyoung   1767:                                mlme.im_ssid_len, mlme.im_ssid);
1.19      dyoung   1768:                } else {
                   1769:                        /*
                   1770:                         * Normal case; just match bssid.
                   1771:                         */
                   1772:                        ni = ieee80211_find_node(&ic->ic_scan, mlme.im_macaddr);
                   1773:                }
                   1774:                if (ni == NULL)
                   1775:                        return EINVAL;
                   1776:                if (!ieee80211_sta_join(ic, ni)) {
                   1777:                        ieee80211_free_node(ni);
                   1778:                        return EINVAL;
                   1779:                }
                   1780:                break;
                   1781:        case IEEE80211_MLME_DISASSOC:
                   1782:        case IEEE80211_MLME_DEAUTH:
                   1783:                switch (ic->ic_opmode) {
                   1784:                case IEEE80211_M_STA:
                   1785:                        /* XXX not quite right */
                   1786:                        ieee80211_new_state(ic, IEEE80211_S_INIT,
                   1787:                                mlme.im_reason);
                   1788:                        break;
                   1789:                case IEEE80211_M_HOSTAP:
1.20      dyoung   1790: #ifndef IEEE80211_NO_HOSTAP
1.19      dyoung   1791:                        /* NB: the broadcast address means do 'em all */
                   1792:                        if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) {
                   1793:                                if ((ni = ieee80211_find_node(&ic->ic_sta,
                   1794:                                                mlme.im_macaddr)) == NULL)
                   1795:                                        return EINVAL;
                   1796:                                domlme(&mlme, ni);
                   1797:                                ieee80211_free_node(ni);
1.1       dyoung   1798:                        } else {
1.19      dyoung   1799:                                ieee80211_iterate_nodes(&ic->ic_sta,
                   1800:                                                domlme, &mlme);
1.1       dyoung   1801:                        }
1.20      dyoung   1802: #endif /* !IEEE80211_NO_HOSTAP */
1.1       dyoung   1803:                        break;
1.19      dyoung   1804:                default:
                   1805:                        return EINVAL;
                   1806:                }
                   1807:                break;
                   1808:        case IEEE80211_MLME_AUTHORIZE:
                   1809:        case IEEE80211_MLME_UNAUTHORIZE:
                   1810:                if (ic->ic_opmode != IEEE80211_M_HOSTAP)
                   1811:                        return EINVAL;
                   1812:                ni = ieee80211_find_node(&ic->ic_sta, mlme.im_macaddr);
                   1813:                if (ni == NULL)
                   1814:                        return EINVAL;
                   1815:                if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
1.26      skrll    1816:                        ieee80211_node_authorize(ni);
1.19      dyoung   1817:                else
1.26      skrll    1818:                        ieee80211_node_unauthorize(ni);
1.19      dyoung   1819:                ieee80211_free_node(ni);
                   1820:                break;
                   1821:        default:
                   1822:                return EINVAL;
                   1823:        }
                   1824:        return 0;
                   1825: }
                   1826:
                   1827: static int
                   1828: ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1829: {
                   1830:        u_int8_t mac[IEEE80211_ADDR_LEN];
                   1831:        const struct ieee80211_aclator *acl = ic->ic_acl;
                   1832:        int error;
                   1833:
                   1834:        if (ireq->i_len != sizeof(mac))
                   1835:                return EINVAL;
                   1836:        error = copyin(ireq->i_data, mac, ireq->i_len);
                   1837:        if (error)
                   1838:                return error;
                   1839:        if (acl == NULL) {
                   1840:                acl = ieee80211_aclator_get("mac");
                   1841:                if (acl == NULL || !acl->iac_attach(ic))
                   1842:                        return EINVAL;
                   1843:                ic->ic_acl = acl;
                   1844:        }
                   1845:        if (ireq->i_type == IEEE80211_IOC_ADDMAC)
                   1846:                acl->iac_add(ic, mac);
                   1847:        else
                   1848:                acl->iac_remove(ic, mac);
                   1849:        return 0;
                   1850: }
                   1851:
                   1852: static int
1.26      skrll    1853: ieee80211_ioctl_setmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
1.19      dyoung   1854: {
                   1855:        const struct ieee80211_aclator *acl = ic->ic_acl;
                   1856:
                   1857:        switch (ireq->i_val) {
                   1858:        case IEEE80211_MACCMD_POLICY_OPEN:
                   1859:        case IEEE80211_MACCMD_POLICY_ALLOW:
                   1860:        case IEEE80211_MACCMD_POLICY_DENY:
                   1861:                if (acl == NULL) {
                   1862:                        acl = ieee80211_aclator_get("mac");
                   1863:                        if (acl == NULL || !acl->iac_attach(ic))
                   1864:                                return EINVAL;
                   1865:                        ic->ic_acl = acl;
                   1866:                }
                   1867:                acl->iac_setpolicy(ic, ireq->i_val);
                   1868:                break;
                   1869:        case IEEE80211_MACCMD_FLUSH:
                   1870:                if (acl != NULL)
                   1871:                        acl->iac_flush(ic);
                   1872:                /* NB: silently ignore when not in use */
                   1873:                break;
                   1874:        case IEEE80211_MACCMD_DETACH:
                   1875:                if (acl != NULL) {
                   1876:                        ic->ic_acl = NULL;
                   1877:                        acl->iac_detach(ic);
                   1878:                }
                   1879:                break;
                   1880:        default:
1.26      skrll    1881:                if (acl == NULL)
                   1882:                        return EINVAL;
                   1883:                else
                   1884:                        return acl->iac_setioctl(ic, ireq);
1.19      dyoung   1885:        }
                   1886:        return 0;
                   1887: }
                   1888:
                   1889: static int
                   1890: ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1891: {
                   1892:        struct ieee80211req_chanlist list;
1.33      christos 1893:        u_int8_t chanlist[IEEE80211_CHAN_BYTES];
1.19      dyoung   1894:        int i, j, error;
                   1895:
                   1896:        if (ireq->i_len != sizeof(list))
                   1897:                return EINVAL;
                   1898:        error = copyin(ireq->i_data, &list, sizeof(list));
                   1899:        if (error)
                   1900:                return error;
                   1901:        memset(chanlist, 0, sizeof(chanlist));
                   1902:        /*
                   1903:         * Since channel 0 is not available for DS, channel 1
                   1904:         * is assigned to LSB on WaveLAN.
                   1905:         */
                   1906:        if (ic->ic_phytype == IEEE80211_T_DS)
                   1907:                i = 1;
                   1908:        else
                   1909:                i = 0;
                   1910:        for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
                   1911:                /*
                   1912:                 * NB: silently discard unavailable channels so users
                   1913:                 *     can specify 1-255 to get all available channels.
                   1914:                 */
                   1915:                if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i))
                   1916:                        setbit(chanlist, i);
                   1917:        }
                   1918:        if (ic->ic_ibss_chan == NULL ||
                   1919:            isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
                   1920:                for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
                   1921:                        if (isset(chanlist, i)) {
                   1922:                                ic->ic_ibss_chan = &ic->ic_channels[i];
                   1923:                                goto found;
1.1       dyoung   1924:                        }
1.19      dyoung   1925:                return EINVAL;                  /* no active channels */
                   1926: found:
                   1927:                ;
                   1928:        }
                   1929:        memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
                   1930:        return IS_UP_AUTO(ic) ? ENETRESET : 0;
                   1931: }
                   1932:
                   1933: static int
                   1934: ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1935: {
                   1936:        struct ieee80211_node *ni;
                   1937:        struct ieee80211req_sta_txpow txpow;
                   1938:        int error;
                   1939:
                   1940:        if (ireq->i_len != sizeof(txpow))
                   1941:                return EINVAL;
                   1942:        error = copyin(ireq->i_data, &txpow, sizeof(txpow));
                   1943:        if (error != 0)
                   1944:                return error;
                   1945:        ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
                   1946:        if (ni == NULL)
                   1947:                return EINVAL;          /* XXX */
                   1948:        ni->ni_txpower = txpow.it_txpow;
                   1949:        ieee80211_free_node(ni);
                   1950:        return error;
                   1951: }
                   1952:
                   1953: static int
                   1954: ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
                   1955: {
                   1956:        struct ieee80211_wme_state *wme = &ic->ic_wme;
                   1957:        struct wmeParams *wmep, *chanp;
                   1958:        int isbss, ac;
                   1959:
                   1960:        if ((ic->ic_caps & IEEE80211_C_WME) == 0)
                   1961:                return EINVAL;
                   1962:
                   1963:        isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
                   1964:        ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
                   1965:        if (ac >= WME_NUM_AC)
                   1966:                ac = WME_AC_BE;
                   1967:        if (isbss) {
                   1968:                chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
                   1969:                wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
                   1970:        } else {
                   1971:                chanp = &wme->wme_chanParams.cap_wmeParams[ac];
                   1972:                wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
                   1973:        }
                   1974:        switch (ireq->i_type) {
                   1975:        case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
                   1976:                if (isbss) {
                   1977:                        wmep->wmep_logcwmin = ireq->i_val;
                   1978:                        if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
                   1979:                                chanp->wmep_logcwmin = ireq->i_val;
                   1980:                } else {
                   1981:                        wmep->wmep_logcwmin = chanp->wmep_logcwmin =
                   1982:                                ireq->i_val;
                   1983:                }
                   1984:                break;
                   1985:        case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
                   1986:                if (isbss) {
                   1987:                        wmep->wmep_logcwmax = ireq->i_val;
                   1988:                        if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
                   1989:                                chanp->wmep_logcwmax = ireq->i_val;
                   1990:                } else {
                   1991:                        wmep->wmep_logcwmax = chanp->wmep_logcwmax =
                   1992:                                ireq->i_val;
                   1993:                }
                   1994:                break;
                   1995:        case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
                   1996:                if (isbss) {
                   1997:                        wmep->wmep_aifsn = ireq->i_val;
                   1998:                        if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
                   1999:                                chanp->wmep_aifsn = ireq->i_val;
                   2000:                } else {
                   2001:                        wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
                   2002:                }
                   2003:                break;
                   2004:        case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
                   2005:                if (isbss) {
                   2006:                        wmep->wmep_txopLimit = ireq->i_val;
                   2007:                        if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
                   2008:                                chanp->wmep_txopLimit = ireq->i_val;
                   2009:                } else {
                   2010:                        wmep->wmep_txopLimit = chanp->wmep_txopLimit =
                   2011:                                ireq->i_val;
                   2012:                }
                   2013:                break;
                   2014:        case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
                   2015:                wmep->wmep_acm = ireq->i_val;
                   2016:                if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
                   2017:                        chanp->wmep_acm = ireq->i_val;
                   2018:                break;
                   2019:        case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (!bss only)*/
                   2020:                wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
                   2021:                        (ireq->i_val) == 0;
                   2022:                break;
                   2023:        }
                   2024:        ieee80211_wme_updateparams(ic);
                   2025:        return 0;
                   2026: }
                   2027:
                   2028: static int
                   2029: cipher2cap(int cipher)
                   2030: {
                   2031:        switch (cipher) {
                   2032:        case IEEE80211_CIPHER_WEP:      return IEEE80211_C_WEP;
                   2033:        case IEEE80211_CIPHER_AES_OCB:  return IEEE80211_C_AES;
                   2034:        case IEEE80211_CIPHER_AES_CCM:  return IEEE80211_C_AES_CCM;
                   2035:        case IEEE80211_CIPHER_CKIP:     return IEEE80211_C_CKIP;
                   2036:        case IEEE80211_CIPHER_TKIP:     return IEEE80211_C_TKIP;
                   2037:        }
                   2038:        return 0;
                   2039: }
                   2040:
                   2041: static int
1.43      christos 2042: ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd,
1.40      christos 2043:     struct ieee80211req *ireq)
1.19      dyoung   2044: {
1.30      dyoung   2045: #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
1.19      dyoung   2046:        static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
                   2047:        u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
                   2048:        char tmpssid[IEEE80211_NWID_LEN];
                   2049:        u_int8_t tmpbssid[IEEE80211_ADDR_LEN];
                   2050:        struct ieee80211_key *k;
1.23      dyoung   2051:        u_int kid;
1.30      dyoung   2052: #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
1.23      dyoung   2053:        struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
                   2054:        int error;
                   2055:        const struct ieee80211_authenticator *auth;
1.19      dyoung   2056:        int j, caps;
                   2057:
                   2058:        error = 0;
                   2059:        switch (ireq->i_type) {
1.30      dyoung   2060: #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
1.19      dyoung   2061:        case IEEE80211_IOC_SSID:
                   2062:                if (ireq->i_val != 0 ||
                   2063:                    ireq->i_len > IEEE80211_NWID_LEN)
                   2064:                        return EINVAL;
                   2065:                error = copyin(ireq->i_data, tmpssid, ireq->i_len);
                   2066:                if (error)
1.1       dyoung   2067:                        break;
1.19      dyoung   2068:                memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
                   2069:                ic->ic_des_esslen = ireq->i_len;
                   2070:                memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
                   2071:                error = ENETRESET;
                   2072:                break;
1.30      dyoung   2073: #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
1.19      dyoung   2074:        case IEEE80211_IOC_WEP:
                   2075:                switch (ireq->i_val) {
                   2076:                case IEEE80211_WEP_OFF:
                   2077:                        ic->ic_flags &= ~IEEE80211_F_PRIVACY;
                   2078:                        ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1.1       dyoung   2079:                        break;
1.19      dyoung   2080:                case IEEE80211_WEP_ON:
                   2081:                        ic->ic_flags |= IEEE80211_F_PRIVACY;
                   2082:                        ic->ic_flags |= IEEE80211_F_DROPUNENC;
1.1       dyoung   2083:                        break;
1.19      dyoung   2084:                case IEEE80211_WEP_MIXED:
                   2085:                        ic->ic_flags |= IEEE80211_F_PRIVACY;
                   2086:                        ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1.1       dyoung   2087:                        break;
1.19      dyoung   2088:                }
                   2089:                error = ENETRESET;
                   2090:                break;
1.30      dyoung   2091: #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
1.19      dyoung   2092:        case IEEE80211_IOC_WEPKEY:
                   2093:                kid = (u_int) ireq->i_val;
                   2094:                if (kid >= IEEE80211_WEP_NKID)
                   2095:                        return EINVAL;
                   2096:                k = &ic->ic_nw_keys[kid];
                   2097:                if (ireq->i_len == 0) {
                   2098:                        /* zero-len =>'s delete any existing key */
                   2099:                        (void) ieee80211_crypto_delkey(ic, k);
1.1       dyoung   2100:                        break;
1.19      dyoung   2101:                }
                   2102:                if (ireq->i_len > sizeof(tmpkey))
                   2103:                        return EINVAL;
                   2104:                memset(tmpkey, 0, sizeof(tmpkey));
                   2105:                error = copyin(ireq->i_data, tmpkey, ireq->i_len);
                   2106:                if (error)
1.1       dyoung   2107:                        break;
1.19      dyoung   2108:                ieee80211_key_update_begin(ic);
                   2109:                k->wk_keyix = kid;      /* NB: force fixed key id */
                   2110:                if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
                   2111:                    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
                   2112:                        k->wk_keylen = ireq->i_len;
                   2113:                        memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
                   2114:                        if  (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
                   2115:                                error = EINVAL;
                   2116:                } else
                   2117:                        error = EINVAL;
                   2118:                ieee80211_key_update_end(ic);
1.21      dyoung   2119:                if (!error)                     /* NB: for compatibility */
                   2120:                        error = ENETRESET;
1.19      dyoung   2121:                break;
                   2122:        case IEEE80211_IOC_WEPTXKEY:
                   2123:                kid = (u_int) ireq->i_val;
                   2124:                if (kid >= IEEE80211_WEP_NKID &&
                   2125:                    (u_int16_t) kid != IEEE80211_KEYIX_NONE)
                   2126:                        return EINVAL;
                   2127:                ic->ic_def_txkey = kid;
                   2128:                error = ENETRESET;      /* push to hardware */
                   2129:                break;
1.30      dyoung   2130: #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
1.19      dyoung   2131:        case IEEE80211_IOC_AUTHMODE:
                   2132:                switch (ireq->i_val) {
                   2133:                case IEEE80211_AUTH_WPA:
                   2134:                case IEEE80211_AUTH_8021X:      /* 802.1x */
                   2135:                case IEEE80211_AUTH_OPEN:       /* open */
                   2136:                case IEEE80211_AUTH_SHARED:     /* shared-key */
                   2137:                case IEEE80211_AUTH_AUTO:       /* auto */
                   2138:                        auth = ieee80211_authenticator_get(ireq->i_val);
                   2139:                        if (auth == NULL)
                   2140:                                return EINVAL;
1.1       dyoung   2141:                        break;
1.19      dyoung   2142:                default:
                   2143:                        return EINVAL;
                   2144:                }
                   2145:                switch (ireq->i_val) {
                   2146:                case IEEE80211_AUTH_WPA:        /* WPA w/ 802.1x */
                   2147:                        ic->ic_flags |= IEEE80211_F_PRIVACY;
                   2148:                        ireq->i_val = IEEE80211_AUTH_8021X;
1.1       dyoung   2149:                        break;
1.19      dyoung   2150:                case IEEE80211_AUTH_OPEN:       /* open */
                   2151:                        ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
1.10      dyoung   2152:                        break;
1.19      dyoung   2153:                case IEEE80211_AUTH_SHARED:     /* shared-key */
                   2154:                case IEEE80211_AUTH_8021X:      /* 802.1x */
                   2155:                        ic->ic_flags &= ~IEEE80211_F_WPA;
                   2156:                        /* both require a key so mark the PRIVACY capability */
                   2157:                        ic->ic_flags |= IEEE80211_F_PRIVACY;
1.10      dyoung   2158:                        break;
1.19      dyoung   2159:                case IEEE80211_AUTH_AUTO:       /* auto */
                   2160:                        ic->ic_flags &= ~IEEE80211_F_WPA;
                   2161:                        /* XXX PRIVACY handling? */
                   2162:                        /* XXX what's the right way to do this? */
1.10      dyoung   2163:                        break;
1.1       dyoung   2164:                }
1.19      dyoung   2165:                /* NB: authenticator attach/detach happens on state change */
                   2166:                ic->ic_bss->ni_authmode = ireq->i_val;
                   2167:                /* XXX mixed/mode/usage? */
                   2168:                ic->ic_auth = auth;
                   2169:                error = ENETRESET;
1.1       dyoung   2170:                break;
1.30      dyoung   2171: #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
1.19      dyoung   2172:        case IEEE80211_IOC_CHANNEL:
                   2173:                /* XXX 0xffff overflows 16-bit signed */
                   2174:                if (ireq->i_val == 0 ||
                   2175:                    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
                   2176:                        ic->ic_des_chan = IEEE80211_CHAN_ANYC;
                   2177:                else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
                   2178:                    isclr(ic->ic_chan_active, ireq->i_val)) {
                   2179:                        return EINVAL;
                   2180:                } else
                   2181:                        ic->ic_ibss_chan = ic->ic_des_chan =
                   2182:                                &ic->ic_channels[ireq->i_val];
                   2183:                switch (ic->ic_state) {
                   2184:                case IEEE80211_S_INIT:
                   2185:                case IEEE80211_S_SCAN:
1.1       dyoung   2186:                        error = ENETRESET;
                   2187:                        break;
1.19      dyoung   2188:                default:
1.1       dyoung   2189:                        /*
1.19      dyoung   2190:                         * If the desired channel has changed (to something
                   2191:                         * other than any) and we're not already scanning,
                   2192:                         * then kick the state machine.
1.1       dyoung   2193:                         */
1.19      dyoung   2194:                        if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
                   2195:                            ic->ic_bss->ni_chan != ic->ic_des_chan &&
                   2196:                            (ic->ic_flags & IEEE80211_F_SCAN) == 0)
                   2197:                                error = ENETRESET;
1.1       dyoung   2198:                        break;
1.19      dyoung   2199:                }
1.26      skrll    2200:                if (error == ENETRESET &&
                   2201:                        ic->ic_opmode == IEEE80211_M_MONITOR) {
                   2202:                        if (IS_UP(ic)) {
                   2203:                                /*
                   2204:                                 * Monitor mode can switch directly.
                   2205:                                 */
                   2206:                                if (ic->ic_des_chan != IEEE80211_CHAN_ANYC)
                   2207:                                        ic->ic_curchan = ic->ic_des_chan;
                   2208:                                error = ic->ic_reset(ic->ic_ifp);
                   2209:                        } else
                   2210:                                error = 0;
                   2211:                }
1.19      dyoung   2212:                break;
                   2213:        case IEEE80211_IOC_POWERSAVE:
                   2214:                switch (ireq->i_val) {
                   2215:                case IEEE80211_POWERSAVE_OFF:
                   2216:                        if (ic->ic_flags & IEEE80211_F_PMGTON) {
                   2217:                                ic->ic_flags &= ~IEEE80211_F_PMGTON;
                   2218:                                error = ENETRESET;
1.18      perry    2219:                        }
1.1       dyoung   2220:                        break;
1.19      dyoung   2221:                case IEEE80211_POWERSAVE_ON:
                   2222:                        if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
1.1       dyoung   2223:                                error = EINVAL;
1.19      dyoung   2224:                        else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
                   2225:                                ic->ic_flags |= IEEE80211_F_PMGTON;
                   2226:                                error = ENETRESET;
1.1       dyoung   2227:                        }
                   2228:                        break;
1.19      dyoung   2229:                default:
                   2230:                        error = EINVAL;
1.1       dyoung   2231:                        break;
1.19      dyoung   2232:                }
                   2233:                break;
                   2234:        case IEEE80211_IOC_POWERSAVESLEEP:
                   2235:                if (ireq->i_val < 0)
                   2236:                        return EINVAL;
                   2237:                ic->ic_lintval = ireq->i_val;
                   2238:                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
                   2239:                break;
1.30      dyoung   2240: #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
1.19      dyoung   2241:        case IEEE80211_IOC_RTSTHRESHOLD:
1.26      skrll    2242:                if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
                   2243:                      ireq->i_val <= IEEE80211_RTS_MAX))
1.19      dyoung   2244:                        return EINVAL;
                   2245:                ic->ic_rtsthreshold = ireq->i_val;
                   2246:                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
                   2247:                break;
                   2248:        case IEEE80211_IOC_PROTMODE:
                   2249:                if (ireq->i_val > IEEE80211_PROT_RTSCTS)
                   2250:                        return EINVAL;
                   2251:                ic->ic_protmode = ireq->i_val;
                   2252:                /* NB: if not operating in 11g this can wait */
                   2253:                if (ic->ic_curmode == IEEE80211_MODE_11G)
                   2254:                        error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
                   2255:                break;
                   2256:        case IEEE80211_IOC_TXPOWER:
                   2257:                if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
                   2258:                        return EINVAL;
                   2259:                if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
                   2260:                      ireq->i_val < IEEE80211_TXPOWER_MAX))
                   2261:                        return EINVAL;
                   2262:                ic->ic_txpowlimit = ireq->i_val;
                   2263:                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
                   2264:                break;
                   2265:        case IEEE80211_IOC_ROAMING:
                   2266:                if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
                   2267:                    ireq->i_val <= IEEE80211_ROAMING_MANUAL))
                   2268:                        return EINVAL;
                   2269:                ic->ic_roaming = ireq->i_val;
                   2270:                /* XXXX reset? */
                   2271:                break;
                   2272:        case IEEE80211_IOC_PRIVACY:
                   2273:                if (ireq->i_val) {
                   2274:                        /* XXX check for key state? */
                   2275:                        ic->ic_flags |= IEEE80211_F_PRIVACY;
                   2276:                } else
                   2277:                        ic->ic_flags &= ~IEEE80211_F_PRIVACY;
                   2278:                break;
                   2279:        case IEEE80211_IOC_DROPUNENCRYPTED:
                   2280:                if (ireq->i_val)
                   2281:                        ic->ic_flags |= IEEE80211_F_DROPUNENC;
                   2282:                else
                   2283:                        ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
                   2284:                break;
                   2285:        case IEEE80211_IOC_WPAKEY:
                   2286:                error = ieee80211_ioctl_setkey(ic, ireq);
                   2287:                break;
                   2288:        case IEEE80211_IOC_DELKEY:
                   2289:                error = ieee80211_ioctl_delkey(ic, ireq);
                   2290:                break;
                   2291:        case IEEE80211_IOC_MLME:
                   2292:                error = ieee80211_ioctl_setmlme(ic, ireq);
                   2293:                break;
                   2294:        case IEEE80211_IOC_OPTIE:
                   2295:                error = ieee80211_ioctl_setoptie(ic, ireq);
                   2296:                break;
                   2297:        case IEEE80211_IOC_COUNTERMEASURES:
                   2298:                if (ireq->i_val) {
                   2299:                        if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
                   2300:                                return EINVAL;
                   2301:                        ic->ic_flags |= IEEE80211_F_COUNTERM;
                   2302:                } else
                   2303:                        ic->ic_flags &= ~IEEE80211_F_COUNTERM;
                   2304:                break;
                   2305:        case IEEE80211_IOC_WPA:
                   2306:                if (ireq->i_val > 3)
                   2307:                        return EINVAL;
                   2308:                /* XXX verify ciphers available */
                   2309:                ic->ic_flags &= ~IEEE80211_F_WPA;
                   2310:                switch (ireq->i_val) {
                   2311:                case 1:
                   2312:                        ic->ic_flags |= IEEE80211_F_WPA1;
1.1       dyoung   2313:                        break;
1.19      dyoung   2314:                case 2:
                   2315:                        ic->ic_flags |= IEEE80211_F_WPA2;
1.1       dyoung   2316:                        break;
1.19      dyoung   2317:                case 3:
                   2318:                        ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
1.1       dyoung   2319:                        break;
1.19      dyoung   2320:                }
                   2321:                error = ENETRESET;              /* XXX? */
                   2322:                break;
                   2323:        case IEEE80211_IOC_WME:
                   2324:                if (ireq->i_val) {
                   2325:                        if ((ic->ic_caps & IEEE80211_C_WME) == 0)
                   2326:                                return EINVAL;
                   2327:                        ic->ic_flags |= IEEE80211_F_WME;
                   2328:                } else
                   2329:                        ic->ic_flags &= ~IEEE80211_F_WME;
                   2330:                error = ENETRESET;              /* XXX maybe not for station? */
                   2331:                break;
                   2332:        case IEEE80211_IOC_HIDESSID:
                   2333:                if (ireq->i_val)
                   2334:                        ic->ic_flags |= IEEE80211_F_HIDESSID;
                   2335:                else
                   2336:                        ic->ic_flags &= ~IEEE80211_F_HIDESSID;
                   2337:                error = ENETRESET;
                   2338:                break;
                   2339:        case IEEE80211_IOC_APBRIDGE:
                   2340:                if (ireq->i_val == 0)
                   2341:                        ic->ic_flags |= IEEE80211_F_NOBRIDGE;
                   2342:                else
                   2343:                        ic->ic_flags &= ~IEEE80211_F_NOBRIDGE;
                   2344:                break;
                   2345:        case IEEE80211_IOC_MCASTCIPHER:
                   2346:                if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 &&
                   2347:                    !ieee80211_crypto_available(ireq->i_val))
                   2348:                        return EINVAL;
                   2349:                rsn->rsn_mcastcipher = ireq->i_val;
                   2350:                error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
                   2351:                break;
                   2352:        case IEEE80211_IOC_MCASTKEYLEN:
                   2353:                if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
                   2354:                        return EINVAL;
                   2355:                /* XXX no way to verify driver capability */
                   2356:                rsn->rsn_mcastkeylen = ireq->i_val;
                   2357:                error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
                   2358:                break;
                   2359:        case IEEE80211_IOC_UCASTCIPHERS:
                   2360:                /*
                   2361:                 * Convert user-specified cipher set to the set
                   2362:                 * we can support (via hardware or software).
                   2363:                 * NB: this logic intentionally ignores unknown and
                   2364:                 * unsupported ciphers so folks can specify 0xff or
                   2365:                 * similar and get all available ciphers.
                   2366:                 */
                   2367:                caps = 0;
                   2368:                for (j = 1; j < 32; j++)        /* NB: skip WEP */
                   2369:                        if ((ireq->i_val & (1<<j)) &&
                   2370:                            ((ic->ic_caps & cipher2cap(j)) ||
                   2371:                             ieee80211_crypto_available(j)))
                   2372:                                caps |= 1<<j;
                   2373:                if (caps == 0)                  /* nothing available */
                   2374:                        return EINVAL;
                   2375:                /* XXX verify ciphers ok for unicast use? */
                   2376:                /* XXX disallow if running as it'll have no effect */
                   2377:                rsn->rsn_ucastcipherset = caps;
                   2378:                error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
                   2379:                break;
                   2380:        case IEEE80211_IOC_UCASTCIPHER:
                   2381:                if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0)
                   2382:                        return EINVAL;
                   2383:                rsn->rsn_ucastcipher = ireq->i_val;
                   2384:                break;
                   2385:        case IEEE80211_IOC_UCASTKEYLEN:
                   2386:                if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
                   2387:                        return EINVAL;
                   2388:                /* XXX no way to verify driver capability */
                   2389:                rsn->rsn_ucastkeylen = ireq->i_val;
                   2390:                break;
                   2391:        case IEEE80211_IOC_DRIVER_CAPS:
                   2392:                /* NB: for testing */
                   2393:                ic->ic_caps = (((u_int16_t) ireq->i_val) << 16) |
                   2394:                               ((u_int16_t) ireq->i_len);
                   2395:                break;
                   2396:        case IEEE80211_IOC_KEYMGTALGS:
                   2397:                /* XXX check */
                   2398:                rsn->rsn_keymgmtset = ireq->i_val;
                   2399:                error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
                   2400:                break;
                   2401:        case IEEE80211_IOC_RSNCAPS:
                   2402:                /* XXX check */
                   2403:                rsn->rsn_caps = ireq->i_val;
                   2404:                error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
                   2405:                break;
1.30      dyoung   2406: #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
1.19      dyoung   2407:        case IEEE80211_IOC_BSSID:
                   2408:                /* NB: should only be set when in STA mode */
                   2409:                if (ic->ic_opmode != IEEE80211_M_STA)
                   2410:                        return EINVAL;
                   2411:                if (ireq->i_len != sizeof(tmpbssid))
                   2412:                        return EINVAL;
                   2413:                error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
                   2414:                if (error)
1.1       dyoung   2415:                        break;
1.19      dyoung   2416:                IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid);
                   2417:                if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
                   2418:                        ic->ic_flags &= ~IEEE80211_F_DESBSSID;
                   2419:                else
                   2420:                        ic->ic_flags |= IEEE80211_F_DESBSSID;
                   2421:                error = ENETRESET;
                   2422:                break;
1.30      dyoung   2423: #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
1.19      dyoung   2424:        case IEEE80211_IOC_CHANLIST:
                   2425:                error = ieee80211_ioctl_setchanlist(ic, ireq);
                   2426:                break;
                   2427:        case IEEE80211_IOC_SCAN_REQ:
                   2428:                if (ic->ic_opmode == IEEE80211_M_HOSTAP)        /* XXX ignore */
1.10      dyoung   2429:                        break;
1.19      dyoung   2430:                error = ieee80211_setupscan(ic, ic->ic_chan_avail);
                   2431:                if (error == 0)         /* XXX background scan */
                   2432:                        error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
                   2433:                break;
                   2434:        case IEEE80211_IOC_ADDMAC:
                   2435:        case IEEE80211_IOC_DELMAC:
                   2436:                error = ieee80211_ioctl_macmac(ic, ireq);
                   2437:                break;
                   2438:        case IEEE80211_IOC_MACCMD:
1.26      skrll    2439:                error = ieee80211_ioctl_setmaccmd(ic, ireq);
1.19      dyoung   2440:                break;
                   2441:        case IEEE80211_IOC_STA_TXPOW:
                   2442:                error = ieee80211_ioctl_setstatxpow(ic, ireq);
                   2443:                break;
                   2444:        case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
                   2445:        case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
                   2446:        case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
                   2447:        case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
                   2448:        case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
                   2449:        case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (bss only) */
                   2450:                error = ieee80211_ioctl_setwmeparam(ic, ireq);
                   2451:                break;
                   2452:        case IEEE80211_IOC_DTIM_PERIOD:
                   2453:                if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
                   2454:                    ic->ic_opmode != IEEE80211_M_IBSS)
                   2455:                        return EINVAL;
                   2456:                if (IEEE80211_DTIM_MIN <= ireq->i_val &&
                   2457:                    ireq->i_val <= IEEE80211_DTIM_MAX) {
                   2458:                        ic->ic_dtim_period = ireq->i_val;
                   2459:                        error = ENETRESET;              /* requires restart */
                   2460:                } else
                   2461:                        error = EINVAL;
                   2462:                break;
                   2463:        case IEEE80211_IOC_BEACON_INTERVAL:
                   2464:                if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
                   2465:                    ic->ic_opmode != IEEE80211_M_IBSS)
                   2466:                        return EINVAL;
                   2467:                if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
                   2468:                    ireq->i_val <= IEEE80211_BINTVAL_MAX) {
1.26      skrll    2469:                        ic->ic_bintval = ireq->i_val;
1.19      dyoung   2470:                        error = ENETRESET;              /* requires restart */
                   2471:                } else
1.1       dyoung   2472:                        error = EINVAL;
1.19      dyoung   2473:                break;
1.21      dyoung   2474:        case IEEE80211_IOC_PUREG:
                   2475:                if (ireq->i_val)
                   2476:                        ic->ic_flags |= IEEE80211_F_PUREG;
                   2477:                else
                   2478:                        ic->ic_flags &= ~IEEE80211_F_PUREG;
                   2479:                /* NB: reset only if we're operating on an 11g channel */
                   2480:                if (ic->ic_curmode == IEEE80211_MODE_11G)
                   2481:                        error = ENETRESET;
                   2482:                break;
1.30      dyoung   2483:        case IEEE80211_IOC_MCAST_RATE:
                   2484:                ic->ic_mcast_rate = ireq->i_val & IEEE80211_RATE_VAL;
                   2485:                break;
1.26      skrll    2486:        case IEEE80211_IOC_FRAGTHRESHOLD:
                   2487:                if ((ic->ic_caps & IEEE80211_C_TXFRAG) == 0 &&
                   2488:                    ireq->i_val != IEEE80211_FRAG_MAX)
                   2489:                        return EINVAL;
                   2490:                if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
                   2491:                      ireq->i_val <= IEEE80211_FRAG_MAX))
                   2492:                        return EINVAL;
                   2493:                ic->ic_fragthreshold = ireq->i_val;
                   2494:                error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
                   2495:                break;
1.19      dyoung   2496:        default:
                   2497:                error = EINVAL;
                   2498:                break;
                   2499:        }
                   2500:        if (error == ENETRESET && !IS_UP_AUTO(ic))
                   2501:                error = 0;
                   2502:        return error;
                   2503: }
                   2504:
                   2505: #ifdef __FreeBSD__
                   2506: int
1.45      christos 2507: ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, void *data)
1.19      dyoung   2508: {
                   2509:        struct ifnet *ifp = ic->ic_ifp;
                   2510:        int error = 0;
                   2511:        struct ifreq *ifr;
                   2512:        struct ifaddr *ifa;                     /* XXX */
                   2513:
                   2514:        switch (cmd) {
                   2515:        case SIOCSIFMEDIA:
                   2516:        case SIOCGIFMEDIA:
                   2517:                error = ifmedia_ioctl(ifp, (struct ifreq *) data,
                   2518:                                &ic->ic_media, cmd);
                   2519:                break;
                   2520:        case SIOCG80211:
                   2521:                error = ieee80211_ioctl_get80211(ic, cmd,
                   2522:                                (struct ieee80211req *) data);
                   2523:                break;
                   2524:        case SIOCS80211:
                   2525:                error = suser(curthread);
                   2526:                if (error == 0)
                   2527:                        error = ieee80211_ioctl_set80211(ic, cmd,
                   2528:                                        (struct ieee80211req *) data);
1.1       dyoung   2529:                break;
                   2530:        case SIOCGIFGENERIC:
1.19      dyoung   2531:                error = ieee80211_cfgget(ic, cmd, data);
1.1       dyoung   2532:                break;
                   2533:        case SIOCSIFGENERIC:
1.19      dyoung   2534:                error = suser(curthread);
1.1       dyoung   2535:                if (error)
                   2536:                        break;
1.19      dyoung   2537:                error = ieee80211_cfgset(ic, cmd, data);
                   2538:                break;
                   2539:        case SIOCG80211STATS:
                   2540:                ifr = (struct ifreq *)data;
                   2541:                copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
                   2542:                break;
                   2543:        case SIOCSIFMTU:
                   2544:                ifr = (struct ifreq *)data;
                   2545:                if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
                   2546:                    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
                   2547:                        error = EINVAL;
                   2548:                else
                   2549:                        ifp->if_mtu = ifr->ifr_mtu;
                   2550:                break;
                   2551:        case SIOCSIFADDR:
                   2552:                /*
                   2553:                 * XXX Handle this directly so we can supress if_init calls.
                   2554:                 * XXX This should be done in ether_ioctl but for the moment
                   2555:                 * XXX there are too many other parts of the system that
                   2556:                 * XXX set IFF_UP and so supress if_init being called when
                   2557:                 * XXX it should be.
                   2558:                 */
                   2559:                ifa = (struct ifaddr *) data;
                   2560:                switch (ifa->ifa_addr->sa_family) {
                   2561: #ifdef INET
                   2562:                case AF_INET:
                   2563:                        if ((ifp->if_flags & IFF_UP) == 0) {
                   2564:                                ifp->if_flags |= IFF_UP;
                   2565:                                ifp->if_init(ifp->if_softc);
                   2566:                        }
                   2567:                        arp_ifinit(ifp, ifa);
                   2568:                        break;
                   2569: #endif
                   2570: #ifdef IPX
                   2571:                /*
                   2572:                 * XXX - This code is probably wrong,
                   2573:                 *       but has been copied many times.
                   2574:                 */
                   2575:                case AF_IPX: {
                   2576:                        struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
                   2577:
                   2578:                        if (ipx_nullhost(*ina))
1.21      dyoung   2579:                                ina->x_host = *(union ipx_host *)
                   2580:                                    IFP2ENADDR(ifp);
1.19      dyoung   2581:                        else
1.45      christos 2582:                                bcopy((void *) ina->x_host.c_host,
                   2583:                                      (void *) IFP2ENADDR(ifp),
1.21      dyoung   2584:                                      ETHER_ADDR_LEN);
1.19      dyoung   2585:                        /* fall thru... */
                   2586:                }
                   2587: #endif
                   2588:                default:
                   2589:                        if ((ifp->if_flags & IFF_UP) == 0) {
                   2590:                                ifp->if_flags |= IFF_UP;
                   2591:                                ifp->if_init(ifp->if_softc);
                   2592:                        }
                   2593:                        break;
                   2594:                }
1.1       dyoung   2595:                break;
                   2596:        default:
                   2597:                error = ether_ioctl(ifp, cmd, data);
                   2598:                break;
                   2599:        }
                   2600:        return error;
                   2601: }
1.2       dyoung   2602: #endif /* __FreeBSD__ */
                   2603:
1.22      dyoung   2604: #ifdef COMPAT_20
                   2605: static void
                   2606: ieee80211_get_ostats(struct ieee80211_ostats *ostats,
                   2607:     struct ieee80211_stats *stats)
                   2608: {
                   2609: #define        COPYSTATS1(__ostats, __nstats, __dstmemb, __srcmemb, __lastmemb)\
                   2610:        (void)memcpy(&(__ostats)->__dstmemb, &(__nstats)->__srcmemb,    \
                   2611:            offsetof(struct ieee80211_stats, __lastmemb) -              \
                   2612:            offsetof(struct ieee80211_stats, __srcmemb))
                   2613: #define        COPYSTATS(__ostats, __nstats, __dstmemb, __lastmemb)            \
                   2614:        COPYSTATS1(__ostats, __nstats, __dstmemb, __dstmemb, __lastmemb)
                   2615:
                   2616:        COPYSTATS(ostats, stats, is_rx_badversion, is_rx_unencrypted);
                   2617:        COPYSTATS(ostats, stats, is_rx_wepfail, is_rx_beacon);
                   2618:        COPYSTATS(ostats, stats, is_rx_rstoobig, is_rx_auth_countermeasures);
                   2619:        COPYSTATS(ostats, stats, is_rx_assoc_bss, is_rx_assoc_badwpaie);
                   2620:        COPYSTATS(ostats, stats, is_rx_deauth, is_rx_unauth);
                   2621:        COPYSTATS1(ostats, stats, is_tx_nombuf, is_tx_nobuf, is_tx_badcipher);
                   2622:        COPYSTATS(ostats, stats, is_scan_active, is_crypto_tkip);
                   2623: }
                   2624: #endif /* COMPAT_20 */
                   2625:
1.2       dyoung   2626: #ifdef __NetBSD__
                   2627: int
1.45      christos 2628: ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, void *data)
1.2       dyoung   2629: {
1.19      dyoung   2630:        struct ifnet *ifp = ic->ic_ifp;
1.2       dyoung   2631:        struct ifreq *ifr = (struct ifreq *)data;
1.19      dyoung   2632:        int i, error = 0, kid, klen, s;
                   2633:        struct ieee80211_key *k;
1.2       dyoung   2634:        struct ieee80211_nwid nwid;
                   2635:        struct ieee80211_nwkey *nwkey;
                   2636:        struct ieee80211_power *power;
                   2637:        struct ieee80211_bssid *bssid;
                   2638:        struct ieee80211chanreq *chanreq;
                   2639:        struct ieee80211_channel *chan;
1.19      dyoung   2640:        uint32_t oflags;
1.22      dyoung   2641: #ifdef COMPAT_20
                   2642:        struct ieee80211_ostats ostats;
                   2643: #endif /* COMPAT_20 */
1.29      dyoung   2644:        static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
1.19      dyoung   2645:        u_int8_t tmpkey[IEEE80211_WEP_NKID][IEEE80211_KEYBUF_SIZE];
1.2       dyoung   2646:
                   2647:        switch (cmd) {
1.46      christos 2648: #ifdef OSIOCSIFMEDIA
                   2649:        case OSIOCSIFMEDIA:
                   2650: #endif
1.2       dyoung   2651:        case SIOCSIFMEDIA:
                   2652:        case SIOCGIFMEDIA:
                   2653:                error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
                   2654:                break;
1.19      dyoung   2655:        case SIOCG80211:
                   2656:                error = ieee80211_ioctl_get80211(ic, cmd,
                   2657:                                (struct ieee80211req *) data);
                   2658:                break;
                   2659:        case SIOCS80211:
1.41      elad     2660:                if ((error = kauth_authorize_network(curlwp->l_cred,
                   2661:                    KAUTH_NETWORK_INTERFACE,
                   2662:                    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
                   2663:                    NULL) != 0))
1.19      dyoung   2664:                        break;
                   2665:                error = ieee80211_ioctl_set80211(ic, cmd,
                   2666:                                (struct ieee80211req *) data);
                   2667:                break;
1.2       dyoung   2668:        case SIOCS80211NWID:
                   2669:                if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
                   2670:                        break;
                   2671:                if (nwid.i_len > IEEE80211_NWID_LEN) {
                   2672:                        error = EINVAL;
                   2673:                        break;
                   2674:                }
                   2675:                memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
                   2676:                ic->ic_des_esslen = nwid.i_len;
                   2677:                memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
                   2678:                error = ENETRESET;
                   2679:                break;
                   2680:        case SIOCG80211NWID:
                   2681:                memset(&nwid, 0, sizeof(nwid));
                   2682:                switch (ic->ic_state) {
                   2683:                case IEEE80211_S_INIT:
                   2684:                case IEEE80211_S_SCAN:
                   2685:                        nwid.i_len = ic->ic_des_esslen;
                   2686:                        memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
                   2687:                        break;
                   2688:                default:
                   2689:                        nwid.i_len = ic->ic_bss->ni_esslen;
                   2690:                        memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
                   2691:                        break;
                   2692:                }
                   2693:                error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
                   2694:                break;
                   2695:        case SIOCS80211NWKEY:
                   2696:                nwkey = (struct ieee80211_nwkey *)data;
1.19      dyoung   2697:                /* transmit key index out of range? */
                   2698:                kid = nwkey->i_defkid - 1;
                   2699:                if (kid < 0 || kid >= IEEE80211_WEP_NKID) {
1.2       dyoung   2700:                        error = EINVAL;
                   2701:                        break;
                   2702:                }
1.19      dyoung   2703:                /* no such transmit key is set? */
                   2704:                if (nwkey->i_key[kid].i_keylen == 0 ||
                   2705:                    (nwkey->i_key[kid].i_keylen == -1 &&
                   2706:                     ic->ic_nw_keys[kid].wk_keylen == 0)) {
                   2707:                        if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
                   2708:                                error = EINVAL;
                   2709:                                break;
                   2710:                        }
                   2711:                }
                   2712:                /* check key lengths */
                   2713:                for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
                   2714:                        klen = nwkey->i_key[kid].i_keylen;
                   2715:                        if ((klen > 0 &&
                   2716:                            klen < IEEE80211_WEP_KEYLEN) ||
                   2717:                            klen > sizeof(ic->ic_nw_keys[kid].wk_key)) {
1.2       dyoung   2718:                                error = EINVAL;
                   2719:                                break;
                   2720:                        }
1.19      dyoung   2721:                }
                   2722:
                   2723:                if (error)
                   2724:                        break;
                   2725:
                   2726:                /* copy in keys */
                   2727:                (void)memset(tmpkey, 0, sizeof(tmpkey));
                   2728:                for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
                   2729:                        klen = nwkey->i_key[kid].i_keylen;
                   2730:                        if (klen <= 0)
1.2       dyoung   2731:                                continue;
1.19      dyoung   2732:                        if ((error = copyin(nwkey->i_key[kid].i_keydat,
                   2733:                            tmpkey[kid], klen)) != 0)
1.2       dyoung   2734:                                break;
                   2735:                }
1.19      dyoung   2736:
1.2       dyoung   2737:                if (error)
                   2738:                        break;
1.19      dyoung   2739:
                   2740:                /* set keys */
                   2741:                ieee80211_key_update_begin(ic);
                   2742:                for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
                   2743:                        klen = nwkey->i_key[kid].i_keylen;
                   2744:                        if (klen <= 0)
                   2745:                                continue;
                   2746:                        k = &ic->ic_nw_keys[kid];
                   2747:                        k->wk_keyix = kid;
                   2748:                        if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
                   2749:                            IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
1.2       dyoung   2750:                                error = EINVAL;
1.19      dyoung   2751:                                continue;
1.2       dyoung   2752:                        }
1.19      dyoung   2753:                        k->wk_keylen = nwkey->i_key[kid].i_keylen;
                   2754:                        (void)memcpy(k->wk_key, tmpkey[kid],
                   2755:                            sizeof(tmpkey[kid]));
                   2756:                        if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
                   2757:                                error = EINVAL;
                   2758:                }
                   2759:                ieee80211_key_update_end(ic);
                   2760:
                   2761:                if (error)
                   2762:                        break;
                   2763:
                   2764:                /* delete keys */
                   2765:                for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
                   2766:                        klen = nwkey->i_key[kid].i_keylen;
                   2767:                        k = &ic->ic_nw_keys[kid];
                   2768:                        if (klen <= 0)
                   2769:                                (void)ieee80211_crypto_delkey(ic, k);
                   2770:                }
                   2771:
                   2772:                /* set transmit key */
                   2773:                kid = nwkey->i_defkid - 1;
                   2774:                if (ic->ic_def_txkey != kid) {
                   2775:                        ic->ic_def_txkey = kid;
                   2776:                        error = ENETRESET;
                   2777:                }
                   2778:                oflags = ic->ic_flags;
                   2779:                if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
1.16      mycroft  2780:                        ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1.19      dyoung   2781:                        ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
                   2782:                } else {
1.16      mycroft  2783:                        ic->ic_flags |= IEEE80211_F_PRIVACY;
1.19      dyoung   2784:                        ic->ic_flags |= IEEE80211_F_DROPUNENC;
1.2       dyoung   2785:                }
1.19      dyoung   2786:                if (oflags != ic->ic_flags)
                   2787:                        error = ENETRESET;
1.2       dyoung   2788:                break;
                   2789:        case SIOCG80211NWKEY:
                   2790:                nwkey = (struct ieee80211_nwkey *)data;
1.16      mycroft  2791:                if (ic->ic_flags & IEEE80211_F_PRIVACY)
1.2       dyoung   2792:                        nwkey->i_wepon = IEEE80211_NWKEY_WEP;
                   2793:                else
                   2794:                        nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
1.19      dyoung   2795:                nwkey->i_defkid = ic->ic_def_txkey + 1;
1.2       dyoung   2796:                for (i = 0; i < IEEE80211_WEP_NKID; i++) {
                   2797:                        if (nwkey->i_key[i].i_keydat == NULL)
                   2798:                                continue;
                   2799:                        /* do not show any keys to non-root user */
1.41      elad     2800:                        if ((error = kauth_authorize_network(curlwp->l_cred,
                   2801:                            KAUTH_NETWORK_INTERFACE,
                   2802:                            KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp,
                   2803:                            (void *)cmd, NULL)) != 0)
1.2       dyoung   2804:                                break;
1.19      dyoung   2805:                        nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_keylen;
1.2       dyoung   2806:                        if ((error = copyout(ic->ic_nw_keys[i].wk_key,
                   2807:                            nwkey->i_key[i].i_keydat,
1.19      dyoung   2808:                            ic->ic_nw_keys[i].wk_keylen)) != 0)
1.2       dyoung   2809:                                break;
                   2810:                }
                   2811:                break;
                   2812:        case SIOCS80211POWER:
                   2813:                power = (struct ieee80211_power *)data;
                   2814:                ic->ic_lintval = power->i_maxsleep;
                   2815:                if (power->i_enabled != 0) {
1.5       dyoung   2816:                        if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
1.2       dyoung   2817:                                error = EINVAL;
                   2818:                        else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
                   2819:                                ic->ic_flags |= IEEE80211_F_PMGTON;
                   2820:                                error = ENETRESET;
                   2821:                        }
                   2822:                } else {
                   2823:                        if (ic->ic_flags & IEEE80211_F_PMGTON) {
                   2824:                                ic->ic_flags &= ~IEEE80211_F_PMGTON;
                   2825:                                error = ENETRESET;
                   2826:                        }
                   2827:                }
                   2828:                break;
                   2829:        case SIOCG80211POWER:
                   2830:                power = (struct ieee80211_power *)data;
                   2831:                power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
                   2832:                power->i_maxsleep = ic->ic_lintval;
                   2833:                break;
                   2834:        case SIOCS80211BSSID:
                   2835:                bssid = (struct ieee80211_bssid *)data;
1.29      dyoung   2836:                IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
                   2837:                if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
1.2       dyoung   2838:                        ic->ic_flags &= ~IEEE80211_F_DESBSSID;
1.29      dyoung   2839:                else
1.2       dyoung   2840:                        ic->ic_flags |= IEEE80211_F_DESBSSID;
1.29      dyoung   2841:                error = ENETRESET;
1.2       dyoung   2842:                break;
                   2843:        case SIOCG80211BSSID:
                   2844:                bssid = (struct ieee80211_bssid *)data;
                   2845:                switch (ic->ic_state) {
                   2846:                case IEEE80211_S_INIT:
                   2847:                case IEEE80211_S_SCAN:
                   2848:                        if (ic->ic_opmode == IEEE80211_M_HOSTAP)
                   2849:                                IEEE80211_ADDR_COPY(bssid->i_bssid,
                   2850:                                    ic->ic_myaddr);
                   2851:                        else if (ic->ic_flags & IEEE80211_F_DESBSSID)
                   2852:                                IEEE80211_ADDR_COPY(bssid->i_bssid,
                   2853:                                    ic->ic_des_bssid);
                   2854:                        else
                   2855:                                memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
                   2856:                        break;
                   2857:                default:
                   2858:                        IEEE80211_ADDR_COPY(bssid->i_bssid,
                   2859:                            ic->ic_bss->ni_bssid);
                   2860:                        break;
                   2861:                }
                   2862:                break;
                   2863:        case SIOCS80211CHANNEL:
                   2864:                chanreq = (struct ieee80211chanreq *)data;
                   2865:                if (chanreq->i_channel == IEEE80211_CHAN_ANY)
                   2866:                        ic->ic_des_chan = IEEE80211_CHAN_ANYC;
                   2867:                else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
                   2868:                    isclr(ic->ic_chan_active, chanreq->i_channel)) {
                   2869:                        error = EINVAL;
                   2870:                        break;
                   2871:                } else
1.4       dyoung   2872:                        ic->ic_ibss_chan = ic->ic_des_chan =
                   2873:                            &ic->ic_channels[chanreq->i_channel];
1.2       dyoung   2874:                switch (ic->ic_state) {
                   2875:                case IEEE80211_S_INIT:
                   2876:                case IEEE80211_S_SCAN:
                   2877:                        error = ENETRESET;
                   2878:                        break;
                   2879:                default:
                   2880:                        if (ic->ic_opmode == IEEE80211_M_STA) {
                   2881:                                if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
                   2882:                                    ic->ic_bss->ni_chan != ic->ic_des_chan)
                   2883:                                        error = ENETRESET;
                   2884:                        } else {
                   2885:                                if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
                   2886:                                        error = ENETRESET;
                   2887:                        }
                   2888:                        break;
                   2889:                }
                   2890:                break;
                   2891:        case SIOCG80211CHANNEL:
                   2892:                chanreq = (struct ieee80211chanreq *)data;
                   2893:                switch (ic->ic_state) {
                   2894:                case IEEE80211_S_INIT:
                   2895:                case IEEE80211_S_SCAN:
                   2896:                        if (ic->ic_opmode == IEEE80211_M_STA)
                   2897:                                chan = ic->ic_des_chan;
                   2898:                        else
                   2899:                                chan = ic->ic_ibss_chan;
                   2900:                        break;
                   2901:                default:
1.39      christos 2902:                        chan = ic->ic_curchan;
1.2       dyoung   2903:                        break;
                   2904:                }
                   2905:                chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
                   2906:                break;
                   2907:        case SIOCGIFGENERIC:
1.19      dyoung   2908:                error = ieee80211_cfgget(ic, cmd, data);
1.2       dyoung   2909:                break;
                   2910:        case SIOCSIFGENERIC:
1.41      elad     2911:                error = kauth_authorize_network(curlwp->l_cred,
                   2912:                    KAUTH_NETWORK_INTERFACE,
                   2913:                    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
                   2914:                    NULL);
1.2       dyoung   2915:                if (error)
                   2916:                        break;
1.19      dyoung   2917:                error = ieee80211_cfgset(ic, cmd, data);
1.7       dyoung   2918:                break;
1.22      dyoung   2919: #ifdef COMPAT_20
                   2920:        case OSIOCG80211STATS:
                   2921:        case OSIOCG80211ZSTATS:
                   2922:                ifr = (struct ifreq *)data;
                   2923:                s = splnet();
                   2924:                ieee80211_get_ostats(&ostats, &ic->ic_stats);
                   2925:                error = copyout(&ostats, ifr->ifr_data, sizeof(ostats));
                   2926:                if (error == 0 && cmd == OSIOCG80211ZSTATS)
                   2927:                        (void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
                   2928:                splx(s);
                   2929:                break;
                   2930: #endif /* COMPAT_20 */
1.17      dyoung   2931:        case SIOCG80211ZSTATS:
1.7       dyoung   2932:        case SIOCG80211STATS:
                   2933:                ifr = (struct ifreq *)data;
1.17      dyoung   2934:                s = splnet();
1.22      dyoung   2935:                error = copyout(&ic->ic_stats, ifr->ifr_buf,
                   2936:                    MIN(sizeof(ic->ic_stats), ifr->ifr_buflen));
                   2937:                if (error == 0 && cmd == SIOCG80211ZSTATS)
1.17      dyoung   2938:                        (void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
                   2939:                splx(s);
1.2       dyoung   2940:                break;
1.10      dyoung   2941:        case SIOCSIFMTU:
                   2942:                ifr = (struct ifreq *)data;
1.49    ! mlelstv  2943:                if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
        !          2944:                    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
1.10      dyoung   2945:                        error = EINVAL;
1.48      dyoung   2946:                else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
                   2947:                        error = 0;
1.10      dyoung   2948:                break;
1.2       dyoung   2949:        default:
                   2950:                error = ether_ioctl(ifp, cmd, data);
                   2951:                break;
                   2952:        }
                   2953:        return error;
                   2954: }
                   2955: #endif /* __NetBSD__ */

CVSweb <webmaster@jp.NetBSD.org>