2 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
5 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. The name "Carnegie Mellon University" must not be used to
20 * endorse or promote products derived from this software without
21 * prior written permission. For permission or any legal
22 * details, please contact
23 * Office of Technology Transfer
24 * Carnegie Mellon University
26 * Pittsburgh, PA 15213-3890
27 * (412) 268-4387, fax: (412) 268-7395
28 * tech-transfer@andrew.cmu.edu
30 * 4. Redistributions of any form whatsoever must retain the following
32 * "This product includes software developed by Computing Services
33 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
36 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
37 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
38 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
39 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
40 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
41 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44 * Carnegie Mellon University
46 * Pittsburgh, PA 15213
51 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
53 * Copyright (c) 1987 Regents of the University of California.
54 * All rights reserved.
56 * Redistribution and use in source and binary forms are permitted
57 * provided that the above copyright notice and this paragraph are
58 * duplicated in all such forms and that any documentation,
59 * advertising materials, and other materials related to such
60 * distribution and use acknowledge that the software was developed
61 * by the University of California, Berkeley. The name of the
62 * University may not be used to endorse or promote products derived
63 * from this software without specific prior written permission.
64 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
65 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
66 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
68 * Serial Line interface
71 * Center for Seismic Studies
72 * 1300 N 17th Street, Suite 1450
73 * Arlington, Virginia 22209
78 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
79 * Converted to 4.3BSD Beta by Chris Torek.
80 * Other changes made at Berkeley, based in part on code by Kirk Smith.
82 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
83 * Added VJ tcp header compression; more unified ioctls
85 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
86 * Cleaned up a lot of the mbuf-related code to fix bugs that
87 * caused system crashes and packet corruption. Changed pppstart
88 * so that it doesn't just give up with a "collision" if the whole
89 * packet doesn't fit in the output ring buffer.
91 * Added priority queueing for interactive IP packets, following
92 * the model of if_sl.c, plus hooks for bpf.
93 * Paul Mackerras (paulus@cs.anu.edu.au).
96 /* $Id: ppp_tty.c,v 1.9 2002/12/06 09:49:15 paulus Exp $ */
97 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
98 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
106 #include <sys/param.h>
107 #include <sys/systm.h>
108 #include <sys/proc.h>
109 #include <sys/mbuf.h>
110 #include <sys/dkstat.h>
111 #include <sys/socket.h>
112 #include <sys/ioctl.h>
113 #include <sys/file.h>
115 #include <sys/kernel.h>
116 #include <sys/conf.h>
117 #include <sys/vnode.h>
120 #include <net/if_types.h>
123 #include <netinet/in.h>
124 #include <netinet/in_systm.h>
125 #include <netinet/ip.h>
126 #include <net/pppcompress.h>
132 #include <net/ppp_defs.h>
133 #include <net/if_ppp.h>
134 #include <net/if_pppvar.h>
136 void pppasyncattach
__P((void));
137 int pppopen
__P((dev_t dev
, struct tty
*tp
));
138 int pppclose
__P((struct tty
*tp
, int flag
));
139 int pppread
__P((struct tty
*tp
, struct uio
*uio
, int flag
));
140 int pppwrite
__P((struct tty
*tp
, struct uio
*uio
, int flag
));
141 int ppptioctl
__P((struct tty
*tp
, int cmd
, caddr_t data
, int flag
,
143 int pppinput
__P((int c
, struct tty
*tp
));
144 int pppstart
__P((struct tty
*tp
));
146 static u_short pppfcs
__P((u_short fcs
, u_char
*cp
, int len
));
147 static void pppasyncstart
__P((struct ppp_softc
*));
148 static void pppasyncctlp
__P((struct ppp_softc
*));
149 static void pppasyncrelinq
__P((struct ppp_softc
*));
150 static void ppp_timeout
__P((void *));
151 static void pppgetm
__P((struct ppp_softc
*sc
));
152 static void pppdumpb
__P((u_char
*b
, int l
));
153 static void ppplogchar
__P((struct ppp_softc
*, int));
156 * Some useful mbuf macros not in mbuf.h.
158 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
160 #define M_DATASTART(m) \
161 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
162 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
164 #define M_DATASIZE(m) \
165 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
166 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
169 * Does c need to be escaped?
171 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
174 * Procedures for using an async tty interface for PPP.
177 /* This is a FreeBSD-2.0 kernel. */
178 #define CCOUNT(q) ((q)->c_cc)
179 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
180 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
183 * Define the PPP line discipline.
186 static struct linesw pppdisc
= {
187 pppopen
, pppclose
, pppread
, pppwrite
, ppptioctl
,
188 pppinput
, pppstart
, ttymodem
194 linesw
[PPPDISC
] = pppdisc
;
197 TEXT_SET(pseudo_set
, pppasyncattach
);
200 * Line specific open routine for async tty devices.
201 * Attach the given tty to the first available ppp unit.
202 * Called from device open routine or ttioctl.
208 register struct tty
*tp
;
210 struct proc
*p
= curproc
; /* XXX */
211 register struct ppp_softc
*sc
;
214 if ((error
= suser(p
->p_ucred
, &p
->p_acflag
)) != 0)
219 if (tp
->t_line
== PPPDISC
) {
220 sc
= (struct ppp_softc
*) tp
->t_sc
;
221 if (sc
!= NULL
&& sc
->sc_devp
== (void *) tp
) {
227 if ((sc
= pppalloc(p
->p_pid
)) == NULL
) {
233 (*sc
->sc_relinq
)(sc
); /* get previous owner to relinquish the unit */
237 bzero(sc
->sc_asyncmap
, 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
;
247 sc
->sc_if
.if_flags
|= IFF_RUNNING
;
248 sc
->sc_if
.if_baudrate
= tp
->t_ospeed
;
250 tp
->t_sc
= (caddr_t
) sc
;
251 ttyflush(tp
, FREAD
| FWRITE
);
258 * Line specific close routine, called from device close routine
260 * Detach the tty from the ppp unit.
261 * Mimics part of ttyclose().
268 register struct ppp_softc
*sc
;
272 ttyflush(tp
, FREAD
|FWRITE
);
274 sc
= (struct ppp_softc
*) tp
->t_sc
;
277 if (tp
== (struct tty
*) sc
->sc_devp
) {
287 * Relinquish the interface unit to another device.
291 struct ppp_softc
*sc
;
297 m_freem(sc
->sc_outm
);
304 if (sc
->sc_flags
& SC_TIMEOUT
) {
305 untimeout(ppp_timeout
, (void *) sc
);
306 sc
->sc_flags
&= ~SC_TIMEOUT
;
312 * Line specific (tty) read routine.
315 pppread(tp
, uio
, flag
)
316 register struct tty
*tp
;
320 register struct ppp_softc
*sc
= (struct ppp_softc
*)tp
->t_sc
;
328 * Loop waiting for input, checking that nothing disasterous
329 * happens in the meantime.
333 if (tp
!= (struct tty
*) sc
->sc_devp
|| tp
->t_line
!= PPPDISC
) {
337 if (sc
->sc_inq
.ifq_head
!= NULL
)
339 if ((tp
->t_state
& TS_CARR_ON
) == 0 && (tp
->t_cflag
& CLOCAL
) == 0
340 && (tp
->t_state
& TS_ISOPEN
)) {
342 return 0; /* end of file */
344 if (tp
->t_state
& TS_ASYNC
|| flag
& IO_NDELAY
) {
346 return (EWOULDBLOCK
);
348 error
= ttysleep(tp
, (caddr_t
)&tp
->t_rawq
, TTIPRI
| PCATCH
, "ttyin", 0);
355 /* Pull place-holder byte out of canonical queue */
358 /* Get the packet from the input queue */
359 IF_DEQUEUE(&sc
->sc_inq
, m0
);
362 for (m
= m0
; m
&& uio
->uio_resid
; m
= m
->m_next
)
363 if ((error
= uiomove(mtod(m
, u_char
*), m
->m_len
, uio
)) != 0)
370 * Line specific (tty) write routine.
373 pppwrite(tp
, uio
, flag
)
374 register struct tty
*tp
;
378 register struct ppp_softc
*sc
= (struct ppp_softc
*)tp
->t_sc
;
379 struct mbuf
*m
, *m0
, **mp
;
383 if ((tp
->t_state
& TS_CARR_ON
) == 0 && (tp
->t_cflag
& CLOCAL
) == 0)
384 return 0; /* wrote 0 bytes */
385 if (tp
->t_line
!= PPPDISC
)
387 if (sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
)
389 if (uio
->uio_resid
> sc
->sc_if
.if_mtu
+ PPP_HDRLEN
||
390 uio
->uio_resid
< PPP_HDRLEN
)
392 for (mp
= &m0
; uio
->uio_resid
; mp
= &m
->m_next
) {
393 MGET(m
, M_WAIT
, MT_DATA
);
394 if ((*mp
= m
) == NULL
) {
399 if (uio
->uio_resid
>= MCLBYTES
/ 2)
400 MCLGET(m
, M_DONTWAIT
);
401 len
= M_TRAILINGSPACE(m
);
402 if (len
> uio
->uio_resid
)
403 len
= uio
->uio_resid
;
404 if ((error
= uiomove(mtod(m
, u_char
*), len
, uio
)) != 0) {
410 dst
.sa_family
= AF_UNSPEC
;
411 bcopy(mtod(m0
, u_char
*), dst
.sa_data
, PPP_HDRLEN
);
412 m0
->m_data
+= PPP_HDRLEN
;
413 m0
->m_len
-= PPP_HDRLEN
;
414 return (pppoutput(&sc
->sc_if
, m0
, &dst
, (struct rtentry
*)0));
418 * Line specific (tty) ioctl routine.
419 * This discipline requires that tty device drivers call
420 * the line specific l_ioctl routine from their ioctl routines.
424 ppptioctl(tp
, cmd
, data
, flag
, p
)
431 struct ppp_softc
*sc
= (struct ppp_softc
*) tp
->t_sc
;
434 if (sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
)
439 case PPPIOCSASYNCMAP
:
440 if ((error
= suser(p
->p_ucred
, &p
->p_acflag
)) != 0)
442 sc
->sc_asyncmap
[0] = *(u_int
*)data
;
445 case PPPIOCGASYNCMAP
:
446 *(u_int
*)data
= sc
->sc_asyncmap
[0];
449 case PPPIOCSRASYNCMAP
:
450 if ((error
= suser(p
->p_ucred
, &p
->p_acflag
)) != 0)
452 sc
->sc_rasyncmap
= *(u_int
*)data
;
455 case PPPIOCGRASYNCMAP
:
456 *(u_int
*)data
= sc
->sc_rasyncmap
;
459 case PPPIOCSXASYNCMAP
:
460 if ((error
= suser(p
->p_ucred
, &p
->p_acflag
)) != 0)
463 bcopy(data
, sc
->sc_asyncmap
, sizeof(sc
->sc_asyncmap
));
464 sc
->sc_asyncmap
[1] = 0; /* mustn't escape 0x20 - 0x3f */
465 sc
->sc_asyncmap
[2] &= ~0x40000000; /* mustn't escape 0x5e */
466 sc
->sc_asyncmap
[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
470 case PPPIOCGXASYNCMAP
:
471 bcopy(sc
->sc_asyncmap
, data
, sizeof(sc
->sc_asyncmap
));
475 error
= pppioctl(sc
, cmd
, data
, flag
, p
);
476 if (error
== 0 && cmd
== PPPIOCSMRU
)
484 * FCS lookup table as calculated by genfcstab.
486 static u_short fcstab
[256] = {
487 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
488 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
489 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
490 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
491 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
492 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
493 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
494 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
495 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
496 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
497 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
498 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
499 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
500 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
501 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
502 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
503 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
504 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
505 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
506 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
507 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
508 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
509 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
510 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
511 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
512 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
513 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
514 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
515 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
516 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
517 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
518 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
522 * Calculate a new FCS given the current FCS and the new data.
526 register u_short fcs
;
531 fcs
= PPP_FCS(fcs
, *cp
++);
536 * This gets called at splsoftnet from if_ppp.c at various times
537 * when there is data ready to be sent.
541 register struct ppp_softc
*sc
;
543 register struct tty
*tp
= (struct tty
*) sc
->sc_devp
;
544 register struct mbuf
*m
;
546 register u_char
*start
, *stop
, *cp
;
547 int n
, ndone
, done
, idle
;
552 while (CCOUNT(&tp
->t_outq
) < PPP_HIWAT
) {
554 * See if we have an existing packet partly sent.
555 * If not, get a new packet and start sending it.
560 * Get another packet to be sent.
569 * The extra PPP_FLAG will start up a new packet, and thus
570 * will flush any accumulated garbage. We do this whenever
571 * the line may have been idle for some time.
573 if (CCOUNT(&tp
->t_outq
) == 0) {
574 ++sc
->sc_stats
.ppp_obytes
;
575 (void) putc(PPP_FLAG
, &tp
->t_outq
);
578 /* Calculate the FCS for the first mbuf's worth. */
579 sc
->sc_outfcs
= pppfcs(PPP_INITFCS
, mtod(m
, u_char
*), m
->m_len
);
580 sc
->sc_if
.if_lastchange
= time
;
584 start
= mtod(m
, u_char
*);
589 * Find out how many bytes in the string we can
590 * handle without doing something special.
592 for (cp
= start
; cp
< stop
; cp
++)
597 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
598 ndone
= n
- b_to_q(start
, n
, &tp
->t_outq
);
601 sc
->sc_stats
.ppp_obytes
+= ndone
;
604 break; /* packet doesn't fit */
607 * If there are characters left in the mbuf,
608 * the first one must be special.
609 * Put it out in a different form.
613 if (putc(PPP_ESCAPE
, &tp
->t_outq
))
615 if (putc(*start
^ PPP_TRANS
, &tp
->t_outq
)) {
616 (void) unputc(&tp
->t_outq
);
621 sc
->sc_stats
.ppp_obytes
+= 2;
628 * If we didn't empty this mbuf, remember where we're up to.
629 * If we emptied the last mbuf, try to add the FCS and closing
630 * flag, and if we can't, leave sc_outm pointing to m, but with
631 * m->m_len == 0, to remind us to output the FCS and flag later.
634 if (done
&& m
->m_next
== NULL
) {
640 * We may have to escape the bytes in the FCS.
643 c
= ~sc
->sc_outfcs
& 0xFF;
646 *p
++ = c
^ PPP_TRANS
;
649 c
= (~sc
->sc_outfcs
>> 8) & 0xFF;
652 *p
++ = c
^ PPP_TRANS
;
658 * Try to output the FCS and flag. If the bytes
659 * don't all fit, back out.
662 for (q
= endseq
; q
< p
; ++q
)
663 if (putc(*q
, &tp
->t_outq
)) {
665 for (; q
> endseq
; --q
)
671 sc
->sc_stats
.ppp_obytes
+= q
- endseq
;
675 /* remember where we got to */
681 /* Finished with this mbuf; free it and move on. */
685 /* Finished a packet */
688 sc
->sc_outfcs
= pppfcs(sc
->sc_outfcs
, mtod(m
, u_char
*), m
->m_len
);
692 * If m == NULL, we have finished a packet.
693 * If m != NULL, we've either done as much work this time
694 * as we need to, or else we've filled up the output queue.
701 /* Call pppstart to start output again if necessary. */
706 * This timeout is needed for operation on a pseudo-tty,
707 * because the pty code doesn't call pppstart after it has
708 * drained the t_outq.
710 if (!idle
&& (sc
->sc_flags
& SC_TIMEOUT
) == 0) {
711 timeout(ppp_timeout
, (void *) sc
, 1);
712 sc
->sc_flags
|= SC_TIMEOUT
;
719 * This gets called when a received packet is placed on
720 * the inq, at splsoftnet.
724 struct ppp_softc
*sc
;
729 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
731 tp
= (struct tty
*) sc
->sc_devp
;
732 putc(0, &tp
->t_canq
);
738 * Start output on async tty interface. If the transmit queue
739 * has drained sufficiently, arrange for pppasyncstart to be
740 * called later at splsoftnet.
741 * Called at spltty or higher.
745 register struct tty
*tp
;
747 register struct ppp_softc
*sc
= (struct ppp_softc
*) tp
->t_sc
;
750 * If there is stuff in the output queue, send it now.
751 * We are being called in lieu of ttstart and must do what it would.
753 if (tp
->t_oproc
!= NULL
)
757 * If the transmit queue has drained and the tty has not hung up
758 * or been disconnected from the ppp unit, then tell if_ppp.c that
759 * we need more output.
761 if (CCOUNT(&tp
->t_outq
) < PPP_LOWAT
762 && !((tp
->t_state
& TS_CARR_ON
) == 0 && (tp
->t_cflag
& CLOCAL
) == 0)
763 && sc
!= NULL
&& tp
== (struct tty
*) sc
->sc_devp
) {
771 * Timeout routine - try to start some more output.
777 struct ppp_softc
*sc
= (struct ppp_softc
*) x
;
778 struct tty
*tp
= (struct tty
*) sc
->sc_devp
;
782 sc
->sc_flags
&= ~SC_TIMEOUT
;
788 * Allocate enough mbuf to handle current MRU.
792 register struct ppp_softc
*sc
;
794 struct mbuf
*m
, **mp
;
798 for (len
= sc
->sc_mru
+ PPP_HDRLEN
+ PPP_FCSLEN
; len
> 0; ){
799 if ((m
= *mp
) == NULL
) {
800 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
804 MCLGET(m
, M_DONTWAIT
);
806 len
-= M_DATASIZE(m
);
812 * tty interface receiver interrupt.
814 static unsigned paritytab
[8] = {
815 0x96696996, 0x69969669, 0x69969669, 0x96696996,
816 0x69969669, 0x96696996, 0x96696996, 0x69969669
822 register struct tty
*tp
;
824 register struct ppp_softc
*sc
;
828 sc
= (struct ppp_softc
*) tp
->t_sc
;
829 if (sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
)
833 ++sc
->sc_stats
.ppp_ibytes
;
836 /* framing error or overrun on this char - abort packet */
837 if (sc
->sc_flags
& SC_DEBUG
)
838 printf("ppp%d: bad char %x\n", sc
->sc_if
.if_unit
, c
);
845 * Handle software flow control of output.
847 if (tp
->t_iflag
& IXON
) {
848 if (c
== tp
->t_cc
[VSTOP
] && tp
->t_cc
[VSTOP
] != _POSIX_VDISABLE
) {
849 if ((tp
->t_state
& TS_TTSTOP
) == 0) {
850 tp
->t_state
|= TS_TTSTOP
;
851 (*cdevsw
[major(tp
->t_dev
)].d_stop
)(tp
, 0);
855 if (c
== tp
->t_cc
[VSTART
] && tp
->t_cc
[VSTART
] != _POSIX_VDISABLE
) {
856 tp
->t_state
&= ~TS_TTSTOP
;
857 if (tp
->t_oproc
!= NULL
)
865 sc
->sc_flags
|= SC_RCV_B7_1
;
867 sc
->sc_flags
|= SC_RCV_B7_0
;
868 if (paritytab
[c
>> 5] & (1 << (c
& 0x1F)))
869 sc
->sc_flags
|= SC_RCV_ODDP
;
871 sc
->sc_flags
|= SC_RCV_EVNP
;
874 if (sc
->sc_flags
& SC_LOG_RAWIN
)
881 if (sc
->sc_rawin_count
> 0)
885 * If SC_ESCAPED is set, then we've seen the packet
886 * abort sequence "}~".
888 if (sc
->sc_flags
& (SC_FLUSH
| SC_ESCAPED
)
889 || (ilen
> 0 && sc
->sc_fcs
!= PPP_GOODFCS
)) {
891 sc
->sc_flags
|= SC_PKTLOST
; /* note the dropped packet */
892 if ((sc
->sc_flags
& (SC_FLUSH
| SC_ESCAPED
)) == 0){
893 if (sc
->sc_flags
& SC_DEBUG
)
894 printf("ppp%d: bad fcs %x, pkt len %d\n",
895 sc
->sc_if
.if_unit
, sc
->sc_fcs
, ilen
);
896 sc
->sc_if
.if_ierrors
++;
897 sc
->sc_stats
.ppp_ierrors
++;
899 sc
->sc_flags
&= ~(SC_FLUSH
| SC_ESCAPED
);
904 if (ilen
< PPP_HDRLEN
+ PPP_FCSLEN
) {
906 if (sc
->sc_flags
& SC_DEBUG
)
907 printf("ppp%d: too short (%d)\n", sc
->sc_if
.if_unit
, ilen
);
909 sc
->sc_if
.if_ierrors
++;
910 sc
->sc_stats
.ppp_ierrors
++;
911 sc
->sc_flags
|= SC_PKTLOST
;
918 * Remove FCS trailer. Somewhat painful...
921 if (--sc
->sc_mc
->m_len
== 0) {
922 for (m
= sc
->sc_m
; m
->m_next
!= sc
->sc_mc
; m
= m
->m_next
)
928 /* excise this mbuf chain */
930 sc
->sc_m
= sc
->sc_mc
->m_next
;
931 sc
->sc_mc
->m_next
= NULL
;
933 ppppktin(sc
, m
, sc
->sc_flags
& SC_PKTLOST
);
934 if (sc
->sc_flags
& SC_PKTLOST
) {
936 sc
->sc_flags
&= ~SC_PKTLOST
;
944 if (sc
->sc_flags
& SC_FLUSH
) {
945 if (sc
->sc_flags
& SC_LOG_FLUSH
)
950 if (c
< 0x20 && (sc
->sc_rasyncmap
& (1 << c
)))
954 if (sc
->sc_flags
& SC_ESCAPED
) {
955 sc
->sc_flags
&= ~SC_ESCAPED
;
957 } else if (c
== PPP_ESCAPE
) {
958 sc
->sc_flags
|= SC_ESCAPED
;
965 * Initialize buffer on first octet received.
966 * First octet could be address or protocol (when compressing
968 * Second octet is control.
969 * Third octet is first or second (when compressing protocol)
971 * Fourth octet is second octet of protocol.
973 if (sc
->sc_ilen
== 0) {
974 /* reset the first input mbuf */
975 if (sc
->sc_m
== NULL
) {
977 if (sc
->sc_m
== NULL
) {
978 if (sc
->sc_flags
& SC_DEBUG
)
979 printf("ppp%d: no input mbufs!\n", sc
->sc_if
.if_unit
);
985 m
->m_data
= M_DATASTART(sc
->sc_m
);
987 sc
->sc_mp
= mtod(m
, char *);
988 sc
->sc_fcs
= PPP_INITFCS
;
989 if (c
!= PPP_ALLSTATIONS
) {
990 if (sc
->sc_flags
& SC_REJ_COMP_AC
) {
991 if (sc
->sc_flags
& SC_DEBUG
)
992 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
993 sc
->sc_if
.if_unit
, c
);
996 *sc
->sc_mp
++ = PPP_ALLSTATIONS
;
997 *sc
->sc_mp
++ = PPP_UI
;
1002 if (sc
->sc_ilen
== 1 && c
!= PPP_UI
) {
1003 if (sc
->sc_flags
& SC_DEBUG
)
1004 printf("ppp%d: missing UI (0x3), got 0x%x\n",
1005 sc
->sc_if
.if_unit
, c
);
1008 if (sc
->sc_ilen
== 2 && (c
& 1) == 1) {
1009 /* a compressed protocol */
1014 if (sc
->sc_ilen
== 3 && (c
& 1) == 0) {
1015 if (sc
->sc_flags
& SC_DEBUG
)
1016 printf("ppp%d: bad protocol %x\n", sc
->sc_if
.if_unit
,
1017 (sc
->sc_mp
[-1] << 8) + c
);
1021 /* packet beyond configured mru? */
1022 if (++sc
->sc_ilen
> sc
->sc_mru
+ PPP_HDRLEN
+ PPP_FCSLEN
) {
1023 if (sc
->sc_flags
& SC_DEBUG
)
1024 printf("ppp%d: packet too big\n", sc
->sc_if
.if_unit
);
1028 /* is this mbuf full? */
1030 if (M_TRAILINGSPACE(m
) <= 0) {
1031 if (m
->m_next
== NULL
) {
1033 if (m
->m_next
== NULL
) {
1034 if (sc
->sc_flags
& SC_DEBUG
)
1035 printf("ppp%d: too few input mbufs!\n", sc
->sc_if
.if_unit
);
1039 sc
->sc_mc
= m
= m
->m_next
;
1041 m
->m_data
= M_DATASTART(m
);
1042 sc
->sc_mp
= mtod(m
, char *);
1047 sc
->sc_fcs
= PPP_FCS(sc
->sc_fcs
, c
);
1051 if (!(sc
->sc_flags
& SC_FLUSH
)) {
1053 sc
->sc_if
.if_ierrors
++;
1054 sc
->sc_stats
.ppp_ierrors
++;
1055 sc
->sc_flags
|= SC_FLUSH
;
1057 if (sc
->sc_flags
& SC_LOG_FLUSH
)
1063 #define MAX_DUMP_BYTES 128
1067 struct ppp_softc
*sc
;
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("ppp%d input: ", sc
->sc_if
.if_unit
);
1075 pppdumpb(sc
->sc_rawin
, sc
->sc_rawin_count
);
1076 sc
->sc_rawin_count
= 0;
1085 char buf
[3*MAX_DUMP_BYTES
+4];
1087 static char digits
[] = "0123456789abcdef";
1090 if (bp
>= buf
+ sizeof(buf
) - 3) {
1094 *bp
++ = digits
[*b
>> 4]; /* convert byte to ascii hex */
1095 *bp
++ = digits
[*b
++ & 0xf];
1100 printf("%s\n", buf
);
1103 #endif /* NPPP > 0 */