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