|
|
1.1 ! root 1: /* if_un.c 6.1 83/07/29 */ ! 2: ! 3: #include "un.h" ! 4: #if NUN > 0 ! 5: /* ! 6: * Ungermann-Bass network/DR11-W interface driver ! 7: */ ! 8: #include "../machine/pte.h" ! 9: ! 10: #include "../h/param.h" ! 11: #include "../h/systm.h" ! 12: #include "../h/mbuf.h" ! 13: #include "../h/buf.h" ! 14: #include "../h/protosw.h" ! 15: #include "../h/socket.h" ! 16: #include "../h/vmmac.h" ! 17: #include "../h/errno.h" ! 18: #include "../h/time.h" ! 19: #include "../h/kernel.h" ! 20: #include "../h/ioctl.h" ! 21: ! 22: #include "../net/if.h" ! 23: #include "../net/netisr.h" ! 24: #include "../net/route.h" ! 25: #include "../netinet/in.h" ! 26: #include "../netinet/in_systm.h" ! 27: #include "../netinet/ip.h" ! 28: #include "../netinet/ip_var.h" ! 29: ! 30: #include "../vax/cpu.h" ! 31: #include "../vax/mtpr.h" ! 32: #include "../vaxif/if_un.h" ! 33: #include "../vaxif/if_unreg.h" ! 34: #include "../vaxif/if_uba.h" ! 35: #include "../vaxuba/ubareg.h" ! 36: #include "../vaxuba/ubavar.h" ! 37: ! 38: #define UNMTU (600-sizeof (struct un_header)) ! 39: ! 40: #define US_NULL 0 /* not doing anything state */ ! 41: #define US_IDLE 1 /* waiting to transfer state */ ! 42: #define US_READ 2 /* reading state */ ! 43: #define US_WRITE 3 /* writing state */ ! 44: #define US_RESET 4 /* waiting for reset state */ ! 45: ! 46: int unprobe(), unattach(), unintr(); ! 47: struct uba_device *uninfo[NUN]; ! 48: u_short unstd[] = { 0 }; ! 49: struct uba_driver undriver = ! 50: { unprobe, 0, unattach, 0, unstd, "un", uninfo }; ! 51: #define UNUNIT(dev) (minor(dev)) ! 52: ! 53: int uninit(), unioctl(), unoutput(), unreset(); ! 54: int unrestart(); ! 55: ! 56: /* ! 57: * Ungermann-Bass software status per interface. ! 58: * ! 59: * Each interface is referenced by a network interface structure, ! 60: * us_if, which the routing code uses to locate the interface. ! 61: * This structure contains the output queue for the interface, its address, ! 62: * etc. We also have, for each interface, a UBA interface structure, which ! 63: * contains information about the UNIBUS resources held by the interface: ! 64: * map registers, buffered data paths, etc. Information is cached in this ! 65: * structure for use by the if_uba.c routines in running the interface ! 66: * efficiently. ! 67: */ ! 68: struct un_softc { ! 69: struct ifnet us_if; /* network-visible interface */ ! 70: struct ifuba us_ifuba; /* UNIBUS resources */ ! 71: short us_state; /* device state */ ! 72: short us_errcnt; /* number of errors since time set */ ! 73: short us_restart; /* restart interval */ ! 74: u_char us_maxtime; /* interval for error counting */ ! 75: u_char us_maxerr; /* errors allowed in interval */ ! 76: time_t us_errtime; /* time for error counting */ ! 77: } un_softc[NUN]; ! 78: ! 79: /* ! 80: * Cause an interrupt to determine interface presence and ! 81: * interrupt vector. ! 82: */ ! 83: unprobe(reg) ! 84: caddr_t reg; ! 85: { ! 86: register int br, cvec; /* r11, r10 value-result */ ! 87: register struct undevice *addr = (struct undevice *)reg; ! 88: ! 89: #ifdef lint ! 90: br = 0; cvec = br; br = cvec; ! 91: unintr(0); ! 92: #endif ! 93: addr->csr = IE|UNRESET; ! 94: addr->csr = IE|UNRESET|GO; ! 95: DELAY(100000); ! 96: addr->csr = 0; ! 97: return (1); ! 98: } ! 99: ! 100: /* ! 101: * Interface exists: make available by filling in network interface ! 102: * record. System will initialize the interface when it is ready ! 103: * to accept packets. ! 104: */ ! 105: unattach(ui) ! 106: struct uba_device *ui; ! 107: { ! 108: register struct un_softc *us = &un_softc[ui->ui_unit]; ! 109: ! 110: us->us_if.if_unit = ui->ui_unit; ! 111: us->us_if.if_name = "un"; ! 112: us->us_if.if_mtu = UNMTU; ! 113: us->us_if.if_init = uninit; ! 114: us->us_if.if_ioctl = unioctl; ! 115: us->us_if.if_output = unoutput; ! 116: us->us_if.if_reset = unreset; ! 117: us->us_if.if_watchdog = unrestart; ! 118: us->us_maxtime = 3; ! 119: us->us_maxerr = 10; ! 120: us->us_restart = 5 * 60; ! 121: us->us_ifuba.ifu_flags = UBA_CANTWAIT; ! 122: #ifdef notdef ! 123: us->us_ifuba.ifu_flags |= UBA_NEEDBDP; ! 124: #endif ! 125: if_attach(&us->us_if); ! 126: } ! 127: ! 128: /* ! 129: * Reset of interface after UNIBUS reset. ! 130: * If interface is on specified uba, reset its state. ! 131: */ ! 132: unreset(unit, uban) ! 133: int unit, uban; ! 134: { ! 135: register struct uba_device *ui; ! 136: ! 137: if (unit >= NUN || (ui = uninfo[unit]) == 0 || ui->ui_alive == 0 || ! 138: ui->ui_ubanum != uban) ! 139: return; ! 140: printf(" un%d", unit); ! 141: uninit(unit); ! 142: } ! 143: ! 144: /* ! 145: * Initialization of interface; clear recorded pending ! 146: * operations, and reinitialize UNIBUS usage. ! 147: */ ! 148: uninit(unit) ! 149: int unit; ! 150: { ! 151: register struct un_softc *us = &un_softc[unit]; ! 152: register struct uba_device *ui = uninfo[unit]; ! 153: register struct undevice *addr; ! 154: struct sockaddr_in *sin; ! 155: int s; ! 156: ! 157: sin = (struct sockaddr_in *)&us->us_if.if_addr; ! 158: if (in_netof(sin->sin_addr) == 0) ! 159: return; ! 160: if (if_ubainit(&us->us_ifuba, ui->ui_ubanum, ! 161: sizeof (struct un_header), (int)btoc(UNMTU)) == 0) { ! 162: printf("un%d: can't initialize\n", unit); ! 163: us->us_if.if_flags &= ~IFF_UP; ! 164: return; ! 165: } ! 166: us->us_if.if_flags |= IFF_RUNNING; ! 167: us->us_errcnt = 0; ! 168: us->us_errtime = time.tv_sec; ! 169: unwhoami(unit); ! 170: ! 171: /* ! 172: * Reset U-B interface, thus causing an interrupt which ! 173: * will start things going. ! 174: */ ! 175: addr = (struct undevice *)ui->ui_addr; ! 176: s = splimp(); ! 177: addr->csr = IE|UNRESET; ! 178: addr->csr = IE|UNRESET|GO; ! 179: us->us_state = US_RESET; ! 180: splx(s); ! 181: } ! 182: ! 183: /* ! 184: * Try to start a write operation. ! 185: * If interface is busy, it must be in idle state, so issue a reset. ! 186: * Otherwise, get the datagram from the output queue, map it onto ! 187: * the UNIBUS, and start the write. This routine should not be ! 188: * called if the output queue is empty. ! 189: */ ! 190: unstart(dev) ! 191: dev_t dev; ! 192: { ! 193: int unit = UNUNIT(dev); ! 194: struct uba_device *ui = uninfo[unit]; ! 195: register struct un_softc *us = &un_softc[unit]; ! 196: register struct undevice *addr = (struct undevice *)ui->ui_addr; ! 197: struct mbuf *m; ! 198: int dataaddr, datalen; ! 199: register short cmdcsr; ! 200: ! 201: if (us->us_state != US_NULL) { ! 202: addr->csr = IE|UNRESET; ! 203: addr->csr = IE|UNRESET|GO; ! 204: us->us_state = US_RESET; ! 205: } else { ! 206: IF_DEQUEUE(&us->us_if.if_snd, m); ! 207: if (m == 0) ! 208: return; ! 209: us->us_state = US_WRITE; ! 210: datalen = if_wubaput(&us->us_ifuba, m); ! 211: if (us->us_ifuba.ifu_flags & UBA_NEEDBDP) ! 212: UBAPURGE(us->us_ifuba.ifu_uba, ! 213: us->us_ifuba.ifu_w.ifrw_bdp); ! 214: dataaddr = us->us_ifuba.ifu_w.ifrw_info; ! 215: addr->bar = dataaddr & 0xffff; ! 216: addr->wcr = -(((datalen + 1) >> 1) + 1); ! 217: cmdcsr = ((dataaddr >> 12) & 0x30) | IE | UNOUT; ! 218: addr->csr = cmdcsr; ! 219: addr->csr = cmdcsr | GO; ! 220: } ! 221: } ! 222: ! 223: /* ! 224: * Ungermann-Bass interface interrupt handler. ! 225: * Determines reason for interrupt and acts accordingly. ! 226: */ ! 227: unintr(unit) ! 228: int unit; ! 229: { ! 230: register struct un_softc *us = &un_softc[unit]; ! 231: struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr; ! 232: register struct un_header *un; ! 233: struct mbuf *m; ! 234: int len; ! 235: register struct ifqueue *inq; ! 236: int cmdcsr; ! 237: ! 238: if ((addr->dar & RESETACK) && us->us_state != US_RESET) { ! 239: if ((us->us_if.if_flags & IFF_UP) == 0) ! 240: return; ! 241: printf("un%d: unexpected reset\n", unit); ! 242: unerror(unit); ! 243: } ! 244: ! 245: switch (us->us_state) { ! 246: ! 247: case US_NULL: ! 248: printf("un%d: stray interrupt\n", unit); ! 249: break; ! 250: ! 251: case US_RESET: ! 252: if (!(addr->dar & RESETACK)) { ! 253: addr->csr = IE|UNRESET; ! 254: addr->csr = IE|UNRESET|GO; ! 255: return; ! 256: } ! 257: break; ! 258: ! 259: case US_IDLE: ! 260: break; ! 261: ! 262: case US_READ: ! 263: us->us_if.if_ipackets++; ! 264: if (us->us_ifuba.ifu_flags & UBA_NEEDBDP) ! 265: UBAPURGE(us->us_ifuba.ifu_uba, ! 266: us->us_ifuba.ifu_r.ifrw_bdp); ! 267: if (addr->csr & STATA) { ! 268: if ((us->us_if.if_flags & IFF_UP) == 0) ! 269: return; ! 270: printf("un%d: input error csr=%b\n", unit, ! 271: addr->csr&0xffff, UNBITS); ! 272: us->us_if.if_ierrors++; ! 273: unerror(unit); ! 274: break; ! 275: } ! 276: un = (struct un_header *)(us->us_ifuba.ifu_r.ifrw_addr); ! 277: switch (un->un_ptype) { ! 278: #ifdef INET ! 279: case UNTYPE_IP: ! 280: len = htons((u_short)((struct ip *) (un+1))->ip_len); ! 281: schednetisr(NETISR_IP); ! 282: inq = &ipintrq; ! 283: break; ! 284: #endif ! 285: case UNTYPE_INQUIRE: { ! 286: struct sockaddr_in *sin; ! 287: ! 288: us->us_if.if_host[0] = ! 289: un->un_dport << 16 | htons(un->un_dniu); ! 290: sin = (struct sockaddr_in *)&us->us_if.if_addr; ! 291: sin->sin_addr = if_makeaddr(us->us_if.if_net, ! 292: us->us_if.if_host[0]); ! 293: us->us_if.if_flags |= IFF_UP; ! 294: if_rtinit(&us->us_if, RTF_UP); ! 295: goto setup; ! 296: } ! 297: ! 298: default: ! 299: printf("un%d: bad packet type %d\n", un->un_ptype); ! 300: goto setup; ! 301: } ! 302: ! 303: m = if_rubaget(&us->us_ifuba, len, 0); ! 304: if (m != 0) ! 305: if (IF_QFULL(inq)) { ! 306: IF_DROP(inq); ! 307: m_freem(m); ! 308: } else ! 309: IF_ENQUEUE(inq, m); ! 310: break; ! 311: ! 312: case US_WRITE: ! 313: us->us_if.if_opackets++; ! 314: if (addr->csr & STATA) { ! 315: if ((us->us_if.if_flags & IFF_UP) == 0) ! 316: return; ! 317: printf("un%d: output error csr=%b\n", ! 318: unit, addr->csr, UNBITS); ! 319: us->us_if.if_oerrors++; ! 320: unerror(unit); ! 321: } ! 322: if (us->us_ifuba.ifu_xtofree) { ! 323: m_freem(us->us_ifuba.ifu_xtofree); ! 324: us->us_ifuba.ifu_xtofree = 0; ! 325: } ! 326: break; ! 327: ! 328: default: ! 329: printf("un%d: invalid state %d csr=%b\n", ! 330: us->us_state, addr->csr, UNBITS); ! 331: } ! 332: ! 333: setup: ! 334: us->us_state = US_NULL; ! 335: if (addr->csr & STATB) { ! 336: us->us_state = US_READ; ! 337: addr->wcr = -((sizeof (struct un_header) + UNMTU + 1)/2+1); ! 338: addr->bar = us->us_ifuba.ifu_r.ifrw_info & 0xffff; ! 339: cmdcsr = ((us->us_ifuba.ifu_r.ifrw_info >> 12) & 0x30); ! 340: cmdcsr |= IE|UNRDDG; ! 341: addr->csr = cmdcsr; ! 342: addr->csr = cmdcsr | GO; ! 343: } else if (us->us_if.if_snd.ifq_head != 0 && (addr->csr & STATC)) ! 344: unstart(unit); ! 345: ! 346: if (us->us_state == US_NULL) { ! 347: us->us_state = US_IDLE; ! 348: addr->csr = IE|UNIDLE; ! 349: addr->csr = IE|UNIDLE|GO; ! 350: } ! 351: } ! 352: ! 353: /* ! 354: * Ungermann-Bass output routine. ! 355: * Encapsulate a packet destined for dst for the local net. ! 356: */ ! 357: unoutput(ifp, m0, dst) ! 358: struct ifnet *ifp; ! 359: struct mbuf *m0; ! 360: struct sockaddr *dst; ! 361: { ! 362: int type, destniu, destport, len; ! 363: register struct mbuf *m = m0; ! 364: register struct un_header *un; ! 365: register struct un_softc *us = &un_softc[ifp->if_unit]; ! 366: int s; ! 367: ! 368: if ((us->us_if.if_flags & IFF_UP) == 0) ! 369: return (ENETDOWN); ! 370: switch (dst->sa_family) { ! 371: ! 372: #ifdef INET ! 373: case AF_INET: { ! 374: struct sockaddr_in *sin = (struct sockaddr_in *)dst; ! 375: struct ip *ip = mtod(m, struct ip *); ! 376: ! 377: if (sin->sin_addr.s_addr & 0xffffff00) { ! 378: destniu = sin->sin_addr.s_addr >> 24; ! 379: destport = (sin->sin_addr.s_addr >> 8) & 0xff; ! 380: } else { ! 381: destniu = 0xffff; ! 382: destport = 0xff; ! 383: } ! 384: len = htons((u_short) ip->ip_len); ! 385: type = UNTYPE_IP; ! 386: break; ! 387: } ! 388: #endif ! 389: default: ! 390: printf("un%d: can't handle af%d\n", ifp->if_unit, ! 391: dst->sa_family); ! 392: m_freem(m0); ! 393: return (EAFNOSUPPORT); ! 394: } ! 395: ! 396: /* ! 397: * Add local net header. If no space in first mbuf, ! 398: * allocate another. ! 399: */ ! 400: if (m->m_off > MMAXOFF || ! 401: MMINOFF + sizeof (struct un_header) > m->m_off) { ! 402: m = m_get(M_DONTWAIT, MT_HEADER); ! 403: if (m == 0) { ! 404: m_freem(m0); ! 405: return (ENOBUFS); ! 406: } ! 407: m->m_next = m0; ! 408: m->m_off = MMINOFF; ! 409: m->m_len = sizeof (struct un_header); ! 410: } else { ! 411: m->m_off -= sizeof (struct un_header); ! 412: m->m_len += sizeof (struct un_header); ! 413: } ! 414: un = mtod(m, struct un_header *); ! 415: bzero((caddr_t)un, sizeof (struct un_header)); ! 416: un->un_length = htons((u_short)(len + sizeof (struct un_header))); ! 417: un->un_dniu = htons((u_short)destniu); ! 418: un->un_dport = destport; ! 419: un->un_dtype = 5; ! 420: un->un_sniu = htons((u_short)(ifp->if_host[0] >> 24)); ! 421: un->un_sport = (ifp->if_host[0] >> 8) & 0xff; ! 422: un->un_stype = 5; ! 423: un->un_ptype = type; ! 424: ! 425: /* ! 426: * Queue message on interface, and start output if interface ! 427: * not yet active. ! 428: */ ! 429: s = splimp(); ! 430: if (IF_QFULL(&ifp->if_snd)) { ! 431: IF_DROP(&ifp->if_snd); ! 432: m_freem(m); ! 433: splx(s); ! 434: return (ENOBUFS); ! 435: } ! 436: IF_ENQUEUE(&ifp->if_snd, m); ! 437: if (us->us_state == US_IDLE) ! 438: unstart(ifp->if_unit); ! 439: splx(s); ! 440: return (0); ! 441: } ! 442: ! 443: /* ! 444: * U-B error handler, if maxerr errors have occured ! 445: * in maxtime seconds, disable the interface. ! 446: */ ! 447: unerror(unit) ! 448: int unit; ! 449: { ! 450: register struct un_softc *us = &un_softc[unit]; ! 451: struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr; ! 452: ! 453: if (time.tv_sec - us->us_errtime > us->us_maxtime) { ! 454: us->us_errtime = time.tv_sec; ! 455: us->us_errcnt = 1; ! 456: } else if (++us->us_errcnt >= us->us_maxerr) { ! 457: printf("un%d: error limit exceeded\n", unit); ! 458: us->us_if.if_flags &= ~IFF_UP; ! 459: addr->csr = 0; ! 460: us->us_if.if_timer = us->us_restart; ! 461: } ! 462: } ! 463: ! 464: unrestart(unit) ! 465: int unit; ! 466: { ! 467: register struct un_softc *us = &un_softc[unit]; ! 468: struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr; ! 469: int s; ! 470: ! 471: us->us_if.if_flags |= IFF_UP; ! 472: printf("un%d: restarting\n", unit); ! 473: unwhoami(unit); ! 474: s = splimp(); ! 475: addr->csr = IE|UNRESET; ! 476: addr->csr = IE|UNRESET|GO; ! 477: us->us_state = US_RESET; ! 478: splx(s); ! 479: } ! 480: ! 481: /* ! 482: * Send a "Who am I?" message to the interface. ! 483: * Interface should respond with an copy of the ! 484: * packet with its real address filled in. The ! 485: * message is placed at the head of the output queue. ! 486: * An interface reset should be done next to start ! 487: * things rolling. ! 488: */ ! 489: unwhoami(unit) ! 490: int unit; ! 491: { ! 492: register struct mbuf *m; ! 493: register struct un_softc *us = &un_softc[unit]; ! 494: register struct un_header *un; ! 495: int s; ! 496: ! 497: if ((m = m_get(M_DONTWAIT, MT_HEADER)) == 0) ! 498: return; ! 499: m->m_off = MMINOFF; ! 500: m->m_len = sizeof(struct un_header); ! 501: un = mtod(m, struct un_header *); ! 502: bzero((caddr_t)un, sizeof (struct un_header)); ! 503: un->un_length = htons(sizeof (struct un_header)); ! 504: un->un_dtype = un->un_stype = 5; ! 505: un->un_ptype = UNTYPE_INQUIRE; ! 506: s = splimp(); ! 507: IF_PREPEND(&us->us_if.if_snd, m); ! 508: splx(s); ! 509: } ! 510: ! 511: /* ! 512: * Process an ioctl request. ! 513: */ ! 514: unioctl(ifp, cmd, data) ! 515: register struct ifnet *ifp; ! 516: int cmd; ! 517: caddr_t data; ! 518: { ! 519: struct ifreq *ifr = (struct ifreq *)data; ! 520: int s = splimp(), error = 0; ! 521: ! 522: switch (cmd) { ! 523: ! 524: case SIOCSIFADDR: ! 525: if (ifp->if_flags & IFF_RUNNING) ! 526: if_rtinit(ifp, -1); /* delete previous route */ ! 527: unsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr); ! 528: if (ifp->if_flags & IFF_RUNNING) ! 529: if_rtinit(ifp, RTF_UP); ! 530: else ! 531: uninit(ifp->if_unit); ! 532: break; ! 533: ! 534: default: ! 535: error = EINVAL; ! 536: } ! 537: splx(s); ! 538: return (error); ! 539: } ! 540: ! 541: unsetaddr(ifp, sin) ! 542: register struct ifnet *ifp; ! 543: register struct sockaddr_in *sin; ! 544: { ! 545: ! 546: ifp->if_net = in_netof(sin->sin_addr); ! 547: sin = (struct sockaddr_in *)&ifp->if_addr; ! 548: sin->sin_family = AF_INET; ! 549: /* host number filled in already, or filled in later */ ! 550: sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); ! 551: sin = (struct sockaddr_in *)&ifp->if_broadaddr; ! 552: sin->sin_family = AF_INET; ! 553: sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); ! 554: ifp->if_flags |= IFF_BROADCAST; ! 555: } ! 556: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.