ppp_tty.c revision 1.61.2.2 1 /* $NetBSD: ppp_tty.c,v 1.61.2.2 2016/11/04 14:49:21 pgoyette 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.61.2.2 2016/11/04 14:49:21 pgoyette Exp $");
97
98 #ifdef _KERNEL_OPT
99 #include "opt_ppp.h"
100 #endif
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 <net/bpf.h>
129 #include <net/ppp_defs.h>
130 #include <net/if_ppp.h>
131 #include <net/if_pppvar.h>
132
133 static int pppopen(dev_t dev, struct tty *tp);
134 static int pppclose(struct tty *tp, int flag);
135 static int pppread(struct tty *tp, struct uio *uio, int flag);
136 static int pppwrite(struct tty *tp, struct uio *uio, int flag);
137 static int ppptioctl(struct tty *tp, u_long cmd, void *data, int flag,
138 struct lwp *);
139 static int pppinput(int c, struct tty *tp);
140 static int pppstart(struct tty *tp);
141
142 struct linesw ppp_disc = { /* XXX should be static */
143 .l_name = "ppp",
144 .l_open = pppopen,
145 .l_close = pppclose,
146 .l_read = pppread,
147 .l_write = pppwrite,
148 .l_ioctl = ppptioctl,
149 .l_rint = pppinput,
150 .l_start = pppstart,
151 .l_modem = ttymodem,
152 .l_poll = ttpoll
153 };
154
155 static void ppprcvframe(struct ppp_softc *sc, struct mbuf *m);
156 static uint16_t pppfcs(uint16_t fcs, const uint8_t *cp, int len);
157 static void pppsyncstart(struct ppp_softc *sc);
158 static void pppasyncstart(struct ppp_softc *);
159 static void pppasyncctlp(struct ppp_softc *);
160 static void pppasyncrelinq(struct ppp_softc *);
161 static void ppp_timeout(void *);
162 static void pppgetm(struct ppp_softc *sc);
163 static void pppdumpb(u_char *b, int l);
164 static void ppplogchar(struct ppp_softc *, int);
165 static void pppdumpframe(struct ppp_softc *sc, struct mbuf* m, int xmit);
166
167 /*
168 * Some useful mbuf macros not in mbuf.h.
169 */
170 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
171
172 #define M_DATASTART(m) \
173 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
174 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
175
176 #define M_DATASIZE(m) \
177 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
178 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
179
180 /*
181 * Does c need to be escaped?
182 */
183 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
184
185 /*
186 * Procedures for using an async tty interface for PPP.
187 */
188
189 /* This is a NetBSD-1.0 or later kernel. */
190 #define CCOUNT(q) ((q)->c_cc)
191
192 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
193 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
194
195 /*
196 * Line specific open routine for async tty devices.
197 * Attach the given tty to the first available ppp unit.
198 * Called from device open routine or ttioctl.
199 */
200 /* ARGSUSED */
201 static int
202 pppopen(dev_t dev, struct tty *tp)
203 {
204 struct lwp *l = curlwp; /* XXX */
205 struct ppp_softc *sc;
206 int error, s;
207
208 error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_PPP,
209 KAUTH_REQ_NETWORK_INTERFACE_PPP_ADD, NULL, NULL, NULL);
210 if (error)
211 return (error);
212
213 s = spltty();
214
215 if (tp->t_linesw == &ppp_disc) {
216 sc = (struct ppp_softc *) tp->t_sc;
217 if (sc != NULL && sc->sc_devp == (void *) tp) {
218 splx(s);
219 return (0);
220 }
221 }
222
223 if ((sc = pppalloc(l->l_proc->p_pid)) == NULL) {
224 splx(s);
225 return ENXIO;
226 }
227
228 if (sc->sc_relinq)
229 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
230
231 /* Switch DLT to PPP-over-serial. */
232 bpf_change_type(&sc->sc_if, DLT_PPP_SERIAL, PPP_HDRLEN);
233
234 sc->sc_ilen = 0;
235 sc->sc_m = NULL;
236 memset(sc->sc_asyncmap, 0, sizeof(sc->sc_asyncmap));
237 sc->sc_asyncmap[0] = 0xffffffff;
238 sc->sc_asyncmap[3] = 0x60000000;
239 sc->sc_rasyncmap = 0;
240 sc->sc_devp = (void *) tp;
241 sc->sc_start = pppasyncstart;
242 sc->sc_ctlp = pppasyncctlp;
243 sc->sc_relinq = pppasyncrelinq;
244 sc->sc_outm = NULL;
245 pppgetm(sc);
246 sc->sc_if.if_flags |= IFF_RUNNING;
247 sc->sc_if.if_baudrate = tp->t_ospeed;
248
249 tp->t_sc = (void *) sc;
250 mutex_spin_enter(&tty_lock);
251 ttyflush(tp, FREAD | FWRITE);
252 mutex_spin_exit(&tty_lock);
253
254 splx(s);
255 return (0);
256 }
257
258 /*
259 * Line specific close routine, called from device close routine
260 * and from ttioctl.
261 * Detach the tty from the ppp unit.
262 * Mimics part of ttyclose().
263 */
264 static int
265 pppclose(struct tty *tp, int flag)
266 {
267 struct ppp_softc *sc;
268 int s;
269
270 s = spltty();
271 mutex_spin_enter(&tty_lock);
272 ttyflush(tp, FREAD|FWRITE);
273 mutex_spin_exit(&tty_lock); /* XXX */
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 /* Change DLT to back none. */
297 bpf_change_type(&sc->sc_if, DLT_NULL, 0);
298
299 s = spltty();
300 if (sc->sc_outm) {
301 m_freem(sc->sc_outm);
302 sc->sc_outm = NULL;
303 }
304 if (sc->sc_m) {
305 m_freem(sc->sc_m);
306 sc->sc_m = NULL;
307 }
308 if (sc->sc_flags & SC_TIMEOUT) {
309 callout_stop(&sc->sc_timo_ch);
310 sc->sc_flags &= ~SC_TIMEOUT;
311 }
312 splx(s);
313 }
314
315 /*
316 * Line specific (tty) read routine.
317 */
318 static int
319 pppread(struct tty *tp, struct uio *uio, int flag)
320 {
321 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
322 struct mbuf *m, *m0;
323 int error = 0;
324
325 if (sc == NULL)
326 return 0;
327 /*
328 * Loop waiting for input, checking that nothing disasterous
329 * happens in the meantime.
330 */
331 mutex_spin_enter(&tty_lock);
332 for (;;) {
333 if (tp != (struct tty *) sc->sc_devp ||
334 tp->t_linesw != &ppp_disc) {
335 mutex_spin_exit(&tty_lock);
336 return 0;
337 }
338 if (sc->sc_inq.ifq_head != NULL)
339 break;
340 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
341 && (tp->t_state & TS_ISOPEN)) {
342 mutex_spin_exit(&tty_lock);
343 return 0; /* end of file */
344 }
345 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
346 mutex_spin_exit(&tty_lock);
347 return (EWOULDBLOCK);
348 }
349 error = ttysleep(tp, &tp->t_rawcv, true, 0);
350 if (error) {
351 mutex_spin_exit(&tty_lock);
352 return error;
353 }
354 }
355
356 /* Pull place-holder byte out of canonical queue */
357 getc(&tp->t_canq);
358
359 /* Get the packet from the input queue */
360 IF_DEQUEUE(&sc->sc_inq, m0);
361 mutex_spin_exit(&tty_lock);
362
363 for (m = m0; m && uio->uio_resid; m = m->m_next)
364 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
365 break;
366 m_freem(m0);
367 return (error);
368 }
369
370 /*
371 * Line specific (tty) write routine.
372 */
373 static int
374 pppwrite(struct tty *tp, struct uio *uio, int flag)
375 {
376 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
377 struct mbuf *m, *m0;
378 struct sockaddr dst;
379 int len, error;
380
381 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
382 return 0; /* wrote 0 bytes */
383 if (tp->t_linesw != &ppp_disc)
384 return (EINVAL);
385 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
386 return EIO;
387 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
388 uio->uio_resid < PPP_HDRLEN)
389 return (EMSGSIZE);
390
391 MGETHDR(m0, M_WAIT, MT_DATA);
392 if (m0 == NULL)
393 return ENOBUFS;
394
395 m0->m_len = 0;
396 m0->m_pkthdr.len = uio->uio_resid;
397 m_reset_rcvif(m0);
398
399 if (uio->uio_resid >= MCLBYTES / 2)
400 MCLGET(m0, M_DONTWAIT);
401
402 for (m = m0; uio->uio_resid;) {
403 len = M_TRAILINGSPACE(m);
404 if (len > uio->uio_resid)
405 len = uio->uio_resid;
406 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
407 m_freem(m0);
408 return (error);
409 }
410 m->m_len = len;
411
412 if (uio->uio_resid == 0)
413 break;
414
415 MGET(m->m_next, M_WAIT, MT_DATA);
416 if (m->m_next == NULL) {
417 m_freem(m0);
418 return ENOBUFS;
419 }
420 m = m->m_next;
421 m->m_len = 0;
422 }
423 dst.sa_family = AF_UNSPEC;
424 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
425 m_adj(m0, PPP_HDRLEN);
426 return if_output_lock(&sc->sc_if, &sc->sc_if, m0, &dst, (struct rtentry *)0);
427 }
428
429 /*
430 * Line specific (tty) ioctl routine.
431 * This discipline requires that tty device drivers call
432 * the line specific l_ioctl routine from their ioctl routines.
433 */
434 /* ARGSUSED */
435 static int
436 ppptioctl(struct tty *tp, u_long cmd, void *data, int flag, struct lwp *l)
437 {
438 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
439 int error, s;
440
441 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
442 return (EPASSTHROUGH);
443
444 error = 0;
445 switch (cmd) {
446 case TIOCRCVFRAME:
447 ppprcvframe(sc,*((struct mbuf **)data));
448 break;
449
450 case PPPIOCSASYNCMAP:
451 if ((error = kauth_authorize_device_tty(l->l_cred,
452 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
453 break;
454 sc->sc_asyncmap[0] = *(u_int *)data;
455 break;
456
457 case PPPIOCGASYNCMAP:
458 *(u_int *)data = sc->sc_asyncmap[0];
459 break;
460
461 case PPPIOCSRASYNCMAP:
462 if ((error = kauth_authorize_device_tty(l->l_cred,
463 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
464 break;
465 sc->sc_rasyncmap = *(u_int *)data;
466 break;
467
468 case PPPIOCGRASYNCMAP:
469 *(u_int *)data = sc->sc_rasyncmap;
470 break;
471
472 case PPPIOCSXASYNCMAP:
473 if ((error = kauth_authorize_device_tty(l->l_cred,
474 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
475 break;
476 s = spltty();
477 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
478 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
479 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
480 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
481 splx(s);
482 break;
483
484 case PPPIOCGXASYNCMAP:
485 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
486 break;
487
488 default:
489 error = pppioctl(sc, cmd, data, flag, l);
490 if (error == 0 && cmd == PPPIOCSMRU)
491 pppgetm(sc);
492 }
493
494 return error;
495 }
496
497 /* receive a complete ppp frame from device in synchronous
498 * hdlc mode. caller gives up ownership of mbuf
499 */
500 static void
501 ppprcvframe(struct ppp_softc *sc, struct mbuf *m)
502 {
503 int len, s;
504 struct mbuf *n;
505 u_char hdr[4];
506 int hlen,count;
507
508 for (n=m,len=0;n != NULL;n = n->m_next)
509 len += n->m_len;
510 if (len==0) {
511 m_freem(m);
512 return;
513 }
514
515 /* extract PPP header from mbuf chain (1 to 4 bytes) */
516 for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) {
517 count = (sizeof(hdr)-hlen) < n->m_len ?
518 sizeof(hdr)-hlen : n->m_len;
519 bcopy(mtod(n,u_char*),&hdr[hlen],count);
520 hlen+=count;
521 }
522
523 s = spltty();
524
525 /* if AFCF compressed then prepend AFCF */
526 if (hdr[0] != PPP_ALLSTATIONS) {
527 if (sc->sc_flags & SC_REJ_COMP_AC) {
528 if (sc->sc_flags & SC_DEBUG)
529 printf(
530 "%s: garbage received: 0x%x (need 0xFF)\n",
531 sc->sc_if.if_xname, hdr[0]);
532 goto bail;
533 }
534 M_PREPEND(m,2,M_DONTWAIT);
535 if (m==NULL) {
536 splx(s);
537 return;
538 }
539 hdr[3] = hdr[1];
540 hdr[2] = hdr[0];
541 hdr[0] = PPP_ALLSTATIONS;
542 hdr[1] = PPP_UI;
543 len += 2;
544 }
545
546 /* if protocol field compressed, add MSB of protocol field = 0 */
547 if (hdr[2] & 1) {
548 /* a compressed protocol */
549 M_PREPEND(m,1,M_DONTWAIT);
550 if (m==NULL) {
551 splx(s);
552 return;
553 }
554 hdr[3] = hdr[2];
555 hdr[2] = 0;
556 len++;
557 }
558
559 /* valid LSB of protocol field has bit0 set */
560 if (!(hdr[3] & 1)) {
561 if (sc->sc_flags & SC_DEBUG)
562 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
563 (hdr[2] << 8) + hdr[3]);
564 goto bail;
565 }
566
567 /* packet beyond configured mru? */
568 if (len > sc->sc_mru + PPP_HDRLEN) {
569 if (sc->sc_flags & SC_DEBUG)
570 printf("%s: packet too big\n", sc->sc_if.if_xname);
571 goto bail;
572 }
573
574 /* add expanded 4 byte header to mbuf chain */
575 for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) {
576 count = (sizeof(hdr)-hlen) < n->m_len ?
577 sizeof(hdr)-hlen : n->m_len;
578 bcopy(&hdr[hlen],mtod(n,u_char*),count);
579 hlen+=count;
580 }
581
582 /* if_ppp.c requires the PPP header and IP header */
583 /* to be contiguous */
584 count = len < MHLEN ? len : MHLEN;
585 if (m->m_len < count) {
586 m = m_pullup(m,count);
587 if (m==NULL)
588 goto bail;
589 }
590
591 sc->sc_stats.ppp_ibytes += len;
592
593 if (sc->sc_flags & SC_LOG_RAWIN)
594 pppdumpframe(sc,m,0);
595
596 ppppktin(sc, m, 0);
597 splx(s);
598 return;
599 bail:
600 m_freem(m);
601 splx(s);
602 }
603
604 /*
605 * FCS lookup table as calculated by genfcstab.
606 */
607 static const uint16_t fcstab[256] = {
608 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
609 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
610 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
611 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
612 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
613 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
614 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
615 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
616 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
617 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
618 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
619 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
620 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
621 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
622 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
623 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
624 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
625 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
626 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
627 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
628 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
629 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
630 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
631 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
632 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
633 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
634 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
635 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
636 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
637 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
638 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
639 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
640 };
641
642 /*
643 * Calculate a new FCS given the current FCS and the new data.
644 */
645 static uint16_t
646 pppfcs(uint16_t fcs, const uint8_t *cp, int len)
647 {
648 while (len--)
649 fcs = PPP_FCS(fcs, *cp++);
650 return (fcs);
651 }
652
653 /* This gets called at splsoftnet from pppasyncstart at various times
654 * when there is data ready to be sent.
655 */
656 static void
657 pppsyncstart(struct ppp_softc *sc)
658 {
659 struct tty *tp = (struct tty *) sc->sc_devp;
660 struct mbuf *m, *n;
661 const struct cdevsw *cdev;
662 int len;
663
664 for(m = sc->sc_outm;;) {
665 if (m == NULL) {
666 m = ppp_dequeue(sc); /* get new packet */
667 if (m == NULL)
668 break; /* no more packets */
669 if (sc->sc_flags & SC_DEBUG)
670 pppdumpframe(sc,m,1);
671 }
672 for(n=m,len=0;n!=NULL;n=n->m_next)
673 len += n->m_len;
674
675 /* call device driver IOCTL to transmit a frame */
676 cdev = cdevsw_lookup_acquire(tp->t_dev);
677 if (cdev == NULL ||
678 (*cdev->d_ioctl)(tp->t_dev, TIOCXMTFRAME, (void *)&m,
679 0, 0)) {
680 /* busy or error, set as current packet */
681 sc->sc_outm = m;
682 break;
683 }
684 sc->sc_outm = m = NULL;
685 sc->sc_stats.ppp_obytes += len;
686 if (cdev != NULL)
687 cdevsw_release(cdev);
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 m = m2 = m_free(m);
838 if (m == NULL) {
839 /* Finished a packet */
840 break;
841 }
842 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, uint8_t *), m->m_len);
843 }
844
845 /*
846 * If m == NULL, we have finished a packet.
847 * If m != NULL, we've either done as much work this time
848 * as we need to, or else we've filled up the output queue.
849 */
850 sc->sc_outm = m;
851 if (m)
852 break;
853 }
854
855 /* Call pppstart to start output again if necessary. */
856 pppstart(tp);
857
858 /*
859 * This timeout is needed for operation on a pseudo-tty,
860 * because the pty code doesn't call pppstart after it has
861 * drained the t_outq.
862 */
863 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
864 callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
865 sc->sc_flags |= SC_TIMEOUT;
866 }
867
868 mutex_spin_exit(&tty_lock);
869 }
870
871 /*
872 * This gets called when a received packet is placed on
873 * the inq, at splsoftnet.
874 */
875 static void
876 pppasyncctlp(struct ppp_softc *sc)
877 {
878 struct tty *tp;
879
880 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
881 mutex_spin_enter(&tty_lock);
882 tp = (struct tty *) sc->sc_devp;
883 putc(0, &tp->t_canq);
884 ttwakeup(tp);
885 mutex_spin_exit(&tty_lock);
886 }
887
888 /*
889 * Start output on async tty interface. If the transmit queue
890 * has drained sufficiently, arrange for pppasyncstart to be
891 * called later at splsoftnet.
892 * Called at spltty or higher.
893 */
894 static int
895 pppstart(struct tty *tp)
896 {
897 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
898
899 /*
900 * If there is stuff in the output queue, send it now.
901 * We are being called in lieu of ttstart and must do what it would.
902 */
903 if (tp->t_oproc != NULL)
904 (*tp->t_oproc)(tp);
905
906 /*
907 * If the transmit queue has drained and the tty has not hung up
908 * or been disconnected from the ppp unit, then tell if_ppp.c that
909 * we need more output.
910 */
911 if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
912 && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
913 return 0;
914 #ifdef ALTQ
915 /*
916 * if ALTQ is enabled, don't invoke NETISR_PPP.
917 * pppintr() could loop without doing anything useful
918 * under rate-limiting.
919 */
920 if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd))
921 return 0;
922 #endif
923 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
924 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
925 ppp_restart(sc);
926 }
927
928 return 0;
929 }
930
931 /*
932 * Timeout routine - try to start some more output.
933 */
934 static void
935 ppp_timeout(void *x)
936 {
937 struct ppp_softc *sc = (struct ppp_softc *) x;
938 struct tty *tp = (struct tty *) sc->sc_devp;
939
940 mutex_spin_enter(&tty_lock);
941 sc->sc_flags &= ~SC_TIMEOUT;
942 pppstart(tp);
943 mutex_spin_exit(&tty_lock);
944 }
945
946 /*
947 * Allocate enough mbuf to handle current MRU.
948 */
949 static void
950 pppgetm(struct ppp_softc *sc)
951 {
952 struct mbuf *m, **mp;
953 int len;
954
955 mp = &sc->sc_m;
956 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
957 if ((m = *mp) == NULL) {
958 MGETHDR(m, M_DONTWAIT, MT_DATA);
959 if (m == NULL)
960 break;
961 *mp = m;
962 MCLGET(m, M_DONTWAIT);
963 }
964 len -= M_DATASIZE(m);
965 mp = &m->m_next;
966 }
967 }
968
969 /*
970 * tty interface receiver interrupt.
971 */
972 static const unsigned paritytab[8] = {
973 0x96696996, 0x69969669, 0x69969669, 0x96696996,
974 0x69969669, 0x96696996, 0x96696996, 0x69969669
975 };
976
977 static int
978 pppinput(int c, struct tty *tp)
979 {
980 struct ppp_softc *sc;
981 struct mbuf *m;
982 int ilen, s;
983 int result;
984
985 sc = (struct ppp_softc *) tp->t_sc;
986 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
987 return 0;
988
989 ++tk_nin;
990 ++sc->sc_stats.ppp_ibytes;
991
992 if (c & TTY_FE) {
993 /* framing error or overrun on this char - abort packet */
994 if (sc->sc_flags & SC_DEBUG)
995 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
996 goto flush;
997 }
998
999 c &= 0xff;
1000
1001 /*
1002 * Handle software flow control of output.
1003 */
1004 result = tty_try_xonxoff(tp, c);
1005 if (result == 0) {
1006 /* Character was recognized and consumed. */
1007 return 0;
1008 }
1009 /* Character wasn't consumed, continue processing it. */
1010
1011 s = spltty();
1012 if (c & 0x80)
1013 sc->sc_flags |= SC_RCV_B7_1;
1014 else
1015 sc->sc_flags |= SC_RCV_B7_0;
1016 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
1017 sc->sc_flags |= SC_RCV_ODDP;
1018 else
1019 sc->sc_flags |= SC_RCV_EVNP;
1020 splx(s);
1021
1022 ppplogchar(sc, c);
1023
1024 if (c == PPP_FLAG) {
1025 ilen = sc->sc_ilen;
1026 sc->sc_ilen = 0;
1027
1028 if ((sc->sc_flags & SC_LOG_RAWIN) && sc->sc_rawin.count > 0)
1029 ppplogchar(sc, -1);
1030
1031 /*
1032 * If SC_ESCAPED is set, then we've seen the packet
1033 * abort sequence "}~".
1034 */
1035 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1036 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
1037 s = spltty();
1038 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1039 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1040 if (sc->sc_flags & SC_DEBUG)
1041 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
1042 sc->sc_fcs);
1043 sc->sc_if.if_ierrors++;
1044 sc->sc_stats.ppp_ierrors++;
1045 } else
1046 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1047 splx(s);
1048 return 0;
1049 }
1050
1051 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1052 if (ilen) {
1053 if (sc->sc_flags & SC_DEBUG)
1054 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
1055 s = spltty();
1056 sc->sc_if.if_ierrors++;
1057 sc->sc_stats.ppp_ierrors++;
1058 sc->sc_flags |= SC_PKTLOST;
1059 splx(s);
1060 }
1061 return 0;
1062 }
1063
1064 /*
1065 * Remove FCS trailer. Somewhat painful...
1066 */
1067 ilen -= 2;
1068 if (--sc->sc_mc->m_len == 0) {
1069 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1070 ;
1071 sc->sc_mc = m;
1072 }
1073 sc->sc_mc->m_len--;
1074
1075 /* excise this mbuf chain */
1076 m = sc->sc_m;
1077 sc->sc_m = sc->sc_mc->m_next;
1078 sc->sc_mc->m_next = NULL;
1079
1080 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1081 if (sc->sc_flags & SC_PKTLOST) {
1082 s = spltty();
1083 sc->sc_flags &= ~SC_PKTLOST;
1084 splx(s);
1085 }
1086
1087 pppgetm(sc);
1088 return 0;
1089 }
1090
1091 if (sc->sc_flags & SC_FLUSH) {
1092 if (sc->sc_flags & SC_LOG_FLUSH)
1093 ppplogchar(sc, c);
1094 return 0;
1095 }
1096
1097 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1098 return 0;
1099
1100 s = spltty();
1101 if (sc->sc_flags & SC_ESCAPED) {
1102 sc->sc_flags &= ~SC_ESCAPED;
1103 c ^= PPP_TRANS;
1104 } else if (c == PPP_ESCAPE) {
1105 sc->sc_flags |= SC_ESCAPED;
1106 splx(s);
1107 return 0;
1108 }
1109 splx(s);
1110
1111 /*
1112 * Initialize buffer on first octet received.
1113 * First octet could be address or protocol (when compressing
1114 * address/control).
1115 * Second octet is control.
1116 * Third octet is first or second (when compressing protocol)
1117 * octet of protocol.
1118 * Fourth octet is second octet of protocol.
1119 */
1120 if (sc->sc_ilen == 0) {
1121 /* reset the first input mbuf */
1122 if (sc->sc_m == NULL) {
1123 pppgetm(sc);
1124 if (sc->sc_m == NULL) {
1125 if (sc->sc_flags & SC_DEBUG)
1126 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
1127 goto flush;
1128 }
1129 }
1130 m = sc->sc_m;
1131 m->m_len = 0;
1132 m->m_data = M_DATASTART(sc->sc_m);
1133 sc->sc_mc = m;
1134 sc->sc_mp = mtod(m, char *);
1135 sc->sc_fcs = PPP_INITFCS;
1136 if (c != PPP_ALLSTATIONS) {
1137 if (sc->sc_flags & SC_REJ_COMP_AC) {
1138 if (sc->sc_flags & SC_DEBUG)
1139 printf("%s: garbage received: 0x%x (need 0xFF)\n",
1140 sc->sc_if.if_xname, c);
1141 goto flush;
1142 }
1143 *sc->sc_mp++ = PPP_ALLSTATIONS;
1144 *sc->sc_mp++ = PPP_UI;
1145 sc->sc_ilen += 2;
1146 m->m_len += 2;
1147 }
1148 }
1149 if (sc->sc_ilen == 1 && c != PPP_UI) {
1150 if (sc->sc_flags & SC_DEBUG)
1151 printf("%s: missing UI (0x3), got 0x%x\n",
1152 sc->sc_if.if_xname, c);
1153 goto flush;
1154 }
1155 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1156 /* a compressed protocol */
1157 *sc->sc_mp++ = 0;
1158 sc->sc_ilen++;
1159 sc->sc_mc->m_len++;
1160 }
1161 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1162 if (sc->sc_flags & SC_DEBUG)
1163 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1164 (sc->sc_mp[-1] << 8) + c);
1165 goto flush;
1166 }
1167
1168 /* packet beyond configured mru? */
1169 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1170 if (sc->sc_flags & SC_DEBUG)
1171 printf("%s: packet too big\n", sc->sc_if.if_xname);
1172 goto flush;
1173 }
1174
1175 /* is this mbuf full? */
1176 m = sc->sc_mc;
1177 if (M_TRAILINGSPACE(m) <= 0) {
1178 if (m->m_next == NULL) {
1179 pppgetm(sc);
1180 if (m->m_next == NULL) {
1181 if (sc->sc_flags & SC_DEBUG)
1182 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1183 goto flush;
1184 }
1185 }
1186 sc->sc_mc = m = m->m_next;
1187 m->m_len = 0;
1188 m->m_data = M_DATASTART(m);
1189 sc->sc_mp = mtod(m, char *);
1190 }
1191
1192 ++m->m_len;
1193 *sc->sc_mp++ = c;
1194 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1195 return 0;
1196
1197 flush:
1198 if (!(sc->sc_flags & SC_FLUSH)) {
1199 s = spltty();
1200 sc->sc_if.if_ierrors++;
1201 sc->sc_stats.ppp_ierrors++;
1202 sc->sc_flags |= SC_FLUSH;
1203 splx(s);
1204 if (sc->sc_flags & SC_LOG_FLUSH)
1205 ppplogchar(sc, c);
1206 }
1207 return 0;
1208 }
1209
1210 #define MAX_DUMP_BYTES 128
1211
1212 static void
1213 ppplogchar(struct ppp_softc *sc, int c)
1214 {
1215 if (c >= 0) {
1216 sc->sc_rawin.buf[sc->sc_rawin_start++] = c;
1217 if (sc->sc_rawin.count < sizeof(sc->sc_rawin.buf))
1218 sc->sc_rawin.count++;
1219 }
1220 if (sc->sc_rawin_start >= sizeof(sc->sc_rawin.buf)
1221 || (c < 0 && sc->sc_rawin_start > 0)) {
1222 if (sc->sc_flags & (SC_LOG_FLUSH|SC_LOG_RAWIN)) {
1223 printf("%s input: ", sc->sc_if.if_xname);
1224 pppdumpb(sc->sc_rawin.buf, sc->sc_rawin_start);
1225 }
1226 if (c < 0)
1227 sc->sc_rawin.count = 0;
1228 sc->sc_rawin_start = 0;
1229 }
1230 }
1231
1232 static void
1233 pppdumpb(u_char *b, int l)
1234 {
1235 char bf[3*MAX_DUMP_BYTES+4];
1236 char *bp = bf;
1237
1238 while (l--) {
1239 if (bp >= bf + sizeof(bf) - 3) {
1240 *bp++ = '>';
1241 break;
1242 }
1243 *bp++ = hexdigits[*b >> 4]; /* convert byte to ascii hex */
1244 *bp++ = hexdigits[*b++ & 0xf];
1245 *bp++ = ' ';
1246 }
1247
1248 *bp = 0;
1249 printf("%s\n", bf);
1250 }
1251
1252 static void
1253 pppdumpframe(struct ppp_softc *sc, struct mbuf *m, int xmit)
1254 {
1255 int i,lcount,copycount,count;
1256 char lbuf[16];
1257 char *data;
1258
1259 if (m == NULL)
1260 return;
1261
1262 for(count=m->m_len,data=mtod(m,char*);m != NULL;) {
1263 /* build a line of output */
1264 for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) {
1265 if (!count) {
1266 m = m->m_next;
1267 if (m == NULL)
1268 break;
1269 count = m->m_len;
1270 data = mtod(m,char*);
1271 }
1272 copycount = (count > sizeof(lbuf)-lcount) ?
1273 sizeof(lbuf)-lcount : count;
1274 bcopy(data,&lbuf[lcount],copycount);
1275 data += copycount;
1276 count -= copycount;
1277 }
1278
1279 /* output line (hex 1st, then ascii) */
1280 printf("%s %s:", sc->sc_if.if_xname,
1281 xmit ? "output" : "input ");
1282 for(i=0;i<lcount;i++)
1283 printf("%02x ",(u_char)lbuf[i]);
1284 for(;i<sizeof(lbuf);i++)
1285 printf(" ");
1286 for(i=0;i<lcount;i++)
1287 printf("%c",(lbuf[i] >= 040 &&
1288 lbuf[i] <= 0176) ? lbuf[i] : '.');
1289 printf("\n");
1290 }
1291 }
1292