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