From 988426d9e5e2673a75c07ef74e5913b96ac913f5 Mon Sep 17 00:00:00 2001 From: fjoe Date: Mon, 15 Mar 2004 22:24:28 +0000 Subject: Add arl(4): driver for Aironet Arlan 655 wireless adapters. MFC after: 2 weeks --- share/man/man4/man4.i386/Makefile | 1 + share/man/man4/man4.i386/arl.4 | 78 +++ sys/conf/files.i386 | 2 + sys/dev/arl/if_arl.c | 973 ++++++++++++++++++++++++++++++++++++++ sys/dev/arl/if_arl_isa.c | 354 ++++++++++++++ sys/dev/arl/if_arlreg.h | 310 ++++++++++++ sys/i386/conf/NOTES | 5 + sys/modules/Makefile | 2 + sys/modules/arl/Makefile | 10 + usr.sbin/Makefile | 2 + usr.sbin/arlconfig/Makefile | 11 + usr.sbin/arlconfig/arlconfig.8 | 236 +++++++++ usr.sbin/arlconfig/arlconfig.c | 612 ++++++++++++++++++++++++ usr.sbin/arlcontrol/arlcontrol.8 | 236 +++++++++ usr.sbin/arlcontrol/arlcontrol.c | 612 ++++++++++++++++++++++++ 15 files changed, 3444 insertions(+) create mode 100644 share/man/man4/man4.i386/arl.4 create mode 100644 sys/dev/arl/if_arl.c create mode 100644 sys/dev/arl/if_arl_isa.c create mode 100644 sys/dev/arl/if_arlreg.h create mode 100644 sys/modules/arl/Makefile create mode 100644 usr.sbin/arlconfig/Makefile create mode 100644 usr.sbin/arlconfig/arlconfig.8 create mode 100644 usr.sbin/arlconfig/arlconfig.c create mode 100644 usr.sbin/arlcontrol/arlcontrol.8 create mode 100644 usr.sbin/arlcontrol/arlcontrol.c diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile index 6f2fe18..bb36a96 100644 --- a/share/man/man4/man4.i386/Makefile +++ b/share/man/man4/man4.i386/Makefile @@ -6,6 +6,7 @@ MAN= acpi_toshiba.4 \ amdpm.4 \ apm.4 \ ar.4 \ + arl.4 \ CPU_ELAN.4 \ cs.4 \ ct.4 \ diff --git a/share/man/man4/man4.i386/arl.4 b/share/man/man4/man4.i386/arl.4 new file mode 100644 index 0000000..9da1798 --- /dev/null +++ b/share/man/man4/man4.i386/arl.4 @@ -0,0 +1,78 @@ +.\" Copyright (c) 1997, 1998, 1999 +.\" Bill Paul . All rights reserved. +.\" +.\" 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 Bill Paul. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 26, 2003 +.Dt ARL 4 +.Os +.Sh NAME +.Nm arl +.Nd "Aironet Arlan 655 wireless network adapter driver" +.Sh SYNOPSIS +.Cd "device arl" +.Sh DESCRIPTION +The +.Nm +driver provides support for Aironet Arlan 655 +wireless network adapter. +The Arlan 655 series adapters operate at 354kbps, 512kbps, 1Mbps and 2Mbps. +.Pp +The Aironet Arlan 655 devices support Aironet TMA, Aironet Non-TMA +and PSP operating modes. +.Pp +By default, the +.Nm +driver configures the Aironet Aironet 655 card for TMA operation. +.Pp +For setup Radio Network parameters use +.Xr arlconfig 8 . +.Sh SEE ALSO +.Xr arp 4 , +.Xr netintro 4 , +.Xr arlconfig 8 , +.Xr ifconfig 8 +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 5.3 . +.Sh AUTHORS +The +.Nm +driver initally was written by +.An Ivan Sharov Aq ivan.sharov@iname.com . +.Aq ran@styx.aic.net +wrote arlconfig utility and added ioctl support to the driver. +.An Stanislav Svirid Aq count@riss-telecom.ru +ported this driver to new ISA architechture, merged some al driver changes, +fixed some bugs and made it a module. +.An Yuri Kurenkov Aq y.kurenkov@init.ru +wrote this manpage. diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index d0a98b8..ee0bf1a 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -122,6 +122,8 @@ dev/aic/aic_isa.c optional aic isa dev/ar/if_ar.c optional ar dev/ar/if_ar_pci.c optional ar pci dev/ar/if_ar_isa.c optional ar isa +dev/arl/if_arl.c optional arl +dev/arl/if_arl_isa.c optional arl isa dev/cm/if_cm_isa.c optional cm isa dev/ctau/ctau.c optional ctau dev/ctau/ctddk.c optional ctau diff --git a/sys/dev/arl/if_arl.c b/sys/dev/arl/if_arl.c new file mode 100644 index 0000000..63bb4b7 --- /dev/null +++ b/sys/dev/arl/if_arl.c @@ -0,0 +1,973 @@ +/* + * $RISS: if_arl/dev/arl/if_arl.c,v 1.5 2004/01/22 12:49:05 frol Exp $ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +/*#define DEBUG */ +#ifdef DEBUG +#define D(x) {printf("arl%d: ", sc->arl_unit); printf x; } +#else +#define D(x) +#endif + +/* + * channel attention + */ +#define ARL_CHANNEL(sc) \ + { \ + D(("channel ctrl %x reg %x\n", sc->arl_control, ar->controlRegister)); \ + ar->controlRegister = (sc->arl_control ^= ARL_CHANNEL_ATTENTION); \ + } + +/* + * Check registration + */ +#define ARL_CHECKREG(sc) (ar->registrationMode && ar->registrationStatus == 0) + +#ifndef BPF_MTAP +#define BPF_MTAP(_ifp,_m) \ + do { \ + if ((_ifp)->if_bpf) \ + bpf_mtap((_ifp), (_m)); \ + } while (0) +#endif + +#if __FreeBSD_version < 500100 +#define BROADCASTADDR (etherbroadcastaddr) +#define _ARL_CURPROC (curproc) +#else +#define BROADCASTADDR (sc->arpcom.ac_if.if_broadcastaddr) +#define _ARL_CURPROC (curthread) +#endif + +static void arl_hwreset (struct arl_softc *); +static void arl_reset (struct arl_softc *); +static int arl_ioctl (struct ifnet *, u_long, caddr_t); +static void arl_init (void *); +static void arl_start (struct ifnet *); + +static void arl_watchdog (struct ifnet *); +static void arl_waitreg (struct ifnet *); + +static void arl_enable (struct arl_softc *); +static void arl_config (struct arl_softc *); +static int arl_command (struct arl_softc *); +static void arl_put (struct arl_softc *); + +static void arl_read (struct arl_softc *, caddr_t, int); +static void arl_recv (struct arl_softc *); +static struct mbuf* arl_get (caddr_t, int, int, struct ifnet *); + +devclass_t arl_devclass; + +/* + * Attach device + */ +int +arl_attach(dev) + device_t dev; +{ + struct arl_softc* sc = device_get_softc(dev); + struct ifnet *ifp = &sc->arpcom.ac_if; + int attached; + + D(("attach\n")); + + if (ar->configuredStatusFlag == 0 && bootverbose) + printf("arl%d: card is NOT configured\n", sc->arl_unit); + + arl_reset (sc); + attached = (ifp->if_softc != 0); + + /* Initialize ifnet structure. */ + ifp->if_softc = sc; +#if __FreeBSD_version < 502000 + ifp->if_unit = sc->arl_unit; + ifp->if_name = "arl"; +#else + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); +#endif + ifp->if_mtu = ETHERMTU; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_output = ether_output; + ifp->if_start = arl_start; + ifp->if_ioctl = arl_ioctl; + ifp->if_watchdog = arl_watchdog; + ifp->if_init = arl_init; + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + ifp->if_baudrate = 2000000; + ifp->if_timer = 0; + + /* + * Attach the interface + */ + if (!attached) { +#if __FreeBSD_version < 500100 + ether_ifattach(ifp, ETHER_BPF_SUPPORTED); +#else + ether_ifattach(ifp, sc->arpcom.ac_enaddr); +#endif + } + + return (0); +} + +/* + * Hardware reset + * reset all setting to default ( setted ARLANDGS ) + */ +static void +arl_hwreset(sc) + struct arl_softc *sc; +{ + D(("hw reset\n")); + + ar->controlRegister = 1; + DELAY(ARDELAY1); + + if (arl_wait_reset(sc, 0x24, ARDELAY1)) + arl_stop(sc); + + ar->controlRegister = (sc->arl_control = 1); + DELAY(ARDELAY1); +} + + +/* + * wait arlan command + */ +static int +arl_command(sc) + struct arl_softc *sc; +{ + int i; /* long stuppid delay ??? */ + + D(("commandByte %x\n", ar->commandByte)); + + for (i = 100000; ar->commandByte && i; i--) + ; + + if (i == 0) + ar->commandByte = 0; + + return (i == 0); +} + +/* + * Enable for recieveng + */ +static void +arl_enable(sc) + struct arl_softc *sc; +{ + D(("enable\n")); + sc->arl_control = (ARL_INTERRUPT_ENABLE | ARL_CLEAR_INTERRUPT); + ar->controlRegister = sc->arl_control; + arl_command(sc); + + ar->rxStatusVector = 0; + ar->commandByte = 0x83; + ar->commandParameter[0] = 1; + ARL_CHANNEL(sc); + arl_command(sc); +} + +/* + * reset and set user parameters + */ +static void +arl_reset(sc) + struct arl_softc *sc; +{ + D(("reset\n")); + arl_hwreset(sc); + + ar->resetFlag1 = 1; + bzero((ar), 0x1FF0); /* fill memory board with 0 */ + ar->resetFlag1 = 0; + + sc->arl_control = 0; + +/* if (arl_wait_reset(sc, 0x168, ARDELAY1)) + return; + */ +#if 1 + { + int cnt = 0x168; + int delay = ARDELAY1; + + ar->resetFlag = 0xFF; /* wish reset */ + ar->controlRegister = 0; /* unreeze - do it */ + + while (ar->resetFlag && cnt--) + DELAY(delay); + + if (cnt == 0) { + printf("arl%d: reset timeout\n", sc->arl_unit); + return; + } + + D(("reset wait %d\n", 0x168 - cnt)); + } +#endif + + if (ar->diagnosticInfo != 0xff) { + printf("arl%d: reset error\n", sc->arl_unit); + return; + } + arl_config(sc); +} + +/* + * configure radio parameters + */ +static void +arl_config(sc) + struct arl_softc *sc; +{ + int i; + + D(("config\n")); + + SET_ARL_PARAM(spreadingCode); + SET_ARL_PARAM(channelNumber); + SET_ARL_PARAM(channelSet); + SET_ARL_PARAM(registrationMode); + SET_ARL_PARAM(priority); + SET_ARL_PARAM(receiveMode); + + bcopy(arcfg.sid, ar->systemId, 4 * sizeof(ar->systemId[0])); + bcopy(arcfg.specifiedRouter, ar->specifiedRouter, ETHER_ADDR_LEN); + bcopy(arcfg.lanCardNodeId, ar->lanCardNodeId, ETHER_ADDR_LEN); + + bzero(ar->name, ARLAN_NAME_SIZE); /* clear name */ + strncpy(ar->name, arcfg.name, ARLAN_NAME_SIZE); + + ar->diagnosticInfo = 0; + ar->commandByte = 1; + ARL_CHANNEL(sc); + DELAY(ARDELAY1); +/* + if (arl_command(sc) != 0) { + int i; + + for (i = 0x168; ar->diagnosticInfo == 0 && i; i--) { + DELAY(ARDELAY1); + } + + if (i != 0 && ar->diagnosticInfo != 0xff) + printf("arl%d: config error\n", sc->arl_unit); + else if (i == 0) + printf("arl%d: config timeout\n", sc->arl_unit); + + } else + printf("arl%d: config failed\n", sc->arl_unit); +*/ + if (arl_command(sc)) { + D(("config failed\n")); + return; + } + + for (i = 0x168; ar->diagnosticInfo == 0 && i; i--) + DELAY(ARDELAY1); + + if (i == 0) { + D(("config timeout\n")); + return; + } + + if (ar->diagnosticInfo != 0xff) { + D(("config error\n")); + return; + } + + D(("config lanCardNodeId %6D\n", ar->lanCardNodeId, ":")); + D(("config channel set %d, frequency %d, spread %d, mode %d\n", + ar->channelSet, + ar->channelNumber, + ar->spreadingCode, + ar->registrationMode)); + /* clear quality stat */ + bzero(&(aqual), ARLAN_MAX_QUALITY * sizeof(aqual[0])); +} + +/* + * Socket Ioctl's. + */ +static int +arl_ioctl(ifp, cmd, data) + register struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct arl_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + d_thread_t *td = _ARL_CURPROC; + struct arl_req arlan_io; + int count, s, error = 0; + caddr_t user; + + D(("ioctl %lx\n", cmd)); + s = splimp(); + + switch (cmd) { + case SIOCSIFADDR: + case SIOCGIFADDR: + case SIOCSIFMTU: + error = ether_ioctl(ifp, cmd, data); + break; + + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_flags & IFF_RUNNING)) + arl_init(sc); + } else { + if (ifp->if_flags & IFF_RUNNING) + arl_stop(sc); + } + break; + +#define GET_PARAM(name) (arlan_io.cfg.name = ar->name) + +#define GET_COPY_PARAM(name) \ + { \ + bzero(arlan_io.cfg.name, sizeof(arlan_io.cfg.name)); \ + bcopy(ar->name, arlan_io.cfg.name, sizeof(arlan_io.cfg.name)); \ + } + + case SIOCGARLALL: + bzero(&arlan_io, sizeof(arlan_io)); + if (!suser(td)) { + bcopy(ar->systemId, arlan_io.cfg.sid, 4); + } + + GET_COPY_PARAM(name); + GET_COPY_PARAM(lanCardNodeId); + GET_COPY_PARAM(specifiedRouter); + GET_PARAM(channelNumber); + GET_PARAM(channelSet); + GET_PARAM(spreadingCode); + GET_PARAM(registrationMode); + GET_PARAM(hardwareType); + GET_PARAM(majorHardwareVersion); + GET_PARAM(minorHardwareVersion); + GET_PARAM(radioModule); + GET_PARAM(priority); + GET_PARAM(receiveMode); + arlan_io.cfg.txRetry = arcfg.txRetry; + + user = (void *)ifr->ifr_data; + for (count = 0; count < sizeof(arlan_io); count++) + if (subyte(user + count, ((char *)&arlan_io)[count])) + return (EFAULT); + break; + +#define SET_PARAM(name) \ + do { \ + if (arlan_io.what_set & ARLAN_SET_##name) \ + arcfg.name = arlan_io.cfg.name; \ + } while (0) +#define SET_COPY_PARAM(name) \ + do { \ + if (arlan_io.what_set & ARLAN_SET_##name) { \ + bzero(arcfg.name, sizeof(arcfg.name)); \ + bcopy(arlan_io.cfg.name, arcfg.name, sizeof(arcfg.name)); \ + } \ + } while (0) + + case SIOCSARLALL: + if (suser(td)) + break; + + user = (void *)ifr->ifr_data; + for (count = 0; count < sizeof(arlan_io); count++) { + if (fubyte(user + count) < 0) + return (EFAULT); + } + + bcopy(user, (char *)&arlan_io, sizeof(arlan_io)); + + D(("need set 0x%04x\n", arlan_io.what_set)); + + if (arlan_io.what_set) { + SET_COPY_PARAM(name); + SET_COPY_PARAM(sid); + SET_COPY_PARAM(specifiedRouter); + SET_COPY_PARAM(lanCardNodeId); + SET_PARAM(channelSet); + SET_PARAM(channelNumber); + SET_PARAM(spreadingCode); + SET_PARAM(registrationMode); + SET_PARAM(priority); + SET_PARAM(receiveMode); + + if (arlan_io.what_set & ARLAN_SET_txRetry) + arcfg.txRetry = arlan_io.cfg.txRetry; + + arl_config(sc); + } +#undef SET_COPY_PARAM +#undef SET_PARAM +#undef GET_COPY_PARAM +#undef GET_PARAM + break; + + case SIOCGARLQLT: + user = (void *)ifr->ifr_data; + for (count = 0; count < sizeof(struct arl_quality); count++) { + if (fubyte(user + count) < 0) + return (EFAULT); + } + while (ar->interruptInProgress) ; /* wait */ + bcopy(&(aqual), (void *)ifr->ifr_data, sizeof(aqual)); + break; + + case SIOCGARLSTB: + user = (void *)ifr->ifr_data; + for (count = 0; count < sizeof(struct arl_stats); count++) { + if (fubyte(user + count) < 0) + return (EFAULT); + } + + while (ar->lancpuLock) ; + ar->hostcpuLock = 1; + bcopy(&(ar->stat), (void *)ifr->ifr_data, sizeof(struct arl_stats)); + ar->hostcpuLock = 0; + break; + + default: + error = EINVAL; + } + + splx(s); + + return (error); +} + +/* + * Wait registration + */ +static void +arl_waitreg(ifp) + struct ifnet *ifp; +{ + struct arl_softc *sc = ifp->if_softc; + + D(("wait reg\n")); + + if (ifp->if_flags & IFF_RUNNING) { + if (ARL_CHECKREG(sc)) { + /* wait registration */ + D(("wait registration\n")); + ifp->if_watchdog = arl_waitreg; + ifp->if_timer = 2; + } else { + /* registration restored */ + D(("registration restored\n")); + ifp->if_timer = 0; + arl_init(sc); + } + } +} + +/* + * Handle transmit timeouts. + */ +static void +arl_watchdog(ifp) + struct ifnet *ifp; +{ + struct arl_softc *sc = ifp->if_softc; + + if (!(ifp->if_flags & IFF_RUNNING)) + return; + + D(("device timeout\n")); + + if (ARL_CHECKREG(sc)) { + /* Lost registratoin */ + D(("timeout lost registration\n")); + ifp->if_watchdog = arl_waitreg; + ifp->if_timer = 2; + } +} + +/* + * Initialize + */ +static void +arl_init(xsc) + void *xsc; +{ + struct arl_softc *sc = xsc; + struct ifnet *ifp = &sc->arpcom.ac_if; + int s; + + D(("init\n")); + + if (TAILQ_EMPTY(&ifp->if_addrhead)) + return; + + s = splimp(); + + if (ARL_CHECKREG(sc)) + arl_reset(sc); + + arl_enable(sc); + + /* set flags */ + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + arl_start(ifp); + + splx(s); + D(("init done\n")); +} + +/* + * Put buffer into arlan buffer and start transmit + */ +static void +arl_put(sc) + struct arl_softc *sc; +{ + struct arl_tx_param txp; + int i; + + if (ARL_CHECKREG(sc)) + sc->arpcom.ac_if.if_oerrors++; + + /* copy dst adr */ + for(i = 0; i < 6; i++) + txp.dest[i] = sc->arl_tx[i]; + txp.clear = 0; + txp.retries = arcfg.txRetry; /* use default value */ + txp.routing = 1; + txp.scrambled = 0; + txp.offset = (intptr_t)ar->txBuffer - (intptr_t)(ar); + txp.length = sc->tx_len - ARLAN_HEADER_SIZE; + +#ifdef SEND_ARLAN_HEADER + if (ar->registrationMode != 1) + txp.length = sc->tx_len; +#endif + + /* copy from internal buffer to adapter memory */ +#ifdef SEND_ARLAN_HEADER + if (ar->registrationMode) +#endif + bcopy(sc->arl_tx + ARLAN_HEADER_SIZE, + ar->txBuffer, + sc->tx_len - ARLAN_HEADER_SIZE); +#ifdef SEND_ARLAN_MODE + else + bcopy(sc->arl_tx, ar->txBuffer, sc->tx_len); +#endif + + /* copy command parametr */ + bcopy(&txp, ar->commandParameter, 14); + ar->commandByte = 0x85; /* send command */ + ARL_CHANNEL(sc); + if (arl_command(sc)) + sc->arpcom.ac_if.if_oerrors++; +} + +/* + * start output + */ +static void +arl_start(ifp) + struct ifnet *ifp; +{ + struct arl_softc *sc; + struct mbuf *m; + struct mbuf *m0 = NULL; + + sc = ifp->if_softc; + + D(("start\n")); + + /* Don't do anything if output is active */ + if (ifp->if_flags & IFF_OACTIVE) + return; + + /* Dequeue the next datagram */ + IF_DEQUEUE(&ifp->if_snd, m0); + + /* If there's nothing to send, return. */ + if (m0 != NULL) { + ifp->if_flags |= IFF_OACTIVE; + + /* Copy the datagram to the buffer. */ + sc->tx_len = 0; + for(m = m0; m != NULL; m = m->m_next) { + if (m->m_len == 0) + continue; + bcopy(mtod(m, caddr_t), + sc->arl_tx + sc->tx_len, m->m_len); + sc->tx_len += m->m_len; + } + + /* if packet size is less than minimum ethernet frame size, + * pad it with zeroes to that size */ + if (sc->tx_len < ETHER_MIN_LEN) { + bzero(sc->arl_tx + sc->tx_len, ETHER_MIN_LEN - sc->tx_len); + sc->tx_len = ETHER_MIN_LEN; + } + + /* Give the packet to the bpf, if any */ + BPF_MTAP(ifp, m0); + + m_freem(m0); + + /* Now transmit the datagram */ + ifp->if_timer = 1; /* wait 1 sec */ + + ifp->if_watchdog = arl_watchdog; + arl_put(sc); + } +} + +/* + * stop interface + */ +void +arl_stop(sc) + struct arl_softc *sc; +{ + struct ifnet *ifp; + int s; + + s = splimp(); + + ifp = &sc->arpcom.ac_if; + + ifp->if_timer = 0; /* disable timer */ + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + /* arl_hwreset( unit ); */ + sc->rx_len = 0; + sc->tx_len = 0; + /* disable interrupt */ + ar->controlRegister = 0; + + splx(s); +} + +/* + * Pull read data off a interface. + * Len is length of data, with local net header stripped. + */ +static struct mbuf* +arl_get(buf, totlen, off0, ifp) + caddr_t buf; + int totlen; + int off0; + struct ifnet * ifp; +{ + struct mbuf *top, **mp, *m; + int off = off0, len; + caddr_t cp = buf; + char *epkt; + + cp = buf; + epkt = cp + totlen; + + if (off) { + cp += off + 2 * sizeof(u_short); + totlen -= 2 * sizeof(u_short); + } + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = totlen; + m->m_len = MHLEN; + top = 0; + mp = ⊤ + while (totlen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + return (0); + } + m->m_len = MLEN; + } + len = min(totlen, epkt - cp); + if (len >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + m->m_len = len = min(len, MCLBYTES); + else + len = m->m_len; + } else { + /* + * * Place initial small packet/header at end of mbuf. + * */ + if (len < m->m_len) { + if (top == 0 && len + max_linkhdr <= m->m_len) + m->m_data += max_linkhdr; + m->m_len = len; + } else + len = m->m_len; + } + bcopy(cp, mtod(m, caddr_t), (unsigned)len); + cp += len; + *mp = m; + mp = &m->m_next; + totlen -= len; + if (cp == epkt) + cp = buf; + } + + return (top); +} + +/* ------------------------------------------------------------------ + * * Pass a packet up to the higher levels. + * */ +static void +arl_read(sc, buf, len) + struct arl_softc *sc; + caddr_t buf; + int len; +{ + register struct ether_header *eh; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + + eh = (struct ether_header *)buf; + /* + * Check if there's a bpf filter listening on this interface. + * If so, hand off the raw packet to bpf. + */ + if (ifp->if_bpf) { + /* + * Note that the interface cannot be in promiscuous mode if + * there are no bpf listeners. And if el are in promiscuous + * mode, el have to check if this packet is really ours. + * + * This test does not support multicasts. + */ + if ((ifp->if_flags & IFF_PROMISC) + && bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, + sizeof(eh->ether_dhost)) != 0 + && bcmp(eh->ether_dhost, BROADCASTADDR, + sizeof(eh->ether_dhost)) != 0) + return; + } + /* + * Pull packet off interface. + */ +#if __FreeBSD_version < 500100 + buf += sizeof(struct ether_header); + len -= sizeof(struct ether_header); +#endif + m = arl_get(buf, len, 0, ifp); + if (m == 0) + return; + +#if __FreeBSD_version < 500100 + ether_input(ifp, eh, m); +#else + (*ifp->if_input)(ifp, m); +#endif +} + +/* + * get packet from adapter + */ +static void +arl_recv(sc) + struct arl_softc *sc; +{ + sc->rx_len = ar->rxLength; + + if (sc->rx_len) { +#ifdef SEND_ARLAN_HEADER + if (ar->registrationMode == 1) { +#endif + bcopy(ar->ultimateDestAddress, sc->arl_rx, 6); + bcopy(ar->rxSrc, (char*)sc->arl_rx + 6, 6); + bcopy((char *)(ar) + ar->rxOffset, + (char *)sc->arl_rx + 12, + sc->rx_len); + sc->rx_len += ARLAN_HEADER_SIZE; +#ifdef SEND_ARLAN_HEADER + } else { + bcopy((char *)(ar) + ar->rxOffset, + (char *)sc->arl_rx, sc->rx_len); + } +#endif + } +} + +/* + * Ethernet interface interrupt processor + */ +void +arl_intr(arg) + void *arg; +{ + register struct arl_softc *sc = (struct arl_softc *) arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + /* enable interrupt */ + ar->controlRegister = (sc->arl_control & ~ARL_CLEAR_INTERRUPT); + ar->controlRegister = (sc->arl_control | ARL_CLEAR_INTERRUPT); + + if (ar->txStatusVector) { + if (ar->txStatusVector != 1) + sc->arpcom.ac_if.if_collisions++; + ifp->if_timer = 0; /* disable timer */ + ifp->if_flags &= ~IFF_OACTIVE; + arl_start(ifp); + ar->txStatusVector = 0; +/* (sc->quality.txLevel)[ar->txAckQuality & 0x0f]++; + (sc->quality.txQuality)[(ar->txAckQuality & 0xf0) >> 4]++;*/ + } + + if (ar->rxStatusVector) { +/* (sc->quality.rxLevel)[ar->rxQuality & 0x0f]++; + (sc->quality.rxQuality)[(ar->rxQuality & 0xf0) >> 4]++; */ + if (ar->rxStatusVector == 1) { /* it is data frame */ + arl_recv(sc); + arl_read(sc, sc->arl_rx, sc->rx_len); + ifp->if_opackets++; + } + ar->rxStatusVector = 0; + + ar->commandByte = 0x83; + ar->commandParameter[0] = 1; + ARL_CHANNEL(sc); + if (arl_command(sc)) + ifp->if_ierrors++; + } + + return; +} + +/* + * waiting for resetFlag dropped + */ +int +arl_wait_reset(sc, cnt, delay) + struct arl_softc *sc; + int cnt; + int delay; +{ + D(("wait_reset cnt=%d delay=%d\n", cnt, delay)); + + ar->resetFlag = 1; /* wish reset */ + ar->controlRegister = 0; /* unreeze - do it */ + + while (ar->resetFlag && cnt--) + DELAY(delay); + + D(("reset done. %d cycles left\n", cnt)); + + if (cnt == 0) + printf("arl%d: reset failed\n", sc->arl_unit); + + return (cnt == 0); +} + +/* + * Allocate an irq resource with the given resource id + */ +int +arl_alloc_irq(dev, rid, flags) + device_t dev; + int rid; + int flags; +{ + struct arl_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + 0ul, ~0ul, 1, (RF_ACTIVE | flags)); + if (res) { + sc->irq_rid = rid; + sc->irq_res = res; + return (0); + } else + return (ENOENT); +} + +/* + * Allocate an memory resource with the given resource id + */ +int +arl_alloc_memory(dev, rid, size) + device_t dev; + int rid; + int size; +{ + struct arl_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + 0ul, ~0ul, size, RF_ACTIVE); + if (res) { + sc->mem_rid = rid; + sc->mem_res = res; + return (0); + } else + return (ENOENT); +} + +/* + * Release all resources + */ +void +arl_release_resources(dev) + device_t dev; +{ + struct arl_softc *sc = device_get_softc(dev); + + if (sc->mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->mem_rid, sc->mem_res); + sc->mem_res = 0; + } + if (sc->irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, + sc->irq_rid, sc->irq_res); + sc->irq_res = 0; + } +} diff --git a/sys/dev/arl/if_arl_isa.c b/sys/dev/arl/if_arl_isa.c new file mode 100644 index 0000000..434407d --- /dev/null +++ b/sys/dev/arl/if_arl_isa.c @@ -0,0 +1,354 @@ +/* + * $RISS: if_arl/dev/arl/if_arl_isa.c,v 1.4 2004/01/22 12:08:48 count Exp $ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +static void arl_isa_identify(driver_t *, device_t); +static int arl_isa_probe (device_t); +static int arl_isa_attach (device_t); +static int arl_isa_detach (device_t); +static char* arl_make_desc (u_int8_t, u_int8_t); + +#define ARL_MAX_ATYPE_LEN 10 +static struct arl_type { + u_int8_t type; + char* desc; +} +arl_type_list[] = { + { 0, "450" }, + { 1, "650" }, + { 0xb, "670" }, + { 0xc, "670E" }, + { 0xd, "650E" }, + { 0xe, "440LT" }, + { 0x2e, "655" }, + { 0x6b, "IC2200" }, + { 0, 0 } +}; + +#define ARL_MAX_RTYPE_LEN 10 +struct radio_type { + u_int8_t type; + char* desc; +} radio_type_list [] = { + { 1, "092/094" }, + { 2, "020" }, + { 3, "092A" }, + { 4, "020B" }, + { 5, "095" }, + { 6, "024" }, + { 7, "025B" }, + { 8, "024B" }, + { 9, "024C" }, + {10, "025C" }, + {11, "024-1A" }, + {12, "025-1A" }, +}; + + +static char* +arl_make_desc(hw_type, radio_mod) + u_int8_t hw_type; + u_int8_t radio_mod; +{ + static char desc[80]; + char atype[ARL_MAX_ATYPE_LEN], rtype[ARL_MAX_RTYPE_LEN]; + int i; + + *atype = *rtype = 0; + + /* arl type */ + for(i = 0; arl_type_list[i].desc; i++) { + if (arl_type_list[i].type == hw_type) + break; + } + + if (arl_type_list[i].desc) + strncpy(atype, arl_type_list[i].desc, ARL_MAX_ATYPE_LEN); + else + snprintf(atype, ARL_MAX_ATYPE_LEN, "(0x%x)", hw_type); + + /* radio type */ + for(i = 0; radio_type_list[i].desc; i++) + if (radio_type_list[i].type == radio_mod) + break; + + if (radio_type_list[i].desc) + strncpy(rtype, radio_type_list[i].desc, ARL_MAX_RTYPE_LEN); + else + snprintf(rtype, ARL_MAX_RTYPE_LEN, "(0x%x)", radio_mod); + + snprintf(desc, 80, "ArLan type %s, radio module %s", atype, rtype); + + return desc; +} + +#define ARL_ADDR2VEC(addr) (1 << ((addr - ARL_BASE_START) / ARL_BASE_STEP)) + +static void +arl_isa_identify (driver_t *driver, device_t parent) +{ + device_t child; + struct arl_softc *sc; + int chunk, found, i; + u_int16_t free_mem = 0xFFFF; + + if (bootverbose) + printf("in identify\n"); + + /* Try avoid already added devices */ + for (i = 0; (child = device_find_child(parent, "arl", i)) != NULL; i++) { + chunk = bus_get_resource_start(child, SYS_RES_MEMORY, 0); + if (bootverbose) + device_printf(child, "found at iomem = 0x%0x\n", chunk); + if (chunk >= ARL_BASE_START && chunk <= ARL_BASE_END) + free_mem ^= ARL_ADDR2VEC(chunk); + } + + if (bootverbose) + printf("arl: free mem vector = 0x%x\n", free_mem); + + for (chunk = ARL_BASE_START; chunk <= ARL_BASE_END; chunk += ARL_BASE_STEP) { + /* If device 'arl' with this chunk was found early - skip it */ + if ( !(free_mem & ARL_ADDR2VEC(chunk)) ) + continue; + + found = 0; + child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "arl", -1); + device_set_driver(child, driver); + sc = device_get_softc(child); + bzero(sc, sizeof(*sc)); + + bus_set_resource(child, SYS_RES_MEMORY, sc->mem_rid, chunk, + ARL_BASE_STEP); + + if (arl_alloc_memory(child, sc->mem_rid, ARL_BASE_STEP) == 0) { + ar = (struct arl_private *) rman_get_virtual(sc->mem_res); + if (!bcmp(ar->textRegion, ARLAN_SIGN, sizeof(ARLAN_SIGN) - 1)) + found++; + } + + if (bootverbose) + device_printf(child, "%sfound at 0x%x\n", + !found ? "not " : "", chunk); + + arl_release_resources(child); + if (!found) { + bus_delete_resource(child, SYS_RES_MEMORY, sc->mem_rid); + device_delete_child(parent, child); + } + + } +} + +static int +arl_isa_probe (device_t dev) +{ + struct arl_softc *sc = device_get_softc(dev); + int error; + u_char *ptr; + u_int8_t irq; + + if (isa_get_vendorid(dev)) + return (ENXIO); + + if (bootverbose) + device_printf(dev, "in probe\n"); + + bzero(sc, sizeof(struct arl_softc)); + + sc->arl_unit = device_get_unit(dev); + + error = arl_alloc_memory(dev, 0, ARL_BASE_STEP); + if (error) { + if (bootverbose) + device_printf(dev, "Error allocating memory (%d)\n", error); + return (error); + } + + ar = (struct arl_private *) rman_get_virtual(sc->mem_res); + if (bcmp(ar->textRegion, ARLAN_SIGN, sizeof(ARLAN_SIGN) - 1)) { + if (bootverbose) + device_printf(dev, "not found\n"); + error = ENOENT; + goto bad; + } + + irq = ar->irqLevel; + if (irq == 2) + irq = 9; + + error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); + if (error) + goto bad; + + error = arl_alloc_irq(dev, 0, 0); + if (error) { + if (bootverbose) + device_printf(dev, "Can't allocate IRQ %d\n", irq); + goto bad; + } + + ar->controlRegister = 1; /* freeze board */ + + /* Memory test */ + for (ptr = (u_char *) ar; + ptr < ((u_char *) ar + ARL_BASE_STEP - 1); ptr++) { + u_char c; + + c = *ptr; *ptr = ~(*ptr); + if (*ptr != (u_char)~c) { + device_printf(dev, "board memory failed at [%lx]\n", + rman_get_start(sc->mem_res) + (ptr - (u_char *)ar)); + break; /* skip memory test */ + } + } + + bzero((void *) ar, ARL_BASE_STEP - 1); /* clear board ram */ + + if (arl_wait_reset(sc, 100, ARDELAY)) { + error = ENXIO; + goto bad; + } + + if (ar->diagnosticInfo == 0xFF) { + /* Copy arp to arpcom struct */ + bcopy(ar->lanCardNodeId, sc->arpcom.ac_enaddr, + ETHER_ADDR_LEN); + + /* copy values to local cache */ + bzero(&arcfg, sizeof(arcfg)); + + bcopy(ar->lanCardNodeId, arcfg.lanCardNodeId, + sizeof(ar->lanCardNodeId)); + bcopy(ar->specifiedRouter, arcfg.specifiedRouter, + sizeof(ar->specifiedRouter)); + + GET_ARL_PARAM(hardwareType); + GET_ARL_PARAM(majorHardwareVersion); + GET_ARL_PARAM(minorHardwareVersion); + GET_ARL_PARAM(radioModule); + GET_ARL_PARAM(channelSet); + if (!arcfg.channelSet) + arcfg.channelSet = ar->defaultChannelSet; + GET_ARL_PARAM(channelNumber); + GET_ARL_PARAM(registrationMode); + GET_ARL_PARAM(spreadingCode); + GET_ARL_PARAM(priority); + GET_ARL_PARAM(receiveMode); + arcfg.txRetry = 0; /* use default */ + + strncpy(arcfg.name, ar->name, ARLAN_NAME_SIZE); + bcopy(ar->systemId, arcfg.sid, 4 * sizeof(ar->systemId[0])); + + device_set_desc_copy(dev, arl_make_desc(ar->hardwareType, ar->radioModule)); + error = 0; + } else { + if (bootverbose) + device_printf(dev, "board self-test failed (0x%x)!\n", + ar->diagnosticInfo); + error = ENXIO; + } + +bad: + arl_release_resources(dev); + + return (error); +} + +static int +arl_isa_attach (device_t dev) +{ + struct arl_softc *sc = device_get_softc(dev); + int error; + + if (bootverbose) + device_printf(dev, "in attach\n"); + + arl_alloc_memory(dev, sc->mem_rid, ARL_BASE_STEP); + arl_alloc_irq(dev, sc->irq_rid, 0); + + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, + arl_intr, sc, &sc->irq_handle); + if (error) { + arl_release_resources(dev); + return (error); + } + +#if __FreeBSD_version < 502108 + device_printf(dev, "Ethernet address %6D\n", sc->arpcom.ac_enaddr, ":"); +#endif + + return arl_attach(dev); +} + +static int +arl_isa_detach(device_t dev) +{ + struct arl_softc *sc = device_get_softc(dev); + + arl_stop(sc); + /* ifmedia_removeall(&sc->an_ifmedia); */ +#if __FreeBSD_version < 500100 + ether_ifdetach(&sc->arpcom.ac_if, ETHER_BPF_SUPPORTED); +#else + ether_ifdetach(&sc->arpcom.ac_if); +#endif + bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); + arl_release_resources(dev); + + return (0); +} + +static device_method_t arl_isa_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, arl_isa_identify), + DEVMETHOD(device_probe, arl_isa_probe), + DEVMETHOD(device_attach, arl_isa_attach), + DEVMETHOD(device_detach, arl_isa_detach), + + { 0, 0 } +}; + +static driver_t arl_isa_driver = { + "arl", + arl_isa_methods, + sizeof(struct arl_softc) +}; + +extern devclass_t arl_devclass; + +DRIVER_MODULE(arl, isa, arl_isa_driver, arl_devclass, 0, 0); +MODULE_DEPEND(arl, isa, 1, 1, 1); +MODULE_DEPEND(arl, ether, 1, 1, 1); diff --git a/sys/dev/arl/if_arlreg.h b/sys/dev/arl/if_arlreg.h new file mode 100644 index 0000000..6c057aa --- /dev/null +++ b/sys/dev/arl/if_arlreg.h @@ -0,0 +1,310 @@ +/* + * $RISS: if_arl/dev/arl/if_arlreg.h,v 1.2 2004/01/22 09:18:13 count Exp $ + * $FreeBSD$ + */ + +#ifndef _IF_ARLREG_H +#define _IF_ARLREG_H + +#define ARL_BASE_START 0xC0000 +#define ARL_BASE_END 0xDE000 +#define ARL_BASE_STEP 0x2000 + +#define ARLAN_NAME_SIZE 16 +#define ARLAN_NAME "ArLan655-SCT" + +/* + * Statistics + */ +struct arl_stats { + u_int32_t numDatagramsTransmitted; + u_int32_t numReTransmissions; + u_int32_t numFramesDiscarded; + u_int32_t numDatagramsReceived; + u_int32_t numDuplicateReceivedFrames; + u_int32_t numDatagramsDiscarded; + u_int16_t maxNumReTransmitDatagram; + u_int16_t maxNumReTransmitFrames; + u_int16_t maxNumConsecutiveDuplicateFrames; + u_int32_t numBytesTransmitted; + u_int32_t numBytesReceived; + u_int32_t numCRCErrors; + u_int32_t numLengthErrors; + u_int32_t numAbortErrors; + u_int32_t numTXUnderruns; + u_int32_t numRXOverruns; + u_int32_t numHoldOffs; + u_int32_t numFramesTransmitted; + u_int32_t numFramesReceived; + u_int32_t numReceiveFramesLost; + u_int32_t numRXBufferOverflows; + u_int32_t numFramesDiscardedAddrMismatch; + u_int32_t numFramesDiscardedSIDMismatch; + u_int32_t numPollsTransmistted; + u_int32_t numPollAcknowledges; + u_int32_t numStatusVectorTimeouts; + u_int32_t numNACKReceived; +} __attribute__((packed)); + +/* + * Arlan private structure in memomory + */ +struct arl_private { + /* Header Signature */ + char textRegion[48]; + u_int8_t resetFlag; + u_int8_t diagnosticInfo; + u_int16_t diagnosticOffset; + u_int8_t _1[12]; + u_int8_t lanCardNodeId[6]; + u_int8_t broadcastAddress[6]; + u_int8_t hardwareType; + u_int8_t majorHardwareVersion; + u_int8_t minorHardwareVersion; + u_int8_t radioModule; + u_int8_t defaultChannelSet; + u_int8_t _2[47]; + + /* Control/Status Block - 0x0080 */ + u_int8_t interruptInProgress; + u_int8_t cntrlRegImage; + u_int8_t _3[14]; + u_int8_t commandByte; + u_int8_t commandParameter[15]; + + /* Receive Status - 0x00a0 */ + u_int8_t rxStatusVector; + u_int8_t rxFrmType; + u_int16_t rxOffset; + u_int16_t rxLength; + u_int8_t rxSrc[6]; + u_int8_t rxBroadcastFlag; + u_int8_t rxQuality; + u_int8_t scrambled; + u_int8_t _4[1]; + + /* Transmit Status - 0x00b0 */ + u_int8_t txStatusVector; + u_int8_t txAckQuality; + u_int8_t numRetries; + u_int8_t _5[14]; + u_int8_t registeredRouter[6]; + u_int8_t backboneRouter[6]; + u_int8_t registrationStatus; + u_int8_t configuredStatusFlag; + u_int8_t _6[1]; + u_int8_t ultimateDestAddress[6]; + u_int8_t immedDestAddress[6]; + u_int8_t immedSrcAddress[6]; + u_int16_t rxSequenceNumber; + u_int8_t assignedLocaltalkAddress; + u_int8_t _7[27]; + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + u_int16_t txTimeout; + u_int16_t transportTime; + u_int8_t _8[4]; + + /* - Configuration Parameters */ + u_int8_t irqLevel; + u_int8_t spreadingCode; + u_int8_t channelSet; + u_int8_t channelNumber; + u_int16_t radioNodeId; + u_int8_t _9[2]; + u_int8_t scramblingDisable; + u_int8_t radioType; + u_int16_t routerId; + u_int8_t _10[9]; + u_int8_t txAttenuation; + u_int8_t systemId[4]; /* on an odd address for a long !!! */ + u_int16_t globalChecksum; + u_int8_t _11[4]; + u_int16_t maxDatagramSize; + u_int16_t maxFrameSize; + u_int8_t maxRetries; + u_int8_t receiveMode; + u_int8_t priority; + u_int8_t rootOrRepeater; + u_int8_t specifiedRouter[6]; + u_int16_t fastPollPeriod; + u_int8_t pollDecay; + u_int8_t fastPollDelay[2]; + u_int8_t arlThreshold; + u_int8_t arlDecay; + u_int8_t _12[1]; + u_int16_t specRouterTimeout; + u_int8_t _13[5]; + + /* Scrambled Area */ + u_int8_t SID[4]; + u_int8_t encryptionKey[12]; + u_int8_t _14[2]; + u_int8_t waitTime[2]; + u_int8_t lParameter[2]; + u_int8_t _15[3]; + u_int16_t headerSize; + u_int16_t sectionChecksum; + + u_int8_t registrationMode; + u_int8_t registrationFill; + u_int16_t pollPeriod; + u_int16_t refreshPeriod; + u_int8_t name[ARLAN_NAME_SIZE]; + u_int8_t NID[6]; + u_int8_t localTalkAddress; + u_int8_t codeFormat; + u_int8_t SSCode[64]; + + u_int8_t _16[0x140]; + + /* Statistics Block - 0x0300 */ + u_int8_t hostcpuLock; + u_int8_t lancpuLock; + u_int8_t resetTime[18]; + + struct arl_stats stat; + + u_int8_t _17[0x86]; + + u_int8_t txBuffer[0x800]; + u_int8_t rxBuffer[0x800]; + + u_int8_t _18[0x0bfd]; + u_int8_t resetFlag1; + u_int8_t _19; + u_int8_t controlRegister; +}; + +/* + * Transmit parametrs + */ +struct arl_tx_param { + u_int16_t offset; + u_int16_t length; + u_int8_t dest[6]; + u_int8_t clear; + u_int8_t retries; + u_int8_t routing; + u_int8_t scrambled; +}; + +#define ARL_HARDWARE_RESET 0x01 +#define ARL_CHANNEL_ATTENTION 0x02 +#define ARL_INTERRUPT_ENABLE 0x04 +#define ARL_CLEAR_INTERRUPT 0x08 + +/* additions for sys/sockio.h ( socket ioctl parameters for arlan card ) */ + +#define SIOCGARLQLT _IOWR('i', 70, struct ifreq) /* get QUALITY */ +#define SIOCGARLALL _IOWR('i', 71, struct ifreq) /* get ALL */ +#define SIOCSARLALL _IOWR('i', 72, struct ifreq) /* set paramter (who_set) */ +#define SIOCGARLSTB _IOWR('i', 73, struct ifreq) /* get statistic block */ + +/* + * Arlan request struct via ioctl + */ +struct arl_cfg_param { + u_char name[ARLAN_NAME_SIZE]; + u_int8_t sid[4]; + u_int8_t channelSet; + u_int8_t channelNumber; + u_int8_t spreadingCode; + u_int8_t registrationMode; + u_int8_t lanCardNodeId[6]; + u_int8_t specifiedRouter[6]; + u_int8_t hardwareType; + u_int8_t majorHardwareVersion; + u_int8_t minorHardwareVersion; + u_int8_t radioModule; + u_int8_t priority; + u_int8_t receiveMode; + u_int8_t txRetry; +}; + +struct arl_req { + u_int32_t what_set; + struct arl_cfg_param cfg; +}; + +#define ARLAN_MAX_QUALITY 16 + +struct arl_quality { + u_int8_t macsrc[6]; + int rx_quality; + int tx_quality; +}; + +#define ARLAN_SET_name 0x0001 +#define ARLAN_SET_sid 0x0002 +#define ARLAN_SET_channelSet 0x0004 +#define ARLAN_SET_channelNumber 0x0008 +#define ARLAN_SET_spreadingCode 0x0010 +#define ARLAN_SET_registrationMode 0x0020 +#define ARLAN_SET_lanCardNodeId 0x0040 +#define ARLAN_SET_specifiedRouter 0x0080 +#define ARLAN_SET_priority 0x0100 +#define ARLAN_SET_receiveMode 0x0200 +#define ARLAN_SET_txRetry 0x0400 + +#ifdef _KERNEL +struct arl_softc { + struct arpcom arpcom; /* Ethernet common */ + + int arl_unit; + struct arl_private * arl_mem; /* arlan data */ + + struct arl_cfg_param arl_cfg; /* arlan vars in our mem */ + u_char arl_control; + + int mem_rid; /* resource id for mem */ + struct resource* mem_res; /* resource for mem */ + int irq_rid; /* resource id for irq */ + struct resource* irq_res; /* resource for irq */ + void* irq_handle; /* handle for irq handler */ + + u_char arl_tx[2048]; + int tx_len; + u_char arl_rx[2048]; + int rx_len; + + struct arl_quality quality[ARLAN_MAX_QUALITY]; +}; +#endif + +#define ARLAN_SIGN "TELESYSTEM" +#define ARLAN_HEADER_SIZE 0x0C + +#define ar sc->arl_mem +#define arcfg sc->arl_cfg +#define aqual sc->quality + +#define ARDELAY 10000 +#define ARDELAY1 50000 + +#define WAIT_RESET(cnt, delay) \ + do { \ + int i; \ + for (i = cnt; i && ar->resetFlag; i--) { \ + DELAY(delay); \ + } \ + } while (0); + +#define GET_ARL_PARAM(name) (arcfg.name = ar->name) +#define SET_ARL_PARAM(name) (ar->name = arcfg.name) + +#ifdef _KERNEL +void arl_release_resources (device_t); +int arl_alloc_memory (device_t, int, int); +int arl_alloc_irq (device_t, int, int); +int arl_attach (device_t); +int arl_wait_reset (struct arl_softc *, int, int); +void arl_stop (struct arl_softc *); + +driver_intr_t arl_intr; +#endif + +#endif /* _IF_ARLREG_H */ diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 8798661..952b1c6 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -493,6 +493,7 @@ hint.mse.0.irq="5" # ar: Arnet SYNC/570i hdlc sync 2/4 port V.35/X.21 serial driver # (requires sppp) +# arl: Aironet Arlan 655 wireless adapters. # ath: Atheros a/b/g WiFi adapters (requires ath_hal and wlan) # ctau: Cronyx/Tau sync dual port V.35/RS-232/RS-530/RS-449/X.21/G.703/E1 # serial adaptor (requires sppp (default), or NETGRAPH if @@ -521,6 +522,10 @@ hint.ar.0.at="isa" hint.ar.0.port="0x300" hint.ar.0.irq="10" hint.ar.0.maddr="0xd0000" +device arl +hint.arl.0.at="isa" +hint.arl.0.irq="9" +hint.arl.0.maddr="0xd0000" device ctau hint.ctau.0.at="isa" hint.ctau.0.port="0x240" diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 1bfc0cc..eb124bc 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -20,6 +20,7 @@ SUBDIR= ${_3dfx} \ ${_aout} \ ${_apm} \ ${_ar} \ + ${_arl} \ ${_arcnet} \ ${_asr} \ ath \ @@ -284,6 +285,7 @@ _amd= amd _aout= aout _apm= apm _ar= ar +_arl= arl _arcnet= arcnet _ath_hal= ath_hal _awi= awi diff --git a/sys/modules/arl/Makefile b/sys/modules/arl/Makefile new file mode 100644 index 0000000..a7ca8d4 --- /dev/null +++ b/sys/modules/arl/Makefile @@ -0,0 +1,10 @@ +# $RISS: if_arl/modules/if_arl/Makefile,v 1.3 2003/01/13 08:05:29 frol Exp $ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/arl + +KMOD= if_arl +SRCS= if_arl.c if_arl_isa.c device_if.h bus_if.h isa_if.h +CFLAGS= -I${.CURDIR}/../.. + +.include diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index b48a73b..69b714f 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -10,6 +10,7 @@ SUBDIR= ac \ ancontrol \ ${_apm} \ ${_apmd} \ + ${_arlconfig} \ arp \ ${_asf} \ ${_atm} \ @@ -241,6 +242,7 @@ _acpi= acpi .endif _apm= apm _apmd= apmd +_arlconfig= arlconfig _asf= asf .if !defined(NO_BLUETOOTH) _bluetooth= bluetooth diff --git a/usr.sbin/arlconfig/Makefile b/usr.sbin/arlconfig/Makefile new file mode 100644 index 0000000..94a03a3 --- /dev/null +++ b/usr.sbin/arlconfig/Makefile @@ -0,0 +1,11 @@ +# +# $RISS: if_arl/arlconfig/Makefile,v 1.5 2003/01/13 08:05:29 frol Exp $ +# $FreeBSD$ +# + +PROG= arlconfig +SRCS= arlconfig.c +CFLAGS= -I${.CURDIR}/../../sys +MAN= arlconfig.8 + +.include diff --git a/usr.sbin/arlconfig/arlconfig.8 b/usr.sbin/arlconfig/arlconfig.8 new file mode 100644 index 0000000..1523bbb --- /dev/null +++ b/usr.sbin/arlconfig/arlconfig.8 @@ -0,0 +1,236 @@ +.\" Copyright (c) 1997, 1998, 1999 +.\" Bill Paul All rights reserved. +.\" +.\" 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 Bill Paul. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 25,2003 +.Dt ARLCONTROL 8 +.Os +.Sh NAME +.Nm arlconfig +.Nd configure Aironet Arlan 655 device +.Sh SYNOPSIS +.Nm +.Ar iface Cm name Ar name +.Nm +.Ar iface Cm sid Ar SID +.Nm +.Ar iface Cm country Ar country ( Cm 9-15 ) +.Nm +.Ar iface Cm channel Ar channel +(depend on +.Ar country ) +.Nm +.Ar iface Cm freq Ar freq ( Cm 2412, 2427, 2442, 2457, 2465 ) +.Nm +.Ar iface Cm spread Ar spread Cm ( 354, 500, 1000, 2000 ) +.Nm +.Ar iface Cm bitrate Ar bitrate ( Cm 0-4) +.Nm +.Ar iface Cm mode Ar mode ( Cm 640 | 655 ) +.Nm +.Ar iface Cm priority Ar priority ( Cm normal, high, highest ) +.Nm +.Ar iface Cm stat +.Nm +.Ar iface Cm quality Ar seconds [ Cm count Ar ] +.Sh DESCRIPTION +The +.Nm +utility controls the operation of Aironet Arlan 655 wireless networking +devices via the +.Xr arl 4 +driver. +Most of the parameters that can be changed are related to the +Aironet protocol which the Aironet Arlan 655 card implements. +The parameters include +the station name, the station operation mode +.Ar (point to point or infrastructure) , +and the network name of a service +set to join. +The +.Nm +utility can also be used to view the current NIC status, configuration +and to dump out the values of the card's statistics counters. +.Pp +The +.Ar iface +argument given to +.Nm +should be the logical interface name associated with the Aironet Arlan 655 +device +.Li ( arl0 , arl1 , +etc.) and must be specified. +.Sh OPTIONS +The options are as follows: +.Bl -tag -width indent +.It Cm name Ar name +Set +.Ar Device Name . +This +parameter is used to establish a 15-byte ASCII name +for the Arlan 655 Client Card. The +.Ar Device Name +is optional and may be left blank. +.Pp +If you choose to assign a name, while operating in +.Ar TMA +mode, the name will appear in the Arlan Access Point's Registration Table. +Duplicate names are allowed. +.It Cm sid Ar SID +Set +.Ar System Identifier. +The System Identifier +.Ar (SID) +is a 4-byte, hexadecimal digit value that +is attached to each packet sent out over the radio. Establishing a +.Ar SID +allows you to group nodes into a microcelluar network and exclude +those nodes that are whiting radio range on other networks. +.Pp +The +.Ar SID +value must be an even number, cannot exceed ts and must start with +00 or 02. Examples of valid SID values are: 00000102, 0200AA14, 00013A18, +007F6380. The +.Ar default +SID is +.Cm 00000002 . +.Pp +Since nodes will only receive packets from other nodes with a matching SID, +you must make sure that the Arlan 655 Client Card is set the same SID as +other nodes on your network. +.It Cm mode Ar mode ( Cm 640 | 655 ) +Use +.Ar operating mode +parameter to specify whether you are operating in +.Ar TMA , Non-TMA +or +.Ar PSP +mode. The +.Ar default +setting is +.Cm TMA +mode. +.Bl -column ".Em Mode" ".Em Regmode" -offset indent indent +.Em "Mode Registration mode" +.It 640 Ta TMA +.It 655 Ta Non-TMA +.It PSP Ta Power save mode +.El +.!!! +.It Cm country Ar country ( Cm 9-15 ) +.It Cm channel Ar channel +.It Cm freq Ar freq ( Cm 2412, 2427, 2442, 2457, 2465 ) +Chose +.Ar country , channel , freq + parameters that depend on the +.Ar contry +according to the following table: +.Bl -column ".Em Country" ".Em Channel" ".Em MHz" -offset indent indent +.Em "Country Ch_Set MHz" +.It "North America" Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.It "U.S.A " Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.It "Canada " Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.It "Mexico " Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.IT "New Zealand " Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.It "E.T.S.I " Ta 10 Ta "2412, 2427, 2442, 2457, 2472" +.It "Japan " Ta 11 Ta "2484" +.It "France " Ta 12 Ta "2457, 2465, 2475" +.It "Australia " Ta 13 Ta "2411, 2425, 2439" +.It "Germany " Ta 14 Ta "2427, 2442, 2457" +.It "U.K.(MPT1349)" Ta 15 Ta "2460" +.It "U.K. " Ta 15 Ta "2460" +.It "Spain " Ta 15 Ta "2460" +.El +.It Cm bitrate Ar bitrate ( Cm 0-4) +.It Cm spread Ar spread Cm ( 354, 500, 1000, 2000 ) +Set device operating bitrate or spread. +.Bl -column ".Em Rate" ".Em Spread" ".Em kb/s" -offset indent indent +.Em "Rate Spread kb/s" +.It 0 Ta - Ta Auto +.It 1 Ta 354 Ta 354 +.It 2 Ta 512 Ta 512 +.It 3 Ta 1000 Ta 1000 +.It 4 Ta 2000 Ta 2000 +.El +.It Cm priority Ar priority ( Cm normal, high, highest ) +Use the +.Ar priority +parameter to set the priority of the Atlan 655 Radio Media Access Control +the values are +.Cm normal , high +or +.Cm higest . +The higher the priority set, the more likely this unit wil be first +to successfully transmit a packet when multiple units are trying +to transmit at the same time. +.Pp +The percentage of units on your network that you set to other than +.Dq normal +should be kept small - 10 percent or less. +.It Cm stat +Print internal Arlan 655 statistics block. +.It Cm quality Ar seconds [ Cm count Ar ] +Perform link quality test during +.Ar seconds +transmitting +.Ar count +packets. +Currently is broken. +.El +.Sh EXAMPLES +.Bd -literal -offset indent +alrlconfig arl0 name NODE1 sid 4 freq 2442 +arlconfig arl0 quality 10 seconds +arlconfig arl0 status +.Pp +You can configure Arlan 655 card from /etc/start_if.arl0. For example: +.Pp +#!/bin/sh +/sbin/arlconfig arl0 sid 0x000002 freq 2412 spread 2000 mode 640 +.Sh SEE ALSO +.Xr arl 4 , +.Xr "Arlan 655 ISA Wireless LAN Client Card User Guide" . +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 5.3 . +.Sh BUGS +Aironet Arlan 640 bridges and Arlan 630 access points don't understand +country codes other than 9. +.Sh AUTHORS +The +.Nm +utility was written by +.Aq ran@styx.aic.net . +Manpage was written by +.An Yuri Kurenkov Aq y.kurenkov@init.ru . diff --git a/usr.sbin/arlconfig/arlconfig.c b/usr.sbin/arlconfig/arlconfig.c new file mode 100644 index 0000000..4ab5ca9 --- /dev/null +++ b/usr.sbin/arlconfig/arlconfig.c @@ -0,0 +1,612 @@ +/* + * $RISS: if_arl/arlconfig/arlconfig.c,v 1.3 2003/01/13 07:23:25 count Exp $ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct freq_list { + short fr_no; + char* name; +}; + +struct freq_list freq_list_1[] = { + { 0, "908.50" }, + { 1, "910.06" }, + { 2, "915.52" }, + { 3, "915.00" }, + { 4, "917.83" }, + { 5, "919.22" }, + { 6, "922.26" }, + { 7, "911.45" }, + { 8, "915.00" }, + { 9, "918.55" }, + { 10,"915.00" }, + { 11,"915.00" } +}; + +struct freq_list freq_list_6[] = { + { 0, "920.31" }, + { 1, "920.33" }, + { 2, "921.55" }, + { 3, "922.17" }, + { 4, "922.79" }, + { 5, "921.46" }, + { 6, "921.55" } +}; + +struct freq_list freq_list_9[] = { + { 0, "Bad" }, + { 1, "2412" }, + { 2, "2427" }, + { 3, "2442" }, + { 4, "2457" }, + { 5, "2465" } +}; + + +struct freq_list freq_list_10[] = { + { 0, "Bad" }, + { 1, "2412" }, + { 2, "2427" }, + { 3, "2442" }, + { 4, "2457" }, + { 5, "2472" } +}; + +struct freq_list freq_list_11[] = { + { 0, "Bad" }, + { 1, "2484" } +}; + +struct freq_list freq_list_12[] = { + { 0, "Bad" }, + { 1, "2457" }, + { 2, "2465" }, + { 3, "2472" }, +}; + +struct freq_list freq_list_13[] = { + { 0, "Bad" }, + { 1, "2411" }, + { 2, "2425" }, + { 3, "2439" } +}; + +struct freq_list freq_list_14[] = { + { 0, "Bad" }, + { 1, "2427" }, + { 2, "2442" }, + { 3, "2457" } +}; + +struct freq_list freq_list_15[] = { + { 0, "Bad" }, + { 1, "2460" } +}; + +#define MAXFREQ(a) sizeof(a)/sizeof(struct freq_list) + +struct rate_list { + short rate_no; + char* name; +}; + +struct rate_list rate_list_2400[] = { + { 0, "Bad" }, + { 1, "354" }, + { 2, "512" }, + { 3, "1000" }, + { 4, "2000" } +}; + +struct radio_type { + int id; + char* name; +} radio_type_list [] = { + { 0, "No EPROM" }, + { 1, "092/094" }, + { 2, "020" }, + { 3, "092A" }, + { 4, "020B" }, + { 5, "095" }, + { 6, "024" }, + { 7, "025B" }, + { 8, "024B" }, + { 9, "024C" }, + {10, "025C" }, + {11, "024-1A" }, + {12, "025-1A" }, + {13, "Other" } +}; + +static struct ch_list { + short chan; + char* fr; + char* country; + struct rate_list* rate; + struct freq_list* freq; + int max_freq; +} CHSET[] = { + { 0, 0, 0, 0, 0, 0 }, + { 1, "900 Mhz", "Canada, U.S.A., Mexico", 0, freq_list_1, MAXFREQ(freq_list_1) }, + { 2, 0, 0, 0, 0, 0 }, + { 3, 0, 0, 0, 0, 0 }, + { 4, 0, 0, 0, 0, 0 }, + { 5, 0, 0, 0, 0, 0 }, + { 6, "900 Mhz", "Australia", 0, freq_list_6, MAXFREQ(freq_list_6) }, + { 7, 0, 0, 0, 0, 0 }, + { 8, 0, 0, 0, 0, 0 }, + { 9, "2400 Mhz", "North America", rate_list_2400, freq_list_9, MAXFREQ(freq_list_9) }, + { 10, "2400 Mhz", "E.T.S.I", rate_list_2400, freq_list_10, MAXFREQ(freq_list_10) }, + { 11, "2400 Mhz", "Japan", rate_list_2400, freq_list_11, MAXFREQ(freq_list_11) }, + { 12, "2400 Mhz", "France", rate_list_2400, freq_list_12, MAXFREQ(freq_list_12) }, + { 13, "2400 Mhz", "Australia", rate_list_2400, freq_list_13, MAXFREQ(freq_list_13) }, + { 14, "2400 Mhz", "Germany", rate_list_2400, freq_list_14, MAXFREQ(freq_list_14) }, + { 15, "2400 Mhz", "U.K.(MPT1349),Spain", rate_list_2400, freq_list_15, MAXFREQ(freq_list_15) } +}; + +char* registrationMode[] = { + "NON-TMA", + "TMA", + "PSP" +}; + +char* priorityList[] = { + "normal", + "high", + "highest" +}; + +void +usage() +{ + const char *progname = getprogname(); + +#if 0 + fprintf(stderr, "\nArlan configuration utility.\n\n"); +#endif + fprintf(stderr, "Usage: %s [ ...]\n", progname); + fprintf(stderr, "\t\tArlan interface name.\n"); + fprintf(stderr, "\t\t\tParameter name (see below).\n"); + fprintf(stderr, "\t\t\tNew value for parameter.\n"); + fprintf(stderr, "Parameter name:\t\tValue:\n"); + fprintf(stderr, "\tname\t\tset Name.\n"); + fprintf(stderr, "\tsid\t\tset System ID.\n"); + fprintf(stderr, "\tfreq\t\tset Frequency Channel (2412, 2427, 2442, 2457, 2465)\n"); + fprintf(stderr, "\tspread\t\tset Bitrate (354, 500, 1000, 2000)\n"); + fprintf(stderr, "\tmode\t\tset Mode (640, 655, PSP).\n"); + fprintf(stderr, "\tcountry\t\tset Country (9-15)\n"); + fprintf(stderr, "\tchannel\t\tset Channel (depended on country)\n"); + fprintf(stderr, "\tbitrate\t\tset Bitrate (0-4)\n"); + fprintf(stderr, "\tpriority\tset Priority (normal, high, highest)\n"); +#if 0 + fprintf(stderr, "\tparent\t\tset Arlan parent's MAC.\n"); + fprintf(stderr, "\taddr\t\tset Arlan MAC.\n"); +#endif + fprintf(stderr, "or: %s stat\n", progname); + fprintf(stderr, "\tprint internal arlan statistics block\n"); + fprintf(stderr, "or: %s quality [count ]\n", + progname); + fprintf(stderr, "\tprint receive packet level and quality with interval\n"); + exit(0); +} + +void +print_al(struct arl_cfg_param *arl_io) +{ + printf("Arlan-655(IC2000) type 0x%x v%d.%d, radio module type %s\n", + arl_io->hardwareType, + arl_io->majorHardwareVersion, + arl_io->minorHardwareVersion, + (arl_io->radioModule < 13) ? + radio_type_list[arl_io->radioModule].name : "Unknown" ); + printf("\tname %s, sid 0x%06x, mode %s, num tx retry %d\n", + arl_io->name, + *(int *)arl_io->sid, + (arl_io->registrationMode < 3) ? + registrationMode[arl_io->registrationMode]:"Unknown", + arl_io->txRetry ); + printf("\tchannel set %d, %s, %s\n", + arl_io->channelSet, + CHSET[arl_io->channelSet].fr, + CHSET[arl_io->channelSet].country); + printf("\tfrequency %s Mhz, bitrate %s kb/s, priority %s, receive mode %d\n", + (CHSET[arl_io->channelSet].freq && + CHSET[arl_io->channelSet].max_freq > arl_io->channelNumber) ? + CHSET[arl_io->channelSet].freq[arl_io->channelNumber].name : + "unknown", + (CHSET[arl_io->channelSet].rate) ? + CHSET[arl_io->channelSet].rate[arl_io->spreadingCode].name : + "unknown", + arl_io->priority <= 2 ? + priorityList[arl_io->priority] : "unknown", + arl_io->receiveMode); + printf("\tether %s", + (char *)ether_ntoa((struct ether_addr *)arl_io->lanCardNodeId)); + printf(" registered to %s\n", + (char *)ether_ntoa((struct ether_addr *)arl_io->specifiedRouter)); +} + +void +print_stb( struct arl_stats stb ) +{ + printf("Arlan internal statistics block\n\n"); + printf("%8u\tdatagrams transmitted\n", + stb.numDatagramsTransmitted); + printf("%8u\tre-transmitted\n", + stb.numReTransmissions); + printf("%8u\tframes discarded internally in a router\n", + stb.numFramesDiscarded); + printf("%8u\tdatagrams received\n", + stb.numDatagramsReceived); + printf("%8u\tduplicate received frame\n", + stb.numDuplicateReceivedFrames); + printf("%8u\tdatagrams discarded due to unavailable mail box buffer\n", + stb.numDatagramsDiscarded); + printf("%8d\tmaximum of re-transmissions datagram\n", + stb.maxNumReTransmitDatagram); + printf("%8d\tmaximum of re-transmissions frame\n", + stb.maxNumReTransmitFrames); + printf("%8d\tmaximum of consecutive duplicate received frames\n", + stb.maxNumConsecutiveDuplicateFrames); + printf("%8u\tbytes transmitted\n", + stb.numBytesTransmitted); + printf("%8u\tbytes received\n", + stb.numBytesReceived); + printf("%8u\tCRC errors\n", + stb.numCRCErrors); + printf("%8u\tlength errors\n", + stb.numLengthErrors); + printf("%8u\tabort errors\n", + stb.numAbortErrors); + printf("%8u\tTX underuns\n", + stb.numTXUnderruns); + printf("%8u\tRX overruns\n", + stb.numRXOverruns); + printf("%8u\tHold Offs (channel tested busy, tx delayed)\n", + stb.numHoldOffs); + printf("%8u\tframes transmitted\n", + stb.numFramesTransmitted); + printf("%8u\tframes received\n", + stb.numFramesReceived); + printf("%8u\treceive frames lost due unavailable buffer\n", + stb.numReceiveFramesLost); + printf("%8u\tRX buffer overflows \n", + stb.numRXBufferOverflows); + printf("%8u\tframes discarded due to Address mismatch\n", + stb.numFramesDiscardedAddrMismatch); + printf("%8u\tframes discarded due to SID mismatch\n", + stb.numFramesDiscardedSIDMismatch); + printf("%8u\tpolls transmitted\n", + stb.numPollsTransmistted); + printf("%8u\tpoll acknowledges received\n", + stb.numPollAcknowledges); + printf("%8u\tstatus vector timeout\n", + stb.numStatusVectorTimeouts); + printf("%8u\tNACK packets received\n", + stb.numNACKReceived); +} + +#ifdef ARL_QUALITY +void +print_qlt(struct arl_quality qlt, int count) +{ + int i, s; + int v, v1; + time_t t; + int minLevel, maxLevel, avgLevel; + int minQuality, maxQuality, avgQuality; + + t = time(NULL); + localtime(&t); + printf("#%d Current date-time: %s", count, ctime(&t)); + printf(" %-39s %s\n","Receive Level","Receive Quality"); + printf( +" pkts 0.......10 11............100 > pkts 0.......10 11............100 >\n"\ +" -----+----------+-----------------+--- -----+----------+-----------------+---\n"); + + minLevel = 16; + maxLevel = 0; + avgLevel = 0; + minQuality = 16; + maxQuality = 0; + avgQuality = 0; + + for (i = 0, s = 0; i < ARLAN_MAX_QUALITY; i++) { + v = qlt.rxLevel[i]; + if (v) { + if (i < minLevel) + minLevel = i; + if (i > maxLevel) + maxLevel = i; + avgLevel += v*i; + printf(" %-4d %x", v, i); + } else + printf(" o %x", i); + s += v; + if (v < 10) + ; + else if (v < 100) + v = 10 + ((v-10) * 20) / 90; + else if (v < 1000) + v = 31; + else + v = 32; + v1 = v; + while (v) { + printf("*"); + v--; + } + + v = 33 - v1; + while (v) { + printf(" "); + v--; + } + + v = qlt.rxQuality[i]; + if (v) { + if (i < minQuality) + minQuality = i; + if (i > maxQuality) + maxQuality = i; + avgQuality += v*i; + printf("%-4d %x", v, i); + } else + printf("o %x", i); + + if (v < 10) + ; + else if (v < 100) + v = 10 + ((v-10) * 20) / 90; + else if (v < 1000) + v = 31; + else + v = 32; + } + v1 = v; + while (v) { + printf("*"); + v--; + } + + printf("\n"); + } + printf(" -----+----------+-----------------+--- -----+----------+-----------------+---\n"); + if (minLevel > 15) + minLevel = 0; + if (minQuality > 15) + minQuality = 0; + printf("\tPackets count %-6d\n", s); + if (!s) + s++; + printf("\tLevel min %d/avg %d/max %d\n", + minLevel, avgLevel/s, maxLevel); + printf("\tQuality min %d/avg %d/max %d\n", + minQuality, avgQuality/s, maxQuality); +} +#endif /* ARL_QUALITY */ + +int +main(int argc, char *argv[]) +{ + struct ifreq ifr; + struct arl_req arl_io; + struct ether_addr *ea; + struct arl_stats stb; + /*static arl_quality qlt;*/ + int sd, argind, val = -1; + long val2; + char *param, *value, *value2; + /*int end_count, i;*/ + + if (argc < 2) + usage(); + + sd = socket(AF_INET, SOCK_DGRAM, 0); + if (sd < 0) + err(1,"socket"); + strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); + ifr.ifr_addr.sa_family = AF_INET; + bzero(&arl_io, sizeof(arl_io)); + ifr.ifr_data = (caddr_t)&arl_io; + + if (argc == 2) { + if (ioctl(sd, SIOCGARLALL, (caddr_t)&ifr)) + err(1,"Get ALL"); + print_al(&arl_io.cfg); + exit(0); + } + + if (argc == 3) { + if (!strcasecmp(argv[2], "stat")) { + strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); + ifr.ifr_addr.sa_family = AF_INET; + ifr.ifr_data = (caddr_t)&stb; + if (ioctl(sd, SIOCGARLSTB, (caddr_t)&ifr)) + err(1,"Get STB"); + print_stb(stb); + exit(0); + } +#ifdef ARL_QUALITY + if (!strcasecmp(argv[2],"quality") && argc > 3) { + val = atoi(argv[3]); + if (val < 0 || val >= 3601) + err(1,"Bad time range"); + end_count = 0; + if (argc > 5 && !strcasecmp(argv[4], "count")) + end_count = atoi(argv[5]); + printf("\n"); + i = 0; + while (i < end_count || !end_count) { /* loop */ + if (i++) + sleep(val); + strncpy(ifr.ifr_name, + argv[1], sizeof(ifr.ifr_name)); + ifr.ifr_addr.sa_family = AF_INET; + ifr.ifr_data = (caddr_t)&qlt; + if (ioctl(sd, SIOCGARLQLT, (caddr_t)&ifr)) + err(1,"Get QLT"); + print_qlt(qlt, i); + } + exit(0); + } +#endif /* ARL_QUALITY */ + } + + arl_io.what_set = 0; + + for (argind = 2; argind < argc; argind += 2) { + param = argv[argind]; + value = argv[argind+1]; + val = -1; + + if (!strcasecmp(param, "name")) { + bzero(arl_io.cfg.name, 16); + strncpy(arl_io.cfg.name, value, 16); + arl_io.what_set |= ARLAN_SET_name; + } + + if (!strcasecmp(param, "sid")) { + val2 = strtol(value, &value2, 0); + if (val2 < 0 || val2 > 0xffffff || val2 % 2 || + value == value2) + err(1, "Bad SID - %s", value); + bcopy(&val2, arl_io.cfg.sid, 4); + arl_io.what_set |= ARLAN_SET_sid; + } + + if (!strcasecmp (param, "freq")) { + if (!strcmp(value, "2412")) + val = 1; + else if (!strcmp(value, "2427")) + val = 2; + else if (!strcmp(value, "2442")) + val = 3; + else if (!strcmp(value, "2457")) + val = 4; + else if (!strcmp(value, "2465")) + val = 5; + if (val == -1) + err(1, "Bad Frequency - %s", value); + arl_io.cfg.channelNumber = val; + arl_io.what_set |= ARLAN_SET_channelNumber; + } + + if (!strcasecmp(param, "spread")) { + if (!strcmp(value, "354")) + val = 1; + else if (!strcmp(value, "500")) + val = 2; + else if (!strcmp(value, "1000")) + val = 3; + else if (!strcmp(value, "2000")) + val = 4; + if (val == -1) + err (1, "Bad Bitrate - %s", value); + arl_io.cfg.spreadingCode = val; + arl_io.what_set |= ARLAN_SET_spreadingCode; + } + + if (!strcasecmp(param, "priority")) { + if (!strcasecmp(value, "normal")) + val = 0; + else if (!strcasecmp(value, "high")) + val = 1; + else if (!strcasecmp(value, "highest")) + val = 2; + if (val == -1) + err( 1, "Bad priority - %s", value); + arl_io.cfg.priority = val; + arl_io.what_set |= ARLAN_SET_priority; + } + + if (!strcasecmp(param, "mode")) { + if (!strcmp(value, "655")) + val = 0; + else if (!strcmp(value, "640")) + val = 1; + else if (!strcasecmp (value, "PSP")) + val = 2; + if (val == -1) + err (1, "Bad Mode - %s", value); + arl_io.cfg.registrationMode = val; + arl_io.what_set |= ARLAN_SET_registrationMode; + } + + if (!strcasecmp(param, "parent")) { + if ((ea = (struct ether_addr*) ether_aton(value)) == NULL) + err (1, "Bad parent's MAC - %s", value); + for (val = 0; val < 6; val++) { + arl_io.cfg.specifiedRouter[val] = + (int) ea->octet[val]; + } + arl_io.what_set |= ARLAN_SET_specifiedRouter; + } + + if (!strcasecmp(param, "addr")) { + if ((ea = (struct ether_addr*) ether_aton(value)) == NULL) + err (1, "Bad MAC - %s", value); + for (val = 0; val < 6; val++) { + arl_io.cfg.lanCardNodeId[val] = + (int) ea->octet[val]; + } + arl_io.what_set |= ARLAN_SET_lanCardNodeId; + } + + if (!strcasecmp(param, "country")) { + arl_io.cfg.channelSet = atoi(value); + arl_io.what_set |= ARLAN_SET_channelSet; + } + + if (!strcasecmp(param, "channel")) { + arl_io.cfg.channelNumber = atoi(value); + arl_io.what_set |= ARLAN_SET_channelNumber; + } + + if (!strcasecmp(param, "bitrate")) { + arl_io.cfg.spreadingCode = atoi(value); + arl_io.what_set |= ARLAN_SET_spreadingCode; + } + + if (!strcasecmp(param, "receive")) { + arl_io.cfg.receiveMode = atoi(value); + arl_io.what_set |= ARLAN_SET_receiveMode; + } + + if (!strcasecmp(param, "txretry")) { + arl_io.cfg.txRetry = atoi(value); + arl_io.what_set |= ARLAN_SET_txRetry; + } + } + + if (arl_io.what_set) { + if (ioctl(sd, SIOCSARLALL, (caddr_t)&ifr)) + err (1, "Set ALL" ); + if (ioctl(sd, SIOCGARLALL, (caddr_t)&ifr)) + err (1, "Get ALL"); + print_al(&arl_io.cfg); + } + + return 0; +} diff --git a/usr.sbin/arlcontrol/arlcontrol.8 b/usr.sbin/arlcontrol/arlcontrol.8 new file mode 100644 index 0000000..1523bbb --- /dev/null +++ b/usr.sbin/arlcontrol/arlcontrol.8 @@ -0,0 +1,236 @@ +.\" Copyright (c) 1997, 1998, 1999 +.\" Bill Paul All rights reserved. +.\" +.\" 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 Bill Paul. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 25,2003 +.Dt ARLCONTROL 8 +.Os +.Sh NAME +.Nm arlconfig +.Nd configure Aironet Arlan 655 device +.Sh SYNOPSIS +.Nm +.Ar iface Cm name Ar name +.Nm +.Ar iface Cm sid Ar SID +.Nm +.Ar iface Cm country Ar country ( Cm 9-15 ) +.Nm +.Ar iface Cm channel Ar channel +(depend on +.Ar country ) +.Nm +.Ar iface Cm freq Ar freq ( Cm 2412, 2427, 2442, 2457, 2465 ) +.Nm +.Ar iface Cm spread Ar spread Cm ( 354, 500, 1000, 2000 ) +.Nm +.Ar iface Cm bitrate Ar bitrate ( Cm 0-4) +.Nm +.Ar iface Cm mode Ar mode ( Cm 640 | 655 ) +.Nm +.Ar iface Cm priority Ar priority ( Cm normal, high, highest ) +.Nm +.Ar iface Cm stat +.Nm +.Ar iface Cm quality Ar seconds [ Cm count Ar ] +.Sh DESCRIPTION +The +.Nm +utility controls the operation of Aironet Arlan 655 wireless networking +devices via the +.Xr arl 4 +driver. +Most of the parameters that can be changed are related to the +Aironet protocol which the Aironet Arlan 655 card implements. +The parameters include +the station name, the station operation mode +.Ar (point to point or infrastructure) , +and the network name of a service +set to join. +The +.Nm +utility can also be used to view the current NIC status, configuration +and to dump out the values of the card's statistics counters. +.Pp +The +.Ar iface +argument given to +.Nm +should be the logical interface name associated with the Aironet Arlan 655 +device +.Li ( arl0 , arl1 , +etc.) and must be specified. +.Sh OPTIONS +The options are as follows: +.Bl -tag -width indent +.It Cm name Ar name +Set +.Ar Device Name . +This +parameter is used to establish a 15-byte ASCII name +for the Arlan 655 Client Card. The +.Ar Device Name +is optional and may be left blank. +.Pp +If you choose to assign a name, while operating in +.Ar TMA +mode, the name will appear in the Arlan Access Point's Registration Table. +Duplicate names are allowed. +.It Cm sid Ar SID +Set +.Ar System Identifier. +The System Identifier +.Ar (SID) +is a 4-byte, hexadecimal digit value that +is attached to each packet sent out over the radio. Establishing a +.Ar SID +allows you to group nodes into a microcelluar network and exclude +those nodes that are whiting radio range on other networks. +.Pp +The +.Ar SID +value must be an even number, cannot exceed ts and must start with +00 or 02. Examples of valid SID values are: 00000102, 0200AA14, 00013A18, +007F6380. The +.Ar default +SID is +.Cm 00000002 . +.Pp +Since nodes will only receive packets from other nodes with a matching SID, +you must make sure that the Arlan 655 Client Card is set the same SID as +other nodes on your network. +.It Cm mode Ar mode ( Cm 640 | 655 ) +Use +.Ar operating mode +parameter to specify whether you are operating in +.Ar TMA , Non-TMA +or +.Ar PSP +mode. The +.Ar default +setting is +.Cm TMA +mode. +.Bl -column ".Em Mode" ".Em Regmode" -offset indent indent +.Em "Mode Registration mode" +.It 640 Ta TMA +.It 655 Ta Non-TMA +.It PSP Ta Power save mode +.El +.!!! +.It Cm country Ar country ( Cm 9-15 ) +.It Cm channel Ar channel +.It Cm freq Ar freq ( Cm 2412, 2427, 2442, 2457, 2465 ) +Chose +.Ar country , channel , freq + parameters that depend on the +.Ar contry +according to the following table: +.Bl -column ".Em Country" ".Em Channel" ".Em MHz" -offset indent indent +.Em "Country Ch_Set MHz" +.It "North America" Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.It "U.S.A " Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.It "Canada " Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.It "Mexico " Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.IT "New Zealand " Ta 9 Ta "2412, 2427, 2442, 2457, 2465" +.It "E.T.S.I " Ta 10 Ta "2412, 2427, 2442, 2457, 2472" +.It "Japan " Ta 11 Ta "2484" +.It "France " Ta 12 Ta "2457, 2465, 2475" +.It "Australia " Ta 13 Ta "2411, 2425, 2439" +.It "Germany " Ta 14 Ta "2427, 2442, 2457" +.It "U.K.(MPT1349)" Ta 15 Ta "2460" +.It "U.K. " Ta 15 Ta "2460" +.It "Spain " Ta 15 Ta "2460" +.El +.It Cm bitrate Ar bitrate ( Cm 0-4) +.It Cm spread Ar spread Cm ( 354, 500, 1000, 2000 ) +Set device operating bitrate or spread. +.Bl -column ".Em Rate" ".Em Spread" ".Em kb/s" -offset indent indent +.Em "Rate Spread kb/s" +.It 0 Ta - Ta Auto +.It 1 Ta 354 Ta 354 +.It 2 Ta 512 Ta 512 +.It 3 Ta 1000 Ta 1000 +.It 4 Ta 2000 Ta 2000 +.El +.It Cm priority Ar priority ( Cm normal, high, highest ) +Use the +.Ar priority +parameter to set the priority of the Atlan 655 Radio Media Access Control +the values are +.Cm normal , high +or +.Cm higest . +The higher the priority set, the more likely this unit wil be first +to successfully transmit a packet when multiple units are trying +to transmit at the same time. +.Pp +The percentage of units on your network that you set to other than +.Dq normal +should be kept small - 10 percent or less. +.It Cm stat +Print internal Arlan 655 statistics block. +.It Cm quality Ar seconds [ Cm count Ar ] +Perform link quality test during +.Ar seconds +transmitting +.Ar count +packets. +Currently is broken. +.El +.Sh EXAMPLES +.Bd -literal -offset indent +alrlconfig arl0 name NODE1 sid 4 freq 2442 +arlconfig arl0 quality 10 seconds +arlconfig arl0 status +.Pp +You can configure Arlan 655 card from /etc/start_if.arl0. For example: +.Pp +#!/bin/sh +/sbin/arlconfig arl0 sid 0x000002 freq 2412 spread 2000 mode 640 +.Sh SEE ALSO +.Xr arl 4 , +.Xr "Arlan 655 ISA Wireless LAN Client Card User Guide" . +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 5.3 . +.Sh BUGS +Aironet Arlan 640 bridges and Arlan 630 access points don't understand +country codes other than 9. +.Sh AUTHORS +The +.Nm +utility was written by +.Aq ran@styx.aic.net . +Manpage was written by +.An Yuri Kurenkov Aq y.kurenkov@init.ru . diff --git a/usr.sbin/arlcontrol/arlcontrol.c b/usr.sbin/arlcontrol/arlcontrol.c new file mode 100644 index 0000000..4ab5ca9 --- /dev/null +++ b/usr.sbin/arlcontrol/arlcontrol.c @@ -0,0 +1,612 @@ +/* + * $RISS: if_arl/arlconfig/arlconfig.c,v 1.3 2003/01/13 07:23:25 count Exp $ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct freq_list { + short fr_no; + char* name; +}; + +struct freq_list freq_list_1[] = { + { 0, "908.50" }, + { 1, "910.06" }, + { 2, "915.52" }, + { 3, "915.00" }, + { 4, "917.83" }, + { 5, "919.22" }, + { 6, "922.26" }, + { 7, "911.45" }, + { 8, "915.00" }, + { 9, "918.55" }, + { 10,"915.00" }, + { 11,"915.00" } +}; + +struct freq_list freq_list_6[] = { + { 0, "920.31" }, + { 1, "920.33" }, + { 2, "921.55" }, + { 3, "922.17" }, + { 4, "922.79" }, + { 5, "921.46" }, + { 6, "921.55" } +}; + +struct freq_list freq_list_9[] = { + { 0, "Bad" }, + { 1, "2412" }, + { 2, "2427" }, + { 3, "2442" }, + { 4, "2457" }, + { 5, "2465" } +}; + + +struct freq_list freq_list_10[] = { + { 0, "Bad" }, + { 1, "2412" }, + { 2, "2427" }, + { 3, "2442" }, + { 4, "2457" }, + { 5, "2472" } +}; + +struct freq_list freq_list_11[] = { + { 0, "Bad" }, + { 1, "2484" } +}; + +struct freq_list freq_list_12[] = { + { 0, "Bad" }, + { 1, "2457" }, + { 2, "2465" }, + { 3, "2472" }, +}; + +struct freq_list freq_list_13[] = { + { 0, "Bad" }, + { 1, "2411" }, + { 2, "2425" }, + { 3, "2439" } +}; + +struct freq_list freq_list_14[] = { + { 0, "Bad" }, + { 1, "2427" }, + { 2, "2442" }, + { 3, "2457" } +}; + +struct freq_list freq_list_15[] = { + { 0, "Bad" }, + { 1, "2460" } +}; + +#define MAXFREQ(a) sizeof(a)/sizeof(struct freq_list) + +struct rate_list { + short rate_no; + char* name; +}; + +struct rate_list rate_list_2400[] = { + { 0, "Bad" }, + { 1, "354" }, + { 2, "512" }, + { 3, "1000" }, + { 4, "2000" } +}; + +struct radio_type { + int id; + char* name; +} radio_type_list [] = { + { 0, "No EPROM" }, + { 1, "092/094" }, + { 2, "020" }, + { 3, "092A" }, + { 4, "020B" }, + { 5, "095" }, + { 6, "024" }, + { 7, "025B" }, + { 8, "024B" }, + { 9, "024C" }, + {10, "025C" }, + {11, "024-1A" }, + {12, "025-1A" }, + {13, "Other" } +}; + +static struct ch_list { + short chan; + char* fr; + char* country; + struct rate_list* rate; + struct freq_list* freq; + int max_freq; +} CHSET[] = { + { 0, 0, 0, 0, 0, 0 }, + { 1, "900 Mhz", "Canada, U.S.A., Mexico", 0, freq_list_1, MAXFREQ(freq_list_1) }, + { 2, 0, 0, 0, 0, 0 }, + { 3, 0, 0, 0, 0, 0 }, + { 4, 0, 0, 0, 0, 0 }, + { 5, 0, 0, 0, 0, 0 }, + { 6, "900 Mhz", "Australia", 0, freq_list_6, MAXFREQ(freq_list_6) }, + { 7, 0, 0, 0, 0, 0 }, + { 8, 0, 0, 0, 0, 0 }, + { 9, "2400 Mhz", "North America", rate_list_2400, freq_list_9, MAXFREQ(freq_list_9) }, + { 10, "2400 Mhz", "E.T.S.I", rate_list_2400, freq_list_10, MAXFREQ(freq_list_10) }, + { 11, "2400 Mhz", "Japan", rate_list_2400, freq_list_11, MAXFREQ(freq_list_11) }, + { 12, "2400 Mhz", "France", rate_list_2400, freq_list_12, MAXFREQ(freq_list_12) }, + { 13, "2400 Mhz", "Australia", rate_list_2400, freq_list_13, MAXFREQ(freq_list_13) }, + { 14, "2400 Mhz", "Germany", rate_list_2400, freq_list_14, MAXFREQ(freq_list_14) }, + { 15, "2400 Mhz", "U.K.(MPT1349),Spain", rate_list_2400, freq_list_15, MAXFREQ(freq_list_15) } +}; + +char* registrationMode[] = { + "NON-TMA", + "TMA", + "PSP" +}; + +char* priorityList[] = { + "normal", + "high", + "highest" +}; + +void +usage() +{ + const char *progname = getprogname(); + +#if 0 + fprintf(stderr, "\nArlan configuration utility.\n\n"); +#endif + fprintf(stderr, "Usage: %s [ ...]\n", progname); + fprintf(stderr, "\t\tArlan interface name.\n"); + fprintf(stderr, "\t\t\tParameter name (see below).\n"); + fprintf(stderr, "\t\t\tNew value for parameter.\n"); + fprintf(stderr, "Parameter name:\t\tValue:\n"); + fprintf(stderr, "\tname\t\tset Name.\n"); + fprintf(stderr, "\tsid\t\tset System ID.\n"); + fprintf(stderr, "\tfreq\t\tset Frequency Channel (2412, 2427, 2442, 2457, 2465)\n"); + fprintf(stderr, "\tspread\t\tset Bitrate (354, 500, 1000, 2000)\n"); + fprintf(stderr, "\tmode\t\tset Mode (640, 655, PSP).\n"); + fprintf(stderr, "\tcountry\t\tset Country (9-15)\n"); + fprintf(stderr, "\tchannel\t\tset Channel (depended on country)\n"); + fprintf(stderr, "\tbitrate\t\tset Bitrate (0-4)\n"); + fprintf(stderr, "\tpriority\tset Priority (normal, high, highest)\n"); +#if 0 + fprintf(stderr, "\tparent\t\tset Arlan parent's MAC.\n"); + fprintf(stderr, "\taddr\t\tset Arlan MAC.\n"); +#endif + fprintf(stderr, "or: %s stat\n", progname); + fprintf(stderr, "\tprint internal arlan statistics block\n"); + fprintf(stderr, "or: %s quality [count ]\n", + progname); + fprintf(stderr, "\tprint receive packet level and quality with interval\n"); + exit(0); +} + +void +print_al(struct arl_cfg_param *arl_io) +{ + printf("Arlan-655(IC2000) type 0x%x v%d.%d, radio module type %s\n", + arl_io->hardwareType, + arl_io->majorHardwareVersion, + arl_io->minorHardwareVersion, + (arl_io->radioModule < 13) ? + radio_type_list[arl_io->radioModule].name : "Unknown" ); + printf("\tname %s, sid 0x%06x, mode %s, num tx retry %d\n", + arl_io->name, + *(int *)arl_io->sid, + (arl_io->registrationMode < 3) ? + registrationMode[arl_io->registrationMode]:"Unknown", + arl_io->txRetry ); + printf("\tchannel set %d, %s, %s\n", + arl_io->channelSet, + CHSET[arl_io->channelSet].fr, + CHSET[arl_io->channelSet].country); + printf("\tfrequency %s Mhz, bitrate %s kb/s, priority %s, receive mode %d\n", + (CHSET[arl_io->channelSet].freq && + CHSET[arl_io->channelSet].max_freq > arl_io->channelNumber) ? + CHSET[arl_io->channelSet].freq[arl_io->channelNumber].name : + "unknown", + (CHSET[arl_io->channelSet].rate) ? + CHSET[arl_io->channelSet].rate[arl_io->spreadingCode].name : + "unknown", + arl_io->priority <= 2 ? + priorityList[arl_io->priority] : "unknown", + arl_io->receiveMode); + printf("\tether %s", + (char *)ether_ntoa((struct ether_addr *)arl_io->lanCardNodeId)); + printf(" registered to %s\n", + (char *)ether_ntoa((struct ether_addr *)arl_io->specifiedRouter)); +} + +void +print_stb( struct arl_stats stb ) +{ + printf("Arlan internal statistics block\n\n"); + printf("%8u\tdatagrams transmitted\n", + stb.numDatagramsTransmitted); + printf("%8u\tre-transmitted\n", + stb.numReTransmissions); + printf("%8u\tframes discarded internally in a router\n", + stb.numFramesDiscarded); + printf("%8u\tdatagrams received\n", + stb.numDatagramsReceived); + printf("%8u\tduplicate received frame\n", + stb.numDuplicateReceivedFrames); + printf("%8u\tdatagrams discarded due to unavailable mail box buffer\n", + stb.numDatagramsDiscarded); + printf("%8d\tmaximum of re-transmissions datagram\n", + stb.maxNumReTransmitDatagram); + printf("%8d\tmaximum of re-transmissions frame\n", + stb.maxNumReTransmitFrames); + printf("%8d\tmaximum of consecutive duplicate received frames\n", + stb.maxNumConsecutiveDuplicateFrames); + printf("%8u\tbytes transmitted\n", + stb.numBytesTransmitted); + printf("%8u\tbytes received\n", + stb.numBytesReceived); + printf("%8u\tCRC errors\n", + stb.numCRCErrors); + printf("%8u\tlength errors\n", + stb.numLengthErrors); + printf("%8u\tabort errors\n", + stb.numAbortErrors); + printf("%8u\tTX underuns\n", + stb.numTXUnderruns); + printf("%8u\tRX overruns\n", + stb.numRXOverruns); + printf("%8u\tHold Offs (channel tested busy, tx delayed)\n", + stb.numHoldOffs); + printf("%8u\tframes transmitted\n", + stb.numFramesTransmitted); + printf("%8u\tframes received\n", + stb.numFramesReceived); + printf("%8u\treceive frames lost due unavailable buffer\n", + stb.numReceiveFramesLost); + printf("%8u\tRX buffer overflows \n", + stb.numRXBufferOverflows); + printf("%8u\tframes discarded due to Address mismatch\n", + stb.numFramesDiscardedAddrMismatch); + printf("%8u\tframes discarded due to SID mismatch\n", + stb.numFramesDiscardedSIDMismatch); + printf("%8u\tpolls transmitted\n", + stb.numPollsTransmistted); + printf("%8u\tpoll acknowledges received\n", + stb.numPollAcknowledges); + printf("%8u\tstatus vector timeout\n", + stb.numStatusVectorTimeouts); + printf("%8u\tNACK packets received\n", + stb.numNACKReceived); +} + +#ifdef ARL_QUALITY +void +print_qlt(struct arl_quality qlt, int count) +{ + int i, s; + int v, v1; + time_t t; + int minLevel, maxLevel, avgLevel; + int minQuality, maxQuality, avgQuality; + + t = time(NULL); + localtime(&t); + printf("#%d Current date-time: %s", count, ctime(&t)); + printf(" %-39s %s\n","Receive Level","Receive Quality"); + printf( +" pkts 0.......10 11............100 > pkts 0.......10 11............100 >\n"\ +" -----+----------+-----------------+--- -----+----------+-----------------+---\n"); + + minLevel = 16; + maxLevel = 0; + avgLevel = 0; + minQuality = 16; + maxQuality = 0; + avgQuality = 0; + + for (i = 0, s = 0; i < ARLAN_MAX_QUALITY; i++) { + v = qlt.rxLevel[i]; + if (v) { + if (i < minLevel) + minLevel = i; + if (i > maxLevel) + maxLevel = i; + avgLevel += v*i; + printf(" %-4d %x", v, i); + } else + printf(" o %x", i); + s += v; + if (v < 10) + ; + else if (v < 100) + v = 10 + ((v-10) * 20) / 90; + else if (v < 1000) + v = 31; + else + v = 32; + v1 = v; + while (v) { + printf("*"); + v--; + } + + v = 33 - v1; + while (v) { + printf(" "); + v--; + } + + v = qlt.rxQuality[i]; + if (v) { + if (i < minQuality) + minQuality = i; + if (i > maxQuality) + maxQuality = i; + avgQuality += v*i; + printf("%-4d %x", v, i); + } else + printf("o %x", i); + + if (v < 10) + ; + else if (v < 100) + v = 10 + ((v-10) * 20) / 90; + else if (v < 1000) + v = 31; + else + v = 32; + } + v1 = v; + while (v) { + printf("*"); + v--; + } + + printf("\n"); + } + printf(" -----+----------+-----------------+--- -----+----------+-----------------+---\n"); + if (minLevel > 15) + minLevel = 0; + if (minQuality > 15) + minQuality = 0; + printf("\tPackets count %-6d\n", s); + if (!s) + s++; + printf("\tLevel min %d/avg %d/max %d\n", + minLevel, avgLevel/s, maxLevel); + printf("\tQuality min %d/avg %d/max %d\n", + minQuality, avgQuality/s, maxQuality); +} +#endif /* ARL_QUALITY */ + +int +main(int argc, char *argv[]) +{ + struct ifreq ifr; + struct arl_req arl_io; + struct ether_addr *ea; + struct arl_stats stb; + /*static arl_quality qlt;*/ + int sd, argind, val = -1; + long val2; + char *param, *value, *value2; + /*int end_count, i;*/ + + if (argc < 2) + usage(); + + sd = socket(AF_INET, SOCK_DGRAM, 0); + if (sd < 0) + err(1,"socket"); + strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); + ifr.ifr_addr.sa_family = AF_INET; + bzero(&arl_io, sizeof(arl_io)); + ifr.ifr_data = (caddr_t)&arl_io; + + if (argc == 2) { + if (ioctl(sd, SIOCGARLALL, (caddr_t)&ifr)) + err(1,"Get ALL"); + print_al(&arl_io.cfg); + exit(0); + } + + if (argc == 3) { + if (!strcasecmp(argv[2], "stat")) { + strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); + ifr.ifr_addr.sa_family = AF_INET; + ifr.ifr_data = (caddr_t)&stb; + if (ioctl(sd, SIOCGARLSTB, (caddr_t)&ifr)) + err(1,"Get STB"); + print_stb(stb); + exit(0); + } +#ifdef ARL_QUALITY + if (!strcasecmp(argv[2],"quality") && argc > 3) { + val = atoi(argv[3]); + if (val < 0 || val >= 3601) + err(1,"Bad time range"); + end_count = 0; + if (argc > 5 && !strcasecmp(argv[4], "count")) + end_count = atoi(argv[5]); + printf("\n"); + i = 0; + while (i < end_count || !end_count) { /* loop */ + if (i++) + sleep(val); + strncpy(ifr.ifr_name, + argv[1], sizeof(ifr.ifr_name)); + ifr.ifr_addr.sa_family = AF_INET; + ifr.ifr_data = (caddr_t)&qlt; + if (ioctl(sd, SIOCGARLQLT, (caddr_t)&ifr)) + err(1,"Get QLT"); + print_qlt(qlt, i); + } + exit(0); + } +#endif /* ARL_QUALITY */ + } + + arl_io.what_set = 0; + + for (argind = 2; argind < argc; argind += 2) { + param = argv[argind]; + value = argv[argind+1]; + val = -1; + + if (!strcasecmp(param, "name")) { + bzero(arl_io.cfg.name, 16); + strncpy(arl_io.cfg.name, value, 16); + arl_io.what_set |= ARLAN_SET_name; + } + + if (!strcasecmp(param, "sid")) { + val2 = strtol(value, &value2, 0); + if (val2 < 0 || val2 > 0xffffff || val2 % 2 || + value == value2) + err(1, "Bad SID - %s", value); + bcopy(&val2, arl_io.cfg.sid, 4); + arl_io.what_set |= ARLAN_SET_sid; + } + + if (!strcasecmp (param, "freq")) { + if (!strcmp(value, "2412")) + val = 1; + else if (!strcmp(value, "2427")) + val = 2; + else if (!strcmp(value, "2442")) + val = 3; + else if (!strcmp(value, "2457")) + val = 4; + else if (!strcmp(value, "2465")) + val = 5; + if (val == -1) + err(1, "Bad Frequency - %s", value); + arl_io.cfg.channelNumber = val; + arl_io.what_set |= ARLAN_SET_channelNumber; + } + + if (!strcasecmp(param, "spread")) { + if (!strcmp(value, "354")) + val = 1; + else if (!strcmp(value, "500")) + val = 2; + else if (!strcmp(value, "1000")) + val = 3; + else if (!strcmp(value, "2000")) + val = 4; + if (val == -1) + err (1, "Bad Bitrate - %s", value); + arl_io.cfg.spreadingCode = val; + arl_io.what_set |= ARLAN_SET_spreadingCode; + } + + if (!strcasecmp(param, "priority")) { + if (!strcasecmp(value, "normal")) + val = 0; + else if (!strcasecmp(value, "high")) + val = 1; + else if (!strcasecmp(value, "highest")) + val = 2; + if (val == -1) + err( 1, "Bad priority - %s", value); + arl_io.cfg.priority = val; + arl_io.what_set |= ARLAN_SET_priority; + } + + if (!strcasecmp(param, "mode")) { + if (!strcmp(value, "655")) + val = 0; + else if (!strcmp(value, "640")) + val = 1; + else if (!strcasecmp (value, "PSP")) + val = 2; + if (val == -1) + err (1, "Bad Mode - %s", value); + arl_io.cfg.registrationMode = val; + arl_io.what_set |= ARLAN_SET_registrationMode; + } + + if (!strcasecmp(param, "parent")) { + if ((ea = (struct ether_addr*) ether_aton(value)) == NULL) + err (1, "Bad parent's MAC - %s", value); + for (val = 0; val < 6; val++) { + arl_io.cfg.specifiedRouter[val] = + (int) ea->octet[val]; + } + arl_io.what_set |= ARLAN_SET_specifiedRouter; + } + + if (!strcasecmp(param, "addr")) { + if ((ea = (struct ether_addr*) ether_aton(value)) == NULL) + err (1, "Bad MAC - %s", value); + for (val = 0; val < 6; val++) { + arl_io.cfg.lanCardNodeId[val] = + (int) ea->octet[val]; + } + arl_io.what_set |= ARLAN_SET_lanCardNodeId; + } + + if (!strcasecmp(param, "country")) { + arl_io.cfg.channelSet = atoi(value); + arl_io.what_set |= ARLAN_SET_channelSet; + } + + if (!strcasecmp(param, "channel")) { + arl_io.cfg.channelNumber = atoi(value); + arl_io.what_set |= ARLAN_SET_channelNumber; + } + + if (!strcasecmp(param, "bitrate")) { + arl_io.cfg.spreadingCode = atoi(value); + arl_io.what_set |= ARLAN_SET_spreadingCode; + } + + if (!strcasecmp(param, "receive")) { + arl_io.cfg.receiveMode = atoi(value); + arl_io.what_set |= ARLAN_SET_receiveMode; + } + + if (!strcasecmp(param, "txretry")) { + arl_io.cfg.txRetry = atoi(value); + arl_io.what_set |= ARLAN_SET_txRetry; + } + } + + if (arl_io.what_set) { + if (ioctl(sd, SIOCSARLALL, (caddr_t)&ifr)) + err (1, "Set ALL" ); + if (ioctl(sd, SIOCGARLALL, (caddr_t)&ifr)) + err (1, "Get ALL"); + print_al(&arl_io.cfg); + } + + return 0; +} -- cgit v1.1