1 /* $NetBSD: ppp_tty.c,v 1.50 2007/11/12 14:20:40 ad Exp $ */ 2 /* Id: ppp_tty.c,v 1.3 1996/07/01 01:04:11 paulus Exp */ 3 4 /* 5 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous 6 * tty devices. 7 * 8 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * 3. The name "Carnegie Mellon University" must not be used to 23 * endorse or promote products derived from this software without 24 * prior written permission. For permission or any legal 25 * details, please contact 26 * Office of Technology Transfer 27 * Carnegie Mellon University 28 * 5000 Forbes Avenue 29 * Pittsburgh, PA 15213-3890 30 * (412) 268-4387, fax: (412) 268-7395 31 * tech-transfer@andrew.cmu.edu 32 * 33 * 4. Redistributions of any form whatsoever must retain the following 34 * acknowledgment: 35 * "This product includes software developed by Computing Services 36 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 37 * 38 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 39 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 40 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 41 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 42 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 43 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 44 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 45 * 46 * Based on: 47 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 48 * 49 * Copyright (c) 1987 Regents of the University of California. 50 * All rights reserved. 51 * 52 * Redistribution and use in source and binary forms are permitted 53 * provided that the above copyright notice and this paragraph are 54 * duplicated in all such forms and that any documentation, 55 * advertising materials, and other materials related to such 56 * distribution and use acknowledge that the software was developed 57 * by the University of California, Berkeley. The name of the 58 * University may not be used to endorse or promote products derived 59 * from this software without specific prior written permission. 60 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 61 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 62 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 63 * 64 * Serial Line interface 65 * 66 * Rick Adams 67 * Center for Seismic Studies 68 * 1300 N 17th Street, Suite 1450 69 * Arlington, Virginia 22209 70 * (703)276-7900 71 * rick@seismo.ARPA 72 * seismo!rick 73 * 74 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 75 * Converted to 4.3BSD Beta by Chris Torek. 76 * Other changes made at Berkeley, based in part on code by Kirk Smith. 77 * 78 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) 79 * Added VJ tcp header compression; more unified ioctls 80 * 81 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). 82 * Cleaned up a lot of the mbuf-related code to fix bugs that 83 * caused system crashes and packet corruption. Changed pppstart 84 * so that it doesn't just give up with a "collision" if the whole 85 * packet doesn't fit in the output ring buffer. 86 * 87 * Added priority queueing for interactive IP packets, following 88 * the model of if_sl.c, plus hooks for bpf. 89 * Paul Mackerras (paulus@cs.anu.edu.au). 90 */ 91 92 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 93 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */ 94 95 #include <sys/cdefs.h> 96 __KERNEL_RCSID(0, "$NetBSD: ppp_tty.c,v 1.50 2007/11/12 14:20:40 ad Exp $"); 97 98 #include "ppp.h" 99 100 #include "opt_ppp.h" 101 #define VJC 102 #define PPP_COMPRESS 103 104 #include <sys/param.h> 105 #include <sys/proc.h> 106 #include <sys/mbuf.h> 107 #include <sys/dkstat.h> 108 #include <sys/socket.h> 109 #include <sys/ioctl.h> 110 #include <sys/file.h> 111 #include <sys/tty.h> 112 #include <sys/kernel.h> 113 #include <sys/conf.h> 114 #include <sys/vnode.h> 115 #include <sys/systm.h> 116 #include <sys/kauth.h> 117 118 #include <net/if.h> 119 #include <net/if_types.h> 120 121 #ifdef VJC 122 #include <netinet/in.h> 123 #include <netinet/in_systm.h> 124 #include <netinet/ip.h> 125 #include <net/slcompress.h> 126 #endif 127 128 #include "bpfilter.h" 129 #if NBPFILTER > 0 || defined(PPP_FILTER) 130 #include <net/bpf.h> 131 #endif 132 #include <net/ppp_defs.h> 133 #include <net/if_ppp.h> 134 #include <net/if_pppvar.h> 135 136 static int pppopen(dev_t dev, struct tty *tp); 137 static int pppclose(struct tty *tp, int flag); 138 static int pppread(struct tty *tp, struct uio *uio, int flag); 139 static int pppwrite(struct tty *tp, struct uio *uio, int flag); 140 static int ppptioctl(struct tty *tp, u_long cmd, void *data, int flag, 141 struct lwp *); 142 static int pppinput(int c, struct tty *tp); 143 static int pppstart(struct tty *tp); 144 145 struct linesw ppp_disc = { /* XXX should be static */ 146 .l_name = "ppp", 147 .l_open = pppopen, 148 .l_close = pppclose, 149 .l_read = pppread, 150 .l_write = pppwrite, 151 .l_ioctl = ppptioctl, 152 .l_rint = pppinput, 153 .l_start = pppstart, 154 .l_modem = ttymodem, 155 .l_poll = ttpoll 156 }; 157 158 static void ppprcvframe(struct ppp_softc *sc, struct mbuf *m); 159 static u_int16_t pppfcs(u_int16_t fcs, u_char *cp, int len); 160 static void pppsyncstart(struct ppp_softc *sc); 161 static void pppasyncstart(struct ppp_softc *); 162 static void pppasyncctlp(struct ppp_softc *); 163 static void pppasyncrelinq(struct ppp_softc *); 164 static void ppp_timeout(void *); 165 static void pppgetm(struct ppp_softc *sc); 166 static void pppdumpb(u_char *b, int l); 167 static void ppplogchar(struct ppp_softc *, int); 168 static void pppdumpframe(struct ppp_softc *sc, struct mbuf* m, int xmit); 169 170 /* 171 * Some useful mbuf macros not in mbuf.h. 172 */ 173 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) 174 175 #define M_DATASTART(m) \ 176 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ 177 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) 178 179 #define M_DATASIZE(m) \ 180 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ 181 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) 182 183 /* 184 * Does c need to be escaped? 185 */ 186 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) 187 188 /* 189 * Procedures for using an async tty interface for PPP. 190 */ 191 192 /* This is a NetBSD-1.0 or later kernel. */ 193 #define CCOUNT(q) ((q)->c_cc) 194 195 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */ 196 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */ 197 198 /* 199 * Line specific open routine for async tty devices. 200 * Attach the given tty to the first available ppp unit. 201 * Called from device open routine or ttioctl. 202 */ 203 /* ARGSUSED */ 204 static int 205 pppopen(dev_t dev, struct tty *tp) 206 { 207 struct lwp *l = curlwp; /* XXX */ 208 struct ppp_softc *sc; 209 int error, s; 210 211 if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, 212 NULL)) != 0) 213 return (error); 214 215 s = spltty(); 216 217 if (tp->t_linesw == &ppp_disc) { 218 sc = (struct ppp_softc *) tp->t_sc; 219 if (sc != NULL && sc->sc_devp == (void *) tp) { 220 splx(s); 221 return (0); 222 } 223 } 224 225 if ((sc = pppalloc(l->l_proc->p_pid)) == NULL) { 226 splx(s); 227 return ENXIO; 228 } 229 230 if (sc->sc_relinq) 231 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ 232 233 #if NBPFILTER > 0 234 /* Switch DLT to PPP-over-serial. */ 235 bpf_change_type(&sc->sc_if, DLT_PPP_SERIAL, PPP_HDRLEN); 236 #endif 237 238 sc->sc_ilen = 0; 239 sc->sc_m = NULL; 240 memset(sc->sc_asyncmap, 0, sizeof(sc->sc_asyncmap)); 241 sc->sc_asyncmap[0] = 0xffffffff; 242 sc->sc_asyncmap[3] = 0x60000000; 243 sc->sc_rasyncmap = 0; 244 sc->sc_devp = (void *) tp; 245 sc->sc_start = pppasyncstart; 246 sc->sc_ctlp = pppasyncctlp; 247 sc->sc_relinq = pppasyncrelinq; 248 sc->sc_outm = NULL; 249 pppgetm(sc); 250 sc->sc_if.if_flags |= IFF_RUNNING; 251 sc->sc_if.if_baudrate = tp->t_ospeed; 252 253 tp->t_sc = (void *) sc; 254 mutex_spin_enter(&tty_lock); 255 ttyflush(tp, FREAD | FWRITE); 256 mutex_spin_exit(&tty_lock); 257 258 splx(s); 259 return (0); 260 } 261 262 /* 263 * Line specific close routine, called from device close routine 264 * and from ttioctl. 265 * Detach the tty from the ppp unit. 266 * Mimics part of ttyclose(). 267 */ 268 static int 269 pppclose(struct tty *tp, int flag) 270 { 271 struct ppp_softc *sc; 272 int s; 273 274 s = spltty(); 275 mutex_spin_enter(&tty_lock); 276 ttyflush(tp, FREAD|FWRITE); 277 mutex_spin_exit(&tty_lock); /* XXX */ 278 ttyldisc_release(tp->t_linesw); 279 tp->t_linesw = ttyldisc_default(); 280 sc = (struct ppp_softc *) tp->t_sc; 281 if (sc != NULL) { 282 tp->t_sc = NULL; 283 if (tp == (struct tty *) sc->sc_devp) { 284 pppasyncrelinq(sc); 285 pppdealloc(sc); 286 } 287 } 288 splx(s); 289 return 0; 290 } 291 292 /* 293 * Relinquish the interface unit to another device. 294 */ 295 static void 296 pppasyncrelinq(struct ppp_softc *sc) 297 { 298 int s; 299 300 #if NBPFILTER > 0 301 /* Change DLT to back none. */ 302 bpf_change_type(&sc->sc_if, DLT_NULL, 0); 303 #endif 304 305 s = spltty(); 306 if (sc->sc_outm) { 307 m_freem(sc->sc_outm); 308 sc->sc_outm = NULL; 309 } 310 if (sc->sc_m) { 311 m_freem(sc->sc_m); 312 sc->sc_m = NULL; 313 } 314 if (sc->sc_flags & SC_TIMEOUT) { 315 callout_stop(&sc->sc_timo_ch); 316 sc->sc_flags &= ~SC_TIMEOUT; 317 } 318 splx(s); 319 } 320 321 /* 322 * Line specific (tty) read routine. 323 */ 324 static int 325 pppread(struct tty *tp, struct uio *uio, int flag) 326 { 327 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 328 struct mbuf *m, *m0; 329 int error = 0; 330 331 if (sc == NULL) 332 return 0; 333 /* 334 * Loop waiting for input, checking that nothing disasterous 335 * happens in the meantime. 336 */ 337 mutex_spin_enter(&tty_lock); 338 for (;;) { 339 if (tp != (struct tty *) sc->sc_devp || 340 tp->t_linesw != &ppp_disc) { 341 mutex_spin_exit(&tty_lock); 342 return 0; 343 } 344 if (sc->sc_inq.ifq_head != NULL) 345 break; 346 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0 347 && (tp->t_state & TS_ISOPEN)) { 348 mutex_spin_exit(&tty_lock); 349 return 0; /* end of file */ 350 } 351 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) { 352 mutex_spin_exit(&tty_lock); 353 return (EWOULDBLOCK); 354 } 355 error = ttysleep(tp, &tp->t_rawq.c_cv, true, 0); 356 if (error) { 357 mutex_spin_exit(&tty_lock); 358 return error; 359 } 360 } 361 362 /* Pull place-holder byte out of canonical queue */ 363 getc(&tp->t_canq); 364 365 /* Get the packet from the input queue */ 366 IF_DEQUEUE(&sc->sc_inq, m0); 367 mutex_spin_exit(&tty_lock); 368 369 for (m = m0; m && uio->uio_resid; m = m->m_next) 370 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0) 371 break; 372 m_freem(m0); 373 return (error); 374 } 375 376 /* 377 * Line specific (tty) write routine. 378 */ 379 static int 380 pppwrite(struct tty *tp, struct uio *uio, int flag) 381 { 382 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 383 struct mbuf *m, *m0; 384 struct sockaddr dst; 385 int len, error; 386 387 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 388 return 0; /* wrote 0 bytes */ 389 if (tp->t_linesw != &ppp_disc) 390 return (EINVAL); 391 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 392 return EIO; 393 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN || 394 uio->uio_resid < PPP_HDRLEN) 395 return (EMSGSIZE); 396 397 MGETHDR(m0, M_WAIT, MT_DATA); 398 if (m0 == NULL) 399 return ENOBUFS; 400 401 m0->m_len = 0; 402 m0->m_pkthdr.len = uio->uio_resid; 403 m0->m_pkthdr.rcvif = NULL; 404 405 if (uio->uio_resid >= MCLBYTES / 2) 406 MCLGET(m0, M_DONTWAIT); 407 408 for (m = m0; uio->uio_resid;) { 409 len = M_TRAILINGSPACE(m); 410 if (len > uio->uio_resid) 411 len = uio->uio_resid; 412 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) { 413 m_freem(m0); 414 return (error); 415 } 416 m->m_len = len; 417 418 if (uio->uio_resid == 0) 419 break; 420 421 MGET(m->m_next, M_WAIT, MT_DATA); 422 if (m->m_next == NULL) { 423 m_freem(m0); 424 return ENOBUFS; 425 } 426 m = m->m_next; 427 m->m_len = 0; 428 } 429 dst.sa_family = AF_UNSPEC; 430 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN); 431 m_adj(m0, PPP_HDRLEN); 432 return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0)); 433 } 434 435 /* 436 * Line specific (tty) ioctl routine. 437 * This discipline requires that tty device drivers call 438 * the line specific l_ioctl routine from their ioctl routines. 439 */ 440 /* ARGSUSED */ 441 static int 442 ppptioctl(struct tty *tp, u_long cmd, void *data, int flag, struct lwp *l) 443 { 444 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 445 int error, s; 446 447 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 448 return (EPASSTHROUGH); 449 450 error = 0; 451 switch (cmd) { 452 case TIOCRCVFRAME: 453 ppprcvframe(sc,*((struct mbuf **)data)); 454 break; 455 456 case PPPIOCSASYNCMAP: 457 if ((error = kauth_authorize_generic(l->l_cred, 458 KAUTH_GENERIC_ISSUSER, NULL)) != 0) 459 break; 460 sc->sc_asyncmap[0] = *(u_int *)data; 461 break; 462 463 case PPPIOCGASYNCMAP: 464 *(u_int *)data = sc->sc_asyncmap[0]; 465 break; 466 467 case PPPIOCSRASYNCMAP: 468 if ((error = kauth_authorize_generic(l->l_cred, 469 KAUTH_GENERIC_ISSUSER, NULL)) != 0) 470 break; 471 sc->sc_rasyncmap = *(u_int *)data; 472 break; 473 474 case PPPIOCGRASYNCMAP: 475 *(u_int *)data = sc->sc_rasyncmap; 476 break; 477 478 case PPPIOCSXASYNCMAP: 479 if ((error = kauth_authorize_generic(l->l_cred, 480 KAUTH_GENERIC_ISSUSER, NULL)) != 0) 481 break; 482 s = spltty(); 483 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 484 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ 485 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ 486 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ 487 splx(s); 488 break; 489 490 case PPPIOCGXASYNCMAP: 491 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); 492 break; 493 494 default: 495 error = pppioctl(sc, cmd, data, flag, l); 496 if (error == 0 && cmd == PPPIOCSMRU) 497 pppgetm(sc); 498 } 499 500 return error; 501 } 502 503 /* receive a complete ppp frame from device in synchronous 504 * hdlc mode. caller gives up ownership of mbuf 505 */ 506 static void 507 ppprcvframe(struct ppp_softc *sc, struct mbuf *m) 508 { 509 int len, s; 510 struct mbuf *n; 511 u_char hdr[4]; 512 int hlen,count; 513 514 for (n=m,len=0;n != NULL;n = n->m_next) 515 len += n->m_len; 516 if (len==0) { 517 m_freem(m); 518 return; 519 } 520 521 /* extract PPP header from mbuf chain (1 to 4 bytes) */ 522 for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) { 523 count = (sizeof(hdr)-hlen) < n->m_len ? 524 sizeof(hdr)-hlen : n->m_len; 525 bcopy(mtod(n,u_char*),&hdr[hlen],count); 526 hlen+=count; 527 } 528 529 s = spltty(); 530 531 /* if AFCF compressed then prepend AFCF */ 532 if (hdr[0] != PPP_ALLSTATIONS) { 533 if (sc->sc_flags & SC_REJ_COMP_AC) { 534 if (sc->sc_flags & SC_DEBUG) 535 printf( 536 "%s: garbage received: 0x%x (need 0xFF)\n", 537 sc->sc_if.if_xname, hdr[0]); 538 goto bail; 539 } 540 M_PREPEND(m,2,M_DONTWAIT); 541 if (m==NULL) { 542 splx(s); 543 return; 544 } 545 hdr[3] = hdr[1]; 546 hdr[2] = hdr[0]; 547 hdr[0] = PPP_ALLSTATIONS; 548 hdr[1] = PPP_UI; 549 len += 2; 550 } 551 552 /* if protocol field compressed, add MSB of protocol field = 0 */ 553 if (hdr[2] & 1) { 554 /* a compressed protocol */ 555 M_PREPEND(m,1,M_DONTWAIT); 556 if (m==NULL) { 557 splx(s); 558 return; 559 } 560 hdr[3] = hdr[2]; 561 hdr[2] = 0; 562 len++; 563 } 564 565 /* valid LSB of protocol field has bit0 set */ 566 if (!(hdr[3] & 1)) { 567 if (sc->sc_flags & SC_DEBUG) 568 printf("%s: bad protocol %x\n", sc->sc_if.if_xname, 569 (hdr[2] << 8) + hdr[3]); 570 goto bail; 571 } 572 573 /* packet beyond configured mru? */ 574 if (len > sc->sc_mru + PPP_HDRLEN) { 575 if (sc->sc_flags & SC_DEBUG) 576 printf("%s: packet too big\n", sc->sc_if.if_xname); 577 goto bail; 578 } 579 580 /* add expanded 4 byte header to mbuf chain */ 581 for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) { 582 count = (sizeof(hdr)-hlen) < n->m_len ? 583 sizeof(hdr)-hlen : n->m_len; 584 bcopy(&hdr[hlen],mtod(n,u_char*),count); 585 hlen+=count; 586 } 587 588 /* if_ppp.c requires the PPP header and IP header */ 589 /* to be contiguous */ 590 count = len < MHLEN ? len : MHLEN; 591 if (m->m_len < count) { 592 m = m_pullup(m,count); 593 if (m==NULL) 594 goto bail; 595 } 596 597 sc->sc_stats.ppp_ibytes += len; 598 599 if (sc->sc_flags & SC_LOG_RAWIN) 600 pppdumpframe(sc,m,0); 601 602 ppppktin(sc, m, 0); 603 splx(s); 604 return; 605 bail: 606 m_freem(m); 607 splx(s); 608 } 609 610 /* 611 * FCS lookup table as calculated by genfcstab. 612 */ 613 static const u_int16_t fcstab[256] = { 614 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 615 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 616 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 617 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 618 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 619 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 620 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 621 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 622 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 623 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 624 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 625 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 626 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 627 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 628 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 629 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 630 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 631 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 632 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 633 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 634 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 635 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 636 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 637 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 638 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 639 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 640 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 641 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 642 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 643 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 644 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 645 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 646 }; 647 648 /* 649 * Calculate a new FCS given the current FCS and the new data. 650 */ 651 static u_int16_t 652 pppfcs(u_int16_t fcs, u_char *cp, int len) 653 { 654 while (len--) 655 fcs = PPP_FCS(fcs, *cp++); 656 return (fcs); 657 } 658 659 /* This gets called at splsoftnet from pppasyncstart at various times 660 * when there is data ready to be sent. 661 */ 662 static void 663 pppsyncstart(struct ppp_softc *sc) 664 { 665 struct tty *tp = (struct tty *) sc->sc_devp; 666 struct mbuf *m, *n; 667 const struct cdevsw *cdev; 668 int len; 669 670 for(m = sc->sc_outm;;) { 671 if (m == NULL) { 672 m = ppp_dequeue(sc); /* get new packet */ 673 if (m == NULL) 674 break; /* no more packets */ 675 if (sc->sc_flags & SC_DEBUG) 676 pppdumpframe(sc,m,1); 677 } 678 for(n=m,len=0;n!=NULL;n=n->m_next) 679 len += n->m_len; 680 681 /* call device driver IOCTL to transmit a frame */ 682 cdev = cdevsw_lookup(tp->t_dev); 683 if (cdev == NULL || 684 (*cdev->d_ioctl)(tp->t_dev, TIOCXMTFRAME, (void *)&m, 685 0, 0)) { 686 /* busy or error, set as current packet */ 687 sc->sc_outm = m; 688 break; 689 } 690 sc->sc_outm = m = NULL; 691 sc->sc_stats.ppp_obytes += len; 692 } 693 } 694 695 /* 696 * This gets called at splsoftnet from if_ppp.c at various times 697 * when there is data ready to be sent. 698 */ 699 static void 700 pppasyncstart(struct ppp_softc *sc) 701 { 702 struct tty *tp = (struct tty *) sc->sc_devp; 703 struct mbuf *m; 704 int len; 705 u_char *start, *stop, *cp; 706 int n, ndone, done, idle; 707 struct mbuf *m2; 708 int s; 709 710 if (sc->sc_flags & SC_SYNC){ 711 pppsyncstart(sc); 712 return; 713 } 714 715 idle = 0; 716 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) { 717 /* 718 * See if we have an existing packet partly sent. 719 * If not, get a new packet and start sending it. 720 */ 721 m = sc->sc_outm; 722 if (m == NULL) { 723 /* 724 * Get another packet to be sent. 725 */ 726 m = ppp_dequeue(sc); 727 if (m == NULL) { 728 idle = 1; 729 break; 730 } 731 732 /* 733 * The extra PPP_FLAG will start up a new packet, and thus 734 * will flush any accumulated garbage. We do this whenever 735 * the line may have been idle for some time. 736 */ 737 if (CCOUNT(&tp->t_outq) == 0) { 738 ++sc->sc_stats.ppp_obytes; 739 (void) putc(PPP_FLAG, &tp->t_outq); 740 } 741 742 /* Calculate the FCS for the first mbuf's worth. */ 743 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); 744 } 745 746 for (;;) { 747 start = mtod(m, u_char *); 748 len = m->m_len; 749 stop = start + len; 750 while (len > 0) { 751 /* 752 * Find out how many bytes in the string we can 753 * handle without doing something special. 754 */ 755 for (cp = start; cp < stop; cp++) 756 if (ESCAPE_P(*cp)) 757 break; 758 n = cp - start; 759 if (n) { 760 /* NetBSD (0.9 or later), 4.3-Reno or similar. */ 761 ndone = n - b_to_q(start, n, &tp->t_outq); 762 len -= ndone; 763 start += ndone; 764 sc->sc_stats.ppp_obytes += ndone; 765 766 if (ndone < n) 767 break; /* packet doesn't fit */ 768 } 769 /* 770 * If there are characters left in the mbuf, 771 * the first one must be special. 772 * Put it out in a different form. 773 */ 774 if (len) { 775 s = spltty(); 776 if (putc(PPP_ESCAPE, &tp->t_outq)) { 777 splx(s); 778 break; 779 } 780 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { 781 (void) unputc(&tp->t_outq); 782 splx(s); 783 break; 784 } 785 splx(s); 786 sc->sc_stats.ppp_obytes += 2; 787 start++; 788 len--; 789 } 790 } 791 792 /* 793 * If we didn't empty this mbuf, remember where we're up to. 794 * If we emptied the last mbuf, try to add the FCS and closing 795 * flag, and if we can't, leave sc_outm pointing to m, but with 796 * m->m_len == 0, to remind us to output the FCS and flag later. 797 */ 798 done = len == 0; 799 if (done && m->m_next == NULL) { 800 u_char *p, *q; 801 int c; 802 u_char endseq[8]; 803 804 /* 805 * We may have to escape the bytes in the FCS. 806 */ 807 p = endseq; 808 c = ~sc->sc_outfcs & 0xFF; 809 if (ESCAPE_P(c)) { 810 *p++ = PPP_ESCAPE; 811 *p++ = c ^ PPP_TRANS; 812 } else 813 *p++ = c; 814 c = (~sc->sc_outfcs >> 8) & 0xFF; 815 if (ESCAPE_P(c)) { 816 *p++ = PPP_ESCAPE; 817 *p++ = c ^ PPP_TRANS; 818 } else 819 *p++ = c; 820 *p++ = PPP_FLAG; 821 822 /* 823 * Try to output the FCS and flag. If the bytes 824 * don't all fit, back out. 825 */ 826 s = spltty(); 827 for (q = endseq; q < p; ++q) 828 if (putc(*q, &tp->t_outq)) { 829 done = 0; 830 for (; q > endseq; --q) 831 unputc(&tp->t_outq); 832 break; 833 } 834 splx(s); 835 if (done) 836 sc->sc_stats.ppp_obytes += q - endseq; 837 } 838 839 if (!done) { 840 /* remember where we got to */ 841 m->m_data = start; 842 m->m_len = len; 843 break; 844 } 845 846 /* Finished with this mbuf; free it and move on. */ 847 MFREE(m, m2); 848 m = m2; 849 if (m == NULL) { 850 /* Finished a packet */ 851 break; 852 } 853 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); 854 } 855 856 /* 857 * If m == NULL, we have finished a packet. 858 * If m != NULL, we've either done as much work this time 859 * as we need to, or else we've filled up the output queue. 860 */ 861 sc->sc_outm = m; 862 if (m) 863 break; 864 } 865 866 /* Call pppstart to start output again if necessary. */ 867 s = spltty(); 868 pppstart(tp); 869 870 /* 871 * This timeout is needed for operation on a pseudo-tty, 872 * because the pty code doesn't call pppstart after it has 873 * drained the t_outq. 874 */ 875 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) { 876 callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc); 877 sc->sc_flags |= SC_TIMEOUT; 878 } 879 880 splx(s); 881 } 882 883 /* 884 * This gets called when a received packet is placed on 885 * the inq, at splsoftnet. 886 */ 887 static void 888 pppasyncctlp(struct ppp_softc *sc) 889 { 890 struct tty *tp; 891 892 /* Put a placeholder byte in canq for ttselect()/ttnread(). */ 893 mutex_spin_enter(&tty_lock); 894 tp = (struct tty *) sc->sc_devp; 895 putc(0, &tp->t_canq); 896 ttwakeup(tp); 897 mutex_spin_exit(&tty_lock); 898 } 899 900 /* 901 * Start output on async tty interface. If the transmit queue 902 * has drained sufficiently, arrange for pppasyncstart to be 903 * called later at splsoftnet. 904 * Called at spltty or higher. 905 */ 906 static int 907 pppstart(struct tty *tp) 908 { 909 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 910 911 /* 912 * If there is stuff in the output queue, send it now. 913 * We are being called in lieu of ttstart and must do what it would. 914 */ 915 if (tp->t_oproc != NULL) 916 (*tp->t_oproc)(tp); 917 918 /* 919 * If the transmit queue has drained and the tty has not hung up 920 * or been disconnected from the ppp unit, then tell if_ppp.c that 921 * we need more output. 922 */ 923 if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT) 924 && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT))) 925 return 0; 926 #ifdef ALTQ 927 /* 928 * if ALTQ is enabled, don't invoke NETISR_PPP. 929 * pppintr() could loop without doing anything useful 930 * under rate-limiting. 931 */ 932 if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd)) 933 return 0; 934 #endif 935 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 936 && sc != NULL && tp == (struct tty *) sc->sc_devp) { 937 ppp_restart(sc); 938 } 939 940 return 0; 941 } 942 943 /* 944 * Timeout routine - try to start some more output. 945 */ 946 static void 947 ppp_timeout(void *x) 948 { 949 struct ppp_softc *sc = (struct ppp_softc *) x; 950 struct tty *tp = (struct tty *) sc->sc_devp; 951 int s; 952 953 s = spltty(); 954 sc->sc_flags &= ~SC_TIMEOUT; 955 pppstart(tp); 956 splx(s); 957 } 958 959 /* 960 * Allocate enough mbuf to handle current MRU. 961 */ 962 static void 963 pppgetm(struct ppp_softc *sc) 964 { 965 struct mbuf *m, **mp; 966 int len; 967 968 mp = &sc->sc_m; 969 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ 970 if ((m = *mp) == NULL) { 971 MGETHDR(m, M_DONTWAIT, MT_DATA); 972 if (m == NULL) 973 break; 974 *mp = m; 975 MCLGET(m, M_DONTWAIT); 976 } 977 len -= M_DATASIZE(m); 978 mp = &m->m_next; 979 } 980 } 981 982 /* 983 * tty interface receiver interrupt. 984 */ 985 static const unsigned paritytab[8] = { 986 0x96696996, 0x69969669, 0x69969669, 0x96696996, 987 0x69969669, 0x96696996, 0x96696996, 0x69969669 988 }; 989 990 static int 991 pppinput(int c, struct tty *tp) 992 { 993 struct ppp_softc *sc; 994 struct mbuf *m; 995 const struct cdevsw *cdev; 996 int ilen, s; 997 998 sc = (struct ppp_softc *) tp->t_sc; 999 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 1000 return 0; 1001 1002 ++tk_nin; 1003 ++sc->sc_stats.ppp_ibytes; 1004 1005 if (c & TTY_FE) { 1006 /* framing error or overrun on this char - abort packet */ 1007 if (sc->sc_flags & SC_DEBUG) 1008 printf("%s: bad char %x\n", sc->sc_if.if_xname, c); 1009 goto flush; 1010 } 1011 1012 c &= 0xff; 1013 1014 /* 1015 * Handle software flow control of output. 1016 */ 1017 if (tp->t_iflag & IXON) { 1018 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 1019 if ((tp->t_state & TS_TTSTOP) == 0) { 1020 tp->t_state |= TS_TTSTOP; 1021 cdev = cdevsw_lookup(tp->t_dev); 1022 if (cdev != NULL) 1023 (*cdev->d_stop)(tp, 0); 1024 } 1025 return 0; 1026 } 1027 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) { 1028 tp->t_state &= ~TS_TTSTOP; 1029 if (tp->t_oproc != NULL) 1030 (*tp->t_oproc)(tp); 1031 return 0; 1032 } 1033 } 1034 1035 s = spltty(); 1036 if (c & 0x80) 1037 sc->sc_flags |= SC_RCV_B7_1; 1038 else 1039 sc->sc_flags |= SC_RCV_B7_0; 1040 if (paritytab[c >> 5] & (1 << (c & 0x1F))) 1041 sc->sc_flags |= SC_RCV_ODDP; 1042 else 1043 sc->sc_flags |= SC_RCV_EVNP; 1044 splx(s); 1045 1046 ppplogchar(sc, c); 1047 1048 if (c == PPP_FLAG) { 1049 ilen = sc->sc_ilen; 1050 sc->sc_ilen = 0; 1051 1052 if ((sc->sc_flags & SC_LOG_RAWIN) && sc->sc_rawin.count > 0) 1053 ppplogchar(sc, -1); 1054 1055 /* 1056 * If SC_ESCAPED is set, then we've seen the packet 1057 * abort sequence "}~". 1058 */ 1059 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) 1060 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { 1061 s = spltty(); 1062 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ 1063 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ 1064 if (sc->sc_flags & SC_DEBUG) 1065 printf("%s: bad fcs %x\n", sc->sc_if.if_xname, 1066 sc->sc_fcs); 1067 sc->sc_if.if_ierrors++; 1068 sc->sc_stats.ppp_ierrors++; 1069 } else 1070 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); 1071 splx(s); 1072 return 0; 1073 } 1074 1075 if (ilen < PPP_HDRLEN + PPP_FCSLEN) { 1076 if (ilen) { 1077 if (sc->sc_flags & SC_DEBUG) 1078 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen); 1079 s = spltty(); 1080 sc->sc_if.if_ierrors++; 1081 sc->sc_stats.ppp_ierrors++; 1082 sc->sc_flags |= SC_PKTLOST; 1083 splx(s); 1084 } 1085 return 0; 1086 } 1087 1088 /* 1089 * Remove FCS trailer. Somewhat painful... 1090 */ 1091 ilen -= 2; 1092 if (--sc->sc_mc->m_len == 0) { 1093 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) 1094 ; 1095 sc->sc_mc = m; 1096 } 1097 sc->sc_mc->m_len--; 1098 1099 /* excise this mbuf chain */ 1100 m = sc->sc_m; 1101 sc->sc_m = sc->sc_mc->m_next; 1102 sc->sc_mc->m_next = NULL; 1103 1104 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST); 1105 if (sc->sc_flags & SC_PKTLOST) { 1106 s = spltty(); 1107 sc->sc_flags &= ~SC_PKTLOST; 1108 splx(s); 1109 } 1110 1111 pppgetm(sc); 1112 return 0; 1113 } 1114 1115 if (sc->sc_flags & SC_FLUSH) { 1116 if (sc->sc_flags & SC_LOG_FLUSH) 1117 ppplogchar(sc, c); 1118 return 0; 1119 } 1120 1121 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) 1122 return 0; 1123 1124 s = spltty(); 1125 if (sc->sc_flags & SC_ESCAPED) { 1126 sc->sc_flags &= ~SC_ESCAPED; 1127 c ^= PPP_TRANS; 1128 } else if (c == PPP_ESCAPE) { 1129 sc->sc_flags |= SC_ESCAPED; 1130 splx(s); 1131 return 0; 1132 } 1133 splx(s); 1134 1135 /* 1136 * Initialize buffer on first octet received. 1137 * First octet could be address or protocol (when compressing 1138 * address/control). 1139 * Second octet is control. 1140 * Third octet is first or second (when compressing protocol) 1141 * octet of protocol. 1142 * Fourth octet is second octet of protocol. 1143 */ 1144 if (sc->sc_ilen == 0) { 1145 /* reset the first input mbuf */ 1146 if (sc->sc_m == NULL) { 1147 pppgetm(sc); 1148 if (sc->sc_m == NULL) { 1149 if (sc->sc_flags & SC_DEBUG) 1150 printf("%s: no input mbufs!\n", sc->sc_if.if_xname); 1151 goto flush; 1152 } 1153 } 1154 m = sc->sc_m; 1155 m->m_len = 0; 1156 m->m_data = M_DATASTART(sc->sc_m); 1157 sc->sc_mc = m; 1158 sc->sc_mp = mtod(m, char *); 1159 sc->sc_fcs = PPP_INITFCS; 1160 if (c != PPP_ALLSTATIONS) { 1161 if (sc->sc_flags & SC_REJ_COMP_AC) { 1162 if (sc->sc_flags & SC_DEBUG) 1163 printf("%s: garbage received: 0x%x (need 0xFF)\n", 1164 sc->sc_if.if_xname, c); 1165 goto flush; 1166 } 1167 *sc->sc_mp++ = PPP_ALLSTATIONS; 1168 *sc->sc_mp++ = PPP_UI; 1169 sc->sc_ilen += 2; 1170 m->m_len += 2; 1171 } 1172 } 1173 if (sc->sc_ilen == 1 && c != PPP_UI) { 1174 if (sc->sc_flags & SC_DEBUG) 1175 printf("%s: missing UI (0x3), got 0x%x\n", 1176 sc->sc_if.if_xname, c); 1177 goto flush; 1178 } 1179 if (sc->sc_ilen == 2 && (c & 1) == 1) { 1180 /* a compressed protocol */ 1181 *sc->sc_mp++ = 0; 1182 sc->sc_ilen++; 1183 sc->sc_mc->m_len++; 1184 } 1185 if (sc->sc_ilen == 3 && (c & 1) == 0) { 1186 if (sc->sc_flags & SC_DEBUG) 1187 printf("%s: bad protocol %x\n", sc->sc_if.if_xname, 1188 (sc->sc_mp[-1] << 8) + c); 1189 goto flush; 1190 } 1191 1192 /* packet beyond configured mru? */ 1193 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { 1194 if (sc->sc_flags & SC_DEBUG) 1195 printf("%s: packet too big\n", sc->sc_if.if_xname); 1196 goto flush; 1197 } 1198 1199 /* is this mbuf full? */ 1200 m = sc->sc_mc; 1201 if (M_TRAILINGSPACE(m) <= 0) { 1202 if (m->m_next == NULL) { 1203 pppgetm(sc); 1204 if (m->m_next == NULL) { 1205 if (sc->sc_flags & SC_DEBUG) 1206 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname); 1207 goto flush; 1208 } 1209 } 1210 sc->sc_mc = m = m->m_next; 1211 m->m_len = 0; 1212 m->m_data = M_DATASTART(m); 1213 sc->sc_mp = mtod(m, char *); 1214 } 1215 1216 ++m->m_len; 1217 *sc->sc_mp++ = c; 1218 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); 1219 return 0; 1220 1221 flush: 1222 if (!(sc->sc_flags & SC_FLUSH)) { 1223 s = spltty(); 1224 sc->sc_if.if_ierrors++; 1225 sc->sc_stats.ppp_ierrors++; 1226 sc->sc_flags |= SC_FLUSH; 1227 splx(s); 1228 if (sc->sc_flags & SC_LOG_FLUSH) 1229 ppplogchar(sc, c); 1230 } 1231 return 0; 1232 } 1233 1234 #define MAX_DUMP_BYTES 128 1235 1236 static void 1237 ppplogchar(struct ppp_softc *sc, int c) 1238 { 1239 if (c >= 0) { 1240 sc->sc_rawin.buf[sc->sc_rawin_start++] = c; 1241 if (sc->sc_rawin.count < sizeof(sc->sc_rawin.buf)) 1242 sc->sc_rawin.count++; 1243 } 1244 if (sc->sc_rawin_start >= sizeof(sc->sc_rawin.buf) 1245 || (c < 0 && sc->sc_rawin_start > 0)) { 1246 if (sc->sc_flags & (SC_LOG_FLUSH|SC_LOG_RAWIN)) { 1247 printf("%s input: ", sc->sc_if.if_xname); 1248 pppdumpb(sc->sc_rawin.buf, sc->sc_rawin_start); 1249 } 1250 if (c < 0) 1251 sc->sc_rawin.count = 0; 1252 sc->sc_rawin_start = 0; 1253 } 1254 } 1255 1256 static void 1257 pppdumpb(u_char *b, int l) 1258 { 1259 char bf[3*MAX_DUMP_BYTES+4]; 1260 char *bp = bf; 1261 1262 while (l--) { 1263 if (bp >= bf + sizeof(bf) - 3) { 1264 *bp++ = '>'; 1265 break; 1266 } 1267 *bp++ = hexdigits[*b >> 4]; /* convert byte to ascii hex */ 1268 *bp++ = hexdigits[*b++ & 0xf]; 1269 *bp++ = ' '; 1270 } 1271 1272 *bp = 0; 1273 printf("%s\n", bf); 1274 } 1275 1276 static void 1277 pppdumpframe(struct ppp_softc *sc, struct mbuf *m, int xmit) 1278 { 1279 int i,lcount,copycount,count; 1280 char lbuf[16]; 1281 char *data; 1282 1283 if (m == NULL) 1284 return; 1285 1286 for(count=m->m_len,data=mtod(m,char*);m != NULL;) { 1287 /* build a line of output */ 1288 for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) { 1289 if (!count) { 1290 m = m->m_next; 1291 if (m == NULL) 1292 break; 1293 count = m->m_len; 1294 data = mtod(m,char*); 1295 } 1296 copycount = (count > sizeof(lbuf)-lcount) ? 1297 sizeof(lbuf)-lcount : count; 1298 bcopy(data,&lbuf[lcount],copycount); 1299 data += copycount; 1300 count -= copycount; 1301 } 1302 1303 /* output line (hex 1st, then ascii) */ 1304 printf("%s %s:", sc->sc_if.if_xname, 1305 xmit ? "output" : "input "); 1306 for(i=0;i<lcount;i++) 1307 printf("%02x ",(u_char)lbuf[i]); 1308 for(;i<sizeof(lbuf);i++) 1309 printf(" "); 1310 for(i=0;i<lcount;i++) 1311 printf("%c",(lbuf[i] >= 040 && 1312 lbuf[i] <= 0176) ? lbuf[i] : '.'); 1313 printf("\n"); 1314 } 1315 } 1316