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