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 = &top;
 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

Defined functions

sl_btom defined in line 370; used 1 times
slattach defined in line 86; used 1 times
slclose defined in line 140; used 2 times
slinit defined in line 348; used 1 times
slinput defined in line 436; used 2 times
slioctl defined in line 511; used 2 times
slopen defined in line 108; used 2 times
sloutput defined in line 180; used 2 times
slstart defined in line 230; used 3 times
sltioctl defined in line 165; used 2 times

Defined variables

sl_softc defined in line 68; used 4 times

Defined struct's

sl_softc defined in line 61; used 24 times

Defined macros

CLISTRESERVE defined in line 59; used 1 times
FRAME_END defined in line 74; used 5 times
FRAME_ESCAPE defined in line 75; used 4 times
SC_ESCAPED defined in line 71; used 3 times
SC_OACTIVE defined in line 72; used 5 times
SLIP_HIWAT defined in line 58; used 1 times
SLMTU defined in line 57; used 3 times
TRANS_FRAME_END defined in line 76; used 1 times
TRANS_FRAME_ESCAPE defined in line 77; used 1 times
t_sc defined in line 79; used 6 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2187
Valid CSS Valid XHTML 1.0 Strict