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