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>