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