if_sl.c revision 1.134
1/* $NetBSD: if_sl.c,v 1.134 2022/08/27 19:19:10 thorpej 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.134 2022/08/27 19:19:10 thorpej 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 IFQ_SET_MAXLEN(&sc->sc_fastq, 32); 273 IFQ_LOCK_INIT(&sc->sc_fastq); 274 IFQ_SET_READY(&sc->sc_if.if_snd); 275 if_attach(&sc->sc_if); 276 if_alloc_sadl(&sc->sc_if); 277 bpf_attach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN); 278 LIST_INSERT_HEAD(&sl_softc_list, sc, sc_iflist); 279 return 0; 280} 281 282static int 283sl_clone_destroy(struct ifnet *ifp) 284{ 285 struct sl_softc *sc = (struct sl_softc *)ifp->if_softc; 286 287 if (sc->sc_ttyp != NULL) 288 return EBUSY; /* Not removing it */ 289 290 LIST_REMOVE(sc, sc_iflist); 291 292 bpf_detach(ifp); 293 if_detach(ifp); 294 295 IFQ_LOCK_DESTROY(&sc->sc_fastq); 296 297 free(sc, M_DEVBUF); 298 return 0; 299} 300 301static int 302slcreate(struct sl_softc *sc) 303{ 304 305 if (sc->sc_mbuf == NULL) { 306 sc->sc_mbuf = m_gethdr(M_WAIT, MT_DATA); 307 m_clget(sc->sc_mbuf, M_WAIT); 308 } 309 sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 310 sc->sc_mbuf->m_ext.ext_size; 311 sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 312 BUFOFFSET; 313 314#ifdef INET 315 sl_compress_init(&sc->sc_comp); 316#endif 317 318 return 1; 319} 320 321/* 322 * Line specific open routine. 323 * Attach the given tty to the first available sl unit. 324 */ 325/* ARGSUSED */ 326static int 327slopen(dev_t dev, struct tty *tp) 328{ 329 struct lwp *l = curlwp; /* XXX */ 330 struct sl_softc *sc; 331 int error; 332 333 error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_SLIP, 334 KAUTH_REQ_NETWORK_INTERFACE_SLIP_ADD, NULL, NULL, NULL); 335 if (error) 336 return error; 337 338 if (tp->t_linesw == &slip_disc) 339 return 0; 340 341 LIST_FOREACH(sc, &sl_softc_list, sc_iflist) 342 if (sc->sc_ttyp == NULL) { 343 sc->sc_si = softint_establish(SOFTINT_NET, 344 slintr, sc); 345 if (sc->sc_si == NULL) 346 return ENOMEM; 347 if (slcreate(sc) == 0) { 348 softint_disestablish(sc->sc_si); 349 return ENOBUFS; 350 } 351 tp->t_sc = (void *)sc; 352 sc->sc_ttyp = tp; 353 sc->sc_if.if_baudrate = tp->t_ospeed; 354 mutex_spin_enter(&tty_lock); 355 tp->t_state |= TS_ISOPEN | TS_XCLUDE; 356 ttyflush(tp, FREAD | FWRITE); 357 /* 358 * make sure tty output queue is large enough 359 * to hold a full-sized packet (including frame 360 * end, and a possible extra frame end). full-sized 361 * packet occupies a max of 2*SLMAX bytes (because 362 * of possible escapes), and add two on for frame 363 * ends. 364 */ 365 if (tp->t_outq.c_cn < 2 * SLMAX + 2) { 366 sc->sc_oldbufsize = tp->t_outq.c_cn; 367 sc->sc_oldbufquot = tp->t_outq.c_cq != 0; 368 369 clfree(&tp->t_outq); 370 mutex_spin_exit(&tty_lock); 371 error = clalloc(&tp->t_outq, 2 * SLMAX + 2, 0); 372 if (error) { 373 softint_disestablish(sc->sc_si); 374 /* 375 * clalloc() might return -1 which 376 * is no good, so we need to return 377 * something else. 378 */ 379 return ENOMEM; /* XXX ?! */ 380 } 381 } else { 382 sc->sc_oldbufsize = sc->sc_oldbufquot = 0; 383 mutex_spin_exit(&tty_lock); 384 } 385 return 0; 386 } 387 return ENXIO; 388} 389 390/* 391 * Line specific close routine. 392 * Detach the tty from the sl unit. 393 */ 394static int 395slclose(struct tty *tp, int flag) 396{ 397 struct sl_softc *sc; 398 int s; 399 400 ttywflush(tp); 401 sc = tp->t_sc; 402 403 if (sc != NULL) { 404 softint_disestablish(sc->sc_si); 405 s = splnet(); 406 if_down(&sc->sc_if); 407 IF_PURGE(&sc->sc_fastq); 408 splx(s); 409 410 s = spltty(); 411 ttyldisc_release(tp->t_linesw); 412 tp->t_linesw = ttyldisc_default(); 413 tp->t_state = 0; 414 415 sc->sc_ttyp = NULL; 416 tp->t_sc = NULL; 417 418 m_freem(sc->sc_mbuf); 419 sc->sc_mbuf = NULL; 420 sc->sc_ep = sc->sc_mp = sc->sc_pktstart = NULL; 421 IF_PURGE(&sc->sc_inq); 422 423 /* 424 * If necessary, install a new outq buffer of the 425 * appropriate size. 426 */ 427 if (sc->sc_oldbufsize != 0) { 428 clfree(&tp->t_outq); 429 clalloc(&tp->t_outq, sc->sc_oldbufsize, 430 sc->sc_oldbufquot); 431 } 432 splx(s); 433 } 434 435 return 0; 436} 437 438/* 439 * Line specific (tty) ioctl routine. 440 * Provide a way to get the sl unit number. 441 */ 442/* ARGSUSED */ 443static int 444sltioctl(struct tty *tp, u_long cmd, void *data, int flag, 445 struct lwp *l) 446{ 447 struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 448 449 /* 450 * XXX 451 * This function can be called without KERNEL_LOCK when caller's 452 * struct cdevsw is set D_MPSAFE. Is KERNEL_LOCK required? 453 */ 454 455 switch (cmd) { 456 case SLIOCGUNIT: 457 *(int *)data = sc->sc_unit; /* XXX */ 458 break; 459 460 default: 461 return EPASSTHROUGH; 462 } 463 return 0; 464} 465 466/* 467 * Queue a packet. Start transmission if not active. 468 * Compression happens in slintr(); if we do it here, IP TOS 469 * will cause us to not compress "background" packets, because 470 * ordering gets trashed. It can be done for all packets in slintr(). 471 */ 472static int 473sloutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 474 const struct rtentry *rtp) 475{ 476 struct sl_softc *sc = ifp->if_softc; 477 struct ip *ip; 478 struct ifqueue *ifq = NULL; 479 int s, error; 480 481 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 482 483 /* 484 * `Cannot happen' (see slioctl). Someday we will extend 485 * the line protocol to support other address families. 486 */ 487 if (dst->sa_family != AF_INET) { 488 printf("%s: af%d not supported\n", sc->sc_if.if_xname, 489 dst->sa_family); 490 m_freem(m); 491 if_statinc(&sc->sc_if, if_noproto); 492 return EAFNOSUPPORT; 493 } 494 495 if (sc->sc_ttyp == NULL) { 496 m_freem(m); 497 return ENETDOWN; /* sort of */ 498 } 499 if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 && 500 (sc->sc_ttyp->t_cflag & CLOCAL) == 0) { 501 m_freem(m); 502 printf("%s: no carrier and not local\n", sc->sc_if.if_xname); 503 return EHOSTUNREACH; 504 } 505 ip = mtod(m, struct ip *); 506#ifdef INET 507 if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 508 m_freem(m); 509 return ENETRESET; /* XXX ? */ 510 } 511#endif 512 513 s = spltty(); 514 if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) { 515 struct bintime bt; 516 517 /* if output's been stalled for too long, and restart */ 518 getbinuptime(&bt); 519 bintime_sub(&bt, &sc->sc_lastpacket); 520 if (bt.sec > 0) { 521 sc->sc_otimeout++; 522 slstart(sc->sc_ttyp); 523 } 524 } 525 splx(s); 526 527 s = splnet(); 528#ifdef INET 529 if ((ip->ip_tos & IPTOS_LOWDELAY) != 0) 530 ifq = &sc->sc_fastq; 531#endif 532 if ((error = ifq_enqueue2(ifp, ifq, m)) != 0) { 533 splx(s); 534 return error; 535 } 536 getbinuptime(&sc->sc_lastpacket); 537 splx(s); 538 539 s = spltty(); 540 if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0) 541 slstart(sc->sc_ttyp); 542 splx(s); 543 544 return 0; 545} 546 547/* 548 * Start output on interface. Get another datagram 549 * to send from the interface queue and map it to 550 * the interface before starting output. 551 */ 552static int 553slstart(struct tty *tp) 554{ 555 struct sl_softc *sc = tp->t_sc; 556 557 /* 558 * If there is more in the output queue, just send it now. 559 * We are being called in lieu of ttstart and must do what 560 * it would. 561 */ 562 if (tp->t_outq.c_cc != 0) { 563 (*tp->t_oproc)(tp); 564 if (tp->t_outq.c_cc > SLIP_HIWAT) 565 return 0; 566 } 567 568 /* 569 * This happens briefly when the line shuts down. 570 */ 571 if (sc == NULL) 572 return 0; 573 softint_schedule(sc->sc_si); 574 return 0; 575} 576 577/* 578 * Copy data buffer to mbuf chain; add ifnet pointer. 579 */ 580static struct mbuf * 581sl_btom(struct sl_softc *sc, int len) 582{ 583 struct mbuf *m; 584 585 /* 586 * Allocate a new input buffer and swap. 587 */ 588 m = sc->sc_mbuf; 589 MGETHDR(sc->sc_mbuf, M_DONTWAIT, MT_DATA); 590 if (sc->sc_mbuf == NULL) { 591 sc->sc_mbuf = m; 592 return NULL; 593 } 594 MCLGET(sc->sc_mbuf, M_DONTWAIT); 595 if ((sc->sc_mbuf->m_flags & M_EXT) == 0) { 596 m_freem(sc->sc_mbuf); 597 sc->sc_mbuf = m; 598 return NULL; 599 } 600 sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 601 sc->sc_mbuf->m_ext.ext_size; 602 603 m->m_data = sc->sc_pktstart; 604 605 m->m_pkthdr.len = m->m_len = len; 606 m_set_rcvif(m, &sc->sc_if); 607 return m; 608} 609 610/* 611 * tty interface receiver interrupt. 612 */ 613static int 614slinput(int c, struct tty *tp) 615{ 616 struct sl_softc *sc; 617 struct mbuf *m; 618 int len; 619 620 tk_nin++; 621 sc = (struct sl_softc *)tp->t_sc; 622 if (sc == NULL) 623 return 0; 624 if ((c & TTY_ERRORMASK) || ((tp->t_state & TS_CARR_ON) == 0 && 625 (tp->t_cflag & CLOCAL) == 0)) { 626 sc->sc_flags |= SC_ERROR; 627 return 0; 628 } 629 c &= TTY_CHARMASK; 630 631 if_statinc(&sc->sc_if, if_ibytes); 632 633 if (sc->sc_if.if_flags & IFF_DEBUG) { 634 if (c == ABT_ESC) { 635 /* 636 * If we have a previous abort, see whether 637 * this one is within the time limit. 638 */ 639 if (sc->sc_abortcount && 640 time_second >= sc->sc_starttime + ABT_WINDOW) 641 sc->sc_abortcount = 0; 642 /* 643 * If we see an abort after "idle" time, count it; 644 * record when the first abort escape arrived. 645 */ 646 if (time_second >= sc->sc_lasttime + ABT_IDLE) { 647 if (++sc->sc_abortcount == 1) 648 sc->sc_starttime = time_second; 649 if (sc->sc_abortcount >= ABT_COUNT) { 650 slclose(tp, 0); 651 return 0; 652 } 653 } 654 } else 655 sc->sc_abortcount = 0; 656 sc->sc_lasttime = time_second; 657 } 658 659 switch (c) { 660 661 case TRANS_FRAME_ESCAPE: 662 if (sc->sc_escape) 663 c = FRAME_ESCAPE; 664 break; 665 666 case TRANS_FRAME_END: 667 if (sc->sc_escape) 668 c = FRAME_END; 669 break; 670 671 case FRAME_ESCAPE: 672 sc->sc_escape = 1; 673 return 0; 674 675 case FRAME_END: 676 if (sc->sc_flags & SC_ERROR) { 677 sc->sc_flags &= ~SC_ERROR; 678 goto newpack; 679 } 680 len = sc->sc_mp - sc->sc_pktstart; 681 if (len < 3) 682 /* less than min length packet - ignore */ 683 goto newpack; 684 685 m = sl_btom(sc, len); 686 if (m == NULL) 687 goto error; 688 689 IF_ENQUEUE(&sc->sc_inq, m); 690 softint_schedule(sc->sc_si); 691 goto newpack; 692 } 693 if (sc->sc_mp < sc->sc_ep) { 694 *sc->sc_mp++ = c; 695 sc->sc_escape = 0; 696 return 0; 697 } 698 699 /* can't put lower; would miss an extra frame */ 700 sc->sc_flags |= SC_ERROR; 701 702error: 703 if_statinc(&sc->sc_if, if_ierrors); 704newpack: 705 sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 706 BUFOFFSET; 707 sc->sc_escape = 0; 708 709 return 0; 710} 711 712static void 713slintr(void *arg) 714{ 715 struct sl_softc *sc = arg; 716 struct tty *tp = sc->sc_ttyp; 717 struct mbuf *m, *n; 718 int s, len; 719 u_char *pktstart; 720 u_char chdr[CHDR_LEN]; 721 722 KASSERT(tp != NULL); 723 724 /* 725 * Output processing loop. 726 */ 727 mutex_enter(softnet_lock); 728 for (;;) { 729 struct mbuf *m2; 730 struct mbuf *bpf_m; 731 732 /* 733 * Do not remove the packet from the queue if it 734 * doesn't look like it will fit into the current 735 * serial output queue. With a packet full of 736 * escapes, this could be as bad as MTU*2+2. 737 */ 738 s = spltty(); 739 if (tp->t_outq.c_cn - tp->t_outq.c_cc < 740 2 * sc->sc_if.if_mtu + 2) { 741 splx(s); 742 break; 743 } 744 splx(s); 745 746 /* 747 * Get a packet and send it to the interface. 748 */ 749 s = splnet(); 750 IF_DEQUEUE(&sc->sc_fastq, m); 751 if (m) 752 if_statinc(&sc->sc_if, if_omcasts); /* XXX */ 753 else 754 IFQ_DEQUEUE(&sc->sc_if.if_snd, m); 755 splx(s); 756 757 if (m == NULL) 758 break; 759 760 /* 761 * We do the header compression here rather than in 762 * sloutput() because the packets will be out of order 763 * if we are using TOS queueing, and the connection 764 * ID compression will get munged when this happens. 765 */ 766 if (sc->sc_if.if_bpf) { 767 /* 768 * We need to save the TCP/IP header before 769 * it's compressed. To avoid complicated 770 * code, we just make a deep copy of the 771 * entire packet (since this is a serial 772 * line, packets should be short and/or the 773 * copy should be negligible cost compared 774 * to the packet transmission time). 775 */ 776 bpf_m = m_dup(m, 0, M_COPYALL, M_DONTWAIT); 777 } else 778 bpf_m = NULL; 779#ifdef INET 780 struct ip *ip; 781 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 782 if (sc->sc_if.if_flags & SC_COMPRESS) 783 *mtod(m, u_char *) |= 784 sl_compress_tcp(m, ip, &sc->sc_comp, 1); 785 } 786#endif 787 if (bpf_m) 788 bpf_mtap_sl_out(&sc->sc_if, mtod(m, u_char *), bpf_m); 789 getbinuptime(&sc->sc_lastpacket); 790 791 s = spltty(); 792 793 /* 794 * The extra FRAME_END will start up a new packet, 795 * and thus will flush any accumulated garbage. We 796 * do this whenever the line may have been idle for 797 * some time. 798 */ 799 if (tp->t_outq.c_cc == 0) { 800 if_statinc(&sc->sc_if, if_obytes); 801 (void)putc(FRAME_END, &tp->t_outq); 802 } 803 804 while (m) { 805 u_char *bp, *cp, *ep; 806 807 bp = cp = mtod(m, u_char *); 808 ep = cp + m->m_len; 809 while (cp < ep) { 810 /* 811 * Find out how many bytes in the 812 * string we can handle without 813 * doing something special. 814 */ 815 while (cp < ep) { 816 switch (*cp++) { 817 case FRAME_ESCAPE: 818 case FRAME_END: 819 cp--; 820 goto out; 821 } 822 } 823 out: 824 if (cp > bp) { 825 /* 826 * Put N characters at once 827 * into the tty output queue. 828 */ 829 if (b_to_q(bp, cp - bp, &tp->t_outq)) 830 break; 831 if_statadd(&sc->sc_if, if_obytes, 832 cp - bp); 833 } 834 /* 835 * If there are characters left in 836 * the mbuf, the first one must be 837 * special.. Put it out in a different 838 * form. 839 */ 840 if (cp < ep) { 841 if (putc(FRAME_ESCAPE, &tp->t_outq)) 842 break; 843 if (putc(*cp++ == FRAME_ESCAPE ? 844 TRANS_FRAME_ESCAPE : 845 TRANS_FRAME_END, 846 &tp->t_outq)) { 847 (void)unputc(&tp->t_outq); 848 break; 849 } 850 if_statadd(&sc->sc_if, if_obytes, 2); 851 } 852 bp = cp; 853 } 854 m = m2 = m_free(m); 855 } 856 857 if (putc(FRAME_END, &tp->t_outq)) { 858 /* 859 * Not enough room. Remove a char to make 860 * room and end the packet normally. If 861 * you get many collisions (more than one 862 * or two a day), you probably do not have 863 * enough clists and you should increase 864 * "nclist" in param.c 865 */ 866 (void)unputc(&tp->t_outq); 867 (void)putc(FRAME_END, &tp->t_outq); 868 if_statinc(&sc->sc_if, if_collisions); 869 } else { 870 if_statadd2(&sc->sc_if, if_obytes, 1, if_opackets, 1); 871 } 872 873 /* 874 * We now have characters in the output queue, 875 * kick the serial port. 876 */ 877 (*tp->t_oproc)(tp); 878 splx(s); 879 } 880 881 /* 882 * Input processing loop. 883 */ 884 for (;;) { 885 s = spltty(); 886 IF_DEQUEUE(&sc->sc_inq, m); 887 splx(s); 888 if (m == NULL) 889 break; 890 pktstart = mtod(m, u_char *); 891 len = m->m_pkthdr.len; 892 if (sc->sc_if.if_bpf) { 893 /* 894 * Save the compressed header, so we 895 * can tack it on later. Note that we 896 * will end up copying garbage in some 897 * cases but this is okay. We remember 898 * where the buffer started so we can 899 * compute the new header length. 900 */ 901 memcpy(chdr, pktstart, CHDR_LEN); 902 } 903#ifdef INET 904 u_char c; 905 if ((c = (*pktstart & 0xf0)) != (IPVERSION << 4)) { 906 if (c & 0x80) 907 c = TYPE_COMPRESSED_TCP; 908 else if (c == TYPE_UNCOMPRESSED_TCP) 909 *pktstart &= 0x4f; /* XXX */ 910 /* 911 * We've got something that's not an IP 912 * packet. If compression is enabled, 913 * try to decompress it. Otherwise, if 914 * `auto-enable' compression is on and 915 * it's a reasonable packet, decompress 916 * it and then enable compression. 917 * Otherwise, drop it. 918 */ 919 if (sc->sc_if.if_flags & SC_COMPRESS) { 920 len = sl_uncompress_tcp(&pktstart, len, 921 (u_int)c, &sc->sc_comp); 922 if (len <= 0) { 923 m_freem(m); 924 continue; 925 } 926 } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 927 c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 928 len = sl_uncompress_tcp(&pktstart, len, 929 (u_int)c, &sc->sc_comp); 930 if (len <= 0) { 931 m_freem(m); 932 continue; 933 } 934 sc->sc_if.if_flags |= SC_COMPRESS; 935 } else { 936 m_freem(m); 937 continue; 938 } 939 } 940#endif 941 m->m_data = (void *) pktstart; 942 m->m_pkthdr.len = m->m_len = len; 943 if (sc->sc_if.if_bpf) { 944 bpf_mtap_sl_in(&sc->sc_if, chdr, &m); 945 if (m == NULL) 946 continue; 947 } 948 /* 949 * If the packet will fit into a single 950 * header mbuf, try to copy it into one, 951 * to save memory. 952 */ 953 if ((m->m_pkthdr.len < MHLEN) && 954 (n = m_gethdr(M_DONTWAIT, MT_DATA))) { 955 int pktlen; 956 957 pktlen = m->m_pkthdr.len; 958 m_move_pkthdr(n, m); 959 memcpy(mtod(n, void *), mtod(m, void *), pktlen); 960 n->m_len = m->m_len; 961 m_freem(m); 962 m = n; 963 } 964 965 if_statinc(&sc->sc_if, if_ipackets); 966 getbinuptime(&sc->sc_lastpacket); 967 968#ifdef INET 969 s = splnet(); 970 if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) { 971 if_statadd2(&sc->sc_if, if_ierrors, 1, if_iqdrops, 1); 972 m_freem(m); 973 } 974 splx(s); 975#endif 976 } 977 mutex_exit(softnet_lock); 978} 979 980/* 981 * Process an ioctl request. 982 */ 983static int 984slioctl(struct ifnet *ifp, u_long cmd, void *data) 985{ 986 struct ifaddr *ifa = (struct ifaddr *)data; 987 struct ifreq *ifr = (struct ifreq *)data; 988 int s = splnet(), error = 0; 989 struct sl_softc *sc = ifp->if_softc; 990 struct ppp_stats *psp; 991 struct ppp_comp_stats *pcp; 992 993 switch (cmd) { 994 995 case SIOCINITIFADDR: 996 if (ifa->ifa_addr->sa_family == AF_INET) 997 ifp->if_flags |= IFF_UP; 998 else 999 error = EAFNOSUPPORT; 1000 break; 1001 1002 case SIOCSIFDSTADDR: 1003 if (ifreq_getaddr(cmd, ifr)->sa_family != AF_INET) 1004 error = EAFNOSUPPORT; 1005 break; 1006 1007 case SIOCSIFMTU: 1008 if ((ifr->ifr_mtu < 3) || (ifr->ifr_mtu > SLMAX)) { 1009 error = EINVAL; 1010 break; 1011 } 1012 /*FALLTHROUGH*/ 1013 case SIOCGIFMTU: 1014 if ((error = ifioctl_common(&sc->sc_if, cmd, data)) == ENETRESET) 1015 error = 0; 1016 break; 1017 1018 case SIOCADDMULTI: 1019 case SIOCDELMULTI: 1020 if (ifr == 0) { 1021 error = EAFNOSUPPORT; /* XXX */ 1022 break; 1023 } 1024 switch (ifreq_getaddr(cmd, ifr)->sa_family) { 1025 1026#ifdef INET 1027 case AF_INET: 1028 break; 1029#endif 1030 1031 default: 1032 error = EAFNOSUPPORT; 1033 break; 1034 } 1035 break; 1036 1037 case SIOCGPPPSTATS: { 1038 struct if_data ifi; 1039 1040 if_export_if_data(&sc->sc_if, &ifi, false); 1041 psp = &((struct ifpppstatsreq *) data)->stats; 1042 (void)memset(psp, 0, sizeof(*psp)); 1043 psp->p.ppp_ibytes = ifi.ifi_ibytes; 1044 psp->p.ppp_ipackets = ifi.ifi_ipackets; 1045 psp->p.ppp_ierrors = ifi.ifi_ierrors; 1046 psp->p.ppp_obytes = ifi.ifi_obytes; 1047 psp->p.ppp_opackets = ifi.ifi_opackets; 1048 psp->p.ppp_oerrors = ifi.ifi_oerrors; 1049#ifdef INET 1050 psp->vj.vjs_packets = sc->sc_comp.sls_packets; 1051 psp->vj.vjs_compressed = sc->sc_comp.sls_compressed; 1052 psp->vj.vjs_searches = sc->sc_comp.sls_searches; 1053 psp->vj.vjs_misses = sc->sc_comp.sls_misses; 1054 psp->vj.vjs_uncompressedin = sc->sc_comp.sls_uncompressedin; 1055 psp->vj.vjs_compressedin = sc->sc_comp.sls_compressedin; 1056 psp->vj.vjs_errorin = sc->sc_comp.sls_errorin; 1057 psp->vj.vjs_tossed = sc->sc_comp.sls_tossed; 1058#endif 1059 } 1060 break; 1061 1062 case SIOCGPPPCSTATS: 1063 pcp = &((struct ifpppcstatsreq *) data)->stats; 1064 (void)memset(pcp, 0, sizeof(*pcp)); 1065 break; 1066 1067 default: 1068 error = ifioctl_common(ifp, cmd, data); 1069 break; 1070 } 1071 splx(s); 1072 return error; 1073} 1074 1075 1076/* 1077 * Module infrastructure 1078 */ 1079 1080#include "if_module.h" 1081 1082IF_MODULE(MODULE_CLASS_DRIVER, sl, "slcompress"); 1083