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