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