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