if_sl.c revision 1.129
1/* $NetBSD: if_sl.c,v 1.129 2018/04/20 09:56:22 knakahara Exp $ */ 2 3/* 4 * Copyright (c) 1987, 1989, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)if_sl.c 8.9 (Berkeley) 1/9/95 32 */ 33 34/* 35 * Serial Line interface 36 * 37 * Rick Adams 38 * Center for Seismic Studies 39 * 1300 N 17th Street, Suite 1450 40 * Arlington, Virginia 22209 41 * (703)276-7900 42 * rick@seismo.ARPA 43 * seismo!rick 44 * 45 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 46 * N.B.: this belongs in netinet, not net, the way it stands now. 47 * Should have a link-layer type designation, but wouldn't be 48 * backwards-compatible. 49 * 50 * Converted to 4.3BSD Beta by Chris Torek. 51 * Other changes made at Berkeley, based in part on code by Kirk Smith. 52 * W. Jolitz added slip abort. 53 * 54 * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov). 55 * Added priority queuing for "interactive" traffic; hooks for TCP 56 * header compression; ICMP filtering (at 2400 baud, some cretin 57 * pinging you can use up all your bandwidth). Made low clist behavior 58 * more robust and slightly less likely to hang serial line. 59 * Sped up a bunch of things. 60 */ 61 62#include <sys/cdefs.h> 63__KERNEL_RCSID(0, "$NetBSD: if_sl.c,v 1.129 2018/04/20 09:56:22 knakahara Exp $"); 64 65#ifdef _KERNEL_OPT 66#include "opt_inet.h" 67#endif 68 69#include <sys/param.h> 70#include <sys/proc.h> 71#include <sys/malloc.h> 72#include <sys/mbuf.h> 73#include <sys/buf.h> 74#include <sys/dkstat.h> 75#include <sys/socket.h> 76#include <sys/ioctl.h> 77#include <sys/file.h> 78#include <sys/conf.h> 79#include <sys/tty.h> 80#include <sys/kernel.h> 81#include <sys/socketvar.h> 82#if __NetBSD__ 83#include <sys/systm.h> 84#include <sys/kauth.h> 85#endif 86#include <sys/cpu.h> 87#include <sys/intr.h> 88#include <sys/device.h> 89#include <sys/module.h> 90 91#include <net/if.h> 92#include <net/if_types.h> 93#include <net/netisr.h> 94#include <net/route.h> 95 96#ifdef INET 97#include <netinet/in.h> 98#include <netinet/in_systm.h> 99#include <netinet/in_var.h> 100#include <netinet/ip.h> 101#endif 102 103#include <net/slcompress.h> 104#include <net/if_slvar.h> 105#include <net/slip.h> 106#include <net/ppp_defs.h> 107#include <net/if_ppp.h> 108 109#include <sys/time.h> 110#include <net/bpf.h> 111 112#include "ioconf.h" 113 114/* 115 * SLMAX is a hard limit on input packet size. To simplify the code 116 * and improve performance, we require that packets fit in an mbuf 117 * cluster, and if we get a compressed packet, there's enough extra 118 * room to expand the header into a max length tcp/ip header (128 119 * bytes). So, SLMAX can be at most 120 * MCLBYTES - 128 121 * 122 * SLMTU is a hard limit on output packet size. To insure good 123 * interactive response, SLMTU wants to be the smallest size that 124 * amortizes the header cost. (Remember that even with 125 * type-of-service queuing, we have to wait for any in-progress 126 * packet to finish. I.e., we wait, on the average, 1/2 * mtu / 127 * cps, where cps is the line speed in characters per second. 128 * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The 129 * average compressed header size is 6-8 bytes so any MTU > 90 130 * bytes will give us 90% of the line bandwidth. A 100ms wait is 131 * tolerable (500ms is not), so want an MTU around 296. (Since TCP 132 * will send 256 byte segments (to allow for 40 byte headers), the 133 * typical packet size on the wire will be around 260 bytes). In 134 * 4.3tahoe+ systems, we can set an MTU in a route so we do that & 135 * leave the interface MTU relatively high (so we don't IP fragment 136 * when acting as a gateway to someone using a stupid MTU). 137 * 138 * Similar considerations apply to SLIP_HIWAT: It's the amount of 139 * data that will be queued 'downstream' of us (i.e., in clists 140 * waiting to be picked up by the tty output interrupt). If we 141 * queue a lot of data downstream, it's immune to our t.o.s. queuing. 142 * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed 143 * telnet/ftp will see a 1 sec wait, independent of the mtu (the 144 * wait is dependent on the ftp window size but that's typically 145 * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize 146 * the cost (in idle time on the wire) of the tty driver running 147 * off the end of its clists & having to call back slstart for a 148 * new packet. For a tty interface with any buffering at all, this 149 * cost will be zero. Even with a totally brain dead interface (like 150 * the one on a typical workstation), the cost will be <= 1 character 151 * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose 152 * at most 1% while maintaining good interactive response. 153 */ 154#define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN) 155#define SLMAX (MCLBYTES - BUFOFFSET) 156#define SLBUFSIZE (SLMAX + BUFOFFSET) 157#ifndef SLMTU 158#define SLMTU 296 159#endif 160#if (SLMTU < 3) 161#error SLMTU way too small. 162#endif 163#define SLIP_HIWAT roundup(50, TTROUND) 164#ifndef __NetBSD__ /* XXX - cgd */ 165#define CLISTRESERVE 1024 /* Can't let clists get too low */ 166#endif /* !__NetBSD__ */ 167 168/* 169 * SLIP ABORT ESCAPE MECHANISM: 170 * (inspired by HAYES modem escape arrangement) 171 * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 172 * within window time signals a "soft" exit from slip mode by remote end 173 * if the IFF_DEBUG flag is on. 174 */ 175#define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 176#define ABT_IDLE 1 /* in seconds - idle before an escape */ 177#define ABT_COUNT 3 /* count of escapes for abort */ 178#define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */ 179 180static int sl_clone_create(struct if_clone *, int); 181static int sl_clone_destroy(struct ifnet *); 182 183static LIST_HEAD(, sl_softc) sl_softc_list; 184 185struct if_clone sl_cloner = 186 IF_CLONE_INITIALIZER("sl", sl_clone_create, sl_clone_destroy); 187 188#define FRAME_END 0xc0 /* Frame End */ 189#define FRAME_ESCAPE 0xdb /* Frame Esc */ 190#define TRANS_FRAME_END 0xdc /* transposed frame end */ 191#define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 192 193static void slintr(void *); 194 195static int slcreate(struct sl_softc *); 196static struct mbuf *sl_btom(struct sl_softc *, int); 197 198static int slclose(struct tty *, int); 199static int slinput(int, struct tty *); 200static int slioctl(struct ifnet *, u_long, void *); 201static int slopen(dev_t, struct tty *); 202static int sloutput(struct ifnet *, struct mbuf *, const struct sockaddr *, 203 const struct rtentry *); 204static int slstart(struct tty *); 205static int sltioctl(struct tty *, u_long, void *, int, struct lwp *); 206 207static struct linesw slip_disc = { 208 .l_name = "slip", 209 .l_open = slopen, 210 .l_close = slclose, 211 .l_read = ttyerrio, 212 .l_write = ttyerrio, 213 .l_ioctl = sltioctl, 214 .l_rint = slinput, 215 .l_start = slstart, 216 .l_modem = nullmodem, 217 .l_poll = ttyerrpoll 218}; 219 220void 221slattach(int n __unused) 222{ 223 224 /* 225 * Nothing to do here, initialization is handled by the 226 * module initialization code in slinit() below). 227 */ 228} 229 230static void 231slinit(void) 232{ 233 234 if (ttyldisc_attach(&slip_disc) != 0) 235 panic("%s", __func__); 236 LIST_INIT(&sl_softc_list); 237 if_clone_attach(&sl_cloner); 238} 239 240static int 241sldetach(void) 242{ 243 int error = 0; 244 245 if (!LIST_EMPTY(&sl_softc_list)) 246 error = EBUSY; 247 248 if (error == 0) 249 error = ttyldisc_detach(&slip_disc); 250 251 if (error == 0) 252 if_clone_detach(&sl_cloner); 253 254 return error; 255} 256 257static int 258sl_clone_create(struct if_clone *ifc, int unit) 259{ 260 struct sl_softc *sc; 261 262 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAIT|M_ZERO); 263 sc->sc_unit = unit; 264 if_initname(&sc->sc_if, ifc->ifc_name, unit); 265 sc->sc_if.if_softc = sc; 266 sc->sc_if.if_mtu = SLMTU; 267 sc->sc_if.if_flags = IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST; 268 sc->sc_if.if_type = IFT_SLIP; 269 sc->sc_if.if_ioctl = slioctl; 270 sc->sc_if.if_output = sloutput; 271 sc->sc_if.if_dlt = DLT_SLIP; 272 sc->sc_fastq.ifq_maxlen = 32; 273 IFQ_SET_READY(&sc->sc_if.if_snd); 274 if_attach(&sc->sc_if); 275 if_alloc_sadl(&sc->sc_if); 276 bpf_attach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN); 277 LIST_INSERT_HEAD(&sl_softc_list, sc, sc_iflist); 278 return 0; 279} 280 281static int 282sl_clone_destroy(struct ifnet *ifp) 283{ 284 struct sl_softc *sc = (struct sl_softc *)ifp->if_softc; 285 286 if (sc->sc_ttyp != NULL) 287 return EBUSY; /* Not removing it */ 288 289 LIST_REMOVE(sc, sc_iflist); 290 291 bpf_detach(ifp); 292 if_detach(ifp); 293 294 free(sc, M_DEVBUF); 295 return 0; 296} 297 298static int 299slcreate(struct sl_softc *sc) 300{ 301 302 if (sc->sc_mbuf == NULL) { 303 sc->sc_mbuf = m_gethdr(M_WAIT, MT_DATA); 304 m_clget(sc->sc_mbuf, M_WAIT); 305 } 306 sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 307 sc->sc_mbuf->m_ext.ext_size; 308 sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 309 BUFOFFSET; 310 311#ifdef INET 312 sl_compress_init(&sc->sc_comp); 313#endif 314 315 return 1; 316} 317 318/* 319 * Line specific open routine. 320 * Attach the given tty to the first available sl unit. 321 */ 322/* ARGSUSED */ 323static int 324slopen(dev_t dev, struct tty *tp) 325{ 326 struct lwp *l = curlwp; /* XXX */ 327 struct sl_softc *sc; 328 int error; 329 330 error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_SLIP, 331 KAUTH_REQ_NETWORK_INTERFACE_SLIP_ADD, NULL, NULL, NULL); 332 if (error) 333 return error; 334 335 if (tp->t_linesw == &slip_disc) 336 return 0; 337 338 LIST_FOREACH(sc, &sl_softc_list, sc_iflist) 339 if (sc->sc_ttyp == NULL) { 340 sc->sc_si = softint_establish(SOFTINT_NET, 341 slintr, sc); 342 if (sc->sc_si == NULL) 343 return ENOMEM; 344 if (slcreate(sc) == 0) { 345 softint_disestablish(sc->sc_si); 346 return ENOBUFS; 347 } 348 tp->t_sc = (void *)sc; 349 sc->sc_ttyp = tp; 350 sc->sc_if.if_baudrate = tp->t_ospeed; 351 mutex_spin_enter(&tty_lock); 352 tp->t_state |= TS_ISOPEN | TS_XCLUDE; 353 ttyflush(tp, FREAD | FWRITE); 354 /* 355 * make sure tty output queue is large enough 356 * to hold a full-sized packet (including frame 357 * end, and a possible extra frame end). full-sized 358 * packet occupies a max of 2*SLMAX bytes (because 359 * of possible escapes), and add two on for frame 360 * ends. 361 */ 362 if (tp->t_outq.c_cn < 2 * SLMAX + 2) { 363 sc->sc_oldbufsize = tp->t_outq.c_cn; 364 sc->sc_oldbufquot = tp->t_outq.c_cq != 0; 365 366 clfree(&tp->t_outq); 367 mutex_spin_exit(&tty_lock); 368 error = clalloc(&tp->t_outq, 2 * SLMAX + 2, 0); 369 if (error) { 370 softint_disestablish(sc->sc_si); 371 /* 372 * clalloc() might return -1 which 373 * is no good, so we need to return 374 * something else. 375 */ 376 return ENOMEM; /* XXX ?! */ 377 } 378 } else { 379 sc->sc_oldbufsize = sc->sc_oldbufquot = 0; 380 mutex_spin_exit(&tty_lock); 381 } 382 return 0; 383 } 384 return ENXIO; 385} 386 387/* 388 * Line specific close routine. 389 * Detach the tty from the sl unit. 390 */ 391static int 392slclose(struct tty *tp, int flag) 393{ 394 struct sl_softc *sc; 395 int s; 396 397 ttywflush(tp); 398 sc = tp->t_sc; 399 400 if (sc != NULL) { 401 softint_disestablish(sc->sc_si); 402 s = splnet(); 403 if_down(&sc->sc_if); 404 IF_PURGE(&sc->sc_fastq); 405 splx(s); 406 407 s = spltty(); 408 ttyldisc_release(tp->t_linesw); 409 tp->t_linesw = ttyldisc_default(); 410 tp->t_state = 0; 411 412 sc->sc_ttyp = NULL; 413 tp->t_sc = NULL; 414 415 m_freem(sc->sc_mbuf); 416 sc->sc_mbuf = NULL; 417 sc->sc_ep = sc->sc_mp = sc->sc_pktstart = NULL; 418 IF_PURGE(&sc->sc_inq); 419 420 /* 421 * If necessary, install a new outq buffer of the 422 * appropriate size. 423 */ 424 if (sc->sc_oldbufsize != 0) { 425 clfree(&tp->t_outq); 426 clalloc(&tp->t_outq, sc->sc_oldbufsize, 427 sc->sc_oldbufquot); 428 } 429 splx(s); 430 } 431 432 return 0; 433} 434 435/* 436 * Line specific (tty) ioctl routine. 437 * Provide a way to get the sl unit number. 438 */ 439/* ARGSUSED */ 440static int 441sltioctl(struct tty *tp, u_long cmd, void *data, int flag, 442 struct lwp *l) 443{ 444 struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 445 446 switch (cmd) { 447 case SLIOCGUNIT: 448 *(int *)data = sc->sc_unit; /* XXX */ 449 break; 450 451 default: 452 return EPASSTHROUGH; 453 } 454 return 0; 455} 456 457/* 458 * Queue a packet. Start transmission if not active. 459 * Compression happens in slintr(); if we do it here, IP TOS 460 * will cause us to not compress "background" packets, because 461 * ordering gets trashed. It can be done for all packets in slintr(). 462 */ 463static int 464sloutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 465 const struct rtentry *rtp) 466{ 467 struct sl_softc *sc = ifp->if_softc; 468 struct ip *ip; 469 struct ifqueue *ifq = NULL; 470 int s, error; 471 472 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 473 474 /* 475 * `Cannot happen' (see slioctl). Someday we will extend 476 * the line protocol to support other address families. 477 */ 478 if (dst->sa_family != AF_INET) { 479 printf("%s: af%d not supported\n", sc->sc_if.if_xname, 480 dst->sa_family); 481 m_freem(m); 482 sc->sc_if.if_noproto++; 483 return EAFNOSUPPORT; 484 } 485 486 if (sc->sc_ttyp == NULL) { 487 m_freem(m); 488 return ENETDOWN; /* sort of */ 489 } 490 if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 && 491 (sc->sc_ttyp->t_cflag & CLOCAL) == 0) { 492 m_freem(m); 493 printf("%s: no carrier and not local\n", sc->sc_if.if_xname); 494 return EHOSTUNREACH; 495 } 496 ip = mtod(m, struct ip *); 497#ifdef INET 498 if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 499 m_freem(m); 500 return ENETRESET; /* XXX ? */ 501 } 502#endif 503 504 s = spltty(); 505 if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) { 506 struct bintime bt; 507 508 /* if output's been stalled for too long, and restart */ 509 getbinuptime(&bt); 510 bintime_sub(&bt, &sc->sc_lastpacket); 511 if (bt.sec > 0) { 512 sc->sc_otimeout++; 513 slstart(sc->sc_ttyp); 514 } 515 } 516 splx(s); 517 518 s = splnet(); 519#ifdef INET 520 if ((ip->ip_tos & IPTOS_LOWDELAY) != 0) 521 ifq = &sc->sc_fastq; 522#endif 523 if ((error = ifq_enqueue2(ifp, ifq, m)) != 0) { 524 splx(s); 525 return error; 526 } 527 getbinuptime(&sc->sc_lastpacket); 528 splx(s); 529 530 s = spltty(); 531 if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0) 532 slstart(sc->sc_ttyp); 533 splx(s); 534 535 return 0; 536} 537 538/* 539 * Start output on interface. Get another datagram 540 * to send from the interface queue and map it to 541 * the interface before starting output. 542 */ 543static int 544slstart(struct tty *tp) 545{ 546 struct sl_softc *sc = tp->t_sc; 547 548 /* 549 * If there is more in the output queue, just send it now. 550 * We are being called in lieu of ttstart and must do what 551 * it would. 552 */ 553 if (tp->t_outq.c_cc != 0) { 554 (*tp->t_oproc)(tp); 555 if (tp->t_outq.c_cc > SLIP_HIWAT) 556 return 0; 557 } 558 559 /* 560 * This happens briefly when the line shuts down. 561 */ 562 if (sc == NULL) 563 return 0; 564 softint_schedule(sc->sc_si); 565 return 0; 566} 567 568/* 569 * Copy data buffer to mbuf chain; add ifnet pointer. 570 */ 571static struct mbuf * 572sl_btom(struct sl_softc *sc, int len) 573{ 574 struct mbuf *m; 575 576 /* 577 * Allocate a new input buffer and swap. 578 */ 579 m = sc->sc_mbuf; 580 MGETHDR(sc->sc_mbuf, M_DONTWAIT, MT_DATA); 581 if (sc->sc_mbuf == NULL) { 582 sc->sc_mbuf = m; 583 return NULL; 584 } 585 MCLGET(sc->sc_mbuf, M_DONTWAIT); 586 if ((sc->sc_mbuf->m_flags & M_EXT) == 0) { 587 m_freem(sc->sc_mbuf); 588 sc->sc_mbuf = m; 589 return NULL; 590 } 591 sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 592 sc->sc_mbuf->m_ext.ext_size; 593 594 m->m_data = sc->sc_pktstart; 595 596 m->m_pkthdr.len = m->m_len = len; 597 m_set_rcvif(m, &sc->sc_if); 598 return m; 599} 600 601/* 602 * tty interface receiver interrupt. 603 */ 604static int 605slinput(int c, struct tty *tp) 606{ 607 struct sl_softc *sc; 608 struct mbuf *m; 609 int len; 610 611 tk_nin++; 612 sc = (struct sl_softc *)tp->t_sc; 613 if (sc == NULL) 614 return 0; 615 if ((c & TTY_ERRORMASK) || ((tp->t_state & TS_CARR_ON) == 0 && 616 (tp->t_cflag & CLOCAL) == 0)) { 617 sc->sc_flags |= SC_ERROR; 618 return 0; 619 } 620 c &= TTY_CHARMASK; 621 622 ++sc->sc_if.if_ibytes; 623 624 if (sc->sc_if.if_flags & IFF_DEBUG) { 625 if (c == ABT_ESC) { 626 /* 627 * If we have a previous abort, see whether 628 * this one is within the time limit. 629 */ 630 if (sc->sc_abortcount && 631 time_second >= sc->sc_starttime + ABT_WINDOW) 632 sc->sc_abortcount = 0; 633 /* 634 * If we see an abort after "idle" time, count it; 635 * record when the first abort escape arrived. 636 */ 637 if (time_second >= sc->sc_lasttime + ABT_IDLE) { 638 if (++sc->sc_abortcount == 1) 639 sc->sc_starttime = time_second; 640 if (sc->sc_abortcount >= ABT_COUNT) { 641 slclose(tp, 0); 642 return 0; 643 } 644 } 645 } else 646 sc->sc_abortcount = 0; 647 sc->sc_lasttime = time_second; 648 } 649 650 switch (c) { 651 652 case TRANS_FRAME_ESCAPE: 653 if (sc->sc_escape) 654 c = FRAME_ESCAPE; 655 break; 656 657 case TRANS_FRAME_END: 658 if (sc->sc_escape) 659 c = FRAME_END; 660 break; 661 662 case FRAME_ESCAPE: 663 sc->sc_escape = 1; 664 return 0; 665 666 case FRAME_END: 667 if (sc->sc_flags & SC_ERROR) { 668 sc->sc_flags &= ~SC_ERROR; 669 goto newpack; 670 } 671 len = sc->sc_mp - sc->sc_pktstart; 672 if (len < 3) 673 /* less than min length packet - ignore */ 674 goto newpack; 675 676 m = sl_btom(sc, len); 677 if (m == NULL) 678 goto error; 679 680 IF_ENQUEUE(&sc->sc_inq, m); 681 softint_schedule(sc->sc_si); 682 goto newpack; 683 } 684 if (sc->sc_mp < sc->sc_ep) { 685 *sc->sc_mp++ = c; 686 sc->sc_escape = 0; 687 return 0; 688 } 689 690 /* can't put lower; would miss an extra frame */ 691 sc->sc_flags |= SC_ERROR; 692 693error: 694 sc->sc_if.if_ierrors++; 695newpack: 696 sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 697 BUFOFFSET; 698 sc->sc_escape = 0; 699 700 return 0; 701} 702 703static void 704slintr(void *arg) 705{ 706 struct sl_softc *sc = arg; 707 struct tty *tp = sc->sc_ttyp; 708 struct mbuf *m, *n; 709 int s, len; 710 u_char *pktstart; 711 u_char chdr[CHDR_LEN]; 712 713 KASSERT(tp != NULL); 714 715 /* 716 * Output processing loop. 717 */ 718 mutex_enter(softnet_lock); 719 for (;;) { 720 struct mbuf *m2; 721 struct mbuf *bpf_m; 722 723 /* 724 * Do not remove the packet from the queue if it 725 * doesn't look like it will fit into the current 726 * serial output queue. With a packet full of 727 * escapes, this could be as bad as MTU*2+2. 728 */ 729 s = spltty(); 730 if (tp->t_outq.c_cn - tp->t_outq.c_cc < 731 2 * sc->sc_if.if_mtu + 2) { 732 splx(s); 733 break; 734 } 735 splx(s); 736 737 /* 738 * Get a packet and send it to the interface. 739 */ 740 s = splnet(); 741 IF_DEQUEUE(&sc->sc_fastq, m); 742 if (m) 743 sc->sc_if.if_omcasts++; /* XXX */ 744 else 745 IFQ_DEQUEUE(&sc->sc_if.if_snd, m); 746 splx(s); 747 748 if (m == NULL) 749 break; 750 751 /* 752 * We do the header compression here rather than in 753 * sloutput() because the packets will be out of order 754 * if we are using TOS queueing, and the connection 755 * ID compression will get munged when this happens. 756 */ 757 if (sc->sc_if.if_bpf) { 758 /* 759 * We need to save the TCP/IP header before 760 * it's compressed. To avoid complicated 761 * code, we just make a deep copy of the 762 * entire packet (since this is a serial 763 * line, packets should be short and/or the 764 * copy should be negligible cost compared 765 * to the packet transmission time). 766 */ 767 bpf_m = m_dup(m, 0, M_COPYALL, M_DONTWAIT); 768 } else 769 bpf_m = NULL; 770#ifdef INET 771 struct ip *ip; 772 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 773 if (sc->sc_if.if_flags & SC_COMPRESS) 774 *mtod(m, u_char *) |= 775 sl_compress_tcp(m, ip, &sc->sc_comp, 1); 776 } 777#endif 778 if (bpf_m) 779 bpf_mtap_sl_out(&sc->sc_if, mtod(m, u_char *), bpf_m); 780 getbinuptime(&sc->sc_lastpacket); 781 782 s = spltty(); 783 784 /* 785 * The extra FRAME_END will start up a new packet, 786 * and thus will flush any accumulated garbage. We 787 * do this whenever the line may have been idle for 788 * some time. 789 */ 790 if (tp->t_outq.c_cc == 0) { 791 sc->sc_if.if_obytes++; 792 (void)putc(FRAME_END, &tp->t_outq); 793 } 794 795 while (m) { 796 u_char *bp, *cp, *ep; 797 798 bp = cp = mtod(m, u_char *); 799 ep = cp + m->m_len; 800 while (cp < ep) { 801 /* 802 * Find out how many bytes in the 803 * string we can handle without 804 * doing something special. 805 */ 806 while (cp < ep) { 807 switch (*cp++) { 808 case FRAME_ESCAPE: 809 case FRAME_END: 810 cp--; 811 goto out; 812 } 813 } 814 out: 815 if (cp > bp) { 816 /* 817 * Put N characters at once 818 * into the tty output queue. 819 */ 820 if (b_to_q(bp, cp - bp, &tp->t_outq)) 821 break; 822 sc->sc_if.if_obytes += cp - bp; 823 } 824 /* 825 * If there are characters left in 826 * the mbuf, the first one must be 827 * special.. Put it out in a different 828 * form. 829 */ 830 if (cp < ep) { 831 if (putc(FRAME_ESCAPE, &tp->t_outq)) 832 break; 833 if (putc(*cp++ == FRAME_ESCAPE ? 834 TRANS_FRAME_ESCAPE : 835 TRANS_FRAME_END, 836 &tp->t_outq)) { 837 (void)unputc(&tp->t_outq); 838 break; 839 } 840 sc->sc_if.if_obytes += 2; 841 } 842 bp = cp; 843 } 844 m = m2 = m_free(m); 845 } 846 847 if (putc(FRAME_END, &tp->t_outq)) { 848 /* 849 * Not enough room. Remove a char to make 850 * room and end the packet normally. If 851 * you get many collisions (more than one 852 * or two a day), you probably do not have 853 * enough clists and you should increase 854 * "nclist" in param.c 855 */ 856 (void)unputc(&tp->t_outq); 857 (void)putc(FRAME_END, &tp->t_outq); 858 sc->sc_if.if_collisions++; 859 } else { 860 sc->sc_if.if_obytes++; 861 sc->sc_if.if_opackets++; 862 } 863 864 /* 865 * We now have characters in the output queue, 866 * kick the serial port. 867 */ 868 (*tp->t_oproc)(tp); 869 splx(s); 870 } 871 872 /* 873 * Input processing loop. 874 */ 875 for (;;) { 876 s = spltty(); 877 IF_DEQUEUE(&sc->sc_inq, m); 878 splx(s); 879 if (m == NULL) 880 break; 881 pktstart = mtod(m, u_char *); 882 len = m->m_pkthdr.len; 883 if (sc->sc_if.if_bpf) { 884 /* 885 * Save the compressed header, so we 886 * can tack it on later. Note that we 887 * will end up copying garbage in some 888 * cases but this is okay. We remember 889 * where the buffer started so we can 890 * compute the new header length. 891 */ 892 memcpy(chdr, pktstart, CHDR_LEN); 893 } 894#ifdef INET 895 u_char c; 896 if ((c = (*pktstart & 0xf0)) != (IPVERSION << 4)) { 897 if (c & 0x80) 898 c = TYPE_COMPRESSED_TCP; 899 else if (c == TYPE_UNCOMPRESSED_TCP) 900 *pktstart &= 0x4f; /* XXX */ 901 /* 902 * We've got something that's not an IP 903 * packet. If compression is enabled, 904 * try to decompress it. Otherwise, if 905 * `auto-enable' compression is on and 906 * it's a reasonable packet, decompress 907 * it and then enable compression. 908 * Otherwise, drop it. 909 */ 910 if (sc->sc_if.if_flags & SC_COMPRESS) { 911 len = sl_uncompress_tcp(&pktstart, len, 912 (u_int)c, &sc->sc_comp); 913 if (len <= 0) { 914 m_freem(m); 915 continue; 916 } 917 } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 918 c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 919 len = sl_uncompress_tcp(&pktstart, len, 920 (u_int)c, &sc->sc_comp); 921 if (len <= 0) { 922 m_freem(m); 923 continue; 924 } 925 sc->sc_if.if_flags |= SC_COMPRESS; 926 } else { 927 m_freem(m); 928 continue; 929 } 930 } 931#endif 932 m->m_data = (void *) pktstart; 933 m->m_pkthdr.len = m->m_len = len; 934 if (sc->sc_if.if_bpf) { 935 bpf_mtap_sl_in(&sc->sc_if, chdr, &m); 936 if (m == NULL) 937 continue; 938 } 939 /* 940 * If the packet will fit into a single 941 * header mbuf, try to copy it into one, 942 * to save memory. 943 */ 944 if ((m->m_pkthdr.len < MHLEN) && 945 (n = m_gethdr(M_DONTWAIT, MT_DATA))) { 946 int pktlen; 947 948 pktlen = m->m_pkthdr.len; 949 M_MOVE_PKTHDR(n, m); 950 memcpy(mtod(n, void *), mtod(m, void *), pktlen); 951 n->m_len = m->m_len; 952 m_freem(m); 953 m = n; 954 } 955 956 sc->sc_if.if_ipackets++; 957 getbinuptime(&sc->sc_lastpacket); 958 959#ifdef INET 960 s = splnet(); 961 if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) { 962 sc->sc_if.if_ierrors++; 963 sc->sc_if.if_iqdrops++; 964 m_freem(m); 965 } 966 splx(s); 967#endif 968 } 969 mutex_exit(softnet_lock); 970} 971 972/* 973 * Process an ioctl request. 974 */ 975static int 976slioctl(struct ifnet *ifp, u_long cmd, void *data) 977{ 978 struct ifaddr *ifa = (struct ifaddr *)data; 979 struct ifreq *ifr = (struct ifreq *)data; 980 int s = splnet(), error = 0; 981 struct sl_softc *sc = ifp->if_softc; 982 struct ppp_stats *psp; 983 struct ppp_comp_stats *pcp; 984 985 switch (cmd) { 986 987 case SIOCINITIFADDR: 988 if (ifa->ifa_addr->sa_family == AF_INET) 989 ifp->if_flags |= IFF_UP; 990 else 991 error = EAFNOSUPPORT; 992 break; 993 994 case SIOCSIFDSTADDR: 995 if (ifreq_getaddr(cmd, ifr)->sa_family != AF_INET) 996 error = EAFNOSUPPORT; 997 break; 998 999 case SIOCSIFMTU: 1000 if ((ifr->ifr_mtu < 3) || (ifr->ifr_mtu > SLMAX)) { 1001 error = EINVAL; 1002 break; 1003 } 1004 /*FALLTHROUGH*/ 1005 case SIOCGIFMTU: 1006 if ((error = ifioctl_common(&sc->sc_if, cmd, data)) == ENETRESET) 1007 error = 0; 1008 break; 1009 1010 case SIOCADDMULTI: 1011 case SIOCDELMULTI: 1012 if (ifr == 0) { 1013 error = EAFNOSUPPORT; /* XXX */ 1014 break; 1015 } 1016 switch (ifreq_getaddr(cmd, ifr)->sa_family) { 1017 1018#ifdef INET 1019 case AF_INET: 1020 break; 1021#endif 1022 1023 default: 1024 error = EAFNOSUPPORT; 1025 break; 1026 } 1027 break; 1028 1029 case SIOCGPPPSTATS: 1030 psp = &((struct ifpppstatsreq *) data)->stats; 1031 (void)memset(psp, 0, sizeof(*psp)); 1032 psp->p.ppp_ibytes = sc->sc_if.if_ibytes; 1033 psp->p.ppp_ipackets = sc->sc_if.if_ipackets; 1034 psp->p.ppp_ierrors = sc->sc_if.if_ierrors; 1035 psp->p.ppp_obytes = sc->sc_if.if_obytes; 1036 psp->p.ppp_opackets = sc->sc_if.if_opackets; 1037 psp->p.ppp_oerrors = sc->sc_if.if_oerrors; 1038#ifdef INET 1039 psp->vj.vjs_packets = sc->sc_comp.sls_packets; 1040 psp->vj.vjs_compressed = sc->sc_comp.sls_compressed; 1041 psp->vj.vjs_searches = sc->sc_comp.sls_searches; 1042 psp->vj.vjs_misses = sc->sc_comp.sls_misses; 1043 psp->vj.vjs_uncompressedin = sc->sc_comp.sls_uncompressedin; 1044 psp->vj.vjs_compressedin = sc->sc_comp.sls_compressedin; 1045 psp->vj.vjs_errorin = sc->sc_comp.sls_errorin; 1046 psp->vj.vjs_tossed = sc->sc_comp.sls_tossed; 1047#endif 1048 break; 1049 1050 case SIOCGPPPCSTATS: 1051 pcp = &((struct ifpppcstatsreq *) data)->stats; 1052 (void)memset(pcp, 0, sizeof(*pcp)); 1053 break; 1054 1055 default: 1056 error = ifioctl_common(ifp, cmd, data); 1057 break; 1058 } 1059 splx(s); 1060 return error; 1061} 1062 1063 1064/* 1065 * Module infrastructure 1066 */ 1067 1068#include "if_module.h" 1069 1070IF_MODULE(MODULE_CLASS_DRIVER, sl, "slcompress"); 1071