Add man page for 802.11
[dragonfly.git] / sys / netproto / 802_11 / ieee80211_ioctl.c
1 /*
2  * Copyright (c) 2001 Atsushi Onoe
3  * Copyright (c) 2002, 2003 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.13 2004/03/30 22:57:57 sam Exp $
33  * $DragonFly: src/sys/netproto/802_11/Attic/ieee80211_ioctl.c,v 1.1 2004/07/26 16:30:17 joerg Exp $
34  */
35
36 /*
37  * IEEE 802.11 ioctl support (FreeBSD-specific)
38  */
39
40 #include "opt_inet.h"
41 #include "opt_ipx.h"
42
43 #include <sys/endian.h>
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/proc.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/systm.h>
50 #include <sys/thread.h>
51  
52 #include <net/if.h>
53 #include <net/if_arp.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 /*
73  * XXX
74  * Wireless LAN specific configuration interface, which is compatible
75  * with wicontrol(8).
76  */
77
78 int
79 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
80 {
81         struct ieee80211com *ic = (void *)ifp;
82         int i, j, error;
83         struct ifreq *ifr = (struct ifreq *)data;
84         struct wi_req wreq;
85         struct wi_ltv_keys *keys;
86         struct wi_apinfo *ap;
87         struct ieee80211_node *ni;
88         struct ieee80211_rateset *rs;
89         struct wi_sigcache wsc;
90         struct wi_scan_p2_hdr *p2;
91         struct wi_scan_res *res;
92
93         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
94         if (error)
95                 return error;
96         wreq.wi_len = 0;
97         switch (wreq.wi_type) {
98         case WI_RID_SERIALNO:
99                 /* nothing appropriate */
100                 break;
101         case WI_RID_NODENAME:
102                 strcpy((char *)&wreq.wi_val[1], hostname);
103                 wreq.wi_val[0] = htole16(strlen(hostname));
104                 wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
105                 break;
106         case WI_RID_CURRENT_SSID:
107                 if (ic->ic_state != IEEE80211_S_RUN) {
108                         wreq.wi_val[0] = 0;
109                         wreq.wi_len = 1;
110                         break;
111                 }
112                 wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
113                 memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
114                     ic->ic_bss->ni_esslen);
115                 wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
116                 break;
117         case WI_RID_OWN_SSID:
118         case WI_RID_DESIRED_SSID:
119                 wreq.wi_val[0] = htole16(ic->ic_des_esslen);
120                 memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
121                 wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
122                 break;
123         case WI_RID_CURRENT_BSSID:
124                 if (ic->ic_state == IEEE80211_S_RUN)
125                         IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
126                 else
127                         memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
128                 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
129                 break;
130         case WI_RID_CHANNEL_LIST:
131                 memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
132                 /*
133                  * Since channel 0 is not available for DS, channel 1
134                  * is assigned to LSB on WaveLAN.
135                  */
136                 if (ic->ic_phytype == IEEE80211_T_DS)
137                         i = 1;
138                 else
139                         i = 0;
140                 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
141                         if (isset(ic->ic_chan_active, i)) {
142                                 setbit((uint8_t *)wreq.wi_val, j);
143                                 wreq.wi_len = j / 16 + 1;
144                         }
145                 break;
146         case WI_RID_OWN_CHNL:
147                 wreq.wi_val[0] = htole16(
148                         ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
149                 wreq.wi_len = 1;
150                 break;
151         case WI_RID_CURRENT_CHAN:
152                 wreq.wi_val[0] = htole16(
153                         ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
154                 wreq.wi_len = 1;
155                 break;
156         case WI_RID_COMMS_QUALITY:
157                 wreq.wi_val[0] = 0;                             /* quality */
158                 wreq.wi_val[1] =
159                         htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
160                 wreq.wi_val[2] = 0;                             /* noise */
161                 wreq.wi_len = 3;
162                 break;
163         case WI_RID_PROMISC:
164                 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
165                 wreq.wi_len = 1;
166                 break;
167         case WI_RID_PORTTYPE:
168                 wreq.wi_val[0] = htole16(ic->ic_opmode);
169                 wreq.wi_len = 1;
170                 break;
171         case WI_RID_MAC_NODE:
172                 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
173                 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
174                 break;
175         case WI_RID_TX_RATE:
176                 if (ic->ic_fixed_rate == -1)
177                         wreq.wi_val[0] = 0;     /* auto */
178                 else
179                         wreq.wi_val[0] = htole16(
180                             (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
181                             IEEE80211_RATE_VAL) / 2);
182                 wreq.wi_len = 1;
183                 break;
184         case WI_RID_CUR_TX_RATE:
185                 wreq.wi_val[0] = htole16(
186                     (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
187                     IEEE80211_RATE_VAL) / 2);
188                 wreq.wi_len = 1;
189                 break;
190         case WI_RID_RTS_THRESH:
191                 wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
192                 wreq.wi_len = 1;
193                 break;
194         case WI_RID_CREATE_IBSS:
195                 wreq.wi_val[0] =
196                     htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
197                 wreq.wi_len = 1;
198                 break;
199         case WI_RID_MICROWAVE_OVEN:
200                 wreq.wi_val[0] = 0;     /* no ... not supported */
201                 wreq.wi_len = 1;
202                 break;
203         case WI_RID_ROAMING_MODE:
204                 wreq.wi_val[0] = htole16(1);    /* enabled ... not supported */
205                 wreq.wi_len = 1;
206                 break;
207         case WI_RID_SYSTEM_SCALE:
208                 wreq.wi_val[0] = htole16(1);    /* low density ... not supp */
209                 wreq.wi_len = 1;
210                 break;
211         case WI_RID_PM_ENABLED:
212                 wreq.wi_val[0] =
213                     htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
214                 wreq.wi_len = 1;
215                 break;
216         case WI_RID_MAX_SLEEP:
217                 wreq.wi_val[0] = htole16(ic->ic_lintval);
218                 wreq.wi_len = 1;
219                 break;
220         case WI_RID_CUR_BEACON_INT:
221                 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
222                 wreq.wi_len = 1;
223                 break;
224         case WI_RID_WEP_AVAIL:
225                 wreq.wi_val[0] =
226                     htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
227                 wreq.wi_len = 1;
228                 break;
229         case WI_RID_CNFAUTHMODE:
230                 wreq.wi_val[0] = htole16(1);    /* TODO: open system only */
231                 wreq.wi_len = 1;
232                 break;
233         case WI_RID_ENCRYPTION:
234                 wreq.wi_val[0] =
235                     htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
236                 wreq.wi_len = 1;
237                 break;
238         case WI_RID_TX_CRYPT_KEY:
239                 wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
240                 wreq.wi_len = 1;
241                 break;
242         case WI_RID_DEFLT_CRYPT_KEYS:
243                 keys = (struct wi_ltv_keys *)&wreq;
244                 /* do not show keys to non-root user */
245                 error = suser_cred(cr, NULL_CRED_OKAY);
246                 if (error) {
247                         memset(keys, 0, sizeof(*keys));
248                         error = 0;
249                         break;
250                 }
251                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
252                         keys->wi_keys[i].wi_keylen =
253                             htole16(ic->ic_nw_keys[i].wk_len);
254                         memcpy(keys->wi_keys[i].wi_keydat,
255                             ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
256                 }
257                 wreq.wi_len = sizeof(*keys) / 2;
258                 break;
259         case WI_RID_MAX_DATALEN:
260                 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN);    /* TODO: frag */
261                 wreq.wi_len = 1;
262                 break;
263         case WI_RID_IFACE_STATS:
264                 /* XXX: should be implemented in lower drivers */
265                 break;
266         case WI_RID_READ_APS:
267                 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
268                         /*
269                          * Don't return results until active scan completes.
270                          */
271                         if (ic->ic_state == IEEE80211_S_SCAN &&
272                             (ic->ic_flags & IEEE80211_F_ASCAN)) {
273                                 error = EINPROGRESS;
274                                 break;
275                         }
276                 }
277                 i = 0;
278                 ap = (void *)((char *)wreq.wi_val + sizeof(i));
279                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
280                         if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
281                                 break;
282                         memset(ap, 0, sizeof(*ap));
283                         if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
284                                 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
285                                 ap->namelen = ic->ic_des_esslen;
286                                 if (ic->ic_des_esslen)
287                                         memcpy(ap->name, ic->ic_des_essid,
288                                             ic->ic_des_esslen);
289                         } else {
290                                 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
291                                 ap->namelen = ni->ni_esslen;
292                                 if (ni->ni_esslen)
293                                         memcpy(ap->name, ni->ni_essid,
294                                             ni->ni_esslen);
295                         }
296                         ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
297                         ap->signal = (*ic->ic_node_getrssi)(ic, ni);
298                         ap->capinfo = ni->ni_capinfo;
299                         ap->interval = ni->ni_intval;
300                         rs = &ni->ni_rates;
301                         for (j = 0; j < rs->rs_nrates; j++) {
302                                 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
303                                         ap->rate = (rs->rs_rates[j] &
304                                             IEEE80211_RATE_VAL) * 5; /* XXX */
305                                 }
306                         }
307                         i++;
308                         ap++;
309                 }
310                 memcpy(wreq.wi_val, &i, sizeof(i));
311                 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
312                 break;
313         case WI_RID_PRISM2:
314                 wreq.wi_val[0] = 1;     /* XXX lie so SCAN_RES can give rates */
315                 wreq.wi_len = sizeof(uint16_t) / 2;
316                 break;
317         case WI_RID_SCAN_RES:                   /* compatibility interface */
318                 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
319                     ic->ic_state == IEEE80211_S_SCAN &&
320                     (ic->ic_flags & IEEE80211_F_ASCAN)) {
321                         error = EINPROGRESS;
322                         break;
323                 }
324                 /* NB: we use the Prism2 format so we can return rate info */
325                 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
326                 res = (void *)&p2[1];
327                 i = 0;
328                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
329                         if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
330                                 break;
331                         res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
332                         res->wi_noise = 0;
333                         res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
334                         IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
335                         res->wi_interval = ni->ni_intval;
336                         res->wi_capinfo = ni->ni_capinfo;
337                         res->wi_ssid_len = ni->ni_esslen;
338                         memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
339                         /* NB: assumes wi_srates holds <= ni->ni_rates */
340                         memcpy(res->wi_srates, ni->ni_rates.rs_rates,
341                                 sizeof(res->wi_srates));
342                         if (ni->ni_rates.rs_nrates < 10)
343                                 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
344                         res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
345                         res->wi_rsvd = 0;
346                         res++, i++;
347                 }
348                 p2->wi_rsvd = 0;
349                 p2->wi_reason = i;
350                 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
351                 break;
352         case WI_RID_READ_CACHE:
353                 i = 0;
354                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
355                         if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
356                                 break;
357                         IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
358                         memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
359                         wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
360                         wsc.noise = 0;
361                         wsc.quality = 0;
362                         memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
363                             &wsc, sizeof(wsc));
364                         i++;
365                 }
366                 wreq.wi_len = sizeof(wsc) * i / 2;
367                 break;
368         case WI_RID_SCAN_APS:
369                 error = EINVAL;
370                 break;
371         default:
372                 error = EINVAL;
373                 break;
374         }
375         if (error == 0) {
376                 wreq.wi_len++;
377                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
378         }
379         return error;
380 }
381
382 static int
383 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
384 {
385 #define IEEERATE(_ic,_m,_i) \
386         ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
387         int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
388         for (i = 0; i < nrates; i++)
389                 if (IEEERATE(ic, mode, i) == rate)
390                         return i;
391         return -1;
392 #undef IEEERATE
393 }
394
395 /*
396  * Prepare to do a user-initiated scan for AP's.  If no
397  * current/default channel is setup or the current channel
398  * is invalid then pick the first available channel from
399  * the active list as the place to start the scan.
400  */
401 static int
402 ieee80211_setupscan(struct ieee80211com *ic)
403 {
404         u_char *chanlist = ic->ic_chan_active;
405         int i;
406
407         if (ic->ic_ibss_chan == NULL ||
408             isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
409                 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
410                         if (isset(chanlist, i)) {
411                                 ic->ic_ibss_chan = &ic->ic_channels[i];
412                                 goto found;
413                         }
414                 return EINVAL;                  /* no active channels */
415 found:
416                 ;
417         }
418         if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
419             isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
420                 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
421         /*
422          * XXX don't permit a scan to be started unless we
423          * know the device is ready.  For the moment this means
424          * the device is marked up as this is the required to
425          * initialize the hardware.  It would be better to permit
426          * scanning prior to being up but that'll require some
427          * changes to the infrastructure.
428          */
429         return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
430 }
431
432 int
433 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
434 {
435         struct ieee80211com *ic = (void *)ifp;
436         int i, j, len, error, rate;
437         struct ifreq *ifr = (struct ifreq *)data;
438         struct wi_ltv_keys *keys;
439         struct wi_req wreq;
440         u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
441
442         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
443         if (error)
444                 return error;
445         len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
446         switch (wreq.wi_type) {
447         case WI_RID_SERIALNO:
448         case WI_RID_NODENAME:
449                 return EPERM;
450         case WI_RID_CURRENT_SSID:
451                 return EPERM;
452         case WI_RID_OWN_SSID:
453         case WI_RID_DESIRED_SSID:
454                 if (le16toh(wreq.wi_val[0]) * 2 > len ||
455                     le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
456                         error = ENOSPC;
457                         break;
458                 }
459                 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
460                 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
461                 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
462                 error = ENETRESET;
463                 break;
464         case WI_RID_CURRENT_BSSID:
465                 return EPERM;
466         case WI_RID_OWN_CHNL:
467                 if (len != 2)
468                         return EINVAL;
469                 i = le16toh(wreq.wi_val[0]);
470                 if (i < 0 ||
471                     i > IEEE80211_CHAN_MAX ||
472                     isclr(ic->ic_chan_active, i))
473                         return EINVAL;
474                 ic->ic_ibss_chan = &ic->ic_channels[i];
475                 if (ic->ic_flags & IEEE80211_F_SIBSS)
476                         error = ENETRESET;
477                 break;
478         case WI_RID_CURRENT_CHAN:
479                 return EPERM;
480         case WI_RID_COMMS_QUALITY:
481                 return EPERM;
482         case WI_RID_PROMISC:
483                 if (len != 2)
484                         return EINVAL;
485                 if (ifp->if_flags & IFF_PROMISC) {
486                         if (wreq.wi_val[0] == 0) {
487                                 ifp->if_flags &= ~IFF_PROMISC;
488                                 error = ENETRESET;
489                         }
490                 } else {
491                         if (wreq.wi_val[0] != 0) {
492                                 ifp->if_flags |= IFF_PROMISC;
493                                 error = ENETRESET;
494                         }
495                 }
496                 break;
497         case WI_RID_PORTTYPE:
498                 if (len != 2)
499                         return EINVAL;
500                 switch (le16toh(wreq.wi_val[0])) {
501                 case IEEE80211_M_STA:
502                         break;
503                 case IEEE80211_M_IBSS:
504                         if (!(ic->ic_caps & IEEE80211_C_IBSS))
505                                 return EINVAL;
506                         break;
507                 case IEEE80211_M_AHDEMO:
508                         if (ic->ic_phytype != IEEE80211_T_DS ||
509                             !(ic->ic_caps & IEEE80211_C_AHDEMO))
510                                 return EINVAL;
511                         break;
512                 case IEEE80211_M_HOSTAP:
513                         if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
514                                 return EINVAL;
515                         break;
516                 default:
517                         return EINVAL;
518                 }
519                 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
520                         ic->ic_opmode = le16toh(wreq.wi_val[0]);
521                         error = ENETRESET;
522                 }
523                 break;
524 #if 0
525         case WI_RID_MAC_NODE:
526                 if (len != IEEE80211_ADDR_LEN)
527                         return EINVAL;
528                 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
529                 /* if_init will copy lladdr into ic_myaddr */
530                 error = ENETRESET;
531                 break;
532 #endif
533         case WI_RID_TX_RATE:
534                 if (len != 2)
535                         return EINVAL;
536                 if (wreq.wi_val[0] == 0) {
537                         /* auto */
538                         ic->ic_fixed_rate = -1;
539                         break;
540                 }
541                 rate = 2 * le16toh(wreq.wi_val[0]);
542                 if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
543                         /*
544                          * In autoselect mode search for the rate.  We take
545                          * the first instance which may not be right, but we
546                          * are limited by the interface.  Note that we also
547                          * lock the mode to insure the rate is meaningful
548                          * when it is used.
549                          */
550                         for (j = IEEE80211_MODE_11A;
551                              j < IEEE80211_MODE_MAX; j++) {
552                                 if ((ic->ic_modecaps & (1<<j)) == 0)
553                                         continue;
554                                 i = findrate(ic, j, rate);
555                                 if (i != -1) {
556                                         /* lock mode too */
557                                         ic->ic_curmode = j;
558                                         goto setrate;
559                                 }
560                         }
561                 } else {
562                         i = findrate(ic, ic->ic_curmode, rate);
563                         if (i != -1)
564                                 goto setrate;
565                 }
566                 return EINVAL;
567         setrate:
568                 ic->ic_fixed_rate = i;
569                 error = ENETRESET;
570                 break;
571         case WI_RID_CUR_TX_RATE:
572                 return EPERM;
573         case WI_RID_RTS_THRESH:
574                 if (len != 2)
575                         return EINVAL;
576                 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
577                         return EINVAL;          /* TODO: RTS */
578                 break;
579         case WI_RID_CREATE_IBSS:
580                 if (len != 2)
581                         return EINVAL;
582                 if (wreq.wi_val[0] != 0) {
583                         if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
584                                 return EINVAL;
585                         if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
586                                 ic->ic_flags |= IEEE80211_F_IBSSON;
587                                 if (ic->ic_opmode == IEEE80211_M_IBSS &&
588                                     ic->ic_state == IEEE80211_S_SCAN)
589                                         error = ENETRESET;
590                         }
591                 } else {
592                         if (ic->ic_flags & IEEE80211_F_IBSSON) {
593                                 ic->ic_flags &= ~IEEE80211_F_IBSSON;
594                                 if (ic->ic_flags & IEEE80211_F_SIBSS) {
595                                         ic->ic_flags &= ~IEEE80211_F_SIBSS;
596                                         error = ENETRESET;
597                                 }
598                         }
599                 }
600                 break;
601         case WI_RID_MICROWAVE_OVEN:
602                 if (len != 2)
603                         return EINVAL;
604                 if (wreq.wi_val[0] != 0)
605                         return EINVAL;          /* not supported */
606                 break;
607         case WI_RID_ROAMING_MODE:
608                 if (len != 2)
609                         return EINVAL;
610                 if (le16toh(wreq.wi_val[0]) != 1)
611                         return EINVAL;          /* not supported */
612                 break;
613         case WI_RID_SYSTEM_SCALE:
614                 if (len != 2)
615                         return EINVAL;
616                 if (le16toh(wreq.wi_val[0]) != 1)
617                         return EINVAL;          /* not supported */
618                 break;
619         case WI_RID_PM_ENABLED:
620                 if (len != 2)
621                         return EINVAL;
622                 if (wreq.wi_val[0] != 0) {
623                         if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
624                                 return EINVAL;
625                         if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
626                                 ic->ic_flags |= IEEE80211_F_PMGTON;
627                                 error = ENETRESET;
628                         }
629                 } else {
630                         if (ic->ic_flags & IEEE80211_F_PMGTON) {
631                                 ic->ic_flags &= ~IEEE80211_F_PMGTON;
632                                 error = ENETRESET;
633                         }
634                 }
635                 break;
636         case WI_RID_MAX_SLEEP:
637                 if (len != 2)
638                         return EINVAL;
639                 ic->ic_lintval = le16toh(wreq.wi_val[0]);
640                 if (ic->ic_flags & IEEE80211_F_PMGTON)
641                         error = ENETRESET;
642                 break;
643         case WI_RID_CUR_BEACON_INT:
644                 return EPERM;
645         case WI_RID_WEP_AVAIL:
646                 return EPERM;
647         case WI_RID_CNFAUTHMODE:
648                 if (len != 2)
649                         return EINVAL;
650                 if (le16toh(wreq.wi_val[0]) != 1)
651                         return EINVAL;          /* TODO: shared key auth */
652                 break;
653         case WI_RID_ENCRYPTION:
654                 if (len != 2)
655                         return EINVAL;
656                 if (wreq.wi_val[0] != 0) {
657                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
658                                 return EINVAL;
659                         if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
660                                 ic->ic_flags |= IEEE80211_F_WEPON;
661                                 error = ENETRESET;
662                         }
663                 } else {
664                         if (ic->ic_flags & IEEE80211_F_WEPON) {
665                                 ic->ic_flags &= ~IEEE80211_F_WEPON;
666                                 error = ENETRESET;
667                         }
668                 }
669                 break;
670         case WI_RID_TX_CRYPT_KEY:
671                 if (len != 2)
672                         return EINVAL;
673                 i = le16toh(wreq.wi_val[0]);
674                 if (i >= IEEE80211_WEP_NKID)
675                         return EINVAL;
676                 ic->ic_wep_txkey = i;
677                 break;
678         case WI_RID_DEFLT_CRYPT_KEYS:
679                 if (len != sizeof(struct wi_ltv_keys))
680                         return EINVAL;
681                 keys = (struct wi_ltv_keys *)&wreq;
682                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
683                         len = le16toh(keys->wi_keys[i].wi_keylen);
684                         if (len != 0 && len < IEEE80211_WEP_KEYLEN)
685                                 return EINVAL;
686                         if (len > sizeof(ic->ic_nw_keys[i].wk_key))
687                                 return EINVAL;
688                 }
689                 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
690                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
691                         len = le16toh(keys->wi_keys[i].wi_keylen);
692                         ic->ic_nw_keys[i].wk_len = len;
693                         memcpy(ic->ic_nw_keys[i].wk_key,
694                             keys->wi_keys[i].wi_keydat, len);
695                 }
696                 error = ENETRESET;
697                 break;
698         case WI_RID_MAX_DATALEN:
699                 if (len != 2)
700                         return EINVAL;
701                 len = le16toh(wreq.wi_val[0]);
702                 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
703                         return EINVAL;
704                 if (len != IEEE80211_MAX_LEN)
705                         return EINVAL;          /* TODO: fragment */
706                 ic->ic_fragthreshold = len;
707                 error = ENETRESET;
708                 break;
709         case WI_RID_IFACE_STATS:
710                 error = EPERM;
711                 break;
712         case WI_RID_SCAN_REQ:                   /* XXX wicontrol */
713                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
714                         break;
715                 error = ieee80211_setupscan(ic);
716                 if (error == 0)
717                         error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
718                 break;
719         case WI_RID_SCAN_APS:
720                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
721                         break;
722                 len--;                  /* XXX: tx rate? */
723                 /* FALLTHRU */
724         case WI_RID_CHANNEL_LIST:
725                 memset(chanlist, 0, sizeof(chanlist));
726                 /*
727                  * Since channel 0 is not available for DS, channel 1
728                  * is assigned to LSB on WaveLAN.
729                  */
730                 if (ic->ic_phytype == IEEE80211_T_DS)
731                         i = 1;
732                 else
733                         i = 0;
734                 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
735                         if ((j / 8) >= len)
736                                 break;
737                         if (isclr((uint8_t *)wreq.wi_val, j))
738                                 continue;
739                         if (isclr(ic->ic_chan_active, i)) {
740                                 if (wreq.wi_type != WI_RID_CHANNEL_LIST)
741                                         continue;
742                                 if (isclr(ic->ic_chan_avail, i))
743                                         return EPERM;
744                         }
745                         setbit(chanlist, i);
746                 }
747                 memcpy(ic->ic_chan_active, chanlist,
748                     sizeof(ic->ic_chan_active));
749                 error = ieee80211_setupscan(ic);
750                 if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
751                         /* NB: ignore error from ieee80211_setupscan */
752                         error = ENETRESET;
753                 } else if (error == 0)
754                         error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
755                 break;
756         default:
757                 error = EINVAL;
758                 break;
759         }
760         return error;
761 }
762
763 int
764 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
765 {
766         struct ieee80211com *ic = (void *)ifp;
767         int error = 0;
768         u_int kid, len;
769         struct ieee80211req *ireq;
770         struct ifreq *ifr;
771         uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
772         char tmpssid[IEEE80211_NWID_LEN];
773         struct ieee80211_channel *chan;
774         struct ifaddr *ifa;                     /* XXX */
775
776         switch (cmd) {
777         case SIOCSIFMEDIA:
778         case SIOCGIFMEDIA:
779                 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
780                                 &ic->ic_media, cmd);
781                 break;
782         case SIOCG80211:
783                 ireq = (struct ieee80211req *) data;
784                 switch (ireq->i_type) {
785                 case IEEE80211_IOC_SSID:
786                         switch (ic->ic_state) {
787                         case IEEE80211_S_INIT:
788                         case IEEE80211_S_SCAN:
789                                 ireq->i_len = ic->ic_des_esslen;
790                                 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
791                                 break;
792                         default:
793                                 ireq->i_len = ic->ic_bss->ni_esslen;
794                                 memcpy(tmpssid, ic->ic_bss->ni_essid,
795                                         ireq->i_len);
796                                 break;
797                         }
798                         error = copyout(tmpssid, ireq->i_data, ireq->i_len);
799                         break;
800                 case IEEE80211_IOC_NUMSSIDS:
801                         ireq->i_val = 1;
802                         break;
803                 case IEEE80211_IOC_WEP:
804                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
805                                 ireq->i_val = IEEE80211_WEP_NOSUP; 
806                         } else {
807                                 if (ic->ic_flags & IEEE80211_F_WEPON) {
808                                         ireq->i_val =
809                                             IEEE80211_WEP_MIXED;
810                                 } else {
811                                         ireq->i_val =
812                                             IEEE80211_WEP_OFF;
813                                 }
814                         }
815                         break;
816                 case IEEE80211_IOC_WEPKEY:
817                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
818                                 error = EINVAL;
819                                 break;
820                         }
821                         kid = (u_int) ireq->i_val;
822                         if (kid >= IEEE80211_WEP_NKID) {
823                                 error = EINVAL;
824                                 break;
825                         }
826                         len = (u_int) ic->ic_nw_keys[kid].wk_len;
827                         /* NB: only root can read WEP keys */
828                         if (suser_cred(cr, NULL_CRED_OKAY) == 0) {
829                                 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
830                         } else {
831                                 bzero(tmpkey, len);
832                         }
833                         ireq->i_len = len;
834                         error = copyout(tmpkey, ireq->i_data, len);
835                         break;
836                 case IEEE80211_IOC_NUMWEPKEYS:
837                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
838                                 error = EINVAL;
839                         else
840                                 ireq->i_val = IEEE80211_WEP_NKID;
841                         break;
842                 case IEEE80211_IOC_WEPTXKEY:
843                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
844                                 error = EINVAL;
845                         else
846                                 ireq->i_val = ic->ic_wep_txkey;
847                         break;
848                 case IEEE80211_IOC_AUTHMODE:
849                         ireq->i_val = IEEE80211_AUTH_OPEN;
850                         break;
851                 case IEEE80211_IOC_CHANNEL:
852                         switch (ic->ic_state) {
853                         case IEEE80211_S_INIT:
854                         case IEEE80211_S_SCAN:
855                                 if (ic->ic_opmode == IEEE80211_M_STA)
856                                         chan = ic->ic_des_chan;
857                                 else
858                                         chan = ic->ic_ibss_chan;
859                                 break;
860                         default:
861                                 chan = ic->ic_bss->ni_chan;
862                                 break;
863                         }
864                         ireq->i_val = ieee80211_chan2ieee(ic, chan);
865                         break;
866                 case IEEE80211_IOC_POWERSAVE:
867                         if (ic->ic_flags & IEEE80211_F_PMGTON)
868                                 ireq->i_val = IEEE80211_POWERSAVE_ON;
869                         else
870                                 ireq->i_val = IEEE80211_POWERSAVE_OFF;
871                         break;
872                 case IEEE80211_IOC_POWERSAVESLEEP:
873                         ireq->i_val = ic->ic_lintval;
874                         break;
875                 case IEEE80211_IOC_RTSTHRESHOLD:
876                         ireq->i_val = ic->ic_rtsthreshold;
877                         break;
878                 case IEEE80211_IOC_PROTMODE:
879                         ireq->i_val = ic->ic_protmode;
880                         break;
881                 case IEEE80211_IOC_TXPOWER:
882                         if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
883                                 error = EINVAL;
884                         else
885                                 ireq->i_val = ic->ic_txpower;
886                         break;
887                 default:
888                         error = EINVAL;
889                         break;
890                 }
891                 break;
892         case SIOCS80211:
893                 error = suser_cred(cr, NULL_CRED_OKAY);
894                 if (error)
895                         break;
896                 ireq = (struct ieee80211req *) data;
897                 switch (ireq->i_type) {
898                 case IEEE80211_IOC_SSID:
899                         if (ireq->i_val != 0 ||
900                             ireq->i_len > IEEE80211_NWID_LEN) {
901                                 error = EINVAL;
902                                 break;
903                         }
904                         error = copyin(ireq->i_data, tmpssid, ireq->i_len);
905                         if (error)
906                                 break;
907                         memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
908                         ic->ic_des_esslen = ireq->i_len;
909                         memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
910                         error = ENETRESET;
911                         break;
912                 case IEEE80211_IOC_WEP:
913                         /*
914                          * These cards only support one mode so
915                          * we just turn wep on if what ever is
916                          * passed in is not OFF.
917                          */
918                         if (ireq->i_val == IEEE80211_WEP_OFF) {
919                                 ic->ic_flags &= ~IEEE80211_F_WEPON;
920                         } else {
921                                 ic->ic_flags |= IEEE80211_F_WEPON;
922                         }
923                         error = ENETRESET;
924                         break;
925                 case IEEE80211_IOC_WEPKEY:
926                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
927                                 error = EINVAL;
928                                 break;
929                         }
930                         kid = (u_int) ireq->i_val;
931                         if (kid >= IEEE80211_WEP_NKID) {
932                                 error = EINVAL;
933                                 break;
934                         } 
935                         if (ireq->i_len > sizeof(tmpkey)) {
936                                 error = EINVAL;
937                                 break;
938                         }
939                         memset(tmpkey, 0, sizeof(tmpkey));
940                         error = copyin(ireq->i_data, tmpkey, ireq->i_len);
941                         if (error)
942                                 break;
943                         memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
944                                 sizeof(tmpkey));
945                         ic->ic_nw_keys[kid].wk_len = ireq->i_len;
946                         error = ENETRESET;
947                         break;
948                 case IEEE80211_IOC_WEPTXKEY:
949                         kid = (u_int) ireq->i_val;
950                         if (kid >= IEEE80211_WEP_NKID) {
951                                 error = EINVAL;
952                                 break;
953                         }
954                         ic->ic_wep_txkey = kid;
955                         error = ENETRESET;
956                         break;
957 #if 0
958                 case IEEE80211_IOC_AUTHMODE:
959                         sc->wi_authmode = ireq->i_val;
960                         break;
961 #endif
962                 case IEEE80211_IOC_CHANNEL:
963                         /* XXX 0xffff overflows 16-bit signed */
964                         if (ireq->i_val == 0 ||
965                             ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
966                                 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
967                         else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
968                             isclr(ic->ic_chan_active, ireq->i_val)) {
969                                 error = EINVAL;
970                                 break;
971                         } else
972                                 ic->ic_ibss_chan = ic->ic_des_chan =
973                                         &ic->ic_channels[ireq->i_val];
974                         switch (ic->ic_state) {
975                         case IEEE80211_S_INIT:
976                         case IEEE80211_S_SCAN:
977                                 error = ENETRESET;
978                                 break;
979                         default:
980                                 if (ic->ic_opmode == IEEE80211_M_STA) {
981                                         if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
982                                             ic->ic_bss->ni_chan != ic->ic_des_chan)
983                                                 error = ENETRESET;
984                                 } else {
985                                         if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
986                                                 error = ENETRESET;
987                                 }
988                                 break;
989                         }
990                         break;
991                 case IEEE80211_IOC_POWERSAVE:
992                         switch (ireq->i_val) {
993                         case IEEE80211_POWERSAVE_OFF:
994                                 if (ic->ic_flags & IEEE80211_F_PMGTON) {
995                                         ic->ic_flags &= ~IEEE80211_F_PMGTON;
996                                         error = ENETRESET;
997                                 }
998                                 break;
999                         case IEEE80211_POWERSAVE_ON:
1000                                 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
1001                                         error = EINVAL;
1002                                 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
1003                                         ic->ic_flags |= IEEE80211_F_PMGTON;
1004                                         error = ENETRESET;
1005                                 }
1006                                 break;
1007                         default:
1008                                 error = EINVAL;
1009                                 break;
1010                         }
1011                         break;
1012                 case IEEE80211_IOC_POWERSAVESLEEP:
1013                         if (ireq->i_val < 0) {
1014                                 error = EINVAL;
1015                                 break;
1016                         }
1017                         ic->ic_lintval = ireq->i_val;
1018                         error = ENETRESET;
1019                         break;
1020                 case IEEE80211_IOC_RTSTHRESHOLD:
1021                         if (!(IEEE80211_RTS_MIN < ireq->i_val &&
1022                               ireq->i_val < IEEE80211_RTS_MAX)) {
1023                                 error = EINVAL;
1024                                 break;
1025                         }
1026                         ic->ic_rtsthreshold = ireq->i_val;
1027                         error = ENETRESET;
1028                         break;
1029                 case IEEE80211_IOC_PROTMODE:
1030                         if (ireq->i_val > IEEE80211_PROT_RTSCTS) {
1031                                 error = EINVAL;
1032                                 break;
1033                         }
1034                         ic->ic_protmode = ireq->i_val;
1035                         /* NB: if not operating in 11g this can wait */
1036                         if (ic->ic_curmode == IEEE80211_MODE_11G)
1037                                 error = ENETRESET;
1038                         break;
1039                 case IEEE80211_IOC_TXPOWER:
1040                         if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
1041                                 error = EINVAL;
1042                                 break;
1043                         }
1044                         if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
1045                               ireq->i_val < IEEE80211_TXPOWER_MAX)) {
1046                                 error = EINVAL;
1047                                 break;
1048                         }
1049                         ic->ic_txpower = ireq->i_val;
1050                         error = ENETRESET;
1051                         break;
1052                 default:
1053                         error = EINVAL;
1054                         break;
1055                 }
1056                 break;
1057         case SIOCGIFGENERIC:
1058                 error = ieee80211_cfgget(ifp, cmd, data, cr);
1059                 break;
1060         case SIOCSIFGENERIC:
1061                 error = suser_cred(cr, NULL_CRED_OKAY);
1062                 if (error)
1063                         break;
1064                 error = ieee80211_cfgset(ifp, cmd, data);
1065                 break;
1066         case SIOCG80211STATS:
1067                 ifr = (struct ifreq *)data;
1068                 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
1069                 break;
1070         case SIOCSIFMTU:
1071                 ifr = (struct ifreq *)data;
1072                 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
1073                     ifr->ifr_mtu <= IEEE80211_MTU_MAX))
1074                         error = EINVAL;
1075                 else
1076                         ifp->if_mtu = ifr->ifr_mtu;
1077                 break;
1078         case SIOCSIFADDR:
1079                 /*
1080                  * XXX Handle this directly so we can supress if_init calls.
1081                  * XXX This should be done in ether_ioctl but for the moment
1082                  * XXX there are too many other parts of the system that
1083                  * XXX set IFF_UP and so supress if_init being called when
1084                  * XXX it should be.
1085                  */
1086                 ifa = (struct ifaddr *) data;
1087                 switch (ifa->ifa_addr->sa_family) {
1088 #ifdef INET
1089                 case AF_INET:
1090                         if ((ifp->if_flags & IFF_UP) == 0) {
1091                                 ifp->if_flags |= IFF_UP;
1092                                 ifp->if_init(ifp->if_softc);
1093                         }
1094                         arp_ifinit(ifp, ifa);
1095                         break;
1096 #endif
1097 #ifdef IPX
1098                 /*
1099                  * XXX - This code is probably wrong,
1100                  *       but has been copied many times.
1101                  */
1102                 case AF_IPX: {
1103                         struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
1104                         struct arpcom *ac = (struct arpcom *)ifp;
1105
1106                         if (ipx_nullhost(*ina))
1107                                 ina->x_host = *(union ipx_host *) ac->ac_enaddr;
1108                         else
1109                                 bcopy((caddr_t) ina->x_host.c_host,
1110                                       (caddr_t) ac->ac_enaddr,
1111                                       sizeof(ac->ac_enaddr));
1112                         /* fall thru... */
1113                 }
1114 #endif
1115                 default:
1116                         if ((ifp->if_flags & IFF_UP) == 0) {
1117                                 ifp->if_flags |= IFF_UP;
1118                                 ifp->if_init(ifp->if_softc);
1119                         }
1120                         break;
1121                 }
1122                 break;
1123         default:
1124                 error = ether_ioctl(ifp, cmd, data);
1125                 break;
1126         }
1127         return error;
1128 }