1*26122Skarels /* @(#)if_sl.c 5.2 (Berkeley) 02/09/86 */ 2*26122Skarels 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 * Some things done here could obviously be done in a better way, 1526121Skarels * but they were done this way to minimize the number of files 1626121Skarels * that had to be changed to accomodate this device. 1726121Skarels * 1826121Skarels * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 1926121Skarels * N.B.: this belongs in netinet, not vaxif, the way it stands now. 20*26122Skarels * Should have a link-layer type designation, but wouldn't be 21*26122Skarels * backwards-compatible. 2226121Skarels * 2326121Skarels * Converted to 4.3BSD Beta by Chris Torek. 2426121Skarels */ 2526121Skarels 2626121Skarels /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */ 2726121Skarels /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 2826121Skarels 2926121Skarels #include "sl.h" 3026121Skarels #if NSL > 0 3126121Skarels 3226121Skarels #include "param.h" 3326121Skarels #include "mbuf.h" 3426121Skarels #include "buf.h" 3526121Skarels #include "socket.h" 3626121Skarels #include "ioctl.h" 3726121Skarels #include "tty.h" 3826121Skarels #include "errno.h" 3926121Skarels 4026121Skarels #include "../net/if.h" 4126121Skarels #include "../net/netisr.h" 4226121Skarels #include "../net/route.h" 4326121Skarels #include "../netinet/in.h" 4426121Skarels #include "../netinet/in_systm.h" 4526121Skarels #include "../netinet/ip.h" 4626121Skarels #include "../netinet/ip_var.h" 4726121Skarels 4826121Skarels #ifdef vax 4926121Skarels #include "../vax/mtpr.h" 5026121Skarels #endif vax 5126121Skarels 5226121Skarels /* 5326121Skarels * N.B.: SLMTU is now a hard limit on input packet size. Some limit 5426121Skarels * is required, lest we use up all mbufs in the case of deleterious data 5526121Skarels * dribbling down the line. 5626121Skarels */ 5726121Skarels #define SLMTU 1006 5826121Skarels 5926121Skarels struct sl_softc { 6026121Skarels struct ifnet sc_if; /* network-visible interface */ 6126121Skarels short sc_flags; /* see below */ 6226121Skarels short sc_ilen; /* length of input-packet-so-far */ 6326121Skarels struct tty *sc_ttyp; /* pointer to tty structure */ 6426121Skarels char *sc_mp; /* pointer to next available buf char */ 6526121Skarels char sc_buf[SLMTU]; /* input buffer */ 6626121Skarels } sl_softc[NSL]; 6726121Skarels 6826121Skarels /* flags */ 6926121Skarels #define SC_ESCAPED 0x0001 /* saw a FRAME_ESCAPE */ 7026121Skarels #define SC_OACTIVE 0x0002 /* output tty is active */ 7126121Skarels 7226121Skarels #define FRAME_END 0300 /* Frame End */ 7326121Skarels #define FRAME_ESCAPE 0333 /* Frame Esc */ 7426121Skarels #define TRANS_FRAME_END 0334 /* transposed frame end */ 7526121Skarels #define TRANS_FRAME_ESCAPE 0335 /* transposed frame esc */ 7626121Skarels 7726121Skarels #define t_sc T_LINEP 7826121Skarels 7926121Skarels int sloutput(), slioctl(), ttrstrt(); 8026121Skarels 8126121Skarels /* 8226121Skarels * Called from boot code to establish sl interfaces. 8326121Skarels */ 8426121Skarels slattach() 8526121Skarels { 8626121Skarels register struct sl_softc *sc; 8726121Skarels register int i = 0; 8826121Skarels 8926121Skarels for (sc = sl_softc; i < NSL; sc++) { 9026121Skarels sc->sc_if.if_name = "sl"; 9126121Skarels sc->sc_if.if_unit = i++; 9226121Skarels sc->sc_if.if_mtu = SLMTU; 9326121Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 9426121Skarels sc->sc_if.if_ioctl = slioctl; 9526121Skarels sc->sc_if.if_output = sloutput; 9626121Skarels sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 9726121Skarels if_attach(&sc->sc_if); 9826121Skarels } 9926121Skarels } 10026121Skarels 10126121Skarels /* 10226121Skarels * Line specific open routine. 10326121Skarels * Attach the given tty to the first available sl unit. 10426121Skarels */ 10526121Skarels slopen(dev, tp) 10626121Skarels dev_t dev; 10726121Skarels register struct tty *tp; 10826121Skarels { 10926121Skarels register struct sl_softc *sc; 11026121Skarels register int nsl; 11126121Skarels 11226121Skarels if (tp->t_sc != NULL) 11326121Skarels return (EBUSY); 11426121Skarels 11526121Skarels for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++) 11626121Skarels if (sc->sc_ttyp == NULL) { 11726121Skarels sc->sc_flags = 0; 11826121Skarels sc->sc_ilen = 0; 11926121Skarels sc->sc_mp = sc->sc_buf; 12026121Skarels tp->t_sc = (caddr_t)sc; 12126121Skarels sc->sc_ttyp = tp; 12226121Skarels return (0); 12326121Skarels } 12426121Skarels 12526121Skarels return (ENOSPC); 12626121Skarels } 12726121Skarels 12826121Skarels /* 12926121Skarels * Line specific close routine. 13026121Skarels * Detach the tty from the sl unit. 13126121Skarels * Mimics part of ttyclose(). 13226121Skarels */ 13326121Skarels slclose(tp) 13426121Skarels struct tty *tp; 13526121Skarels { 13626121Skarels register struct sl_softc *sc; 13726121Skarels int s; 13826121Skarels 13926121Skarels ttywflush(tp); 14026121Skarels tp->t_line = 0; 14126121Skarels s = splimp(); /* paranoid; splnet probably ok */ 14226121Skarels sc = (struct sl_softc *)tp->t_sc; 14326121Skarels if (sc != NULL) { 14426121Skarels if_down(&sc->sc_if); 14526121Skarels sc->sc_ttyp = NULL; 14626121Skarels tp->t_sc = NULL; 14726121Skarels } 14826121Skarels splx(s); 14926121Skarels } 15026121Skarels 15126121Skarels /* 15226121Skarels * Line specific (tty) ioctl routine. 15326121Skarels * Provide a way to get the sl unit number. 15426121Skarels */ 15526121Skarels sltioctl(tp, cmd, data, flag) 15626121Skarels struct tty *tp; 15726121Skarels caddr_t data; 15826121Skarels { 15926121Skarels 16026121Skarels if (cmd == TIOCGETD) { 16126121Skarels *(int *)data = ((struct sl_softc *)tp->t_sc)->sc_if.if_unit; 16226121Skarels return (0); 16326121Skarels } 16426121Skarels return (-1); 16526121Skarels } 16626121Skarels 16726121Skarels /* 16826121Skarels * Queue a packet. Start transmission if not active. 16926121Skarels */ 17026121Skarels sloutput(ifp, m, dst) 17126121Skarels register struct ifnet *ifp; 17226121Skarels register struct mbuf *m; 17326121Skarels struct sockaddr *dst; 17426121Skarels { 17526121Skarels register struct sl_softc *sc; 17626121Skarels int s; 17726121Skarels 17826121Skarels /* 17926121Skarels * `Cannot happen' (see slioctl). Someday we will extend 18026121Skarels * the line protocol to support other address families. 18126121Skarels */ 18226121Skarels if (dst->sa_family != AF_INET) { 18326121Skarels printf("sl%d: af%d not supported\n", ifp->if_unit, 18426121Skarels dst->sa_family); 18526121Skarels m_freem(m); 18626121Skarels return (EAFNOSUPPORT); 18726121Skarels } 18826121Skarels 18926121Skarels sc = &sl_softc[ifp->if_unit]; 19026121Skarels if (sc->sc_ttyp == NULL) { 19126121Skarels m_freem(m); 19226121Skarels return (ENETDOWN); /* sort of */ 19326121Skarels } 19426121Skarels s = splimp(); 19526121Skarels if (IF_QFULL(&ifp->if_snd)) { 19626121Skarels IF_DROP(&ifp->if_snd); 19726121Skarels splx(s); 19826121Skarels m_freem(m); 19926121Skarels sc->sc_if.if_collisions++; 20026121Skarels return (ENOBUFS); 20126121Skarels } 20226121Skarels IF_ENQUEUE(&ifp->if_snd, m); 20326121Skarels if ((sc->sc_flags & SC_OACTIVE) == 0) { 20426121Skarels splx(s); 20526121Skarels slstart(sc->sc_ttyp); 20626121Skarels } else 20726121Skarels splx(s); 20826121Skarels return (0); 20926121Skarels } 21026121Skarels 21126121Skarels /* 21226121Skarels * Start output on interface. Get another datagram 21326121Skarels * to send from the interface queue and map it to 21426121Skarels * the interface before starting output. 21526121Skarels */ 21626121Skarels slstart(tp) 21726121Skarels register struct tty *tp; 21826121Skarels { 21926121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 22026121Skarels register struct mbuf *m; 22126121Skarels register int c, len; 22226121Skarels register u_char *mcp; 22326121Skarels int flush; 22426121Skarels 22526121Skarels /* 22626121Skarels * If there is more in the output queue, just send it now. 22726121Skarels * We are being called in lieu of ttstart and must do what 22826121Skarels * it would. 22926121Skarels */ 23026121Skarels if (tp->t_outq.c_cc > 0) { 23126121Skarels ttstart(tp); 23226121Skarels return; 23326121Skarels } 23426121Skarels 23526121Skarels /* 23626121Skarels * This happens briefly when the line shuts down. 23726121Skarels */ 23826121Skarels if (sc == NULL) 23926121Skarels return; 24026121Skarels 24126121Skarels /* 24226121Skarels * Get a packet and map it to the interface. 24326121Skarels */ 24426121Skarels c = splimp(); 24526121Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 24626121Skarels if (m == NULL) { 24726121Skarels sc->sc_flags &= ~SC_OACTIVE; 24826121Skarels splx(c); 24926121Skarels return; 25026121Skarels } 25126121Skarels flush = !(sc->sc_flags & SC_OACTIVE); 25226121Skarels sc->sc_flags |= SC_OACTIVE; 25326121Skarels splx(c); 25426121Skarels 25526121Skarels /* 25626121Skarels * The extra FRAME_END will start up a new packet, and thus 25726121Skarels * will flush any accumulated garbage. We do this whenever 25826121Skarels * the line may have been idle for some time. 25926121Skarels */ 26026121Skarels if (flush) 26126121Skarels (void) putc(FRAME_END, &tp->t_outq); 26226121Skarels 26326121Skarels while (m != NULL) { 26426121Skarels len = m->m_len; 26526121Skarels mcp = mtod(m, u_char *); 26626121Skarels while (--len >= 0) { 26726121Skarels c = *mcp++; 26826121Skarels if (c == FRAME_ESCAPE || c == FRAME_END) { 26926121Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 27026121Skarels goto full; 27126121Skarels c = c == FRAME_ESCAPE ? TRANS_FRAME_ESCAPE : 27226121Skarels TRANS_FRAME_END; 27326121Skarels if (putc(c, &tp->t_outq)) { 27426121Skarels (void) unputc(&tp->t_outq); 27526121Skarels goto full; 27626121Skarels } 27726121Skarels } else 27826121Skarels if (putc(c, &tp->t_outq)) 27926121Skarels goto full; 28026121Skarels } 28126121Skarels m = m_free(m); 28226121Skarels } 28326121Skarels 28426121Skarels if (putc(FRAME_END, &tp->t_outq)) { 28526121Skarels full: 28626121Skarels /* 28726121Skarels * If you get many oerrors (more than one or two a day) 28826121Skarels * you probably do not have enough clists and you should 28926121Skarels * increase "nclist" in param.c. 29026121Skarels */ 29126121Skarels (void) unputc(&tp->t_outq); /* make room */ 29226121Skarels putc(FRAME_END, &tp->t_outq); /* end the packet */ 29326121Skarels sc->sc_if.if_oerrors++; 29426121Skarels } else 29526121Skarels sc->sc_if.if_opackets++; 29626121Skarels 29726121Skarels /* 29826121Skarels * Start transmission. Note that slstart, not ttstart, will be 29926121Skarels * called when the transmission completes, be that after a single 30026121Skarels * piece of what we have mapped, or be it after the entire thing 30126121Skarels * has been sent. That is why we need to check the output queue 30226121Skarels * count at the top. 30326121Skarels */ 30426121Skarels ttstart(tp); 30526121Skarels } 30626121Skarels 30726121Skarels /* 30826121Skarels * Copy data buffer to mbuf chain; add ifnet pointer ifp. 30926121Skarels */ 31026121Skarels struct mbuf * 31126121Skarels sl_btom(addr, len, ifp) 31226121Skarels register caddr_t addr; 31326121Skarels register int len; 31426121Skarels struct ifnet *ifp; 31526121Skarels { 31626121Skarels register struct mbuf *m, **mp; 31726121Skarels register int count; 31826121Skarels struct mbuf *top = NULL; 31926121Skarels 32026121Skarels mp = ⊤ 32126121Skarels while (len > 0) { 32226121Skarels MGET(m, M_DONTWAIT, MT_DATA); 32326121Skarels if ((*mp = m) == NULL) { 32426121Skarels m_freem(top); 32526121Skarels return (NULL); 32626121Skarels } 32726121Skarels if (ifp) { 32826121Skarels m->m_off += sizeof(ifp); 32926121Skarels count = MIN(len, MLEN - sizeof(ifp)); 33026121Skarels } else { 33126121Skarels if (len >= NBPG) { 33226121Skarels struct mbuf *p; 33326121Skarels 33426121Skarels MCLGET(p, 1); 33526121Skarels if (p != NULL) { 33626121Skarels count = MIN(len, CLBYTES); 33726121Skarels m->m_off = (int)p - (int)m; 33826121Skarels } else 33926121Skarels count = MIN(len, MLEN); 34026121Skarels } else 34126121Skarels count = MIN(len, MLEN); 34226121Skarels } 34326121Skarels bcopy(addr, mtod(m, caddr_t), count); 34426121Skarels m->m_len = count; 34526121Skarels if (ifp) { 34626121Skarels m->m_off -= sizeof(ifp); 34726121Skarels m->m_len += sizeof(ifp); 34826121Skarels *mtod(m, struct ifnet **) = ifp; 34926121Skarels ifp = NULL; 35026121Skarels } 35126121Skarels addr += count; 35226121Skarels len -= count; 35326121Skarels mp = &m->m_next; 35426121Skarels } 35526121Skarels return (top); 35626121Skarels } 35726121Skarels 35826121Skarels /* 35926121Skarels * tty interface receiver interrupt. 36026121Skarels */ 36126121Skarels slinput(c, tp) 36226121Skarels register int c; 36326121Skarels register struct tty *tp; 36426121Skarels { 36526121Skarels register struct sl_softc *sc; 36626121Skarels register struct mbuf *m; 36726121Skarels int s; 36826121Skarels 36926121Skarels sc = (struct sl_softc *)tp->t_sc; 37026121Skarels if (sc == NULL) 37126121Skarels return; 37226121Skarels 37326121Skarels c &= 0xff; 37426121Skarels if (sc->sc_flags & SC_ESCAPED) { 37526121Skarels sc->sc_flags &= ~SC_ESCAPED; 37626121Skarels switch (c) { 37726121Skarels 37826121Skarels case TRANS_FRAME_ESCAPE: 37926121Skarels c = FRAME_ESCAPE; 38026121Skarels break; 38126121Skarels 38226121Skarels case TRANS_FRAME_END: 38326121Skarels c = FRAME_END; 38426121Skarels break; 38526121Skarels 38626121Skarels default: 38726121Skarels sc->sc_if.if_ierrors++; 38826121Skarels sc->sc_mp = sc->sc_buf; 38926121Skarels sc->sc_ilen = 0; 39026121Skarels return; 39126121Skarels } 39226121Skarels } else { 39326121Skarels switch (c) { 39426121Skarels 39526121Skarels case FRAME_END: 39626121Skarels if (sc->sc_ilen == 0) /* ignore */ 39726121Skarels return; 39826121Skarels m = sl_btom(sc->sc_buf, sc->sc_ilen, &sc->sc_if); 39926121Skarels if (m == NULL) { 40026121Skarels sc->sc_if.if_ierrors++; 40126121Skarels return; 40226121Skarels } 40326121Skarels sc->sc_mp = sc->sc_buf; 40426121Skarels sc->sc_ilen = 0; 40526121Skarels sc->sc_if.if_ipackets++; 40626121Skarels s = splimp(); 40726121Skarels if (IF_QFULL(&ipintrq)) { 40826121Skarels IF_DROP(&ipintrq); 40926121Skarels sc->sc_if.if_ierrors++; 41026121Skarels m_freem(m); 41126121Skarels } else { 41226121Skarels IF_ENQUEUE(&ipintrq, m); 41326121Skarels schednetisr(NETISR_IP); 41426121Skarels } 41526121Skarels splx(s); 41626121Skarels return; 41726121Skarels 41826121Skarels case FRAME_ESCAPE: 41926121Skarels sc->sc_flags |= SC_ESCAPED; 42026121Skarels return; 42126121Skarels } 42226121Skarels } 42326121Skarels if (++sc->sc_ilen >= SLMTU) { 42426121Skarels sc->sc_if.if_ierrors++; 42526121Skarels sc->sc_mp = sc->sc_buf; 42626121Skarels sc->sc_ilen = 0; 42726121Skarels return; 42826121Skarels } 42926121Skarels *sc->sc_mp++ = c; 43026121Skarels } 43126121Skarels 43226121Skarels /* 43326121Skarels * Process an ioctl request. 43426121Skarels */ 43526121Skarels slioctl(ifp, cmd, data) 43626121Skarels register struct ifnet *ifp; 43726121Skarels int cmd; 43826121Skarels caddr_t data; 43926121Skarels { 44026121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 44126121Skarels int s = splimp(), error = 0; 44226121Skarels 44326121Skarels switch (cmd) { 44426121Skarels 44526121Skarels case SIOCSIFADDR: 44626121Skarels if (ifa->ifa_addr.sa_family == AF_INET) 44726121Skarels ifp->if_flags |= IFF_UP; 44826121Skarels else 44926121Skarels error = EAFNOSUPPORT; 45026121Skarels break; 45126121Skarels 45226121Skarels case SIOCSIFDSTADDR: 45326121Skarels if (ifa->ifa_addr.sa_family != AF_INET) 45426121Skarels error = EAFNOSUPPORT; 45526121Skarels break; 45626121Skarels 45726121Skarels default: 45826121Skarels error = EINVAL; 45926121Skarels } 46026121Skarels splx(s); 46126121Skarels return (error); 46226121Skarels } 46326121Skarels #endif 464