Add include/linux/if_pppol2tp.h, missed in a previous commit
[mpls-ppp.git] / freebsd-2.0 / ppp_tty.c
blobf46148ea69ea7cf3d0463709152be77151a02e11
1 /*
2 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
3 * tty devices.
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
9 * are met:
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
17 * distribution.
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
25 * 5000 Forbes Avenue
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
31 * acknowledgment:
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.
43 * Drew D. Perkins
44 * Carnegie Mellon University
45 * 4910 Forbes Ave.
46 * Pittsburgh, PA 15213
47 * (412) 268-8576
48 * ddp@andrew.cmu.edu
50 * Based on:
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
70 * Rick Adams
71 * Center for Seismic Studies
72 * 1300 N 17th Street, Suite 1450
73 * Arlington, Virginia 22209
74 * (703)276-7900
75 * rick@seismo.ARPA
76 * seismo!rick
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 */
100 #include "ppp.h"
101 #if NPPP > 0
103 #define VJC
104 #define PPP_COMPRESS
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>
114 #include <sys/tty.h>
115 #include <sys/kernel.h>
116 #include <sys/conf.h>
117 #include <sys/vnode.h>
119 #include <net/if.h>
120 #include <net/if_types.h>
122 #ifdef VJC
123 #include <netinet/in.h>
124 #include <netinet/in_systm.h>
125 #include <netinet/ip.h>
126 #include <net/pppcompress.h>
127 #endif
129 #ifdef PPP_FILTER
130 #include <net/bpf.h>
131 #endif
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,
142 struct proc *));
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
191 void
192 pppasyncattach()
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.
204 /* ARGSUSED */
206 pppopen(dev, tp)
207 dev_t dev;
208 register struct tty *tp;
210 struct proc *p = curproc; /* XXX */
211 register struct ppp_softc *sc;
212 int error, s;
214 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
215 return (error);
217 s = spltty();
219 if (tp->t_line == PPPDISC) {
220 sc = (struct ppp_softc *) tp->t_sc;
221 if (sc != NULL && sc->sc_devp == (void *) tp) {
222 splx(s);
223 return (0);
227 if ((sc = pppalloc(p->p_pid)) == NULL) {
228 splx(s);
229 return ENXIO;
232 if (sc->sc_relinq)
233 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
235 sc->sc_ilen = 0;
236 sc->sc_m = NULL;
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;
245 sc->sc_outm = NULL;
246 pppgetm(sc);
247 sc->sc_if.if_flags |= IFF_RUNNING;
248 sc->sc_if.if_baudrate = tp->t_ospeed;
250 tp->t_sc = (caddr_t) sc;
251 ttyflush(tp, FREAD | FWRITE);
253 splx(s);
254 return (0);
258 * Line specific close routine, called from device close routine
259 * and from ttioctl.
260 * Detach the tty from the ppp unit.
261 * Mimics part of ttyclose().
264 pppclose(tp, flag)
265 struct tty *tp;
266 int flag;
268 register struct ppp_softc *sc;
269 int s;
271 s = spltty();
272 ttyflush(tp, FREAD|FWRITE);
273 tp->t_line = 0;
274 sc = (struct ppp_softc *) tp->t_sc;
275 if (sc != NULL) {
276 tp->t_sc = NULL;
277 if (tp == (struct tty *) sc->sc_devp) {
278 pppasyncrelinq(sc);
279 pppdealloc(sc);
282 splx(s);
283 return 0;
287 * Relinquish the interface unit to another device.
289 static void
290 pppasyncrelinq(sc)
291 struct ppp_softc *sc;
293 int s;
295 s = spltty();
296 if (sc->sc_outm) {
297 m_freem(sc->sc_outm);
298 sc->sc_outm = NULL;
300 if (sc->sc_m) {
301 m_freem(sc->sc_m);
302 sc->sc_m = NULL;
304 if (sc->sc_flags & SC_TIMEOUT) {
305 untimeout(ppp_timeout, (void *) sc);
306 sc->sc_flags &= ~SC_TIMEOUT;
308 splx(s);
312 * Line specific (tty) read routine.
315 pppread(tp, uio, flag)
316 register struct tty *tp;
317 struct uio *uio;
318 int flag;
320 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
321 struct mbuf *m, *m0;
322 register int s;
323 int error = 0;
325 if (sc == NULL)
326 return 0;
328 * Loop waiting for input, checking that nothing disasterous
329 * happens in the meantime.
331 s = spltty();
332 for (;;) {
333 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
334 splx(s);
335 return 0;
337 if (sc->sc_inq.ifq_head != NULL)
338 break;
339 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
340 && (tp->t_state & TS_ISOPEN)) {
341 splx(s);
342 return 0; /* end of file */
344 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
345 splx(s);
346 return (EWOULDBLOCK);
348 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, "ttyin", 0);
349 if (error) {
350 splx(s);
351 return error;
355 /* Pull place-holder byte out of canonical queue */
356 getc(&tp->t_canq);
358 /* Get the packet from the input queue */
359 IF_DEQUEUE(&sc->sc_inq, m0);
360 splx(s);
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)
364 break;
365 m_freem(m0);
366 return (error);
370 * Line specific (tty) write routine.
373 pppwrite(tp, uio, flag)
374 register struct tty *tp;
375 struct uio *uio;
376 int flag;
378 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
379 struct mbuf *m, *m0, **mp;
380 struct sockaddr dst;
381 int len, error;
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)
386 return (EINVAL);
387 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
388 return EIO;
389 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
390 uio->uio_resid < PPP_HDRLEN)
391 return (EMSGSIZE);
392 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
393 MGET(m, M_WAIT, MT_DATA);
394 if ((*mp = m) == NULL) {
395 m_freem(m0);
396 return (ENOBUFS);
398 m->m_len = 0;
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) {
405 m_freem(m0);
406 return (error);
408 m->m_len = len;
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.
422 /* ARGSUSED */
424 ppptioctl(tp, cmd, data, flag, p)
425 struct tty *tp;
426 int cmd;
427 caddr_t data;
428 int flag;
429 struct proc *p;
431 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
432 int error, s;
434 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
435 return -1;
437 error = 0;
438 switch (cmd) {
439 case PPPIOCSASYNCMAP:
440 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
441 break;
442 sc->sc_asyncmap[0] = *(u_int *)data;
443 break;
445 case PPPIOCGASYNCMAP:
446 *(u_int *)data = sc->sc_asyncmap[0];
447 break;
449 case PPPIOCSRASYNCMAP:
450 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
451 break;
452 sc->sc_rasyncmap = *(u_int *)data;
453 break;
455 case PPPIOCGRASYNCMAP:
456 *(u_int *)data = sc->sc_rasyncmap;
457 break;
459 case PPPIOCSXASYNCMAP:
460 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
461 break;
462 s = spltty();
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 */
467 splx(s);
468 break;
470 case PPPIOCGXASYNCMAP:
471 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
472 break;
474 default:
475 error = pppioctl(sc, cmd, data, flag, p);
476 if (error == 0 && cmd == PPPIOCSMRU)
477 pppgetm(sc);
480 return error;
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.
524 static u_short
525 pppfcs(fcs, cp, len)
526 register u_short fcs;
527 register u_char *cp;
528 register int len;
530 while (len--)
531 fcs = PPP_FCS(fcs, *cp++);
532 return (fcs);
536 * This gets called at splsoftnet from if_ppp.c at various times
537 * when there is data ready to be sent.
539 static void
540 pppasyncstart(sc)
541 register struct ppp_softc *sc;
543 register struct tty *tp = (struct tty *) sc->sc_devp;
544 register struct mbuf *m;
545 register int len;
546 register u_char *start, *stop, *cp;
547 int n, ndone, done, idle;
548 struct mbuf *m2;
549 int s;
551 idle = 0;
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.
557 m = sc->sc_outm;
558 if (m == NULL) {
560 * Get another packet to be sent.
562 m = ppp_dequeue(sc);
563 if (m == NULL) {
564 idle = 1;
565 break;
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;
583 for (;;) {
584 start = mtod(m, u_char *);
585 len = m->m_len;
586 stop = start + len;
587 while (len > 0) {
589 * Find out how many bytes in the string we can
590 * handle without doing something special.
592 for (cp = start; cp < stop; cp++)
593 if (ESCAPE_P(*cp))
594 break;
595 n = cp - start;
596 if (n) {
597 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
598 ndone = n - b_to_q(start, n, &tp->t_outq);
599 len -= ndone;
600 start += ndone;
601 sc->sc_stats.ppp_obytes += ndone;
603 if (ndone < n)
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.
611 if (len) {
612 s = spltty();
613 if (putc(PPP_ESCAPE, &tp->t_outq))
614 break;
615 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
616 (void) unputc(&tp->t_outq);
617 splx(s);
618 break;
620 splx(s);
621 sc->sc_stats.ppp_obytes += 2;
622 start++;
623 len--;
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.
633 done = len == 0;
634 if (done && m->m_next == NULL) {
635 u_char *p, *q;
636 int c;
637 u_char endseq[8];
640 * We may have to escape the bytes in the FCS.
642 p = endseq;
643 c = ~sc->sc_outfcs & 0xFF;
644 if (ESCAPE_P(c)) {
645 *p++ = PPP_ESCAPE;
646 *p++ = c ^ PPP_TRANS;
647 } else
648 *p++ = c;
649 c = (~sc->sc_outfcs >> 8) & 0xFF;
650 if (ESCAPE_P(c)) {
651 *p++ = PPP_ESCAPE;
652 *p++ = c ^ PPP_TRANS;
653 } else
654 *p++ = c;
655 *p++ = PPP_FLAG;
658 * Try to output the FCS and flag. If the bytes
659 * don't all fit, back out.
661 s = spltty();
662 for (q = endseq; q < p; ++q)
663 if (putc(*q, &tp->t_outq)) {
664 done = 0;
665 for (; q > endseq; --q)
666 unputc(&tp->t_outq);
667 break;
669 splx(s);
670 if (done)
671 sc->sc_stats.ppp_obytes += q - endseq;
674 if (!done) {
675 /* remember where we got to */
676 m->m_data = start;
677 m->m_len = len;
678 break;
681 /* Finished with this mbuf; free it and move on. */
682 MFREE(m, m2);
683 m = m2;
684 if (m == NULL) {
685 /* Finished a packet */
686 break;
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.
696 sc->sc_outm = m;
697 if (m)
698 break;
701 /* Call pppstart to start output again if necessary. */
702 s = spltty();
703 pppstart(tp);
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;
715 splx(s);
719 * This gets called when a received packet is placed on
720 * the inq, at splsoftnet.
722 static void
723 pppasyncctlp(sc)
724 struct ppp_softc *sc;
726 struct tty *tp;
727 int s;
729 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
730 s = spltty();
731 tp = (struct tty *) sc->sc_devp;
732 putc(0, &tp->t_canq);
733 ttwakeup(tp);
734 splx(s);
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.
744 pppstart(tp)
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)
754 (*tp->t_oproc)(tp);
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) {
764 ppp_restart(sc);
767 return 0;
771 * Timeout routine - try to start some more output.
773 static void
774 ppp_timeout(x)
775 void *x;
777 struct ppp_softc *sc = (struct ppp_softc *) x;
778 struct tty *tp = (struct tty *) sc->sc_devp;
779 int s;
781 s = spltty();
782 sc->sc_flags &= ~SC_TIMEOUT;
783 pppstart(tp);
784 splx(s);
788 * Allocate enough mbuf to handle current MRU.
790 static void
791 pppgetm(sc)
792 register struct ppp_softc *sc;
794 struct mbuf *m, **mp;
795 int len;
797 mp = &sc->sc_m;
798 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
799 if ((m = *mp) == NULL) {
800 MGETHDR(m, M_DONTWAIT, MT_DATA);
801 if (m == NULL)
802 break;
803 *mp = m;
804 MCLGET(m, M_DONTWAIT);
806 len -= M_DATASIZE(m);
807 mp = &m->m_next;
812 * tty interface receiver interrupt.
814 static unsigned paritytab[8] = {
815 0x96696996, 0x69969669, 0x69969669, 0x96696996,
816 0x69969669, 0x96696996, 0x96696996, 0x69969669
820 pppinput(c, tp)
821 int c;
822 register struct tty *tp;
824 register struct ppp_softc *sc;
825 struct mbuf *m;
826 int ilen, s;
828 sc = (struct ppp_softc *) tp->t_sc;
829 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
830 return 0;
832 ++tk_nin;
833 ++sc->sc_stats.ppp_ibytes;
835 if (c & TTY_FE) {
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);
839 goto flush;
842 c &= 0xff;
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);
853 return 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)
858 (*tp->t_oproc)(tp);
859 return 0;
863 s = spltty();
864 if (c & 0x80)
865 sc->sc_flags |= SC_RCV_B7_1;
866 else
867 sc->sc_flags |= SC_RCV_B7_0;
868 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
869 sc->sc_flags |= SC_RCV_ODDP;
870 else
871 sc->sc_flags |= SC_RCV_EVNP;
872 splx(s);
874 if (sc->sc_flags & SC_LOG_RAWIN)
875 ppplogchar(sc, c);
877 if (c == PPP_FLAG) {
878 ilen = sc->sc_ilen;
879 sc->sc_ilen = 0;
881 if (sc->sc_rawin_count > 0)
882 ppplogchar(sc, -1);
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)) {
890 s = spltty();
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++;
898 } else
899 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
900 splx(s);
901 return 0;
904 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
905 if (ilen) {
906 if (sc->sc_flags & SC_DEBUG)
907 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
908 s = spltty();
909 sc->sc_if.if_ierrors++;
910 sc->sc_stats.ppp_ierrors++;
911 sc->sc_flags |= SC_PKTLOST;
912 splx(s);
914 return 0;
918 * Remove FCS trailer. Somewhat painful...
920 ilen -= 2;
921 if (--sc->sc_mc->m_len == 0) {
922 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
924 sc->sc_mc = m;
926 sc->sc_mc->m_len--;
928 /* excise this mbuf chain */
929 m = sc->sc_m;
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) {
935 s = spltty();
936 sc->sc_flags &= ~SC_PKTLOST;
937 splx(s);
940 pppgetm(sc);
941 return 0;
944 if (sc->sc_flags & SC_FLUSH) {
945 if (sc->sc_flags & SC_LOG_FLUSH)
946 ppplogchar(sc, c);
947 return 0;
950 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
951 return 0;
953 s = spltty();
954 if (sc->sc_flags & SC_ESCAPED) {
955 sc->sc_flags &= ~SC_ESCAPED;
956 c ^= PPP_TRANS;
957 } else if (c == PPP_ESCAPE) {
958 sc->sc_flags |= SC_ESCAPED;
959 splx(s);
960 return 0;
962 splx(s);
965 * Initialize buffer on first octet received.
966 * First octet could be address or protocol (when compressing
967 * address/control).
968 * Second octet is control.
969 * Third octet is first or second (when compressing protocol)
970 * octet of 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) {
976 pppgetm(sc);
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);
980 goto flush;
983 m = sc->sc_m;
984 m->m_len = 0;
985 m->m_data = M_DATASTART(sc->sc_m);
986 sc->sc_mc = 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);
994 goto flush;
996 *sc->sc_mp++ = PPP_ALLSTATIONS;
997 *sc->sc_mp++ = PPP_UI;
998 sc->sc_ilen += 2;
999 m->m_len += 2;
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);
1006 goto flush;
1008 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1009 /* a compressed protocol */
1010 *sc->sc_mp++ = 0;
1011 sc->sc_ilen++;
1012 sc->sc_mc->m_len++;
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);
1018 goto flush;
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);
1025 goto flush;
1028 /* is this mbuf full? */
1029 m = sc->sc_mc;
1030 if (M_TRAILINGSPACE(m) <= 0) {
1031 if (m->m_next == NULL) {
1032 pppgetm(sc);
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);
1036 goto flush;
1039 sc->sc_mc = m = m->m_next;
1040 m->m_len = 0;
1041 m->m_data = M_DATASTART(m);
1042 sc->sc_mp = mtod(m, char *);
1045 ++m->m_len;
1046 *sc->sc_mp++ = c;
1047 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1048 return 0;
1050 flush:
1051 if (!(sc->sc_flags & SC_FLUSH)) {
1052 s = spltty();
1053 sc->sc_if.if_ierrors++;
1054 sc->sc_stats.ppp_ierrors++;
1055 sc->sc_flags |= SC_FLUSH;
1056 splx(s);
1057 if (sc->sc_flags & SC_LOG_FLUSH)
1058 ppplogchar(sc, c);
1060 return 0;
1063 #define MAX_DUMP_BYTES 128
1065 static void
1066 ppplogchar(sc, c)
1067 struct ppp_softc *sc;
1068 int c;
1070 if (c >= 0)
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;
1080 static void
1081 pppdumpb(b, l)
1082 u_char *b;
1083 int l;
1085 char buf[3*MAX_DUMP_BYTES+4];
1086 char *bp = buf;
1087 static char digits[] = "0123456789abcdef";
1089 while (l--) {
1090 if (bp >= buf + sizeof(buf) - 3) {
1091 *bp++ = '>';
1092 break;
1094 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1095 *bp++ = digits[*b++ & 0xf];
1096 *bp++ = ' ';
1099 *bp = 0;
1100 printf("%s\n", buf);
1103 #endif /* NPPP > 0 */