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: * rick@seismo.ARPA 12: * seismo!rick 13: * 14: * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, 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