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

Defined functions

sl_btom defined in line 390; used 1 times
slattach defined in line 95; never used
slclose defined in line 153; never used
slinit defined in line 368; used 1 times
slinput defined in line 456; never used
slioctl defined in line 533; used 2 times
slopen defined in line 117; used 1 times
  • in line 90
sloutput defined in line 196; used 2 times
slstart defined in line 248; used 1 times
sltioctl defined in line 180; used 1 times
  • in line 90

Defined variables

sl_softc defined in line 78; used 4 times

Defined struct's

sl_softc defined in line 71; used 24 times

Defined macros

CLISTRESERVE defined in line 69; used 1 times
FRAME_END defined in line 83; used 5 times
FRAME_ESCAPE defined in line 84; used 4 times
SC_ESCAPED defined in line 81; used 3 times
SLIP_HIWAT defined in line 68; used 1 times
SLMTU defined in line 67; used 3 times
TRANS_FRAME_END defined in line 85; used 1 times
TRANS_FRAME_ESCAPE defined in line 86; used 1 times
t_sc defined in line 88; used 6 times
Last modified: 1988-09-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5196
Valid CSS Valid XHTML 1.0 Strict