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