1: /*
   2:  * Copyright (c) 1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  *
   6:  *	@(#)if_vv.c	2.1 (2.11BSD) 1996/11/27
   7:  */
   8: 
   9: #include "vv.h"
  10: #if NVV > 0
  11: 
  12: /*
  13:  * Proteon proNET-10 and proNET-80 token ring driver.
  14:  * The name of this device driver derives from the old MIT
  15:  * name of V2LNI for the proNET hardware, would would abbreviate
  16:  * to "v2", but this won't work right. Thus the name is "vv".
  17:  *
  18:  * This driver is compatible with the proNET 10 meagbit and
  19:  * 80 megabit token ring interfaces (models p1000 and p1080).
  20:  * A unit may be marked as 80 megabit using "flags 1" in the
  21:  * config file.
  22:  *
  23:  * TRAILERS: This driver has a new implementation of trailers that
  24:  * is at least a tolerable neighbor on the ring. The offset is not
  25:  * stored in the protocol type, but instead only in the vh_info
  26:  * field. Also, the vh_info field, and the two shorts before the
  27:  * trailing header, are in network byte order, not VAX byte order.
  28:  *
  29:  * Of course, nothing but BSD UNIX supports trailers on ProNET.
  30:  * If you need interoperability with anything else, turn off
  31:  * trailers using the -trailers option to ifconfig!
  32:  *
  33:  * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001)
  34:  * have a serial number >= 040, which is about March, 1982. Older
  35:  * HSBUs do not carry across 64kbyte boundaries. They can be supported
  36:  * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization
  37:  * in vvattach().
  38:  *
  39:  * The old warning about use without Wire Centers applies only to CTL
  40:  * (p1002) cards with serial <= 057, which have not received ECO 176-743,
  41:  * which was implemented in March, 1982. Most such CTLs have received
  42:  * this ECO.
  43:  */
  44: 
  45: #include "param.h"
  46: #include "../machine/seg.h"
  47: #include "systm.h"
  48: #include "mbuf.h"
  49: #include "buf.h"
  50: #include "domain.h"
  51: #include "protosw.h"
  52: #include "socket.h"
  53: #include "ioctl.h"
  54: #include "pdpif/if_vv.h"
  55: #include "pdpif/if_uba.h"
  56: #include "errno.h"
  57: #include "pdpuba/ubavar.h"
  58: #include "net/if.h"
  59: #include "net/netisr.h"
  60: #include "net/route.h"
  61: 
  62: #ifdef  INET
  63: #include "netinet/in.h"
  64: #include "netinet/in_systm.h"
  65: #include "netinet/in_var.h"
  66: #include "netinet/ip.h"
  67: #include "netinet/ip_var.h"
  68: #endif
  69: 
  70: /*
  71:  *    maximum transmission unit definition --
  72:  *        you can set VVMTU at anything from 576 to 2024.
  73:  *        1536 is a popular "large" value, because it is a multiple
  74:  *	  of 512, which the trailer scheme likes.
  75:  *        The absolute maximum size is 2024, which is enforced.
  76:  */
  77: 
  78: #define VVMTU (1536)
  79: 
  80: #define VVMRU (VVMTU + 16)
  81: #define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
  82: #if VVMTU>2024
  83: #undef VVMTU
  84: #undef VVMRU
  85: #undef VVBUFSIZE
  86: #define VVBUFSIZE (2046)
  87: #define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
  88: #define VVMTU (VVMRU - 16)
  89: #endif
  90: 
  91: /*
  92:  *   debugging and tracing stuff
  93:  */
  94: int vv_tracehdr = 0;    /* 1 => trace headers (slowly!!) */
  95: 
  96: #define vvtracehdr  if (vv_tracehdr) vvprt_hdr
  97: #define vvprintf    if (vs->vs_if.if_flags & IFF_DEBUG) printf
  98: 
  99: /*
 100:  * externals, types, etc.
 101:  */
 102: int vvprobe(), vvattach(), vvreset(), vvinit();
 103: int vvidentify(), vvstart(), vvxint(), vvwatchdog();
 104: int vvrint(), vvoutput(), vvioctl();
 105: struct  uba_device *vvinfo[NVV];
 106: u_short vvstd[] = { 0 };
 107: struct  uba_driver vvdriver =
 108:     { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
 109: #define VVUNIT(x)   minor(x)
 110: 
 111: #define LOOPBACK        /* use loopback for packets meant for us */
 112: #ifdef  LOOPBACK
 113: extern struct ifnet loif;
 114: #endif
 115: 
 116: /*
 117:  * Software status of each interface.
 118:  *
 119:  * Each interface is referenced by a network interface structure,
 120:  * vs_if, which the routing code uses to locate the interface.
 121:  * This structure contains the output queue for the interface, its address, ...
 122:  * We also have, for each interface, a UBA interface structure, which
 123:  * contains information about the UNIBUS resources held by the interface:
 124:  * map registers, buffered data paths, etc.  Information is cached in this
 125:  * structure for use by the if_uba.c routines in running the interface
 126:  * efficiently.
 127:  */
 128: struct  vv_softc {
 129:     struct  ifnet vs_if;        /* network-visible interface */
 130:     struct  ifuba vs_ifuba;     /* UNIBUS resources */
 131:     u_short vs_host;        /* this interface address */
 132:     short   vs_oactive;     /* is output active */
 133:     short   vs_is80;        /* is 80 megabit version */
 134:     short   vs_olen;        /* length of last output */
 135:     u_short vs_lastx;       /* address of last packet sent */
 136:     u_short vs_lastr;       /* address of last packet received */
 137:     short   vs_tries;       /* transmit current retry count */
 138:     short   vs_init;        /* number of ring inits */
 139:     short   vs_refused;     /* number of packets refused */
 140:     short   vs_timeouts;        /* number of transmit timeouts */
 141:     short   vs_otimeout;        /* number of output timeouts */
 142:     short   vs_ibadf;       /* number of input bad formats */
 143:     short   vs_parity;      /* number of parity errors on 10 meg, */
 144:                     /* link data errors on 80 meg */
 145: } vv_softc[NVV];
 146: 
 147: #define NOHOST  0xffff          /* illegal host number */
 148: 
 149: vvprobe(reg)
 150:     caddr_t reg;
 151: {
 152: #ifdef  notdef
 153:     register int br, cvec;
 154:     register struct vvreg *addr;
 155: 
 156: #ifdef lint
 157:     br = 0; cvec = br; br = cvec;
 158: #endif
 159:     addr = (struct vvreg *)reg;
 160:     /* reset interface, enable, and wait till dust settles */
 161:     addr->vvicsr = VV_RST;
 162:     addr->vvocsr = VV_RST;
 163:     DELAY(100000L);
 164: 
 165:     /* generate interrupt by doing 1 word DMA from 0 in uba space!! */
 166:     addr->vvoba = 0;        /* low 16 bits */
 167:     addr->vvoea = 0;        /* extended bits */
 168:     addr->vvowc = -1;       /* for 1 word */
 169:     addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */
 170:     DELAY(100000L);
 171:     addr->vvocsr = VV_RST;      /* clear out the CSR */
 172:     if (cvec && cvec != 0x200)
 173:         cvec -= 4;      /* backup so vector => receive */
 174: #endif
 175:     return(1);
 176: }
 177: 
 178: /*
 179:  * Interface exists: make available by filling in network interface
 180:  * record.  System will initialize the interface when it is ready
 181:  * to accept packets.
 182:  */
 183: vvattach(ui)
 184:     struct uba_device *ui;
 185: {
 186:     register struct vv_softc *vs;
 187: 
 188:     vs = &vv_softc[ui->ui_unit];
 189:     vs->vs_if.if_unit = ui->ui_unit;
 190:     vs->vs_if.if_name = "vv";
 191:     vs->vs_if.if_mtu = VVMTU;
 192:     vs->vs_if.if_flags = IFF_BROADCAST;
 193:     vs->vs_if.if_init = vvinit;
 194:     vs->vs_if.if_ioctl = vvioctl;
 195:     vs->vs_if.if_output = vvoutput;
 196:     vs->vs_if.if_reset = vvreset;
 197:     vs->vs_if.if_timer = 0;
 198:     vs->vs_if.if_watchdog = vvwatchdog;
 199:     vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP;
 200: 
 201:     /* use flag to determine if this is proNET-80 */
 202:     vs->vs_is80 = (short)(ui->ui_flags & 01);
 203: 
 204: #if defined(VAX750)
 205:     /* don't chew up 750 bdp's */
 206:     if (cpu == VAX_750 && ui->ui_unit > 0)
 207:         vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
 208: #endif
 209:     if_attach(&vs->vs_if);
 210: }
 211: 
 212: /*
 213:  * Reset of interface after UNIBUS reset.
 214:  * If interface is on specified uba, reset its state.
 215:  */
 216: vvreset(unit, uban)
 217:     int unit, uban;
 218: {
 219:     register struct uba_device *ui;
 220: 
 221:     if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
 222:         ui->ui_ubanum != uban)
 223:         return;
 224:     printf(" vv%d", unit);
 225:     vvinit(unit);
 226: }
 227: 
 228: /*
 229:  * Initialization of interface; clear recorded pending
 230:  * operations, and reinitialize UNIBUS usage.
 231:  */
 232: vvinit(unit)
 233:     int unit;
 234: {
 235:     register struct vv_softc *vs;
 236:     register struct uba_device *ui;
 237:     register struct vvreg *addr;
 238:     register int s;
 239:     ubadr_t ubainfo;
 240: 
 241:     vs = &vv_softc[unit];
 242:     ui = vvinfo[unit];
 243: 
 244:     if (vs->vs_if.if_addrlist == (struct ifaddr *)0)
 245:         return;
 246: 
 247:     addr = (struct vvreg *)ui->ui_addr;
 248:     if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
 249:         sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
 250:         printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
 251:         vs->vs_if.if_flags &= ~IFF_UP;
 252:         return;
 253:     }
 254: 
 255:     /*
 256: 	 * Now that the uba is set up, figure out our address and
 257: 	 * update complete our host address.
 258: 	 */
 259:     if ((vs->vs_host = vvidentify(unit)) == NOHOST) {
 260:         vs->vs_if.if_flags &= ~IFF_UP;
 261:         return;
 262:     }
 263:     printf("vv%d: host %u\n", unit, vs->vs_host);
 264: 
 265:     /*
 266: 	 * Reset the interface, and stay in the ring
 267: 	 */
 268:     addr->vvocsr = VV_RST;          /* take over output */
 269:     addr->vvocsr = VV_CPB;          /* clear packet buffer */
 270:     addr->vvicsr = VV_RST | VV_HEN;     /* take over input, */
 271:                         /* keep relay closed */
 272:     DELAY(500000L);             /* let contacts settle */
 273: 
 274:     vs->vs_init = 0;            /* clear counters, etc. */
 275:     vs->vs_refused = 0;
 276:     vs->vs_timeouts = 0;
 277:     vs->vs_otimeout = 0;
 278:     vs->vs_ibadf = 0;
 279:     vs->vs_parity = 0;
 280:     vs->vs_lastx = 256;         /* an invalid address */
 281:     vs->vs_lastr = 256;         /* an invalid address */
 282: 
 283:     /*
 284: 	 * Hang a receive and start any
 285: 	 * pending writes by faking a transmit complete.
 286: 	 */
 287:     s = splimp();
 288:     ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
 289:     addr->vviba = (u_short)ubainfo;
 290:     addr->vviea = (u_short)(ubainfo >> 16);
 291:     addr->vviwc = -(VVBUFSIZE) >> 1;
 292:     addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
 293:     vs->vs_oactive = 1;
 294:     vs->vs_if.if_flags |= IFF_RUNNING;
 295:     vvxint(unit);
 296:     splx(s);
 297: }
 298: 
 299: /*
 300:  * Return our host address.
 301:  */
 302: 
 303: vvidentify(unit)
 304:     int unit;
 305: {
 306:     register struct vv_softc *vs;
 307:     register struct uba_device *ui;
 308:     register struct vvreg *addr;
 309:     register struct mbuf *m;
 310:     register struct vv_header *v;
 311:     register int attempts, waitcount;
 312:     ubadr_t ubainfo;
 313:     segm    seg5;
 314:     u_short host;
 315:     u_char  type;
 316: 
 317:     /*
 318: 	 * Build a multicast message to identify our address
 319: 	 */
 320:     vs = &vv_softc[unit];
 321:     ui = vvinfo[unit];
 322:     addr = (struct vvreg *)ui->ui_addr;
 323:     attempts = 0;       /* total attempts, including bad msg type */
 324:     m = m_get(M_DONTWAIT, MT_HEADER);
 325:     if (m == NULL) {
 326:         printf("vv%d: can't initialize, m_get() failed\n", unit);
 327:         return (NOHOST);
 328:     }
 329:     m->m_next = 0;
 330:     m->m_off = MMINOFF;
 331:     m->m_len = sizeof(struct vv_header);
 332:     v = mtod(m, struct vv_header *);
 333:     v->vh_dhost = VV_BROADCAST; /* multicast destination address */
 334:     v->vh_shost = 0;        /* will be overwritten with ours */
 335:     v->vh_version = RING_VERSION;
 336:     v->vh_type = RING_WHOAMI;
 337:     v->vh_info = 0;
 338:     /* map xmit message into uba */
 339:     vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
 340:     /*
 341: 	 * Reset interface, establish Digital Loopback Mode, and
 342: 	 * send the multicast (to myself) with Input Copy enabled.
 343: 	 */
 344: retry:
 345:     ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
 346:     addr->vvicsr = VV_RST;
 347:     addr->vviba = (u_short) ubainfo;
 348:     addr->vviea = (u_short) (ubainfo >> 16);
 349:     addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
 350:     addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
 351: 
 352:     /* let flag timers fire so ring will initialize */
 353:     DELAY(2000000L);        /* about 2 SECONDS on a 780!! */
 354: 
 355:     addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
 356:     ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
 357:     addr->vvoba = (u_short) ubainfo;
 358:     addr->vvoea = (u_short) (ubainfo >> 16);
 359:     addr->vvowc = -((vs->vs_olen + 1) >> 1);
 360:     addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
 361:     /*
 362: 	 * Wait for receive side to finish.
 363: 	 * Extract source address (which will be our own),
 364: 	 * and post to interface structure.
 365: 	 */
 366:     DELAY(10000L);
 367:     for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
 368:         if (waitcount < 10) {
 369:             DELAY(1000L);
 370:             continue;
 371:         }
 372:         if (attempts++ < VVIDENTRETRY)
 373:             goto retry;
 374:         break;
 375:     }
 376:     /* deallocate mbuf used for send packet */
 377:     if (vs->vs_ifuba.ifu_xtofree) {
 378:         m_freem(vs->vs_ifuba.ifu_xtofree);
 379:         vs->vs_ifuba.ifu_xtofree = 0;
 380:     }
 381:     if (attempts >= VVIDENTRETRY) {
 382:         printf("vv%d: can't initialize after %d tries, icsr = %b\n",
 383:             unit, VVIDENTRETRY, 0xffff&(addr->vvicsr), VV_IBITS);
 384:         return (NOHOST);
 385:     }
 386:     m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0, &vs->vs_if);
 387:     if (m != NULL)
 388:         m_freem(m);
 389:     /*
 390: 	 * Check message type before we believe the source host address
 391: 	 */
 392:     saveseg5(seg5);
 393:     mapseg5(vs->vs_ifuba.ifu_r.ifrw_click, 077406);
 394:     v = (struct vv_header *) SEG5;
 395:     type = v->vh_type;
 396:     host = (u_short)v->vh_shost;
 397:     restorseg5(seg5);
 398:     if (type != (u_char)RING_WHOAMI)
 399:         goto retry;
 400:     return(host);
 401: }
 402: 
 403: /*
 404:  * Start or restart output on interface.
 405:  * If interface is active, this is a retransmit, so just
 406:  * restuff registers and go.
 407:  * If interface is not already active, get another datagram
 408:  * to send off of the interface queue, and map it to the interface
 409:  * before starting the output.
 410:  */
 411: vvstart(dev)
 412:     dev_t dev;
 413: {
 414:     register struct uba_device *ui;
 415:     register struct vv_softc *vs;
 416:     register struct vvreg *addr;
 417:     register struct mbuf *m;
 418:     register int unit, dest, s;
 419:     ubadr_t ubainfo;
 420:     segm save5;
 421: 
 422:     unit = VVUNIT(dev);
 423:     ui = vvinfo[unit];
 424:     vs = &vv_softc[unit];
 425:     if (vs->vs_oactive)
 426:         goto restart;
 427:     /*
 428: 	 * Not already active: dequeue another request
 429: 	 * and map it to the UNIBUS.  If no more requests,
 430: 	 * just return.
 431: 	 */
 432:     s = splimp();
 433:     IF_DEQUEUE(&vs->vs_if.if_snd, m);
 434:     splx(s);
 435:     if (m == NULL) {
 436:         vs->vs_oactive = 0;
 437:         return;
 438:     }
 439:     dest = mtod(m, struct vv_header *)->vh_dhost;
 440:     vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
 441:     vs->vs_lastx = dest;
 442: restart:
 443:     /*
 444: 	 * Have request mapped to UNIBUS for transmission.
 445: 	 * Purge any stale data from this BDP, and start the output.
 446: 	 *
 447: 	 * Make sure this packet will fit in the interface.
 448: 	 */
 449:     if (vs->vs_olen > VVBUFSIZE) {
 450:         printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
 451:         panic("vvdriver vs_olen botch");
 452:     }
 453: 
 454:     vs->vs_if.if_timer = VVTIMEOUT;
 455:     vs->vs_oactive = 1;
 456: 
 457:     /* ship it */
 458:     addr = (struct vvreg *)ui->ui_addr;
 459:     ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
 460:     addr->vvoba = (u_short) ubainfo;
 461:     addr->vvoea = (u_short) (ubainfo >> 16);
 462:     addr->vvowc = -((vs->vs_olen + 1) >> 1);
 463:     addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */
 464:     if (addr->vvocsr & VV_NOK)
 465:         vs->vs_init++;          /* count ring inits */
 466:     addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
 467: }
 468: 
 469: /*
 470:  * proNET transmit interrupt
 471:  * Start another output if more data to send.
 472:  */
 473: vvxint(unit)
 474:     int unit;
 475: {
 476:     register struct uba_device *ui;
 477:     register struct vv_softc *vs;
 478:     register struct vvreg *addr;
 479:     register int oc;
 480: 
 481:     ui = vvinfo[unit];
 482:     vs = &vv_softc[unit];
 483:     vs->vs_if.if_timer = 0;
 484:     addr = (struct vvreg *)ui->ui_addr;
 485:     oc = 0xffff & (addr->vvocsr);
 486:     if (vs->vs_oactive == 0) {
 487:         vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit,
 488:             oc, VV_OBITS);
 489:         return;
 490:     }
 491: 
 492:     /*
 493: 	 * we retransmit on soft error
 494: 	 * TODO: sort retransmits to end of queue if possible!
 495: 	 */
 496:     if (oc & (VV_OPT | VV_RFS)) {
 497:         if (vs->vs_tries++ < VVRETRY) {
 498:             if (oc & VV_OPT)
 499:                 vs->vs_otimeout++;
 500:             if (oc & VV_RFS) {
 501:                 vs->vs_if.if_collisions++;
 502:                 vs->vs_refused++;
 503:             }
 504:             vvstart(unit);      /* restart this message */
 505:             return;
 506:         }
 507:     }
 508:     vs->vs_if.if_opackets++;
 509:     vs->vs_oactive = 0;
 510:     vs->vs_tries = 0;
 511: 
 512:     if (oc & VVXERR) {
 513:         vs->vs_if.if_oerrors++;
 514:         vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
 515:             VV_OBITS);
 516:     }
 517:     if (vs->vs_ifuba.ifu_xtofree) {
 518:         m_freem(vs->vs_ifuba.ifu_xtofree);
 519:         vs->vs_ifuba.ifu_xtofree = 0;
 520:     }
 521:     vvstart(unit);
 522: }
 523: 
 524: /*
 525:  * Transmit watchdog timer routine.
 526:  * This routine gets called when we lose a transmit interrupt.
 527:  * The best we can do is try to restart output.
 528:  */
 529: vvwatchdog(unit)
 530:     int unit;
 531: {
 532:     register struct vv_softc *vs;
 533:     register int s;
 534: 
 535:     vs = &vv_softc[unit];
 536:     vvprintf("vv%d: lost a transmit interrupt.\n", unit);
 537:     vs->vs_timeouts++;
 538:     s = splimp();
 539:     vvstart(unit);
 540:     splx(s);
 541: }
 542: 
 543: /*
 544:  * proNET interface receiver interrupt.
 545:  * If input error just drop packet.
 546:  * Otherwise purge input buffered data path and examine
 547:  * packet to determine type.  If can't determine length
 548:  * from type, then have to drop packet.  Otherwise decapsulate
 549:  * packet based on type and pass to type specific higher-level
 550:  * input routine.
 551:  */
 552: vvrint(unit)
 553:     int unit;
 554: {
 555:     register struct vv_softc *vs;
 556:     register struct vvreg *addr;
 557:     register struct vv_header *vv;
 558:     register struct ifqueue *inq;
 559:     register struct mbuf *m;
 560:     int len, off, s;
 561:     ubadr_t ubainfo;
 562:     segm save5;
 563:     short resid;
 564:     u_short type, shost;
 565: 
 566:     saveseg5(save5);
 567:     vs = &vv_softc[unit];
 568:     vs->vs_if.if_ipackets++;
 569:     addr = (struct vvreg *)vvinfo[unit]->ui_addr;
 570:     if (addr->vvicsr & VVRERR) {
 571:         vvprintf("vv%d: receive error, vvicsr = %b\n", unit,
 572:             0xffff&(addr->vvicsr), VV_IBITS);
 573:         if (addr->vvicsr & VV_BDF)
 574:             vs->vs_ibadf++;
 575:         goto dropit;
 576:     }
 577: 
 578:     /*
 579: 	 * parity errors?
 580: 	 */
 581:     if (addr->vvicsr & VV_LDE) {
 582:         /* we don't have to clear it because the receive command */
 583:         /* writes 0 to parity bit */
 584:         vs->vs_parity++;
 585: 
 586:         /*
 587: 		 * only on 10 megabit proNET is VV_LDE an end-to-end parity
 588: 		 * bit. On 80 megabit, it returns to the intended use of
 589: 		 * node-to-node parity. End-to-end parity errors on 80 megabit
 590: 		 * give VV_BDF.
 591: 		 */
 592:         if (vs->vs_is80 == 0)
 593:             goto dropit;
 594:     }
 595: 
 596:     /*
 597: 	 * Get packet length from residual word count
 598: 	 *
 599: 	 * Compute header offset if trailer protocol
 600: 	 *
 601: 	 * Pull packet off interface.  Off is nonzero if packet
 602: 	 * has trailing header; if_rubaget will then force this header
 603: 	 * information to be at the front.  The vh_info field
 604: 	 * carries the offset to the trailer data in trailer
 605: 	 * format packets.
 606: 	 */
 607:     mapseg5(vs->vs_ifuba.ifu_r.ifrw_click, (btoc(VVMRU) << 8) | RW);
 608:     vv = (struct vv_header *) SEG5;
 609:     vvtracehdr("vi", vv);
 610:     resid = addr->vviwc & 01777;        /* only low 10 bits valid */
 611:     if (resid)
 612:         resid |= 0176000;       /* high 6 bits are undefined */
 613:     len = ((VVBUFSIZE >> 1) + resid) << 1;
 614:     len -= sizeof(struct vv_header);
 615: 
 616:     if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
 617:         vvprintf("vv%d: len too long or short, \
 618: len = %d, vvicsr = %b\n",
 619:             unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
 620:         goto dropit;
 621:     }
 622: 
 623:     /* check the protocol header version */
 624:     if (vv->vh_version != RING_VERSION) {
 625:         vvprintf("vv%d: bad protocol header version %d\n",
 626:             unit, vv->vh_version & 0xff);
 627:         goto dropit;
 628:     }
 629: 
 630: #define vvdataaddr(vv, off, type)   ((type)(((caddr_t)((vv)+1)+(off))))
 631:     if (vv->vh_type == RING_TRAILER ) {
 632:         off = ntohs((u_short)vv->vh_info);
 633:         if (off > VVMTU) {
 634:             vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
 635:                     unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
 636:             goto dropit;
 637:         }
 638:         vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *));
 639:         resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *)));
 640:         if (off + resid > len) {
 641:             vvprintf("vv%d: trailer packet too short\n", unit);
 642:             vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n",
 643:                     unit, off, resid,
 644:                     0xffff&(addr->vvicsr), VV_IBITS);
 645:             goto dropit;
 646:         }
 647:         len = off + resid;
 648:     } else
 649:         off = 0;
 650: 
 651:     if (len == 0) {
 652:         vvprintf("vv%d: len is zero, vvicsr = %b\n", unit,
 653:                 0xffff&(addr->vvicsr), VV_IBITS);
 654:         goto dropit;
 655:     }
 656: /*
 657:  * have to restore the mapping before manipulating mbufs because
 658:  * there may be mbufs in SEG5.  save the 'type' and 'shost' then
 659:  * restore the mapping.
 660: */
 661:     type = vv->vh_type;
 662:     shost = vv->vh_shost;
 663:     restorseg5(save5);
 664:     m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if);
 665:     if (m == NULL) {
 666:         vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit,
 667:                 0xffff&(addr->vvicsr), VV_IBITS);
 668:         goto dropit;
 669:     }
 670:     if (off) {
 671:         struct ifnet *ifp;
 672: 
 673:         ifp = *(mtod(m, struct ifnet **));
 674:         m->m_off += 2 * sizeof (u_short);
 675:         m->m_len -= 2 * sizeof (u_short);
 676:         *(mtod(m, struct ifnet **)) = ifp;
 677:     }
 678: 
 679:     /* Keep track of source address of this packet */
 680:     vs->vs_lastr = shost;
 681: 
 682:     /*
 683: 	 * Demultiplex on packet type
 684: 	 */
 685:     switch (type) {
 686: 
 687: #ifdef INET
 688:     case RING_IP:
 689:         schednetisr(NETISR_IP);
 690:         inq = &ipintrq;
 691:         break;
 692: #endif
 693:     default:
 694:         vvprintf("vv%d: unknown pkt type 0x%x\n", unit, type);
 695:         m_freem(m);
 696:         goto setup;
 697:     }
 698:     s = splimp();
 699:     if (IF_QFULL(inq)) {
 700:         IF_DROP(inq);
 701:         m_freem(m);
 702:     } else
 703:         IF_ENQUEUE(inq, m);
 704: 
 705:     splx(s);
 706:     /*
 707: 	 * Reset for the next packet.
 708: 	 */
 709: setup:
 710:     restorseg5(save5);
 711:     ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
 712:     addr->vviba = (u_short) ubainfo;
 713:     addr->vviea = (u_short) (ubainfo >> 16);
 714:     addr->vviwc = -(VVBUFSIZE) >> 1;
 715:     addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
 716:     return;
 717: 
 718:     /*
 719: 	 * Drop packet on floor -- count them!!
 720: 	 */
 721: dropit:
 722:     vs->vs_if.if_ierrors++;
 723:     goto setup;
 724: }
 725: 
 726: /*
 727:  * proNET output routine.
 728:  * Encapsulate a packet of type family for the local net.
 729:  * Use trailer local net encapsulation if enough data in first
 730:  * packet leaves a multiple of 512 bytes of data in remainder.
 731:  */
 732: vvoutput(ifp, m0, dst)
 733:     struct ifnet *ifp;
 734:     struct mbuf *m0;
 735:     struct sockaddr *dst;
 736: {
 737:     register struct mbuf *m;
 738:     register struct vv_header *vv;
 739:     register int off;
 740:     register int unit;
 741:     register struct vvreg *addr;
 742:     register struct vv_softc *vs;
 743:     register int s;
 744:     int type, error;
 745:     u_long dest;
 746:     segm save5;
 747: 
 748:     saveseg5(save5);
 749:     m = m0;
 750:     unit = ifp->if_unit;
 751:     addr = (struct vvreg *)vvinfo[unit]->ui_addr;
 752:     vs = &vv_softc[unit];
 753: 
 754:     /*
 755: 	 * Check to see if the input side has wedged.
 756: 	 *
 757: 	 * We are lower than device ipl when we enter this routine,
 758: 	 * so if the interface is ready with an input packet then
 759: 	 * an input interrupt must have slipped through the cracks.
 760: 	 *
 761: 	 * Avoid the race with an input interrupt by watching to see
 762: 	 * if any packets come in.
 763: 	 */
 764:     s = vs->vs_if.if_ipackets;
 765:     if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
 766:         vvprintf("vv%d: lost a receive interrupt, icsr = %b\n",
 767:                 unit, 0xffff&(addr->vvicsr), VV_IBITS);
 768:         s = splimp();
 769:         vvrint(unit);
 770:         splx(s);
 771:     }
 772: 
 773:     switch (dst->sa_family) {
 774: 
 775: #ifdef INET
 776:     case AF_INET:
 777:         if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
 778:             dest = VV_BROADCAST;
 779:         else
 780:             dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
 781: /* Rene Nieuwboer reneni@psy.vu.nl suggests a 'dest &= 0xff;' at this point */
 782: /*   dest is contrained in the 'if' a few lines down, i don't see why the & */
 783: #ifdef  LOOPBACK
 784:         if (dest == vs->vs_host && (loif.if_flags & IFF_UP))
 785:             return (looutput(&loif, m0, dst));
 786: #endif	LOOPBACK
 787:         if (dest >= 0x100) {
 788:             error = EPERM;
 789:             goto bad;
 790:         }
 791:         off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
 792:         /*
 793: 		 * Trailerize, if the configuration allows it.
 794: 		 * TODO: Need per host negotiation.
 795: 		 */
 796:         if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
 797:         if (off > 0 && (off & 0x1ff) == 0 &&
 798:             m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
 799:             type = RING_TRAILER;
 800:             m->m_off -= 2 * sizeof (u_short);
 801:             m->m_len += 2 * sizeof (u_short);
 802:             *mtod(m, u_short *) = htons((short)RING_IP);
 803:             *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
 804:             goto gottrailertype;
 805:         }
 806:         type = RING_IP;
 807:         off = 0;
 808:         goto gottype;
 809: #endif
 810:     default:
 811:         printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
 812:         error = EAFNOSUPPORT;
 813:         goto bad;
 814:     }
 815: 
 816: gottrailertype:
 817:     /*
 818: 	 * Packet to be sent as trailer: move first packet
 819: 	 * (control information) to end of chain.
 820: 	 */
 821:     while (m->m_next)
 822:         m = m->m_next;
 823:     m->m_next = m0;
 824:     m = m0->m_next;
 825:     m0->m_next = 0;
 826:     m0 = m;
 827: gottype:
 828:     /*
 829: 	 * Add local net header.  If no space in first mbuf,
 830: 	 * allocate another.
 831: 	 */
 832:     if (m->m_off > MMAXOFF ||
 833:         MMINOFF + sizeof (struct vv_header) > m->m_off) {
 834:         m = m_get(M_DONTWAIT, MT_HEADER);
 835:         if (m == NULL) {
 836:             error = ENOBUFS;
 837:             goto bad;
 838:         }
 839:         m->m_next = m0;
 840:         m->m_off = MMINOFF;
 841:         m->m_len = sizeof (struct vv_header);
 842:     } else {
 843:         m->m_off -= sizeof (struct vv_header);
 844:         m->m_len += sizeof (struct vv_header);
 845:     }
 846:     vv = mtod(m, struct vv_header *);
 847:     vv->vh_shost = vs->vs_host;
 848:     vv->vh_dhost = dest;
 849:     vv->vh_version = RING_VERSION;
 850:     vv->vh_type = type;
 851:     vv->vh_info = htons((u_short)off);
 852:     vvtracehdr("vo", vv);
 853: 
 854:     /*
 855: 	 * Queue message on interface, and start output if interface
 856: 	 * not yet active.
 857: 	 */
 858:     s = splimp();
 859:     if (IF_QFULL(&ifp->if_snd)) {
 860:         IF_DROP(&ifp->if_snd);
 861:         error = ENOBUFS;
 862:         goto qfull;
 863:     }
 864:     IF_ENQUEUE(&ifp->if_snd, m);
 865:     if (vs->vs_oactive == 0)
 866:         vvstart(unit);
 867:     splx(s);
 868:     return (0);
 869: qfull:
 870:     m0 = m;
 871:     splx(s);
 872: bad:
 873:     m_freem(m0);
 874:     return(error);
 875: }
 876: 
 877: /*
 878:  * Process an ioctl request.
 879:  */
 880: vvioctl(ifp, cmd, data)
 881:     register struct ifnet *ifp;
 882:     u_int cmd;
 883:     caddr_t data;
 884: {
 885:     struct ifaddr *ifa = (struct ifaddr *) data;
 886:     int s = splimp(), error = 0;
 887: 
 888:     switch (cmd) {
 889: 
 890:     case SIOCSIFADDR:
 891:         ifp->if_flags |= IFF_UP;
 892:         if ((ifp->if_flags & IFF_RUNNING) == 0)
 893:             vvinit(ifp->if_unit);
 894:         /*
 895: 		 * Did self-test succeed?
 896: 		 */
 897:         if ((ifp->if_flags & IFF_UP) == 0)
 898:             error = ENETDOWN;
 899:                 /*
 900:                  * Attempt to check agreement of protocol address
 901:                  * and board address.
 902:                  */
 903:         switch (ifa->ifa_addr.sa_family) {
 904:                 case AF_INET:
 905: /* Rene Nieuwboer reneni@psy.vu.nl suggests a '& 0xff;' below */
 906:             if ((u_short)(in_lnaof(IA_SIN(ifa)->sin_addr)) !=
 907:                 vv_softc[ifp->if_unit].vs_host)
 908:                 error = EADDRNOTAVAIL;
 909:             break;
 910:         }
 911:         break;
 912: 
 913:     default:
 914:         error = EINVAL;
 915:     }
 916:     splx(s);
 917:     return (error);
 918: }
 919: 
 920: /*
 921:  * vvprt_hdr(s, v) print the local net header in "v"
 922:  *	with title is "s"
 923:  */
 924: vvprt_hdr(s, v)
 925:     char *s;
 926:     register struct vv_header *v;
 927: {
 928:     printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
 929:         s,
 930:         0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
 931:         0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
 932:         0xffff & (int)(v->vh_info));
 933: }
 934: #endif NVV

