if_ppp.c revision 1.9
1/* 2 * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver. 3 * 4 * Copyright (c) 1989 Carnegie Mellon University. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms are permitted 8 * provided that the above copyright notice and this paragraph are 9 * duplicated in all such forms and that any documentation, 10 * advertising materials, and other materials related to such 11 * distribution and use acknowledge that the software was developed 12 * by Carnegie Mellon University. The name of the 13 * University may not be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 18 * 19 * Drew D. Perkins 20 * Carnegie Mellon University 21 * 4910 Forbes Ave. 22 * Pittsburgh, PA 15213 23 * (412) 268-8576 24 * ddp@andrew.cmu.edu 25 * 26 * Based on: 27 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 28 * 29 * Copyright (c) 1987 Regents of the University of California. 30 * All rights reserved. 31 * 32 * Redistribution and use in source and binary forms are permitted 33 * provided that the above copyright notice and this paragraph are 34 * duplicated in all such forms and that any documentation, 35 * advertising materials, and other materials related to such 36 * distribution and use acknowledge that the software was developed 37 * by the University of California, Berkeley. The name of the 38 * University may not be used to endorse or promote products derived 39 * from this software without specific prior written permission. 40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 41 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 42 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 43 * 44 * Serial Line interface 45 * 46 * Rick Adams 47 * Center for Seismic Studies 48 * 1300 N 17th Street, Suite 1450 49 * Arlington, Virginia 22209 50 * (703)276-7900 51 * rick@seismo.ARPA 52 * seismo!rick 53 * 54 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 55 * Converted to 4.3BSD Beta by Chris Torek. 56 * Other changes made at Berkeley, based in part on code by Kirk Smith. 57 * 58 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) 59 * Added VJ tcp header compression; more unified ioctls 60 * 61 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). 62 * Cleaned up a lot of the mbuf-related code to fix bugs that 63 * caused system crashes and packet corruption. Changed pppstart 64 * so that it doesn't just give up with a collision if the whole 65 * packet doesn't fit in the output ring buffer. 66 * 67 * Added priority queueing for interactive IP packets, following 68 * the model of if_sl.c, plus hooks for bpf. 69 * Paul Mackerras (paulus@cs.anu.edu.au). 70 */ 71 72/* $Id: if_ppp.c,v 1.9 1994/05/13 06:02:48 mycroft Exp $ */ 73/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 74 75#include "ppp.h" 76#if NPPP > 0 77 78#define VJC 79 80#include <sys/param.h> 81#include <sys/proc.h> 82#include <sys/mbuf.h> 83#include <sys/buf.h> 84#include <sys/dkstat.h> 85#include <sys/socket.h> 86#include <sys/ioctl.h> 87#include <sys/file.h> 88#include <sys/tty.h> 89#include <sys/kernel.h> 90#include <sys/conf.h> 91#include <sys/vnode.h> 92 93#include <net/if.h> 94#include <net/if_types.h> 95#include <net/netisr.h> 96#include <net/route.h> 97 98#if INET 99#include <netinet/in.h> 100#include <netinet/in_systm.h> 101#include <netinet/in_var.h> 102#include <netinet/ip.h> 103#endif 104 105#include "bpfilter.h" 106#if NBPFILTER > 0 107#include <sys/time.h> 108#include <net/bpf.h> 109#endif 110 111#ifdef VJC 112#include <net/slcompress.h> 113#define HDROFF MAX_HDR 114/* HDROFF should really be 128, but other parts of the system will 115 panic on TCP+IP headers bigger than MAX_HDR = MHLEN (100). */ 116 117#else 118#define HDROFF (0) 119#endif 120 121#include <net/if_ppp.h> 122#include <machine/cpu.h> 123 124/* This is a NetBSD-current kernel. */ 125#define CCOUNT(q) ((q)->c_cc) 126 127#define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */ 128 129struct ppp_softc ppp_softc[NPPP]; 130 131void pppattach __P((void)); 132int pppopen __P((dev_t dev, struct tty *tp)); 133void pppclose __P((struct tty *tp, int flag)); 134int pppread __P((struct tty *tp, struct uio *uio, int flag)); 135int pppwrite __P((struct tty *tp, struct uio *uio, int flag)); 136int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag, 137 struct proc *)); 138int pppoutput __P((struct ifnet *ifp, struct mbuf *m0, 139 struct sockaddr *dst, struct rtentry *rtp)); 140void pppinput __P((int c, struct tty *tp)); 141int pppioctl __P((struct ifnet *ifp, int cmd, caddr_t data)); 142void pppstart __P((struct tty *tp)); 143 144static int pppasyncstart __P((struct ppp_softc *)); 145static u_short pppfcs __P((u_short fcs, u_char *cp, int len)); 146static int pppgetm __P((struct ppp_softc *sc)); 147static struct mbuf *ppp_btom __P((struct ppp_softc *sc)); 148static void pppdumpm __P((struct mbuf *m0, int pktlen)); 149static void pppdumpb __P((u_char *b, int l)); 150static void ppplogchar __P((struct ppp_softc *, int)); 151 152/* 153 * Some useful mbuf macros not in mbuf.h. 154 */ 155#define M_DATASTART(m) \ 156 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf : \ 157 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) 158 159#define M_DATASIZE(m) \ 160 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_size : \ 161 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) 162 163/* 164 * The following disgusting hack gets around the problem that IP TOS 165 * can't be set yet. We want to put "interactive" traffic on a high 166 * priority queue. To decide if traffic is interactive, we check that 167 * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 168 */ 169static u_short interactive_ports[8] = { 170 0, 513, 0, 0, 171 0, 21, 0, 23, 172}; 173#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 174 175/* 176 * Does c need to be escaped? 177 */ 178#define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) 179 180/* 181 * Called from boot code to establish ppp interfaces. 182 */ 183void 184pppattach() 185{ 186 register struct ppp_softc *sc; 187 register int i = 0; 188 189 for (sc = ppp_softc; i < NPPP; sc++) { 190 sc->sc_if.if_name = "ppp"; 191 sc->sc_if.if_unit = i++; 192 sc->sc_if.if_mtu = PPP_MTU; 193 sc->sc_if.if_flags = IFF_POINTOPOINT; 194 sc->sc_if.if_type = IFT_PPP; 195 sc->sc_if.if_hdrlen = PPP_HDRLEN; 196 sc->sc_if.if_ioctl = pppioctl; 197 sc->sc_if.if_output = pppoutput; 198 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 199 sc->sc_inq.ifq_maxlen = IFQ_MAXLEN; 200 sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN; 201 if_attach(&sc->sc_if); 202#if NBPFILTER > 0 203 bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN); 204#endif 205 } 206} 207 208/* 209 * Allocate a ppp interface unit and initialize it. 210 */ 211struct ppp_softc * 212pppalloc(pid) 213 pid_t pid; 214{ 215 int nppp; 216 struct ppp_softc *sc; 217 218 for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) 219 if (sc->sc_xfer == pid) { 220 sc->sc_xfer = 0; 221 break; 222 } 223 if (nppp >= NPPP) 224 for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) 225 if (sc->sc_devp == NULL) 226 break; 227 if (nppp >= NPPP) 228 return NULL; 229 230 sc->sc_flags = 0; 231 sc->sc_mru = PPP_MRU; 232#ifdef VJC 233 sl_compress_init(&sc->sc_comp, -1); 234#endif 235 sc->sc_if.if_flags |= IFF_RUNNING; 236 237 return sc; 238} 239 240/* 241 * Deallocate a ppp unit. 242 */ 243pppdealloc(sc) 244 struct ppp_softc *sc; 245{ 246 struct mbuf *m; 247 248 if_down(&sc->sc_if); 249 sc->sc_devp = NULL; 250 sc->sc_xfer = 0; 251 for (;;) { 252 IF_DEQUEUE(&sc->sc_inq, m); 253 if (m == NULL) 254 break; 255 m_freem(m); 256 } 257 for (;;) { 258 IF_DEQUEUE(&sc->sc_fastq, m); 259 if (m == NULL) 260 break; 261 m_freem(m); 262 } 263 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 264} 265 266/* 267 * Line specific open routine for async tty devices. 268 * Attach the given tty to the first available ppp unit. 269 */ 270/* ARGSUSED */ 271int 272pppopen(dev, tp) 273 dev_t dev; 274 register struct tty *tp; 275{ 276 struct proc *p = curproc; /* XXX */ 277 register struct ppp_softc *sc; 278 int error, s, i; 279 280 if (error = suser(p->p_ucred, &p->p_acflag)) 281 return (error); 282 283 if (tp->t_line == PPPDISC) { 284 sc = (struct ppp_softc *) tp->t_sc; 285 if (sc != NULL && sc->sc_devp == (void *) tp) 286 return (0); 287 } 288 289 if ((sc = pppalloc(p->p_pid)) == NULL) 290 return ENXIO; 291 292 if (sc->sc_outm != NULL) { 293 m_freem(sc->sc_outm); 294 sc->sc_outm = NULL; 295 } 296 297 if (pppgetm(sc) == 0) { 298 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 299 return (ENOBUFS); 300 } 301 302 sc->sc_ilen = 0; 303 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 304 sc->sc_asyncmap[0] = 0xffffffff; 305 sc->sc_asyncmap[3] = 0x60000000; 306 sc->sc_rasyncmap = 0; 307 sc->sc_devp = (void *) tp; 308 sc->sc_start = pppasyncstart; 309 310 tp->t_sc = (caddr_t) sc; 311 ttyflush(tp, FREAD | FWRITE); 312 313 return (0); 314} 315 316/* 317 * Line specific close routine. 318 * Detach the tty from the ppp unit. 319 * Mimics part of ttyclose(). 320 */ 321void 322pppclose(tp, flag) 323 struct tty *tp; 324 int flag; 325{ 326 register struct ppp_softc *sc; 327 struct mbuf *m; 328 int s; 329 330 ttywflush(tp); 331 s = splimp(); /* paranoid; splnet probably ok */ 332 tp->t_line = 0; 333 sc = (struct ppp_softc *)tp->t_sc; 334 if (sc != NULL) { 335 tp->t_sc = NULL; 336 if (tp == (struct tty *) sc->sc_devp) { 337 m_freem(sc->sc_outm); 338 sc->sc_outm = NULL; 339 m_freem(sc->sc_m); 340 sc->sc_m = NULL; 341 pppdealloc(sc); 342 } 343 } 344 splx(s); 345} 346 347/* 348 * Line specific (tty) read routine. 349 */ 350int 351pppread(tp, uio, flag) 352 register struct tty *tp; 353 struct uio *uio; 354 int flag; 355{ 356 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 357 struct mbuf *m, *m0; 358 register int s; 359 int error = 0; 360 361 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 362 return 0; /* end of file */ 363 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 364 return 0; 365 s = splimp(); 366 while (sc->sc_inq.ifq_head == NULL && tp->t_line == PPPDISC) { 367 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) { 368 splx(s); 369 return (EWOULDBLOCK); 370 } 371 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0); 372 if (error) 373 return error; 374 } 375 if (tp->t_line != PPPDISC) { 376 splx(s); 377 return (-1); 378 } 379 380 /* Pull place-holder byte out of canonical queue */ 381 getc(&tp->t_canq); 382 383 /* Get the packet from the input queue */ 384 IF_DEQUEUE(&sc->sc_inq, m0); 385 splx(s); 386 387 for (m = m0; m && uio->uio_resid; m = m->m_next) 388 if (error = uiomove(mtod(m, u_char *), m->m_len, uio)) 389 break; 390 m_freem(m0); 391 return (error); 392} 393 394/* 395 * Line specific (tty) write routine. 396 */ 397int 398pppwrite(tp, uio, flag) 399 register struct tty *tp; 400 struct uio *uio; 401 int flag; 402{ 403 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 404 struct mbuf *m, *m0, **mp; 405 struct sockaddr dst; 406 struct ppp_header *ph1, *ph2; 407 int len, error; 408 409 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 410 return 0; /* wrote 0 bytes */ 411 if (tp->t_line != PPPDISC) 412 return (EINVAL); 413 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 414 return EIO; 415 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN || 416 uio->uio_resid < PPP_HDRLEN) 417 return (EMSGSIZE); 418 for (mp = &m0; uio->uio_resid; mp = &m->m_next) { 419 MGET(m, M_WAIT, MT_DATA); 420 if ((*mp = m) == NULL) { 421 m_freem(m0); 422 return (ENOBUFS); 423 } 424 if (uio->uio_resid >= MCLBYTES / 2) 425 MCLGET(m, M_DONTWAIT); 426 len = MIN(M_TRAILINGSPACE(m), uio->uio_resid); 427 if (error = uiomove(mtod(m, u_char *), len, uio)) { 428 m_freem(m0); 429 return (error); 430 } 431 m->m_len = len; 432 } 433 dst.sa_family = AF_UNSPEC; 434 ph1 = (struct ppp_header *) &dst.sa_data; 435 ph2 = mtod(m0, struct ppp_header *); 436 *ph1 = *ph2; 437 m0->m_data += PPP_HDRLEN; 438 m0->m_len -= PPP_HDRLEN; 439 return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0)); 440} 441 442/* 443 * Line specific (tty) ioctl routine. 444 * Provide a way to get the ppp unit number. 445 * This discipline requires that tty device drivers call 446 * the line specific l_ioctl routine from their ioctl routines. 447 */ 448/* ARGSUSED */ 449int 450ppptioctl(tp, cmd, data, flag, p) 451 struct tty *tp; 452 caddr_t data; 453 int cmd, flag; 454 struct proc *p; 455{ 456 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 457 int s, error, flags, mru; 458 459 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 460 return -1; 461 462 switch (cmd) { 463 case FIONREAD: 464 *(int *)data = sc->sc_inq.ifq_len; 465 break; 466 467 case PPPIOCGUNIT: 468 *(int *)data = sc->sc_if.if_unit; 469 break; 470 471 case PPPIOCGFLAGS: 472 *(u_int *)data = sc->sc_flags; 473 break; 474 475 case PPPIOCSFLAGS: 476 if (error = suser(p->p_ucred, &p->p_acflag)) 477 return (error); 478 flags = *(int *)data & SC_MASK; 479 s = splimp(); 480 sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags; 481 splx(s); 482 break; 483 484 case PPPIOCSASYNCMAP: 485 if (error = suser(p->p_ucred, &p->p_acflag)) 486 return (error); 487 sc->sc_asyncmap[0] = *(u_int *)data; 488 break; 489 490 case PPPIOCGASYNCMAP: 491 *(u_int *)data = sc->sc_asyncmap[0]; 492 break; 493 494 case PPPIOCSRASYNCMAP: 495 if (error = suser(p->p_ucred, &p->p_acflag)) 496 return (error); 497 sc->sc_rasyncmap = *(u_int *)data; 498 break; 499 500 case PPPIOCGRASYNCMAP: 501 *(u_int *)data = sc->sc_rasyncmap; 502 break; 503 504 case PPPIOCSXASYNCMAP: 505 if (error = suser(p->p_ucred, &p->p_acflag)) 506 return (error); 507 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 508 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ 509 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ 510 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ 511 break; 512 513 case PPPIOCGXASYNCMAP: 514 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); 515 break; 516 517 case PPPIOCSMRU: 518 if (error = suser(p->p_ucred, &p->p_acflag)) 519 return (error); 520 mru = *(int *)data; 521 if (mru >= PPP_MRU && mru <= PPP_MAXMRU) { 522 sc->sc_mru = mru; 523 if (pppgetm(sc) == 0) { 524 error = ENOBUFS; 525 sc->sc_mru = PPP_MRU; 526 if (pppgetm(sc) == 0) 527 sc->sc_if.if_flags &= ~IFF_UP; 528 } 529 } 530 break; 531 532 case PPPIOCGMRU: 533 *(int *)data = sc->sc_mru; 534 break; 535 536#ifdef VJC 537 case PPPIOCSMAXCID: 538 if (error = suser(p->p_ucred, &p->p_acflag)) 539 return (error); 540 sl_compress_init(&sc->sc_comp, *(int *)data); 541 break; 542#endif 543 544 case PPPIOCXFERUNIT: 545 if (error = suser(p->p_ucred, &p->p_acflag)) 546 return (error); 547 sc->sc_xfer = p->p_pid; 548 break; 549 550 default: 551 return (-1); 552 } 553 return (0); 554} 555 556/* 557 * FCS lookup table as calculated by genfcstab. 558 */ 559static u_short fcstab[256] = { 560 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 561 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 562 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 563 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 564 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 565 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 566 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 567 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 568 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 569 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 570 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 571 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 572 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 573 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 574 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 575 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 576 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 577 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 578 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 579 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 580 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 581 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 582 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 583 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 584 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 585 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 586 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 587 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 588 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 589 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 590 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 591 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 592}; 593 594/* 595 * Calculate a new FCS given the current FCS and the new data. 596 */ 597static u_short 598pppfcs(fcs, cp, len) 599 register u_short fcs; 600 register u_char *cp; 601 register int len; 602{ 603 while (len--) 604 fcs = PPP_FCS(fcs, *cp++); 605 return (fcs); 606} 607 608/* 609 * Queue a packet. Start transmission if not active. 610 * Packet is placed in Information field of PPP frame. 611 */ 612int 613pppoutput(ifp, m0, dst, rtp) 614 struct ifnet *ifp; 615 struct mbuf *m0; 616 struct sockaddr *dst; 617 struct rtentry *rtp; 618{ 619 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; 620 struct ppp_header *ph; 621 int protocol, address, control; 622 u_char *cp; 623 int s, error; 624 struct ip *ip; 625 struct ifqueue *ifq; 626 627 if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0 628 || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) { 629 error = ENETDOWN; /* sort of */ 630 goto bad; 631 } 632 633 /* 634 * Compute PPP header. 635 */ 636 address = PPP_ALLSTATIONS; 637 control = PPP_UI; 638 ifq = &ifp->if_snd; 639 switch (dst->sa_family) { 640#ifdef INET 641 case AF_INET: 642 protocol = PPP_IP; 643 if ((sc->sc_flags & SC_ENABLE_IP) == 0) { 644 error = ENETDOWN; 645 goto bad; 646 } 647 648 /* 649 * If this is a TCP packet to or from an "interactive" port, 650 * put the packet on the fastq instead. 651 */ 652 if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) { 653 register int p = ntohl(((int *)ip)[ip->ip_hl]); 654 if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) 655 ifq = &sc->sc_fastq; 656 } 657 break; 658#endif 659#ifdef NS 660 case AF_NS: 661 protocol = PPP_XNS; 662 break; 663#endif 664 case AF_UNSPEC: 665 ph = (struct ppp_header *) dst->sa_data; 666 address = ph->ph_address; 667 control = ph->ph_control; 668 protocol = ntohs(ph->ph_protocol); 669 break; 670 default: 671 printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family); 672 error = EAFNOSUPPORT; 673 goto bad; 674 } 675 676 /* 677 * Add PPP header. If no space in first mbuf, allocate another. 678 * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.) 679 */ 680 if (M_LEADINGSPACE(m0) < PPP_HDRLEN) { 681 m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT); 682 if (m0 == 0) { 683 error = ENOBUFS; 684 goto bad; 685 } 686 m0->m_len = 0; 687 } else 688 m0->m_data -= PPP_HDRLEN; 689 690 cp = mtod(m0, u_char *); 691 *cp++ = address; 692 *cp++ = control; 693 *cp++ = protocol >> 8; 694 *cp++ = protocol & 0xff; 695 m0->m_len += PPP_HDRLEN; 696 697 if (sc->sc_flags & SC_LOG_OUTPKT) { 698 printf("ppp%d output: ", ifp->if_unit); 699 pppdumpm(m0, -1); 700 } 701 702#if NBPFILTER > 0 703 /* See if bpf wants to look at the packet. */ 704 if (sc->sc_bpf) 705 bpf_mtap(sc->sc_bpf, m0); 706#endif 707 708 /* 709 * Put the packet on the appropriate queue. 710 */ 711 s = splimp(); 712 if (IF_QFULL(ifq)) { 713 IF_DROP(ifq); 714 splx(s); 715 sc->sc_if.if_oerrors++; 716 error = ENOBUFS; 717 goto bad; 718 } 719 IF_ENQUEUE(ifq, m0); 720 721 /* 722 * Tell the device to send it out. 723 */ 724 (*sc->sc_start)(sc); 725 726 splx(s); 727 return (0); 728 729bad: 730 m_freem(m0); 731 return (error); 732} 733 734/* 735 * Grab another packet off a queue and apply VJ compression, 736 * address/control and/or protocol compression if appropriate. 737 */ 738struct mbuf * 739ppp_dequeue(sc) 740 struct ppp_softc *sc; 741{ 742 int s; 743 struct mbuf *m; 744 u_char *cp; 745 int address, control, protocol; 746 747 s = splimp(); 748 IF_DEQUEUE(&sc->sc_fastq, m); 749 if (m == NULL) 750 IF_DEQUEUE(&sc->sc_if.if_snd, m); 751 splx(s); 752 if (m == NULL) 753 return NULL; 754 755 /* 756 * Extract the ppp header of the new packet. 757 * The ppp header will be in one mbuf. 758 */ 759 cp = mtod(m, u_char *); 760 address = cp[0]; 761 control = cp[1]; 762 protocol = (cp[2] << 8) + cp[3]; 763 764#ifdef VJC 765 /* 766 * If the packet is a TCP/IP packet, see if we can compress it. 767 */ 768 if (protocol == PPP_IP && sc->sc_flags & SC_COMP_TCP) { 769 struct ip *ip; 770 int type; 771 struct mbuf *mp; 772 773 mp = m; 774 ip = (struct ip *) (cp + PPP_HDRLEN); 775 if (mp->m_len <= PPP_HDRLEN) { 776 mp = mp->m_next; 777 ip = mtod(mp, struct ip *); 778 } 779 /* this code assumes the IP/TCP header is in one non-shared mbuf */ 780 if (ip->ip_p == IPPROTO_TCP) { 781 type = sl_compress_tcp(mp, ip, &sc->sc_comp, 782 !(sc->sc_flags & SC_NO_TCP_CCID)); 783 switch (type) { 784 case TYPE_UNCOMPRESSED_TCP: 785 protocol = PPP_VJC_UNCOMP; 786 break; 787 case TYPE_COMPRESSED_TCP: 788 protocol = PPP_VJC_COMP; 789 cp = mtod(m, u_char *); 790 cp[0] = address; /* header has moved */ 791 cp[1] = control; 792 cp[2] = 0; 793 break; 794 } 795 cp[3] = protocol; /* update protocol in PPP header */ 796 } 797 } 798#endif /* VJC */ 799 800#ifdef BSD_COMP 801 if (protocol < PPP_COMP && (sc->sc_flags & SC_BSD_COMP)) { 802 slen = m_totallen(m0); 803 clen = pf_bsd_comp(sc->sc_bsd_db, cbuf, proto, m0, slen); 804 } 805#endif /* BSD_COMP */ 806 807 /* 808 * Compress the address/control and protocol, if possible. 809 */ 810 if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS && 811 control == PPP_UI && protocol != PPP_ALLSTATIONS && 812 protocol != PPP_LCP) { 813 /* can compress address/control */ 814 m->m_data += 2; 815 m->m_len -= 2; 816 } 817 if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) { 818 /* can compress protocol */ 819 if (mtod(m, u_char *) == cp) { 820 cp[2] = cp[1]; /* move address/control up */ 821 cp[1] = cp[0]; 822 } 823 ++m->m_data; 824 --m->m_len; 825 } 826 827 return m; 828} 829 830/* 831 * This gets called from pppoutput when a new packet is 832 * put on a queue. 833 */ 834static 835pppasyncstart(sc) 836 register struct ppp_softc *sc; 837{ 838 register struct tty *tp = (struct tty *) sc->sc_devp; 839 840 pppstart(tp); 841} 842 843/* 844 * Start output on async tty interface. Get another datagram 845 * to send from the interface queue and start sending it. 846 */ 847void 848pppstart(tp) 849 register struct tty *tp; 850{ 851 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 852 register struct mbuf *m; 853 register int len; 854 register u_char *start, *stop, *cp; 855 int n, s, ndone, done; 856 struct mbuf *m2; 857 858 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) { 859 /* sorry, I can't talk now */ 860 return; 861 } 862 if (sc == NULL || tp != (struct tty *) sc->sc_devp) { 863 (*tp->t_oproc)(tp); 864 return; 865 } 866 867 for (;;) { 868 /* 869 * If there is more in the output queue, just send it now. 870 * We are being called in lieu of ttstart and must do what 871 * it would. 872 */ 873 if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) { 874 (*tp->t_oproc)(tp); 875 if (CCOUNT(&tp->t_outq) > PPP_HIWAT) 876 return; 877 } 878 879 /* 880 * See if we have an existing packet partly sent. 881 * If not, get a new packet and start sending it. 882 * We take packets on the priority queue ahead of those 883 * on the normal queue. 884 */ 885 m = sc->sc_outm; 886 if (m == NULL) { 887 /* 888 * Get another packet to be sent 889 */ 890 m = ppp_dequeue(sc); 891 if (m == NULL) 892 return; 893 894 /* 895 * The extra PPP_FLAG will start up a new packet, and thus 896 * will flush any accumulated garbage. We do this whenever 897 * the line may have been idle for some time. 898 */ 899 if (CCOUNT(&tp->t_outq) == 0) { 900 ++sc->sc_bytessent; 901 (void) putc(PPP_FLAG, &tp->t_outq); 902 } 903 904 /* Calculate the FCS for the first mbuf's worth. */ 905 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); 906 } 907 908 for (;;) { 909 start = mtod(m, u_char *); 910 len = m->m_len; 911 stop = start + len; 912 while (len > 0) { 913 /* 914 * Find out how many bytes in the string we can 915 * handle without doing something special. 916 */ 917 for (cp = start; cp < stop; cp++) 918 if (ESCAPE_P(*cp)) 919 break; 920 n = cp - start; 921 if (n) { 922#ifndef RB_LEN 923 /* NetBSD (0.9 or later), 4.3-Reno or similar. */ 924 ndone = n - b_to_q(start, n, &tp->t_outq); 925#else 926#ifdef NetBSD 927 /* NetBSD with 2-byte ring buffer entries */ 928 ndone = rb_cwrite(&tp->t_out, start, n); 929#else 930 /* 386BSD, FreeBSD */ 931 int cc, nleft; 932 for (nleft = n; nleft > 0; nleft -= cc) { 933 if ((cc = RB_CONTIGPUT(&tp->t_out)) == 0) 934 break; 935 cc = min (cc, nleft); 936 bcopy((char *)start + n - nleft, tp->t_out.rb_tl, cc); 937 tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out, 938 tp->t_out.rb_tl + cc); 939 } 940 ndone = n - nleft; 941#endif /* NetBSD */ 942#endif /* RB_LEN */ 943 len -= ndone; 944 start += ndone; 945 sc->sc_bytessent += ndone; 946 947 if (ndone < n) 948 break; /* packet doesn't fit */ 949 } 950 /* 951 * If there are characters left in the mbuf, 952 * the first one must be special.. 953 * Put it out in a different form. 954 */ 955 if (len) { 956 if (putc(PPP_ESCAPE, &tp->t_outq)) 957 break; 958 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { 959 (void) unputc(&tp->t_outq); 960 break; 961 } 962 sc->sc_bytessent += 2; 963 start++; 964 len--; 965 } 966 } 967 /* 968 * If we didn't empty this mbuf, remember where we're up to. 969 * If we emptied the last mbuf, try to add the FCS and closing 970 * flag, and if we can't, leave sc_outm pointing to m, but with 971 * m->m_len == 0, to remind us to output the FCS and flag later. 972 */ 973 done = len == 0; 974 if (done && m->m_next == NULL) { 975 u_char *p, *q; 976 int c; 977 u_char endseq[8]; 978 979 /* 980 * We may have to escape the bytes in the FCS. 981 */ 982 p = endseq; 983 c = ~sc->sc_outfcs & 0xFF; 984 if (ESCAPE_P(c)) { 985 *p++ = PPP_ESCAPE; 986 *p++ = c ^ PPP_TRANS; 987 } else 988 *p++ = c; 989 c = (~sc->sc_outfcs >> 8) & 0xFF; 990 if (ESCAPE_P(c)) { 991 *p++ = PPP_ESCAPE; 992 *p++ = c ^ PPP_TRANS; 993 } else 994 *p++ = c; 995 *p++ = PPP_FLAG; 996 997 /* 998 * Try to output the FCS and flag. If the bytes 999 * don't all fit, back out. 1000 */ 1001 for (q = endseq; q < p; ++q) 1002 if (putc(*q, &tp->t_outq)) { 1003 done = 0; 1004 for (; q > endseq; --q) 1005 unputc(&tp->t_outq); 1006 break; 1007 } 1008 } 1009 1010 if (!done) { 1011 m->m_data = start; 1012 m->m_len = len; 1013 sc->sc_outm = m; 1014 if (tp->t_oproc != NULL) 1015 (*tp->t_oproc)(tp); 1016 return; /* can't do any more at the moment */ 1017 } 1018 1019 /* Finished with this mbuf; free it and move on. */ 1020 MFREE(m, m2); 1021 if (m2 == NULL) 1022 break; 1023 1024 m = m2; 1025 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); 1026 } 1027 1028 /* Finished a packet */ 1029 sc->sc_outm = NULL; 1030 sc->sc_bytessent++; /* account for closing flag */ 1031 sc->sc_if.if_opackets++; 1032 sc->sc_if.if_obytes = sc->sc_bytessent; 1033 } 1034} 1035 1036/* 1037 * Allocate enough mbuf to handle current MRU. 1038 */ 1039static int 1040pppgetm(sc) 1041 register struct ppp_softc *sc; 1042{ 1043 struct mbuf *m, **mp; 1044 int len = HDROFF + sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; 1045 int s; 1046 1047 s = splimp(); 1048 for (mp = &sc->sc_m; (m = *mp) != NULL; mp = &m->m_next) 1049 if ((len -= M_DATASIZE(m)) <= 0) { 1050 splx(s); 1051 return (1); 1052 } 1053 1054 for (;; mp = &m->m_next) { 1055 MGETHDR(m, M_DONTWAIT, MT_DATA); 1056 if (m == 0) { 1057 m_freem(sc->sc_m); 1058 sc->sc_m = NULL; 1059 splx(s); 1060 printf("ppp%d: can't allocate mbuf\n", sc->sc_if.if_unit); 1061 return (0); 1062 } 1063 *mp = m; 1064 MCLGET(m, M_DONTWAIT); 1065 if ((len -= M_DATASIZE(m)) <= 0) { 1066 splx(s); 1067 return (1); 1068 } 1069 } 1070} 1071 1072/* 1073 * Copy mbuf chain. Would like to use m_copy(), but we need a real copy 1074 * of the data, not just copies of pointers to the data. 1075 */ 1076static struct mbuf * 1077ppp_btom(sc) 1078 struct ppp_softc *sc; 1079{ 1080 register struct mbuf *m, **mp; 1081 struct mbuf *top = sc->sc_m; 1082 1083 /* 1084 * First check current mbuf. If we have more than a small mbuf, 1085 * return the whole cluster and set beginning of buffer to the 1086 * next mbuf. 1087 * Else, copy the current bytes into a small mbuf, attach the new 1088 * mbuf to the end of the chain and set beginning of buffer to the 1089 * current mbuf. 1090 */ 1091 1092 if (sc->sc_mc->m_len > MHLEN) { 1093 sc->sc_m = sc->sc_mc->m_next; 1094 sc->sc_mc->m_next = NULL; 1095 } 1096 else { 1097 /* rather than waste a whole cluster on <= MHLEN bytes, 1098 alloc a small mbuf and copy to it */ 1099 MGETHDR(m, M_DONTWAIT, MT_DATA); 1100 if (m == NULL) 1101 return (NULL); 1102 1103 bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t), sc->sc_mc->m_len); 1104 m->m_len = sc->sc_mc->m_len; 1105 for (mp = ⊤ *mp != sc->sc_mc; mp = &(*mp)->m_next) 1106 ; 1107 *mp = m; 1108 sc->sc_m = sc->sc_mc; 1109 } 1110 1111 /* 1112 * Try to allocate enough extra mbufs to handle the next packet. 1113 */ 1114 if (pppgetm(sc) == 0) { 1115 m_freem(top); 1116 if (pppgetm(sc) == 0) 1117 sc->sc_if.if_flags &= ~IFF_UP; 1118 return (NULL); 1119 } 1120 1121 return (top); 1122} 1123 1124/* 1125 * PPP packet input routine. 1126 * The caller has checked and removed the FCS. 1127 * The return value is 1 if the packet was put on sc->sc_inq, 1128 * 0 otherwise. 1129 */ 1130#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ 1131 TYPE_UNCOMPRESSED_TCP) 1132 1133int 1134ppppktin(sc, m, ilen) 1135 struct ppp_softc *sc; 1136 struct mbuf *m; 1137 int ilen; 1138{ 1139 struct ifqueue *inq; 1140 int s, xlen, proto, rv; 1141 struct ppp_header hdr; 1142 1143 sc->sc_if.if_ipackets++; 1144 rv = 0; 1145 1146 hdr = *mtod(m, struct ppp_header *); 1147 proto = ntohs(hdr.ph_protocol); 1148 1149#ifdef VJC 1150 /* 1151 * See if we have a VJ-compressed packet to uncompress. 1152 */ 1153 if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) { 1154 char *pkttype = proto == PPP_VJC_COMP? "": "un"; 1155 1156 if (sc->sc_flags & SC_REJ_COMP_TCP) { 1157 if (sc->sc_flags & SC_DEBUG) 1158 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n", 1159 sc->sc_if.if_unit, pkttype, sc->sc_flags); 1160 sc->sc_if.if_ierrors++; 1161 return 0; 1162 } 1163 1164 m->m_data += PPP_HDRLEN; 1165 m->m_len -= PPP_HDRLEN; 1166 ilen -= PPP_HDRLEN; 1167 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data), 1168 m->m_len, ilen, 1169 COMPTYPE(proto), &sc->sc_comp); 1170 1171 if (xlen == 0) { 1172 if (sc->sc_flags & SC_DEBUG) 1173 printf("ppp%d: sl_uncompress failed on type %scomp\n", 1174 sc->sc_if.if_unit, pkttype); 1175 sc->sc_if.if_ierrors++; 1176 return 0; 1177 } 1178 1179 /* adjust the first mbuf by the decompressed amt */ 1180 xlen += PPP_HDRLEN; 1181 m->m_len += xlen - ilen; 1182 ilen = xlen; 1183 m->m_data -= PPP_HDRLEN; 1184 proto = PPP_IP; 1185 1186 /* put the ppp header back in place */ 1187 hdr.ph_protocol = htons(PPP_IP); 1188 *mtod(m, struct ppp_header *) = hdr; 1189 } 1190#endif /* VJC */ 1191 1192 /* get this packet as an mbuf chain */ 1193 if ((m = ppp_btom(sc)) == NULL) { 1194 sc->sc_if.if_ierrors++; 1195 return 0; 1196 } 1197 m->m_pkthdr.len = ilen; 1198 m->m_pkthdr.rcvif = &sc->sc_if; 1199 1200#if NBPFILTER > 0 1201 /* See if bpf wants to look at the packet. */ 1202 if (sc->sc_bpf) 1203 bpf_mtap(sc->sc_bpf, m); 1204#endif 1205 1206 switch (proto) { 1207#ifdef INET 1208 case PPP_IP: 1209 /* 1210 * IP packet - take off the ppp header and pass it up to IP. 1211 */ 1212 if ((sc->sc_if.if_flags & IFF_UP) == 0 1213 || (sc->sc_flags & SC_ENABLE_IP) == 0) { 1214 /* interface is down - drop the packet. */ 1215 m_freem(m); 1216 return 0; 1217 } 1218 m->m_pkthdr.len -= PPP_HDRLEN; 1219 m->m_data += PPP_HDRLEN; 1220 m->m_len -= PPP_HDRLEN; 1221 schednetisr(NETISR_IP); 1222 inq = &ipintrq; 1223 break; 1224#endif 1225 1226 default: 1227 /* 1228 * Some other protocol - place on input queue for read(). 1229 */ 1230 inq = &sc->sc_inq; 1231 rv = 1; 1232 break; 1233 } 1234 1235 /* 1236 * Put the packet on the appropriate input queue. 1237 */ 1238 s = splimp(); 1239 if (IF_QFULL(inq)) { 1240 IF_DROP(inq); 1241 if (sc->sc_flags & SC_DEBUG) 1242 printf("ppp%d: queue full\n", sc->sc_if.if_unit); 1243 sc->sc_if.if_ierrors++; 1244 sc->sc_if.if_iqdrops++; 1245 m_freem(m); 1246 rv = 0; 1247 } else 1248 IF_ENQUEUE(inq, m); 1249 1250 splx(s); 1251 return rv; 1252} 1253 1254/* 1255 * tty interface receiver interrupt. 1256 */ 1257static unsigned paritytab[8] = { 1258 0x96696996, 0x69969669, 0x69969669, 0x96696996, 1259 0x69969669, 0x96696996, 0x96696996, 0x69969669 1260}; 1261 1262void 1263pppinput(c, tp) 1264 int c; 1265 register struct tty *tp; 1266{ 1267 register struct ppp_softc *sc; 1268 struct mbuf *m; 1269 int ilen; 1270 1271 tk_nin++; 1272 sc = (struct ppp_softc *) tp->t_sc; 1273 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 1274 return; 1275 1276 ++sc->sc_bytesrcvd; 1277 1278 if (c & TTY_FE) { 1279 /* framing error or overrun on this char - abort packet */ 1280 if (sc->sc_flags & SC_DEBUG) 1281 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c); 1282 goto flush; 1283 } 1284 1285 c &= 0xff; 1286 1287 if (c & 0x80) 1288 sc->sc_flags |= SC_RCV_B7_1; 1289 else 1290 sc->sc_flags |= SC_RCV_B7_0; 1291 if (paritytab[c >> 5] & (1 << (c & 0x1F))) 1292 sc->sc_flags |= SC_RCV_ODDP; 1293 else 1294 sc->sc_flags |= SC_RCV_EVNP; 1295 1296 if (sc->sc_flags & SC_LOG_RAWIN) 1297 ppplogchar(sc, c); 1298 1299 if (c == PPP_FLAG) { 1300 ilen = sc->sc_ilen; 1301 sc->sc_ilen = 0; 1302 sc->sc_if.if_ibytes = sc->sc_bytesrcvd; 1303 1304 if (sc->sc_rawin_count > 0) 1305 ppplogchar(sc, -1); 1306 1307 /* 1308 * If SC_ESCAPED is set, then we've seen the packet 1309 * abort sequence "}~". 1310 */ 1311 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) 1312 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) { 1313#ifdef VJC 1314 /* 1315 * If we've missed a packet, we must toss subsequent compressed 1316 * packets which don't have an explicit connection ID. 1317 */ 1318 sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp); 1319#endif 1320 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ 1321 if (sc->sc_flags & SC_DEBUG) 1322 printf("ppp%d: bad fcs\n", sc->sc_if.if_unit); 1323 sc->sc_if.if_ierrors++; 1324 } else 1325 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); 1326 return; 1327 } 1328 1329 if (ilen < PPP_HDRLEN + PPP_FCSLEN) { 1330 if (ilen) { 1331 if (sc->sc_flags & SC_DEBUG) 1332 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen); 1333 sc->sc_if.if_ierrors++; 1334 } 1335 return; 1336 } 1337 1338 /* 1339 * Remove FCS trailer. Somewhat painful... 1340 */ 1341 ilen -= 2; 1342 if (--sc->sc_mc->m_len == 0) { 1343 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) 1344 ; 1345 sc->sc_mc = m; 1346 } 1347 sc->sc_mc->m_len--; 1348 1349 m = sc->sc_m; 1350 1351 if (sc->sc_flags & SC_LOG_INPKT) { 1352 printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen); 1353 pppdumpm(m, ilen); 1354 } 1355 1356 if (ppppktin(sc, m, ilen)) { 1357 /* Put a placeholder byte in canq for ttselect()/ttnread(). */ 1358 putc(0, &tp->t_canq); 1359 ttwakeup(tp); 1360 } 1361 return; 1362 } 1363 1364 if (sc->sc_flags & SC_FLUSH) { 1365 if (sc->sc_flags & SC_LOG_FLUSH) 1366 ppplogchar(sc, c); 1367 return; 1368 } 1369 1370 if (c == PPP_ESCAPE) { 1371 sc->sc_flags |= SC_ESCAPED; 1372 return; 1373 } 1374 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) 1375 return; 1376 1377 if (sc->sc_flags & SC_ESCAPED) { 1378 sc->sc_flags &= ~SC_ESCAPED; 1379 c ^= PPP_TRANS; 1380 } 1381 1382 /* 1383 * Initialize buffer on first octet received. 1384 * First octet could be address or protocol (when compressing 1385 * address/control). 1386 * Second octet is control. 1387 * Third octet is first or second (when compressing protocol) 1388 * octet of protocol. 1389 * Fourth octet is second octet of protocol. 1390 */ 1391 if (sc->sc_ilen == 0) { 1392 /* reset the first input mbuf */ 1393 m = sc->sc_m; 1394 m->m_len = 0; 1395 m->m_data = M_DATASTART(sc->sc_m) + HDROFF; 1396 sc->sc_mc = m; 1397 sc->sc_mp = mtod(m, char *); 1398 sc->sc_fcs = PPP_INITFCS; 1399 if (c != PPP_ALLSTATIONS) { 1400 if (sc->sc_flags & SC_REJ_COMP_AC) { 1401 if (sc->sc_flags & SC_DEBUG) 1402 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n", 1403 sc->sc_if.if_unit, c); 1404 goto flush; 1405 } 1406 *sc->sc_mp++ = PPP_ALLSTATIONS; 1407 *sc->sc_mp++ = PPP_UI; 1408 sc->sc_ilen += 2; 1409 m->m_len += 2; 1410 } 1411 } 1412 if (sc->sc_ilen == 1 && c != PPP_UI) { 1413 if (sc->sc_flags & SC_DEBUG) 1414 printf("ppp%d: missing UI (0x3), got 0x%x\n", 1415 sc->sc_if.if_unit, c); 1416 goto flush; 1417 } 1418 if (sc->sc_ilen == 2 && (c & 1) == 1) { 1419 /* a compressed protocol */ 1420 *sc->sc_mp++ = 0; 1421 sc->sc_ilen++; 1422 sc->sc_mc->m_len++; 1423 } 1424 if (sc->sc_ilen == 3 && (c & 1) == 0) { 1425 if (sc->sc_flags & SC_DEBUG) 1426 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit, 1427 (sc->sc_mp[-1] << 8) + c); 1428 goto flush; 1429 } 1430 1431 /* packet beyond configured mru? */ 1432 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { 1433 if (sc->sc_flags & SC_DEBUG) 1434 printf("ppp%d: packet too big\n", sc->sc_if.if_unit); 1435 goto flush; 1436 } 1437 1438 /* is this mbuf full? */ 1439 m = sc->sc_mc; 1440 if (M_TRAILINGSPACE(m) <= 0) { 1441 sc->sc_mc = m = m->m_next; 1442 if (m == NULL) { 1443 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit); 1444 goto flush; 1445 } 1446 m->m_len = 0; 1447 m->m_data = M_DATASTART(m); 1448 sc->sc_mp = mtod(m, char *); 1449 } 1450 1451 ++m->m_len; 1452 *sc->sc_mp++ = c; 1453 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); 1454 return; 1455 1456 flush: 1457 if (!(sc->sc_flags & SC_FLUSH)) { 1458 sc->sc_if.if_ierrors++; 1459 sc->sc_flags |= SC_FLUSH; 1460 if (sc->sc_flags & SC_LOG_FLUSH) 1461 ppplogchar(sc, c); 1462 } 1463} 1464 1465/* 1466 * Process an ioctl request to interface. 1467 */ 1468pppioctl(ifp, cmd, data) 1469 register struct ifnet *ifp; 1470 int cmd; 1471 caddr_t data; 1472{ 1473 struct proc *p = curproc; /* XXX */ 1474 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; 1475 register struct ifaddr *ifa = (struct ifaddr *)data; 1476 register struct ifreq *ifr = (struct ifreq *)data; 1477 int s = splimp(), error = 0; 1478 1479 1480 switch (cmd) { 1481 case SIOCSIFFLAGS: 1482 if ((ifp->if_flags & IFF_RUNNING) == 0) 1483 ifp->if_flags &= ~IFF_UP; 1484 break; 1485 1486 case SIOCSIFADDR: 1487 if (ifa->ifa_addr->sa_family != AF_INET) 1488 error = EAFNOSUPPORT; 1489 break; 1490 1491 case SIOCSIFDSTADDR: 1492 if (ifa->ifa_addr->sa_family != AF_INET) 1493 error = EAFNOSUPPORT; 1494 break; 1495 1496 case SIOCSIFMTU: 1497 if (error = suser(p->p_ucred, &p->p_acflag)) 1498 return (error); 1499 sc->sc_if.if_mtu = ifr->ifr_mtu; 1500 break; 1501 1502 case SIOCGIFMTU: 1503 ifr->ifr_mtu = sc->sc_if.if_mtu; 1504 break; 1505 1506 default: 1507 error = EINVAL; 1508 } 1509 splx(s); 1510 return (error); 1511} 1512 1513#define MAX_DUMP_BYTES 128 1514 1515static void 1516pppdumpm(m0, pktlen) 1517 struct mbuf *m0; 1518 int pktlen; 1519{ 1520 char buf[3*MAX_DUMP_BYTES+4]; 1521 char *bp = buf; 1522 struct mbuf *m; 1523 static char digits[] = "0123456789abcdef"; 1524 1525 for (m = m0; m && pktlen; m = m->m_next) { 1526 int l = m->m_len; 1527 u_char *rptr = (u_char *)m->m_data; 1528 1529 if (pktlen > 0) { 1530 l = min(l, pktlen); 1531 pktlen -= l; 1532 } 1533 while (l--) { 1534 if (bp > buf + sizeof(buf) - 4) 1535 goto done; 1536 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */ 1537 *bp++ = digits[*rptr++ & 0xf]; 1538 } 1539 1540 if (m->m_next) { 1541 if (bp > buf + sizeof(buf) - 3) 1542 goto done; 1543 *bp++ = '|'; 1544 } else 1545 *bp++ = ' '; 1546 } 1547done: 1548 if (m && pktlen) 1549 *bp++ = '>'; 1550 *bp = 0; 1551 printf("%s\n", buf); 1552} 1553 1554static void 1555ppplogchar(sc, c) 1556 struct ppp_softc *sc; 1557 int c; 1558{ 1559 if (c >= 0) 1560 sc->sc_rawin[sc->sc_rawin_count++] = c; 1561 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) 1562 || c < 0 && sc->sc_rawin_count > 0) { 1563 printf("ppp%d input: ", sc->sc_if.if_unit); 1564 pppdumpb(sc->sc_rawin, sc->sc_rawin_count); 1565 sc->sc_rawin_count = 0; 1566 } 1567} 1568 1569static void 1570pppdumpb(b, l) 1571 u_char *b; 1572 int l; 1573{ 1574 char buf[3*MAX_DUMP_BYTES+4]; 1575 char *bp = buf; 1576 static char digits[] = "0123456789abcdef"; 1577 1578 while (l--) { 1579 if (bp >= buf + sizeof(buf) - 3) { 1580 *bp++ = '>'; 1581 break; 1582 } 1583 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ 1584 *bp++ = digits[*b++ & 0xf]; 1585 *bp++ = ' '; 1586 } 1587 1588 *bp = 0; 1589 printf("%s\n", buf); 1590} 1591 1592 1593#endif /* NPPP > 0 */ 1594