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