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