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