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