summaryrefslogtreecommitdiffstats
path: root/sys/dev/awi/awi_wicfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/awi/awi_wicfg.c')
-rw-r--r--sys/dev/awi/awi_wicfg.c632
1 files changed, 632 insertions, 0 deletions
diff --git a/sys/dev/awi/awi_wicfg.c b/sys/dev/awi/awi_wicfg.c
new file mode 100644
index 0000000..db97d63
--- /dev/null
+++ b/sys/dev/awi/awi_wicfg.c
@@ -0,0 +1,632 @@
+/* $NetBSD: awi_wicfg.c,v 1.3 2000/07/06 17:22:25 onoe Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Atsushi Onoe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * WaveLAN compatible configuration support routines for the awi driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#if defined(__FreeBSD__) && __FreeBSD_version >= 400000
+#include <sys/bus.h>
+#else
+#include <sys/device.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#ifdef __FreeBSD__
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#else
+#include <net/if_ether.h>
+#endif
+#include <net/if_media.h>
+#include <net/if_ieee80211.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#ifdef __NetBSD__
+#include <dev/ic/am79c930reg.h>
+#include <dev/ic/am79c930var.h>
+#include <dev/ic/awireg.h>
+#include <dev/ic/awivar.h>
+
+#include <dev/pcmcia/if_wi_ieee.h> /* XXX */
+#endif
+#ifdef __FreeBSD__
+#include <dev/awi/am79c930reg.h>
+#include <dev/awi/am79c930var.h>
+
+#undef _KERNEL /* XXX */
+#include <dev/wi/if_wavelan_ieee.h> /* XXX */
+#define _KERNEL /* XXX */
+#include <dev/awi/awireg.h>
+#include <dev/awi/awivar.h>
+#endif
+
+static int awi_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data);
+static int awi_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data);
+
+int
+awi_wicfg(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ int error;
+
+ switch (cmd) {
+ case SIOCGWAVELAN:
+ error = awi_cfgget(ifp, cmd, data);
+ break;
+ case SIOCSWAVELAN:
+#ifdef __FreeBSD__
+#if __FreeBSD_version < 500028
+ error = suser(curproc);
+#else
+ error = suser(curthread);
+#endif
+#else
+ error = suser(curproc->p_ucred, &curproc->p_acflag);
+#endif
+ if (error)
+ break;
+ error = awi_cfgset(ifp, cmd, data);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+static int
+awi_cfgget(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ int i, error, keylen;
+ char *p;
+ struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct wi_ltv_keys *keys;
+ struct wi_key *k;
+ struct wi_req wreq;
+#ifdef WICACHE
+ struct wi_sigcache wsc;
+ struct awi_bss *bp;
+#endif /* WICACHE */
+
+ error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
+ if (error)
+ return error;
+ switch (wreq.wi_type) {
+ case WI_RID_SERIALNO:
+ memcpy(wreq.wi_val, sc->sc_banner, AWI_BANNER_LEN);
+ wreq.wi_len = (AWI_BANNER_LEN + 1) / 2;
+ break;
+ case WI_RID_NODENAME:
+ strcpy((char *)&wreq.wi_val[1], hostname);
+ wreq.wi_val[0] = strlen(hostname);
+ wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
+ break;
+ case WI_RID_OWN_SSID:
+ p = sc->sc_ownssid;
+ wreq.wi_val[0] = p[1];
+ memcpy(&wreq.wi_val[1], p + 2, p[1]);
+ wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
+ break;
+ case WI_RID_CURRENT_SSID:
+ if (ifp->if_flags & IFF_RUNNING) {
+ p = sc->sc_bss.essid;
+ wreq.wi_val[0] = p[1];
+ memcpy(&wreq.wi_val[1], p + 2, p[1]);
+ } else {
+ wreq.wi_val[0] = 0;
+ wreq.wi_val[1] = '\0';
+ }
+ wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
+ break;
+ case WI_RID_DESIRED_SSID:
+ p = sc->sc_mib_mac.aDesired_ESS_ID;
+ wreq.wi_val[0] = p[1];
+ memcpy(&wreq.wi_val[1], p + 2, p[1]);
+ wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
+ break;
+ case WI_RID_CURRENT_BSSID:
+ if (ifp->if_flags & IFF_RUNNING)
+ memcpy(wreq.wi_val, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+ else
+ memset(wreq.wi_val, 0, ETHER_ADDR_LEN);
+ wreq.wi_len = ETHER_ADDR_LEN / 2;
+ break;
+ case WI_RID_CHANNEL_LIST:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ wreq.wi_val[0] = sc->sc_scan_min;
+ wreq.wi_val[1] = sc->sc_scan_max;
+ wreq.wi_len = 2;
+ } else {
+ wreq.wi_val[0] = 0;
+ for (i = sc->sc_scan_min; i <= sc->sc_scan_max; i++)
+ wreq.wi_val[0] |= 1 << (i - 1);
+ wreq.wi_len = 1;
+ }
+ break;
+ case WI_RID_OWN_CHNL:
+ wreq.wi_val[0] = sc->sc_ownch;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_CURRENT_CHAN:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ wreq.wi_val[0] = sc->sc_bss.pattern;
+ else
+ wreq.wi_val[0] = sc->sc_bss.chanset;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_COMMS_QUALITY:
+ wreq.wi_val[0] = 0; /* quality */
+ wreq.wi_val[1] = sc->sc_bss.rssi; /* signal */
+ wreq.wi_val[2] = 0; /* noise */
+ wreq.wi_len = 3;
+ break;
+ case WI_RID_PROMISC:
+ wreq.wi_val[0] = sc->sc_mib_mac.aPromiscuous_Enable;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_PORTTYPE:
+ if (sc->sc_mib_local.Network_Mode)
+ wreq.wi_val[0] = 1;
+ else if (!sc->sc_no_bssid)
+ wreq.wi_val[0] = 2;
+ else
+ wreq.wi_val[0] = 3;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_MAC_NODE:
+ memcpy(wreq.wi_val, sc->sc_mib_addr.aMAC_Address,
+ ETHER_ADDR_LEN);
+ wreq.wi_len = ETHER_ADDR_LEN / 2;
+ break;
+ case WI_RID_TX_RATE:
+ case WI_RID_CUR_TX_RATE:
+ wreq.wi_val[0] = sc->sc_tx_rate / 10;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_RTS_THRESH:
+ wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aRTS_Threshold);
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_CREATE_IBSS:
+ wreq.wi_val[0] = sc->sc_start_bss;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_SYSTEM_SCALE:
+ wreq.wi_val[0] = 1; /* low density ... not supported */
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_PM_ENABLED:
+ wreq.wi_val[0] = sc->sc_mib_local.Power_Saving_Mode_Dis ? 0 : 1;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_MAX_SLEEP:
+ wreq.wi_val[0] = 0; /* not implemented */
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_WEP_AVAIL:
+ wreq.wi_val[0] = 1;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_ENCRYPTION:
+ wreq.wi_val[0] = awi_wep_getalgo(sc);
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_TX_CRYPT_KEY:
+ wreq.wi_val[0] = sc->sc_wep_defkid;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_DEFLT_CRYPT_KEYS:
+ keys = (struct wi_ltv_keys *)&wreq;
+ /* do not show keys to non-root user */
+#ifdef __FreeBSD__
+#if __FreeBSD_version < 500028
+ error = suser(curproc);
+#else
+ error = suser(curthread);
+#endif
+#else
+ error = suser(curproc->p_ucred, &curproc->p_acflag);
+#endif
+ if (error) {
+ memset(keys, 0, sizeof(*keys));
+ error = 0;
+ break;
+ }
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ k = &keys->wi_keys[i];
+ keylen = sizeof(k->wi_keydat);
+ error = awi_wep_getkey(sc, i, k->wi_keydat, &keylen);
+ if (error)
+ break;
+ k->wi_keylen = keylen;
+ }
+ wreq.wi_len = sizeof(*keys) / 2;
+ break;
+ case WI_RID_MAX_DATALEN:
+ wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aMax_Frame_Length);
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_IFACE_STATS:
+ /* not implemented yet */
+ wreq.wi_len = 0;
+ break;
+#ifdef WICACHE
+ case WI_RID_READ_CACHE:
+ for (bp = TAILQ_FIRST(&sc->sc_scan), i = 0;
+ bp != NULL && i < MAXWICACHE;
+ bp = TAILQ_NEXT(bp, list), i++) {
+ memcpy(wsc.macsrc, bp->esrc, ETHER_ADDR_LEN);
+ /*XXX*/
+ memcpy(&wsc.ipsrc, bp->bssid, sizeof(wsc.ipsrc));
+ wsc.signal = bp->rssi;
+ wsc.noise = 0;
+ wsc.quality = 0;
+ memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
+ &wsc, sizeof(wsc));
+ }
+ wreq.wi_len = sizeof(wsc) * i / 2;
+ break;
+#endif /* WICACHE */
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error == 0) {
+ wreq.wi_len++;
+ error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
+ }
+ return error;
+}
+
+static int
+awi_cfgset(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ int i, error, rate, oregion;
+ u_int8_t *phy_rates;
+ struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct wi_ltv_keys *keys;
+ struct wi_key *k;
+ struct wi_req wreq;
+
+ error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
+ if (error)
+ return error;
+ if (wreq.wi_len-- < 1)
+ return EINVAL;
+ switch (wreq.wi_type) {
+ case WI_RID_SERIALNO:
+ case WI_RID_NODENAME:
+ error = EPERM;
+ break;
+ case WI_RID_OWN_SSID:
+ if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ memset(sc->sc_ownssid, 0, AWI_ESS_ID_SIZE);
+ sc->sc_ownssid[0] = IEEE80211_ELEMID_SSID;
+ sc->sc_ownssid[1] = wreq.wi_val[0];
+ memcpy(&sc->sc_ownssid[2], &wreq.wi_val[1], wreq.wi_val[0]);
+ if (!sc->sc_mib_local.Network_Mode &&
+ !sc->sc_no_bssid && sc->sc_start_bss)
+ error = ENETRESET;
+ break;
+ case WI_RID_CURRENT_SSID:
+ error = EPERM;
+ break;
+ case WI_RID_DESIRED_SSID:
+ if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
+ sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
+ sc->sc_mib_mac.aDesired_ESS_ID[1] = wreq.wi_val[0];
+ memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], &wreq.wi_val[1],
+ wreq.wi_val[0]);
+ if (sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid)
+ error = ENETRESET;
+ break;
+ case WI_RID_CURRENT_BSSID:
+ error = EPERM;
+ break;
+ case WI_RID_CHANNEL_LIST:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ oregion = sc->sc_mib_phy.aCurrent_Reg_Domain;
+ if (wreq.wi_val[0] == oregion)
+ break;
+ sc->sc_mib_phy.aCurrent_Reg_Domain = wreq.wi_val[0];
+ error = awi_init_region(sc);
+ if (error) {
+ sc->sc_mib_phy.aCurrent_Reg_Domain = oregion;
+ break;
+ }
+ error = ENETRESET;
+ break;
+ case WI_RID_OWN_CHNL:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] < sc->sc_scan_min ||
+ wreq.wi_val[0] > sc->sc_scan_max) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_ownch = wreq.wi_val[0];
+ if (!sc->sc_mib_local.Network_Mode)
+ error = ENETRESET;
+ break;
+ case WI_RID_CURRENT_CHAN:
+ error = EPERM;
+ break;
+ case WI_RID_COMMS_QUALITY:
+ error = EPERM;
+ break;
+ case WI_RID_PROMISC:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (ifp->if_flags & IFF_PROMISC) {
+ if (wreq.wi_val[0] == 0) {
+ ifp->if_flags &= ~IFF_PROMISC;
+ error = ENETRESET;
+ }
+ } else {
+ if (wreq.wi_val[0] != 0) {
+ ifp->if_flags |= IFF_PROMISC;
+ error = ENETRESET;
+ }
+ }
+ break;
+ case WI_RID_PORTTYPE:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ switch (wreq.wi_val[0]) {
+ case 1:
+ sc->sc_mib_local.Network_Mode = 1;
+ sc->sc_no_bssid = 0;
+ error = ENETRESET;
+ break;
+ case 2:
+ sc->sc_mib_local.Network_Mode = 0;
+ sc->sc_no_bssid = 0;
+ error = ENETRESET;
+ break;
+ case 3:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_mib_local.Network_Mode = 0;
+ sc->sc_no_bssid = 1;
+ error = ENETRESET;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case WI_RID_MAC_NODE:
+ /* XXX: should be implemented? */
+ error = EPERM;
+ break;
+ case WI_RID_TX_RATE:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
+ switch (wreq.wi_val[0]) {
+ case 1:
+ case 2:
+ case 5:
+ case 11:
+ rate = wreq.wi_val[0] * 10;
+ if (rate == 50)
+ rate += 5; /*XXX*/
+ break;
+ case 3:
+ case 6:
+ case 7:
+ /* auto rate */
+ phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
+ rate = AWI_RATE_1MBIT;
+ for (i = 0; i < phy_rates[1]; i++) {
+ if (AWI_80211_RATE(phy_rates[2 + i]) > rate)
+ rate = AWI_80211_RATE(phy_rates[2 + i]);
+ }
+ break;
+ default:
+ rate = 0;
+ error = EINVAL;
+ break;
+ }
+ if (error)
+ break;
+ for (i = 0; i < phy_rates[1]; i++) {
+ if (rate == AWI_80211_RATE(phy_rates[2 + i]))
+ break;
+ }
+ if (i == phy_rates[1]) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_tx_rate = rate;
+ break;
+ case WI_RID_CUR_TX_RATE:
+ error = EPERM;
+ break;
+ case WI_RID_RTS_THRESH:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ LE_WRITE_2(&sc->sc_mib_mac.aRTS_Threshold, wreq.wi_val[0]);
+ error = ENETRESET;
+ break;
+ case WI_RID_CREATE_IBSS:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_start_bss = wreq.wi_val[0] ? 1 : 0;
+ error = ENETRESET;
+ break;
+ case WI_RID_SYSTEM_SCALE:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] != 1)
+ error = EINVAL; /* not supported */
+ break;
+ case WI_RID_PM_ENABLED:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] != 0)
+ error = EINVAL; /* not implemented */
+ break;
+ case WI_RID_MAX_SLEEP:
+ error = EINVAL; /* not implemented */
+ break;
+ case WI_RID_WEP_AVAIL:
+ error = EPERM;
+ break;
+ case WI_RID_ENCRYPTION:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ error = awi_wep_setalgo(sc, wreq.wi_val[0]);
+ if (error)
+ break;
+ error = ENETRESET;
+ break;
+ case WI_RID_TX_CRYPT_KEY:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] >= IEEE80211_WEP_NKID) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_wep_defkid = wreq.wi_val[1];
+ break;
+ case WI_RID_DEFLT_CRYPT_KEYS:
+ if (wreq.wi_len != sizeof(*keys) / 2) {
+ error = EINVAL;
+ break;
+ }
+ keys = (struct wi_ltv_keys *)&wreq;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ k = &keys->wi_keys[i];
+ error = awi_wep_setkey(sc, i, k->wi_keydat,
+ k->wi_keylen);
+ if (error)
+ break;
+ }
+ break;
+ case WI_RID_MAX_DATALEN:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] < 350 || wreq.wi_val[0] > 2304) {
+ error = EINVAL;
+ break;
+ }
+ LE_WRITE_2(&sc->sc_mib_mac.aMax_Frame_Length, wreq.wi_val[0]);
+ break;
+ case WI_RID_IFACE_STATS:
+ error = EPERM;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error == ENETRESET) {
+ if (sc->sc_enabled) {
+ awi_stop(sc);
+ error = awi_init(sc);
+ } else
+ error = 0;
+ }
+ return error;
+}
OpenPOWER on IntegriCloud