2 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
5 * Copyright (c) 1989 Carnegie Mellon University.
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by Carnegie Mellon University. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 * Carnegie Mellon University
23 * Pittsburgh, PA 15213
28 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
30 * Copyright (c) 1987 Regents of the University of California.
31 * All rights reserved.
33 * Redistribution and use in source and binary forms are permitted
34 * provided that the above copyright notice and this paragraph are
35 * duplicated in all such forms and that any documentation,
36 * advertising materials, and other materials related to such
37 * distribution and use acknowledge that the software was developed
38 * by the University of California, Berkeley. The name of the
39 * University may not be used to endorse or promote products derived
40 * from this software without specific prior written permission.
41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
42 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
43 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
45 * Serial Line interface
48 * Center for Seismic Studies
49 * 1300 N 17th Street, Suite 1450
50 * Arlington, Virginia 22209
55 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
56 * Converted to 4.3BSD Beta by Chris Torek.
57 * Other changes made at Berkeley, based in part on code by Kirk Smith.
59 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
60 * Added VJ tcp header compression; more unified ioctls
62 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
63 * Cleaned up a lot of the mbuf-related code to fix bugs that
64 * caused system crashes and packet corruption. Changed pppstart
65 * so that it doesn't just give up with a "collision" if the whole
66 * packet doesn't fit in the output ring buffer.
68 * Added priority queueing for interactive IP packets, following
69 * the model of if_sl.c, plus hooks for bpf.
70 * Paul Mackerras (paulus@cs.anu.edu.au).
73 /* $FreeBSD: src/sys/net/ppp_tty.c,v 1.43.2.1 2002/02/13 00:43:11 dillon Exp $ */
74 /* $DragonFly: src/sys/net/ppp_layer/ppp_tty.c,v 1.22 2006/10/25 20:56:03 dillon Exp $ */
76 #include "opt_ppp.h" /* XXX for ppp_defs.h */
78 #define VJC /* XXX for ppp_defs.h */
80 #include <sys/param.h>
81 #include <sys/systm.h>
84 #include <sys/dkstat.h>
85 #include <sys/socket.h>
86 #include <sys/fcntl.h>
87 #include <sys/thread2.h>
91 #include <sys/vnode.h>
94 #include <net/ifq_var.h>
99 #include <net/ppp/if_ppp.h>
100 #include <net/ppp/if_pppvar.h>
102 static int pppopen (cdev_t dev, struct tty *tp);
103 static int pppclose (struct tty *tp, int flag);
104 static int pppread (struct tty *tp, struct uio *uio, int flag);
105 static int pppwrite (struct tty *tp, struct uio *uio, int flag);
106 static int ppptioctl (struct tty *tp, u_long cmd, caddr_t data,
107 int flag, struct ucred *);
108 static int pppinput (int c, struct tty *tp);
109 static int pppstart (struct tty *tp);
111 static u_short pppfcs (u_short fcs, u_char *cp, int len);
112 static void pppasyncstart (struct ppp_softc *);
113 static void pppasyncctlp (struct ppp_softc *);
114 static void pppasyncrelinq (struct ppp_softc *);
115 static void pppasyncsetmtu (struct ppp_softc *);
116 static void ppp_timeout (void *);
117 static void pppgetm (struct ppp_softc *sc);
118 static void ppplogchar (struct ppp_softc *, int);
120 /* XXX called from if_ppp.c - layering violation */
121 void pppasyncattach (void *);
124 * Some useful mbuf macros not in mbuf.h.
126 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
128 #define M_DATASTART(m) \
129 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
130 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
132 #define M_DATASIZE(m) \
133 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
134 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
137 * Does c need to be escaped?
139 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
142 * Procedures for using an async tty interface for PPP.
145 /* This is a FreeBSD-2.X kernel. */
146 #define CCOUNT(q) ((q)->c_cc)
147 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
148 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
151 * Define the PPP line discipline.
154 static struct linesw pppdisc = {
155 pppopen, pppclose, pppread, pppwrite,
156 ppptioctl, pppinput, pppstart, ttymodem,
161 pppasyncattach(void *dummy)
163 /* register line discipline */
164 linesw[PPPDISC] = pppdisc;
168 * Line specific open routine for async tty devices.
169 * Attach the given tty to the first available ppp unit.
170 * Called from device open routine or ttioctl() at >= splsofttty()
174 pppopen(cdev_t dev, struct tty *tp)
176 struct thread *td = curthread; /* XXX */
177 struct ppp_softc *sc;
180 if ((error = suser(td)) != 0)
185 if (tp->t_line == PPPDISC) {
186 sc = (struct ppp_softc *) tp->t_sc;
187 if (sc != NULL && sc->sc_devp == (void *) tp) {
193 if ((sc = pppalloc(td)) == NULL) {
199 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
203 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
204 sc->sc_asyncmap[0] = 0xffffffff;
205 sc->sc_asyncmap[3] = 0x60000000;
206 sc->sc_rasyncmap = 0;
207 sc->sc_devp = (void *) tp;
208 sc->sc_start = pppasyncstart;
209 sc->sc_ctlp = pppasyncctlp;
210 sc->sc_relinq = pppasyncrelinq;
211 sc->sc_setmtu = pppasyncsetmtu;
214 sc->sc_if.if_flags |= IFF_RUNNING;
215 getmicrotime(&sc->sc_if.if_lastchange);
216 sc->sc_if.if_baudrate = tp->t_ospeed;
218 tp->t_sc = (caddr_t) sc;
219 ttyflush(tp, FREAD | FWRITE);
222 * Pre-allocate cblocks to the "just right" amount. The 1 byte t_canq
223 * allocation helps avoid the need for select and/or FIONREAD.
224 * We also pass 1 byte tokens through t_canq...
226 clist_alloc_cblocks(&tp->t_canq, 1, 1);
227 clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT,
228 sc->sc_if.if_mtu + PPP_HIWAT);
229 clist_alloc_cblocks(&tp->t_rawq, 0, 0);
237 * Line specific close routine, called from device close routine
238 * and from ttioctl at >= splsofttty().
239 * Detach the tty from the ppp unit.
240 * Mimics part of ttyclose().
243 pppclose(struct tty *tp, int flag)
245 struct ppp_softc *sc;
248 ttyflush(tp, FREAD | FWRITE);
249 clist_free_cblocks(&tp->t_canq);
250 clist_free_cblocks(&tp->t_outq);
252 sc = (struct ppp_softc *) tp->t_sc;
255 if (tp == (struct tty *) sc->sc_devp) {
265 * Relinquish the interface unit to another device.
268 pppasyncrelinq(struct ppp_softc *sc)
273 m_freem(sc->sc_outm);
280 if (sc->sc_flags & SC_TIMEOUT) {
281 callout_stop(&sc->sc_timeout);
282 sc->sc_flags &= ~SC_TIMEOUT;
289 * This gets called from the upper layer to notify a mtu change
292 pppasyncsetmtu(struct ppp_softc *sc)
294 struct tty *tp = (struct tty *) sc->sc_devp;
298 clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT,
299 sc->sc_if.if_mtu + PPP_HIWAT);
304 * Line specific (tty) read routine.
305 * called at zero spl from the device driver in the response to user-level
306 * reads on the tty file descriptor (ie: pppd).
309 pppread(struct tty *tp, struct uio *uio, int flag)
311 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
318 * Loop waiting for input, checking that nothing disasterous
319 * happens in the meantime.
323 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
327 if (sc->sc_inq.ifq_head != NULL)
329 if ((tp->t_state & TS_CONNECTED) == 0) {
331 return 0; /* end of file */
333 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
335 return (EWOULDBLOCK);
337 error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), PCATCH, "pppin", 0);
344 /* Pull place-holder byte out of canonical queue */
345 clist_getc(&tp->t_canq);
347 /* Get the packet from the input queue */
348 IF_DEQUEUE(&sc->sc_inq, m0);
351 for (m = m0; m && uio->uio_resid; m = m->m_next)
352 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
359 * Line specific (tty) write routine.
360 * called at zero spl from the device driver in the response to user-level
361 * writes on the tty file descriptor (ie: pppd).
364 pppwrite(struct tty *tp, struct uio *uio, int flag)
366 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
367 struct mbuf *m, *m0, **mp;
371 if ((tp->t_state & TS_CONNECTED) == 0)
372 return 0; /* wrote 0 bytes */
373 if (tp->t_line != PPPDISC)
375 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
377 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
378 uio->uio_resid < PPP_HDRLEN)
382 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
383 MGET(m, MB_WAIT, MT_DATA);
384 if ((*mp = m) == NULL) {
390 if (uio->uio_resid >= MCLBYTES / 2)
391 MCLGET(m, MB_DONTWAIT);
392 len = M_TRAILINGSPACE(m);
393 if (len > uio->uio_resid)
394 len = uio->uio_resid;
395 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
402 dst.sa_family = AF_UNSPEC;
403 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
404 m0->m_data += PPP_HDRLEN;
405 m0->m_len -= PPP_HDRLEN;
407 /* call the upper layer to "transmit" it... */
408 lwkt_serialize_enter(sc->sc_if.if_serializer);
409 error = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0);
410 lwkt_serialize_exit(sc->sc_if.if_serializer);
416 * Line specific (tty) ioctl routine.
417 * This discipline requires that tty device drivers call
418 * the line specific l_ioctl routine from their ioctl routines.
422 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct ucred *cr)
424 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
427 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
432 case PPPIOCSASYNCMAP:
433 if ((error = suser_cred(cr, 0)) != 0)
435 sc->sc_asyncmap[0] = *(u_int *)data;
438 case PPPIOCGASYNCMAP:
439 *(u_int *)data = sc->sc_asyncmap[0];
442 case PPPIOCSRASYNCMAP:
443 if ((error = suser_cred(cr, 0)) != 0)
445 sc->sc_rasyncmap = *(u_int *)data;
448 case PPPIOCGRASYNCMAP:
449 *(u_int *)data = sc->sc_rasyncmap;
452 case PPPIOCSXASYNCMAP:
453 if ((error = suser_cred(cr, 0)) != 0)
456 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
457 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
458 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
459 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
463 case PPPIOCGXASYNCMAP:
464 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
468 error = pppioctl(sc, cmd, data, flag, cr);
469 if (error == 0 && cmd == PPPIOCSMRU)
477 * FCS lookup table as calculated by genfcstab.
479 static u_short fcstab[256] = {
480 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
481 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
482 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
483 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
484 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
485 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
486 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
487 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
488 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
489 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
490 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
491 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
492 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
493 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
494 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
495 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
496 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
497 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
498 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
499 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
500 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
501 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
502 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
503 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
504 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
505 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
506 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
507 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
508 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
509 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
510 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
511 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
515 * Calculate a new FCS given the current FCS and the new data.
518 pppfcs(u_short fcs, u_char *cp, int len)
521 fcs = PPP_FCS(fcs, *cp++);
526 * This gets called at splsoftnet from if_ppp.c at various times
527 * when there is data ready to be sent.
530 pppasyncstart(struct ppp_softc *sc)
532 struct tty *tp = (struct tty *) sc->sc_devp;
535 u_char *start, *stop, *cp;
536 int n, ndone, done, idle;
539 /* XXX assumes atomic access to *tp although we're not at spltty(). */
540 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
542 * See if we have an existing packet partly sent.
543 * If not, get a new packet and start sending it.
548 * Get another packet to be sent.
557 * The extra PPP_FLAG will start up a new packet, and thus
558 * will flush any accumulated garbage. We do this whenever
559 * the line may have been idle for some time.
562 if (CCOUNT(&tp->t_outq) == 0) {
563 ++sc->sc_stats.ppp_obytes;
564 clist_putc(PPP_FLAG, &tp->t_outq);
567 /* Calculate the FCS for the first mbuf's worth. */
568 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
569 getmicrotime(&sc->sc_if.if_lastchange);
573 start = mtod(m, u_char *);
578 * Find out how many bytes in the string we can
579 * handle without doing something special.
581 for (cp = start; cp < stop; cp++)
586 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
587 ndone = n - b_to_q(start, n, &tp->t_outq);
590 sc->sc_stats.ppp_obytes += ndone;
593 break; /* packet doesn't fit */
596 * If there are characters left in the mbuf,
597 * the first one must be special.
598 * Put it out in a different form.
602 if (clist_putc(PPP_ESCAPE, &tp->t_outq)) {
606 if (clist_putc(*start ^ PPP_TRANS, &tp->t_outq)) {
607 clist_unputc(&tp->t_outq);
612 sc->sc_stats.ppp_obytes += 2;
619 * If we didn't empty this mbuf, remember where we're up to.
620 * If we emptied the last mbuf, try to add the FCS and closing
621 * flag, and if we can't, leave sc_outm pointing to m, but with
622 * m->m_len == 0, to remind us to output the FCS and flag later.
625 if (done && m->m_next == NULL) {
631 * We may have to escape the bytes in the FCS.
634 c = ~sc->sc_outfcs & 0xFF;
637 *p++ = c ^ PPP_TRANS;
640 c = (~sc->sc_outfcs >> 8) & 0xFF;
643 *p++ = c ^ PPP_TRANS;
649 * Try to output the FCS and flag. If the bytes
650 * don't all fit, back out.
653 for (q = endseq; q < p; ++q)
654 if (clist_putc(*q, &tp->t_outq)) {
656 for (; q > endseq; --q)
657 clist_unputc(&tp->t_outq);
662 sc->sc_stats.ppp_obytes += q - endseq;
666 /* remember where we got to */
672 /* Finished with this mbuf; free it and move on. */
675 /* Finished a packet */
678 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
682 * If m == NULL, we have finished a packet.
683 * If m != NULL, we've either done as much work this time
684 * as we need to, or else we've filled up the output queue.
691 /* Call pppstart to start output again if necessary. */
696 * This timeout is needed for operation on a pseudo-tty,
697 * because the pty code doesn't call pppstart after it has
698 * drained the t_outq.
700 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
701 callout_reset(&sc->sc_timeout, 1, ppp_timeout, sc);
702 sc->sc_flags |= SC_TIMEOUT;
709 * This gets called when a received packet is placed on
710 * the inq, at splsoftnet. The pppd daemon is to be woken up to do a read().
713 pppasyncctlp(struct ppp_softc *sc)
717 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
719 tp = (struct tty *) sc->sc_devp;
720 clist_putc(0, &tp->t_canq);
726 * Start output on async tty interface. If the transmit queue
727 * has drained sufficiently, arrange for pppasyncstart to be
728 * called later at splsoftnet.
729 * Called at spltty or higher.
732 pppstart(struct tty *tp)
734 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
737 * Call output process whether or not there is any output.
738 * We are being called in lieu of ttstart and must do what it would.
740 if (tp->t_oproc != NULL)
744 * If ALTQ is enabled, don't invoke NETISR_PPP.
745 * pppintr() could loop without doing anything useful
746 * under rate-limiting.
748 if (ifq_is_enabled(&sc->sc_if.if_snd))
752 * If the transmit queue has drained and the tty has not hung up
753 * or been disconnected from the ppp unit, then tell if_ppp.c that
754 * we need more output.
756 if (CCOUNT(&tp->t_outq) < PPP_LOWAT
757 && !((tp->t_state & TS_CONNECTED) == 0)
758 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
766 * Timeout routine - try to start some more output.
771 struct ppp_softc *sc = (struct ppp_softc *) x;
772 struct tty *tp = (struct tty *) sc->sc_devp;
775 sc->sc_flags &= ~SC_TIMEOUT;
781 * Allocate enough mbuf to handle current MRU.
784 pppgetm(struct ppp_softc *sc)
786 struct mbuf *m, **mp;
790 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
791 if ((m = *mp) == NULL) {
792 MGETHDR(m, MB_DONTWAIT, MT_DATA);
796 MCLGET(m, MB_DONTWAIT);
798 len -= M_DATASIZE(m);
804 * tty interface receiver interrupt.
806 static unsigned paritytab[8] = {
807 0x96696996, 0x69969669, 0x69969669, 0x96696996,
808 0x69969669, 0x96696996, 0x96696996, 0x69969669
812 * Called when character is available from device driver.
813 * Only guaranteed to be at splsofttty() or spltty()
814 * This is safe to be called while the upper half's netisr is preempted.
817 pppinput(int c, struct tty *tp)
819 struct ppp_softc *sc;
823 sc = (struct ppp_softc *) tp->t_sc;
824 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
828 ++sc->sc_stats.ppp_ibytes;
830 if ((tp->t_state & TS_CONNECTED) == 0) {
831 if (sc->sc_flags & SC_DEBUG)
832 printf("%s: no carrier\n", sc->sc_if.if_xname);
836 if (c & TTY_ERRORMASK) {
837 /* framing error or overrun on this char - abort packet */
838 if (sc->sc_flags & SC_DEBUG)
839 printf("%s: line error %x\n", sc->sc_if.if_xname,
847 * Handle software flow control of output.
849 if (tp->t_iflag & IXON) {
850 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
851 if ((tp->t_state & TS_TTSTOP) == 0) {
852 tp->t_state |= TS_TTSTOP;
857 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
858 tp->t_state &= ~TS_TTSTOP;
859 if (tp->t_oproc != NULL)
867 sc->sc_flags |= SC_RCV_B7_1;
869 sc->sc_flags |= SC_RCV_B7_0;
870 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
871 sc->sc_flags |= SC_RCV_ODDP;
873 sc->sc_flags |= SC_RCV_EVNP;
876 if (sc->sc_flags & SC_LOG_RAWIN)
883 if (sc->sc_rawin_count > 0)
887 * If SC_ESCAPED is set, then we've seen the packet
888 * abort sequence "}~".
890 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
891 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
893 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
894 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
895 if (sc->sc_flags & SC_DEBUG)
896 printf("%s: bad fcs %x, pkt len %d\n",
897 sc->sc_if.if_xname, sc->sc_fcs, ilen);
898 sc->sc_if.if_ierrors++;
899 sc->sc_stats.ppp_ierrors++;
901 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
906 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
908 if (sc->sc_flags & SC_DEBUG)
909 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
911 sc->sc_if.if_ierrors++;
912 sc->sc_stats.ppp_ierrors++;
913 sc->sc_flags |= SC_PKTLOST;
920 * Remove FCS trailer. Somewhat painful...
923 if (--sc->sc_mc->m_len == 0) {
924 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
930 /* excise this mbuf chain */
932 sc->sc_m = sc->sc_mc->m_next;
933 sc->sc_mc->m_next = NULL;
935 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
936 if (sc->sc_flags & SC_PKTLOST) {
938 sc->sc_flags &= ~SC_PKTLOST;
946 if (sc->sc_flags & SC_FLUSH) {
947 if (sc->sc_flags & SC_LOG_FLUSH)
952 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
956 if (sc->sc_flags & SC_ESCAPED) {
957 sc->sc_flags &= ~SC_ESCAPED;
959 } else if (c == PPP_ESCAPE) {
960 sc->sc_flags |= SC_ESCAPED;
967 * Initialize buffer on first octet received.
968 * First octet could be address or protocol (when compressing
970 * Second octet is control.
971 * Third octet is first or second (when compressing protocol)
973 * Fourth octet is second octet of protocol.
975 if (sc->sc_ilen == 0) {
976 /* reset the first input mbuf */
977 if (sc->sc_m == NULL) {
979 if (sc->sc_m == NULL) {
980 if (sc->sc_flags & SC_DEBUG)
981 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
987 m->m_data = M_DATASTART(sc->sc_m);
989 sc->sc_mp = mtod(m, char *);
990 sc->sc_fcs = PPP_INITFCS;
991 if (c != PPP_ALLSTATIONS) {
992 if (sc->sc_flags & SC_REJ_COMP_AC) {
993 if (sc->sc_flags & SC_DEBUG)
994 printf("%s: garbage received: 0x%x (need 0xFF)\n",
995 sc->sc_if.if_xname, c);
998 *sc->sc_mp++ = PPP_ALLSTATIONS;
999 *sc->sc_mp++ = PPP_UI;
1004 if (sc->sc_ilen == 1 && c != PPP_UI) {
1005 if (sc->sc_flags & SC_DEBUG)
1006 printf("%s: missing UI (0x3), got 0x%x\n",
1007 sc->sc_if.if_xname, c);
1010 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1011 /* a compressed protocol */
1016 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1017 if (sc->sc_flags & SC_DEBUG)
1018 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1019 (sc->sc_mp[-1] << 8) + c);
1023 /* packet beyond configured mru? */
1024 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1025 if (sc->sc_flags & SC_DEBUG)
1026 printf("%s: packet too big\n", sc->sc_if.if_xname);
1030 /* is this mbuf full? */
1032 if (M_TRAILINGSPACE(m) <= 0) {
1033 if (m->m_next == NULL) {
1035 if (m->m_next == NULL) {
1036 if (sc->sc_flags & SC_DEBUG)
1037 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1041 sc->sc_mc = m = m->m_next;
1043 m->m_data = M_DATASTART(m);
1044 sc->sc_mp = mtod(m, char *);
1049 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1053 if (!(sc->sc_flags & SC_FLUSH)) {
1055 sc->sc_if.if_ierrors++;
1056 sc->sc_stats.ppp_ierrors++;
1057 sc->sc_flags |= SC_FLUSH;
1059 if (sc->sc_flags & SC_LOG_FLUSH)
1065 #define MAX_DUMP_BYTES 128
1068 ppplogchar(struct ppp_softc *sc, int c)
1071 sc->sc_rawin[sc->sc_rawin_count++] = c;
1072 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1073 || (c < 0 && sc->sc_rawin_count > 0)) {
1074 printf("%s input: %*D", sc->sc_if.if_xname,
1075 sc->sc_rawin_count, sc->sc_rawin, " ");
1076 sc->sc_rawin_count = 0;