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