]> git.ozlabs.org Git - ppp.git/blob - freebsd-2.0/ppp_tty.c
clock32_t is clock_t (long)
[ppp.git] / freebsd-2.0 / ppp_tty.c
1 /*
2  * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
3  *             tty devices.
4  *
5  * Copyright (c) 1989 Carnegie Mellon University.
6  * All rights reserved.
7  *
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.
19  *
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
26  *
27  * Based on:
28  *      @(#)if_sl.c     7.6.1.2 (Berkeley) 2/15/89
29  *
30  * Copyright (c) 1987 Regents of the University of California.
31  * All rights reserved.
32  *
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.
44  *
45  * Serial Line interface
46  *
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
54  *
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.
58  *
59  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
60  * Added VJ tcp header compression; more unified ioctls
61  *
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.
67  *
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).
71  */
72
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 */
76
77 #include "ppp.h"
78 #if NPPP > 0
79
80 #define VJC
81 #define PPP_COMPRESS
82
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>
95
96 #include <net/if.h>
97 #include <net/if_types.h>
98
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
105
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>
112
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));
122
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));
131
132 /*
133  * Some useful mbuf macros not in mbuf.h.
134  */
135 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
136
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)
140
141 #define M_DATASIZE(m)   \
142         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
143             (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
144
145 /*
146  * Does c need to be escaped?
147  */
148 #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
149
150 /*
151  * Procedures for using an async tty interface for PPP.
152  */
153
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 */
158
159 /*
160  * Define the PPP line discipline.
161  */
162
163 static struct linesw pppdisc = {
164         pppopen, pppclose, pppread, pppwrite, ppptioctl,
165         pppinput, pppstart, ttymodem
166 };
167
168 void
169 pppasyncattach()
170 {
171     linesw[PPPDISC] = pppdisc;
172 }
173
174 TEXT_SET(pseudo_set, pppasyncattach);
175
176 /*
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.
180  */
181 /* ARGSUSED */
182 int
183 pppopen(dev, tp)
184     dev_t dev;
185     register struct tty *tp;
186 {
187     struct proc *p = curproc;           /* XXX */
188     register struct ppp_softc *sc;
189     int error, s;
190
191     if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
192         return (error);
193
194     s = spltty();
195
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);
201         }
202     }
203
204     if ((sc = pppalloc(p->p_pid)) == NULL) {
205         splx(s);
206         return ENXIO;
207     }
208
209     if (sc->sc_relinq)
210         (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
211
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;
226
227     tp->t_sc = (caddr_t) sc;
228     ttyflush(tp, FREAD | FWRITE);
229
230     splx(s);
231     return (0);
232 }
233
234 /*
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().
239  */
240 int
241 pppclose(tp, flag)
242     struct tty *tp;
243     int flag;
244 {
245     register struct ppp_softc *sc;
246     int s;
247
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);
257         }
258     }
259     splx(s);
260     return 0;
261 }
262
263 /*
264  * Relinquish the interface unit to another device.
265  */
266 static void
267 pppasyncrelinq(sc)
268     struct ppp_softc *sc;
269 {
270     int s;
271
272     s = spltty();
273     if (sc->sc_outm) {
274         m_freem(sc->sc_outm);
275         sc->sc_outm = NULL;
276     }
277     if (sc->sc_m) {
278         m_freem(sc->sc_m);
279         sc->sc_m = NULL;
280     }
281     if (sc->sc_flags & SC_TIMEOUT) {
282         untimeout(ppp_timeout, (void *) sc);
283         sc->sc_flags &= ~SC_TIMEOUT;
284     }
285     splx(s);
286 }
287
288 /*
289  * Line specific (tty) read routine.
290  */
291 int
292 pppread(tp, uio, flag)
293     register struct tty *tp;
294     struct uio *uio;
295     int flag;
296 {
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;
301
302     if (sc == NULL)
303         return 0;
304     /*
305      * Loop waiting for input, checking that nothing disasterous
306      * happens in the meantime.
307      */
308     s = spltty();
309     for (;;) {
310         if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
311             splx(s);
312             return 0;
313         }
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 */
320         }
321         if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
322             splx(s);
323             return (EWOULDBLOCK);
324         }
325         error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, "ttyin", 0);
326         if (error) {
327             splx(s);
328             return error;
329         }
330     }
331
332     /* Pull place-holder byte out of canonical queue */
333     getc(&tp->t_canq);
334
335     /* Get the packet from the input queue */
336     IF_DEQUEUE(&sc->sc_inq, m0);
337     splx(s);
338
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);
344 }
345
346 /*
347  * Line specific (tty) write routine.
348  */
349 int
350 pppwrite(tp, uio, flag)
351     register struct tty *tp;
352     struct uio *uio;
353     int flag;
354 {
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;
359
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);
374         }
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);
384         }
385         m->m_len = len;
386     }
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));
392 }
393
394 /*
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.
398  */
399 /* ARGSUSED */
400 int
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;
407 {
408     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
409     int error, s;
410
411     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
412         return -1;
413
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;
421
422     case PPPIOCGASYNCMAP:
423         *(u_int *)data = sc->sc_asyncmap[0];
424         break;
425
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;
431
432     case PPPIOCGRASYNCMAP:
433         *(u_int *)data = sc->sc_rasyncmap;
434         break;
435
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;
446
447     case PPPIOCGXASYNCMAP:
448         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
449         break;
450
451     default:
452         error = pppioctl(sc, cmd, data, flag, p);
453         if (error == 0 && cmd == PPPIOCSMRU)
454             pppgetm(sc);
455     }
456
457     return error;
458 }
459
460 /*
461  * FCS lookup table as calculated by genfcstab.
462  */
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
496 };
497
498 /*
499  * Calculate a new FCS given the current FCS and the new data.
500  */
501 static u_short
502 pppfcs(fcs, cp, len)
503     register u_short fcs;
504     register u_char *cp;
505     register int len;
506 {
507     while (len--)
508         fcs = PPP_FCS(fcs, *cp++);
509     return (fcs);
510 }
511
512 /*
513  * This gets called at splsoftnet from if_ppp.c at various times
514  * when there is data ready to be sent.
515  */
516 static void
517 pppasyncstart(sc)
518     register struct ppp_softc *sc;
519 {
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;
527
528     idle = 0;
529     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
530         /*
531          * See if we have an existing packet partly sent.
532          * If not, get a new packet and start sending it.
533          */
534         m = sc->sc_outm;
535         if (m == NULL) {
536             /*
537              * Get another packet to be sent.
538              */
539             m = ppp_dequeue(sc);
540             if (m == NULL) {
541                 idle = 1;
542                 break;
543             }
544
545             /*
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.
549              */
550             if (CCOUNT(&tp->t_outq) == 0) {
551                 ++sc->sc_stats.ppp_obytes;
552                 (void) putc(PPP_FLAG, &tp->t_outq);
553             }
554
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;
558         }
559
560         for (;;) {
561             start = mtod(m, u_char *);
562             len = m->m_len;
563             stop = start + len;
564             while (len > 0) {
565                 /*
566                  * Find out how many bytes in the string we can
567                  * handle without doing something special.
568                  */
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;
579
580                     if (ndone < n)
581                         break;  /* packet doesn't fit */
582                 }
583                 /*
584                  * If there are characters left in the mbuf,
585                  * the first one must be special.
586                  * Put it out in a different form.
587                  */
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;
596                     }
597                     splx(s);
598                     sc->sc_stats.ppp_obytes += 2;
599                     start++;
600                     len--;
601                 }
602             }
603
604             /*
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.
609              */
610             done = len == 0;
611             if (done && m->m_next == NULL) {
612                 u_char *p, *q;
613                 int c;
614                 u_char endseq[8];
615
616                 /*
617                  * We may have to escape the bytes in the FCS.
618                  */
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;
633
634                 /*
635                  * Try to output the FCS and flag.  If the bytes
636                  * don't all fit, back out.
637                  */
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;
645                     }
646                 splx(s);
647                 if (done)
648                     sc->sc_stats.ppp_obytes += q - endseq;
649             }
650
651             if (!done) {
652                 /* remember where we got to */
653                 m->m_data = start;
654                 m->m_len = len;
655                 break;
656             }
657
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;
664             }
665             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
666         }
667
668         /*
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.
672          */
673         sc->sc_outm = m;
674         if (m)
675             break;
676     }
677
678     /* Call pppstart to start output again if necessary. */
679     s = spltty();
680     pppstart(tp);
681
682     /*
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.
686      */
687     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
688         timeout(ppp_timeout, (void *) sc, 1);
689         sc->sc_flags |= SC_TIMEOUT;
690     }
691
692     splx(s);
693 }
694
695 /*
696  * This gets called when a received packet is placed on
697  * the inq, at splsoftnet.
698  */
699 static void
700 pppasyncctlp(sc)
701     struct ppp_softc *sc;
702 {
703     struct tty *tp;
704     int s;
705
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);
712 }
713
714 /*
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.
719  */
720 int
721 pppstart(tp)
722     register struct tty *tp;
723 {
724     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
725
726     /*
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.
729      */
730     if (tp->t_oproc != NULL)
731         (*tp->t_oproc)(tp);
732
733     /*
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.
737      */
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);
742     }
743
744     return 0;
745 }
746
747 /*
748  * Timeout routine - try to start some more output.
749  */
750 static void
751 ppp_timeout(x)
752     void *x;
753 {
754     struct ppp_softc *sc = (struct ppp_softc *) x;
755     struct tty *tp = (struct tty *) sc->sc_devp;
756     int s;
757
758     s = spltty();
759     sc->sc_flags &= ~SC_TIMEOUT;
760     pppstart(tp);
761     splx(s);
762 }
763
764 /*
765  * Allocate enough mbuf to handle current MRU.
766  */
767 static void
768 pppgetm(sc)
769     register struct ppp_softc *sc;
770 {
771     struct mbuf *m, **mp;
772     int len;
773
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);
782         }
783         len -= M_DATASIZE(m);
784         mp = &m->m_next;
785     }
786 }
787
788 /*
789  * tty interface receiver interrupt.
790  */
791 static unsigned paritytab[8] = {
792     0x96696996, 0x69969669, 0x69969669, 0x96696996,
793     0x69969669, 0x96696996, 0x96696996, 0x69969669
794 };
795
796 int
797 pppinput(c, tp)
798     int c;
799     register struct tty *tp;
800 {
801     register struct ppp_softc *sc;
802     struct mbuf *m;
803     int ilen, s;
804
805     sc = (struct ppp_softc *) tp->t_sc;
806     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
807         return 0;
808
809     ++tk_nin;
810     ++sc->sc_stats.ppp_ibytes;
811
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;
817     }
818
819     c &= 0xff;
820
821     /*
822      * Handle software flow control of output.
823      */
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);
829             }
830             return 0;
831         }
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;
837         }
838     }
839
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);
850
851     if (sc->sc_flags & SC_LOG_RAWIN)
852         ppplogchar(sc, c);
853
854     if (c == PPP_FLAG) {
855         ilen = sc->sc_ilen;
856         sc->sc_ilen = 0;
857
858         if (sc->sc_rawin_count > 0) 
859             ppplogchar(sc, -1);
860
861         /*
862          * If SC_ESCAPED is set, then we've seen the packet
863          * abort sequence "}~".
864          */
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;
879         }
880
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);
890             }
891             return 0;
892         }
893
894         /*
895          * Remove FCS trailer.  Somewhat painful...
896          */
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)
900                 ;
901             sc->sc_mc = m;
902         }
903         sc->sc_mc->m_len--;
904
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;
909
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);
915         }
916
917         pppgetm(sc);
918         return 0;
919     }
920
921     if (sc->sc_flags & SC_FLUSH) {
922         if (sc->sc_flags & SC_LOG_FLUSH)
923             ppplogchar(sc, c);
924         return 0;
925     }
926
927     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
928         return 0;
929
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;
938     }
939     splx(s);
940
941     /*
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.
949      */
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;
958             }
959         }
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;
972             }
973             *sc->sc_mp++ = PPP_ALLSTATIONS;
974             *sc->sc_mp++ = PPP_UI;
975             sc->sc_ilen += 2;
976             m->m_len += 2;
977         }
978     }
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;
984     }
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++;
990     }
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;
996     }
997
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;
1003     }
1004
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;
1014             }
1015         }
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 *);
1020     }
1021
1022     ++m->m_len;
1023     *sc->sc_mp++ = c;
1024     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1025     return 0;
1026
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);
1036     }
1037     return 0;
1038 }
1039
1040 #define MAX_DUMP_BYTES  128
1041
1042 static void
1043 ppplogchar(sc, c)
1044     struct ppp_softc *sc;
1045     int c;
1046 {
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;
1054     }
1055 }
1056
1057 static void
1058 pppdumpb(b, l)
1059     u_char *b;
1060     int l;
1061 {
1062     char buf[3*MAX_DUMP_BYTES+4];
1063     char *bp = buf;
1064     static char digits[] = "0123456789abcdef";
1065
1066     while (l--) {
1067         if (bp >= buf + sizeof(buf) - 3) {
1068             *bp++ = '>';
1069             break;
1070         }
1071         *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1072         *bp++ = digits[*b++ & 0xf];
1073         *bp++ = ' ';
1074     }
1075
1076     *bp = 0;
1077     printf("%s\n", buf);
1078 }
1079
1080 #endif  /* NPPP > 0 */