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