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