Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:28:22 dillon 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(__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 #ifdef __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 <net/if_ieee80211.h>
70
71 #include <machine/cpu.h>
72 #include <machine/bus.h>
73 #ifdef __FreeBSD__
74 #include <machine/clock.h>
75 #endif
76
77 #ifdef __NetBSD__
78 #include <dev/ic/am79c930reg.h>
79 #include <dev/ic/am79c930var.h>
80 #include <dev/ic/awireg.h>
81 #include <dev/ic/awivar.h>
82
83 #include <dev/pcmcia/if_wi_ieee.h>      /* XXX */
84 #endif
85 #ifdef __FreeBSD__
86 #include <dev/awi/am79c930reg.h>
87 #include <dev/awi/am79c930var.h>
88
89 #undef  _KERNEL         /* XXX */
90 #include <dev/wi/if_wavelan_ieee.h>     /* XXX */
91 #define _KERNEL         /* XXX */
92 #include <dev/awi/awireg.h>
93 #include <dev/awi/awivar.h>
94 #endif
95
96 static int awi_cfgget __P((struct ifnet *ifp, u_long cmd, caddr_t data));
97 static int awi_cfgset __P((struct ifnet *ifp, u_long cmd, caddr_t data));
98
99 int
100 awi_wicfg(ifp, cmd, data)
101         struct ifnet *ifp;
102         u_long cmd;
103         caddr_t data;
104 {
105         int error;
106
107         switch (cmd) {
108         case SIOCGWAVELAN:
109                 error = awi_cfgget(ifp, cmd, data);
110                 break;
111         case SIOCSWAVELAN:
112 #ifdef __FreeBSD__
113                 error = suser(curproc);
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
146         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
147         if (error)
148                 return error;
149         switch (wreq.wi_type) {
150         case WI_RID_SERIALNO:
151                 memcpy(wreq.wi_val, sc->sc_banner, AWI_BANNER_LEN);
152                 wreq.wi_len = (AWI_BANNER_LEN + 1) / 2;
153                 break;
154         case WI_RID_NODENAME:
155                 strcpy((char *)&wreq.wi_val[1], hostname);
156                 wreq.wi_val[0] = strlen(hostname);
157                 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
158                 break;
159         case WI_RID_OWN_SSID:
160                 p = sc->sc_ownssid;
161                 wreq.wi_val[0] = p[1];
162                 memcpy(&wreq.wi_val[1], p + 2, p[1]);
163                 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
164                 break;
165         case WI_RID_CURRENT_SSID:
166                 if (ifp->if_flags & IFF_RUNNING) {
167                         p = sc->sc_bss.essid;
168                         wreq.wi_val[0] = p[1];
169                         memcpy(&wreq.wi_val[1], p + 2, p[1]);
170                 } else {
171                         wreq.wi_val[0] = 0;
172                         wreq.wi_val[1] = '\0';
173                 }
174                 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
175                 break;
176         case WI_RID_DESIRED_SSID:
177                 p = sc->sc_mib_mac.aDesired_ESS_ID;
178                 wreq.wi_val[0] = p[1];
179                 memcpy(&wreq.wi_val[1], p + 2, p[1]);
180                 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
181                 break;
182         case WI_RID_CURRENT_BSSID:
183                 if (ifp->if_flags & IFF_RUNNING)
184                         memcpy(wreq.wi_val, sc->sc_bss.bssid, ETHER_ADDR_LEN);
185                 else
186                         memset(wreq.wi_val, 0, ETHER_ADDR_LEN);
187                 wreq.wi_len = ETHER_ADDR_LEN / 2;
188                 break;
189         case WI_RID_CHANNEL_LIST:
190                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
191                         wreq.wi_val[0] = sc->sc_scan_min;
192                         wreq.wi_val[1] = sc->sc_scan_max;
193                         wreq.wi_len = 2;
194                 } else {
195                         wreq.wi_val[0] = 0;
196                         for (i = sc->sc_scan_min; i <= sc->sc_scan_max; i++)
197                                 wreq.wi_val[0] |= 1 << (i - 1);
198                         wreq.wi_len = 1;
199                 }
200                 break;
201         case WI_RID_OWN_CHNL:
202                 wreq.wi_val[0] = sc->sc_ownch;
203                 wreq.wi_len = 1;
204                 break;
205         case WI_RID_CURRENT_CHAN:
206                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
207                         wreq.wi_val[0] = sc->sc_bss.pattern;
208                 else
209                         wreq.wi_val[0] = sc->sc_bss.chanset;
210                 wreq.wi_len = 1;
211                 break;
212         case WI_RID_COMMS_QUALITY:
213                 wreq.wi_val[0] = 0;                     /* quality */
214                 wreq.wi_val[1] = sc->sc_bss.rssi;       /* signal */
215                 wreq.wi_val[2] = 0;                     /* noise */
216                 wreq.wi_len = 3;
217                 break;
218         case WI_RID_PROMISC:
219                 wreq.wi_val[0] = sc->sc_mib_mac.aPromiscuous_Enable;
220                 wreq.wi_len = 1;
221                 break;
222         case WI_RID_PORTTYPE:
223                 if (sc->sc_mib_local.Network_Mode)
224                         wreq.wi_val[0] = 1;
225                 else if (!sc->sc_no_bssid)
226                         wreq.wi_val[0] = 2;
227                 else
228                         wreq.wi_val[0] = 3;
229                 wreq.wi_len = 1;
230                 break;
231         case WI_RID_MAC_NODE:
232                 memcpy(wreq.wi_val, sc->sc_mib_addr.aMAC_Address,
233                     ETHER_ADDR_LEN);
234                 wreq.wi_len = ETHER_ADDR_LEN / 2;
235                 break;
236         case WI_RID_TX_RATE:
237         case WI_RID_CUR_TX_RATE:
238                 wreq.wi_val[0] = sc->sc_tx_rate / 10;
239                 wreq.wi_len = 1;
240                 break;
241         case WI_RID_RTS_THRESH:
242                 wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aRTS_Threshold);
243                 wreq.wi_len = 1;
244                 break;
245         case WI_RID_CREATE_IBSS:
246                 wreq.wi_val[0] = sc->sc_start_bss;
247                 wreq.wi_len = 1;
248                 break;
249         case WI_RID_SYSTEM_SCALE:
250                 wreq.wi_val[0] = 1;     /* low density ... not supported */
251                 wreq.wi_len = 1;
252                 break;
253         case WI_RID_PM_ENABLED:
254                 wreq.wi_val[0] = sc->sc_mib_local.Power_Saving_Mode_Dis ? 0 : 1;
255                 wreq.wi_len = 1;
256                 break;
257         case WI_RID_MAX_SLEEP:
258                 wreq.wi_val[0] = 0;     /* not implemented */
259                 wreq.wi_len = 1;
260                 break;
261         case WI_RID_WEP_AVAIL:
262                 wreq.wi_val[0] = 1;
263                 wreq.wi_len = 1;
264                 break;
265         case WI_RID_ENCRYPTION:
266                 wreq.wi_val[0] = awi_wep_getalgo(sc);
267                 wreq.wi_len = 1;
268                 break;
269         case WI_RID_TX_CRYPT_KEY:
270                 wreq.wi_val[0] = sc->sc_wep_defkid;
271                 wreq.wi_len = 1;
272                 break;
273         case WI_RID_DEFLT_CRYPT_KEYS:
274                 keys = (struct wi_ltv_keys *)&wreq;
275                 /* do not show keys to non-root user */
276 #ifdef __FreeBSD__
277                 error = suser(curproc);
278 #else
279                 error = suser(curproc->p_ucred, &curproc->p_acflag);
280 #endif
281                 if (error) {
282                         memset(keys, 0, sizeof(*keys));
283                         error = 0;
284                         break;
285                 }
286                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
287                         k = &keys->wi_keys[i];
288                         keylen = sizeof(k->wi_keydat);
289                         error = awi_wep_getkey(sc, i, k->wi_keydat, &keylen);
290                         if (error)
291                                 break;
292                         k->wi_keylen = keylen;
293                 }
294                 wreq.wi_len = sizeof(*keys) / 2;
295                 break;
296         case WI_RID_MAX_DATALEN:
297                 wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aMax_Frame_Length);
298                 wreq.wi_len = 1;
299                 break;
300         case WI_RID_IFACE_STATS:
301                 /* not implemented yet */
302                 wreq.wi_len = 0;
303                 break;
304 #ifdef WICACHE
305         case WI_RID_READ_CACHE:
306                 for (bp = TAILQ_FIRST(&sc->sc_scan), i = 0;
307                     bp != NULL && i < MAXWICACHE;
308                     bp = TAILQ_NEXT(bp, list), i++) {
309                         memcpy(wsc.macsrc, bp->esrc, ETHER_ADDR_LEN);
310                         /*XXX*/
311                         memcpy(&wsc.ipsrc, bp->bssid, sizeof(wsc.ipsrc));
312                         wsc.signal = bp->rssi;
313                         wsc.noise = 0;
314                         wsc.quality = 0;
315                         memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
316                             &wsc, sizeof(wsc));
317                 }
318                 wreq.wi_len = sizeof(wsc) * i / 2;
319                 break;
320 #endif /* WICACHE */
321         default:
322                 error = EINVAL;
323                 break;
324         }
325         if (error == 0) {
326                 wreq.wi_len++;
327                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
328         }
329         return error;
330 }
331
332 static int
333 awi_cfgset(ifp, cmd, data)
334         struct ifnet *ifp;
335         u_long cmd;
336         caddr_t data;
337 {
338         int i, error, rate, oregion;
339         u_int8_t *phy_rates;
340         struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
341         struct ifreq *ifr = (struct ifreq *)data;
342         struct wi_ltv_keys *keys;
343         struct wi_key *k;
344         struct wi_req wreq;
345
346         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
347         if (error)
348                 return error;
349         if (wreq.wi_len-- < 1)
350                 return EINVAL;
351         switch (wreq.wi_type) {
352         case WI_RID_SERIALNO:
353         case WI_RID_NODENAME:
354                 error = EPERM;
355                 break;
356         case WI_RID_OWN_SSID:
357                 if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
358                         error = EINVAL;
359                         break;
360                 }
361                 if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
362                         error = EINVAL;
363                         break;
364                 }
365                 memset(sc->sc_ownssid, 0, AWI_ESS_ID_SIZE);
366                 sc->sc_ownssid[0] = IEEE80211_ELEMID_SSID;
367                 sc->sc_ownssid[1] = wreq.wi_val[0];
368                 memcpy(&sc->sc_ownssid[2], &wreq.wi_val[1], wreq.wi_val[0]);
369                 if (!sc->sc_mib_local.Network_Mode &&
370                     !sc->sc_no_bssid && sc->sc_start_bss)
371                         error = ENETRESET;
372                 break;
373         case WI_RID_CURRENT_SSID:
374                 error = EPERM;
375                 break;
376         case WI_RID_DESIRED_SSID:
377                 if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
378                         error = EINVAL;
379                         break;
380                 }
381                 if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
382                         error = EINVAL;
383                         break;
384                 }
385                 memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
386                 sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
387                 sc->sc_mib_mac.aDesired_ESS_ID[1] = wreq.wi_val[0];
388                 memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], &wreq.wi_val[1],
389                     wreq.wi_val[0]);
390                 if (sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid)
391                         error = ENETRESET;
392                 break;
393         case WI_RID_CURRENT_BSSID:
394                 error = EPERM;
395                 break;
396         case WI_RID_CHANNEL_LIST:
397                 if (wreq.wi_len != 1) {
398                         error = EINVAL;
399                         break;
400                 }
401                 oregion = sc->sc_mib_phy.aCurrent_Reg_Domain;
402                 if (wreq.wi_val[0] == oregion)
403                         break;
404                 sc->sc_mib_phy.aCurrent_Reg_Domain = wreq.wi_val[0];
405                 error = awi_init_region(sc);
406                 if (error) {
407                         sc->sc_mib_phy.aCurrent_Reg_Domain = oregion;
408                         break;
409                 }
410                 error = ENETRESET;
411                 break;
412         case WI_RID_OWN_CHNL:
413                 if (wreq.wi_len != 1) {
414                         error = EINVAL;
415                         break;
416                 }
417                 if (wreq.wi_val[0] < sc->sc_scan_min ||
418                     wreq.wi_val[0] > sc->sc_scan_max) {
419                         error = EINVAL;
420                         break;
421                 }
422                 sc->sc_ownch = wreq.wi_val[0];
423                 if (!sc->sc_mib_local.Network_Mode)
424                         error = ENETRESET;
425                 break;
426         case WI_RID_CURRENT_CHAN:
427                 error = EPERM;
428                 break;
429         case WI_RID_COMMS_QUALITY:
430                 error = EPERM;
431                 break;
432         case WI_RID_PROMISC:
433                 if (wreq.wi_len != 1) {
434                         error = EINVAL;
435                         break;
436                 }
437                 if (ifp->if_flags & IFF_PROMISC) {
438                         if (wreq.wi_val[0] == 0) {
439                                 ifp->if_flags &= ~IFF_PROMISC;
440                                 error = ENETRESET;
441                         }
442                 } else {
443                         if (wreq.wi_val[0] != 0) {
444                                 ifp->if_flags |= IFF_PROMISC;
445                                 error = ENETRESET;
446                         }
447                 }
448                 break;
449         case WI_RID_PORTTYPE:
450                 if (wreq.wi_len != 1) {
451                         error = EINVAL;
452                         break;
453                 }
454                 switch (wreq.wi_val[0]) {
455                 case 1:
456                         sc->sc_mib_local.Network_Mode = 1;
457                         sc->sc_no_bssid = 0;
458                         error = ENETRESET;
459                         break;
460                 case 2:
461                         sc->sc_mib_local.Network_Mode = 0;
462                         sc->sc_no_bssid = 0;
463                         error = ENETRESET;
464                         break;
465                 case 3:
466                         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
467                                 error = EINVAL;
468                                 break;
469                         }
470                         sc->sc_mib_local.Network_Mode = 0;
471                         sc->sc_no_bssid = 1;
472                         error = ENETRESET;
473                         break;
474                 default:
475                         error = EINVAL;
476                         break;
477                 }
478                 break;
479         case WI_RID_MAC_NODE:
480                 /* XXX: should be implemented? */
481                 error = EPERM;
482                 break;
483         case WI_RID_TX_RATE:
484                 if (wreq.wi_len != 1) {
485                         error = EINVAL;
486                         break;
487                 }
488                 phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
489                 switch (wreq.wi_val[0]) {
490                 case 1:
491                 case 2:
492                 case 5:
493                 case 11:
494                         rate = wreq.wi_val[0] * 10;
495                         if (rate == 50)
496                                 rate += 5;      /*XXX*/
497                         break;
498                 case 3:
499                 case 6:
500                 case 7:
501                         /* auto rate */
502                         phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
503                         rate = AWI_RATE_1MBIT;
504                         for (i = 0; i < phy_rates[1]; i++) {
505                                 if (AWI_80211_RATE(phy_rates[2 + i]) > rate)
506                                         rate = AWI_80211_RATE(phy_rates[2 + i]);
507                         }
508                         break;
509                 default:
510                         rate = 0;
511                         error = EINVAL;
512                         break;
513                 }
514                 if (error)
515                         break;
516                 for (i = 0; i < phy_rates[1]; i++) {
517                         if (rate == AWI_80211_RATE(phy_rates[2 + i]))
518                                 break;
519                 }
520                 if (i == phy_rates[1]) {
521                         error = EINVAL;
522                         break;
523                 }
524                 sc->sc_tx_rate = rate;
525                 break;
526         case WI_RID_CUR_TX_RATE:
527                 error = EPERM;
528                 break;
529         case WI_RID_RTS_THRESH:
530                 if (wreq.wi_len != 1) {
531                         error = EINVAL;
532                         break;
533                 }
534                 LE_WRITE_2(&sc->sc_mib_mac.aRTS_Threshold, wreq.wi_val[0]);
535                 error = ENETRESET;
536                 break;
537         case WI_RID_CREATE_IBSS:
538                 if (wreq.wi_len != 1) {
539                         error = EINVAL;
540                         break;
541                 }
542                 sc->sc_start_bss = wreq.wi_val[0] ? 1 : 0;
543                 error = ENETRESET;
544                 break;
545         case WI_RID_SYSTEM_SCALE:
546                 if (wreq.wi_len != 1) {
547                         error = EINVAL;
548                         break;
549                 }
550                 if (wreq.wi_val[0] != 1)
551                         error = EINVAL;         /* not supported */
552                 break;
553         case WI_RID_PM_ENABLED:
554                 if (wreq.wi_len != 1) {
555                         error = EINVAL;
556                         break;
557                 }
558                 if (wreq.wi_val[0] != 0)
559                         error = EINVAL;         /* not implemented */
560                 break;
561         case WI_RID_MAX_SLEEP:
562                 error = EINVAL;         /* not implemented */
563                 break;
564         case WI_RID_WEP_AVAIL:
565                 error = EPERM;
566                 break;
567         case WI_RID_ENCRYPTION:
568                 if (wreq.wi_len != 1) {
569                         error = EINVAL;
570                         break;
571                 }
572                 error = awi_wep_setalgo(sc, wreq.wi_val[0]);
573                 if (error)
574                         break;
575                 error = ENETRESET;
576                 break;
577         case WI_RID_TX_CRYPT_KEY:
578                 if (wreq.wi_len != 1) {
579                         error = EINVAL;
580                         break;
581                 }
582                 if (wreq.wi_val[0] >= IEEE80211_WEP_NKID) {
583                         error = EINVAL;
584                         break;
585                 }
586                 sc->sc_wep_defkid = wreq.wi_val[1];
587                 break;
588         case WI_RID_DEFLT_CRYPT_KEYS:
589                 if (wreq.wi_len != sizeof(*keys) / 2) {
590                         error = EINVAL;
591                         break;
592                 }
593                 keys = (struct wi_ltv_keys *)&wreq;
594                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
595                         k = &keys->wi_keys[i];
596                         error = awi_wep_setkey(sc, i, k->wi_keydat,
597                             k->wi_keylen);
598                         if (error)
599                                 break;
600                 }
601                 break;
602         case WI_RID_MAX_DATALEN:
603                 if (wreq.wi_len != 1) {
604                         error = EINVAL;
605                         break;
606                 }
607                 if (wreq.wi_val[0] < 350 || wreq.wi_val[0] > 2304) {
608                         error = EINVAL;
609                         break;
610                 }
611                 LE_WRITE_2(&sc->sc_mib_mac.aMax_Frame_Length, wreq.wi_val[0]);
612                 break;
613         case WI_RID_IFACE_STATS:
614                 error = EPERM;
615                 break;
616         default:
617                 error = EINVAL;
618                 break;
619         }
620         if (error == ENETRESET) {
621                 if (sc->sc_enabled) {
622                         awi_stop(sc);
623                         error = awi_init(sc);
624                 } else
625                         error = 0;
626         }
627         return error;
628 }