1*26378Skarels /* @(#)if_sl.c 5.3 (Berkeley) 02/23/86 */ 226122Skarels 326121Skarels /* 426121Skarels * Serial Line interface 526121Skarels * 626121Skarels * Rick Adams 726121Skarels * Center for Seismic Studies 826121Skarels * 1300 N 17th Street, Suite 1450 926121Skarels * Arlington, Virginia 22209 1026121Skarels * (703)276-7900 1126121Skarels * rick@seismo.ARPA 1226121Skarels * seismo!rick 1326121Skarels * 1426121Skarels * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 15*26378Skarels * N.B.: this belongs in netinet, not net, the way it stands now. 1626122Skarels * Should have a link-layer type designation, but wouldn't be 1726122Skarels * backwards-compatible. 1826121Skarels * 1926121Skarels * Converted to 4.3BSD Beta by Chris Torek. 20*26378Skarels * Other changes made at Berkeley, based in part on code by Kirk Smith. 2126121Skarels */ 2226121Skarels 2326121Skarels /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */ 2426121Skarels /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 2526121Skarels 2626121Skarels #include "sl.h" 2726121Skarels #if NSL > 0 2826121Skarels 2926121Skarels #include "param.h" 3026121Skarels #include "mbuf.h" 3126121Skarels #include "buf.h" 32*26378Skarels #include "dk.h" 3326121Skarels #include "socket.h" 3426121Skarels #include "ioctl.h" 35*26378Skarels #include "file.h" 3626121Skarels #include "tty.h" 3726121Skarels #include "errno.h" 3826121Skarels 39*26378Skarels #include "if.h" 40*26378Skarels #include "netisr.h" 41*26378Skarels #include "route.h" 42*26378Skarels #if INET 4326121Skarels #include "../netinet/in.h" 4426121Skarels #include "../netinet/in_systm.h" 4526121Skarels #include "../netinet/ip.h" 4626121Skarels #include "../netinet/ip_var.h" 47*26378Skarels #endif 4826121Skarels 4926121Skarels #ifdef vax 5026121Skarels #include "../vax/mtpr.h" 5126121Skarels #endif vax 5226121Skarels 5326121Skarels /* 54*26378Skarels * N.B.: SLMTU is now a hard limit on input packet size. 55*26378Skarels * SLMTU must be <= CLBYTES - sizeof(struct ifnet *). 5626121Skarels */ 5726121Skarels #define SLMTU 1006 58*26378Skarels #define SLIP_HIWAT 1000 /* don't start a new packet if HIWAT on queue */ 59*26378Skarels #define CLISTRESERVE 1000 /* Can't let clists get too low */ 6026121Skarels 6126121Skarels struct sl_softc { 6226121Skarels struct ifnet sc_if; /* network-visible interface */ 6326121Skarels short sc_flags; /* see below */ 6426121Skarels short sc_ilen; /* length of input-packet-so-far */ 6526121Skarels struct tty *sc_ttyp; /* pointer to tty structure */ 6626121Skarels char *sc_mp; /* pointer to next available buf char */ 67*26378Skarels char *sc_buf; /* input buffer */ 6826121Skarels } sl_softc[NSL]; 6926121Skarels 7026121Skarels /* flags */ 7126121Skarels #define SC_ESCAPED 0x0001 /* saw a FRAME_ESCAPE */ 7226121Skarels #define SC_OACTIVE 0x0002 /* output tty is active */ 7326121Skarels 7426121Skarels #define FRAME_END 0300 /* Frame End */ 7526121Skarels #define FRAME_ESCAPE 0333 /* Frame Esc */ 7626121Skarels #define TRANS_FRAME_END 0334 /* transposed frame end */ 7726121Skarels #define TRANS_FRAME_ESCAPE 0335 /* transposed frame esc */ 7826121Skarels 7926121Skarels #define t_sc T_LINEP 8026121Skarels 8126121Skarels int sloutput(), slioctl(), ttrstrt(); 8226121Skarels 8326121Skarels /* 8426121Skarels * Called from boot code to establish sl interfaces. 8526121Skarels */ 8626121Skarels slattach() 8726121Skarels { 8826121Skarels register struct sl_softc *sc; 8926121Skarels register int i = 0; 9026121Skarels 9126121Skarels for (sc = sl_softc; i < NSL; sc++) { 9226121Skarels sc->sc_if.if_name = "sl"; 9326121Skarels sc->sc_if.if_unit = i++; 9426121Skarels sc->sc_if.if_mtu = SLMTU; 9526121Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 9626121Skarels sc->sc_if.if_ioctl = slioctl; 9726121Skarels sc->sc_if.if_output = sloutput; 9826121Skarels sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 9926121Skarels if_attach(&sc->sc_if); 10026121Skarels } 10126121Skarels } 10226121Skarels 10326121Skarels /* 10426121Skarels * Line specific open routine. 10526121Skarels * Attach the given tty to the first available sl unit. 10626121Skarels */ 107*26378Skarels /* ARGSUSED */ 10826121Skarels slopen(dev, tp) 10926121Skarels dev_t dev; 11026121Skarels register struct tty *tp; 11126121Skarels { 11226121Skarels register struct sl_softc *sc; 11326121Skarels register int nsl; 11426121Skarels 115*26378Skarels if (!suser()) 116*26378Skarels return (EPERM); 117*26378Skarels if (tp->t_line == SLIPDISC) 11826121Skarels return (EBUSY); 11926121Skarels 12026121Skarels for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++) 12126121Skarels if (sc->sc_ttyp == NULL) { 12226121Skarels sc->sc_flags = 0; 12326121Skarels sc->sc_ilen = 0; 124*26378Skarels if (slinit(sc) == 0) 125*26378Skarels return (ENOBUFS); 12626121Skarels tp->t_sc = (caddr_t)sc; 12726121Skarels sc->sc_ttyp = tp; 128*26378Skarels ttyflush(tp, FREAD | FWRITE); 12926121Skarels return (0); 13026121Skarels } 13126121Skarels 132*26378Skarels return (ENXIO); 13326121Skarels } 13426121Skarels 13526121Skarels /* 13626121Skarels * Line specific close routine. 13726121Skarels * Detach the tty from the sl unit. 13826121Skarels * Mimics part of ttyclose(). 13926121Skarels */ 14026121Skarels slclose(tp) 14126121Skarels struct tty *tp; 14226121Skarels { 14326121Skarels register struct sl_softc *sc; 14426121Skarels int s; 14526121Skarels 14626121Skarels ttywflush(tp); 14726121Skarels tp->t_line = 0; 14826121Skarels s = splimp(); /* paranoid; splnet probably ok */ 14926121Skarels sc = (struct sl_softc *)tp->t_sc; 15026121Skarels if (sc != NULL) { 15126121Skarels if_down(&sc->sc_if); 15226121Skarels sc->sc_ttyp = NULL; 15326121Skarels tp->t_sc = NULL; 154*26378Skarels MCLFREE((struct mbuf *)sc->sc_buf); 155*26378Skarels sc->sc_buf = 0; 15626121Skarels } 15726121Skarels splx(s); 15826121Skarels } 15926121Skarels 16026121Skarels /* 16126121Skarels * Line specific (tty) ioctl routine. 16226121Skarels * Provide a way to get the sl unit number. 16326121Skarels */ 164*26378Skarels /* ARGSUSED */ 16526121Skarels sltioctl(tp, cmd, data, flag) 16626121Skarels struct tty *tp; 16726121Skarels caddr_t data; 16826121Skarels { 16926121Skarels 17026121Skarels if (cmd == TIOCGETD) { 17126121Skarels *(int *)data = ((struct sl_softc *)tp->t_sc)->sc_if.if_unit; 17226121Skarels return (0); 17326121Skarels } 17426121Skarels return (-1); 17526121Skarels } 17626121Skarels 17726121Skarels /* 17826121Skarels * Queue a packet. Start transmission if not active. 17926121Skarels */ 18026121Skarels sloutput(ifp, m, dst) 18126121Skarels register struct ifnet *ifp; 18226121Skarels register struct mbuf *m; 18326121Skarels struct sockaddr *dst; 18426121Skarels { 18526121Skarels register struct sl_softc *sc; 18626121Skarels int s; 18726121Skarels 18826121Skarels /* 18926121Skarels * `Cannot happen' (see slioctl). Someday we will extend 19026121Skarels * the line protocol to support other address families. 19126121Skarels */ 19226121Skarels if (dst->sa_family != AF_INET) { 19326121Skarels printf("sl%d: af%d not supported\n", ifp->if_unit, 19426121Skarels dst->sa_family); 19526121Skarels m_freem(m); 19626121Skarels return (EAFNOSUPPORT); 19726121Skarels } 19826121Skarels 19926121Skarels sc = &sl_softc[ifp->if_unit]; 20026121Skarels if (sc->sc_ttyp == NULL) { 20126121Skarels m_freem(m); 20226121Skarels return (ENETDOWN); /* sort of */ 20326121Skarels } 20426121Skarels s = splimp(); 20526121Skarels if (IF_QFULL(&ifp->if_snd)) { 20626121Skarels IF_DROP(&ifp->if_snd); 20726121Skarels splx(s); 20826121Skarels m_freem(m); 209*26378Skarels sc->sc_if.if_oerrors++; 21026121Skarels return (ENOBUFS); 21126121Skarels } 21226121Skarels IF_ENQUEUE(&ifp->if_snd, m); 21326121Skarels if ((sc->sc_flags & SC_OACTIVE) == 0) { 21426121Skarels splx(s); 21526121Skarels slstart(sc->sc_ttyp); 21626121Skarels } else 21726121Skarels splx(s); 21826121Skarels return (0); 21926121Skarels } 22026121Skarels 22126121Skarels /* 22226121Skarels * Start output on interface. Get another datagram 22326121Skarels * to send from the interface queue and map it to 22426121Skarels * the interface before starting output. 22526121Skarels */ 22626121Skarels slstart(tp) 22726121Skarels register struct tty *tp; 22826121Skarels { 22926121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 23026121Skarels register struct mbuf *m; 231*26378Skarels register int len; 232*26378Skarels register u_char *cp; 233*26378Skarels int flush, nd, np, n, s; 234*26378Skarels struct mbuf *m2; 235*26378Skarels extern int cfreecount; 23626121Skarels 237*26378Skarels for (;;) { 238*26378Skarels /* 239*26378Skarels * If there is more in the output queue, just send it now. 240*26378Skarels * We are being called in lieu of ttstart and must do what 241*26378Skarels * it would. 242*26378Skarels */ 243*26378Skarels if (tp->t_outq.c_cc > 0) 244*26378Skarels ttstart(tp); 245*26378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 246*26378Skarels return; 24726121Skarels 248*26378Skarels /* 249*26378Skarels * This happens briefly when the line shuts down. 250*26378Skarels */ 251*26378Skarels if (sc == NULL) 252*26378Skarels return; 25326121Skarels 254*26378Skarels /* 255*26378Skarels * If system is getting low on clists 256*26378Skarels * and we have something running already, stop here. 257*26378Skarels */ 258*26378Skarels if (cfreecount < CLISTRESERVE + SLMTU && 259*26378Skarels sc->sc_flags & SC_OACTIVE) 260*26378Skarels return; 26126121Skarels 262*26378Skarels /* 263*26378Skarels * Get a packet and send it to the interface. 264*26378Skarels */ 265*26378Skarels s = splimp(); 266*26378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 267*26378Skarels if (m == NULL) { 268*26378Skarels if (tp->t_outq.c_cc == 0) 269*26378Skarels sc->sc_flags &= ~SC_OACTIVE; 270*26378Skarels splx(s); 271*26378Skarels return; 272*26378Skarels } 273*26378Skarels flush = !(sc->sc_flags & SC_OACTIVE); 274*26378Skarels sc->sc_flags |= SC_OACTIVE; 275*26378Skarels splx(s); 27626121Skarels 277*26378Skarels /* 278*26378Skarels * The extra FRAME_END will start up a new packet, and thus 279*26378Skarels * will flush any accumulated garbage. We do this whenever 280*26378Skarels * the line may have been idle for some time. 281*26378Skarels */ 282*26378Skarels if (flush) 283*26378Skarels (void) putc(FRAME_END, &tp->t_outq); 284*26378Skarels 285*26378Skarels while (m) { 286*26378Skarels cp = mtod(m, u_char *); 287*26378Skarels len = m->m_len; 288*26378Skarels while (len > 0) { 289*26378Skarels /* 290*26378Skarels * Find out how many bytes in the string we can 291*26378Skarels * handle without doing something special. 292*26378Skarels */ 293*26378Skarels nd = locc(FRAME_ESCAPE, len, cp); 294*26378Skarels np = locc(FRAME_END, len, cp); 295*26378Skarels n = len - MAX(nd, np); 296*26378Skarels if (n) { 297*26378Skarels /* 298*26378Skarels * Put n characters at once 299*26378Skarels * into the tty output queue. 300*26378Skarels */ 301*26378Skarels if (b_to_q((char *)cp, n, &tp->t_outq)) 302*26378Skarels break; 30326121Skarels } 304*26378Skarels /* 305*26378Skarels * If there are characters left in the mbuf, 306*26378Skarels * the first one must be special.. 307*26378Skarels * Put it out in a different form. 308*26378Skarels */ 309*26378Skarels if (len) { 310*26378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 311*26378Skarels break; 312*26378Skarels if (putc(*cp == FRAME_ESCAPE ? 313*26378Skarels TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 314*26378Skarels &tp->t_outq)) { 315*26378Skarels (void) unputc(&tp->t_outq); 316*26378Skarels break; 317*26378Skarels } 318*26378Skarels cp++; 319*26378Skarels len--; 320*26378Skarels } 321*26378Skarels } 322*26378Skarels MFREE(m, m2); 323*26378Skarels m = m2; 32426121Skarels } 325*26378Skarels 326*26378Skarels if (putc(FRAME_END, &tp->t_outq)) { 327*26378Skarels /* 328*26378Skarels * Not enough room. Remove a char to make room 329*26378Skarels * and end the packet normally. 330*26378Skarels * If you get many collisions (more than one or two 331*26378Skarels * a day) you probably do not have enough clists 332*26378Skarels * and you should increase "nclist" in param.c. 333*26378Skarels */ 334*26378Skarels (void) unputc(&tp->t_outq); 335*26378Skarels (void) putc(FRAME_END, &tp->t_outq); 336*26378Skarels sc->sc_if.if_collisions++; 337*26378Skarels } else 338*26378Skarels sc->sc_if.if_opackets++; 33926121Skarels } 340*26378Skarels } 34126121Skarels 342*26378Skarels slinit(sc) 343*26378Skarels register struct sl_softc *sc; 344*26378Skarels { 345*26378Skarels struct mbuf *p; 34626121Skarels 347*26378Skarels if (sc->sc_buf == (char *) 0) { 348*26378Skarels MCLALLOC(p, 1); 349*26378Skarels if (p) { 350*26378Skarels sc->sc_buf = (char *)p; 351*26378Skarels sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *); 352*26378Skarels } else { 353*26378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 354*26378Skarels sc->sc_if.if_flags &= ~IFF_UP; 355*26378Skarels return (0); 356*26378Skarels } 357*26378Skarels } 358*26378Skarels return (1); 35926121Skarels } 36026121Skarels 36126121Skarels /* 36226121Skarels * Copy data buffer to mbuf chain; add ifnet pointer ifp. 36326121Skarels */ 36426121Skarels struct mbuf * 365*26378Skarels sl_btom(sc, len, ifp) 366*26378Skarels struct sl_softc *sc; 36726121Skarels register int len; 36826121Skarels struct ifnet *ifp; 36926121Skarels { 370*26378Skarels register caddr_t cp; 37126121Skarels register struct mbuf *m, **mp; 372*26378Skarels register unsigned count; 37326121Skarels struct mbuf *top = NULL; 37426121Skarels 375*26378Skarels cp = sc->sc_buf + sizeof(struct ifnet *); 37626121Skarels mp = ⊤ 37726121Skarels while (len > 0) { 37826121Skarels MGET(m, M_DONTWAIT, MT_DATA); 37926121Skarels if ((*mp = m) == NULL) { 38026121Skarels m_freem(top); 38126121Skarels return (NULL); 38226121Skarels } 383*26378Skarels if (ifp) 38426121Skarels m->m_off += sizeof(ifp); 385*26378Skarels /* 386*26378Skarels * If we have at least NBPG bytes, 387*26378Skarels * allocate a new page. Swap the current buffer page 388*26378Skarels * with the new one. We depend on having a space 389*26378Skarels * left at the beginning of the buffer 390*26378Skarels * for the interface pointer. 391*26378Skarels */ 392*26378Skarels if (len >= NBPG) { 393*26378Skarels MCLGET(m); 394*26378Skarels if (m->m_len == CLBYTES) { 395*26378Skarels cp = mtod(m, char *); 396*26378Skarels m->m_off = (int)sc->sc_buf - (int)m; 397*26378Skarels sc->sc_buf = mtod(m, char *); 398*26378Skarels if (ifp) { 399*26378Skarels m->m_off += sizeof(ifp); 400*26378Skarels count = MIN(len, 401*26378Skarels CLBYTES - sizeof(struct ifnet *)); 402*26378Skarels } else 40326121Skarels count = MIN(len, CLBYTES); 404*26378Skarels goto nocopy; 405*26378Skarels } 40626121Skarels } 407*26378Skarels if (ifp) 408*26378Skarels count = MIN(len, MLEN - sizeof(ifp)); 409*26378Skarels else 410*26378Skarels count = MIN(len, MLEN); 411*26378Skarels bcopy(cp, mtod(m, caddr_t), count); 412*26378Skarels nocopy: 41326121Skarels m->m_len = count; 41426121Skarels if (ifp) { 41526121Skarels m->m_off -= sizeof(ifp); 41626121Skarels m->m_len += sizeof(ifp); 41726121Skarels *mtod(m, struct ifnet **) = ifp; 41826121Skarels ifp = NULL; 41926121Skarels } 420*26378Skarels cp += count; 42126121Skarels len -= count; 42226121Skarels mp = &m->m_next; 42326121Skarels } 42426121Skarels return (top); 42526121Skarels } 42626121Skarels 42726121Skarels /* 42826121Skarels * tty interface receiver interrupt. 42926121Skarels */ 43026121Skarels slinput(c, tp) 43126121Skarels register int c; 43226121Skarels register struct tty *tp; 43326121Skarels { 43426121Skarels register struct sl_softc *sc; 43526121Skarels register struct mbuf *m; 43626121Skarels int s; 43726121Skarels 438*26378Skarels tk_nin++; 43926121Skarels sc = (struct sl_softc *)tp->t_sc; 44026121Skarels if (sc == NULL) 44126121Skarels return; 44226121Skarels 44326121Skarels c &= 0xff; 44426121Skarels if (sc->sc_flags & SC_ESCAPED) { 44526121Skarels sc->sc_flags &= ~SC_ESCAPED; 44626121Skarels switch (c) { 44726121Skarels 44826121Skarels case TRANS_FRAME_ESCAPE: 44926121Skarels c = FRAME_ESCAPE; 45026121Skarels break; 45126121Skarels 45226121Skarels case TRANS_FRAME_END: 45326121Skarels c = FRAME_END; 45426121Skarels break; 45526121Skarels 45626121Skarels default: 45726121Skarels sc->sc_if.if_ierrors++; 458*26378Skarels sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *); 45926121Skarels sc->sc_ilen = 0; 46026121Skarels return; 46126121Skarels } 46226121Skarels } else { 46326121Skarels switch (c) { 46426121Skarels 46526121Skarels case FRAME_END: 46626121Skarels if (sc->sc_ilen == 0) /* ignore */ 46726121Skarels return; 468*26378Skarels m = sl_btom(sc, sc->sc_ilen, &sc->sc_if); 46926121Skarels if (m == NULL) { 47026121Skarels sc->sc_if.if_ierrors++; 47126121Skarels return; 47226121Skarels } 473*26378Skarels sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *); 47426121Skarels sc->sc_ilen = 0; 47526121Skarels sc->sc_if.if_ipackets++; 47626121Skarels s = splimp(); 47726121Skarels if (IF_QFULL(&ipintrq)) { 47826121Skarels IF_DROP(&ipintrq); 47926121Skarels sc->sc_if.if_ierrors++; 48026121Skarels m_freem(m); 48126121Skarels } else { 48226121Skarels IF_ENQUEUE(&ipintrq, m); 48326121Skarels schednetisr(NETISR_IP); 48426121Skarels } 48526121Skarels splx(s); 48626121Skarels return; 48726121Skarels 48826121Skarels case FRAME_ESCAPE: 48926121Skarels sc->sc_flags |= SC_ESCAPED; 49026121Skarels return; 49126121Skarels } 49226121Skarels } 49326121Skarels if (++sc->sc_ilen >= SLMTU) { 49426121Skarels sc->sc_if.if_ierrors++; 495*26378Skarels sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *); 49626121Skarels sc->sc_ilen = 0; 49726121Skarels return; 49826121Skarels } 49926121Skarels *sc->sc_mp++ = c; 50026121Skarels } 50126121Skarels 50226121Skarels /* 50326121Skarels * Process an ioctl request. 50426121Skarels */ 50526121Skarels slioctl(ifp, cmd, data) 50626121Skarels register struct ifnet *ifp; 50726121Skarels int cmd; 50826121Skarels caddr_t data; 50926121Skarels { 51026121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 51126121Skarels int s = splimp(), error = 0; 51226121Skarels 51326121Skarels switch (cmd) { 51426121Skarels 51526121Skarels case SIOCSIFADDR: 51626121Skarels if (ifa->ifa_addr.sa_family == AF_INET) 51726121Skarels ifp->if_flags |= IFF_UP; 51826121Skarels else 51926121Skarels error = EAFNOSUPPORT; 52026121Skarels break; 52126121Skarels 52226121Skarels case SIOCSIFDSTADDR: 52326121Skarels if (ifa->ifa_addr.sa_family != AF_INET) 52426121Skarels error = EAFNOSUPPORT; 52526121Skarels break; 52626121Skarels 52726121Skarels default: 52826121Skarels error = EINVAL; 52926121Skarels } 53026121Skarels splx(s); 53126121Skarels return (error); 53226121Skarels } 53326121Skarels #endif 534