1 /* 2 * Copyright (c) 1987, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)if_sl.c 7.23 (Berkeley) 10/16/91 8 */ 9 10 /* 11 * Serial Line interface 12 * 13 * Rick Adams 14 * Center for Seismic Studies 15 * 1300 N 17th Street, Suite 1450 16 * Arlington, Virginia 22209 17 * (703)276-7900 18 * rick@seismo.ARPA 19 * seismo!rick 20 * 21 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 22 * N.B.: this belongs in netinet, not net, the way it stands now. 23 * Should have a link-layer type designation, but wouldn't be 24 * backwards-compatible. 25 * 26 * Converted to 4.3BSD Beta by Chris Torek. 27 * Other changes made at Berkeley, based in part on code by Kirk Smith. 28 * W. Jolitz added slip abort. 29 * 30 * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov). 31 * Added priority queuing for "interactive" traffic; hooks for TCP 32 * header compression; ICMP filtering (at 2400 baud, some cretin 33 * pinging you can use up all your bandwidth). Made low clist behavior 34 * more robust and slightly less likely to hang serial line. 35 * Sped up a bunch of things. 36 * 37 * Note that splimp() is used throughout to block both (tty) input 38 * interrupts and network activity; thus, splimp must be >= spltty. 39 */ 40 41 /* $Header: /usr/src/sys/net/RCS/if_sl.c,v 1.1 91/08/30 11:14:57 william Exp Locker: william $ */ 42 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 43 44 #include "sl.h" 45 #if NSL > 0 46 47 #include "param.h" 48 #include "proc.h" 49 #include "mbuf.h" 50 #include "buf.h" 51 #include "dkstat.h" 52 #include "socket.h" 53 #include "ioctl.h" 54 #include "file.h" 55 #include "tty.h" 56 #include "kernel.h" 57 #include "conf.h" 58 59 #include "if.h" 60 #include "if_types.h" 61 #include "netisr.h" 62 #include "route.h" 63 #if INET 64 #include "netinet/in.h" 65 #include "netinet/in_systm.h" 66 #include "netinet/in_var.h" 67 #include "netinet/ip.h" 68 #else 69 Huh? Slip without inet? 70 #endif 71 72 #include "machine/mtpr.h" 73 74 #include "slcompress.h" 75 #include "if_slvar.h" 76 77 /* 78 * SLMAX is a hard limit on input packet size. To simplify the code 79 * and improve performance, we require that packets fit in an mbuf 80 * cluster, and if we get a compressed packet, there's enough extra 81 * room to expand the header into a max length tcp/ip header (128 82 * bytes). So, SLMAX can be at most 83 * MCLBYTES - 128 84 * 85 * SLMTU is a hard limit on output packet size. To insure good 86 * interactive response, SLMTU wants to be the smallest size that 87 * amortizes the header cost. (Remember that even with 88 * type-of-service queuing, we have to wait for any in-progress 89 * packet to finish. I.e., we wait, on the average, 1/2 * mtu / 90 * cps, where cps is the line speed in characters per second. 91 * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The 92 * average compressed header size is 6-8 bytes so any MTU > 90 93 * bytes will give us 90% of the line bandwidth. A 100ms wait is 94 * tolerable (500ms is not), so want an MTU around 296. (Since TCP 95 * will send 256 byte segments (to allow for 40 byte headers), the 96 * typical packet size on the wire will be around 260 bytes). In 97 * 4.3tahoe+ systems, we can set an MTU in a route so we do that & 98 * leave the interface MTU relatively high (so we don't IP fragment 99 * when acting as a gateway to someone using a stupid MTU). 100 * 101 * Similar considerations apply to SLIP_HIWAT: It's the amount of 102 * data that will be queued 'downstream' of us (i.e., in clists 103 * waiting to be picked up by the tty output interrupt). If we 104 * queue a lot of data downstream, it's immune to our t.o.s. queuing. 105 * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed 106 * telnet/ftp will see a 1 sec wait, independent of the mtu (the 107 * wait is dependent on the ftp window size but that's typically 108 * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize 109 * the cost (in idle time on the wire) of the tty driver running 110 * off the end of its clists & having to call back slstart for a 111 * new packet. For a tty interface with any buffering at all, this 112 * cost will be zero. Even with a totally brain dead interface (like 113 * the one on a typical workstation), the cost will be <= 1 character 114 * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose 115 * at most 1% while maintaining good interactive response. 116 */ 117 #define BUFOFFSET 128 118 #define SLMAX (MCLBYTES - BUFOFFSET) 119 #define SLBUFSIZE (SLMAX + BUFOFFSET) 120 #define SLMTU 296 121 #define SLIP_HIWAT roundup(50,CBSIZE) 122 #define CLISTRESERVE 1024 /* Can't let clists get too low */ 123 124 /* 125 * SLIP ABORT ESCAPE MECHANISM: 126 * (inspired by HAYES modem escape arrangement) 127 * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 128 * signals a "soft" exit from slip mode by usermode process 129 */ 130 131 #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 132 #define ABT_WAIT 1 /* in seconds - idle before an escape & after */ 133 #define ABT_RECYCLE (5*2+2) /* in seconds - time window processing abort */ 134 135 #define ABT_SOFT 3 /* count of escapes */ 136 137 /* 138 * The following disgusting hack gets around the problem that IP TOS 139 * can't be set yet. We want to put "interactive" traffic on a high 140 * priority queue. To decide if traffic is interactive, we check that 141 * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 142 */ 143 static u_short interactive_ports[8] = { 144 0, 513, 0, 0, 145 0, 21, 0, 23, 146 }; 147 #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 148 149 struct sl_softc sl_softc[NSL]; 150 151 #define FRAME_END 0xc0 /* Frame End */ 152 #define FRAME_ESCAPE 0xdb /* Frame Esc */ 153 #define TRANS_FRAME_END 0xdc /* transposed frame end */ 154 #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 155 156 #define t_sc T_LINEP 157 158 int sloutput(), slioctl(), ttrstrt(); 159 extern struct timeval time; 160 161 /* 162 * Called from boot code to establish sl interfaces. 163 */ 164 slattach() 165 { 166 register struct sl_softc *sc; 167 register int i = 0; 168 169 for (sc = sl_softc; i < NSL; sc++) { 170 sc->sc_if.if_name = "sl"; 171 sc->sc_if.if_unit = i++; 172 sc->sc_if.if_mtu = SLMTU; 173 sc->sc_if.if_flags = IFF_POINTOPOINT; 174 sc->sc_if.if_type = IFT_SLIP; 175 sc->sc_if.if_ioctl = slioctl; 176 sc->sc_if.if_output = sloutput; 177 sc->sc_if.if_snd.ifq_maxlen = 50; 178 sc->sc_fastq.ifq_maxlen = 32; 179 if_attach(&sc->sc_if); 180 } 181 } 182 183 static int 184 slinit(sc) 185 register struct sl_softc *sc; 186 { 187 register caddr_t p; 188 189 if (sc->sc_ep == (u_char *) 0) { 190 MCLALLOC(p, M_WAIT); 191 if (p) 192 sc->sc_ep = (u_char *)p + SLBUFSIZE; 193 else { 194 printf("sl%d: can't allocate buffer\n", sc - sl_softc); 195 sc->sc_if.if_flags &= ~IFF_UP; 196 return (0); 197 } 198 } 199 sc->sc_buf = sc->sc_ep - SLMAX; 200 sc->sc_mp = sc->sc_buf; 201 sl_compress_init(&sc->sc_comp); 202 return (1); 203 } 204 205 /* 206 * Line specific open routine. 207 * Attach the given tty to the first available sl unit. 208 */ 209 /* ARGSUSED */ 210 slopen(dev, tp) 211 dev_t dev; 212 register struct tty *tp; 213 { 214 struct proc *p = curproc; /* XXX */ 215 register struct sl_softc *sc; 216 register int nsl; 217 int error; 218 219 if (error = suser(p->p_ucred, &p->p_acflag)) 220 return (error); 221 222 if (tp->t_line == SLIPDISC) 223 return (0); 224 225 for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 226 if (sc->sc_ttyp == NULL) { 227 if (slinit(sc) == 0) 228 return (ENOBUFS); 229 tp->t_sc = (caddr_t)sc; 230 sc->sc_ttyp = tp; 231 sc->sc_if.if_baudrate = tp->t_ospeed; 232 ttyflush(tp, FREAD | FWRITE); 233 return (0); 234 } 235 return (ENXIO); 236 } 237 238 /* 239 * Line specific close routine. 240 * Detach the tty from the sl unit. 241 * Mimics part of ttyclose(). 242 */ 243 slclose(tp) 244 struct tty *tp; 245 { 246 register struct sl_softc *sc; 247 int s; 248 249 ttywflush(tp); 250 s = splimp(); /* actually, max(spltty, splnet) */ 251 tp->t_line = 0; 252 sc = (struct sl_softc *)tp->t_sc; 253 if (sc != NULL) { 254 if_down(&sc->sc_if); 255 sc->sc_ttyp = NULL; 256 tp->t_sc = NULL; 257 MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); 258 sc->sc_ep = 0; 259 sc->sc_mp = 0; 260 sc->sc_buf = 0; 261 } 262 splx(s); 263 } 264 265 /* 266 * Line specific (tty) ioctl routine. 267 * Provide a way to get the sl unit number. 268 */ 269 /* ARGSUSED */ 270 sltioctl(tp, cmd, data, flag) 271 struct tty *tp; 272 caddr_t data; 273 { 274 struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 275 int s; 276 277 switch (cmd) { 278 case SLIOCGUNIT: 279 *(int *)data = sc->sc_if.if_unit; 280 break; 281 282 case SLIOCGFLAGS: 283 *(int *)data = sc->sc_if.if_flags; 284 break; 285 286 case SLIOCSFLAGS: 287 #define LLC_MASK (IFF_LLC0|IFF_LLC1|IFF_LLC2) 288 s = splimp(); 289 sc->sc_if.if_flags = 290 (sc->sc_if.if_flags &~ LLC_MASK) 291 | ((*(int *)data) & LLC_MASK); 292 splx(s); 293 break; 294 295 default: 296 return (-1); 297 } 298 return (0); 299 } 300 301 /* 302 * Queue a packet. Start transmission if not active. 303 */ 304 sloutput(ifp, m, dst) 305 struct ifnet *ifp; 306 register struct mbuf *m; 307 struct sockaddr *dst; 308 { 309 register struct sl_softc *sc = &sl_softc[ifp->if_unit]; 310 register struct ip *ip; 311 register struct ifqueue *ifq; 312 int s; 313 314 /* 315 * `Cannot happen' (see slioctl). Someday we will extend 316 * the line protocol to support other address families. 317 */ 318 if (dst->sa_family != AF_INET) { 319 printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, 320 dst->sa_family); 321 m_freem(m); 322 return (EAFNOSUPPORT); 323 } 324 325 if (sc->sc_ttyp == NULL) { 326 m_freem(m); 327 return (ENETDOWN); /* sort of */ 328 } 329 if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 330 m_freem(m); 331 return (EHOSTUNREACH); 332 } 333 ifq = &sc->sc_if.if_snd; 334 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 335 register int p = ((int *)ip)[ip->ip_hl]; 336 337 if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) { 338 ifq = &sc->sc_fastq; 339 p = 1; 340 } else 341 p = 0; 342 343 if (sc->sc_if.if_flags & SC_COMPRESS) { 344 /* 345 * The last parameter turns off connection id 346 * compression for background traffic: Since 347 * fastq traffic can jump ahead of the background 348 * traffic, we don't know what order packets will 349 * go on the line. 350 */ 351 p = sl_compress_tcp(m, ip, &sc->sc_comp, p); 352 *mtod(m, u_char *) |= p; 353 } 354 } else if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 355 m_freem(m); 356 return (0); 357 } 358 s = splimp(); 359 if (IF_QFULL(ifq)) { 360 IF_DROP(ifq); 361 m_freem(m); 362 splx(s); 363 sc->sc_if.if_oerrors++; 364 return (ENOBUFS); 365 } 366 IF_ENQUEUE(ifq, m); 367 sc->sc_if.if_lastchange = time; 368 if (sc->sc_ttyp->t_outq.c_cc == 0) 369 slstart(sc->sc_ttyp); 370 splx(s); 371 return (0); 372 } 373 374 /* 375 * Start output on interface. Get another datagram 376 * to send from the interface queue and map it to 377 * the interface before starting output. 378 */ 379 slstart(tp) 380 register struct tty *tp; 381 { 382 register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 383 register struct mbuf *m; 384 register u_char *cp; 385 int s; 386 struct mbuf *m2; 387 extern int cfreecount; 388 389 for (;;) { 390 /* 391 * If there is more in the output queue, just send it now. 392 * We are being called in lieu of ttstart and must do what 393 * it would. 394 */ 395 if (tp->t_outq.c_cc != 0) { 396 (*tp->t_oproc)(tp); 397 if (tp->t_outq.c_cc > SLIP_HIWAT) 398 return; 399 } 400 /* 401 * This happens briefly when the line shuts down. 402 */ 403 if (sc == NULL) 404 return; 405 406 /* 407 * Get a packet and send it to the interface. 408 */ 409 s = splimp(); 410 IF_DEQUEUE(&sc->sc_fastq, m); 411 if (m == NULL) 412 IF_DEQUEUE(&sc->sc_if.if_snd, m); 413 splx(s); 414 if (m == NULL) 415 return; 416 sc->sc_if.if_lastchange = time; 417 418 /* 419 * If system is getting low on clists, just flush our 420 * output queue (if the stuff was important, it'll get 421 * retransmitted). 422 */ 423 if (cfreecount < CLISTRESERVE + SLMTU) { 424 m_freem(m); 425 sc->sc_if.if_collisions++; 426 continue; 427 } 428 /* 429 * The extra FRAME_END will start up a new packet, and thus 430 * will flush any accumulated garbage. We do this whenever 431 * the line may have been idle for some time. 432 */ 433 if (tp->t_outq.c_cc == 0) { 434 ++sc->sc_bytessent; 435 (void) putc(FRAME_END, &tp->t_outq); 436 } 437 438 while (m) { 439 register u_char *ep; 440 441 cp = mtod(m, u_char *); ep = cp + m->m_len; 442 while (cp < ep) { 443 /* 444 * Find out how many bytes in the string we can 445 * handle without doing something special. 446 */ 447 register u_char *bp = cp; 448 449 while (cp < ep) { 450 switch (*cp++) { 451 case FRAME_ESCAPE: 452 case FRAME_END: 453 --cp; 454 goto out; 455 } 456 } 457 out: 458 if (cp > bp) { 459 /* 460 * Put n characters at once 461 * into the tty output queue. 462 */ 463 if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) 464 break; 465 sc->sc_bytessent += cp - bp; 466 } 467 /* 468 * If there are characters left in the mbuf, 469 * the first one must be special.. 470 * Put it out in a different form. 471 */ 472 if (cp < ep) { 473 if (putc(FRAME_ESCAPE, &tp->t_outq)) 474 break; 475 if (putc(*cp++ == FRAME_ESCAPE ? 476 TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 477 &tp->t_outq)) { 478 (void) unputc(&tp->t_outq); 479 break; 480 } 481 sc->sc_bytessent += 2; 482 } 483 } 484 MFREE(m, m2); 485 m = m2; 486 } 487 488 if (putc(FRAME_END, &tp->t_outq)) { 489 /* 490 * Not enough room. Remove a char to make room 491 * and end the packet normally. 492 * If you get many collisions (more than one or two 493 * a day) you probably do not have enough clists 494 * and you should increase "nclist" in param.c. 495 */ 496 (void) unputc(&tp->t_outq); 497 (void) putc(FRAME_END, &tp->t_outq); 498 sc->sc_if.if_collisions++; 499 } else { 500 ++sc->sc_bytessent; 501 sc->sc_if.if_opackets++; 502 } 503 sc->sc_if.if_obytes = sc->sc_bytessent; 504 } 505 } 506 507 /* 508 * Copy data buffer to mbuf chain; add ifnet pointer. 509 */ 510 static struct mbuf * 511 sl_btom(sc, len) 512 register struct sl_softc *sc; 513 register int len; 514 { 515 register struct mbuf *m; 516 517 MGETHDR(m, M_DONTWAIT, MT_DATA); 518 if (m == NULL) 519 return (NULL); 520 521 /* 522 * If we have more than MHLEN bytes, it's cheaper to 523 * queue the cluster we just filled & allocate a new one 524 * for the input buffer. Otherwise, fill the mbuf we 525 * allocated above. Note that code in the input routine 526 * guarantees that packet will fit in a cluster. 527 */ 528 if (len >= MHLEN) { 529 MCLGET(m, M_DONTWAIT); 530 if ((m->m_flags & M_EXT) == 0) { 531 /* 532 * we couldn't get a cluster - if memory's this 533 * low, it's time to start dropping packets. 534 */ 535 (void) m_free(m); 536 return (NULL); 537 } 538 sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; 539 m->m_data = (caddr_t)sc->sc_buf; 540 m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET); 541 } else 542 bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); 543 544 m->m_len = len; 545 m->m_pkthdr.len = len; 546 m->m_pkthdr.rcvif = &sc->sc_if; 547 return (m); 548 } 549 550 /* 551 * tty interface receiver interrupt. 552 */ 553 slinput(c, tp) 554 register int c; 555 register struct tty *tp; 556 { 557 register struct sl_softc *sc; 558 register struct mbuf *m; 559 register int len; 560 int s; 561 562 tk_nin++; 563 sc = (struct sl_softc *)tp->t_sc; 564 if (sc == NULL) 565 return; 566 if (!(tp->t_state&TS_CARR_ON)) /* XXX */ 567 return; 568 569 ++sc->sc_bytesrcvd; 570 ++sc->sc_if.if_ibytes; 571 c &= 0xff; /* XXX */ 572 573 #ifdef ABT_ESC 574 { 575 /* if we see an abort after "idle" time, count it */ 576 if (c == ABT_ESC && time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 577 sc->sc_abortcount++; 578 /* record when the first abort escape arrived */ 579 if (sc->sc_abortcount == 1) 580 sc->sc_starttime = time.tv_sec; 581 } 582 /* 583 * if we have an abort, see that we have not run out of time, 584 * or that we have an "idle" time after the complete escape 585 * sequence 586 */ 587 if (sc->sc_abortcount) { 588 if (time.tv_sec >= sc->sc_starttime + ABT_RECYCLE) 589 sc->sc_abortcount = 0; 590 if (sc->sc_abortcount >= ABT_SOFT && 591 time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 592 slclose(tp); 593 return; 594 } 595 } 596 sc->sc_lasttime = time.tv_sec; 597 } 598 #endif 599 600 switch (c) { 601 602 case TRANS_FRAME_ESCAPE: 603 if (sc->sc_escape) 604 c = FRAME_ESCAPE; 605 break; 606 607 case TRANS_FRAME_END: 608 if (sc->sc_escape) 609 c = FRAME_END; 610 break; 611 612 case FRAME_ESCAPE: 613 sc->sc_escape = 1; 614 return; 615 616 case FRAME_END: 617 len = sc->sc_mp - sc->sc_buf; 618 if (len < 3) 619 /* less than min length packet - ignore */ 620 goto newpack; 621 622 if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 623 if (c & 0x80) 624 c = TYPE_COMPRESSED_TCP; 625 else if (c == TYPE_UNCOMPRESSED_TCP) 626 *sc->sc_buf &= 0x4f; /* XXX */ 627 /* 628 * We've got something that's not an IP packet. 629 * If compression is enabled, try to decompress it. 630 * Otherwise, if `auto-enable' compression is on and 631 * it's a reasonable packet, decompress it and then 632 * enable compression. Otherwise, drop it. 633 */ 634 if (sc->sc_if.if_flags & SC_COMPRESS) { 635 len = sl_uncompress_tcp(&sc->sc_buf, len, 636 (u_int)c, &sc->sc_comp); 637 if (len <= 0) 638 goto error; 639 } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 640 c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 641 len = sl_uncompress_tcp(&sc->sc_buf, len, 642 (u_int)c, &sc->sc_comp); 643 if (len <= 0) 644 goto error; 645 sc->sc_if.if_flags |= SC_COMPRESS; 646 } else 647 goto error; 648 } 649 m = sl_btom(sc, len); 650 if (m == NULL) 651 goto error; 652 653 sc->sc_if.if_ipackets++; 654 sc->sc_if.if_lastchange = time; 655 s = splimp(); 656 if (IF_QFULL(&ipintrq)) { 657 IF_DROP(&ipintrq); 658 sc->sc_if.if_ierrors++; 659 sc->sc_if.if_iqdrops++; 660 m_freem(m); 661 } else { 662 IF_ENQUEUE(&ipintrq, m); 663 schednetisr(NETISR_IP); 664 } 665 splx(s); 666 goto newpack; 667 } 668 if (sc->sc_mp < sc->sc_ep) { 669 *sc->sc_mp++ = c; 670 sc->sc_escape = 0; 671 return; 672 } 673 error: 674 sc->sc_if.if_ierrors++; 675 newpack: 676 sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; 677 sc->sc_escape = 0; 678 } 679 680 /* 681 * Process an ioctl request. 682 */ 683 slioctl(ifp, cmd, data) 684 register struct ifnet *ifp; 685 int cmd; 686 caddr_t data; 687 { 688 register struct ifaddr *ifa = (struct ifaddr *)data; 689 int s = splimp(), error = 0; 690 691 switch (cmd) { 692 693 case SIOCSIFADDR: 694 if (ifa->ifa_addr->sa_family == AF_INET) 695 ifp->if_flags |= IFF_UP; 696 else 697 error = EAFNOSUPPORT; 698 break; 699 700 case SIOCSIFDSTADDR: 701 if (ifa->ifa_addr->sa_family != AF_INET) 702 error = EAFNOSUPPORT; 703 break; 704 705 default: 706 error = EINVAL; 707 } 708 splx(s); 709 return (error); 710 } 711 #endif 712