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