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