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