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
96 #include <kernserv/lock.h>
98 #include <kern/lock.h>
99 #endif /* NS_TARGET */
100 #endif /* NS_TARGET */
102 #include <sys/param.h>
104 typedef simple_lock_data_t lock_data_t; /* XXX */
105 #endif /* NS_TARGET */
106 #include <sys/proc.h>
107 #include <sys/user.h>
109 #include <sys/socket.h>
110 #include <sys/ioctl.h>
111 #include <sys/file.h>
113 #include <sys/conf.h>
116 #include <sys/errno.h>
117 #if !(NS_TARGET >= 40)
118 /* XXX what happened to this header file? */
119 #include <machine/param.h>
122 #include <kernserv/prototypes.h>
123 /* NeXT broke spl.h in 3.2/m68k. Thanks EPS! */
128 #include <driverkit/generalFuncs.h>
129 #import <kernserv/machine/spl.h>
132 #include <kernserv/kern_server_types.h>
135 #include <net/route.h>
138 #include <netinet/in.h>
139 #include <netinet/in_systm.h>
140 #include <netinet/ip.h>
143 #include <net/ppp_defs.h>
145 #include <net/vjcompress.h>
147 #include <net/if_ppp.h>
148 #include "if_pppvar.h"
152 int pppopen __P((dev_t dev, struct tty *tp));
153 void pppclose __P((struct tty *tp));
154 int pppread __P((struct tty *tp, struct uio *uio));
155 int pppwrite __P((struct tty *tp, struct uio *uio));
156 int ppptioctl __P((struct tty *tp, int cmd, void *data, int flag));
157 void pppinput __P((int c, struct tty *tp));
158 void pppstart __P((struct tty *tp));
161 * Must return an actual netbuf_t since other protocols
162 * use this to get our buffers.
164 netbuf_t pppgetbuf __P((netif_t));
167 * Must accept an actual netbuf_t since others use this
168 * Procedure to access our output routine.
170 int pppoutput __P((netif_t ifp, netbuf_t m, void *arg));
172 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
173 static void pppasyncstart __P((struct ppp_softc *));
174 static void pppasyncctlp __P((struct ppp_softc *));
175 static void pppasyncrelinq __P((struct ppp_softc *));
176 static int ppp_timeout __P((void *));
177 void pppgetm __P((struct ppp_softc *sc));
178 static void pppdumpb __P((u_char *b, int l));
179 void ppplogchar __P((struct ppp_softc *, int));
181 extern kern_server_t instance;
184 * Does c need to be escaped?
186 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
188 #define CCOUNT(q) ((q)->c_cc)
190 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
192 #include "linedisc.h"
195 extern int ttymodem(struct tty*, int);
196 extern int ttselect(struct tty *tp, int rw);
200 pppgetinbuf(netif_t ifp)
202 register struct ppp_softc *sc = &ppp_softc[if_unit(ifp)];
204 int len = MAX(sc->sc_mru, PPP_MTU) + sizeof (struct ifnet *) +
208 PPP_HDRLEN + PPP_FCSLEN;
213 NB_SHRINK_TOP(nb, VJ_HDRLEN + PPP_HDRLEN);
215 NB_SHRINK_TOP(nb, PPP_HDRLEN);
223 * I was a bit worried about reentrancy here. +++SJP
227 pppfillfreeq(void *arg)
229 struct ppp_softc *sc = (struct ppp_softc *)arg;
231 volatile static int in = 0;
237 while(!nbq_high(&sc->sc_freeq)) {
238 nb = pppgetinbuf(sc->sc_if);
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; /* 0x7D and 0x7E */
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;
363 struct nty *np = ttynty(tp);
366 if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0)
367 return 0; /* end of file */
371 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
372 return 0; /* end of file */
374 #endif /* NEW_CLOCAL */
376 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
379 while (nbq_empty(&sc->sc_inq) && tp->t_line == PPPDISC) {
380 if (tp->t_state & (TS_ASYNC | TS_NBIO)) {
382 return (EWOULDBLOCK);
384 sleep((caddr_t)&tp->t_rawq, TTIPRI);
386 if (tp->t_line != PPPDISC) {
391 /* Pull place-holder byte out of canonical queue */
394 /* Get the packet from the input queue */
395 m = nbq_dequeue(&sc->sc_inq);
398 if (sc->sc_flags & SC_DEBUG)
399 IOLogDbg("Read didn't get a buffer at %s %d\n", __FILE__, __LINE__);
402 error = uiomove(NB_MAP(m), NB_SIZE(m), UIO_READ, uio);
408 * Line specific (tty) write routine.
412 register struct tty *tp;
415 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
419 struct nty *np = ttynty(tp);
423 if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0)
424 return 0; /* wrote 0 bytes */
428 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
429 return 0; /* wrote 0 bytes */
431 #endif /* NEW_CLOCAL */
433 if (tp->t_line != PPPDISC)
435 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
437 if (uio->uio_resid > if_mtu(sc->sc_if) + PPP_HDRLEN ||
438 uio->uio_resid < PPP_HDRLEN)
440 m = nb_TO_NB(pppgetbuf(sc->sc_if));
443 if (sc->sc_flags & SC_DEBUG)
444 IOLogDbg("No buffers available for user level write()\n");
447 NB_GROW_TOP(m, PPP_HDRLEN);
448 len = uio->uio_resid;
449 if (error = uiomove(NB_MAP(m), NB_SIZE(m), UIO_WRITE, uio)) {
453 NB_SHRINK_BOT(m, NB_SIZE(m) - len);
454 dst.sa_family = AF_UNSPEC;
455 bcopy(mtod(m, u_char *), dst.sa_data, PPP_HDRLEN);
457 NB_SHRINK_TOP(m, PPP_HDRLEN);
458 return (pppoutput(sc->sc_if, NB_TO_nb(m), &dst));
462 * Line specific (tty) ioctl routine.
463 * This discipline requires that tty device drivers call
464 * the line specific l_ioctl routine from their ioctl routines.
468 ppptioctl(tp, cmd, data, flag)
473 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
476 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
481 case PPPIOCSASYNCMAP:
485 sc->sc_asyncmap[0] = *(u_int *)data;
488 case PPPIOCGASYNCMAP:
489 *(u_int *)data = sc->sc_asyncmap[0];
492 case PPPIOCSRASYNCMAP:
495 sc->sc_rasyncmap = *(u_int *)data;
498 case PPPIOCGRASYNCMAP:
499 *(u_int *)data = sc->sc_rasyncmap;
502 case PPPIOCSXASYNCMAP:
506 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
507 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
508 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
509 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
513 case PPPIOCGXASYNCMAP:
514 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
518 error = pppioctl(sc, cmd, data, flag);
519 if (error == 0 && cmd == PPPIOCSMRU)
524 if (! error && (cmd & IOC_OUT)) {
525 struct uthread *_u = uthread_from_thread(current_thread());
527 /* third arg is destination in ioctl() call... */
528 copyout(data, (caddr_t) _u->uu_arg[2], (cmd >> 16) & IOCPARM_MASK);
536 * FCS lookup table as calculated by genfcstab.
538 static const u_int16_t fcstab[256] = {
539 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
540 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
541 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
542 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
543 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
544 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
545 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
546 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
547 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
548 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
549 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
550 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
551 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
552 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
553 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
554 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
555 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
556 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
557 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
558 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
559 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
560 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
561 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
562 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
563 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
564 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
565 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
566 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
567 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
568 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
569 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
570 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
574 * Calculate a new FCS given the current FCS and the new data.
578 register u_int16_t fcs;
583 fcs = PPP_FCS(fcs, *cp++);
588 * This gets called from pppoutput when a new packet is
593 register struct ppp_softc *sc;
595 register struct tty *tp = (struct tty *) sc->sc_devp;
604 * This gets called when a received packet is placed on
609 struct ppp_softc *sc;
613 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
614 tp = (struct tty *) sc->sc_devp;
615 putc(0, &tp->t_canq);
620 * Start output on async tty interface. Get another datagram
621 * to send from the interface queue and start sending it.
625 register struct tty *tp;
627 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
630 register u_char *start, *stop, *cp;
631 int n, ndone, done, idle;
632 struct nty *np = ttynty(tp);
636 if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0
640 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0
642 #endif /* NEW_CLOCAL */
644 || sc == NULL || tp != (struct tty *) sc->sc_devp) {
645 if (tp->t_oproc != NULL)
652 while (CCOUNT(&tp->t_outq) == 0) {
654 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
657 * See if we have an existing packet partly sent.
658 * If not, get a new packet and start sending it.
663 * Get another packet to be sent.
672 * The extra PPP_FLAG will start up a new packet, and thus
673 * will flush any accumulated garbage. We do this whenever
674 * the line may have been idle for some time.
676 if (CCOUNT(&tp->t_outq) == 0) {
678 (void) putc(PPP_FLAG, &tp->t_outq);
681 /* Calculate the FCS for the first netbuf's worth. */
682 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), NB_SIZE(m));
683 sc->sc_outfcs ^= 0xffff;
685 cp = mtod(m, u_char *) + NB_SIZE(m);
686 NB_GROW_BOT(m, PPP_FCSLEN);
687 *cp++ = sc->sc_outfcs & 0xFF;
688 *cp++ = (sc->sc_outfcs >> 8) & 0xFF;
691 start = mtod(m, u_char *);
696 * Find out how many bytes in the string we can
697 * handle without doing something special.
699 for (cp = start; cp < stop; cp++)
707 * b_to_q returns the number of characters
710 * NetBSD (0.9 or later), 4.3-Reno or similar.
712 ndone = n - b_to_q(start, n, &tp->t_outq);
715 sc->sc_bytessent += ndone;
718 break; /* packet doesn't fit */
723 * If there are characters left in the netbuf,
724 * the first one must be special..
725 * Put it out in a different form.
728 if (putc(PPP_ESCAPE, &tp->t_outq))
730 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
731 (void) unputc(&tp->t_outq);
734 sc->sc_bytessent += 2;
740 * If we didn't empty this netbuf, remember where we're up to.
745 /* remember where we got to */
746 NB_SHRINK_TOP(m, start - mtod(m, u_char *));
747 break; /* can't do any more at the moment */
751 * Output trailing PPP flag and finish packet.
752 * We make the length zero in case the flag
753 * cannot be output immediately.
755 NB_SHRINK_TOP(m, NB_SIZE(m));
756 if (putc(PPP_FLAG, &tp->t_outq))
761 /* Finished with this netbuf; free it and move on. */
764 incr_cnt(sc->sc_if, if_opackets);
770 * If there is stuff in the output queue, send it now.
771 * We are being called in lieu of ttstart and must do what it would.
773 if (tp->t_oproc != NULL)
777 * This timeout is needed for operation on a pseudo-tty,
778 * because the pty code doesn't call pppstart after it has
779 * drained the t_outq.
781 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
783 timeout(ppp_timeout, (void *) sc, 1);
785 ns_timeout(ppp_timeout, (void *) sc, 1 * (1000000000L / HZ), CALLOUT_PRI_SOFTINT0);
786 #endif /*NS_TARGET */
787 sc->sc_flags |= SC_TIMEOUT;
794 * Timeout routine - try to start some more output.
800 struct ppp_softc *sc = (struct ppp_softc *) x;
801 struct tty *tp = (struct tty *) sc->sc_devp;
805 sc->sc_flags &= ~SC_TIMEOUT;
812 * Allocate enough netbuf to handle current MRU.
814 * Warning Will Robinson: pppgetm() can get called at interrupt-level!
818 register struct ppp_softc *sc;
824 * When the MRU is being changed, we could conceivably end up
825 * nuking a packet being received, but I doubt it, since the
826 * hand-shake is lock-step (ie. single packet).
828 if (sc->sc_m != NULL)
830 sc->sc_m = nbq_dequeue(&sc->sc_freeq);
835 * 4.3 says this is an unused function. However,
836 * it appears to be returning a NULL terminated string
837 * of several characters. My guess is that the serial
838 * driver is doing a little buffering so that we don't
839 * get burdend with interrupts.
841 * This function gets called when you use the NeXT
842 * supplied serial drivers. It does not get called
843 * with the MuX driver.
845 * In order to expedite the work done here, we
846 * handle most things here that don't require
847 * processing of a PPP_FLAG.
858 #ifndef OPTIMIZE_PPPREND
859 #warning PPPREND Not optimized!!!
860 while (n--) pppinput((u_char) *cp++, tp);
864 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
867 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
869 printf("Warning, bad softc structure at %s %d\n", __FILE__, __LINE__);
874 * We can handle FLUSHs, ESCAPES, and non PPP_FLAG characters
879 if (sc->sc_flags & SC_FLUSH)
883 if (*(cp++) == PPP_FLAG)
885 pppinput(PPP_FLAG, tp);
889 else if (sc->sc_flags & SC_LOG_FLUSH)
894 else if (sc->sc_ilen > 3 &&
895 (NB_SIZE(sc->sc_m) - sc->sc_ilen) > n &&
897 *cp != PPP_ESCAPE) /* Dont really handle escapes properly...should */
899 unsigned char* cp1 = cp;
900 if (sc->sc_flags & SC_ESCAPED)
902 sc->sc_flags &= ~SC_ESCAPED;
908 sc->sc_fcs = PPP_FCS(sc->sc_fcs, *(cp++));
909 if (sc->sc_flags & SC_LOG_RAWIN)
912 } while(--n && *cp != PPP_FLAG && *cp != PPP_ESCAPE);
915 bcopy(cp1, sc->sc_mp, (cp-cp1));
917 sc->sc_bytesrcvd += (cp - cp1);
918 sc->sc_ilen += (cp-cp1);
919 sc->sc_mp += (cp-cp1);
925 pppinput(*(cp++), tp);
929 #endif /* OPTIMIZE_PPPREND */
933 * tty interface receiver interrupt.
935 static const unsigned paritytab[8] = {
936 0x96696996, 0x69969669, 0x69969669, 0x96696996,
937 0x69969669, 0x96696996, 0x96696996, 0x69969669
943 register struct tty *tp;
945 register struct ppp_softc *sc;
949 sc = (struct ppp_softc *) tp->t_sc;
950 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
957 /* framing error or overrun on this char - abort packet */
958 IOLogDbg("ppp%d: bad char 0x%x\n", if_unit(sc->sc_if), c);
965 sc->sc_flags |= SC_RCV_B7_1;
967 sc->sc_flags |= SC_RCV_B7_0;
968 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
969 sc->sc_flags |= SC_RCV_ODDP;
971 sc->sc_flags |= SC_RCV_EVNP;
973 if (sc->sc_flags & SC_LOG_RAWIN)
978 if (sc->sc_ilen == 0)
984 if (sc->sc_rawin_count > 0)
989 * Each Control Escape octet is also
990 * removed, and the following octet is exclusive-or'd with hexadecimal
991 * 0x20, unless it is the Flag Sequence (which aborts a frame).
993 * So, if SC_ESCAPED is set, then we've seen the packet
994 * abort sequence "}~".
996 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) ||
997 ((ilen > 0) && (sc->sc_fcs != PPP_GOODFCS)))
999 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1000 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0)
1002 IOLog("ppp%d: bad fcs 0x%04x\n", if_unit(sc->sc_if), sc->sc_fcs);
1003 incr_cnt(sc->sc_if, if_ierrors);
1007 IOLog("ppp%d: bad packet flushed...\n", if_unit(sc->sc_if));
1008 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1013 if (ilen < (PPP_HDRLEN + PPP_FCSLEN))
1017 IOLogDbg("ppp%d: too short (%d)\n", if_unit(sc->sc_if), ilen);
1018 incr_cnt(sc->sc_if, if_ierrors);
1019 sc->sc_flags |= SC_PKTLOST;
1025 * Remove FCS trailer. Set packet length...
1028 NB_SHRINK_BOT(sc->sc_m, NB_SIZE(sc->sc_m) - ilen);
1030 /* excise this netbuf */
1034 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1035 sc->sc_flags &= ~SC_PKTLOST;
1041 if (sc->sc_flags & SC_FLUSH) {
1042 if (sc->sc_flags & SC_LOG_FLUSH)
1049 * On reception, prior to FCS computation, each octet with value less
1050 * than hexadecimal 0x20 is checked. If it is flagged in the receiving
1051 * ACCM, it is simply removed (it may have been inserted by intervening
1052 * data communications equipment). Each Control Escape octet is also
1053 * removed, and the following octet is exclusive-or'd with hexadecimal
1054 * 0x20, unless it is the Flag Sequence (which aborts a frame).
1056 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) {
1060 if (sc->sc_flags & SC_ESCAPED) {
1061 sc->sc_flags &= ~SC_ESCAPED;
1063 } else if (c == PPP_ESCAPE) {
1064 sc->sc_flags |= SC_ESCAPED;
1069 * Initialize buffer on first octet received.
1070 * First octet could be address or protocol (when compressing
1072 * Second octet is control.
1073 * Third octet is first or second (when compressing protocol)
1074 * octet of protocol.
1075 * Fourth octet is second octet of protocol.
1077 if (sc->sc_ilen == 0) {
1079 /* reset the input netbuf */
1080 if (sc->sc_m == NULL) {
1082 if (sc->sc_m == NULL) {
1084 * We schedule a call here as pppindrain will
1085 * not get scheduled and we need the free buffers
1087 IOLog("ppp%d: no input netbufs!\n", if_unit(sc->sc_if));
1088 (void)pppsched(pppfillfreeq, sc);
1093 sc->sc_mp = mtod(m, char *);
1094 sc->sc_fcs = PPP_INITFCS;
1096 if (c != PPP_ALLSTATIONS) {
1097 if (sc->sc_flags & SC_REJ_COMP_AC) {
1098 IOLogDbg("ppp%d: garbage received: 0x%02x (need 0x%02x)\n",
1099 if_unit(sc->sc_if), c, PPP_ALLSTATIONS);
1102 *sc->sc_mp++ = PPP_ALLSTATIONS;
1103 *sc->sc_mp++ = PPP_UI;
1109 if (sc->sc_ilen == 1 && c != PPP_UI) {
1110 IOLogDbg("ppp%d: missing UI (0x%02x), got 0x%02x\n",
1111 if_unit(sc->sc_if), PPP_UI, c);
1115 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1116 /* a compressed protocol */
1121 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1122 IOLogDbg("ppp%d: bad protocol %x\n", if_unit(sc->sc_if),
1123 (sc->sc_mp[-1] << 8) + c);
1127 /* packet beyond configured mru? */
1128 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1129 IOLogDbg("ppp%d: packet too big (%d bytes)\n", if_unit(sc->sc_if),
1134 /* ilen was incremented above... */
1136 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1140 if (!(sc->sc_flags & SC_FLUSH)) {
1141 incr_cnt(sc->sc_if, if_ierrors);
1142 sc->sc_flags |= SC_FLUSH;
1143 if (sc->sc_flags & SC_LOG_FLUSH)
1150 install_ppp_ld(void)
1152 return tty_ld_install(PPPDISC, NORMAL_LDISC, pppopen,
1153 pppclose, pppread, pppwrite, ppptioctl,
1154 pppinput, ppprend, pppstart, ttymodem,
1158 #define MAX_DUMP_BYTES 128
1162 struct ppp_softc *sc;
1166 sc->sc_rawin[sc->sc_rawin_count++] = c;
1167 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1168 || c < 0 && sc->sc_rawin_count > 0) {
1169 IOLog("ppp%d input:\n", if_unit(sc->sc_if));
1170 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1171 sc->sc_rawin_count = 0;
1180 char buf[3*MAX_DUMP_BYTES+4];
1182 static char digits[] = "0123456789abcdef";
1185 if (bp >= buf + sizeof(buf) - 3) {
1189 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1190 *bp++ = digits[*b++ & 0xf];
1197 #endif /* NUM_PPP > 0 */