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 $ */
5 * Copyright (c) 2000 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
41 * WaveLAN compatible configuration support routines for the awi driver.
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
48 #include <sys/malloc.h>
50 #include <sys/socket.h>
51 #include <sys/errno.h>
52 #include <sys/sockio.h>
53 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
56 #include <sys/device.h>
60 #include <net/if_dl.h>
62 #include <net/ethernet.h>
63 #include <net/if_arp.h>
65 #include <net/if_ether.h>
67 #include <net/if_media.h>
68 #include <net/if_ieee80211.h>
70 #include <machine/cpu.h>
71 #include <machine/bus.h>
73 #include <machine/clock.h>
77 #include <dev/ic/am79c930reg.h>
78 #include <dev/ic/am79c930var.h>
79 #include <dev/ic/awireg.h>
80 #include <dev/ic/awivar.h>
82 #include <dev/pcmcia/if_wi_ieee.h> /* XXX */
85 #include <dev/awi/am79c930reg.h>
86 #include <dev/awi/am79c930var.h>
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>
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));
99 awi_wicfg(ifp, cmd, data)
108 error = awi_cfgget(ifp, cmd, data);
112 error = suser(curproc);
114 error = suser(curproc->p_ucred, &curproc->p_acflag);
118 error = awi_cfgset(ifp, cmd, data);
128 awi_cfgget(ifp, cmd, data)
133 int i, error, keylen;
135 struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
136 struct ifreq *ifr = (struct ifreq *)data;
137 struct wi_ltv_keys *keys;
141 struct wi_sigcache wsc;
145 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
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;
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;
158 case WI_RID_OWN_SSID:
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;
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]);
171 wreq.wi_val[1] = '\0';
173 wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
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;
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);
185 memset(wreq.wi_val, 0, ETHER_ADDR_LEN);
186 wreq.wi_len = ETHER_ADDR_LEN / 2;
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;
195 for (i = sc->sc_scan_min; i <= sc->sc_scan_max; i++)
196 wreq.wi_val[0] |= 1 << (i - 1);
200 case WI_RID_OWN_CHNL:
201 wreq.wi_val[0] = sc->sc_ownch;
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;
208 wreq.wi_val[0] = sc->sc_bss.chanset;
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 */
218 wreq.wi_val[0] = sc->sc_mib_mac.aPromiscuous_Enable;
221 case WI_RID_PORTTYPE:
222 if (sc->sc_mib_local.Network_Mode)
224 else if (!sc->sc_no_bssid)
230 case WI_RID_MAC_NODE:
231 memcpy(wreq.wi_val, sc->sc_mib_addr.aMAC_Address,
233 wreq.wi_len = ETHER_ADDR_LEN / 2;
236 case WI_RID_CUR_TX_RATE:
237 wreq.wi_val[0] = sc->sc_tx_rate / 10;
240 case WI_RID_RTS_THRESH:
241 wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aRTS_Threshold);
244 case WI_RID_CREATE_IBSS:
245 wreq.wi_val[0] = sc->sc_start_bss;
248 case WI_RID_SYSTEM_SCALE:
249 wreq.wi_val[0] = 1; /* low density ... not supported */
252 case WI_RID_PM_ENABLED:
253 wreq.wi_val[0] = sc->sc_mib_local.Power_Saving_Mode_Dis ? 0 : 1;
256 case WI_RID_MAX_SLEEP:
257 wreq.wi_val[0] = 0; /* not implemented */
260 case WI_RID_WEP_AVAIL:
264 case WI_RID_ENCRYPTION:
265 wreq.wi_val[0] = awi_wep_getalgo(sc);
268 case WI_RID_TX_CRYPT_KEY:
269 wreq.wi_val[0] = sc->sc_wep_defkid;
272 case WI_RID_DEFLT_CRYPT_KEYS:
273 keys = (struct wi_ltv_keys *)&wreq;
274 /* do not show keys to non-root user */
276 error = suser(curproc);
278 error = suser(curproc->p_ucred, &curproc->p_acflag);
281 memset(keys, 0, sizeof(*keys));
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);
291 k->wi_keylen = keylen;
293 wreq.wi_len = sizeof(*keys) / 2;
295 case WI_RID_MAX_DATALEN:
296 wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aMax_Frame_Length);
299 case WI_RID_IFACE_STATS:
300 /* not implemented yet */
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);
310 memcpy(&wsc.ipsrc, bp->bssid, sizeof(wsc.ipsrc));
311 wsc.signal = bp->rssi;
314 memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
317 wreq.wi_len = sizeof(wsc) * i / 2;
326 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
332 awi_cfgset(ifp, cmd, data)
337 int i, error, rate, oregion;
339 struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
340 struct ifreq *ifr = (struct ifreq *)data;
341 struct wi_ltv_keys *keys;
345 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
348 if (wreq.wi_len-- < 1)
350 switch (wreq.wi_type) {
351 case WI_RID_SERIALNO:
352 case WI_RID_NODENAME:
355 case WI_RID_OWN_SSID:
356 if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
360 if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
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)
372 case WI_RID_CURRENT_SSID:
375 case WI_RID_DESIRED_SSID:
376 if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
380 if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
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],
389 if (sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid)
392 case WI_RID_CURRENT_BSSID:
395 case WI_RID_CHANNEL_LIST:
396 if (wreq.wi_len != 1) {
400 oregion = sc->sc_mib_phy.aCurrent_Reg_Domain;
401 if (wreq.wi_val[0] == oregion)
403 sc->sc_mib_phy.aCurrent_Reg_Domain = wreq.wi_val[0];
404 error = awi_init_region(sc);
406 sc->sc_mib_phy.aCurrent_Reg_Domain = oregion;
411 case WI_RID_OWN_CHNL:
412 if (wreq.wi_len != 1) {
416 if (wreq.wi_val[0] < sc->sc_scan_min ||
417 wreq.wi_val[0] > sc->sc_scan_max) {
421 sc->sc_ownch = wreq.wi_val[0];
422 if (!sc->sc_mib_local.Network_Mode)
425 case WI_RID_CURRENT_CHAN:
428 case WI_RID_COMMS_QUALITY:
432 if (wreq.wi_len != 1) {
436 if (ifp->if_flags & IFF_PROMISC) {
437 if (wreq.wi_val[0] == 0) {
438 ifp->if_flags &= ~IFF_PROMISC;
442 if (wreq.wi_val[0] != 0) {
443 ifp->if_flags |= IFF_PROMISC;
448 case WI_RID_PORTTYPE:
449 if (wreq.wi_len != 1) {
453 switch (wreq.wi_val[0]) {
455 sc->sc_mib_local.Network_Mode = 1;
460 sc->sc_mib_local.Network_Mode = 0;
465 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
469 sc->sc_mib_local.Network_Mode = 0;
478 case WI_RID_MAC_NODE:
479 /* XXX: should be implemented? */
483 if (wreq.wi_len != 1) {
487 phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
488 switch (wreq.wi_val[0]) {
493 rate = wreq.wi_val[0] * 10;
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]);
515 for (i = 0; i < phy_rates[1]; i++) {
516 if (rate == AWI_80211_RATE(phy_rates[2 + i]))
519 if (i == phy_rates[1]) {
523 sc->sc_tx_rate = rate;
525 case WI_RID_CUR_TX_RATE:
528 case WI_RID_RTS_THRESH:
529 if (wreq.wi_len != 1) {
533 LE_WRITE_2(&sc->sc_mib_mac.aRTS_Threshold, wreq.wi_val[0]);
536 case WI_RID_CREATE_IBSS:
537 if (wreq.wi_len != 1) {
541 sc->sc_start_bss = wreq.wi_val[0] ? 1 : 0;
544 case WI_RID_SYSTEM_SCALE:
545 if (wreq.wi_len != 1) {
549 if (wreq.wi_val[0] != 1)
550 error = EINVAL; /* not supported */
552 case WI_RID_PM_ENABLED:
553 if (wreq.wi_len != 1) {
557 if (wreq.wi_val[0] != 0)
558 error = EINVAL; /* not implemented */
560 case WI_RID_MAX_SLEEP:
561 error = EINVAL; /* not implemented */
563 case WI_RID_WEP_AVAIL:
566 case WI_RID_ENCRYPTION:
567 if (wreq.wi_len != 1) {
571 error = awi_wep_setalgo(sc, wreq.wi_val[0]);
576 case WI_RID_TX_CRYPT_KEY:
577 if (wreq.wi_len != 1) {
581 if (wreq.wi_val[0] >= IEEE80211_WEP_NKID) {
585 sc->sc_wep_defkid = wreq.wi_val[1];
587 case WI_RID_DEFLT_CRYPT_KEYS:
588 if (wreq.wi_len != sizeof(*keys) / 2) {
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,
601 case WI_RID_MAX_DATALEN:
602 if (wreq.wi_len != 1) {
606 if (wreq.wi_val[0] < 350 || wreq.wi_val[0] > 2304) {
610 LE_WRITE_2(&sc->sc_mib_mac.aMax_Frame_Length, wreq.wi_val[0]);
612 case WI_RID_IFACE_STATS:
619 if (error == ENETRESET) {
620 if (sc->sc_enabled) {
622 error = awi_init(sc);