]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/awi/awi_wicfg.c
This commit was generated by cvs2svn to compensate for changes in r104858,
[FreeBSD/FreeBSD.git] / sys / dev / awi / awi_wicfg.c
1 /*      $NetBSD: awi_wicfg.c,v 1.3 2000/07/06 17:22:25 onoe Exp $       */
2 /* $FreeBSD$ */
3
4 /*
5  * Copyright (c) 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Atsushi Onoe.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the NetBSD
22  *      Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39
40 /*
41  * WaveLAN compatible configuration support routines for the awi driver.
42  */
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/mbuf.h>
48 #include <sys/proc.h>
49 #include <sys/malloc.h>
50 #include <sys/socket.h>
51 #include <sys/errno.h>
52 #include <sys/sockio.h>
53 #if defined(__FreeBSD__) && __FreeBSD_version >= 400000
54 #include <sys/bus.h>
55 #else
56 #include <sys/device.h>
57 #endif
58
59 #include <net/if.h>
60 #include <net/if_dl.h>
61 #ifdef __FreeBSD__
62 #include <net/ethernet.h>
63 #include <net/if_arp.h>
64 #else
65 #include <net/if_ether.h>
66 #endif
67 #include <net/if_media.h>
68 #include <net/if_ieee80211.h>
69
70 #include <machine/cpu.h>
71 #include <machine/bus.h>
72
73 #ifdef __NetBSD__
74 #include <dev/ic/am79c930reg.h>
75 #include <dev/ic/am79c930var.h>
76 #include <dev/ic/awireg.h>
77 #include <dev/ic/awivar.h>
78
79 #include <dev/pcmcia/if_wi_ieee.h>      /* XXX */
80 #endif
81 #ifdef __FreeBSD__
82 #include <dev/awi/am79c930reg.h>
83 #include <dev/awi/am79c930var.h>
84
85 #undef  _KERNEL         /* XXX */
86 #include <dev/wi/if_wavelan_ieee.h>     /* XXX */
87 #define _KERNEL         /* XXX */
88 #include <dev/awi/awireg.h>
89 #include <dev/awi/awivar.h>
90 #endif
91
92 static int awi_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data);
93 static int awi_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data);
94
95 int
96 awi_wicfg(ifp, cmd, data)
97         struct ifnet *ifp;
98         u_long cmd;
99         caddr_t data;
100 {
101         int error;
102
103         switch (cmd) {
104         case SIOCGWAVELAN:
105                 error = awi_cfgget(ifp, cmd, data);
106                 break;
107         case SIOCSWAVELAN:
108 #ifdef __FreeBSD__
109 #if __FreeBSD_version < 500028
110                 error = suser(curproc);
111 #else
112                 error = suser(curthread);
113 #endif
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 #if __FreeBSD_version < 500028
278                 error = suser(curproc);
279 #else
280                 error = suser(curthread);
281 #endif
282 #else
283                 error = suser(curproc->p_ucred, &curproc->p_acflag);
284 #endif
285                 if (error) {
286                         memset(keys, 0, sizeof(*keys));
287                         error = 0;
288                         break;
289                 }
290                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
291                         k = &keys->wi_keys[i];
292                         keylen = sizeof(k->wi_keydat);
293                         error = awi_wep_getkey(sc, i, k->wi_keydat, &keylen);
294                         if (error)
295                                 break;
296                         k->wi_keylen = keylen;
297                 }
298                 wreq.wi_len = sizeof(*keys) / 2;
299                 break;
300         case WI_RID_MAX_DATALEN:
301                 wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aMax_Frame_Length);
302                 wreq.wi_len = 1;
303                 break;
304         case WI_RID_IFACE_STATS:
305                 /* not implemented yet */
306                 wreq.wi_len = 0;
307                 break;
308 #ifdef WICACHE
309         case WI_RID_READ_CACHE:
310                 for (bp = TAILQ_FIRST(&sc->sc_scan), i = 0;
311                     bp != NULL && i < MAXWICACHE;
312                     bp = TAILQ_NEXT(bp, list), i++) {
313                         memcpy(wsc.macsrc, bp->esrc, ETHER_ADDR_LEN);
314                         /*XXX*/
315                         memcpy(&wsc.ipsrc, bp->bssid, sizeof(wsc.ipsrc));
316                         wsc.signal = bp->rssi;
317                         wsc.noise = 0;
318                         wsc.quality = 0;
319                         memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
320                             &wsc, sizeof(wsc));
321                 }
322                 wreq.wi_len = sizeof(wsc) * i / 2;
323                 break;
324 #endif /* WICACHE */
325         default:
326                 error = EINVAL;
327                 break;
328         }
329         if (error == 0) {
330                 wreq.wi_len++;
331                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
332         }
333         return error;
334 }
335
336 static int
337 awi_cfgset(ifp, cmd, data)
338         struct ifnet *ifp;
339         u_long cmd;
340         caddr_t data;
341 {
342         int i, error, rate, oregion;
343         u_int8_t *phy_rates;
344         struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
345         struct ifreq *ifr = (struct ifreq *)data;
346         struct wi_ltv_keys *keys;
347         struct wi_key *k;
348         struct wi_req wreq;
349
350         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
351         if (error)
352                 return error;
353         if (wreq.wi_len-- < 1)
354                 return EINVAL;
355         switch (wreq.wi_type) {
356         case WI_RID_SERIALNO:
357         case WI_RID_NODENAME:
358                 error = EPERM;
359                 break;
360         case WI_RID_OWN_SSID:
361                 if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
362                         error = EINVAL;
363                         break;
364                 }
365                 if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
366                         error = EINVAL;
367                         break;
368                 }
369                 memset(sc->sc_ownssid, 0, AWI_ESS_ID_SIZE);
370                 sc->sc_ownssid[0] = IEEE80211_ELEMID_SSID;
371                 sc->sc_ownssid[1] = wreq.wi_val[0];
372                 memcpy(&sc->sc_ownssid[2], &wreq.wi_val[1], wreq.wi_val[0]);
373                 if (!sc->sc_mib_local.Network_Mode &&
374                     !sc->sc_no_bssid && sc->sc_start_bss)
375                         error = ENETRESET;
376                 break;
377         case WI_RID_CURRENT_SSID:
378                 error = EPERM;
379                 break;
380         case WI_RID_DESIRED_SSID:
381                 if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
382                         error = EINVAL;
383                         break;
384                 }
385                 if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
386                         error = EINVAL;
387                         break;
388                 }
389                 memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
390                 sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
391                 sc->sc_mib_mac.aDesired_ESS_ID[1] = wreq.wi_val[0];
392                 memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], &wreq.wi_val[1],
393                     wreq.wi_val[0]);
394                 if (sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid)
395                         error = ENETRESET;
396                 break;
397         case WI_RID_CURRENT_BSSID:
398                 error = EPERM;
399                 break;
400         case WI_RID_CHANNEL_LIST:
401                 if (wreq.wi_len != 1) {
402                         error = EINVAL;
403                         break;
404                 }
405                 oregion = sc->sc_mib_phy.aCurrent_Reg_Domain;
406                 if (wreq.wi_val[0] == oregion)
407                         break;
408                 sc->sc_mib_phy.aCurrent_Reg_Domain = wreq.wi_val[0];
409                 error = awi_init_region(sc);
410                 if (error) {
411                         sc->sc_mib_phy.aCurrent_Reg_Domain = oregion;
412                         break;
413                 }
414                 error = ENETRESET;
415                 break;
416         case WI_RID_OWN_CHNL:
417                 if (wreq.wi_len != 1) {
418                         error = EINVAL;
419                         break;
420                 }
421                 if (wreq.wi_val[0] < sc->sc_scan_min ||
422                     wreq.wi_val[0] > sc->sc_scan_max) {
423                         error = EINVAL;
424                         break;
425                 }
426                 sc->sc_ownch = wreq.wi_val[0];
427                 if (!sc->sc_mib_local.Network_Mode)
428                         error = ENETRESET;
429                 break;
430         case WI_RID_CURRENT_CHAN:
431                 error = EPERM;
432                 break;
433         case WI_RID_COMMS_QUALITY:
434                 error = EPERM;
435                 break;
436         case WI_RID_PROMISC:
437                 if (wreq.wi_len != 1) {
438                         error = EINVAL;
439                         break;
440                 }
441                 if (ifp->if_flags & IFF_PROMISC) {
442                         if (wreq.wi_val[0] == 0) {
443                                 ifp->if_flags &= ~IFF_PROMISC;
444                                 error = ENETRESET;
445                         }
446                 } else {
447                         if (wreq.wi_val[0] != 0) {
448                                 ifp->if_flags |= IFF_PROMISC;
449                                 error = ENETRESET;
450                         }
451                 }
452                 break;
453         case WI_RID_PORTTYPE:
454                 if (wreq.wi_len != 1) {
455                         error = EINVAL;
456                         break;
457                 }
458                 switch (wreq.wi_val[0]) {
459                 case 1:
460                         sc->sc_mib_local.Network_Mode = 1;
461                         sc->sc_no_bssid = 0;
462                         error = ENETRESET;
463                         break;
464                 case 2:
465                         sc->sc_mib_local.Network_Mode = 0;
466                         sc->sc_no_bssid = 0;
467                         error = ENETRESET;
468                         break;
469                 case 3:
470                         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
471                                 error = EINVAL;
472                                 break;
473                         }
474                         sc->sc_mib_local.Network_Mode = 0;
475                         sc->sc_no_bssid = 1;
476                         error = ENETRESET;
477                         break;
478                 default:
479                         error = EINVAL;
480                         break;
481                 }
482                 break;
483         case WI_RID_MAC_NODE:
484                 /* XXX: should be implemented? */
485                 error = EPERM;
486                 break;
487         case WI_RID_TX_RATE:
488                 if (wreq.wi_len != 1) {
489                         error = EINVAL;
490                         break;
491                 }
492                 phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
493                 switch (wreq.wi_val[0]) {
494                 case 1:
495                 case 2:
496                 case 5:
497                 case 11:
498                         rate = wreq.wi_val[0] * 10;
499                         if (rate == 50)
500                                 rate += 5;      /*XXX*/
501                         break;
502                 case 3:
503                 case 6:
504                 case 7:
505                         /* auto rate */
506                         phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
507                         rate = AWI_RATE_1MBIT;
508                         for (i = 0; i < phy_rates[1]; i++) {
509                                 if (AWI_80211_RATE(phy_rates[2 + i]) > rate)
510                                         rate = AWI_80211_RATE(phy_rates[2 + i]);
511                         }
512                         break;
513                 default:
514                         rate = 0;
515                         error = EINVAL;
516                         break;
517                 }
518                 if (error)
519                         break;
520                 for (i = 0; i < phy_rates[1]; i++) {
521                         if (rate == AWI_80211_RATE(phy_rates[2 + i]))
522                                 break;
523                 }
524                 if (i == phy_rates[1]) {
525                         error = EINVAL;
526                         break;
527                 }
528                 sc->sc_tx_rate = rate;
529                 break;
530         case WI_RID_CUR_TX_RATE:
531                 error = EPERM;
532                 break;
533         case WI_RID_RTS_THRESH:
534                 if (wreq.wi_len != 1) {
535                         error = EINVAL;
536                         break;
537                 }
538                 LE_WRITE_2(&sc->sc_mib_mac.aRTS_Threshold, wreq.wi_val[0]);
539                 error = ENETRESET;
540                 break;
541         case WI_RID_CREATE_IBSS:
542                 if (wreq.wi_len != 1) {
543                         error = EINVAL;
544                         break;
545                 }
546                 sc->sc_start_bss = wreq.wi_val[0] ? 1 : 0;
547                 error = ENETRESET;
548                 break;
549         case WI_RID_SYSTEM_SCALE:
550                 if (wreq.wi_len != 1) {
551                         error = EINVAL;
552                         break;
553                 }
554                 if (wreq.wi_val[0] != 1)
555                         error = EINVAL;         /* not supported */
556                 break;
557         case WI_RID_PM_ENABLED:
558                 if (wreq.wi_len != 1) {
559                         error = EINVAL;
560                         break;
561                 }
562                 if (wreq.wi_val[0] != 0)
563                         error = EINVAL;         /* not implemented */
564                 break;
565         case WI_RID_MAX_SLEEP:
566                 error = EINVAL;         /* not implemented */
567                 break;
568         case WI_RID_WEP_AVAIL:
569                 error = EPERM;
570                 break;
571         case WI_RID_ENCRYPTION:
572                 if (wreq.wi_len != 1) {
573                         error = EINVAL;
574                         break;
575                 }
576                 error = awi_wep_setalgo(sc, wreq.wi_val[0]);
577                 if (error)
578                         break;
579                 error = ENETRESET;
580                 break;
581         case WI_RID_TX_CRYPT_KEY:
582                 if (wreq.wi_len != 1) {
583                         error = EINVAL;
584                         break;
585                 }
586                 if (wreq.wi_val[0] >= IEEE80211_WEP_NKID) {
587                         error = EINVAL;
588                         break;
589                 }
590                 sc->sc_wep_defkid = wreq.wi_val[1];
591                 break;
592         case WI_RID_DEFLT_CRYPT_KEYS:
593                 if (wreq.wi_len != sizeof(*keys) / 2) {
594                         error = EINVAL;
595                         break;
596                 }
597                 keys = (struct wi_ltv_keys *)&wreq;
598                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
599                         k = &keys->wi_keys[i];
600                         error = awi_wep_setkey(sc, i, k->wi_keydat,
601                             k->wi_keylen);
602                         if (error)
603                                 break;
604                 }
605                 break;
606         case WI_RID_MAX_DATALEN:
607                 if (wreq.wi_len != 1) {
608                         error = EINVAL;
609                         break;
610                 }
611                 if (wreq.wi_val[0] < 350 || wreq.wi_val[0] > 2304) {
612                         error = EINVAL;
613                         break;
614                 }
615                 LE_WRITE_2(&sc->sc_mib_mac.aMax_Frame_Length, wreq.wi_val[0]);
616                 break;
617         case WI_RID_IFACE_STATS:
618                 error = EPERM;
619                 break;
620         default:
621                 error = EINVAL;
622                 break;
623         }
624         if (error == ENETRESET) {
625                 if (sc->sc_enabled) {
626                         awi_stop(sc);
627                         error = awi_init(sc);
628                 } else
629                         error = 0;
630         }
631         return error;
632 }