Annotation of sys/net80211/ieee80211_ioctl.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ieee80211_ioctl.c,v 1.19 2007/07/18 18:10:31 damien Exp $ */
2: /* $NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $ */
3:
4: /*-
5: * Copyright (c) 2001 Atsushi Onoe
6: * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. The name of the author may not be used to endorse or promote products
18: * derived from this software without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /*
33: * IEEE 802.11 ioctl support
34: */
35:
36: #include <sys/param.h>
37: #include <sys/kernel.h>
38: #include <sys/socket.h>
39: #include <sys/sockio.h>
40: #include <sys/systm.h>
41: #include <sys/endian.h>
42: #include <sys/proc.h>
43: #include <sys/tree.h>
44:
45: #include <net/if.h>
46: #include <net/if_arp.h>
47: #include <net/if_media.h>
48:
49: #ifdef INET
50: #include <netinet/in.h>
51: #include <netinet/if_ether.h>
52: #endif
53:
54: #include <net80211/ieee80211_var.h>
55: #include <net80211/ieee80211_ioctl.h>
56:
57: void ieee80211_node2req(struct ieee80211com *,
58: const struct ieee80211_node *, struct ieee80211_nodereq *);
59: void ieee80211_req2node(struct ieee80211com *,
60: const struct ieee80211_nodereq *, struct ieee80211_node *);
61:
62: void
63: ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
64: struct ieee80211_nodereq *nr)
65: {
66: /* Node address and name information */
67: IEEE80211_ADDR_COPY(nr->nr_macaddr, ni->ni_macaddr);
68: IEEE80211_ADDR_COPY(nr->nr_bssid, ni->ni_bssid);
69: nr->nr_nwid_len = ni->ni_esslen;
70: bcopy(ni->ni_essid, nr->nr_nwid, IEEE80211_NWID_LEN);
71:
72: /* Channel and rates */
73: nr->nr_channel = ieee80211_chan2ieee(ic, ni->ni_chan);
74: nr->nr_chan_flags = ni->ni_chan->ic_flags;
75: nr->nr_nrates = ni->ni_rates.rs_nrates;
76: bcopy(ni->ni_rates.rs_rates, nr->nr_rates, IEEE80211_RATE_MAXSIZE);
77:
78: /* Node status information */
79: nr->nr_rssi = (*ic->ic_node_getrssi)(ic, ni);
80: nr->nr_max_rssi = ic->ic_max_rssi;
81: bcopy(ni->ni_tstamp, nr->nr_tstamp, sizeof(nr->nr_tstamp));
82: nr->nr_intval = ni->ni_intval;
83: nr->nr_capinfo = ni->ni_capinfo;
84: nr->nr_fhdwell = ni->ni_fhdwell;
85: nr->nr_fhindex = ni->ni_fhindex;
86: nr->nr_erp = ni->ni_erp;
87: nr->nr_pwrsave = ni->ni_pwrsave;
88: nr->nr_associd = ni->ni_associd;
89: nr->nr_txseq = ni->ni_txseq;
90: nr->nr_rxseq = ni->ni_rxseq;
91: nr->nr_fails = ni->ni_fails;
92: nr->nr_inact = ni->ni_inact;
93: nr->nr_txrate = ni->ni_txrate;
94: nr->nr_state = ni->ni_state;
95:
96: /* Node flags */
97: nr->nr_flags = 0;
98: if (bcmp(nr->nr_macaddr, nr->nr_bssid, IEEE80211_ADDR_LEN) == 0)
99: nr->nr_flags |= IEEE80211_NODEREQ_AP;
100: if (ni == ic->ic_bss)
101: nr->nr_flags |= IEEE80211_NODEREQ_AP_BSS;
102: }
103:
104: void
105: ieee80211_req2node(struct ieee80211com *ic, const struct ieee80211_nodereq *nr,
106: struct ieee80211_node *ni)
107: {
108: /* Node address and name information */
109: IEEE80211_ADDR_COPY(ni->ni_macaddr, nr->nr_macaddr);
110: IEEE80211_ADDR_COPY(ni->ni_bssid, nr->nr_bssid);
111: ni->ni_esslen = nr->nr_nwid_len;
112: bcopy(nr->nr_nwid, ni->ni_essid, IEEE80211_NWID_LEN);
113:
114: /* Rates */
115: ni->ni_rates.rs_nrates = nr->nr_nrates;
116: bcopy(nr->nr_rates, ni->ni_rates.rs_rates, IEEE80211_RATE_MAXSIZE);
117:
118: /* Node information */
119: ni->ni_intval = nr->nr_intval;
120: ni->ni_capinfo = nr->nr_capinfo;
121: ni->ni_fhdwell = nr->nr_fhdwell;
122: ni->ni_fhindex = nr->nr_fhindex;
123: ni->ni_erp = nr->nr_erp;
124: ni->ni_pwrsave = nr->nr_pwrsave;
125: ni->ni_associd = nr->nr_associd;
126: ni->ni_txseq = nr->nr_txseq;
127: ni->ni_rxseq = nr->nr_rxseq;
128: ni->ni_fails = nr->nr_fails;
129: ni->ni_inact = nr->nr_inact;
130: ni->ni_txrate = nr->nr_txrate;
131: ni->ni_state = nr->nr_state;
132: }
133:
134: int
135: ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
136: {
137: struct ieee80211com *ic = (void *)ifp;
138: struct ifreq *ifr = (struct ifreq *)data;
139: int i, error = 0;
140: struct ieee80211_nwid nwid;
141: struct ieee80211_nwkey *nwkey;
142: struct ieee80211_power *power;
143: struct ieee80211_bssid *bssid;
144: struct ieee80211chanreq *chanreq;
145: struct ieee80211_channel *chan;
146: struct ieee80211_txpower *txpower;
147: struct ieee80211_key keys[IEEE80211_WEP_NKID];
148: static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
149: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
150: };
151: struct ieee80211_nodereq *nr, nrbuf;
152: struct ieee80211_nodereq_all *na;
153: struct ieee80211_node *ni;
154: u_int32_t flags;
155:
156: switch (cmd) {
157: case SIOCSIFADDR:
158: case SIOCGIFADDR:
159: error = ether_ioctl(ifp, &ic->ic_ac, cmd, data);
160: break;
161: case SIOCSIFMEDIA:
162: case SIOCGIFMEDIA:
163: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
164: break;
165: case SIOCS80211NWID:
166: if ((error = suser(curproc, 0)) != 0)
167: break;
168: if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
169: break;
170: if (nwid.i_len > IEEE80211_NWID_LEN) {
171: error = EINVAL;
172: break;
173: }
174: memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
175: ic->ic_des_esslen = nwid.i_len;
176: memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
177: error = ENETRESET;
178: break;
179: case SIOCG80211NWID:
180: memset(&nwid, 0, sizeof(nwid));
181: switch (ic->ic_state) {
182: case IEEE80211_S_INIT:
183: case IEEE80211_S_SCAN:
184: nwid.i_len = ic->ic_des_esslen;
185: memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
186: break;
187: default:
188: nwid.i_len = ic->ic_bss->ni_esslen;
189: memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
190: break;
191: }
192: error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
193: break;
194: case SIOCS80211NWKEY:
195: if ((error = suser(curproc, 0)) != 0)
196: break;
197: nwkey = (struct ieee80211_nwkey *)data;
198: if ((ic->ic_caps & IEEE80211_C_WEP) == 0 &&
199: nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
200: error = EINVAL;
201: break;
202: }
203: /* check and copy keys */
204: memset(keys, 0, sizeof(keys));
205: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
206: keys[i].k_len = nwkey->i_key[i].i_keylen;
207: /*
208: * Limit the maximal allowed key size to
209: * IEEE80211_KEYBUF_SIZE bytes.
210: */
211: if (keys[i].k_len > sizeof(keys[i].k_key)) {
212: error = EINVAL;
213: break;
214: }
215: if (keys[i].k_len <= 0)
216: continue;
217: if ((error = copyin(nwkey->i_key[i].i_keydat,
218: keys[i].k_key, keys[i].k_len)) != 0)
219: break;
220: }
221: if (error)
222: break;
223: i = nwkey->i_defkid - 1;
224: if (i < 0 || i >= IEEE80211_WEP_NKID ||
225: keys[i].k_len == 0 ||
226: (keys[i].k_len == -1 && ic->ic_nw_keys[i].k_len == 0)) {
227: if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
228: error = EINVAL;
229: break;
230: }
231: } else
232: ic->ic_wep_txkey = i;
233: /* save the key */
234: if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN)
235: ic->ic_flags &= ~IEEE80211_F_WEPON;
236: else
237: ic->ic_flags |= IEEE80211_F_WEPON;
238: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
239: struct ieee80211_key *k = &ic->ic_nw_keys[i];
240: if (keys[i].k_len < 0)
241: continue;
242: if (keys[i].k_len == 0)
243: k->k_cipher = IEEE80211_CIPHER_NONE;
244: else if (keys[i].k_len <= 5)
245: k->k_cipher = IEEE80211_CIPHER_WEP40;
246: else
247: k->k_cipher = IEEE80211_CIPHER_WEP104;
248: k->k_len = keys[i].k_len;
249: memcpy(k->k_key, keys[i].k_key, sizeof(keys[i].k_key));
250: }
251: error = ENETRESET;
252: break;
253: case SIOCG80211NWKEY:
254: nwkey = (struct ieee80211_nwkey *)data;
255: if (ic->ic_flags & IEEE80211_F_WEPON)
256: nwkey->i_wepon = IEEE80211_NWKEY_WEP;
257: else
258: nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
259: nwkey->i_defkid = ic->ic_wep_txkey + 1;
260: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
261: if (nwkey->i_key[i].i_keydat == NULL)
262: continue;
263: /* do not show any keys to non-root user */
264: if ((error = suser(curproc, 0)) != 0)
265: break;
266: nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].k_len;
267: if ((error = copyout(ic->ic_nw_keys[i].k_key,
268: nwkey->i_key[i].i_keydat,
269: ic->ic_nw_keys[i].k_len)) != 0)
270: break;
271: }
272: break;
273: case SIOCS80211POWER:
274: if ((error = suser(curproc, 0)) != 0)
275: break;
276: power = (struct ieee80211_power *)data;
277: ic->ic_lintval = power->i_maxsleep;
278: if (power->i_enabled != 0) {
279: if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
280: error = EINVAL;
281: else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
282: ic->ic_flags |= IEEE80211_F_PMGTON;
283: error = ENETRESET;
284: }
285: } else {
286: if (ic->ic_flags & IEEE80211_F_PMGTON) {
287: ic->ic_flags &= ~IEEE80211_F_PMGTON;
288: error = ENETRESET;
289: }
290: }
291: break;
292: case SIOCG80211POWER:
293: power = (struct ieee80211_power *)data;
294: power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
295: power->i_maxsleep = ic->ic_lintval;
296: break;
297: case SIOCS80211BSSID:
298: if ((error = suser(curproc, 0)) != 0)
299: break;
300: bssid = (struct ieee80211_bssid *)data;
301: if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
302: ic->ic_flags &= ~IEEE80211_F_DESBSSID;
303: else {
304: ic->ic_flags |= IEEE80211_F_DESBSSID;
305: IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
306: }
307: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
308: break;
309: switch (ic->ic_state) {
310: case IEEE80211_S_INIT:
311: case IEEE80211_S_SCAN:
312: error = ENETRESET;
313: break;
314: default:
315: if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
316: !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
317: ic->ic_bss->ni_bssid))
318: error = ENETRESET;
319: break;
320: }
321: break;
322: case SIOCG80211BSSID:
323: bssid = (struct ieee80211_bssid *)data;
324: switch (ic->ic_state) {
325: case IEEE80211_S_INIT:
326: case IEEE80211_S_SCAN:
327: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
328: IEEE80211_ADDR_COPY(bssid->i_bssid,
329: ic->ic_myaddr);
330: else if (ic->ic_flags & IEEE80211_F_DESBSSID)
331: IEEE80211_ADDR_COPY(bssid->i_bssid,
332: ic->ic_des_bssid);
333: else
334: memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
335: break;
336: default:
337: IEEE80211_ADDR_COPY(bssid->i_bssid,
338: ic->ic_bss->ni_bssid);
339: break;
340: }
341: break;
342: case SIOCS80211CHANNEL:
343: if ((error = suser(curproc, 0)) != 0)
344: break;
345: chanreq = (struct ieee80211chanreq *)data;
346: if (chanreq->i_channel == IEEE80211_CHAN_ANY)
347: ic->ic_des_chan = IEEE80211_CHAN_ANYC;
348: else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
349: isclr(ic->ic_chan_active, chanreq->i_channel)) {
350: error = EINVAL;
351: break;
352: } else
353: ic->ic_ibss_chan = ic->ic_des_chan =
354: &ic->ic_channels[chanreq->i_channel];
355: switch (ic->ic_state) {
356: case IEEE80211_S_INIT:
357: case IEEE80211_S_SCAN:
358: error = ENETRESET;
359: break;
360: default:
361: if (ic->ic_opmode == IEEE80211_M_STA) {
362: if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
363: ic->ic_bss->ni_chan != ic->ic_des_chan)
364: error = ENETRESET;
365: } else {
366: if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
367: error = ENETRESET;
368: }
369: break;
370: }
371: break;
372: case SIOCG80211CHANNEL:
373: chanreq = (struct ieee80211chanreq *)data;
374: switch (ic->ic_state) {
375: case IEEE80211_S_INIT:
376: case IEEE80211_S_SCAN:
377: if (ic->ic_opmode == IEEE80211_M_STA)
378: chan = ic->ic_des_chan;
379: else
380: chan = ic->ic_ibss_chan;
381: break;
382: default:
383: chan = ic->ic_bss->ni_chan;
384: break;
385: }
386: chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
387: break;
388: #if 0
389: case SIOCG80211ZSTATS:
390: #endif
391: case SIOCG80211STATS:
392: ifr = (struct ifreq *)data;
393: copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
394: #if 0
395: if (cmd == SIOCG80211ZSTATS)
396: memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
397: #endif
398: break;
399: case SIOCS80211TXPOWER:
400: if ((error = suser(curproc, 0)) != 0)
401: break;
402: txpower = (struct ieee80211_txpower *)data;
403: if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
404: error = EINVAL;
405: break;
406: }
407: if (!(IEEE80211_TXPOWER_MIN < txpower->i_val &&
408: txpower->i_val < IEEE80211_TXPOWER_MAX)) {
409: error = EINVAL;
410: break;
411: }
412: ic->ic_txpower = txpower->i_val;
413: error = ENETRESET;
414: break;
415: case SIOCG80211TXPOWER:
416: txpower = (struct ieee80211_txpower *)data;
417: if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
418: error = EINVAL;
419: else
420: txpower->i_val = ic->ic_txpower;
421: break;
422: case SIOCSIFMTU:
423: ifr = (struct ifreq *)data;
424: if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
425: ifr->ifr_mtu <= IEEE80211_MTU_MAX))
426: error = EINVAL;
427: else
428: ifp->if_mtu = ifr->ifr_mtu;
429: break;
430: case SIOCS80211SCAN:
431: if ((error = suser(curproc, 0)) != 0)
432: break;
433: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
434: break;
435: if ((ifp->if_flags & IFF_UP) == 0) {
436: error = ENETDOWN;
437: break;
438: }
439: if ((ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) == 0) {
440: if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED)
441: ic->ic_scan_lock |= IEEE80211_SCAN_RESUME;
442: ic->ic_scan_lock |= IEEE80211_SCAN_REQUEST;
443: if (ic->ic_state != IEEE80211_S_SCAN)
444: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
445: }
446: /* Let the userspace process wait for completion */
447: error = tsleep(&ic->ic_scan_lock, PCATCH, "80211scan",
448: hz * IEEE80211_SCAN_TIMEOUT);
449: break;
450: case SIOCG80211NODE:
451: nr = (struct ieee80211_nodereq *)data;
452: ni = ieee80211_find_node(ic, nr->nr_macaddr);
453: if (ni == NULL) {
454: error = ENOENT;
455: break;
456: }
457: ieee80211_node2req(ic, ni, nr);
458: break;
459: case SIOCS80211NODE:
460: if ((error = suser(curproc, 0)) != 0)
461: break;
462: if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
463: error = EINVAL;
464: break;
465: }
466: nr = (struct ieee80211_nodereq *)data;
467:
468: ni = ieee80211_find_node(ic, nr->nr_macaddr);
469: if (ni == NULL)
470: ni = ieee80211_alloc_node(ic, nr->nr_macaddr);
471: if (ni == NULL) {
472: error = ENOENT;
473: break;
474: }
475:
476: if (nr->nr_flags & IEEE80211_NODEREQ_COPY)
477: ieee80211_req2node(ic, nr, ni);
478: break;
479: case SIOCS80211DELNODE:
480: if ((error = suser(curproc, 0)) != 0)
481: break;
482: nr = (struct ieee80211_nodereq *)data;
483: ni = ieee80211_find_node(ic, nr->nr_macaddr);
484: if (ni == NULL)
485: error = ENOENT;
486: else if (ni == ic->ic_bss)
487: error = EPERM;
488: else {
489: if (ni->ni_state == IEEE80211_STA_COLLECT)
490: break;
491:
492: /* Disassociate station. */
493: if (ni->ni_state == IEEE80211_STA_ASSOC)
494: IEEE80211_SEND_MGMT(ic, ni,
495: IEEE80211_FC0_SUBTYPE_DISASSOC,
496: IEEE80211_REASON_ASSOC_LEAVE);
497:
498: /* Deauth station. */
499: if (ni->ni_state >= IEEE80211_STA_AUTH)
500: IEEE80211_SEND_MGMT(ic, ni,
501: IEEE80211_FC0_SUBTYPE_DEAUTH,
502: IEEE80211_REASON_AUTH_LEAVE);
503:
504: ieee80211_release_node(ic, ni);
505: }
506: break;
507: case SIOCG80211ALLNODES:
508: na = (struct ieee80211_nodereq_all *)data;
509: na->na_nodes = i = 0;
510: ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
511: while (ni && na->na_size >=
512: i + sizeof(struct ieee80211_nodereq)) {
513: ieee80211_node2req(ic, ni, &nrbuf);
514: error = copyout(&nrbuf, (caddr_t)na->na_node + i,
515: sizeof(struct ieee80211_nodereq));
516: if (error)
517: break;
518: i += sizeof(struct ieee80211_nodereq);
519: na->na_nodes++;
520: ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
521: }
522: break;
523: case SIOCG80211FLAGS:
524: flags = ic->ic_flags;
525: if (ic->ic_opmode != IEEE80211_M_HOSTAP)
526: flags &= ~IEEE80211_F_HOSTAPMASK;
527: ifr->ifr_flags = flags >> IEEE80211_F_USERSHIFT;
528: break;
529: case SIOCS80211FLAGS:
530: if ((error = suser(curproc, 0)) != 0)
531: break;
532: flags = (u_int32_t)ifr->ifr_flags << IEEE80211_F_USERSHIFT;
533: if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
534: (flags & IEEE80211_F_HOSTAPMASK)) {
535: error = EINVAL;
536: break;
537: }
538: ic->ic_flags = (ic->ic_flags & ~IEEE80211_F_USERMASK) | flags;
539: error = ENETRESET;
540: break;
541: default:
542: error = EINVAL;
543: break;
544: }
545: return error;
546: }
CVSweb