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