Annotation of sys/dev/ic/rln.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: rln.c,v 1.18 2006/03/25 22:41:43 djm Exp $ */
! 2: /*
! 3: * David Leonard <d@openbsd.org>, 1999. Public Domain.
! 4: *
! 5: * Driver for the Proxim RangeLAN2 wireless network adaptor.
! 6: *
! 7: * Information and ideas gleaned from disassembly of Dave Koberstein's
! 8: * <davek@komacke.com> Linux driver (apparently based on Proxim source),
! 9: * from Yoichi Shinoda's <shinoda@cs.washington.edu> BSDI driver, and
! 10: * Geoff Voelker's <voelker@cs.washington.edu> Linux port of the same.
! 11: *
! 12: */
! 13:
! 14: #include "bpfilter.h"
! 15:
! 16: #include <sys/param.h>
! 17: #include <sys/systm.h>
! 18: #include <sys/mbuf.h>
! 19: #include <sys/socket.h>
! 20: #include <sys/ioctl.h>
! 21: #include <sys/syslog.h>
! 22: #include <sys/device.h>
! 23: #include <sys/kernel.h>
! 24:
! 25: #include <net/if.h>
! 26: #include <net/if_media.h>
! 27:
! 28: #ifdef INET
! 29: #include <netinet/in.h>
! 30: #include <netinet/if_ether.h>
! 31: #endif
! 32:
! 33: #if NBPFILTER > 0
! 34: #include <net/bpf.h>
! 35: #endif
! 36:
! 37: #include <machine/bus.h>
! 38: #include <machine/intr.h>
! 39:
! 40: #include <dev/ic/rln.h>
! 41: #include <dev/ic/rlnvar.h>
! 42: #include <dev/ic/rlnreg.h>
! 43: #include <dev/ic/rlncmd.h>
! 44:
! 45: /* Autoconfig definition of driver back-end. */
! 46: struct cfdriver rln_cd = {
! 47: NULL, "rln", DV_IFNET
! 48: };
! 49:
! 50: void rlninit(struct rln_softc *);
! 51: void rlnstart(struct ifnet*);
! 52: void rlnwatchdog(struct ifnet*);
! 53: int rlnioctl(struct ifnet *, u_long, caddr_t);
! 54: void rlnstop(struct rln_softc *);
! 55:
! 56: /* Interrupt handler. */
! 57: void rlnsoftintr(void *);
! 58:
! 59: /* Packet I/O. */
! 60: int rln_transmit(struct rln_softc *, struct mbuf *,
! 61: int, int);
! 62: struct mbuf * rlnget(struct rln_softc *, struct rln_mm_cmd *,
! 63: int);
! 64:
! 65: /* Card protocol-level functions. */
! 66: int rln_getenaddr(struct rln_softc *, u_int8_t *);
! 67: int rln_getpromvers(struct rln_softc *, char *, int);
! 68: int rln_sendinit(struct rln_softc *);
! 69: #if notyet
! 70: int rln_roamconfig(struct rln_softc *);
! 71: int rln_roam(struct rln_softc *);
! 72: int rln_multicast(struct rln_softc *, int);
! 73: int rln_searchsync(struct rln_softc *);
! 74: int rln_iosetparam(struct rln_softc *, struct rln_param *);
! 75: int rln_lockprom(struct rln_softc *);
! 76: int rln_ito(struct rln_softc *);
! 77: int rln_standby(struct rln_softc *);
! 78: #endif
! 79:
! 80: /* Back-end attach and configure. Assumes card has been reset. */
! 81: void
! 82: rlnconfig(sc)
! 83: struct rln_softc * sc;
! 84: {
! 85: struct ifnet * ifp = &sc->sc_arpcom.ac_if;
! 86: char promvers[7];
! 87: int i;
! 88:
! 89: dprintf(" [attach %p]", sc);
! 90:
! 91: /* Use the flags supplied from config. */
! 92: sc->sc_cardtype |= sc->sc_dev.dv_cfdata->cf_flags;
! 93:
! 94: /* Initialise values in the soft state. */
! 95: sc->sc_pktseq = 0; /* rln_newseq() */
! 96: sc->sc_txseq = 0;
! 97: sc->sc_state = 0;
! 98:
! 99: /* Initialise user-configurable params. */
! 100: sc->sc_param.rp_roam_config = RLN_ROAM_NORMAL;
! 101: sc->sc_param.rp_security = RLN_SECURITY_DEFAULT;
! 102: sc->sc_param.rp_station_type = RLN_STATIONTYPE_ALTMASTER;
! 103: sc->sc_param.rp_domain = 0;
! 104: sc->sc_param.rp_channel = 1;
! 105: sc->sc_param.rp_subchannel = 1;
! 106:
! 107: bzero(sc->sc_param.rp_master, sizeof sc->sc_param.rp_master);
! 108:
! 109: /* Initialise the message mailboxes. */
! 110: for (i = 0; i < RLN_NMBOX; i++)
! 111: sc->sc_mbox[i].mb_state = RLNMBOX_VOID;
! 112:
! 113: /* Probe for some properties. */
! 114: printf(", %s-piece",
! 115: (sc->sc_cardtype & RLN_CTYPE_ONE_PIECE) ? "one" : "two");
! 116: if (sc->sc_cardtype & RLN_CTYPE_OEM)
! 117: printf(" oem");
! 118: if (sc->sc_cardtype & RLN_CTYPE_UISA)
! 119: printf(" micro-isa");
! 120:
! 121: /* Read the card's PROM revision. */
! 122: if (rln_getpromvers(sc, promvers, sizeof promvers)) {
! 123: printf(": could not read PROM version\n");
! 124: return;
! 125: }
! 126: printf(", fw %.7s", promvers);
! 127:
! 128: /* Fetch the card's MAC address. */
! 129: if (rln_getenaddr(sc, sc->sc_arpcom.ac_enaddr)) {
! 130: printf(": could not read MAC address\n");
! 131: return;
! 132: }
! 133: printf(", addr %s", ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 134:
! 135: timeout_set(&sc->sc_timeout, rlnsoftintr, sc);
! 136:
! 137: /* Attach as a network interface. */
! 138: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 139: ifp->if_softc = sc;
! 140: ifp->if_start = rlnstart;
! 141: ifp->if_ioctl = rlnioctl;
! 142: ifp->if_watchdog = rlnwatchdog;
! 143: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
! 144: IFQ_SET_READY(&ifp->if_snd);
! 145: if_attach(ifp);
! 146: ether_ifattach(ifp);
! 147: }
! 148:
! 149: /* Bring device up. */
! 150: void
! 151: rlninit(sc)
! 152: struct rln_softc * sc;
! 153: {
! 154: /* LLDInit() */
! 155: struct ifnet * ifp = &sc->sc_arpcom.ac_if;
! 156: int s;
! 157:
! 158: s = splnet();
! 159: dprintf(" [init]");
! 160:
! 161: sc->sc_intsel = 0;
! 162: sc->sc_status = 0;
! 163: sc->sc_control = 0;
! 164: ifp->if_flags &= ~IFF_RUNNING;
! 165: ifp->if_flags &= ~IFF_OACTIVE;
! 166:
! 167: /* Do a hard reset. */
! 168: if (rln_reset(sc)) {
! 169: printf("%s: could not reset card\n", sc->sc_dev.dv_xname);
! 170: goto fail;
! 171: }
! 172: sc->sc_state = 0; /* Also clears RLN_STATE_NEEDINIT. */
! 173:
! 174: /* Use this host's name as a master name. */
! 175: if (!cold && sc->sc_param.rp_master[0] == '\0') {
! 176: bcopy(hostname, sc->sc_param.rp_master,
! 177: min(hostnamelen, sizeof sc->sc_param.rp_master));
! 178: }
! 179:
! 180: rln_enable(sc, 1);
! 181:
! 182: /* Initialise operational params. */
! 183: if (rln_sendinit(sc)) {
! 184: printf("%s: could not set card parameters\n",
! 185: sc->sc_dev.dv_xname);
! 186: goto fail;
! 187: }
! 188: #if 0
! 189: rln_roamconfig(sc);
! 190: /* rln_lockprom(sc); */
! 191: /* SendSetITO() */
! 192: rln_multicast(sc, 1);
! 193: rln_roam(sc);
! 194:
! 195: /* Synchronise with something. */
! 196: rln_searchsync(sc);
! 197: #endif
! 198: ifp->if_flags |= IFF_RUNNING;
! 199: rlnstart(ifp);
! 200: splx(s);
! 201:
! 202: return;
! 203:
! 204: fail:
! 205: ifp->if_flags &= ~IFF_UP;
! 206: splx(s);
! 207: return;
! 208: }
! 209:
! 210: /* Start outputting on interface. This is always called at splnet(). */
! 211: void
! 212: rlnstart(ifp)
! 213: struct ifnet * ifp;
! 214: {
! 215: struct rln_softc * sc = (struct rln_softc *)ifp->if_softc;
! 216: struct mbuf * m0;
! 217: int len, pad, ret, s;
! 218:
! 219: dprintf(" start[");
! 220:
! 221: if (sc->sc_state & RLN_STATE_NEEDINIT)
! 222: rlninit(sc);
! 223:
! 224: /* Don't transmit if interface is busy or not running. */
! 225: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) {
! 226: dprintf(" %s] ", (ifp->if_flags & IFF_OACTIVE) ?
! 227: "busy" : "stopped");
! 228: return;
! 229: }
! 230:
! 231: /* Don't transmit if we are not synchronised. */
! 232: if ((sc->sc_state & RLN_STATE_SYNC) == 0) {
! 233: dprintf(" nosync]");
! 234: return;
! 235: }
! 236:
! 237: rln_enable(sc, 1);
! 238:
! 239: startagain:
! 240: s = splnet();
! 241: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 242: splx(s);
! 243:
! 244: if (m0 == NULL) {
! 245: dprintf(" empty]");
! 246: return;
! 247: }
! 248:
! 249: #if NBPFILTER > 0
! 250: /* Tap packet stream here for BPF listeners. */
! 251: if (ifp->if_bpf)
! 252: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 253: #endif
! 254:
! 255: /* We need to use m->m_pkthdr.len, so require the header. */
! 256: if ((m0->m_flags & M_PKTHDR) == 0) {
! 257: printf("%s: no mbuf header\n", sc->sc_dev.dv_xname);
! 258: goto oerror;
! 259: }
! 260:
! 261: len = m0->m_pkthdr.len;
! 262:
! 263: #define PACKETMIN (sizeof (struct ether_header) + ETHERMIN)
! 264: #define PACKETMAX (sizeof (struct ether_header) + ETHERMTU + 4)
! 265:
! 266: /* Packet size has to be an even number between 60 and 1518 octets. */
! 267: pad = len & 1;
! 268: if (len + pad < PACKETMIN)
! 269: pad = PACKETMIN - len;
! 270:
! 271: if (len + pad > PACKETMAX) {
! 272: printf("%s: packet too big (%d > %d)\n",
! 273: sc->sc_dev.dv_xname, len + pad,
! 274: PACKETMAX);
! 275: ++ifp->if_oerrors;
! 276: m_freem(m0);
! 277: goto startagain;
! 278: }
! 279:
! 280: ret = rln_transmit(sc, m0, len, pad);
! 281: if (ret)
! 282: goto oerror;
! 283:
! 284: ifp->if_flags |= IFF_OACTIVE;
! 285: m_freem(m0);
! 286:
! 287: dprintf(" sent]");
! 288: return;
! 289:
! 290: oerror:
! 291: ++ifp->if_oerrors;
! 292: m_freem(m0);
! 293: rln_need_reset(sc);
! 294: return;
! 295: }
! 296:
! 297: /* Transmit one packet. */
! 298: int
! 299: rln_transmit(sc, m0, len, pad)
! 300: struct rln_softc * sc;
! 301: struct mbuf * m0;
! 302: int len;
! 303: int pad;
! 304: {
! 305: struct mbuf * m;
! 306: int zfirst;
! 307: int actlen;
! 308: int tlen = len + pad;
! 309: struct rln_msg_tx_state state;
! 310: static u_int8_t zeroes[60];
! 311: struct rln_mm_sendpacket cmd = { RLN_MM_SENDPACKET };
! 312:
! 313: /* Does the packet start with a zero bit? */
! 314: zfirst = ((*mtod(m0, u_int8_t *) & 1) == 0);
! 315:
! 316: cmd.mode =
! 317: RLN_MM_SENDPACKET_MODE_BIT7 |
! 318: (zfirst ? RLN_MM_SENDPACKET_MODE_ZFIRST : 0) |
! 319: (0 ? RLN_MM_SENDPACKET_MODE_QFSK : 0), /* sc->qfsk? */
! 320: cmd.power = 0x70; /* 0x70 or 0xf0 */
! 321: cmd.length_lo = htons(4 + tlen) & 0xff;
! 322: cmd.length_hi = (htons(4 + tlen) >> 8) & 0xff;
! 323: cmd.xxx1 = 0;
! 324: cmd.xxx2 = 0;
! 325: cmd.xxx3 = 0;
! 326:
! 327: /* A unique packet-level sequence number, independent of sc_seq. */
! 328: cmd.sequence = sc->sc_txseq;
! 329: sc->sc_txseq++;
! 330: if (sc->sc_txseq > RLN_MAXSEQ)
! 331: sc->sc_txseq = 0;
! 332:
! 333: dprintf(" T[%d+%d", len, pad);
! 334:
! 335: if (rln_msg_tx_start(sc, &cmd, sizeof cmd + tlen, &state))
! 336: goto error;
! 337:
! 338: cmd.mm_cmd.cmd_seq = rln_newseq(sc);
! 339:
! 340: /* Send the SENDPACKET command header */
! 341: #ifdef RLNDUMP
! 342: printf("%s: send %c%d seq %d data ", sc->sc_dev.dv_xname,
! 343: cmd.mm_cmd.cmd_letter, cmd.mm_cmd.cmd_fn, cmd.mm_cmd.cmd_seq);
! 344: RLNDUMPHEX(&cmd, sizeof cmd);
! 345: printf(":");
! 346: #endif
! 347: rln_msg_tx_data(sc, &cmd, sizeof cmd, &state);
! 348:
! 349: /* XXX do we need to insert a hardware header here??? */
! 350:
! 351: /* Follow the header immediately with the packet payload */
! 352: actlen = 0;
! 353: for (m = m0; m; m = m->m_next) {
! 354: if (m->m_len) {
! 355: #ifdef RLNDUMP
! 356: RLNDUMPHEX(mtod(m, void *), m->m_len);
! 357: #endif
! 358: rln_msg_tx_data(sc, mtod(m, void *), m->m_len, &state);
! 359: }
! 360: if (m->m_next)
! 361: printf("|");
! 362: actlen += m->m_len;
! 363: }
! 364: #ifdef DIAGNOSTIC
! 365: if (actlen != len)
! 366: panic("rln_transmit: len %d != %d", actlen, len);
! 367: if (pad > sizeof zeroes)
! 368: panic("rln_transmit: pad %d > %d", pad, sizeof zeroes);
! 369: #endif
! 370: if (pad) {
! 371: #ifdef RLNDUMP
! 372: printf(":");
! 373: RLNDUMPHEX(zeroes, pad);
! 374: #endif
! 375: rln_msg_tx_data(sc, zeroes, pad, &state);
! 376: }
! 377:
! 378: #ifdef RLNDUMP
! 379: printf("\n");
! 380: #endif
! 381: if (rln_msg_tx_end(sc, &state))
! 382: goto error;
! 383: return (0);
! 384:
! 385: error:
! 386: dprintf(" error]");
! 387: return (-1);
! 388: }
! 389:
! 390: /* (Supposedly) called when interrupts are suspiciously absent. */
! 391: void
! 392: rlnwatchdog(ifp)
! 393: struct ifnet * ifp;
! 394: {
! 395: struct rln_softc * sc = (struct rln_softc *)ifp->if_softc;
! 396:
! 397: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 398: ++sc->sc_arpcom.ac_if.if_oerrors;
! 399: rlninit(sc);
! 400: rln_enable(sc, 1);
! 401: }
! 402:
! 403: /* Handle single card interrupt. */
! 404: int
! 405: rlnintr(arg)
! 406: void * arg;
! 407: {
! 408: struct rln_softc * sc = (struct rln_softc *)arg;
! 409:
! 410: dprintf("!");
! 411:
! 412: /* Tell card not to interrupt any more. */
! 413: rln_enable(sc, 0);
! 414:
! 415: if (cold)
! 416: /* During autoconfig - must handle interrupts now. */
! 417: rlnsoftintr(sc);
! 418: else
! 419: /* Handle later. */
! 420: timeout_add(&sc->sc_timeout, 1);
! 421:
! 422: return (1);
! 423: }
! 424:
! 425: /* Process earlier card interrupt at splsoftnet. */
! 426: void
! 427: rlnsoftintr(arg)
! 428: void * arg;
! 429: {
! 430: struct rln_softc *sc = (struct rln_softc *)arg;
! 431: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 432: int len;
! 433: u_int8_t w;
! 434: struct rln_mm_cmd hdr;
! 435: int s;
! 436:
! 437: s = splsoftnet();
! 438: dprintf(" si(");
! 439:
! 440: again:
! 441: /* Save wakeup state. */
! 442: w = rln_wakeup(sc, RLN_WAKEUP_SET);
! 443:
! 444: if ((len = rln_rx_request(sc, 300)) < 0) {
! 445: /* Error in transfer. */
! 446: rln_need_reset(sc);
! 447: rln_rx_end(sc);
! 448: } else if (len < sizeof hdr) {
! 449: /* Short message. */
! 450: rln_rx_end(sc);
! 451: printf("%s: short msg (%d)\n", sc->sc_dev.dv_xname, len);
! 452: ifp->if_ierrors++;
! 453: } else {
! 454: /* Valid message: read header and process. */
! 455: rln_rx_data(sc, &hdr, sizeof hdr);
! 456: rlnread(sc, &hdr, len);
! 457: }
! 458:
! 459: /* Ensure that wakeup state is unchanged if transmitting. */
! 460: if (ifp->if_flags & IFF_OACTIVE)
! 461: w |= RLN_WAKEUP_NOCHANGE;
! 462: rln_wakeup(sc, w);
! 463:
! 464: /* Check for more interrupts. */
! 465: if ((sc->sc_state & RLN_STATE_NEEDINIT) == 0 &&
! 466: rln_status_rx_ready(sc)) {
! 467: if (rln_status_rx_read(sc) == RLN_STATUS_RX_ERROR) {
! 468: #ifdef DIAGNOSTIC
! 469: printf("%s: protocol error\n", sc->sc_dev.dv_xname);
! 470: #endif
! 471: DELAY(100 * 1000); /* Woah, baby. */
! 472: rln_clear_nak(sc);
! 473: } else {
! 474: #ifdef DIAGNOSTIC
! 475: printf("%s: intr piggyback\n", sc->sc_dev.dv_xname);
! 476: #endif
! 477: goto again;
! 478: }
! 479: }
! 480:
! 481: rln_eoi(sc);
! 482: rln_enable(sc, 1);
! 483:
! 484: dprintf(")");
! 485: splx(s);
! 486: }
! 487:
! 488: /* Read and process a message from the card. */
! 489: void
! 490: rlnread(sc, hdr, len)
! 491: struct rln_softc *sc;
! 492: struct rln_mm_cmd *hdr;
! 493: int len;
! 494: {
! 495: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 496: struct mbuf *m;
! 497: u_int8_t data[1538];
! 498: u_int8_t *buf;
! 499: size_t buflen;
! 500: struct rln_pdata pd = RLN_PDATA_INIT;
! 501: struct rln_mm_synchronised * syncp = (struct rln_mm_synchronised *)data;
! 502: int s;
! 503:
! 504: dprintf(" [read]");
! 505:
! 506: /* Were we waiting for this message? */
! 507: if (rln_mbox_lock(sc, hdr->cmd_seq, (void **)&buf, &buflen) == 0) {
! 508: #ifdef DIAGNOSTIC
! 509: if (buflen < sizeof *hdr)
! 510: panic("rlnread buflen");
! 511: #endif
! 512: bcopy(hdr, buf, sizeof *hdr);
! 513: buf += sizeof *hdr;
! 514: len -= sizeof *hdr;
! 515: buflen -= sizeof *hdr;
! 516: if (len) {
! 517: if (len == buflen) /* Expected size */
! 518: rln_rx_pdata(sc, buf, len, &pd);
! 519: else if (len < buflen) { /* Underfill */
! 520: #ifdef DIAGNOSTIC
! 521: printf("%s: underfill %d<%d, cmd %c%d\n",
! 522: sc->sc_dev.dv_xname,
! 523: len, buflen,
! 524: hdr->cmd_letter, hdr->cmd_fn);
! 525: #endif
! 526: rln_rx_pdata(sc, buf, len, &pd);
! 527: } else { /* Overflow */
! 528: #ifdef DIAGNOSTIC
! 529: printf("%s: overflow %d>%d, cmd %c%d\n",
! 530: sc->sc_dev.dv_xname,
! 531: len, buflen,
! 532: hdr->cmd_letter, hdr->cmd_fn);
! 533: #endif
! 534: rln_rx_pdata(sc, buf, buflen, &pd);
! 535: /* Drain the rest somewhere. */
! 536: rln_rx_pdata(sc, data, len - buflen, &pd);
! 537: }
! 538: }
! 539: rln_rx_end(sc);
! 540:
! 541: /* This message can now be handled by the waiter. */
! 542: rln_mbox_unlock(sc, hdr->cmd_seq, len + sizeof *hdr);
! 543: return;
! 544: }
! 545:
! 546: /* Otherwise, handle the message, right here, right now. */
! 547:
! 548: /* Check if we can cope with the size of this message. */
! 549: if (len > sizeof data) {
! 550: printf("%s: msg too big (%d)\n", sc->sc_dev.dv_xname, len);
! 551: ifp->if_ierrors++;
! 552: rln_rx_end(sc);
! 553: /* rln_need_reset(sc); */
! 554: return;
! 555: }
! 556:
! 557: /* Check for error results. */
! 558: if (hdr->cmd_error & 0x80) {
! 559: printf("%s: command error 0x%02x command %c%d len=%d\n",
! 560: sc->sc_dev.dv_xname,
! 561: hdr->cmd_error & ~0x80,
! 562: hdr->cmd_letter, hdr->cmd_fn,
! 563: len);
! 564: ifp->if_ierrors++;
! 565: rln_rx_end(sc);
! 566: rln_need_reset(sc);
! 567: return;
! 568: }
! 569:
! 570: /*
! 571: * "b1": Receiving a packet is a special case.
! 572: * We wish to read the data with pio straight into an
! 573: * mbuf to avoid a memory-memory copy.
! 574: */
! 575: if (hdr->cmd_letter == 'b' && hdr->cmd_fn == 1) {
! 576: m = rlnget(sc, hdr, len);
! 577: rln_rx_end(sc);
! 578: if (m == NULL)
! 579: return;
! 580: ifp->if_ipackets++;
! 581: #ifdef DIAGNOSTIC
! 582: if (bcmp(mtod(m, u_int8_t *), "prox", 4) == 0) {
! 583: printf("%s: proxim special packet received\n",
! 584: sc->sc_dev.dv_xname);
! 585: }
! 586: #endif
! 587:
! 588: #if NBPFILTER > 0
! 589: if (ifp->if_bpf)
! 590: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 591: #endif
! 592:
! 593: ether_input_mbuf(ifp, m);
! 594: return;
! 595: }
! 596:
! 597:
! 598: /* Otherwise we read the packet into a buffer on the stack. */
! 599: bcopy(hdr, data, sizeof *hdr);
! 600: if (len > sizeof *hdr)
! 601: rln_rx_pdata(sc, data + sizeof *hdr, len - sizeof *hdr, &pd);
! 602: rln_rx_end(sc);
! 603:
! 604: #ifdef RLNDUMP
! 605: printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname,
! 606: hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq);
! 607: RLNDUMPHEX(hdr, sizeof hdr);
! 608: printf(":");
! 609: RLNDUMPHEX(data + sizeof hdr, len - sizeof hdr);
! 610: printf("\n");
! 611: #endif
! 612:
! 613: switch (RLN_MM_CMD(hdr->cmd_letter, hdr->cmd_fn)) {
! 614: case RLN_MM_CMD('b', 0): /* b0: Transmit done. */
! 615: #ifdef DIAGNOSTIC
! 616: if (len != 7)
! 617: printf("%s: 'b0' len %d != 7\n",
! 618: sc->sc_dev.dv_xname, len);
! 619: #endif
! 620: ifp->if_flags &= ~IFF_OACTIVE;
! 621: ifp->if_opackets++;
! 622: s = splnet();
! 623: rlnstart(ifp);
! 624: splx(s);
! 625: break;
! 626:
! 627: case RLN_MM_CMD('a', 20): /* a20: Card fault. */
! 628: printf("%s: hardware fault\n", sc->sc_dev.dv_xname);
! 629: break;
! 630:
! 631: case RLN_MM_CMD('a', 4): /* a4: Sync'd. */
! 632: if (bcmp(syncp->enaddr, sc->sc_arpcom.ac_enaddr,
! 633: ETHER_ADDR_LEN) == 0) {
! 634: /* Sync'd to own enaddr. */
! 635: /*
! 636: * From http://www.proxim.com/support/faq/7400.shtml
! 637: * 3. RLNSETUP reports that I'm synchronized to my own MAC address. What
! 638: * does that mean?
! 639: * You are the acting Master for this network. Either you are
! 640: * configured as the Master or as an Alternate Master. If you are an
! 641: * Alternate Master, you may be out of range or on a different Domain
! 642: * and Security ID from the true Master.
! 643: */
! 644:
! 645: printf("%s: nothing to sync to; now master ",
! 646: sc->sc_dev.dv_xname);
! 647: }
! 648: else
! 649: printf("%s: synchronised to ", sc->sc_dev.dv_xname);
! 650: printf("%.11s (%s) channel %d/%d\n",
! 651: syncp->mastername,
! 652: ether_sprintf(syncp->enaddr),
! 653: syncp->channel,
! 654: syncp->subchannel);
! 655:
! 656: /* Record the new circumstances. */
! 657: sc->sc_param.rp_channel = syncp->channel;
! 658: sc->sc_param.rp_subchannel = syncp->subchannel;
! 659: sc->sc_state |= RLN_STATE_SYNC;
! 660:
! 661: /* Resume sending. */
! 662: s = splnet();
! 663: rlnstart(ifp);
! 664: splx(s);
! 665: break;
! 666:
! 667: case RLN_MM_CMD('a', 5): /* a4: Lost sync. */
! 668: printf("%s: lost sync\n", sc->sc_dev.dv_xname);
! 669: sc->sc_state &= ~RLN_STATE_SYNC;
! 670: break;
! 671:
! 672: case RLN_MM_CMD('a', 18): /* a18: Roaming. */
! 673: printf("%s: roaming\n", sc->sc_dev.dv_xname);
! 674: break;
! 675: default:
! 676: #ifdef DIAGNOSTIC
! 677: printf("%s: msg `%c%d' seq %d data {",
! 678: sc->sc_dev.dv_xname,
! 679: hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq);
! 680: RLNDUMPHEX(hdr, sizeof hdr);
! 681: printf(":");
! 682: RLNDUMPHEX(data, len);
! 683: printf("}\n");
! 684: #endif
! 685: break;
! 686: }
! 687:
! 688: }
! 689:
! 690: /* Extract a received network packet from the card. */
! 691: struct mbuf *
! 692: rlnget(sc, hdr, totlen)
! 693: struct rln_softc *sc;
! 694: struct rln_mm_cmd *hdr;
! 695: int totlen;
! 696: {
! 697: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 698: int len;
! 699: int pad;
! 700: struct mbuf *m, **mp, *top;
! 701: struct rln_pdata pd = RLN_PDATA_INIT;
! 702: struct {
! 703: u_int8_t rssi;
! 704: u_int8_t xxx1; /* always 00? */
! 705: u_int16_t len; /* payload length */
! 706: u_int8_t xxx2; /* always 00? */
! 707: u_int8_t xxx3; /* always c0? */
! 708: u_int8_t seq;
! 709: u_int8_t xxx4;
! 710: struct ether_addr to; /* destination station addr */
! 711: struct ether_addr from; /* sending station addr */
! 712: } hwhdr;
! 713:
! 714: dprintf(" [get]");
! 715:
! 716: #ifdef RLNDUMP
! 717: /* Decode the command header: */
! 718: printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname,
! 719: hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq);
! 720: RLNDUMPHEX(hdr, sizeof hdr);
! 721: printf(":");
! 722: #endif
! 723: totlen -= sizeof *hdr;
! 724:
! 725: #ifdef DIAGNOSTIC
! 726: if (totlen <= 0) {
! 727: printf("%s: empty packet", sc->sc_dev.dv_xname);
! 728: goto drop;
! 729: }
! 730: #endif
! 731:
! 732: /* Decode the hardware header: */
! 733: rln_rx_pdata(sc, &hwhdr, sizeof hwhdr, &pd);
! 734: totlen -= sizeof hwhdr;
! 735: #ifdef RLNDUMP
! 736: RLNDUMPHEX(&hwhdr, sizeof hwhdr);
! 737: printf("/");
! 738: #endif
! 739: /* (Most of the following code fleeced from elink3.c.) */
! 740:
! 741: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 742: if (m == NULL)
! 743: goto drop;
! 744: m->m_pkthdr.rcvif = ifp;
! 745: m->m_pkthdr.len = totlen;
! 746: /*
! 747: * Insert some leading padding in the mbuf, so that payload data is
! 748: * aligned.
! 749: */
! 750: pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
! 751: m->m_data += pad;
! 752: len = MHLEN - pad;
! 753: top = 0;
! 754: mp = ⊤
! 755:
! 756: while (totlen > 0) {
! 757: if (top) {
! 758: MGET(m, M_DONTWAIT, MT_DATA);
! 759: if (m == NULL) {
! 760: m_freem(top);
! 761: goto drop;
! 762: }
! 763: len = MLEN;
! 764: }
! 765: if (totlen >= MINCLSIZE) {
! 766: MCLGET(m, M_DONTWAIT);
! 767: if (m->m_flags & M_EXT) {
! 768: len = MCLBYTES;
! 769: if (!top) {
! 770: m->m_data += pad;
! 771: len -= pad;
! 772: }
! 773: }
! 774: }
! 775: len = min(totlen, len);
! 776: rln_rx_pdata(sc, mtod(m, u_int8_t *), len, &pd);
! 777: #ifdef RLNDUMP
! 778: RLNDUMPHEX(mtod(m, u_int8_t *), len);
! 779: if (totlen != len)
! 780: printf("|");
! 781: #endif
! 782: m->m_len = len;
! 783: totlen -= len;
! 784: *mp = m;
! 785: mp = &m->m_next;
! 786: }
! 787: #ifdef RLNDUMP
! 788: printf("\n");
! 789: #endif
! 790: return top;
! 791:
! 792: drop:
! 793: #ifdef RLNDUMP
! 794: printf(": drop\n");
! 795: #endif
! 796: ifp->if_iqdrops++;
! 797: return NULL;
! 798: }
! 799:
! 800: /* Interface control. */
! 801: int
! 802: rlnioctl(ifp, cmd, data)
! 803: struct ifnet *ifp;
! 804: u_long cmd;
! 805: caddr_t data;
! 806: {
! 807: struct rln_softc *sc = ifp->if_softc;
! 808: struct ifaddr *ifa = (struct ifaddr *)data;
! 809: int s, error;
! 810: int need_init;
! 811:
! 812: printf("%s: ioctl cmd[%c/%d] data=%x\n", sc->sc_dev.dv_xname,
! 813: IOCGROUP(cmd), IOCBASECMD(cmd), data);
! 814:
! 815: s = splnet();
! 816: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) != 0) {
! 817: splx(s);
! 818: return error;
! 819: }
! 820:
! 821: switch (cmd) {
! 822: case SIOCSIFADDR:
! 823: /* Set address. */
! 824: ifp->if_flags |= IFF_UP;
! 825:
! 826: switch (ifa->ifa_addr->sa_family) {
! 827: #ifdef INET
! 828: case AF_INET:
! 829: rlninit(sc);
! 830: arp_ifinit(&sc->sc_arpcom, ifa);
! 831: break;
! 832: #endif
! 833: default:
! 834: rlninit(sc);
! 835: break;
! 836: }
! 837: break;
! 838:
! 839: case SIOCSIFFLAGS:
! 840: need_init = 0;
! 841:
! 842: if ((ifp->if_flags & IFF_UP) == 0 &&
! 843: (ifp->if_flags & IFF_RUNNING) != 0) {
! 844: /* Was running, want down: stop. */
! 845: rlnstop(sc);
! 846: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 847: (ifp->if_flags & IFF_RUNNING) == 0) {
! 848: /* Was not running, want up: start. */
! 849: need_init = 1;
! 850: }
! 851:
! 852: if (ifp->if_flags & IFF_RUNNING) {
! 853: if ((ifp->if_flags & IFF_PROMISC) &&
! 854: (sc->sc_state & RLN_STATE_PROMISC) == 0) {
! 855: sc->sc_state |= RLN_STATE_PROMISC;
! 856: need_init = 1;
! 857: }
! 858: else if ((ifp->if_flags & IFF_PROMISC) == 0 &&
! 859: (sc->sc_state & RLN_STATE_PROMISC)) {
! 860: sc->sc_state &= ~RLN_STATE_PROMISC;
! 861: need_init = 1;
! 862: }
! 863: }
! 864:
! 865: if (need_init)
! 866: rlninit(sc);
! 867:
! 868: break;
! 869:
! 870: case SIOCADDMULTI:
! 871: case SIOCDELMULTI:
! 872: error = EOPNOTSUPP;
! 873: break;
! 874:
! 875: #if notyet
! 876: case RLNIOSPARAM:
! 877: error = rln_iosetparam(sc, (struct rln_param *)&data);
! 878: break;
! 879:
! 880: case RLNIOGPARAM:
! 881: bcopy(&sc->sc_param, (struct rln_param *)&data,
! 882: sizeof sc->sc_param);
! 883: break;
! 884: #endif
! 885:
! 886: default:
! 887: error = EINVAL;
! 888: break;
! 889: }
! 890:
! 891: splx(s);
! 892: return (error);
! 893: }
! 894:
! 895: /* Stop output from the card. */
! 896: void
! 897: rlnstop(sc)
! 898: struct rln_softc *sc;
! 899: {
! 900: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 901:
! 902: dprintf(" [stop]");
! 903: ifp->if_flags &= ~IFF_RUNNING;
! 904: rln_enable(sc, 0);
! 905: }
! 906:
! 907: /* Get MAC address from card. */
! 908: int
! 909: rln_getenaddr(sc, enaddr)
! 910: struct rln_softc *sc;
! 911: u_int8_t * enaddr;
! 912: {
! 913: struct rln_mm_cmd query = RLN_MM_GETENADDR;
! 914: struct rln_mm_gotenaddr response = { RLN_MM_GETENADDR };
! 915:
! 916: if (rln_msg_txrx(sc, &query, sizeof query,
! 917: &response, sizeof response))
! 918: return (-1);
! 919: bcopy(response.enaddr, enaddr, sizeof response.enaddr);
! 920: return (0);
! 921: };
! 922:
! 923: /* Get firmware version string from card. */
! 924: int
! 925: rln_getpromvers(sc, ver, verlen)
! 926: struct rln_softc *sc;
! 927: char *ver;
! 928: int verlen;
! 929: {
! 930: struct rln_mm_cmd query = RLN_MM_GETPROMVERSION;
! 931: struct rln_mm_gotpromversion response = { RLN_MM_GOTPROMVERSION };
! 932: int i;
! 933:
! 934: #ifdef DIAGNOSTIC
! 935: if (verlen != sizeof response.version)
! 936: panic("rln_getpromvers");
! 937: #endif
! 938:
! 939: if (rln_msg_txrx(sc, &query, sizeof query,
! 940: &response, sizeof response))
! 941: return (-1);
! 942: bcopy(response.version, ver, verlen);
! 943: /* Nul trailing spaces. */
! 944: for (i = verlen - 1; i >= 0 && ver[i] <= ' '; i--)
! 945: ver[i] = '\0';
! 946: return (0);
! 947: };
! 948:
! 949: /* Set default operational parameters on card. */
! 950: int
! 951: rln_sendinit(sc)
! 952: struct rln_softc *sc;
! 953: {
! 954: struct rln_mm_init init = { RLN_MM_INIT };
! 955: struct rln_mm_initted iresponse;
! 956: #if 0
! 957: struct rln_mm_setmagic magic = { RLN_MM_SETMAGIC };
! 958: struct rln_mm_disablehopping hop = { RLN_MM_DISABLEHOPPING };
! 959: struct rln_mm_cmd response;
! 960: #endif
! 961:
! 962: bzero((char *)&init + sizeof init.mm_cmd,
! 963: sizeof init - sizeof init.mm_cmd);
! 964:
! 965: dprintf(" [setting parameters]");
! 966: init.opmode = (sc->sc_state & RLN_STATE_PROMISC ?
! 967: RLN_MM_INIT_OPMODE_PROMISC : RLN_MM_INIT_OPMODE_NORMAL);
! 968: init.stationtype = sc->sc_param.rp_station_type;
! 969:
! 970: /* Spread-spectrum frequency hopping. */
! 971: init.hop_period = 1;
! 972: init.bfreq = 2;
! 973: init.sfreq = 7;
! 974:
! 975: /* Choose channel. */
! 976: init.channel = sc->sc_param.rp_channel;
! 977: init.subchannel = sc->sc_param.rp_subchannel;
! 978: init.domain = sc->sc_param.rp_domain;
! 979:
! 980: /* Name of this station when acting as master. */
! 981: bcopy(sc->sc_param.rp_master, init.mastername, sizeof init.mastername);
! 982:
! 983: /* Security params. */
! 984: init.sec1 = (sc->sc_param.rp_security & 0x0000ff) >> 0;
! 985: init.sec2 = (sc->sc_param.rp_security & 0x00ff00) >> 8;
! 986: init.sec3 = (sc->sc_param.rp_security & 0xff0000) >> 16;
! 987:
! 988: init.sync_to = 1;
! 989: bzero(init.syncname, sizeof init.syncname);
! 990:
! 991: if (rln_msg_txrx(sc, &init, sizeof init,
! 992: &iresponse, sizeof iresponse))
! 993: return (-1);
! 994: #if 0
! 995: dprintf(" [setting magic]");
! 996: magic.fairness_slot = 3; /* lite: 1, norm: 3, off: -1 */
! 997: magic.deferral_slot = 3; /* lite: 0, norm: 3, off: -1 */
! 998: magic.regular_mac_retry = 7;
! 999: magic.frag_mac_retry = 10;
! 1000: magic.regular_mac_qfsk = 2;
! 1001: magic.frag_mac_qfsk = 5;
! 1002: magic.xxx1 = 0xff;
! 1003: magic.xxx2 = 0xff;
! 1004: magic.xxx3 = 0xff;
! 1005: magic.xxx4 = 0x00;
! 1006: if (rln_msg_txrx(sc, &magic, sizeof magic,
! 1007: &response, sizeof response))
! 1008: return (-1);
! 1009:
! 1010: dprintf(" [disabling freq hopping]");
! 1011: hop.hopflag = RLN_MM_DISABLEHOPPING_HOPFLAG_DISABLE;
! 1012: if (rln_msg_txrx(sc, &hop, sizeof hop,
! 1013: &response, sizeof response))
! 1014: return (-1);
! 1015:
! 1016: #endif
! 1017: return (0);
! 1018: }
! 1019:
! 1020: #if notyet
! 1021: /* Configure the way the card leaves a basestation. */
! 1022: int
! 1023: rln_roamconfig(sc)
! 1024: struct rln_softc *sc;
! 1025: {
! 1026: struct rln_mm_setroaming roam = { RLN_MM_SETROAMING };
! 1027: struct rln_mm_cmd response;
! 1028: static int retry[3] = { 6, 6, 4 };
! 1029: static int rssi[3] = { 5, 15, 5 };
! 1030:
! 1031: dprintf(" [roamconfig]");
! 1032: #ifdef DIAGNOSTIC
! 1033: if (sc->sc_param.rp_roam_config > 2)
! 1034: panic("roamconfig");
! 1035: #endif
! 1036: roam.sync_alarm = 0;
! 1037: roam.retry_thresh = retry[sc->sc_param.rp_roam_config];
! 1038: roam.rssi_threshold = rssi[sc->sc_param.rp_roam_config];
! 1039: roam.xxx1 = 0x5a;
! 1040: roam.sync_rssi_threshold = 0;
! 1041: roam.xxx2 = 0x5a;
! 1042: roam.missed_sync = 0x4;
! 1043: if (rln_msg_txrx(sc, &roam, sizeof roam,
! 1044: &response, sizeof response))
! 1045: return (-1);
! 1046:
! 1047: return (0);
! 1048: }
! 1049:
! 1050: /* Enable roaming. */
! 1051: int
! 1052: rln_roam(sc)
! 1053: struct rln_softc *sc;
! 1054: {
! 1055: struct rln_mm_cmd roam = RLN_MM_ROAM;
! 1056: struct rln_mm_cmd response;
! 1057:
! 1058: return (rln_msg_txrx(sc, &roam, sizeof roam,
! 1059: &response, sizeof response));
! 1060: }
! 1061:
! 1062: /* Enable multicast capability. */
! 1063: int
! 1064: rln_multicast(sc, enable)
! 1065: struct rln_softc *sc;
! 1066: int enable;
! 1067: {
! 1068: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1069: struct rln_mm_multicast mcast = { RLN_MM_MULTICAST };
! 1070: struct rln_mm_cmd response;
! 1071: int ret;
! 1072:
! 1073: mcast.enable = enable;
! 1074:
! 1075: ret = rln_msg_txrx(sc, &mcast, sizeof mcast,
! 1076: &response, sizeof response);
! 1077: if (ret == 0) {
! 1078: if (enable)
! 1079: ifp->if_flags |= IFF_MULTICAST;
! 1080: else
! 1081: ifp->if_flags &= ~IFF_MULTICAST;
! 1082: }
! 1083: return (ret);
! 1084: }
! 1085:
! 1086: /* Search for and sync with any master. */
! 1087: int
! 1088: rln_searchsync(sc)
! 1089: struct rln_softc *sc;
! 1090: {
! 1091: struct rln_mm_search search = { RLN_MM_SEARCH };
! 1092: struct rln_mm_searching response;
! 1093:
! 1094: bzero(search.xxx1, sizeof search.xxx1);
! 1095: search.domain = sc->sc_param.rp_domain;
! 1096: search.roaming = 1;
! 1097: search.xxx3 = 0;
! 1098: search.xxx4 = 1;
! 1099: search.xxx5 = 0;
! 1100: bzero(search.xxx6, sizeof search.xxx6);
! 1101:
! 1102: return (rln_msg_txrx(sc, &search, sizeof search,
! 1103: &response, sizeof response));
! 1104: }
! 1105:
! 1106: /* Set values from an external parameter block. */
! 1107: int
! 1108: rln_iosetparam(sc, param)
! 1109: struct rln_softc *sc;
! 1110: struct rln_param *param;
! 1111: {
! 1112: int error = 0;
! 1113:
! 1114: if (param->rp_roam_config > 2)
! 1115: error = EINVAL;
! 1116: if (param->rp_security > 0x00ffffff)
! 1117: error = EINVAL;
! 1118: if (param->rp_station_type > 2)
! 1119: error = EINVAL;
! 1120: if (param->rp_channel > 15)
! 1121: error = EINVAL;
! 1122: if (param->rp_subchannel > 15)
! 1123: error = EINVAL;
! 1124: if (error == 0) {
! 1125: /* Apply immediately. */
! 1126: bcopy(param, &sc->sc_param, sizeof *param);
! 1127: if (rln_sendinit(sc))
! 1128: error = EIO;
! 1129: }
! 1130: return (error);
! 1131: }
! 1132:
! 1133: /* Protect the eeprom from storing a security ID(?) */
! 1134: int
! 1135: rln_lockprom(sc)
! 1136: struct rln_softc *sc;
! 1137: {
! 1138: struct rln_mm_cmd lock = RLN_MM_EEPROM_PROTECT;
! 1139: struct rln_mm_cmd response;
! 1140:
! 1141: /* XXX Always yields an error? */
! 1142: return (rln_msg_txrx(sc, &lock, sizeof lock,
! 1143: &response, sizeof response));
! 1144: }
! 1145:
! 1146: /* Set the h/w Inactivity Time Out timer on the card. */
! 1147: int
! 1148: rln_ito(sc)
! 1149: struct rln_softc * sc;
! 1150: {
! 1151: struct rln_mm_setito ito = { RLN_MM_MULTICAST };
! 1152: struct rln_mm_cmd response;
! 1153:
! 1154: ito.xxx = 3;
! 1155: ito.timeout = LLDInactivityTimeOut /* enabler, 0 or 1 */;
! 1156: ito.bd_wakeup = LLDBDWakeup /* 0 */;
! 1157: ito.pm_sync = LLDPMSync /* 0 */;
! 1158: ito.sniff_time = ito.timeout ? LLDSniffTime /* 0 */ : 0;
! 1159:
! 1160: if (rln_msg_txrx(sc, &ito, sizeof ito,
! 1161: &response, sizeof response))
! 1162: return (-1);
! 1163: }
! 1164:
! 1165: /* Put the card into standby mode. */
! 1166: int
! 1167: rln_standby(sc)
! 1168: struct rln_softc * sc;
! 1169: {
! 1170: struct rln_mm_standby standby = { RLN_MM_STANDBY };
! 1171:
! 1172: standby.xxx = 0;
! 1173: if (rln_msg_txrx(sc, &ito, sizeof ito, NULL, 0))
! 1174: return (-1);
! 1175: }
! 1176:
! 1177: void
! 1178: rln_crypt(userkey, cardkey)
! 1179: char *userkey; /* User's string (max 20 chars). */
! 1180: u_int8_t *cardkey; /* 20 bits (3 bytes) */
! 1181: {
! 1182: /*
! 1183: * From <http://www.proxim.com/learn/whiteppr/rl2security.shtml>
! 1184: * "RangeLAN2 Security Features":
! 1185: *
! 1186: * The Security ID is a unique, 20 character alphanumeric
! 1187: * string defined and configured by the user. It must be
! 1188: * identically configured in every radio intended to
! 1189: * communicate with others in the same network. Once
! 1190: * configured, the Security ID is reduced to 20 bits by a
! 1191: * proprietary algorithm confidential to Proxim. It is
! 1192: * merged with the radio MAC address (a 12 character field
! 1193: * unique to every radio), scrambled and stored using another
! 1194: * proprietary, confidential algorithm.
! 1195: */
! 1196: int32_t key;
! 1197: int8_t ret;
! 1198: int i;
! 1199: int len;
! 1200: int32_t multiplicand = 0x80000181;
! 1201: int64_t res;
! 1202:
! 1203: /*
! 1204: * This algorithm is `compatible' with Proxim's first
! 1205: * `proprietary confidential algorithm': i.e., it appears
! 1206: * to be functionally identical.
! 1207: */
! 1208: len = strlen(s);
! 1209: key = 0x030201;
! 1210: for (i = 0; i < len; i++) {
! 1211:
! 1212: key *= userkey[i];
! 1213: res = (int64_t)multiplicand * key;
! 1214: key = key - 0xfffffd *
! 1215: (((key + (int32_t)(res >> 32)) >> 23) - (key >> 31));
! 1216: }
! 1217:
! 1218: cardkey[0] = (key >> 16) & 0xff;
! 1219: cardkey[1] = (key >> 8) & 0xff;
! 1220: cardkey[2] = key & 0xff;
! 1221:
! 1222: cardkey[0] |= 0x03; /* Restrict key space by 2 bits. */
! 1223: }
! 1224: #endif
CVSweb