explain about behaviour when opening the device
[mpls-ppp.git] / freebsd-2.0 / ppp_tty.c
blob912f0831a27c7081ee9a8abbc2a86416154de7eb
1 /*
2 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
3 * tty devices.
5 * Copyright (c) 1989 Carnegie Mellon University.
6 * All rights reserved.
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.
20 * Drew D. Perkins
21 * Carnegie Mellon University
22 * 4910 Forbes Ave.
23 * Pittsburgh, PA 15213
24 * (412) 268-8576
25 * ddp@andrew.cmu.edu
27 * Based on:
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
47 * Rick Adams
48 * Center for Seismic Studies
49 * 1300 N 17th Street, Suite 1450
50 * Arlington, Virginia 22209
51 * (703)276-7900
52 * rick@seismo.ARPA
53 * seismo!rick
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 /* $Id: ppp_tty.c,v 1.8 1997/04/30 05:42:08 paulus Exp $ */
74 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
75 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
77 #include "ppp.h"
78 #if NPPP > 0
80 #define VJC
81 #define PPP_COMPRESS
83 #include <sys/param.h>
84 #include <sys/systm.h>
85 #include <sys/proc.h>
86 #include <sys/mbuf.h>
87 #include <sys/dkstat.h>
88 #include <sys/socket.h>
89 #include <sys/ioctl.h>
90 #include <sys/file.h>
91 #include <sys/tty.h>
92 #include <sys/kernel.h>
93 #include <sys/conf.h>
94 #include <sys/vnode.h>
96 #include <net/if.h>
97 #include <net/if_types.h>
99 #ifdef VJC
100 #include <netinet/in.h>
101 #include <netinet/in_systm.h>
102 #include <netinet/ip.h>
103 #include <net/pppcompress.h>
104 #endif
106 #ifdef PPP_FILTER
107 #include <net/bpf.h>
108 #endif
109 #include <net/ppp_defs.h>
110 #include <net/if_ppp.h>
111 #include <net/if_pppvar.h>
113 void pppasyncattach __P((void));
114 int pppopen __P((dev_t dev, struct tty *tp));
115 int pppclose __P((struct tty *tp, int flag));
116 int pppread __P((struct tty *tp, struct uio *uio, int flag));
117 int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
118 int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag,
119 struct proc *));
120 int pppinput __P((int c, struct tty *tp));
121 int pppstart __P((struct tty *tp));
123 static u_short pppfcs __P((u_short fcs, u_char *cp, int len));
124 static void pppasyncstart __P((struct ppp_softc *));
125 static void pppasyncctlp __P((struct ppp_softc *));
126 static void pppasyncrelinq __P((struct ppp_softc *));
127 static void ppp_timeout __P((void *));
128 static void pppgetm __P((struct ppp_softc *sc));
129 static void pppdumpb __P((u_char *b, int l));
130 static void ppplogchar __P((struct ppp_softc *, int));
133 * Some useful mbuf macros not in mbuf.h.
135 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
137 #define M_DATASTART(m) \
138 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
139 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
141 #define M_DATASIZE(m) \
142 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
143 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
146 * Does c need to be escaped?
148 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
151 * Procedures for using an async tty interface for PPP.
154 /* This is a FreeBSD-2.0 kernel. */
155 #define CCOUNT(q) ((q)->c_cc)
156 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
157 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
160 * Define the PPP line discipline.
163 static struct linesw pppdisc = {
164 pppopen, pppclose, pppread, pppwrite, ppptioctl,
165 pppinput, pppstart, ttymodem
168 void
169 pppasyncattach()
171 linesw[PPPDISC] = pppdisc;
174 TEXT_SET(pseudo_set, pppasyncattach);
177 * Line specific open routine for async tty devices.
178 * Attach the given tty to the first available ppp unit.
179 * Called from device open routine or ttioctl.
181 /* ARGSUSED */
183 pppopen(dev, tp)
184 dev_t dev;
185 register struct tty *tp;
187 struct proc *p = curproc; /* XXX */
188 register struct ppp_softc *sc;
189 int error, s;
191 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
192 return (error);
194 s = spltty();
196 if (tp->t_line == PPPDISC) {
197 sc = (struct ppp_softc *) tp->t_sc;
198 if (sc != NULL && sc->sc_devp == (void *) tp) {
199 splx(s);
200 return (0);
204 if ((sc = pppalloc(p->p_pid)) == NULL) {
205 splx(s);
206 return ENXIO;
209 if (sc->sc_relinq)
210 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
212 sc->sc_ilen = 0;
213 sc->sc_m = NULL;
214 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
215 sc->sc_asyncmap[0] = 0xffffffff;
216 sc->sc_asyncmap[3] = 0x60000000;
217 sc->sc_rasyncmap = 0;
218 sc->sc_devp = (void *) tp;
219 sc->sc_start = pppasyncstart;
220 sc->sc_ctlp = pppasyncctlp;
221 sc->sc_relinq = pppasyncrelinq;
222 sc->sc_outm = NULL;
223 pppgetm(sc);
224 sc->sc_if.if_flags |= IFF_RUNNING;
225 sc->sc_if.if_baudrate = tp->t_ospeed;
227 tp->t_sc = (caddr_t) sc;
228 ttyflush(tp, FREAD | FWRITE);
230 splx(s);
231 return (0);
235 * Line specific close routine, called from device close routine
236 * and from ttioctl.
237 * Detach the tty from the ppp unit.
238 * Mimics part of ttyclose().
241 pppclose(tp, flag)
242 struct tty *tp;
243 int flag;
245 register struct ppp_softc *sc;
246 int s;
248 s = spltty();
249 ttyflush(tp, FREAD|FWRITE);
250 tp->t_line = 0;
251 sc = (struct ppp_softc *) tp->t_sc;
252 if (sc != NULL) {
253 tp->t_sc = NULL;
254 if (tp == (struct tty *) sc->sc_devp) {
255 pppasyncrelinq(sc);
256 pppdealloc(sc);
259 splx(s);
260 return 0;
264 * Relinquish the interface unit to another device.
266 static void
267 pppasyncrelinq(sc)
268 struct ppp_softc *sc;
270 int s;
272 s = spltty();
273 if (sc->sc_outm) {
274 m_freem(sc->sc_outm);
275 sc->sc_outm = NULL;
277 if (sc->sc_m) {
278 m_freem(sc->sc_m);
279 sc->sc_m = NULL;
281 if (sc->sc_flags & SC_TIMEOUT) {
282 untimeout(ppp_timeout, (void *) sc);
283 sc->sc_flags &= ~SC_TIMEOUT;
285 splx(s);
289 * Line specific (tty) read routine.
292 pppread(tp, uio, flag)
293 register struct tty *tp;
294 struct uio *uio;
295 int flag;
297 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
298 struct mbuf *m, *m0;
299 register int s;
300 int error = 0;
302 if (sc == NULL)
303 return 0;
305 * Loop waiting for input, checking that nothing disasterous
306 * happens in the meantime.
308 s = spltty();
309 for (;;) {
310 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
311 splx(s);
312 return 0;
314 if (sc->sc_inq.ifq_head != NULL)
315 break;
316 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
317 && (tp->t_state & TS_ISOPEN)) {
318 splx(s);
319 return 0; /* end of file */
321 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
322 splx(s);
323 return (EWOULDBLOCK);
325 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, "ttyin", 0);
326 if (error) {
327 splx(s);
328 return error;
332 /* Pull place-holder byte out of canonical queue */
333 getc(&tp->t_canq);
335 /* Get the packet from the input queue */
336 IF_DEQUEUE(&sc->sc_inq, m0);
337 splx(s);
339 for (m = m0; m && uio->uio_resid; m = m->m_next)
340 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
341 break;
342 m_freem(m0);
343 return (error);
347 * Line specific (tty) write routine.
350 pppwrite(tp, uio, flag)
351 register struct tty *tp;
352 struct uio *uio;
353 int flag;
355 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
356 struct mbuf *m, *m0, **mp;
357 struct sockaddr dst;
358 int len, error;
360 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
361 return 0; /* wrote 0 bytes */
362 if (tp->t_line != PPPDISC)
363 return (EINVAL);
364 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
365 return EIO;
366 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
367 uio->uio_resid < PPP_HDRLEN)
368 return (EMSGSIZE);
369 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
370 MGET(m, M_WAIT, MT_DATA);
371 if ((*mp = m) == NULL) {
372 m_freem(m0);
373 return (ENOBUFS);
375 m->m_len = 0;
376 if (uio->uio_resid >= MCLBYTES / 2)
377 MCLGET(m, M_DONTWAIT);
378 len = M_TRAILINGSPACE(m);
379 if (len > uio->uio_resid)
380 len = uio->uio_resid;
381 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
382 m_freem(m0);
383 return (error);
385 m->m_len = len;
387 dst.sa_family = AF_UNSPEC;
388 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
389 m0->m_data += PPP_HDRLEN;
390 m0->m_len -= PPP_HDRLEN;
391 return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
395 * Line specific (tty) ioctl routine.
396 * This discipline requires that tty device drivers call
397 * the line specific l_ioctl routine from their ioctl routines.
399 /* ARGSUSED */
401 ppptioctl(tp, cmd, data, flag, p)
402 struct tty *tp;
403 int cmd;
404 caddr_t data;
405 int flag;
406 struct proc *p;
408 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
409 int error, s;
411 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
412 return -1;
414 error = 0;
415 switch (cmd) {
416 case PPPIOCSASYNCMAP:
417 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
418 break;
419 sc->sc_asyncmap[0] = *(u_int *)data;
420 break;
422 case PPPIOCGASYNCMAP:
423 *(u_int *)data = sc->sc_asyncmap[0];
424 break;
426 case PPPIOCSRASYNCMAP:
427 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
428 break;
429 sc->sc_rasyncmap = *(u_int *)data;
430 break;
432 case PPPIOCGRASYNCMAP:
433 *(u_int *)data = sc->sc_rasyncmap;
434 break;
436 case PPPIOCSXASYNCMAP:
437 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
438 break;
439 s = spltty();
440 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
441 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
442 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
443 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
444 splx(s);
445 break;
447 case PPPIOCGXASYNCMAP:
448 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
449 break;
451 default:
452 error = pppioctl(sc, cmd, data, flag, p);
453 if (error == 0 && cmd == PPPIOCSMRU)
454 pppgetm(sc);
457 return error;
461 * FCS lookup table as calculated by genfcstab.
463 static u_short fcstab[256] = {
464 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
465 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
466 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
467 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
468 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
469 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
470 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
471 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
472 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
473 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
474 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
475 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
476 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
477 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
478 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
479 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
480 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
481 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
482 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
483 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
484 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
485 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
486 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
487 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
488 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
489 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
490 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
491 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
492 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
493 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
494 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
495 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
499 * Calculate a new FCS given the current FCS and the new data.
501 static u_short
502 pppfcs(fcs, cp, len)
503 register u_short fcs;
504 register u_char *cp;
505 register int len;
507 while (len--)
508 fcs = PPP_FCS(fcs, *cp++);
509 return (fcs);
513 * This gets called at splsoftnet from if_ppp.c at various times
514 * when there is data ready to be sent.
516 static void
517 pppasyncstart(sc)
518 register struct ppp_softc *sc;
520 register struct tty *tp = (struct tty *) sc->sc_devp;
521 register struct mbuf *m;
522 register int len;
523 register u_char *start, *stop, *cp;
524 int n, ndone, done, idle;
525 struct mbuf *m2;
526 int s;
528 idle = 0;
529 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
531 * See if we have an existing packet partly sent.
532 * If not, get a new packet and start sending it.
534 m = sc->sc_outm;
535 if (m == NULL) {
537 * Get another packet to be sent.
539 m = ppp_dequeue(sc);
540 if (m == NULL) {
541 idle = 1;
542 break;
546 * The extra PPP_FLAG will start up a new packet, and thus
547 * will flush any accumulated garbage. We do this whenever
548 * the line may have been idle for some time.
550 if (CCOUNT(&tp->t_outq) == 0) {
551 ++sc->sc_stats.ppp_obytes;
552 (void) putc(PPP_FLAG, &tp->t_outq);
555 /* Calculate the FCS for the first mbuf's worth. */
556 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
557 sc->sc_if.if_lastchange = time;
560 for (;;) {
561 start = mtod(m, u_char *);
562 len = m->m_len;
563 stop = start + len;
564 while (len > 0) {
566 * Find out how many bytes in the string we can
567 * handle without doing something special.
569 for (cp = start; cp < stop; cp++)
570 if (ESCAPE_P(*cp))
571 break;
572 n = cp - start;
573 if (n) {
574 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
575 ndone = n - b_to_q(start, n, &tp->t_outq);
576 len -= ndone;
577 start += ndone;
578 sc->sc_stats.ppp_obytes += ndone;
580 if (ndone < n)
581 break; /* packet doesn't fit */
584 * If there are characters left in the mbuf,
585 * the first one must be special.
586 * Put it out in a different form.
588 if (len) {
589 s = spltty();
590 if (putc(PPP_ESCAPE, &tp->t_outq))
591 break;
592 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
593 (void) unputc(&tp->t_outq);
594 splx(s);
595 break;
597 splx(s);
598 sc->sc_stats.ppp_obytes += 2;
599 start++;
600 len--;
605 * If we didn't empty this mbuf, remember where we're up to.
606 * If we emptied the last mbuf, try to add the FCS and closing
607 * flag, and if we can't, leave sc_outm pointing to m, but with
608 * m->m_len == 0, to remind us to output the FCS and flag later.
610 done = len == 0;
611 if (done && m->m_next == NULL) {
612 u_char *p, *q;
613 int c;
614 u_char endseq[8];
617 * We may have to escape the bytes in the FCS.
619 p = endseq;
620 c = ~sc->sc_outfcs & 0xFF;
621 if (ESCAPE_P(c)) {
622 *p++ = PPP_ESCAPE;
623 *p++ = c ^ PPP_TRANS;
624 } else
625 *p++ = c;
626 c = (~sc->sc_outfcs >> 8) & 0xFF;
627 if (ESCAPE_P(c)) {
628 *p++ = PPP_ESCAPE;
629 *p++ = c ^ PPP_TRANS;
630 } else
631 *p++ = c;
632 *p++ = PPP_FLAG;
635 * Try to output the FCS and flag. If the bytes
636 * don't all fit, back out.
638 s = spltty();
639 for (q = endseq; q < p; ++q)
640 if (putc(*q, &tp->t_outq)) {
641 done = 0;
642 for (; q > endseq; --q)
643 unputc(&tp->t_outq);
644 break;
646 splx(s);
647 if (done)
648 sc->sc_stats.ppp_obytes += q - endseq;
651 if (!done) {
652 /* remember where we got to */
653 m->m_data = start;
654 m->m_len = len;
655 break;
658 /* Finished with this mbuf; free it and move on. */
659 MFREE(m, m2);
660 m = m2;
661 if (m == NULL) {
662 /* Finished a packet */
663 break;
665 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
669 * If m == NULL, we have finished a packet.
670 * If m != NULL, we've either done as much work this time
671 * as we need to, or else we've filled up the output queue.
673 sc->sc_outm = m;
674 if (m)
675 break;
678 /* Call pppstart to start output again if necessary. */
679 s = spltty();
680 pppstart(tp);
683 * This timeout is needed for operation on a pseudo-tty,
684 * because the pty code doesn't call pppstart after it has
685 * drained the t_outq.
687 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
688 timeout(ppp_timeout, (void *) sc, 1);
689 sc->sc_flags |= SC_TIMEOUT;
692 splx(s);
696 * This gets called when a received packet is placed on
697 * the inq, at splsoftnet.
699 static void
700 pppasyncctlp(sc)
701 struct ppp_softc *sc;
703 struct tty *tp;
704 int s;
706 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
707 s = spltty();
708 tp = (struct tty *) sc->sc_devp;
709 putc(0, &tp->t_canq);
710 ttwakeup(tp);
711 splx(s);
715 * Start output on async tty interface. If the transmit queue
716 * has drained sufficiently, arrange for pppasyncstart to be
717 * called later at splsoftnet.
718 * Called at spltty or higher.
721 pppstart(tp)
722 register struct tty *tp;
724 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
727 * If there is stuff in the output queue, send it now.
728 * We are being called in lieu of ttstart and must do what it would.
730 if (tp->t_oproc != NULL)
731 (*tp->t_oproc)(tp);
734 * If the transmit queue has drained and the tty has not hung up
735 * or been disconnected from the ppp unit, then tell if_ppp.c that
736 * we need more output.
738 if (CCOUNT(&tp->t_outq) < PPP_LOWAT
739 && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
740 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
741 ppp_restart(sc);
744 return 0;
748 * Timeout routine - try to start some more output.
750 static void
751 ppp_timeout(x)
752 void *x;
754 struct ppp_softc *sc = (struct ppp_softc *) x;
755 struct tty *tp = (struct tty *) sc->sc_devp;
756 int s;
758 s = spltty();
759 sc->sc_flags &= ~SC_TIMEOUT;
760 pppstart(tp);
761 splx(s);
765 * Allocate enough mbuf to handle current MRU.
767 static void
768 pppgetm(sc)
769 register struct ppp_softc *sc;
771 struct mbuf *m, **mp;
772 int len;
774 mp = &sc->sc_m;
775 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
776 if ((m = *mp) == NULL) {
777 MGETHDR(m, M_DONTWAIT, MT_DATA);
778 if (m == NULL)
779 break;
780 *mp = m;
781 MCLGET(m, M_DONTWAIT);
783 len -= M_DATASIZE(m);
784 mp = &m->m_next;
789 * tty interface receiver interrupt.
791 static unsigned paritytab[8] = {
792 0x96696996, 0x69969669, 0x69969669, 0x96696996,
793 0x69969669, 0x96696996, 0x96696996, 0x69969669
797 pppinput(c, tp)
798 int c;
799 register struct tty *tp;
801 register struct ppp_softc *sc;
802 struct mbuf *m;
803 int ilen, s;
805 sc = (struct ppp_softc *) tp->t_sc;
806 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
807 return 0;
809 ++tk_nin;
810 ++sc->sc_stats.ppp_ibytes;
812 if (c & TTY_FE) {
813 /* framing error or overrun on this char - abort packet */
814 if (sc->sc_flags & SC_DEBUG)
815 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
816 goto flush;
819 c &= 0xff;
822 * Handle software flow control of output.
824 if (tp->t_iflag & IXON) {
825 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
826 if ((tp->t_state & TS_TTSTOP) == 0) {
827 tp->t_state |= TS_TTSTOP;
828 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
830 return 0;
832 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
833 tp->t_state &= ~TS_TTSTOP;
834 if (tp->t_oproc != NULL)
835 (*tp->t_oproc)(tp);
836 return 0;
840 s = spltty();
841 if (c & 0x80)
842 sc->sc_flags |= SC_RCV_B7_1;
843 else
844 sc->sc_flags |= SC_RCV_B7_0;
845 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
846 sc->sc_flags |= SC_RCV_ODDP;
847 else
848 sc->sc_flags |= SC_RCV_EVNP;
849 splx(s);
851 if (sc->sc_flags & SC_LOG_RAWIN)
852 ppplogchar(sc, c);
854 if (c == PPP_FLAG) {
855 ilen = sc->sc_ilen;
856 sc->sc_ilen = 0;
858 if (sc->sc_rawin_count > 0)
859 ppplogchar(sc, -1);
862 * If SC_ESCAPED is set, then we've seen the packet
863 * abort sequence "}~".
865 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
866 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
867 s = spltty();
868 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
869 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
870 if (sc->sc_flags & SC_DEBUG)
871 printf("ppp%d: bad fcs %x, pkt len %d\n",
872 sc->sc_if.if_unit, sc->sc_fcs, ilen);
873 sc->sc_if.if_ierrors++;
874 sc->sc_stats.ppp_ierrors++;
875 } else
876 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
877 splx(s);
878 return 0;
881 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
882 if (ilen) {
883 if (sc->sc_flags & SC_DEBUG)
884 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
885 s = spltty();
886 sc->sc_if.if_ierrors++;
887 sc->sc_stats.ppp_ierrors++;
888 sc->sc_flags |= SC_PKTLOST;
889 splx(s);
891 return 0;
895 * Remove FCS trailer. Somewhat painful...
897 ilen -= 2;
898 if (--sc->sc_mc->m_len == 0) {
899 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
901 sc->sc_mc = m;
903 sc->sc_mc->m_len--;
905 /* excise this mbuf chain */
906 m = sc->sc_m;
907 sc->sc_m = sc->sc_mc->m_next;
908 sc->sc_mc->m_next = NULL;
910 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
911 if (sc->sc_flags & SC_PKTLOST) {
912 s = spltty();
913 sc->sc_flags &= ~SC_PKTLOST;
914 splx(s);
917 pppgetm(sc);
918 return 0;
921 if (sc->sc_flags & SC_FLUSH) {
922 if (sc->sc_flags & SC_LOG_FLUSH)
923 ppplogchar(sc, c);
924 return 0;
927 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
928 return 0;
930 s = spltty();
931 if (sc->sc_flags & SC_ESCAPED) {
932 sc->sc_flags &= ~SC_ESCAPED;
933 c ^= PPP_TRANS;
934 } else if (c == PPP_ESCAPE) {
935 sc->sc_flags |= SC_ESCAPED;
936 splx(s);
937 return 0;
939 splx(s);
942 * Initialize buffer on first octet received.
943 * First octet could be address or protocol (when compressing
944 * address/control).
945 * Second octet is control.
946 * Third octet is first or second (when compressing protocol)
947 * octet of protocol.
948 * Fourth octet is second octet of protocol.
950 if (sc->sc_ilen == 0) {
951 /* reset the first input mbuf */
952 if (sc->sc_m == NULL) {
953 pppgetm(sc);
954 if (sc->sc_m == NULL) {
955 if (sc->sc_flags & SC_DEBUG)
956 printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
957 goto flush;
960 m = sc->sc_m;
961 m->m_len = 0;
962 m->m_data = M_DATASTART(sc->sc_m);
963 sc->sc_mc = m;
964 sc->sc_mp = mtod(m, char *);
965 sc->sc_fcs = PPP_INITFCS;
966 if (c != PPP_ALLSTATIONS) {
967 if (sc->sc_flags & SC_REJ_COMP_AC) {
968 if (sc->sc_flags & SC_DEBUG)
969 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
970 sc->sc_if.if_unit, c);
971 goto flush;
973 *sc->sc_mp++ = PPP_ALLSTATIONS;
974 *sc->sc_mp++ = PPP_UI;
975 sc->sc_ilen += 2;
976 m->m_len += 2;
979 if (sc->sc_ilen == 1 && c != PPP_UI) {
980 if (sc->sc_flags & SC_DEBUG)
981 printf("ppp%d: missing UI (0x3), got 0x%x\n",
982 sc->sc_if.if_unit, c);
983 goto flush;
985 if (sc->sc_ilen == 2 && (c & 1) == 1) {
986 /* a compressed protocol */
987 *sc->sc_mp++ = 0;
988 sc->sc_ilen++;
989 sc->sc_mc->m_len++;
991 if (sc->sc_ilen == 3 && (c & 1) == 0) {
992 if (sc->sc_flags & SC_DEBUG)
993 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
994 (sc->sc_mp[-1] << 8) + c);
995 goto flush;
998 /* packet beyond configured mru? */
999 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1000 if (sc->sc_flags & SC_DEBUG)
1001 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
1002 goto flush;
1005 /* is this mbuf full? */
1006 m = sc->sc_mc;
1007 if (M_TRAILINGSPACE(m) <= 0) {
1008 if (m->m_next == NULL) {
1009 pppgetm(sc);
1010 if (m->m_next == NULL) {
1011 if (sc->sc_flags & SC_DEBUG)
1012 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1013 goto flush;
1016 sc->sc_mc = m = m->m_next;
1017 m->m_len = 0;
1018 m->m_data = M_DATASTART(m);
1019 sc->sc_mp = mtod(m, char *);
1022 ++m->m_len;
1023 *sc->sc_mp++ = c;
1024 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1025 return 0;
1027 flush:
1028 if (!(sc->sc_flags & SC_FLUSH)) {
1029 s = spltty();
1030 sc->sc_if.if_ierrors++;
1031 sc->sc_stats.ppp_ierrors++;
1032 sc->sc_flags |= SC_FLUSH;
1033 splx(s);
1034 if (sc->sc_flags & SC_LOG_FLUSH)
1035 ppplogchar(sc, c);
1037 return 0;
1040 #define MAX_DUMP_BYTES 128
1042 static void
1043 ppplogchar(sc, c)
1044 struct ppp_softc *sc;
1045 int c;
1047 if (c >= 0)
1048 sc->sc_rawin[sc->sc_rawin_count++] = c;
1049 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1050 || (c < 0 && sc->sc_rawin_count > 0)) {
1051 printf("ppp%d input: ", sc->sc_if.if_unit);
1052 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1053 sc->sc_rawin_count = 0;
1057 static void
1058 pppdumpb(b, l)
1059 u_char *b;
1060 int l;
1062 char buf[3*MAX_DUMP_BYTES+4];
1063 char *bp = buf;
1064 static char digits[] = "0123456789abcdef";
1066 while (l--) {
1067 if (bp >= buf + sizeof(buf) - 3) {
1068 *bp++ = '>';
1069 break;
1071 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1072 *bp++ = digits[*b++ & 0xf];
1073 *bp++ = ' ';
1076 *bp = 0;
1077 printf("%s\n", buf);
1080 #endif /* NPPP > 0 */