|
|
1.1 ! root 1: /* @(#)if_sl.c 7.1 (Berkeley) 6/4/86 */ ! 2: ! 3: /* ! 4: * Serial Line interface ! 5: * ! 6: * Rick Adams ! 7: * Center for Seismic Studies ! 8: * 1300 N 17th Street, Suite 1450 ! 9: * Arlington, Virginia 22209 ! 10: * (703)276-7900 ! 11: * [email protected] ! 12: * seismo!rick ! 13: * ! 14: * Pounded on heavily by Chris Torek ([email protected], umcp-cs!chris). ! 15: * N.B.: this belongs in netinet, not net, the way it stands now. ! 16: * Should have a link-layer type designation, but wouldn't be ! 17: * backwards-compatible. ! 18: * ! 19: * Converted to 4.3BSD Beta by Chris Torek. ! 20: * Other changes made at Berkeley, based in part on code by Kirk Smith. ! 21: */ ! 22: ! 23: /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */ ! 24: /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ ! 25: ! 26: #include "sl.h" ! 27: #if NSL > 0 ! 28: ! 29: #include "param.h" ! 30: #include "mbuf.h" ! 31: #include "buf.h" ! 32: #include "dk.h" ! 33: #include "socket.h" ! 34: #include "ioctl.h" ! 35: #include "file.h" ! 36: #include "tty.h" ! 37: #include "errno.h" ! 38: ! 39: #include "if.h" ! 40: #include "netisr.h" ! 41: #include "route.h" ! 42: #if INET ! 43: #include "../netinet/in.h" ! 44: #include "../netinet/in_systm.h" ! 45: #include "../netinet/in_var.h" ! 46: #include "../netinet/ip.h" ! 47: #endif ! 48: ! 49: #ifdef vax ! 50: #include "../vax/mtpr.h" ! 51: #endif vax ! 52: ! 53: /* ! 54: * N.B.: SLMTU is now a hard limit on input packet size. ! 55: * SLMTU must be <= CLBYTES - sizeof(struct ifnet *). ! 56: */ ! 57: #define SLMTU 1006 ! 58: #define SLIP_HIWAT 1000 /* don't start a new packet if HIWAT on queue */ ! 59: #define CLISTRESERVE 1000 /* Can't let clists get too low */ ! 60: ! 61: struct sl_softc { ! 62: struct ifnet sc_if; /* network-visible interface */ ! 63: short sc_flags; /* see below */ ! 64: short sc_ilen; /* length of input-packet-so-far */ ! 65: struct tty *sc_ttyp; /* pointer to tty structure */ ! 66: char *sc_mp; /* pointer to next available buf char */ ! 67: char *sc_buf; /* input buffer */ ! 68: } sl_softc[NSL]; ! 69: ! 70: /* flags */ ! 71: #define SC_ESCAPED 0x0001 /* saw a FRAME_ESCAPE */ ! 72: #define SC_OACTIVE 0x0002 /* output tty is active */ ! 73: ! 74: #define FRAME_END 0300 /* Frame End */ ! 75: #define FRAME_ESCAPE 0333 /* Frame Esc */ ! 76: #define TRANS_FRAME_END 0334 /* transposed frame end */ ! 77: #define TRANS_FRAME_ESCAPE 0335 /* transposed frame esc */ ! 78: ! 79: #define t_sc T_LINEP ! 80: ! 81: int sloutput(), slioctl(), ttrstrt(); ! 82: ! 83: /* ! 84: * Called from boot code to establish sl interfaces. ! 85: */ ! 86: slattach() ! 87: { ! 88: register struct sl_softc *sc; ! 89: register int i = 0; ! 90: ! 91: for (sc = sl_softc; i < NSL; sc++) { ! 92: sc->sc_if.if_name = "sl"; ! 93: sc->sc_if.if_unit = i++; ! 94: sc->sc_if.if_mtu = SLMTU; ! 95: sc->sc_if.if_flags = IFF_POINTOPOINT; ! 96: sc->sc_if.if_ioctl = slioctl; ! 97: sc->sc_if.if_output = sloutput; ! 98: sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; ! 99: if_attach(&sc->sc_if); ! 100: } ! 101: } ! 102: ! 103: /* ! 104: * Line specific open routine. ! 105: * Attach the given tty to the first available sl unit. ! 106: */ ! 107: /* ARGSUSED */ ! 108: slopen(dev, tp) ! 109: dev_t dev; ! 110: register struct tty *tp; ! 111: { ! 112: register struct sl_softc *sc; ! 113: register int nsl; ! 114: ! 115: if (!suser()) ! 116: return (EPERM); ! 117: if (tp->t_line == SLIPDISC) ! 118: return (EBUSY); ! 119: ! 120: for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++) ! 121: if (sc->sc_ttyp == NULL) { ! 122: sc->sc_flags = 0; ! 123: sc->sc_ilen = 0; ! 124: if (slinit(sc) == 0) ! 125: return (ENOBUFS); ! 126: tp->t_sc = (caddr_t)sc; ! 127: sc->sc_ttyp = tp; ! 128: ttyflush(tp, FREAD | FWRITE); ! 129: return (0); ! 130: } ! 131: ! 132: return (ENXIO); ! 133: } ! 134: ! 135: /* ! 136: * Line specific close routine. ! 137: * Detach the tty from the sl unit. ! 138: * Mimics part of ttyclose(). ! 139: */ ! 140: slclose(tp) ! 141: struct tty *tp; ! 142: { ! 143: register struct sl_softc *sc; ! 144: int s; ! 145: ! 146: ttywflush(tp); ! 147: tp->t_line = 0; ! 148: s = splimp(); /* paranoid; splnet probably ok */ ! 149: sc = (struct sl_softc *)tp->t_sc; ! 150: if (sc != NULL) { ! 151: if_down(&sc->sc_if); ! 152: sc->sc_ttyp = NULL; ! 153: tp->t_sc = NULL; ! 154: MCLFREE((struct mbuf *)sc->sc_buf); ! 155: sc->sc_buf = 0; ! 156: } ! 157: splx(s); ! 158: } ! 159: ! 160: /* ! 161: * Line specific (tty) ioctl routine. ! 162: * Provide a way to get the sl unit number. ! 163: */ ! 164: /* ARGSUSED */ ! 165: sltioctl(tp, cmd, data, flag) ! 166: struct tty *tp; ! 167: caddr_t data; ! 168: { ! 169: ! 170: if (cmd == TIOCGETD) { ! 171: *(int *)data = ((struct sl_softc *)tp->t_sc)->sc_if.if_unit; ! 172: return (0); ! 173: } ! 174: return (-1); ! 175: } ! 176: ! 177: /* ! 178: * Queue a packet. Start transmission if not active. ! 179: */ ! 180: sloutput(ifp, m, dst) ! 181: register struct ifnet *ifp; ! 182: register struct mbuf *m; ! 183: struct sockaddr *dst; ! 184: { ! 185: register struct sl_softc *sc; ! 186: int s; ! 187: ! 188: /* ! 189: * `Cannot happen' (see slioctl). Someday we will extend ! 190: * the line protocol to support other address families. ! 191: */ ! 192: if (dst->sa_family != AF_INET) { ! 193: printf("sl%d: af%d not supported\n", ifp->if_unit, ! 194: dst->sa_family); ! 195: m_freem(m); ! 196: return (EAFNOSUPPORT); ! 197: } ! 198: ! 199: sc = &sl_softc[ifp->if_unit]; ! 200: if (sc->sc_ttyp == NULL) { ! 201: m_freem(m); ! 202: return (ENETDOWN); /* sort of */ ! 203: } ! 204: if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { ! 205: m_freem(m); ! 206: return (EHOSTUNREACH); ! 207: } ! 208: s = splimp(); ! 209: if (IF_QFULL(&ifp->if_snd)) { ! 210: IF_DROP(&ifp->if_snd); ! 211: splx(s); ! 212: m_freem(m); ! 213: sc->sc_if.if_oerrors++; ! 214: return (ENOBUFS); ! 215: } ! 216: IF_ENQUEUE(&ifp->if_snd, m); ! 217: if ((sc->sc_flags & SC_OACTIVE) == 0) { ! 218: splx(s); ! 219: slstart(sc->sc_ttyp); ! 220: } else ! 221: splx(s); ! 222: return (0); ! 223: } ! 224: ! 225: /* ! 226: * Start output on interface. Get another datagram ! 227: * to send from the interface queue and map it to ! 228: * the interface before starting output. ! 229: */ ! 230: slstart(tp) ! 231: register struct tty *tp; ! 232: { ! 233: register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; ! 234: register struct mbuf *m; ! 235: register int len; ! 236: register u_char *cp; ! 237: int flush, nd, np, n, s; ! 238: struct mbuf *m2; ! 239: extern int cfreecount; ! 240: ! 241: for (;;) { ! 242: /* ! 243: * If there is more in the output queue, just send it now. ! 244: * We are being called in lieu of ttstart and must do what ! 245: * it would. ! 246: */ ! 247: if (tp->t_outq.c_cc > 0) ! 248: ttstart(tp); ! 249: if (tp->t_outq.c_cc > SLIP_HIWAT) ! 250: return; ! 251: ! 252: /* ! 253: * This happens briefly when the line shuts down. ! 254: */ ! 255: if (sc == NULL) ! 256: return; ! 257: ! 258: /* ! 259: * If system is getting low on clists ! 260: * and we have something running already, stop here. ! 261: */ ! 262: if (cfreecount < CLISTRESERVE + SLMTU && ! 263: sc->sc_flags & SC_OACTIVE) ! 264: return; ! 265: ! 266: /* ! 267: * Get a packet and send it to the interface. ! 268: */ ! 269: s = splimp(); ! 270: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 271: if (m == NULL) { ! 272: if (tp->t_outq.c_cc == 0) ! 273: sc->sc_flags &= ~SC_OACTIVE; ! 274: splx(s); ! 275: return; ! 276: } ! 277: flush = !(sc->sc_flags & SC_OACTIVE); ! 278: sc->sc_flags |= SC_OACTIVE; ! 279: splx(s); ! 280: ! 281: /* ! 282: * The extra FRAME_END will start up a new packet, and thus ! 283: * will flush any accumulated garbage. We do this whenever ! 284: * the line may have been idle for some time. ! 285: */ ! 286: if (flush) ! 287: (void) putc(FRAME_END, &tp->t_outq); ! 288: ! 289: while (m) { ! 290: cp = mtod(m, u_char *); ! 291: len = m->m_len; ! 292: while (len > 0) { ! 293: /* ! 294: * Find out how many bytes in the string we can ! 295: * handle without doing something special. ! 296: */ ! 297: nd = locc(FRAME_ESCAPE, len, cp); ! 298: np = locc(FRAME_END, len, cp); ! 299: n = len - MAX(nd, np); ! 300: if (n) { ! 301: /* ! 302: * Put n characters at once ! 303: * into the tty output queue. ! 304: */ ! 305: if (b_to_q((char *)cp, n, &tp->t_outq)) ! 306: break; ! 307: len -= n; ! 308: cp += n; ! 309: } ! 310: /* ! 311: * If there are characters left in the mbuf, ! 312: * the first one must be special.. ! 313: * Put it out in a different form. ! 314: */ ! 315: if (len) { ! 316: if (putc(FRAME_ESCAPE, &tp->t_outq)) ! 317: break; ! 318: if (putc(*cp == FRAME_ESCAPE ? ! 319: TRANS_FRAME_ESCAPE : TRANS_FRAME_END, ! 320: &tp->t_outq)) { ! 321: (void) unputc(&tp->t_outq); ! 322: break; ! 323: } ! 324: cp++; ! 325: len--; ! 326: } ! 327: } ! 328: MFREE(m, m2); ! 329: m = m2; ! 330: } ! 331: ! 332: if (putc(FRAME_END, &tp->t_outq)) { ! 333: /* ! 334: * Not enough room. Remove a char to make room ! 335: * and end the packet normally. ! 336: * If you get many collisions (more than one or two ! 337: * a day) you probably do not have enough clists ! 338: * and you should increase "nclist" in param.c. ! 339: */ ! 340: (void) unputc(&tp->t_outq); ! 341: (void) putc(FRAME_END, &tp->t_outq); ! 342: sc->sc_if.if_collisions++; ! 343: } else ! 344: sc->sc_if.if_opackets++; ! 345: } ! 346: } ! 347: ! 348: slinit(sc) ! 349: register struct sl_softc *sc; ! 350: { ! 351: struct mbuf *p; ! 352: ! 353: if (sc->sc_buf == (char *) 0) { ! 354: MCLALLOC(p, 1); ! 355: if (p) { ! 356: sc->sc_buf = (char *)p; ! 357: sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *); ! 358: } else { ! 359: printf("sl%d: can't allocate buffer\n", sc - sl_softc); ! 360: sc->sc_if.if_flags &= ~IFF_UP; ! 361: return (0); ! 362: } ! 363: } ! 364: return (1); ! 365: } ! 366: ! 367: /* ! 368: * Copy data buffer to mbuf chain; add ifnet pointer ifp. ! 369: */ ! 370: struct mbuf * ! 371: sl_btom(sc, len, ifp) ! 372: struct sl_softc *sc; ! 373: register int len; ! 374: struct ifnet *ifp; ! 375: { ! 376: register caddr_t cp; ! 377: register struct mbuf *m, **mp; ! 378: register unsigned count; ! 379: struct mbuf *top = NULL; ! 380: ! 381: cp = sc->sc_buf + sizeof(struct ifnet *); ! 382: mp = ⊤ ! 383: while (len > 0) { ! 384: MGET(m, M_DONTWAIT, MT_DATA); ! 385: if ((*mp = m) == NULL) { ! 386: m_freem(top); ! 387: return (NULL); ! 388: } ! 389: if (ifp) ! 390: m->m_off += sizeof(ifp); ! 391: /* ! 392: * If we have at least NBPG bytes, ! 393: * allocate a new page. Swap the current buffer page ! 394: * with the new one. We depend on having a space ! 395: * left at the beginning of the buffer ! 396: * for the interface pointer. ! 397: */ ! 398: if (len >= NBPG) { ! 399: MCLGET(m); ! 400: if (m->m_len == CLBYTES) { ! 401: cp = mtod(m, char *); ! 402: m->m_off = (int)sc->sc_buf - (int)m; ! 403: sc->sc_buf = cp; ! 404: if (ifp) { ! 405: m->m_off += sizeof(ifp); ! 406: count = MIN(len, ! 407: CLBYTES - sizeof(struct ifnet *)); ! 408: } else ! 409: count = MIN(len, CLBYTES); ! 410: goto nocopy; ! 411: } ! 412: } ! 413: if (ifp) ! 414: count = MIN(len, MLEN - sizeof(ifp)); ! 415: else ! 416: count = MIN(len, MLEN); ! 417: bcopy(cp, mtod(m, caddr_t), count); ! 418: nocopy: ! 419: m->m_len = count; ! 420: if (ifp) { ! 421: m->m_off -= sizeof(ifp); ! 422: m->m_len += sizeof(ifp); ! 423: *mtod(m, struct ifnet **) = ifp; ! 424: ifp = NULL; ! 425: } ! 426: cp += count; ! 427: len -= count; ! 428: mp = &m->m_next; ! 429: } ! 430: return (top); ! 431: } ! 432: ! 433: /* ! 434: * tty interface receiver interrupt. ! 435: */ ! 436: slinput(c, tp) ! 437: register int c; ! 438: register struct tty *tp; ! 439: { ! 440: register struct sl_softc *sc; ! 441: register struct mbuf *m; ! 442: int s; ! 443: ! 444: tk_nin++; ! 445: sc = (struct sl_softc *)tp->t_sc; ! 446: if (sc == NULL) ! 447: return; ! 448: ! 449: c &= 0xff; ! 450: if (sc->sc_flags & SC_ESCAPED) { ! 451: sc->sc_flags &= ~SC_ESCAPED; ! 452: switch (c) { ! 453: ! 454: case TRANS_FRAME_ESCAPE: ! 455: c = FRAME_ESCAPE; ! 456: break; ! 457: ! 458: case TRANS_FRAME_END: ! 459: c = FRAME_END; ! 460: break; ! 461: ! 462: default: ! 463: sc->sc_if.if_ierrors++; ! 464: sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *); ! 465: sc->sc_ilen = 0; ! 466: return; ! 467: } ! 468: } else { ! 469: switch (c) { ! 470: ! 471: case FRAME_END: ! 472: if (sc->sc_ilen == 0) /* ignore */ ! 473: return; ! 474: m = sl_btom(sc, sc->sc_ilen, &sc->sc_if); ! 475: if (m == NULL) { ! 476: sc->sc_if.if_ierrors++; ! 477: return; ! 478: } ! 479: sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *); ! 480: sc->sc_ilen = 0; ! 481: sc->sc_if.if_ipackets++; ! 482: s = splimp(); ! 483: if (IF_QFULL(&ipintrq)) { ! 484: IF_DROP(&ipintrq); ! 485: sc->sc_if.if_ierrors++; ! 486: m_freem(m); ! 487: } else { ! 488: IF_ENQUEUE(&ipintrq, m); ! 489: schednetisr(NETISR_IP); ! 490: } ! 491: splx(s); ! 492: return; ! 493: ! 494: case FRAME_ESCAPE: ! 495: sc->sc_flags |= SC_ESCAPED; ! 496: return; ! 497: } ! 498: } ! 499: if (++sc->sc_ilen > SLMTU) { ! 500: sc->sc_if.if_ierrors++; ! 501: sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *); ! 502: sc->sc_ilen = 0; ! 503: return; ! 504: } ! 505: *sc->sc_mp++ = c; ! 506: } ! 507: ! 508: /* ! 509: * Process an ioctl request. ! 510: */ ! 511: slioctl(ifp, cmd, data) ! 512: register struct ifnet *ifp; ! 513: int cmd; ! 514: caddr_t data; ! 515: { ! 516: register struct ifaddr *ifa = (struct ifaddr *)data; ! 517: int s = splimp(), error = 0; ! 518: ! 519: switch (cmd) { ! 520: ! 521: case SIOCSIFADDR: ! 522: if (ifa->ifa_addr.sa_family == AF_INET) ! 523: ifp->if_flags |= IFF_UP; ! 524: else ! 525: error = EAFNOSUPPORT; ! 526: break; ! 527: ! 528: case SIOCSIFDSTADDR: ! 529: if (ifa->ifa_addr.sa_family != AF_INET) ! 530: error = EAFNOSUPPORT; ! 531: break; ! 532: ! 533: default: ! 534: error = EINVAL; ! 535: } ! 536: splx(s); ! 537: return (error); ! 538: } ! 539: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.