ppp_tty.c revision 1.58.4.1 1 /* $NetBSD: ppp_tty.c,v 1.58.4.1 2015/09/22 12:06:10 skrll 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.58.4.1 2015/09/22 12:06:10 skrll Exp $");
97
98 #include "ppp.h"
99
100 #ifdef _KERNEL_OPT
101 #include "opt_ppp.h"
102 #endif
103 #define VJC
104 #define PPP_COMPRESS
105
106 #include <sys/param.h>
107 #include <sys/proc.h>
108 #include <sys/mbuf.h>
109 #include <sys/dkstat.h>
110 #include <sys/socket.h>
111 #include <sys/ioctl.h>
112 #include <sys/file.h>
113 #include <sys/tty.h>
114 #include <sys/kernel.h>
115 #include <sys/conf.h>
116 #include <sys/vnode.h>
117 #include <sys/systm.h>
118 #include <sys/kauth.h>
119
120 #include <net/if.h>
121 #include <net/if_types.h>
122
123 #ifdef VJC
124 #include <netinet/in.h>
125 #include <netinet/in_systm.h>
126 #include <netinet/ip.h>
127 #include <net/slcompress.h>
128 #endif
129
130 #include <net/bpf.h>
131 #include <net/ppp_defs.h>
132 #include <net/if_ppp.h>
133 #include <net/if_pppvar.h>
134
135 static int pppopen(dev_t dev, struct tty *tp);
136 static int pppclose(struct tty *tp, int flag);
137 static int pppread(struct tty *tp, struct uio *uio, int flag);
138 static int pppwrite(struct tty *tp, struct uio *uio, int flag);
139 static int ppptioctl(struct tty *tp, u_long cmd, void *data, int flag,
140 struct lwp *);
141 static int pppinput(int c, struct tty *tp);
142 static int pppstart(struct tty *tp);
143
144 struct linesw ppp_disc = { /* XXX should be static */
145 .l_name = "ppp",
146 .l_open = pppopen,
147 .l_close = pppclose,
148 .l_read = pppread,
149 .l_write = pppwrite,
150 .l_ioctl = ppptioctl,
151 .l_rint = pppinput,
152 .l_start = pppstart,
153 .l_modem = ttymodem,
154 .l_poll = ttpoll
155 };
156
157 static void ppprcvframe(struct ppp_softc *sc, struct mbuf *m);
158 static uint16_t pppfcs(uint16_t fcs, const uint8_t *cp, int len);
159 static void pppsyncstart(struct ppp_softc *sc);
160 static void pppasyncstart(struct ppp_softc *);
161 static void pppasyncctlp(struct ppp_softc *);
162 static void pppasyncrelinq(struct ppp_softc *);
163 static void ppp_timeout(void *);
164 static void pppgetm(struct ppp_softc *sc);
165 static void pppdumpb(u_char *b, int l);
166 static void ppplogchar(struct ppp_softc *, int);
167 static void pppdumpframe(struct ppp_softc *sc, struct mbuf* m, int xmit);
168
169 /*
170 * Some useful mbuf macros not in mbuf.h.
171 */
172 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
173
174 #define M_DATASTART(m) \
175 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
176 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
177
178 #define M_DATASIZE(m) \
179 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
180 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
181
182 /*
183 * Does c need to be escaped?
184 */
185 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
186
187 /*
188 * Procedures for using an async tty interface for PPP.
189 */
190
191 /* This is a NetBSD-1.0 or later kernel. */
192 #define CCOUNT(q) ((q)->c_cc)
193
194 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
195 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
196
197 /*
198 * Line specific open routine for async tty devices.
199 * Attach the given tty to the first available ppp unit.
200 * Called from device open routine or ttioctl.
201 */
202 /* ARGSUSED */
203 static int
204 pppopen(dev_t dev, struct tty *tp)
205 {
206 struct lwp *l = curlwp; /* XXX */
207 struct ppp_softc *sc;
208 int error, s;
209
210 error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_PPP,
211 KAUTH_REQ_NETWORK_INTERFACE_PPP_ADD, NULL, NULL, NULL);
212 if (error)
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 /* Switch DLT to PPP-over-serial. */
234 bpf_change_type(&sc->sc_if, DLT_PPP_SERIAL, PPP_HDRLEN);
235
236 sc->sc_ilen = 0;
237 sc->sc_m = NULL;
238 memset(sc->sc_asyncmap, 0, sizeof(sc->sc_asyncmap));
239 sc->sc_asyncmap[0] = 0xffffffff;
240 sc->sc_asyncmap[3] = 0x60000000;
241 sc->sc_rasyncmap = 0;
242 sc->sc_devp = (void *) tp;
243 sc->sc_start = pppasyncstart;
244 sc->sc_ctlp = pppasyncctlp;
245 sc->sc_relinq = pppasyncrelinq;
246 sc->sc_outm = NULL;
247 pppgetm(sc);
248 sc->sc_if.if_flags |= IFF_RUNNING;
249 sc->sc_if.if_baudrate = tp->t_ospeed;
250
251 tp->t_sc = (void *) sc;
252 mutex_spin_enter(&tty_lock);
253 ttyflush(tp, FREAD | FWRITE);
254 mutex_spin_exit(&tty_lock);
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 mutex_spin_enter(&tty_lock);
274 ttyflush(tp, FREAD|FWRITE);
275 mutex_spin_exit(&tty_lock); /* XXX */
276 ttyldisc_release(tp->t_linesw);
277 tp->t_linesw = ttyldisc_default();
278 sc = (struct ppp_softc *) tp->t_sc;
279 if (sc != NULL) {
280 tp->t_sc = NULL;
281 if (tp == (struct tty *) sc->sc_devp) {
282 pppasyncrelinq(sc);
283 pppdealloc(sc);
284 }
285 }
286 splx(s);
287 return 0;
288 }
289
290 /*
291 * Relinquish the interface unit to another device.
292 */
293 static void
294 pppasyncrelinq(struct ppp_softc *sc)
295 {
296 int s;
297
298 /* Change DLT to back none. */
299 bpf_change_type(&sc->sc_if, DLT_NULL, 0);
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_rawcv, 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_device_tty(l->l_cred,
454 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 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_device_tty(l->l_cred,
465 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 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_device_tty(l->l_cred,
476 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 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 uint16_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 uint16_t
648 pppfcs(uint16_t fcs, const uint8_t *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
705 if (sc->sc_flags & SC_SYNC){
706 pppsyncstart(sc);
707 return;
708 }
709
710 mutex_spin_enter(&tty_lock);
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, uint8_t *), 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 if (putc(PPP_ESCAPE, &tp->t_outq))
773 break;
774 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
775 (void) unputc(&tp->t_outq);
776 break;
777 }
778 sc->sc_stats.ppp_obytes += 2;
779 start++;
780 len--;
781 }
782 }
783
784 /*
785 * If we didn't empty this mbuf, remember where we're up to.
786 * If we emptied the last mbuf, try to add the FCS and closing
787 * flag, and if we can't, leave sc_outm pointing to m, but with
788 * m->m_len == 0, to remind us to output the FCS and flag later.
789 */
790 done = len == 0;
791 if (done && m->m_next == NULL) {
792 u_char *p, *q;
793 int c;
794 u_char endseq[8];
795
796 /*
797 * We may have to escape the bytes in the FCS.
798 */
799 p = endseq;
800 c = ~sc->sc_outfcs & 0xFF;
801 if (ESCAPE_P(c)) {
802 *p++ = PPP_ESCAPE;
803 *p++ = c ^ PPP_TRANS;
804 } else
805 *p++ = c;
806 c = (~sc->sc_outfcs >> 8) & 0xFF;
807 if (ESCAPE_P(c)) {
808 *p++ = PPP_ESCAPE;
809 *p++ = c ^ PPP_TRANS;
810 } else
811 *p++ = c;
812 *p++ = PPP_FLAG;
813
814 /*
815 * Try to output the FCS and flag. If the bytes
816 * don't all fit, back out.
817 */
818 for (q = endseq; q < p; ++q)
819 if (putc(*q, &tp->t_outq)) {
820 done = 0;
821 for (; q > endseq; --q)
822 unputc(&tp->t_outq);
823 break;
824 }
825 if (done)
826 sc->sc_stats.ppp_obytes += q - endseq;
827 }
828
829 if (!done) {
830 /* remember where we got to */
831 m->m_data = start;
832 m->m_len = len;
833 break;
834 }
835
836 /* Finished with this mbuf; free it and move on. */
837 MFREE(m, m2);
838 m = m2;
839 if (m == NULL) {
840 /* Finished a packet */
841 break;
842 }
843 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, uint8_t *), m->m_len);
844 }
845
846 /*
847 * If m == NULL, we have finished a packet.
848 * If m != NULL, we've either done as much work this time
849 * as we need to, or else we've filled up the output queue.
850 */
851 sc->sc_outm = m;
852 if (m)
853 break;
854 }
855
856 /* Call pppstart to start output again if necessary. */
857 pppstart(tp);
858
859 /*
860 * This timeout is needed for operation on a pseudo-tty,
861 * because the pty code doesn't call pppstart after it has
862 * drained the t_outq.
863 */
864 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
865 callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
866 sc->sc_flags |= SC_TIMEOUT;
867 }
868
869 mutex_spin_exit(&tty_lock);
870 }
871
872 /*
873 * This gets called when a received packet is placed on
874 * the inq, at splsoftnet.
875 */
876 static void
877 pppasyncctlp(struct ppp_softc *sc)
878 {
879 struct tty *tp;
880
881 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
882 mutex_spin_enter(&tty_lock);
883 tp = (struct tty *) sc->sc_devp;
884 putc(0, &tp->t_canq);
885 ttwakeup(tp);
886 mutex_spin_exit(&tty_lock);
887 }
888
889 /*
890 * Start output on async tty interface. If the transmit queue
891 * has drained sufficiently, arrange for pppasyncstart to be
892 * called later at splsoftnet.
893 * Called at spltty or higher.
894 */
895 static int
896 pppstart(struct tty *tp)
897 {
898 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
899
900 /*
901 * If there is stuff in the output queue, send it now.
902 * We are being called in lieu of ttstart and must do what it would.
903 */
904 if (tp->t_oproc != NULL)
905 (*tp->t_oproc)(tp);
906
907 /*
908 * If the transmit queue has drained and the tty has not hung up
909 * or been disconnected from the ppp unit, then tell if_ppp.c that
910 * we need more output.
911 */
912 if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
913 && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
914 return 0;
915 #ifdef ALTQ
916 /*
917 * if ALTQ is enabled, don't invoke NETISR_PPP.
918 * pppintr() could loop without doing anything useful
919 * under rate-limiting.
920 */
921 if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd))
922 return 0;
923 #endif
924 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
925 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
926 ppp_restart(sc);
927 }
928
929 return 0;
930 }
931
932 /*
933 * Timeout routine - try to start some more output.
934 */
935 static void
936 ppp_timeout(void *x)
937 {
938 struct ppp_softc *sc = (struct ppp_softc *) x;
939 struct tty *tp = (struct tty *) sc->sc_devp;
940
941 mutex_spin_enter(&tty_lock);
942 sc->sc_flags &= ~SC_TIMEOUT;
943 pppstart(tp);
944 mutex_spin_exit(&tty_lock);
945 }
946
947 /*
948 * Allocate enough mbuf to handle current MRU.
949 */
950 static void
951 pppgetm(struct ppp_softc *sc)
952 {
953 struct mbuf *m, **mp;
954 int len;
955
956 mp = &sc->sc_m;
957 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
958 if ((m = *mp) == NULL) {
959 MGETHDR(m, M_DONTWAIT, MT_DATA);
960 if (m == NULL)
961 break;
962 *mp = m;
963 MCLGET(m, M_DONTWAIT);
964 }
965 len -= M_DATASIZE(m);
966 mp = &m->m_next;
967 }
968 }
969
970 /*
971 * tty interface receiver interrupt.
972 */
973 static const unsigned paritytab[8] = {
974 0x96696996, 0x69969669, 0x69969669, 0x96696996,
975 0x69969669, 0x96696996, 0x96696996, 0x69969669
976 };
977
978 static int
979 pppinput(int c, struct tty *tp)
980 {
981 struct ppp_softc *sc;
982 struct mbuf *m;
983 int ilen, s;
984 int result;
985
986 sc = (struct ppp_softc *) tp->t_sc;
987 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
988 return 0;
989
990 ++tk_nin;
991 ++sc->sc_stats.ppp_ibytes;
992
993 if (c & TTY_FE) {
994 /* framing error or overrun on this char - abort packet */
995 if (sc->sc_flags & SC_DEBUG)
996 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
997 goto flush;
998 }
999
1000 c &= 0xff;
1001
1002 /*
1003 * Handle software flow control of output.
1004 */
1005 result = tty_try_xonxoff(tp, c);
1006 if (result == 0) {
1007 /* Character was recognized and consumed. */
1008 return 0;
1009 }
1010 /* Character wasn't consumed, continue processing it. */
1011
1012 s = spltty();
1013 if (c & 0x80)
1014 sc->sc_flags |= SC_RCV_B7_1;
1015 else
1016 sc->sc_flags |= SC_RCV_B7_0;
1017 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
1018 sc->sc_flags |= SC_RCV_ODDP;
1019 else
1020 sc->sc_flags |= SC_RCV_EVNP;
1021 splx(s);
1022
1023 ppplogchar(sc, c);
1024
1025 if (c == PPP_FLAG) {
1026 ilen = sc->sc_ilen;
1027 sc->sc_ilen = 0;
1028
1029 if ((sc->sc_flags & SC_LOG_RAWIN) && sc->sc_rawin.count > 0)
1030 ppplogchar(sc, -1);
1031
1032 /*
1033 * If SC_ESCAPED is set, then we've seen the packet
1034 * abort sequence "}~".
1035 */
1036 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1037 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
1038 s = spltty();
1039 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1040 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1041 if (sc->sc_flags & SC_DEBUG)
1042 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
1043 sc->sc_fcs);
1044 sc->sc_if.if_ierrors++;
1045 sc->sc_stats.ppp_ierrors++;
1046 } else
1047 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1048 splx(s);
1049 return 0;
1050 }
1051
1052 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1053 if (ilen) {
1054 if (sc->sc_flags & SC_DEBUG)
1055 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
1056 s = spltty();
1057 sc->sc_if.if_ierrors++;
1058 sc->sc_stats.ppp_ierrors++;
1059 sc->sc_flags |= SC_PKTLOST;
1060 splx(s);
1061 }
1062 return 0;
1063 }
1064
1065 /*
1066 * Remove FCS trailer. Somewhat painful...
1067 */
1068 ilen -= 2;
1069 if (--sc->sc_mc->m_len == 0) {
1070 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1071 ;
1072 sc->sc_mc = m;
1073 }
1074 sc->sc_mc->m_len--;
1075
1076 /* excise this mbuf chain */
1077 m = sc->sc_m;
1078 sc->sc_m = sc->sc_mc->m_next;
1079 sc->sc_mc->m_next = NULL;
1080
1081 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1082 if (sc->sc_flags & SC_PKTLOST) {
1083 s = spltty();
1084 sc->sc_flags &= ~SC_PKTLOST;
1085 splx(s);
1086 }
1087
1088 pppgetm(sc);
1089 return 0;
1090 }
1091
1092 if (sc->sc_flags & SC_FLUSH) {
1093 if (sc->sc_flags & SC_LOG_FLUSH)
1094 ppplogchar(sc, c);
1095 return 0;
1096 }
1097
1098 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1099 return 0;
1100
1101 s = spltty();
1102 if (sc->sc_flags & SC_ESCAPED) {
1103 sc->sc_flags &= ~SC_ESCAPED;
1104 c ^= PPP_TRANS;
1105 } else if (c == PPP_ESCAPE) {
1106 sc->sc_flags |= SC_ESCAPED;
1107 splx(s);
1108 return 0;
1109 }
1110 splx(s);
1111
1112 /*
1113 * Initialize buffer on first octet received.
1114 * First octet could be address or protocol (when compressing
1115 * address/control).
1116 * Second octet is control.
1117 * Third octet is first or second (when compressing protocol)
1118 * octet of protocol.
1119 * Fourth octet is second octet of protocol.
1120 */
1121 if (sc->sc_ilen == 0) {
1122 /* reset the first input mbuf */
1123 if (sc->sc_m == NULL) {
1124 pppgetm(sc);
1125 if (sc->sc_m == NULL) {
1126 if (sc->sc_flags & SC_DEBUG)
1127 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
1128 goto flush;
1129 }
1130 }
1131 m = sc->sc_m;
1132 m->m_len = 0;
1133 m->m_data = M_DATASTART(sc->sc_m);
1134 sc->sc_mc = m;
1135 sc->sc_mp = mtod(m, char *);
1136 sc->sc_fcs = PPP_INITFCS;
1137 if (c != PPP_ALLSTATIONS) {
1138 if (sc->sc_flags & SC_REJ_COMP_AC) {
1139 if (sc->sc_flags & SC_DEBUG)
1140 printf("%s: garbage received: 0x%x (need 0xFF)\n",
1141 sc->sc_if.if_xname, c);
1142 goto flush;
1143 }
1144 *sc->sc_mp++ = PPP_ALLSTATIONS;
1145 *sc->sc_mp++ = PPP_UI;
1146 sc->sc_ilen += 2;
1147 m->m_len += 2;
1148 }
1149 }
1150 if (sc->sc_ilen == 1 && c != PPP_UI) {
1151 if (sc->sc_flags & SC_DEBUG)
1152 printf("%s: missing UI (0x3), got 0x%x\n",
1153 sc->sc_if.if_xname, c);
1154 goto flush;
1155 }
1156 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1157 /* a compressed protocol */
1158 *sc->sc_mp++ = 0;
1159 sc->sc_ilen++;
1160 sc->sc_mc->m_len++;
1161 }
1162 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1163 if (sc->sc_flags & SC_DEBUG)
1164 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1165 (sc->sc_mp[-1] << 8) + c);
1166 goto flush;
1167 }
1168
1169 /* packet beyond configured mru? */
1170 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1171 if (sc->sc_flags & SC_DEBUG)
1172 printf("%s: packet too big\n", sc->sc_if.if_xname);
1173 goto flush;
1174 }
1175
1176 /* is this mbuf full? */
1177 m = sc->sc_mc;
1178 if (M_TRAILINGSPACE(m) <= 0) {
1179 if (m->m_next == NULL) {
1180 pppgetm(sc);
1181 if (m->m_next == NULL) {
1182 if (sc->sc_flags & SC_DEBUG)
1183 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1184 goto flush;
1185 }
1186 }
1187 sc->sc_mc = m = m->m_next;
1188 m->m_len = 0;
1189 m->m_data = M_DATASTART(m);
1190 sc->sc_mp = mtod(m, char *);
1191 }
1192
1193 ++m->m_len;
1194 *sc->sc_mp++ = c;
1195 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1196 return 0;
1197
1198 flush:
1199 if (!(sc->sc_flags & SC_FLUSH)) {
1200 s = spltty();
1201 sc->sc_if.if_ierrors++;
1202 sc->sc_stats.ppp_ierrors++;
1203 sc->sc_flags |= SC_FLUSH;
1204 splx(s);
1205 if (sc->sc_flags & SC_LOG_FLUSH)
1206 ppplogchar(sc, c);
1207 }
1208 return 0;
1209 }
1210
1211 #define MAX_DUMP_BYTES 128
1212
1213 static void
1214 ppplogchar(struct ppp_softc *sc, int c)
1215 {
1216 if (c >= 0) {
1217 sc->sc_rawin.buf[sc->sc_rawin_start++] = c;
1218 if (sc->sc_rawin.count < sizeof(sc->sc_rawin.buf))
1219 sc->sc_rawin.count++;
1220 }
1221 if (sc->sc_rawin_start >= sizeof(sc->sc_rawin.buf)
1222 || (c < 0 && sc->sc_rawin_start > 0)) {
1223 if (sc->sc_flags & (SC_LOG_FLUSH|SC_LOG_RAWIN)) {
1224 printf("%s input: ", sc->sc_if.if_xname);
1225 pppdumpb(sc->sc_rawin.buf, sc->sc_rawin_start);
1226 }
1227 if (c < 0)
1228 sc->sc_rawin.count = 0;
1229 sc->sc_rawin_start = 0;
1230 }
1231 }
1232
1233 static void
1234 pppdumpb(u_char *b, int l)
1235 {
1236 char bf[3*MAX_DUMP_BYTES+4];
1237 char *bp = bf;
1238
1239 while (l--) {
1240 if (bp >= bf + sizeof(bf) - 3) {
1241 *bp++ = '>';
1242 break;
1243 }
1244 *bp++ = hexdigits[*b >> 4]; /* convert byte to ascii hex */
1245 *bp++ = hexdigits[*b++ & 0xf];
1246 *bp++ = ' ';
1247 }
1248
1249 *bp = 0;
1250 printf("%s\n", bf);
1251 }
1252
1253 static void
1254 pppdumpframe(struct ppp_softc *sc, struct mbuf *m, int xmit)
1255 {
1256 int i,lcount,copycount,count;
1257 char lbuf[16];
1258 char *data;
1259
1260 if (m == NULL)
1261 return;
1262
1263 for(count=m->m_len,data=mtod(m,char*);m != NULL;) {
1264 /* build a line of output */
1265 for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) {
1266 if (!count) {
1267 m = m->m_next;
1268 if (m == NULL)
1269 break;
1270 count = m->m_len;
1271 data = mtod(m,char*);
1272 }
1273 copycount = (count > sizeof(lbuf)-lcount) ?
1274 sizeof(lbuf)-lcount : count;
1275 bcopy(data,&lbuf[lcount],copycount);
1276 data += copycount;
1277 count -= copycount;
1278 }
1279
1280 /* output line (hex 1st, then ascii) */
1281 printf("%s %s:", sc->sc_if.if_xname,
1282 xmit ? "output" : "input ");
1283 for(i=0;i<lcount;i++)
1284 printf("%02x ",(u_char)lbuf[i]);
1285 for(;i<sizeof(lbuf);i++)
1286 printf(" ");
1287 for(i=0;i<lcount;i++)
1288 printf("%c",(lbuf[i] >= 040 &&
1289 lbuf[i] <= 0176) ? lbuf[i] : '.');
1290 printf("\n");
1291 }
1292 }
1293