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