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