1 /* $ID: ppp_tty.c,v 1.4 1994/12/13 03:42:17 paulus Exp paulus $ */
4 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
7 * Copyright (c) 1989 Carnegie Mellon University.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by Carnegie Mellon University. The name of the
16 * University may not be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * Carnegie Mellon University
25 * Pittsburgh, PA 15213
30 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
32 * Copyright (c) 1987 Regents of the University of California.
33 * All rights reserved.
35 * Redistribution and use in source and binary forms are permitted
36 * provided that the above copyright notice and this paragraph are
37 * duplicated in all such forms and that any documentation,
38 * advertising materials, and other materials related to such
39 * distribution and use acknowledge that the software was developed
40 * by the University of California, Berkeley. The name of the
41 * University may not be used to endorse or promote products derived
42 * from this software without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
47 * Serial Line interface
50 * Center for Seismic Studies
51 * 1300 N 17th Street, Suite 1450
52 * Arlington, Virginia 22209
57 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
58 * Converted to 4.3BSD Beta by Chris Torek.
59 * Other changes made at Berkeley, based in part on code by Kirk Smith.
61 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
62 * Added VJ tcp header compression; more unified ioctls
64 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
65 * Cleaned up a lot of the mbuf-related code to fix bugs that
66 * caused system crashes and packet corruption. Changed pppstart
67 * so that it doesn't just give up with a collision if the whole
68 * packet doesn't fit in the output ring buffer.
70 * Added priority queueing for interactive IP packets, following
71 * the model of if_sl.c, plus hooks for bpf.
72 * Paul Mackerras (paulus@cs.anu.edu.au).
74 * Rewritten for NextStep's funky kernel functions, I/O threads,
75 * and netbufs (instead of real mbufs). Also, ifnets don't install
76 * into the kernel under NS as they do under BSD. We have tried to
77 * make the code remain as similar to the NetBSD version without
78 * incurring too much hassle. This code is the merge of
79 * Philip Prindeville's <philipp@res.enst.fr>/Pete French's <pete@ohm.york.ac.uk>
80 * and Stephen Perkins' <perkins@cps.msu.edu> independent ports.
84 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
85 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:59 cgd Exp */
87 /* #include "ppp.h" */
91 #define KERNEL_FEATURES 1
94 #include <sys/param.h>
98 #include <sys/socket.h>
99 #include <sys/ioctl.h>
100 #include <sys/file.h>
102 #include <sys/conf.h>
105 #include <sys/errno.h>
106 #include <machine/param.h>
109 #include <kernserv/prototypes.h>
110 /* NeXT broke spl.h in 3.2/m68k. Thanks EPS! */
115 #include <driverkit/generalFuncs.h>
116 #import <kernserv/machine/spl.h>
119 #include <kernserv/kern_server_types.h>
122 #include <net/route.h>
125 #include <netinet/in.h>
126 #include <netinet/in_systm.h>
127 #include <netinet/ip.h>
130 #include <net/ppp_defs.h>
132 #include <net/vjcompress.h>
134 #include <net/if_ppp.h>
135 #include "if_pppvar.h"
139 int pppopen __P((dev_t dev, struct tty *tp));
140 void pppclose __P((struct tty *tp));
141 int pppread __P((struct tty *tp, struct uio *uio));
142 int pppwrite __P((struct tty *tp, struct uio *uio));
143 int ppptioctl __P((struct tty *tp, int cmd, void *data, int flag));
144 void pppinput __P((int c, struct tty *tp));
145 void pppstart __P((struct tty *tp));
147 netbuf_t pppgetbuf __P((netif_t));
148 int pppoutput __P((netif_t ifp, netbuf_t m, void *arg));
149 void pppintr __P((void *));
151 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
152 static void pppasyncstart __P((struct ppp_softc *));
153 static void pppasyncctlp __P((struct ppp_softc *));
154 static void pppasyncrelinq __P((struct ppp_softc *));
155 static int ppp_timeout __P((void *));
156 void pppgetm __P((struct ppp_softc *sc));
157 static void pppdumpb __P((u_char *b, int l));
158 void ppplogchar __P((struct ppp_softc *, int));
160 extern kern_server_t instance;
164 static int in_error_pkt_count = 0; /* Number of packets received */
165 static int in_error_limit = -1; /* Insert error at this limit */
166 static int in_error_max_sep = 50; /* Max range of random number */
168 static int out_error_pkt_count = 0; /* Number of packets sent */
169 static int out_error_limit = -1; /* Insert error at this limit */
170 static int out_error_max_sep = 50; /* Max range of random number */
172 #endif /* ADD_ERRORS */
176 * Does c need to be escaped?
178 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
180 #define CCOUNT(q) ((q)->c_cc)
182 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
184 #include "linedisc.h"
187 extern int ttymodem(struct tty*, int);
188 extern int ttselect(struct tty *tp, int rw);
192 pppgetinbuf(netif_t ifp)
194 register struct ppp_softc *sc = &ppp_softc[if_unit(ifp)];
196 int len = MAX(sc->sc_mru, PPP_MTU) + sizeof (struct ifnet *) +
200 PPP_HDRLEN + PPP_FCSLEN;
201 nb = ppp_nb_alloc(len);
205 ppp_nb_shrink_top(nb, VJ_HDRLEN + PPP_HDRLEN);
207 ppp_nb_shrink_top(nb, PPP_HDRLEN);
215 * I was a bit worried about reentrancy here. +++SJP
219 pppfillfreeq(void *arg)
221 struct ppp_softc *sc = (struct ppp_softc *)arg;
223 volatile static int in = 0;
229 while(!nbq_high(&sc->sc_freeq)) {
230 nb = pppgetinbuf(sc->sc_if);
234 * we no longer reset the length to 0 and then advance the
235 * packet length bit by bit; instead we write into it whenever
236 * we want, and at the end resize the packet before handing-off.
238 nb_shrink_bot(nb, nb_size(nb));
240 nbq_enqueue(&sc->sc_freeq, nb);
247 * Line specific open routine for async tty devices.
248 * Attach the given tty to the first available ppp unit.
254 register struct tty *tp;
256 struct proc *p = curproc; /* XXX */
257 register struct ppp_softc *sc;
263 if (tp->t_line == PPPDISC) {
264 sc = (struct ppp_softc *) tp->t_sc;
265 if (sc != NULL && sc->sc_devp == (void *) tp)
269 if ((sc = pppalloc(p->p_pid)) == NULL)
273 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
275 pppfillfreeq((void *) sc); /* fill the free queue - we may block */
280 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
281 sc->sc_asyncmap[0] = 0xffffffff;
282 sc->sc_asyncmap[3] = 0x60000000;
283 sc->sc_rasyncmap = 0;
284 sc->sc_devp = (void *) tp;
285 sc->sc_start = pppasyncstart;
286 sc->sc_ctlp = pppasyncctlp;
287 sc->sc_relinq = pppasyncrelinq;
290 if_flags_set(sc->sc_if, if_flags(sc->sc_if) | IFF_RUNNING);
292 tp->t_sc = (caddr_t) sc;
293 ttyflush(tp, FREAD | FWRITE);
300 * Line specific close routine.
301 * Detach the tty from the ppp unit.
302 * Mimics part of ttyclose().
308 register struct ppp_softc *sc;
312 s = splimp(); /* paranoid; splnet probably ok */
314 sc = (struct ppp_softc *) tp->t_sc;
317 if (tp == (struct tty *) sc->sc_devp) {
327 * Relinquish the interface unit to another device.
331 struct ppp_softc *sc;
337 nb_free(sc->sc_outm);
344 if (sc->sc_flags & SC_TIMEOUT) {
345 ns_untimeout(ppp_timeout, (void *) sc);
346 sc->sc_flags &= ~SC_TIMEOUT;
352 * Line specific (tty) read routine.
356 register struct tty *tp;
359 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
364 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
365 return 0; /* end of file */
366 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
369 while (nbq_empty(&sc->sc_inq) && tp->t_line == PPPDISC) {
370 if (tp->t_state & (TS_ASYNC | TS_NBIO)) {
372 return (EWOULDBLOCK);
375 /* NetBSD version... */
376 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
382 sleep((caddr_t)&tp->t_rawq, TTIPRI);
385 if (tp->t_line != PPPDISC) {
390 /* Pull place-holder byte out of canonical queue */
393 /* Get the packet from the input queue */
394 m = nbq_dequeue(&sc->sc_inq);
397 if (sc->sc_flags & SC_DEBUG)
398 IOLogDbg("Read didn't get a buffer at %s %d\n", __FILE__, __LINE__);
401 error = uiomove(nb_map(m), nb_size(m), UIO_READ, uio);
407 * Line specific (tty) write routine.
411 register struct tty *tp;
414 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
419 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
420 return 0; /* wrote 0 bytes */
421 if (tp->t_line != PPPDISC)
423 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
425 if (uio->uio_resid > if_mtu(sc->sc_if) + PPP_HDRLEN ||
426 uio->uio_resid < PPP_HDRLEN)
428 m = pppgetbuf(sc->sc_if);
430 if (sc->sc_flags & SC_DEBUG)
431 IOLogDbg("No buffers available for user level write()\n");
434 ppp_nb_grow_top(m, PPP_HDRLEN);
435 len = uio->uio_resid;
436 if (error = uiomove(nb_map(m), nb_size(m), UIO_WRITE, uio)) {
440 nb_shrink_bot(m, nb_size(m) - len);
441 dst.sa_family = AF_UNSPEC;
442 bcopy(mtod(m, u_char *), dst.sa_data, PPP_HDRLEN);
443 ppp_nb_shrink_top(m, PPP_HDRLEN);
444 return (pppoutput(sc->sc_if, m, &dst));
448 * Line specific (tty) ioctl routine.
449 * This discipline requires that tty device drivers call
450 * the line specific l_ioctl routine from their ioctl routines.
454 ppptioctl(tp, cmd, data, flag)
459 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
462 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
467 case PPPIOCSASYNCMAP:
471 IOLogDbg("ppp%d: set async map to 0x%08x\n", if_unit(sc->sc_if),
474 sc->sc_asyncmap[0] = *(u_int *)data;
477 case PPPIOCGASYNCMAP:
478 *(u_int *)data = sc->sc_asyncmap[0];
480 IOLogDbg("ppp%d: asyncmap gets 0x%x\n", if_unit(sc->sc_if), *(u_int *)data);
484 case PPPIOCSRASYNCMAP:
487 sc->sc_rasyncmap = *(u_int *)data;
489 IOLogDbg("ppp%d: setting rasyncmap 0x%x\n", if_unit(sc->sc_if), sc->sc_rasyncmap);
493 case PPPIOCGRASYNCMAP:
494 *(u_int *)data = sc->sc_rasyncmap;
496 IOLogDbg("ppp%d: rasyncmap gets 0x%x\n", if_unit(sc->sc_if), *(u_int *)data);
500 case PPPIOCSXASYNCMAP:
504 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
505 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
506 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
507 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
511 case PPPIOCGXASYNCMAP:
512 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
514 IOLogDbg("ppp%d: xasyncmap gets 0x%x/0x%x/0x%x/0x%x\n", if_unit(sc->sc_if), ((u_int *)data)[0], ((u_int *)data)[1], ((u_int *)data)[2], ((u_int *)data)[3]);
519 error = pppioctl(sc, cmd, data, flag);
520 if (error == 0 && cmd == PPPIOCSMRU)
525 if (! error && (cmd & IOC_OUT)) {
526 struct uthread *_u = uthread_from_thread(current_thread());
528 /* third arg is destination in ioctl() call... */
529 copyout(data, (caddr_t) _u->uu_arg[2], (cmd >> 16) & IOCPARM_MASK);
537 * FCS lookup table as calculated by genfcstab.
539 static const u_int16_t fcstab[256] = {
540 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
541 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
542 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
543 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
544 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
545 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
546 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
547 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
548 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
549 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
550 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
551 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
552 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
553 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
554 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
555 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
556 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
557 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
558 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
559 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
560 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
561 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
562 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
563 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
564 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
565 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
566 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
567 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
568 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
569 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
570 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
571 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
575 * Calculate a new FCS given the current FCS and the new data.
579 register u_int16_t fcs;
584 fcs = PPP_FCS(fcs, *cp++);
589 * This gets called from pppoutput when a new packet is
594 register struct ppp_softc *sc;
596 register struct tty *tp = (struct tty *) sc->sc_devp;
605 * This gets called when a received packet is placed on
610 struct ppp_softc *sc;
614 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
615 tp = (struct tty *) sc->sc_devp;
616 putc(0, &tp->t_canq);
621 * Start output on async tty interface. Get another datagram
622 * to send from the interface queue and start sending it.
626 register struct tty *tp;
628 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
631 register u_char *start, *stop, *cp;
632 int n, ndone, done, idle;
634 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0
635 || sc == NULL || tp != (struct tty *) sc->sc_devp) {
636 if (tp->t_oproc != NULL)
643 while (CCOUNT(&tp->t_outq) == 0) {
645 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
648 * See if we have an existing packet partly sent.
649 * If not, get a new packet and start sending it.
654 * Get another packet to be sent.
663 * The extra PPP_FLAG will start up a new packet, and thus
664 * will flush any accumulated garbage. We do this whenever
665 * the line may have been idle for some time.
667 if (CCOUNT(&tp->t_outq) == 0) {
669 (void) putc(PPP_FLAG, &tp->t_outq);
672 /* Calculate the FCS for the first netbuf's worth. */
673 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), nb_size(m));
674 sc->sc_outfcs ^= 0xffff;
678 * This section will adds random errors to
682 if (out_error_limit == -1) /* Initial time through */
684 out_error_limit = rand() % out_error_max_sep;
685 IOLog("Introducing outgoing random error after %d more packets\n",
689 if (out_error_pkt_count >= out_error_limit)
691 sc->sc_outfcs ^= 0x99; /* Munge with some noise */
692 out_error_pkt_count = 0;
693 out_error_limit = rand() % out_error_max_sep;
694 IOLog("Introducing outgoing random error after %d more packets\n",
698 ++out_error_pkt_count;
701 #endif /* ADD_ERRORS */
703 cp = mtod(m, u_char *) + nb_size(m);
704 nb_grow_bot(m, PPP_FCSLEN);
705 *cp++ = sc->sc_outfcs & 0xFF;
706 *cp++ = (sc->sc_outfcs >> 8) & 0xFF;
709 start = mtod(m, u_char *);
714 * Find out how many bytes in the string we can
715 * handle without doing something special.
717 for (cp = start; cp < stop; cp++)
722 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
723 ndone = n - b_to_q(start, n, &tp->t_outq);
726 sc->sc_bytessent += ndone;
729 break; /* packet doesn't fit */
733 * If there are characters left in the netbuf,
734 * the first one must be special..
735 * Put it out in a different form.
738 if (putc(PPP_ESCAPE, &tp->t_outq))
740 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
741 (void) unputc(&tp->t_outq);
744 sc->sc_bytessent += 2;
750 * If we didn't empty this netbuf, remember where we're up to.
755 /* remember where we got to */
756 ppp_nb_shrink_top(m, start - mtod(m, u_char *));
757 break; /* can't do any more at the moment */
761 * Output trailing PPP flag and finish packet.
762 * We make the length zero in case the flag
763 * cannot be output immediately.
765 ppp_nb_shrink_top(m, nb_size(m));
766 if (putc(PPP_FLAG, &tp->t_outq))
770 /* Finished with this netbuf; free it and move on. */
773 incr_cnt(sc->sc_if, if_opackets);
779 * If there is stuff in the output queue, send it now.
780 * We are being called in lieu of ttstart and must do what it would.
782 if (tp->t_oproc != NULL)
786 * This timeout is needed for operation on a pseudo-tty,
787 * because the pty code doesn't call pppstart after it has
788 * drained the t_outq.
790 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
791 ns_timeout(ppp_timeout, (void *) sc, 1 * (1000000000L / HZ), CALLOUT_PRI_SOFTINT0);
792 sc->sc_flags |= SC_TIMEOUT;
799 * Timeout routine - try to start some more output.
805 struct ppp_softc *sc = (struct ppp_softc *) x;
806 struct tty *tp = (struct tty *) sc->sc_devp;
810 sc->sc_flags &= ~SC_TIMEOUT;
817 * Allocate enough netbuf to handle current MRU.
819 * Warning Will Robinson: pppgetm() can get called at interrupt-level!
823 register struct ppp_softc *sc;
829 * When the MRU is being changed, we could conceivably end up
830 * nuking a packet being received, but I doubt it, since the
831 * hand-shake is lock-step (ie. single packet).
833 if (sc->sc_m != NULL)
835 sc->sc_m = nbq_dequeue(&sc->sc_freeq);
840 * 4.3 says this is an unused function. However,
841 * it appears to be returning a NULL terminated string
842 * of several characters. My guess is that the serial
843 * driver is doing a little buffering so that we don't
844 * get burdend with interrupts.
846 * This function gets called when you use the NeXT
847 * supplied serial drivers. It does not get called
848 * with the MuX driver.
850 * In order to expedite the work done here, we
851 * handle most things here that don't require
852 * processing of a PPP_FLAG.
863 #ifndef OPTIMIZE_PPPREND
864 while (n--) pppinput((u_char) *cp++, tp);
866 #warning OPTIMIZE_PPPREND in effect
868 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
871 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
873 printf("Warning, bad softc structure at %s %d\n", __FILE__, __LINE__);
878 * We can handle FLUSHs, ESCAPES, and non PPP_FLAG characters
883 if (sc->sc_flags & SC_FLUSH)
887 if (*(cp++) == PPP_FLAG)
889 pppinput(PPP_FLAG, tp);
893 else if (sc->sc_flags & SC_LOG_FLUSH)
898 else if (sc->sc_ilen > 3 &&
899 (nb_size(sc->sc_m) - sc->sc_ilen) > n &&
901 *cp != PPP_ESCAPE) /* Dont really handle escapes properly...should */
903 unsigned char* cp1 = cp;
904 if (sc->sc_flags & SC_ESCAPED)
906 sc->sc_flags &= ~SC_ESCAPED;
912 sc->sc_fcs = PPP_FCS(sc->sc_fcs, *(cp++));
913 if (sc->sc_flags & SC_LOG_RAWIN)
916 } while(--n && *cp != PPP_FLAG && *cp != PPP_ESCAPE);
919 bcopy(cp1, sc->sc_mp, (cp-cp1));
921 sc->sc_bytesrcvd += (cp - cp1);
922 sc->sc_ilen += (cp-cp1);
923 sc->sc_mp += (cp-cp1);
928 pppinput(*(cp++), tp);
932 #endif /* OPTIMIZE_PPPREND */
936 * tty interface receiver interrupt.
938 static const unsigned paritytab[8] = {
939 0x96696996, 0x69969669, 0x69969669, 0x96696996,
940 0x69969669, 0x96696996, 0x96696996, 0x69969669
946 register struct tty *tp;
948 register struct ppp_softc *sc;
952 sc = (struct ppp_softc *) tp->t_sc;
953 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
960 /* framing error or overrun on this char - abort packet */
961 IOLogDbg("ppp%d: bad char 0x%x\n", if_unit(sc->sc_if), c);
968 sc->sc_flags |= SC_RCV_B7_1;
970 sc->sc_flags |= SC_RCV_B7_0;
971 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
972 sc->sc_flags |= SC_RCV_ODDP;
974 sc->sc_flags |= SC_RCV_EVNP;
976 if (sc->sc_flags & SC_LOG_RAWIN)
985 if (sc->sc_rawin_count > 0)
990 * This section will adds random packet
995 * Initial time through
997 if (in_error_limit == -1)
999 in_error_limit = rand() % in_error_max_sep;
1000 IOLog("Introducing incoming random error after %d more packets\n",
1004 if ((in_error_pkt_count >= in_error_limit) && (ilen != 0))
1006 sc->sc_fcs = !PPP_GOODFCS;
1007 in_error_pkt_count = 0;
1008 in_error_limit = rand() % in_error_max_sep;
1009 IOLog("Introducing incoming random error after %d more packets\n",
1014 ++in_error_pkt_count;
1017 #endif /* ADD_ERRORS */
1021 * Each Control Escape octet is also
1022 * removed, and the following octet is exclusive-or'd with hexadecimal
1023 * 0x20, unless it is the Flag Sequence (which aborts a frame).
1025 * So, if SC_ESCAPED is set, then we've seen the packet
1026 * abort sequence "}~".
1029 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1030 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
1031 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1032 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1033 IOLogDbg("ppp%d: bad fcs 0x%04x\n", if_unit(sc->sc_if), sc->sc_fcs);
1034 incr_cnt(sc->sc_if, if_ierrors);
1036 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1040 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1042 IOLogDbg("ppp%d: too short (%d)\n", if_unit(sc->sc_if), ilen);
1043 incr_cnt(sc->sc_if, if_ierrors);
1044 sc->sc_flags |= SC_PKTLOST;
1050 * Remove FCS trailer. Set packet length...
1053 nb_shrink_bot(sc->sc_m, nb_size(sc->sc_m) - ilen);
1055 /* excise this netbuf */
1059 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1060 sc->sc_flags &= ~SC_PKTLOST;
1066 if (sc->sc_flags & SC_FLUSH) {
1067 if (sc->sc_flags & SC_LOG_FLUSH)
1074 * On reception, prior to FCS computation, each octet with value less
1075 * than hexadecimal 0x20 is checked. If it is flagged in the receiving
1076 * ACCM, it is simply removed (it may have been inserted by intervening
1077 * data communications equipment). Each Control Escape octet is also
1078 * removed, and the following octet is exclusive-or'd with hexadecimal
1079 * 0x20, unless it is the Flag Sequence (which aborts a frame).
1082 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) {
1086 if (sc->sc_flags & SC_ESCAPED) {
1087 sc->sc_flags &= ~SC_ESCAPED;
1089 } else if (c == PPP_ESCAPE) {
1090 sc->sc_flags |= SC_ESCAPED;
1096 * Initialize buffer on first octet received.
1097 * First octet could be address or protocol (when compressing
1099 * Second octet is control.
1100 * Third octet is first or second (when compressing protocol)
1101 * octet of protocol.
1102 * Fourth octet is second octet of protocol.
1104 if (sc->sc_ilen == 0) {
1105 /* reset the input netbuf */
1106 if (sc->sc_m == NULL) {
1108 if (sc->sc_m == NULL) {
1110 * We schedule a call here as pppindrain will
1111 * not get scheduled and we need the free buffers
1113 IOLog("ppp%d: no input netbufs!\n", if_unit(sc->sc_if));
1114 (void)pppsched(pppfillfreeq, sc);
1119 sc->sc_mp = mtod(m, char *);
1120 sc->sc_fcs = PPP_INITFCS;
1121 if (c != PPP_ALLSTATIONS) {
1122 if (sc->sc_flags & SC_REJ_COMP_AC) {
1123 IOLogDbg("ppp%d: garbage received: 0x%02x (need 0x%02x)\n",
1124 if_unit(sc->sc_if), c, PPP_ALLSTATIONS);
1127 *sc->sc_mp++ = PPP_ALLSTATIONS;
1128 *sc->sc_mp++ = PPP_UI;
1132 if (sc->sc_ilen == 1 && c != PPP_UI) {
1133 IOLogDbg("ppp%d: missing UI (0x%02x), got 0x%02x\n",
1134 if_unit(sc->sc_if), PPP_UI, c);
1137 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1138 /* a compressed protocol */
1142 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1143 IOLogDbg("ppp%d: bad protocol %x\n", if_unit(sc->sc_if),
1144 (sc->sc_mp[-1] << 8) + c);
1148 /* packet beyond configured mru? */
1149 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1150 IOLogDbg("ppp%d: packet too big (%d bytes)\n", if_unit(sc->sc_if),
1155 /* ilen was incremented above... */
1157 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1161 if (!(sc->sc_flags & SC_FLUSH)) {
1162 incr_cnt(sc->sc_if, if_ierrors);
1163 sc->sc_flags |= SC_FLUSH;
1164 if (sc->sc_flags & SC_LOG_FLUSH)
1171 install_ppp_ld(void)
1173 return tty_ld_install(PPPDISC, NORMAL_LDISC, pppopen,
1174 pppclose, pppread, pppwrite, ppptioctl,
1175 pppinput, ppprend, pppstart, ttymodem,
1179 #define MAX_DUMP_BYTES 128
1183 struct ppp_softc *sc;
1187 sc->sc_rawin[sc->sc_rawin_count++] = c;
1188 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1189 || c < 0 && sc->sc_rawin_count > 0) {
1190 IOLog("ppp%d input:\n", if_unit(sc->sc_if));
1191 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1192 sc->sc_rawin_count = 0;
1201 char buf[3*MAX_DUMP_BYTES+4];
1203 static char digits[] = "0123456789abcdef";
1206 if (bp >= buf + sizeof(buf) - 3) {
1210 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1211 *bp++ = digits[*b++ & 0xf];
1218 #endif /* NUM_PPP > 0 */