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