1*26121Skarels /* 2*26121Skarels * Serial Line interface 3*26121Skarels * 4*26121Skarels * Rick Adams 5*26121Skarels * Center for Seismic Studies 6*26121Skarels * 1300 N 17th Street, Suite 1450 7*26121Skarels * Arlington, Virginia 22209 8*26121Skarels * (703)276-7900 9*26121Skarels * rick@seismo.ARPA 10*26121Skarels * seismo!rick 11*26121Skarels * 12*26121Skarels * Some things done here could obviously be done in a better way, 13*26121Skarels * but they were done this way to minimize the number of files 14*26121Skarels * that had to be changed to accomodate this device. 15*26121Skarels * A lot of this code belongs in the tty driver. 16*26121Skarels * 17*26121Skarels * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 18*26121Skarels * N.B.: this belongs in netinet, not vaxif, the way it stands now. 19*26121Skarels * 20*26121Skarels * Converted to 4.3BSD Beta by Chris Torek. 21*26121Skarels */ 22*26121Skarels 23*26121Skarels /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */ 24*26121Skarels /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 25*26121Skarels 26*26121Skarels #include "sl.h" 27*26121Skarels #if NSL > 0 28*26121Skarels 29*26121Skarels #include "param.h" 30*26121Skarels #include "mbuf.h" 31*26121Skarels #include "buf.h" 32*26121Skarels #include "socket.h" 33*26121Skarels #include "ioctl.h" 34*26121Skarels #include "tty.h" 35*26121Skarels #include "errno.h" 36*26121Skarels 37*26121Skarels #include "../net/if.h" 38*26121Skarels #include "../net/netisr.h" 39*26121Skarels #include "../net/route.h" 40*26121Skarels #include "../netinet/in.h" 41*26121Skarels #include "../netinet/in_systm.h" 42*26121Skarels #include "../netinet/ip.h" 43*26121Skarels #include "../netinet/ip_var.h" 44*26121Skarels 45*26121Skarels #ifdef vax 46*26121Skarels #include "../vax/mtpr.h" 47*26121Skarels #endif vax 48*26121Skarels 49*26121Skarels /* 50*26121Skarels * N.B.: SLMTU is now a hard limit on input packet size. Some limit 51*26121Skarels * is required, lest we use up all mbufs in the case of deleterious data 52*26121Skarels * dribbling down the line. 53*26121Skarels */ 54*26121Skarels #define SLMTU 1006 55*26121Skarels 56*26121Skarels struct sl_softc { 57*26121Skarels struct ifnet sc_if; /* network-visible interface */ 58*26121Skarels short sc_flags; /* see below */ 59*26121Skarels short sc_ilen; /* length of input-packet-so-far */ 60*26121Skarels struct tty *sc_ttyp; /* pointer to tty structure */ 61*26121Skarels char *sc_mp; /* pointer to next available buf char */ 62*26121Skarels char sc_buf[SLMTU]; /* input buffer */ 63*26121Skarels } sl_softc[NSL]; 64*26121Skarels 65*26121Skarels /* flags */ 66*26121Skarels #define SC_ESCAPED 0x0001 /* saw a FRAME_ESCAPE */ 67*26121Skarels #define SC_OACTIVE 0x0002 /* output tty is active */ 68*26121Skarels 69*26121Skarels #define FRAME_END 0300 /* Frame End */ 70*26121Skarels #define FRAME_ESCAPE 0333 /* Frame Esc */ 71*26121Skarels #define TRANS_FRAME_END 0334 /* transposed frame end */ 72*26121Skarels #define TRANS_FRAME_ESCAPE 0335 /* transposed frame esc */ 73*26121Skarels 74*26121Skarels #define t_sc T_LINEP 75*26121Skarels 76*26121Skarels int sloutput(), slioctl(), ttrstrt(); 77*26121Skarels 78*26121Skarels /* 79*26121Skarels * Called from boot code to establish sl interfaces. 80*26121Skarels */ 81*26121Skarels slattach() 82*26121Skarels { 83*26121Skarels register struct sl_softc *sc; 84*26121Skarels register int i = 0; 85*26121Skarels 86*26121Skarels for (sc = sl_softc; i < NSL; sc++) { 87*26121Skarels sc->sc_if.if_name = "sl"; 88*26121Skarels sc->sc_if.if_unit = i++; 89*26121Skarels sc->sc_if.if_mtu = SLMTU; 90*26121Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 91*26121Skarels sc->sc_if.if_ioctl = slioctl; 92*26121Skarels sc->sc_if.if_output = sloutput; 93*26121Skarels sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 94*26121Skarels if_attach(&sc->sc_if); 95*26121Skarels } 96*26121Skarels } 97*26121Skarels 98*26121Skarels /* 99*26121Skarels * Line specific open routine. 100*26121Skarels * Attach the given tty to the first available sl unit. 101*26121Skarels */ 102*26121Skarels slopen(dev, tp) 103*26121Skarels dev_t dev; 104*26121Skarels register struct tty *tp; 105*26121Skarels { 106*26121Skarels register struct sl_softc *sc; 107*26121Skarels register int nsl; 108*26121Skarels 109*26121Skarels if (tp->t_sc != NULL) 110*26121Skarels return (EBUSY); 111*26121Skarels 112*26121Skarels for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++) 113*26121Skarels if (sc->sc_ttyp == NULL) { 114*26121Skarels sc->sc_flags = 0; 115*26121Skarels sc->sc_ilen = 0; 116*26121Skarels sc->sc_mp = sc->sc_buf; 117*26121Skarels tp->t_sc = (caddr_t)sc; 118*26121Skarels sc->sc_ttyp = tp; 119*26121Skarels return (0); 120*26121Skarels } 121*26121Skarels 122*26121Skarels return (ENOSPC); 123*26121Skarels } 124*26121Skarels 125*26121Skarels /* 126*26121Skarels * Line specific close routine. 127*26121Skarels * Detach the tty from the sl unit. 128*26121Skarels * Mimics part of ttyclose(). 129*26121Skarels */ 130*26121Skarels slclose(tp) 131*26121Skarels struct tty *tp; 132*26121Skarels { 133*26121Skarels register struct sl_softc *sc; 134*26121Skarels int s; 135*26121Skarels 136*26121Skarels ttywflush(tp); 137*26121Skarels tp->t_line = 0; 138*26121Skarels s = splimp(); /* paranoid; splnet probably ok */ 139*26121Skarels sc = (struct sl_softc *)tp->t_sc; 140*26121Skarels if (sc != NULL) { 141*26121Skarels if_down(&sc->sc_if); 142*26121Skarels sc->sc_ttyp = NULL; 143*26121Skarels tp->t_sc = NULL; 144*26121Skarels } 145*26121Skarels splx(s); 146*26121Skarels } 147*26121Skarels 148*26121Skarels /* 149*26121Skarels * Line specific (tty) ioctl routine. 150*26121Skarels * Provide a way to get the sl unit number. 151*26121Skarels */ 152*26121Skarels sltioctl(tp, cmd, data, flag) 153*26121Skarels struct tty *tp; 154*26121Skarels caddr_t data; 155*26121Skarels { 156*26121Skarels 157*26121Skarels if (cmd == TIOCGETD) { 158*26121Skarels *(int *)data = ((struct sl_softc *)tp->t_sc)->sc_if.if_unit; 159*26121Skarels return (0); 160*26121Skarels } 161*26121Skarels return (-1); 162*26121Skarels } 163*26121Skarels 164*26121Skarels /* 165*26121Skarels * Queue a packet. Start transmission if not active. 166*26121Skarels */ 167*26121Skarels sloutput(ifp, m, dst) 168*26121Skarels register struct ifnet *ifp; 169*26121Skarels register struct mbuf *m; 170*26121Skarels struct sockaddr *dst; 171*26121Skarels { 172*26121Skarels register struct sl_softc *sc; 173*26121Skarels int s; 174*26121Skarels 175*26121Skarels /* 176*26121Skarels * `Cannot happen' (see slioctl). Someday we will extend 177*26121Skarels * the line protocol to support other address families. 178*26121Skarels */ 179*26121Skarels if (dst->sa_family != AF_INET) { 180*26121Skarels printf("sl%d: af%d not supported\n", ifp->if_unit, 181*26121Skarels dst->sa_family); 182*26121Skarels m_freem(m); 183*26121Skarels return (EAFNOSUPPORT); 184*26121Skarels } 185*26121Skarels 186*26121Skarels sc = &sl_softc[ifp->if_unit]; 187*26121Skarels if (sc->sc_ttyp == NULL) { 188*26121Skarels m_freem(m); 189*26121Skarels return (ENETDOWN); /* sort of */ 190*26121Skarels } 191*26121Skarels s = splimp(); 192*26121Skarels if (IF_QFULL(&ifp->if_snd)) { 193*26121Skarels IF_DROP(&ifp->if_snd); 194*26121Skarels splx(s); 195*26121Skarels m_freem(m); 196*26121Skarels sc->sc_if.if_collisions++; 197*26121Skarels return (ENOBUFS); 198*26121Skarels } 199*26121Skarels IF_ENQUEUE(&ifp->if_snd, m); 200*26121Skarels if ((sc->sc_flags & SC_OACTIVE) == 0) { 201*26121Skarels splx(s); 202*26121Skarels slstart(sc->sc_ttyp); 203*26121Skarels } else 204*26121Skarels splx(s); 205*26121Skarels return (0); 206*26121Skarels } 207*26121Skarels 208*26121Skarels /* 209*26121Skarels * Start output on interface. Get another datagram 210*26121Skarels * to send from the interface queue and map it to 211*26121Skarels * the interface before starting output. 212*26121Skarels */ 213*26121Skarels slstart(tp) 214*26121Skarels register struct tty *tp; 215*26121Skarels { 216*26121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 217*26121Skarels register struct mbuf *m; 218*26121Skarels register int c, len; 219*26121Skarels register u_char *mcp; 220*26121Skarels int flush; 221*26121Skarels 222*26121Skarels /* 223*26121Skarels * If there is more in the output queue, just send it now. 224*26121Skarels * We are being called in lieu of ttstart and must do what 225*26121Skarels * it would. 226*26121Skarels */ 227*26121Skarels if (tp->t_outq.c_cc > 0) { 228*26121Skarels ttstart(tp); 229*26121Skarels return; 230*26121Skarels } 231*26121Skarels 232*26121Skarels /* 233*26121Skarels * This happens briefly when the line shuts down. 234*26121Skarels */ 235*26121Skarels if (sc == NULL) 236*26121Skarels return; 237*26121Skarels 238*26121Skarels /* 239*26121Skarels * Get a packet and map it to the interface. 240*26121Skarels */ 241*26121Skarels c = splimp(); 242*26121Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 243*26121Skarels if (m == NULL) { 244*26121Skarels sc->sc_flags &= ~SC_OACTIVE; 245*26121Skarels splx(c); 246*26121Skarels return; 247*26121Skarels } 248*26121Skarels flush = !(sc->sc_flags & SC_OACTIVE); 249*26121Skarels sc->sc_flags |= SC_OACTIVE; 250*26121Skarels splx(c); 251*26121Skarels 252*26121Skarels /* 253*26121Skarels * The extra FRAME_END will start up a new packet, and thus 254*26121Skarels * will flush any accumulated garbage. We do this whenever 255*26121Skarels * the line may have been idle for some time. 256*26121Skarels */ 257*26121Skarels if (flush) 258*26121Skarels (void) putc(FRAME_END, &tp->t_outq); 259*26121Skarels 260*26121Skarels while (m != NULL) { 261*26121Skarels len = m->m_len; 262*26121Skarels mcp = mtod(m, u_char *); 263*26121Skarels while (--len >= 0) { 264*26121Skarels c = *mcp++; 265*26121Skarels if (c == FRAME_ESCAPE || c == FRAME_END) { 266*26121Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 267*26121Skarels goto full; 268*26121Skarels c = c == FRAME_ESCAPE ? TRANS_FRAME_ESCAPE : 269*26121Skarels TRANS_FRAME_END; 270*26121Skarels if (putc(c, &tp->t_outq)) { 271*26121Skarels (void) unputc(&tp->t_outq); 272*26121Skarels goto full; 273*26121Skarels } 274*26121Skarels } else 275*26121Skarels if (putc(c, &tp->t_outq)) 276*26121Skarels goto full; 277*26121Skarels } 278*26121Skarels m = m_free(m); 279*26121Skarels } 280*26121Skarels 281*26121Skarels if (putc(FRAME_END, &tp->t_outq)) { 282*26121Skarels full: 283*26121Skarels /* 284*26121Skarels * If you get many oerrors (more than one or two a day) 285*26121Skarels * you probably do not have enough clists and you should 286*26121Skarels * increase "nclist" in param.c. 287*26121Skarels */ 288*26121Skarels (void) unputc(&tp->t_outq); /* make room */ 289*26121Skarels putc(FRAME_END, &tp->t_outq); /* end the packet */ 290*26121Skarels sc->sc_if.if_oerrors++; 291*26121Skarels } else 292*26121Skarels sc->sc_if.if_opackets++; 293*26121Skarels 294*26121Skarels /* 295*26121Skarels * Start transmission. Note that slstart, not ttstart, will be 296*26121Skarels * called when the transmission completes, be that after a single 297*26121Skarels * piece of what we have mapped, or be it after the entire thing 298*26121Skarels * has been sent. That is why we need to check the output queue 299*26121Skarels * count at the top. 300*26121Skarels */ 301*26121Skarels ttstart(tp); 302*26121Skarels } 303*26121Skarels 304*26121Skarels /* 305*26121Skarels * Copy data buffer to mbuf chain; add ifnet pointer ifp. 306*26121Skarels */ 307*26121Skarels struct mbuf * 308*26121Skarels sl_btom(addr, len, ifp) 309*26121Skarels register caddr_t addr; 310*26121Skarels register int len; 311*26121Skarels struct ifnet *ifp; 312*26121Skarels { 313*26121Skarels register struct mbuf *m, **mp; 314*26121Skarels register int count; 315*26121Skarels struct mbuf *top = NULL; 316*26121Skarels 317*26121Skarels mp = ⊤ 318*26121Skarels while (len > 0) { 319*26121Skarels MGET(m, M_DONTWAIT, MT_DATA); 320*26121Skarels if ((*mp = m) == NULL) { 321*26121Skarels m_freem(top); 322*26121Skarels return (NULL); 323*26121Skarels } 324*26121Skarels if (ifp) { 325*26121Skarels m->m_off += sizeof(ifp); 326*26121Skarels count = MIN(len, MLEN - sizeof(ifp)); 327*26121Skarels } else { 328*26121Skarels if (len >= NBPG) { 329*26121Skarels struct mbuf *p; 330*26121Skarels 331*26121Skarels MCLGET(p, 1); 332*26121Skarels if (p != NULL) { 333*26121Skarels count = MIN(len, CLBYTES); 334*26121Skarels m->m_off = (int)p - (int)m; 335*26121Skarels } else 336*26121Skarels count = MIN(len, MLEN); 337*26121Skarels } else 338*26121Skarels count = MIN(len, MLEN); 339*26121Skarels } 340*26121Skarels bcopy(addr, mtod(m, caddr_t), count); 341*26121Skarels m->m_len = count; 342*26121Skarels if (ifp) { 343*26121Skarels m->m_off -= sizeof(ifp); 344*26121Skarels m->m_len += sizeof(ifp); 345*26121Skarels *mtod(m, struct ifnet **) = ifp; 346*26121Skarels ifp = NULL; 347*26121Skarels } 348*26121Skarels addr += count; 349*26121Skarels len -= count; 350*26121Skarels mp = &m->m_next; 351*26121Skarels } 352*26121Skarels return (top); 353*26121Skarels } 354*26121Skarels 355*26121Skarels /* 356*26121Skarels * tty interface receiver interrupt. 357*26121Skarels */ 358*26121Skarels slinput(c, tp) 359*26121Skarels register int c; 360*26121Skarels register struct tty *tp; 361*26121Skarels { 362*26121Skarels register struct sl_softc *sc; 363*26121Skarels register struct mbuf *m; 364*26121Skarels int s; 365*26121Skarels 366*26121Skarels sc = (struct sl_softc *)tp->t_sc; 367*26121Skarels if (sc == NULL) 368*26121Skarels return; 369*26121Skarels 370*26121Skarels c &= 0xff; 371*26121Skarels if (sc->sc_flags & SC_ESCAPED) { 372*26121Skarels sc->sc_flags &= ~SC_ESCAPED; 373*26121Skarels switch (c) { 374*26121Skarels 375*26121Skarels case TRANS_FRAME_ESCAPE: 376*26121Skarels c = FRAME_ESCAPE; 377*26121Skarels break; 378*26121Skarels 379*26121Skarels case TRANS_FRAME_END: 380*26121Skarels c = FRAME_END; 381*26121Skarels break; 382*26121Skarels 383*26121Skarels default: 384*26121Skarels sc->sc_if.if_ierrors++; 385*26121Skarels sc->sc_mp = sc->sc_buf; 386*26121Skarels sc->sc_ilen = 0; 387*26121Skarels return; 388*26121Skarels } 389*26121Skarels } else { 390*26121Skarels switch (c) { 391*26121Skarels 392*26121Skarels case FRAME_END: 393*26121Skarels if (sc->sc_ilen == 0) /* ignore */ 394*26121Skarels return; 395*26121Skarels m = sl_btom(sc->sc_buf, sc->sc_ilen, &sc->sc_if); 396*26121Skarels if (m == NULL) { 397*26121Skarels sc->sc_if.if_ierrors++; 398*26121Skarels return; 399*26121Skarels } 400*26121Skarels sc->sc_mp = sc->sc_buf; 401*26121Skarels sc->sc_ilen = 0; 402*26121Skarels sc->sc_if.if_ipackets++; 403*26121Skarels s = splimp(); 404*26121Skarels if (IF_QFULL(&ipintrq)) { 405*26121Skarels IF_DROP(&ipintrq); 406*26121Skarels sc->sc_if.if_ierrors++; 407*26121Skarels m_freem(m); 408*26121Skarels } else { 409*26121Skarels IF_ENQUEUE(&ipintrq, m); 410*26121Skarels schednetisr(NETISR_IP); 411*26121Skarels } 412*26121Skarels splx(s); 413*26121Skarels return; 414*26121Skarels 415*26121Skarels case FRAME_ESCAPE: 416*26121Skarels sc->sc_flags |= SC_ESCAPED; 417*26121Skarels return; 418*26121Skarels } 419*26121Skarels } 420*26121Skarels if (++sc->sc_ilen >= SLMTU) { 421*26121Skarels sc->sc_if.if_ierrors++; 422*26121Skarels sc->sc_mp = sc->sc_buf; 423*26121Skarels sc->sc_ilen = 0; 424*26121Skarels return; 425*26121Skarels } 426*26121Skarels *sc->sc_mp++ = c; 427*26121Skarels } 428*26121Skarels 429*26121Skarels /* 430*26121Skarels * Process an ioctl request. 431*26121Skarels */ 432*26121Skarels slioctl(ifp, cmd, data) 433*26121Skarels register struct ifnet *ifp; 434*26121Skarels int cmd; 435*26121Skarels caddr_t data; 436*26121Skarels { 437*26121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 438*26121Skarels int s = splimp(), error = 0; 439*26121Skarels 440*26121Skarels switch (cmd) { 441*26121Skarels 442*26121Skarels case SIOCSIFADDR: 443*26121Skarels if (ifa->ifa_addr.sa_family == AF_INET) 444*26121Skarels ifp->if_flags |= IFF_UP; 445*26121Skarels else 446*26121Skarels error = EAFNOSUPPORT; 447*26121Skarels break; 448*26121Skarels 449*26121Skarels case SIOCSIFDSTADDR: 450*26121Skarels if (ifa->ifa_addr.sa_family != AF_INET) 451*26121Skarels error = EAFNOSUPPORT; 452*26121Skarels break; 453*26121Skarels 454*26121Skarels default: 455*26121Skarels error = EINVAL; 456*26121Skarels } 457*26121Skarels splx(s); 458*26121Skarels return (error); 459*26121Skarels } 460*26121Skarels #endif 461