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