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