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