Merge from vendor branch NTPD:
[dragonfly.git] / sys / dev / netif / awi / awi_wicfg.c
1 /*      $NetBSD: awi_wicfg.c,v 1.3 2000/07/06 17:22:25 onoe Exp $       */
2 /* $FreeBSD: src/sys/dev/awi/awi_wicfg.c,v 1.3.2.2 2002/06/18 08:06:15 jhay Exp $ */
3 /* $DragonFly: src/sys/dev/netif/awi/Attic/awi_wicfg.c,v 1.8 2004/07/27 14:25:56 joerg Exp $ */
4
5 /*
6  * Copyright (c) 2000 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Atsushi Onoe.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *      This product includes software developed by the NetBSD
23  *      Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40
41 /*
42  * WaveLAN compatible configuration support routines for the awi driver.
43  */
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/mbuf.h>
49 #include <sys/malloc.h>
50 #include <sys/proc.h>
51 #include <sys/socket.h>
52 #include <sys/errno.h>
53 #include <sys/sockio.h>
54 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
55 #include <sys/bus.h>
56 #else
57 #include <sys/device.h>
58 #endif
59
60 #include <net/if.h>
61 #include <net/if_dl.h>
62 #if defined(__DragonFly__) || defined(__FreeBSD__)
63 #include <net/ethernet.h>
64 #include <net/if_arp.h>
65 #else
66 #include <net/if_ether.h>
67 #endif
68 #include <net/if_media.h>
69 #include <netproto/802_11/ieee80211.h>
70 #include <netproto/802_11/ieee80211_ioctl.h>
71
72 #include <machine/cpu.h>
73 #include <machine/bus.h>
74 #if defined(__DragonFly__) || defined(__FreeBSD__)
75 #include <machine/clock.h>
76 #endif
77
78 #ifdef __NetBSD__
79 #include <dev/ic/am79c930reg.h>
80 #include <dev/ic/am79c930var.h>
81 #include <dev/ic/awireg.h>
82 #include <dev/ic/awivar.h>
83
84 #include <dev/pcmcia/if_wi_ieee.h>      /* XXX */
85 #endif
86 #if defined(__DragonFly__) || defined(__FreeBSD__)
87 #include "am79c930reg.h"
88 #include "am79c930var.h"
89
90 #include <netproto/802_11/if_wavelan_ieee.h>
91 #include "awireg.h"
92 #include "awivar.h"
93 #endif
94
95 static int awi_cfgget (struct ifnet *ifp, u_long cmd, caddr_t data);
96 static int awi_cfgset (struct ifnet *ifp, u_long cmd, caddr_t data);
97
98 int
99 awi_wicfg(ifp, cmd, data)
100         struct ifnet *ifp;
101         u_long cmd;
102         caddr_t data;
103 {
104         int error;
105         struct thread *td = curthread;
106
107         switch (cmd) {
108         case SIOCGWAVELAN:
109                 error = awi_cfgget(ifp, cmd, data);
110                 break;
111         case SIOCSWAVELAN:
112 #if defined(__DragonFly__) || defined(__FreeBSD__)
113                 error = suser(td);      /* note: EPERM if no proc */
114 #else
115                 error = suser(curproc->p_ucred, &curproc->p_acflag);
116 #endif
117                 if (error)
118                         break;
119                 error = awi_cfgset(ifp, cmd, data);
120                 break;
121         default:
122                 error = EINVAL;
123                 break;
124         }
125         return error;
126 }
127
128 static int
129 awi_cfgget(ifp, cmd, data)
130         struct ifnet *ifp;
131         u_long cmd;
132         caddr_t data;
133 {
134         int i, error, keylen;
135         char *p;
136         struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
137         struct ifreq *ifr = (struct ifreq *)data;
138         struct wi_ltv_keys *keys;
139         struct wi_key *k;
140         struct wi_req wreq;
141 #ifdef WICACHE
142         struct wi_sigcache wsc;
143         struct awi_bss *bp;
144 #endif /* WICACHE */
145         struct thread *td = curthread;
146
147         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
148         if (error)
149                 return error;
150         switch (wreq.wi_type) {
151         case WI_RID_SERIALNO:
152                 memcpy(wreq.wi_val, sc->sc_banner, AWI_BANNER_LEN);
153                 wreq.wi_len = (AWI_BANNER_LEN + 1) / 2;
154                 break;
155         case WI_RID_NODENAME:
156                 strcpy((char *)&wreq.wi_val[1], hostname);
157                 wreq.wi_val[0] = strlen(hostname);
158                 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
159                 break;
160         case WI_RID_OWN_SSID:
161                 p = sc->sc_ownssid;
162                 wreq.wi_val[0] = p[1];
163                 memcpy(&wreq.wi_val[1], p + 2, p[1]);
164                 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
165                 break;
166         case WI_RID_CURRENT_SSID:
167                 if (ifp->if_flags & IFF_RUNNING) {
168                         p = sc->sc_bss.essid;
169                         wreq.wi_val[0] = p[1];
170                         memcpy(&wreq.wi_val[1], p + 2, p[1]);
171                 } else {
172                         wreq.wi_val[0] = 0;
173                         wreq.wi_val[1] = '\0';
174                 }
175                 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
176                 break;
177         case WI_RID_DESIRED_SSID:
178                 p = sc->sc_mib_mac.aDesired_ESS_ID;
179                 wreq.wi_val[0] = p[1];
180                 memcpy(&wreq.wi_val[1], p + 2, p[1]);
181                 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
182                 break;
183         case WI_RID_CURRENT_BSSID:
184                 if (ifp->if_flags & IFF_RUNNING)
185                         memcpy(wreq.wi_val, sc->sc_bss.bssid, ETHER_ADDR_LEN);
186                 else
187                         memset(wreq.wi_val, 0, ETHER_ADDR_LEN);
188                 wreq.wi_len = ETHER_ADDR_LEN / 2;
189                 break;
190         case WI_RID_CHANNEL_LIST:
191                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
192                         wreq.wi_val[0] = sc->sc_scan_min;
193                         wreq.wi_val[1] = sc->sc_scan_max;
194                         wreq.wi_len = 2;
195                 } else {
196                         wreq.wi_val[0] = 0;
197                         for (i = sc->sc_scan_min; i <= sc->sc_scan_max; i++)
198                                 wreq.wi_val[0] |= 1 << (i - 1);
199                         wreq.wi_len = 1;
200                 }
201                 break;
202         case WI_RID_OWN_CHNL:
203                 wreq.wi_val[0] = sc->sc_ownch;
204                 wreq.wi_len = 1;
205                 break;
206         case WI_RID_CURRENT_CHAN:
207                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
208                         wreq.wi_val[0] = sc->sc_bss.pattern;
209                 else
210                         wreq.wi_val[0] = sc->sc_bss.chanset;
211                 wreq.wi_len = 1;
212                 break;
213         case WI_RID_COMMS_QUALITY:
214                 wreq.wi_val[0] = 0;                     /* quality */
215                 wreq.wi_val[1] = sc->sc_bss.rssi;       /* signal */
216                 wreq.wi_val[2] = 0;                     /* noise */
217                 wreq.wi_len = 3;
218                 break;
219         case WI_RID_PROMISC:
220                 wreq.wi_val[0] = sc->sc_mib_mac.aPromiscuous_Enable;
221                 wreq.wi_len = 1;
222                 break;
223         case WI_RID_PORTTYPE:
224                 if (sc->sc_mib_local.Network_Mode)
225                         wreq.wi_val[0] = 1;
226                 else if (!sc->sc_no_bssid)
227                         wreq.wi_val[0] = 2;
228                 else
229                         wreq.wi_val[0] = 3;
230                 wreq.wi_len = 1;
231                 break;
232         case WI_RID_MAC_NODE:
233                 memcpy(wreq.wi_val, sc->sc_mib_addr.aMAC_Address,
234                     ETHER_ADDR_LEN);
235                 wreq.wi_len = ETHER_ADDR_LEN / 2;
236                 break;
237         case WI_RID_TX_RATE:
238         case WI_RID_CUR_TX_RATE:
239                 wreq.wi_val[0] = sc->sc_tx_rate / 10;
240                 wreq.wi_len = 1;
241                 break;
242         case WI_RID_RTS_THRESH:
243                 wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aRTS_Threshold);
244                 wreq.wi_len = 1;
245                 break;
246         case WI_RID_CREATE_IBSS:
247                 wreq.wi_val[0] = sc->sc_start_bss;
248                 wreq.wi_len = 1;
249                 break;
250         case WI_RID_SYSTEM_SCALE:
251                 wreq.wi_val[0] = 1;     /* low density ... not supported */
252                 wreq.wi_len = 1;
253                 break;
254         case WI_RID_PM_ENABLED:
255                 wreq.wi_val[0] = sc->sc_mib_local.Power_Saving_Mode_Dis ? 0 : 1;
256                 wreq.wi_len = 1;
257                 break;
258         case WI_RID_MAX_SLEEP:
259                 wreq.wi_val[0] = 0;     /* not implemented */
260                 wreq.wi_len = 1;
261                 break;
262         case WI_RID_WEP_AVAIL:
263                 wreq.wi_val[0] = 1;
264                 wreq.wi_len = 1;
265                 break;
266         case WI_RID_ENCRYPTION:
267                 wreq.wi_val[0] = awi_wep_getalgo(sc);
268                 wreq.wi_len = 1;
269                 break;
270         case WI_RID_TX_CRYPT_KEY:
271                 wreq.wi_val[0] = sc->sc_wep_defkid;
272                 wreq.wi_len = 1;
273                 break;
274         case WI_RID_DEFLT_CRYPT_KEYS:
275                 keys = (struct wi_ltv_keys *)&wreq;
276                 /* do not show keys to non-root user */
277 #if defined(__DragonFly__) || defined(__FreeBSD__)
278                 error = suser(td);      /* note: EPERM if no proc */
279 #else
280                 error = suser(curproc->p_ucred, &curproc->p_acflag);
281 #endif
282                 if (error) {
283                         memset(keys, 0, sizeof(*keys));
284                         error = 0;
285                         break;
286                 }
287                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
288                         k = &keys->wi_keys[i];
289                         keylen = sizeof(k->wi_keydat);
290                         error = awi_wep_getkey(sc, i, k->wi_keydat, &keylen);
291                         if (error)
292                                 break;
293                         k->wi_keylen = keylen;
294                 }
295                 wreq.wi_len = sizeof(*keys) / 2;
296                 break;
297         case WI_RID_MAX_DATALEN:
298                 wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aMax_Frame_Length);
299                 wreq.wi_len = 1;
300                 break;
301         case WI_RID_IFACE_STATS:
302                 /* not implemented yet */
303                 wreq.wi_len = 0;
304                 break;
305 #ifdef WICACHE
306         case WI_RID_READ_CACHE:
307                 for (bp = TAILQ_FIRST(&sc->sc_scan), i = 0;
308                     bp != NULL && i < MAXWICACHE;
309                     bp = TAILQ_NEXT(bp, list), i++) {
310                         memcpy(wsc.macsrc, bp->esrc, ETHER_ADDR_LEN);
311                         /*XXX*/
312                         memcpy(&wsc.ipsrc, bp->bssid, sizeof(wsc.ipsrc));
313                         wsc.signal = bp->rssi;
314                         wsc.noise = 0;
315                         wsc.quality = 0;
316                         memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
317                             &wsc, sizeof(wsc));
318                 }
319                 wreq.wi_len = sizeof(wsc) * i / 2;
320                 break;
321 #endif /* WICACHE */
322         default:
323                 error = EINVAL;
324                 break;
325         }
326         if (error == 0) {
327                 wreq.wi_len++;
328                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
329         }
330         return error;
331 }
332
333 static int
334 awi_cfgset(ifp, cmd, data)
335         struct ifnet *ifp;
336         u_long cmd;
337         caddr_t data;
338 {
339         int i, error, rate, oregion;
340         u_int8_t *phy_rates;
341         struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
342         struct ifreq *ifr = (struct ifreq *)data;
343         struct wi_ltv_keys *keys;
344         struct wi_key *k;
345         struct wi_req wreq;
346
347         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
348         if (error)
349                 return error;
350         if (wreq.wi_len-- < 1)
351                 return EINVAL;
352         switch (wreq.wi_type) {
353         case WI_RID_SERIALNO:
354         case WI_RID_NODENAME:
355                 error = EPERM;
356                 break;
357         case WI_RID_OWN_SSID:
358                 if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
359                         error = EINVAL;
360                         break;
361                 }
362                 if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
363                         error = EINVAL;
364                         break;
365                 }
366                 memset(sc->sc_ownssid, 0, AWI_ESS_ID_SIZE);
367                 sc->sc_ownssid[0] = IEEE80211_ELEMID_SSID;
368                 sc->sc_ownssid[1] = wreq.wi_val[0];
369                 memcpy(&sc->sc_ownssid[2], &wreq.wi_val[1], wreq.wi_val[0]);
370                 if (!sc->sc_mib_local.Network_Mode &&
371                     !sc->sc_no_bssid && sc->sc_start_bss)
372                         error = ENETRESET;
373                 break;
374         case WI_RID_CURRENT_SSID:
375                 error = EPERM;
376                 break;
377         case WI_RID_DESIRED_SSID:
378                 if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
379                         error = EINVAL;
380                         break;
381                 }
382                 if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
383                         error = EINVAL;
384                         break;
385                 }
386                 memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
387                 sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
388                 sc->sc_mib_mac.aDesired_ESS_ID[1] = wreq.wi_val[0];
389                 memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], &wreq.wi_val[1],
390                     wreq.wi_val[0]);
391                 if (sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid)
392                         error = ENETRESET;
393                 break;
394         case WI_RID_CURRENT_BSSID:
395                 error = EPERM;
396                 break;
397         case WI_RID_CHANNEL_LIST:
398                 if (wreq.wi_len != 1) {
399                         error = EINVAL;
400                         break;
401                 }
402                 oregion = sc->sc_mib_phy.aCurrent_Reg_Domain;
403                 if (wreq.wi_val[0] == oregion)
404                         break;
405                 sc->sc_mib_phy.aCurrent_Reg_Domain = wreq.wi_val[0];
406                 error = awi_init_region(sc);
407                 if (error) {
408                         sc->sc_mib_phy.aCurrent_Reg_Domain = oregion;
409                         break;
410                 }
411                 error = ENETRESET;
412                 break;
413         case WI_RID_OWN_CHNL:
414                 if (wreq.wi_len != 1) {
415                         error = EINVAL;
416                         break;
417                 }
418                 if (wreq.wi_val[0] < sc->sc_scan_min ||
419                     wreq.wi_val[0] > sc->sc_scan_max) {
420                         error = EINVAL;
421                         break;
422                 }
423                 sc->sc_ownch = wreq.wi_val[0];
424                 if (!sc->sc_mib_local.Network_Mode)
425                         error = ENETRESET;
426                 break;
427         case WI_RID_CURRENT_CHAN:
428                 error = EPERM;
429                 break;
430         case WI_RID_COMMS_QUALITY:
431                 error = EPERM;
432                 break;
433         case WI_RID_PROMISC:
434                 if (wreq.wi_len != 1) {
435                         error = EINVAL;
436                         break;
437                 }
438                 if (ifp->if_flags & IFF_PROMISC) {
439                         if (wreq.wi_val[0] == 0) {
440                                 ifp->if_flags &= ~IFF_PROMISC;
441                                 error = ENETRESET;
442                         }
443                 } else {
444                         if (wreq.wi_val[0] != 0) {
445                                 ifp->if_flags |= IFF_PROMISC;
446                                 error = ENETRESET;
447                         }
448                 }
449                 break;
450         case WI_RID_PORTTYPE:
451                 if (wreq.wi_len != 1) {
452                         error = EINVAL;
453                         break;
454                 }
455                 switch (wreq.wi_val[0]) {
456                 case 1:
457                         sc->sc_mib_local.Network_Mode = 1;
458                         sc->sc_no_bssid = 0;
459                         error = ENETRESET;
460                         break;
461                 case 2:
462                         sc->sc_mib_local.Network_Mode = 0;
463                         sc->sc_no_bssid = 0;
464                         error = ENETRESET;
465                         break;
466                 case 3:
467                         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
468                                 error = EINVAL;
469                                 break;
470                         }
471                         sc->sc_mib_local.Network_Mode = 0;
472                         sc->sc_no_bssid = 1;
473                         error = ENETRESET;
474                         break;
475                 default:
476                         error = EINVAL;
477                         break;
478                 }
479                 break;
480         case WI_RID_MAC_NODE:
481                 /* XXX: should be implemented? */
482                 error = EPERM;
483                 break;
484         case WI_RID_TX_RATE:
485                 if (wreq.wi_len != 1) {
486                         error = EINVAL;
487                         break;
488                 }
489                 phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
490                 switch (wreq.wi_val[0]) {
491                 case 1:
492                 case 2:
493                 case 5:
494                 case 11:
495                         rate = wreq.wi_val[0] * 10;
496                         if (rate == 50)
497                                 rate += 5;      /*XXX*/
498                         break;
499                 case 3:
500                 case 6:
501                 case 7:
502                         /* auto rate */
503                         phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
504                         rate = AWI_RATE_1MBIT;
505                         for (i = 0; i < phy_rates[1]; i++) {
506                                 if (AWI_80211_RATE(phy_rates[2 + i]) > rate)
507                                         rate = AWI_80211_RATE(phy_rates[2 + i]);
508                         }
509                         break;
510                 default:
511                         rate = 0;
512                         error = EINVAL;
513                         break;
514                 }
515                 if (error)
516                         break;
517                 for (i = 0; i < phy_rates[1]; i++) {
518                         if (rate == AWI_80211_RATE(phy_rates[2 + i]))
519                                 break;
520                 }
521                 if (i == phy_rates[1]) {
522                         error = EINVAL;
523                         break;
524                 }
525                 sc->sc_tx_rate = rate;
526                 break;
527         case WI_RID_CUR_TX_RATE:
528                 error = EPERM;
529                 break;
530         case WI_RID_RTS_THRESH:
531                 if (wreq.wi_len != 1) {
532                         error = EINVAL;
533                         break;
534                 }
535                 LE_WRITE_2(&sc->sc_mib_mac.aRTS_Threshold, wreq.wi_val[0]);
536                 error = ENETRESET;
537                 break;
538         case WI_RID_CREATE_IBSS:
539                 if (wreq.wi_len != 1) {
540                         error = EINVAL;
541                         break;
542                 }
543                 sc->sc_start_bss = wreq.wi_val[0] ? 1 : 0;
544                 error = ENETRESET;
545                 break;
546         case WI_RID_SYSTEM_SCALE:
547                 if (wreq.wi_len != 1) {
548                         error = EINVAL;
549                         break;
550                 }
551                 if (wreq.wi_val[0] != 1)
552                         error = EINVAL;         /* not supported */
553                 break;
554         case WI_RID_PM_ENABLED:
555                 if (wreq.wi_len != 1) {
556                         error = EINVAL;
557                         break;
558                 }
559                 if (wreq.wi_val[0] != 0)
560                         error = EINVAL;         /* not implemented */
561                 break;
562         case WI_RID_MAX_SLEEP:
563                 error = EINVAL;         /* not implemented */
564                 break;
565         case WI_RID_WEP_AVAIL:
566                 error = EPERM;
567                 break;
568         case WI_RID_ENCRYPTION:
569                 if (wreq.wi_len != 1) {
570                         error = EINVAL;
571                         break;
572                 }
573                 error = awi_wep_setalgo(sc, wreq.wi_val[0]);
574                 if (error)
575                         break;
576                 error = ENETRESET;
577                 break;
578         case WI_RID_TX_CRYPT_KEY:
579                 if (wreq.wi_len != 1) {
580                         error = EINVAL;
581                         break;
582                 }
583                 if (wreq.wi_val[0] >= IEEE80211_WEP_NKID) {
584                         error = EINVAL;
585                         break;
586                 }
587                 sc->sc_wep_defkid = wreq.wi_val[1];
588                 break;
589         case WI_RID_DEFLT_CRYPT_KEYS:
590                 if (wreq.wi_len != sizeof(*keys) / 2) {
591                         error = EINVAL;
592                         break;
593                 }
594                 keys = (struct wi_ltv_keys *)&wreq;
595                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
596                         k = &keys->wi_keys[i];
597                         error = awi_wep_setkey(sc, i, k->wi_keydat,
598                             k->wi_keylen);
599                         if (error)
600                                 break;
601                 }
602                 break;
603         case WI_RID_MAX_DATALEN:
604                 if (wreq.wi_len != 1) {
605                         error = EINVAL;
606                         break;
607                 }
608                 if (wreq.wi_val[0] < 350 || wreq.wi_val[0] > 2304) {
609                         error = EINVAL;
610                         break;
611                 }
612                 LE_WRITE_2(&sc->sc_mib_mac.aMax_Frame_Length, wreq.wi_val[0]);
613                 break;
614         case WI_RID_IFACE_STATS:
615                 error = EPERM;
616                 break;
617         default:
618                 error = EINVAL;
619                 break;
620         }
621         if (error == ENETRESET) {
622                 if (sc->sc_enabled) {
623                         awi_stop(sc);
624                         error = awi_init(sc);
625                 } else
626                         error = 0;
627         }
628         return error;
629 }