]> git.ozlabs.org Git - ppp.git/blob - freebsd-2.0/ppp_tty.c
mods from Steve Perkins
[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.7 1997/03/04 03:27:28 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 #include <net/ppp_defs.h>
107 #include <net/if_ppp.h>
108 #include <net/if_pppvar.h>
109
110 void    pppasyncattach __P((void));
111 int     pppopen __P((dev_t dev, struct tty *tp));
112 int     pppclose __P((struct tty *tp, int flag));
113 int     pppread __P((struct tty *tp, struct uio *uio, int flag));
114 int     pppwrite __P((struct tty *tp, struct uio *uio, int flag));
115 int     ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag,
116                        struct proc *));
117 int     pppinput __P((int c, struct tty *tp));
118 int     pppstart __P((struct tty *tp));
119
120 static u_short  pppfcs __P((u_short fcs, u_char *cp, int len));
121 static void     pppasyncstart __P((struct ppp_softc *));
122 static void     pppasyncctlp __P((struct ppp_softc *));
123 static void     pppasyncrelinq __P((struct ppp_softc *));
124 static void     ppp_timeout __P((void *));
125 static void     pppgetm __P((struct ppp_softc *sc));
126 static void     pppdumpb __P((u_char *b, int l));
127 static void     ppplogchar __P((struct ppp_softc *, int));
128
129 /*
130  * Some useful mbuf macros not in mbuf.h.
131  */
132 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
133
134 #define M_DATASTART(m)  \
135         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
136             (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
137
138 #define M_DATASIZE(m)   \
139         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
140             (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
141
142 /*
143  * Does c need to be escaped?
144  */
145 #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
146
147 /*
148  * Procedures for using an async tty interface for PPP.
149  */
150
151 /* This is a FreeBSD-2.0 kernel. */
152 #define CCOUNT(q)       ((q)->c_cc)
153 #define PPP_LOWAT       100     /* Process more output when < LOWAT on queue */
154 #define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
155
156 /*
157  * Define the PPP line discipline.
158  */
159
160 static struct linesw pppdisc = {
161         pppopen, pppclose, pppread, pppwrite, ppptioctl,
162         pppinput, pppstart, ttymodem
163 };
164
165 void
166 pppasyncattach()
167 {
168     linesw[PPPDISC] = pppdisc;
169 }
170
171 TEXT_SET(pseudo_set, pppasyncattach);
172
173 /*
174  * Line specific open routine for async tty devices.
175  * Attach the given tty to the first available ppp unit.
176  * Called from device open routine or ttioctl.
177  */
178 /* ARGSUSED */
179 int
180 pppopen(dev, tp)
181     dev_t dev;
182     register struct tty *tp;
183 {
184     struct proc *p = curproc;           /* XXX */
185     register struct ppp_softc *sc;
186     int error, s;
187
188     if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
189         return (error);
190
191     s = spltty();
192
193     if (tp->t_line == PPPDISC) {
194         sc = (struct ppp_softc *) tp->t_sc;
195         if (sc != NULL && sc->sc_devp == (void *) tp) {
196             splx(s);
197             return (0);
198         }
199     }
200
201     if ((sc = pppalloc(p->p_pid)) == NULL) {
202         splx(s);
203         return ENXIO;
204     }
205
206     if (sc->sc_relinq)
207         (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
208
209     sc->sc_ilen = 0;
210     sc->sc_m = NULL;
211     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
212     sc->sc_asyncmap[0] = 0xffffffff;
213     sc->sc_asyncmap[3] = 0x60000000;
214     sc->sc_rasyncmap = 0;
215     sc->sc_devp = (void *) tp;
216     sc->sc_start = pppasyncstart;
217     sc->sc_ctlp = pppasyncctlp;
218     sc->sc_relinq = pppasyncrelinq;
219     sc->sc_outm = NULL;
220     pppgetm(sc);
221     sc->sc_if.if_flags |= IFF_RUNNING;
222     sc->sc_if.if_baudrate = tp->t_ospeed;
223
224     tp->t_sc = (caddr_t) sc;
225     ttyflush(tp, FREAD | FWRITE);
226
227     splx(s);
228     return (0);
229 }
230
231 /*
232  * Line specific close routine, called from device close routine
233  * and from ttioctl.
234  * Detach the tty from the ppp unit.
235  * Mimics part of ttyclose().
236  */
237 int
238 pppclose(tp, flag)
239     struct tty *tp;
240     int flag;
241 {
242     register struct ppp_softc *sc;
243     int s;
244
245     s = spltty();
246     ttyflush(tp, FREAD|FWRITE);
247     tp->t_line = 0;
248     sc = (struct ppp_softc *) tp->t_sc;
249     if (sc != NULL) {
250         tp->t_sc = NULL;
251         if (tp == (struct tty *) sc->sc_devp) {
252             pppasyncrelinq(sc);
253             pppdealloc(sc);
254         }
255     }
256     splx(s);
257     return 0;
258 }
259
260 /*
261  * Relinquish the interface unit to another device.
262  */
263 static void
264 pppasyncrelinq(sc)
265     struct ppp_softc *sc;
266 {
267     int s;
268
269     s = spltty();
270     if (sc->sc_outm) {
271         m_freem(sc->sc_outm);
272         sc->sc_outm = NULL;
273     }
274     if (sc->sc_m) {
275         m_freem(sc->sc_m);
276         sc->sc_m = NULL;
277     }
278     if (sc->sc_flags & SC_TIMEOUT) {
279         untimeout(ppp_timeout, (void *) sc);
280         sc->sc_flags &= ~SC_TIMEOUT;
281     }
282     splx(s);
283 }
284
285 /*
286  * Line specific (tty) read routine.
287  */
288 int
289 pppread(tp, uio, flag)
290     register struct tty *tp;
291     struct uio *uio;
292     int flag;
293 {
294     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
295     struct mbuf *m, *m0;
296     register int s;
297     int error = 0;
298
299     if (sc == NULL)
300         return 0;
301     /*
302      * Loop waiting for input, checking that nothing disasterous
303      * happens in the meantime.
304      */
305     s = spltty();
306     for (;;) {
307         if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
308             splx(s);
309             return 0;
310         }
311         if (sc->sc_inq.ifq_head != NULL)
312             break;
313         if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
314             && (tp->t_state & TS_ISOPEN)) {
315             splx(s);
316             return 0;           /* end of file */
317         }
318         if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
319             splx(s);
320             return (EWOULDBLOCK);
321         }
322         error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, "ttyin", 0);
323         if (error) {
324             splx(s);
325             return error;
326         }
327     }
328
329     /* Pull place-holder byte out of canonical queue */
330     getc(&tp->t_canq);
331
332     /* Get the packet from the input queue */
333     IF_DEQUEUE(&sc->sc_inq, m0);
334     splx(s);
335
336     for (m = m0; m && uio->uio_resid; m = m->m_next)
337         if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
338             break;
339     m_freem(m0);
340     return (error);
341 }
342
343 /*
344  * Line specific (tty) write routine.
345  */
346 int
347 pppwrite(tp, uio, flag)
348     register struct tty *tp;
349     struct uio *uio;
350     int flag;
351 {
352     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
353     struct mbuf *m, *m0, **mp;
354     struct sockaddr dst;
355     int len, error;
356
357     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
358         return 0;               /* wrote 0 bytes */
359     if (tp->t_line != PPPDISC)
360         return (EINVAL);
361     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
362         return EIO;
363     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
364         uio->uio_resid < PPP_HDRLEN)
365         return (EMSGSIZE);
366     for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
367         MGET(m, M_WAIT, MT_DATA);
368         if ((*mp = m) == NULL) {
369             m_freem(m0);
370             return (ENOBUFS);
371         }
372         m->m_len = 0;
373         if (uio->uio_resid >= MCLBYTES / 2)
374             MCLGET(m, M_DONTWAIT);
375         len = M_TRAILINGSPACE(m);
376         if (len > uio->uio_resid)
377             len = uio->uio_resid;
378         if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
379             m_freem(m0);
380             return (error);
381         }
382         m->m_len = len;
383     }
384     dst.sa_family = AF_UNSPEC;
385     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
386     m0->m_data += PPP_HDRLEN;
387     m0->m_len -= PPP_HDRLEN;
388     return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
389 }
390
391 /*
392  * Line specific (tty) ioctl routine.
393  * This discipline requires that tty device drivers call
394  * the line specific l_ioctl routine from their ioctl routines.
395  */
396 /* ARGSUSED */
397 int
398 ppptioctl(tp, cmd, data, flag, p)
399     struct tty *tp;
400     int cmd;
401     caddr_t data;
402     int flag;
403     struct proc *p;
404 {
405     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
406     int error, s;
407
408     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
409         return -1;
410
411     error = 0;
412     switch (cmd) {
413     case PPPIOCSASYNCMAP:
414         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
415             break;
416         sc->sc_asyncmap[0] = *(u_int *)data;
417         break;
418
419     case PPPIOCGASYNCMAP:
420         *(u_int *)data = sc->sc_asyncmap[0];
421         break;
422
423     case PPPIOCSRASYNCMAP:
424         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
425             break;
426         sc->sc_rasyncmap = *(u_int *)data;
427         break;
428
429     case PPPIOCGRASYNCMAP:
430         *(u_int *)data = sc->sc_rasyncmap;
431         break;
432
433     case PPPIOCSXASYNCMAP:
434         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
435             break;
436         s = spltty();
437         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
438         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
439         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
440         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
441         splx(s);
442         break;
443
444     case PPPIOCGXASYNCMAP:
445         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
446         break;
447
448     default:
449         error = pppioctl(sc, cmd, data, flag, p);
450         if (error == 0 && cmd == PPPIOCSMRU)
451             pppgetm(sc);
452     }
453
454     return error;
455 }
456
457 /*
458  * FCS lookup table as calculated by genfcstab.
459  */
460 static u_short fcstab[256] = {
461         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
462         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
463         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
464         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
465         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
466         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
467         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
468         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
469         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
470         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
471         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
472         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
473         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
474         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
475         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
476         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
477         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
478         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
479         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
480         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
481         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
482         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
483         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
484         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
485         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
486         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
487         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
488         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
489         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
490         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
491         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
492         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
493 };
494
495 /*
496  * Calculate a new FCS given the current FCS and the new data.
497  */
498 static u_short
499 pppfcs(fcs, cp, len)
500     register u_short fcs;
501     register u_char *cp;
502     register int len;
503 {
504     while (len--)
505         fcs = PPP_FCS(fcs, *cp++);
506     return (fcs);
507 }
508
509 /*
510  * This gets called at splsoftnet from if_ppp.c at various times
511  * when there is data ready to be sent.
512  */
513 static void
514 pppasyncstart(sc)
515     register struct ppp_softc *sc;
516 {
517     register struct tty *tp = (struct tty *) sc->sc_devp;
518     register struct mbuf *m;
519     register int len;
520     register u_char *start, *stop, *cp;
521     int n, ndone, done, idle;
522     struct mbuf *m2;
523     int s;
524
525     idle = 0;
526     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
527         /*
528          * See if we have an existing packet partly sent.
529          * If not, get a new packet and start sending it.
530          */
531         m = sc->sc_outm;
532         if (m == NULL) {
533             /*
534              * Get another packet to be sent.
535              */
536             m = ppp_dequeue(sc);
537             if (m == NULL) {
538                 idle = 1;
539                 break;
540             }
541
542             /*
543              * The extra PPP_FLAG will start up a new packet, and thus
544              * will flush any accumulated garbage.  We do this whenever
545              * the line may have been idle for some time.
546              */
547             if (CCOUNT(&tp->t_outq) == 0) {
548                 ++sc->sc_stats.ppp_obytes;
549                 (void) putc(PPP_FLAG, &tp->t_outq);
550             }
551
552             /* Calculate the FCS for the first mbuf's worth. */
553             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
554             sc->sc_if.if_lastchange = time;
555         }
556
557         for (;;) {
558             start = mtod(m, u_char *);
559             len = m->m_len;
560             stop = start + len;
561             while (len > 0) {
562                 /*
563                  * Find out how many bytes in the string we can
564                  * handle without doing something special.
565                  */
566                 for (cp = start; cp < stop; cp++)
567                     if (ESCAPE_P(*cp))
568                         break;
569                 n = cp - start;
570                 if (n) {
571                     /* NetBSD (0.9 or later), 4.3-Reno or similar. */
572                     ndone = n - b_to_q(start, n, &tp->t_outq);
573                     len -= ndone;
574                     start += ndone;
575                     sc->sc_stats.ppp_obytes += ndone;
576
577                     if (ndone < n)
578                         break;  /* packet doesn't fit */
579                 }
580                 /*
581                  * If there are characters left in the mbuf,
582                  * the first one must be special.
583                  * Put it out in a different form.
584                  */
585                 if (len) {
586                     s = spltty();
587                     if (putc(PPP_ESCAPE, &tp->t_outq))
588                         break;
589                     if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
590                         (void) unputc(&tp->t_outq);
591                         splx(s);
592                         break;
593                     }
594                     splx(s);
595                     sc->sc_stats.ppp_obytes += 2;
596                     start++;
597                     len--;
598                 }
599             }
600
601             /*
602              * If we didn't empty this mbuf, remember where we're up to.
603              * If we emptied the last mbuf, try to add the FCS and closing
604              * flag, and if we can't, leave sc_outm pointing to m, but with
605              * m->m_len == 0, to remind us to output the FCS and flag later.
606              */
607             done = len == 0;
608             if (done && m->m_next == NULL) {
609                 u_char *p, *q;
610                 int c;
611                 u_char endseq[8];
612
613                 /*
614                  * We may have to escape the bytes in the FCS.
615                  */
616                 p = endseq;
617                 c = ~sc->sc_outfcs & 0xFF;
618                 if (ESCAPE_P(c)) {
619                     *p++ = PPP_ESCAPE;
620                     *p++ = c ^ PPP_TRANS;
621                 } else
622                     *p++ = c;
623                 c = (~sc->sc_outfcs >> 8) & 0xFF;
624                 if (ESCAPE_P(c)) {
625                     *p++ = PPP_ESCAPE;
626                     *p++ = c ^ PPP_TRANS;
627                 } else
628                     *p++ = c;
629                 *p++ = PPP_FLAG;
630
631                 /*
632                  * Try to output the FCS and flag.  If the bytes
633                  * don't all fit, back out.
634                  */
635                 s = spltty();
636                 for (q = endseq; q < p; ++q)
637                     if (putc(*q, &tp->t_outq)) {
638                         done = 0;
639                         for (; q > endseq; --q)
640                             unputc(&tp->t_outq);
641                         break;
642                     }
643                 splx(s);
644                 if (done)
645                     sc->sc_stats.ppp_obytes += q - endseq;
646             }
647
648             if (!done) {
649                 /* remember where we got to */
650                 m->m_data = start;
651                 m->m_len = len;
652                 break;
653             }
654
655             /* Finished with this mbuf; free it and move on. */
656             MFREE(m, m2);
657             m = m2;
658             if (m == NULL) {
659                 /* Finished a packet */
660                 break;
661             }
662             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
663         }
664
665         /*
666          * If m == NULL, we have finished a packet.
667          * If m != NULL, we've either done as much work this time
668          * as we need to, or else we've filled up the output queue.
669          */
670         sc->sc_outm = m;
671         if (m)
672             break;
673     }
674
675     /* Call pppstart to start output again if necessary. */
676     s = spltty();
677     pppstart(tp);
678
679     /*
680      * This timeout is needed for operation on a pseudo-tty,
681      * because the pty code doesn't call pppstart after it has
682      * drained the t_outq.
683      */
684     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
685         timeout(ppp_timeout, (void *) sc, 1);
686         sc->sc_flags |= SC_TIMEOUT;
687     }
688
689     splx(s);
690 }
691
692 /*
693  * This gets called when a received packet is placed on
694  * the inq, at splsoftnet.
695  */
696 static void
697 pppasyncctlp(sc)
698     struct ppp_softc *sc;
699 {
700     struct tty *tp;
701     int s;
702
703     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
704     s = spltty();
705     tp = (struct tty *) sc->sc_devp;
706     putc(0, &tp->t_canq);
707     ttwakeup(tp);
708     splx(s);
709 }
710
711 /*
712  * Start output on async tty interface.  If the transmit queue
713  * has drained sufficiently, arrange for pppasyncstart to be
714  * called later at splsoftnet.
715  * Called at spltty or higher.
716  */
717 int
718 pppstart(tp)
719     register struct tty *tp;
720 {
721     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
722
723     /*
724      * If there is stuff in the output queue, send it now.
725      * We are being called in lieu of ttstart and must do what it would.
726      */
727     if (tp->t_oproc != NULL)
728         (*tp->t_oproc)(tp);
729
730     /*
731      * If the transmit queue has drained and the tty has not hung up
732      * or been disconnected from the ppp unit, then tell if_ppp.c that
733      * we need more output.
734      */
735     if (CCOUNT(&tp->t_outq) < PPP_LOWAT
736         && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
737         && sc != NULL && tp == (struct tty *) sc->sc_devp) {
738         ppp_restart(sc);
739     }
740
741     return 0;
742 }
743
744 /*
745  * Timeout routine - try to start some more output.
746  */
747 static void
748 ppp_timeout(x)
749     void *x;
750 {
751     struct ppp_softc *sc = (struct ppp_softc *) x;
752     struct tty *tp = (struct tty *) sc->sc_devp;
753     int s;
754
755     s = spltty();
756     sc->sc_flags &= ~SC_TIMEOUT;
757     pppstart(tp);
758     splx(s);
759 }
760
761 /*
762  * Allocate enough mbuf to handle current MRU.
763  */
764 static void
765 pppgetm(sc)
766     register struct ppp_softc *sc;
767 {
768     struct mbuf *m, **mp;
769     int len;
770
771     mp = &sc->sc_m;
772     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
773         if ((m = *mp) == NULL) {
774             MGETHDR(m, M_DONTWAIT, MT_DATA);
775             if (m == NULL)
776                 break;
777             *mp = m;
778             MCLGET(m, M_DONTWAIT);
779         }
780         len -= M_DATASIZE(m);
781         mp = &m->m_next;
782     }
783 }
784
785 /*
786  * tty interface receiver interrupt.
787  */
788 static unsigned paritytab[8] = {
789     0x96696996, 0x69969669, 0x69969669, 0x96696996,
790     0x69969669, 0x96696996, 0x96696996, 0x69969669
791 };
792
793 int
794 pppinput(c, tp)
795     int c;
796     register struct tty *tp;
797 {
798     register struct ppp_softc *sc;
799     struct mbuf *m;
800     int ilen, s;
801
802     sc = (struct ppp_softc *) tp->t_sc;
803     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
804         return 0;
805
806     ++tk_nin;
807     ++sc->sc_stats.ppp_ibytes;
808
809     if (c & TTY_FE) {
810         /* framing error or overrun on this char - abort packet */
811         if (sc->sc_flags & SC_DEBUG)
812             printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
813         goto flush;
814     }
815
816     c &= 0xff;
817
818     /*
819      * Handle software flow control of output.
820      */
821     if (tp->t_iflag & IXON) {
822         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
823             if ((tp->t_state & TS_TTSTOP) == 0) {
824                 tp->t_state |= TS_TTSTOP;
825                 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
826             }
827             return 0;
828         }
829         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
830             tp->t_state &= ~TS_TTSTOP;
831             if (tp->t_oproc != NULL)
832                 (*tp->t_oproc)(tp);
833             return 0;
834         }
835     }
836
837     s = spltty();
838     if (c & 0x80)
839         sc->sc_flags |= SC_RCV_B7_1;
840     else
841         sc->sc_flags |= SC_RCV_B7_0;
842     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
843         sc->sc_flags |= SC_RCV_ODDP;
844     else
845         sc->sc_flags |= SC_RCV_EVNP;
846     splx(s);
847
848     if (sc->sc_flags & SC_LOG_RAWIN)
849         ppplogchar(sc, c);
850
851     if (c == PPP_FLAG) {
852         ilen = sc->sc_ilen;
853         sc->sc_ilen = 0;
854
855         if (sc->sc_rawin_count > 0) 
856             ppplogchar(sc, -1);
857
858         /*
859          * If SC_ESCAPED is set, then we've seen the packet
860          * abort sequence "}~".
861          */
862         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
863             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
864             s = spltty();
865             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
866             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
867                 if (sc->sc_flags & SC_DEBUG)
868                     printf("ppp%d: bad fcs %x, pkt len %d\n",
869                            sc->sc_if.if_unit, sc->sc_fcs, ilen);
870                 sc->sc_if.if_ierrors++;
871                 sc->sc_stats.ppp_ierrors++;
872             } else
873                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
874             splx(s);
875             return 0;
876         }
877
878         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
879             if (ilen) {
880                 if (sc->sc_flags & SC_DEBUG)
881                     printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
882                 s = spltty();
883                 sc->sc_if.if_ierrors++;
884                 sc->sc_stats.ppp_ierrors++;
885                 sc->sc_flags |= SC_PKTLOST;
886                 splx(s);
887             }
888             return 0;
889         }
890
891         /*
892          * Remove FCS trailer.  Somewhat painful...
893          */
894         ilen -= 2;
895         if (--sc->sc_mc->m_len == 0) {
896             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
897                 ;
898             sc->sc_mc = m;
899         }
900         sc->sc_mc->m_len--;
901
902         /* excise this mbuf chain */
903         m = sc->sc_m;
904         sc->sc_m = sc->sc_mc->m_next;
905         sc->sc_mc->m_next = NULL;
906
907         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
908         if (sc->sc_flags & SC_PKTLOST) {
909             s = spltty();
910             sc->sc_flags &= ~SC_PKTLOST;
911             splx(s);
912         }
913
914         pppgetm(sc);
915         return 0;
916     }
917
918     if (sc->sc_flags & SC_FLUSH) {
919         if (sc->sc_flags & SC_LOG_FLUSH)
920             ppplogchar(sc, c);
921         return 0;
922     }
923
924     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
925         return 0;
926
927     s = spltty();
928     if (sc->sc_flags & SC_ESCAPED) {
929         sc->sc_flags &= ~SC_ESCAPED;
930         c ^= PPP_TRANS;
931     } else if (c == PPP_ESCAPE) {
932         sc->sc_flags |= SC_ESCAPED;
933         splx(s);
934         return 0;
935     }
936     splx(s);
937
938     /*
939      * Initialize buffer on first octet received.
940      * First octet could be address or protocol (when compressing
941      * address/control).
942      * Second octet is control.
943      * Third octet is first or second (when compressing protocol)
944      * octet of protocol.
945      * Fourth octet is second octet of protocol.
946      */
947     if (sc->sc_ilen == 0) {
948         /* reset the first input mbuf */
949         if (sc->sc_m == NULL) {
950             pppgetm(sc);
951             if (sc->sc_m == NULL) {
952                 if (sc->sc_flags & SC_DEBUG)
953                     printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
954                 goto flush;
955             }
956         }
957         m = sc->sc_m;
958         m->m_len = 0;
959         m->m_data = M_DATASTART(sc->sc_m);
960         sc->sc_mc = m;
961         sc->sc_mp = mtod(m, char *);
962         sc->sc_fcs = PPP_INITFCS;
963         if (c != PPP_ALLSTATIONS) {
964             if (sc->sc_flags & SC_REJ_COMP_AC) {
965                 if (sc->sc_flags & SC_DEBUG)
966                     printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
967                            sc->sc_if.if_unit, c);
968                 goto flush;
969             }
970             *sc->sc_mp++ = PPP_ALLSTATIONS;
971             *sc->sc_mp++ = PPP_UI;
972             sc->sc_ilen += 2;
973             m->m_len += 2;
974         }
975     }
976     if (sc->sc_ilen == 1 && c != PPP_UI) {
977         if (sc->sc_flags & SC_DEBUG)
978             printf("ppp%d: missing UI (0x3), got 0x%x\n",
979                    sc->sc_if.if_unit, c);
980         goto flush;
981     }
982     if (sc->sc_ilen == 2 && (c & 1) == 1) {
983         /* a compressed protocol */
984         *sc->sc_mp++ = 0;
985         sc->sc_ilen++;
986         sc->sc_mc->m_len++;
987     }
988     if (sc->sc_ilen == 3 && (c & 1) == 0) {
989         if (sc->sc_flags & SC_DEBUG)
990             printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
991                    (sc->sc_mp[-1] << 8) + c);
992         goto flush;
993     }
994
995     /* packet beyond configured mru? */
996     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
997         if (sc->sc_flags & SC_DEBUG)
998             printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
999         goto flush;
1000     }
1001
1002     /* is this mbuf full? */
1003     m = sc->sc_mc;
1004     if (M_TRAILINGSPACE(m) <= 0) {
1005         if (m->m_next == NULL) {
1006             pppgetm(sc);
1007             if (m->m_next == NULL) {
1008                 if (sc->sc_flags & SC_DEBUG)
1009                     printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1010                 goto flush;
1011             }
1012         }
1013         sc->sc_mc = m = m->m_next;
1014         m->m_len = 0;
1015         m->m_data = M_DATASTART(m);
1016         sc->sc_mp = mtod(m, char *);
1017     }
1018
1019     ++m->m_len;
1020     *sc->sc_mp++ = c;
1021     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1022     return 0;
1023
1024  flush:
1025     if (!(sc->sc_flags & SC_FLUSH)) {
1026         s = spltty();
1027         sc->sc_if.if_ierrors++;
1028         sc->sc_stats.ppp_ierrors++;
1029         sc->sc_flags |= SC_FLUSH;
1030         splx(s);
1031         if (sc->sc_flags & SC_LOG_FLUSH)
1032             ppplogchar(sc, c);
1033     }
1034     return 0;
1035 }
1036
1037 #define MAX_DUMP_BYTES  128
1038
1039 static void
1040 ppplogchar(sc, c)
1041     struct ppp_softc *sc;
1042     int c;
1043 {
1044     if (c >= 0)
1045         sc->sc_rawin[sc->sc_rawin_count++] = c;
1046     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1047         || (c < 0 && sc->sc_rawin_count > 0)) {
1048         printf("ppp%d input: ", sc->sc_if.if_unit);
1049         pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1050         sc->sc_rawin_count = 0;
1051     }
1052 }
1053
1054 static void
1055 pppdumpb(b, l)
1056     u_char *b;
1057     int l;
1058 {
1059     char buf[3*MAX_DUMP_BYTES+4];
1060     char *bp = buf;
1061     static char digits[] = "0123456789abcdef";
1062
1063     while (l--) {
1064         if (bp >= buf + sizeof(buf) - 3) {
1065             *bp++ = '>';
1066             break;
1067         }
1068         *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1069         *bp++ = digits[*b++ & 0xf];
1070         *bp++ = ' ';
1071     }
1072
1073     *bp = 0;
1074     printf("%s\n", buf);
1075 }
1076
1077 #endif  /* NPPP > 0 */