Defined functions

vvattach defined in line 183; used 2 times
vvidentify defined in line 303; used 2 times
vvinit defined in line 232; used 4 times
vvioctl defined in line 880; used 2 times
vvoutput defined in line 732; used 2 times
vvprobe defined in line 149; used 2 times
vvprt_hdr defined in line 924; used 1 times
  • in line 96
vvreset defined in line 216; used 2 times
vvrint defined in line 552; used 2 times
vvstart defined in line 411; used 5 times
vvwatchdog defined in line 529; used 2 times
vvxint defined in line 473; used 2 times

Defined variables

vv_softc defined in line 145; used 9 times
vv_tracehdr defined in line 94; used 1 times
  • in line 96
vvdriver defined in line 107; never used
vvinfo defined in line 105; used 8 times
vvstd defined in line 106; used 1 times

Defined struct's

vv_softc defined in line 128; used 16 times

Defined macros

LOOPBACK defined in line 111; used 2 times
NOHOST defined in line 147; used 3 times
VVBUFSIZE defined in line 86; used 6 times
VVMRU defined in line 87; used 5 times
VVMTU defined in line 88; used 7 times
VVUNIT defined in line 109; used 1 times
vvdataaddr defined in line 630; used 2 times
vvprintf defined in line 97; used 13 times
vvtracehdr defined in line 96; used 2 times
Last modified: 1996-11-18
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 141
Valid CSS Valid XHTML 1.0 Strict