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