fix prototypes & spls; added software flow control
[ppp.git] / ultrix / 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  * Ultrix port by Per Sundstrom <sundstrom@stkhlm.enet.dec.com>,
73  * Robert Olsson <robert@robur.slu.se> and Paul Mackerras.
74  */
75
76 /* $Id: ppp_tty.c,v 1.6 1995/10/27 04:00:10 paulus Exp $ */
77 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
78
79 #include "ppp.h"
80 #if NPPP > 0
81
82 #define VJC
83 #define PPP_COMPRESS
84
85 #include "../h/param.h"
86 #include "../h/user.h"
87 #include "../h/proc.h"
88 #include "../h/mbuf.h"
89 #include "../h/buf.h"
90 #include "../h/socket.h"
91 #include "../h/ioctl.h"
92 #include "../h/file.h"
93 #include "../h/tty.h"
94 #include "../h/kernel.h"
95 #include "../h/conf.h"
96 #include "../h/uio.h"
97 #include "../h/systm.h"
98
99 #include "../net/net/if.h"
100 #include "ppp_defs.h"
101
102 #ifdef VJC
103 #include "../net/netinet/in.h"
104 #include "../net/netinet/in_systm.h"
105 #include "../net/netinet/ip.h"
106 #include "slcompress.h"
107 #endif
108
109 #include "if_ppp.h"
110 #include "if_pppvar.h"
111
112 int     pppopen __P((dev_t dev, struct tty *tp));
113 int     pppclose __P((struct tty *tp, int flag));
114 int     pppread __P((struct tty *tp, struct uio *uio, int flag));
115 int     pppwrite __P((struct tty *tp, struct uio *uio, int flag));
116 int     ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag));
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_off > MMAXOFF)
133
134 #define M_TRAILINGSPACE(m) \
135         ((M_IS_CLUSTER(m) ? (u_int)(m)->m_clptr + M_CLUSTERSZ : MSIZE) \
136          - ((m)->m_off + (m)->m_len))
137
138 #define M_OFFSTART(m)   \
139         (M_IS_CLUSTER(m) ? (u_int)(m)->m_clptr : MMINOFF)
140
141 #define M_DATASIZE(m)   \
142         (M_IS_CLUSTER(m) ? M_CLUSTERSZ : MLEN)
143
144 /*
145  * Does c need to be escaped?
146  */
147 #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
148
149 /*
150  * Procedures for using an async tty interface for PPP.
151  */
152
153 /*
154  * This is an Ultrix kernel, we've got clists.
155  */
156 #define CCOUNT(q)       ((q)->c_cc)
157
158 #define t_sc            T_LINEP
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     register struct ppp_softc *sc;
173     int error, s, i;
174     struct proc *p = u.u_procp;
175
176     if (!suser())
177         return EPERM;
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
211     tp->t_sc = (caddr_t) sc;
212     ttyflush(tp, FREAD | FWRITE);
213
214     splx(s);
215     return (0);
216 }
217
218 /*
219  * Line specific close routine, called from device close routine
220  * and from ttioctl.
221  * Detach the tty from the ppp unit.
222  * Mimics part of ttyclose().
223  */
224 int
225 pppclose(tp, flag)
226     struct tty *tp;
227     int flag;
228 {
229     register struct ppp_softc *sc;
230     struct mbuf *m;
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 | TS_NBIO)) {
307             splx(s);
308             return (EWOULDBLOCK);
309         }
310         sleep((caddr_t) &tp->t_rawq, TTIPRI);
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_READ, uio))
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, *p;
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         if (uio->uio_resid >= CLBYTES / 2) {
357             MCLGET(m, p);
358         } else
359             m->m_len = MLEN;
360         len = MIN(m->m_len, uio->uio_resid);
361         if (error = uiomove(mtod(m, u_char *), len, UIO_WRITE, uio)) {
362             m_freem(m0);
363             return (error);
364         }
365         m->m_len = len;
366     }
367     dst.sa_family = AF_UNSPEC;
368     bcopy(mtod(m0, caddr_t), dst.sa_data, PPP_HDRLEN);
369     m0->m_off += PPP_HDRLEN;
370     m0->m_len -= PPP_HDRLEN;
371     return (pppoutput(&sc->sc_if, m0, &dst));
372 }
373
374 /*
375  * Line specific (tty) ioctl routine.
376  * This discipline requires that tty device drivers call
377  * the line specific l_ioctl routine from their ioctl routines.
378  */
379 /* ARGSUSED */
380 int
381 ppptioctl(tp, cmd, data, flag)
382     struct tty *tp;
383     caddr_t data;
384     int cmd, flag;
385 {
386     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
387     int error, s;
388
389     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
390         return -1;
391
392     error = 0;
393     switch (cmd) {
394     case PPPIOCSASYNCMAP:
395         if (!suser())
396             return EPERM;
397         sc->sc_asyncmap[0] = *(u_int *)data;
398         break;
399
400     case PPPIOCGASYNCMAP:
401         *(u_int *)data = sc->sc_asyncmap[0];
402         break;
403
404     case PPPIOCSRASYNCMAP:
405         if (!suser())
406             return EPERM;
407         sc->sc_rasyncmap = *(u_int *)data;
408         break;
409
410     case PPPIOCGRASYNCMAP:
411         *(u_int *)data = sc->sc_rasyncmap;
412         break;
413
414     case PPPIOCSXASYNCMAP:
415         if (!suser())
416             return EPERM;
417         s = spltty();
418         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
419         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
420         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
421         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
422         splx(s);
423         break;
424
425     case PPPIOCGXASYNCMAP:
426         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
427         break;
428
429     default:
430         error = pppioctl(sc, cmd, data, flag);
431         if (error == 0 && cmd == PPPIOCSMRU)
432             pppgetm(sc);
433     }
434
435     return error;
436 }
437
438 /*
439  * FCS lookup table as calculated by genfcstab.
440  */
441 static u_short fcstab[256] = {
442         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
443         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
444         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
445         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
446         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
447         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
448         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
449         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
450         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
451         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
452         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
453         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
454         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
455         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
456         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
457         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
458         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
459         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
460         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
461         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
462         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
463         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
464         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
465         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
466         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
467         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
468         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
469         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
470         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
471         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
472         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
473         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
474 };
475
476 /*
477  * Calculate a new FCS given the current FCS and the new data.
478  */
479 static u_short
480 pppfcs(fcs, cp, len)
481     register u_short fcs;
482     register u_char *cp;
483     register int len;
484 {
485     while (len--)
486         fcs = PPP_FCS(fcs, *cp++);
487     return (fcs);
488 }
489
490 /*
491  * This gets called from pppoutput when a new packet is
492  * put on a queue, at splnet.
493  */
494 static void
495 pppasyncstart(sc)
496     register struct ppp_softc *sc;
497 {
498     register struct tty *tp = (struct tty *) sc->sc_devp;
499     int s;
500
501     s = spltty();
502     pppstart(tp);
503     splx(s);
504 }
505
506 /*
507  * This gets called when a received packet is placed on
508  * the inq, at splnet.
509  */
510 static void
511 pppasyncctlp(sc)
512     struct ppp_softc *sc;
513 {
514     struct tty *tp;
515     int s;
516
517     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
518     s = spltty();
519     tp = (struct tty *) sc->sc_devp;
520     putc(0, &tp->t_canq);
521     ttwakeup(tp);
522     splx(s);
523 }
524
525 /*
526  * Start output on async tty interface.  Get another datagram
527  * to send from the interface queue and start sending it.
528  * Called at spltty or higher.
529  */
530 int
531 pppstart(tp)
532     register struct tty *tp;
533 {
534     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
535     register struct mbuf *m;
536     register int len;
537     register u_char *start, *stop, *cp;
538     int n, s, ndone, done, idle;
539     struct mbuf *m2;
540
541     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
542         || sc == NULL || tp != (struct tty *) sc->sc_devp) {
543         if (tp->t_oproc != NULL)
544             (*tp->t_oproc)(tp);
545         return 0;
546     }
547
548     idle = 0;
549     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
550         /*
551          * See if we have an existing packet partly sent.
552          * If not, get a new packet and start sending it.
553          */
554         m = sc->sc_outm;
555         if (m == NULL) {
556             /*
557              * Get another packet to be sent.
558              */
559             m = ppp_dequeue(sc);
560             if (m == NULL) {
561                 idle = 1;
562                 break;
563             }
564
565             /*
566              * The extra PPP_FLAG will start up a new packet, and thus
567              * will flush any accumulated garbage.  We do this whenever
568              * the line may have been idle for some time.
569              */
570             if (CCOUNT(&tp->t_outq) == 0) {
571                 ++sc->sc_bytessent;
572                 (void) putc(PPP_FLAG, &tp->t_outq);
573             }
574
575             /* Calculate the FCS for the first mbuf's worth. */
576             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
577         }
578
579         for (;;) {
580             start = mtod(m, u_char *);
581             len = m->m_len;
582             stop = start + len;
583             while (len > 0) {
584                 /*
585                  * Find out how many bytes in the string we can
586                  * handle without doing something special.
587                  */
588                 for (cp = start; cp < stop; cp++)
589                     if (ESCAPE_P(*cp))
590                         break;
591                 n = cp - start;
592                 if (n) {
593                     ndone = n - b_to_q(start, n, &tp->t_outq);
594                     len -= ndone;
595                     start += ndone;
596                     sc->sc_bytessent += ndone;
597
598                     if (ndone < n)
599                         break;  /* packet doesn't fit */
600                 }
601                 /*
602                  * If there are characters left in the mbuf,
603                  * the first one must be special..
604                  * Put it out in a different form.
605                  */
606                 if (len) {
607                     if (putc(PPP_ESCAPE, &tp->t_outq))
608                         break;
609                     if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
610                         (void) unputc(&tp->t_outq);
611                         break;
612                     }
613                     sc->sc_bytessent += 2;
614                     start++;
615                     len--;
616                 }
617             }
618
619             /*
620              * If we didn't empty this mbuf, remember where we're up to.
621              * If we emptied the last mbuf, try to add the FCS and closing
622              * flag, and if we can't, leave sc_outm pointing to m, but with
623              * m->m_len == 0, to remind us to output the FCS and flag later.
624              */
625             done = len == 0;
626             if (done && m->m_next == NULL) {
627                 u_char *p, *q;
628                 int c;
629                 u_char endseq[8];
630
631                 /*
632                  * We may have to escape the bytes in the FCS.
633                  */
634                 p = endseq;
635                 c = ~sc->sc_outfcs & 0xFF;
636                 if (ESCAPE_P(c)) {
637                     *p++ = PPP_ESCAPE;
638                     *p++ = c ^ PPP_TRANS;
639                 } else
640                     *p++ = c;
641                 c = (~sc->sc_outfcs >> 8) & 0xFF;
642                 if (ESCAPE_P(c)) {
643                     *p++ = PPP_ESCAPE;
644                     *p++ = c ^ PPP_TRANS;
645                 } else
646                     *p++ = c;
647                 *p++ = PPP_FLAG;
648
649                 /*
650                  * Try to output the FCS and flag.  If the bytes
651                  * don't all fit, back out.
652                  */
653                 for (q = endseq; q < p; ++q)
654                     if (putc(*q, &tp->t_outq)) {
655                         done = 0;
656                         for (; q > endseq; --q)
657                             unputc(&tp->t_outq);
658                         break;
659                     }
660                 sc->sc_bytessent += q - endseq;
661             }
662
663             if (!done) {
664                 m->m_off += m->m_len - len;
665                 m->m_len = len;
666                 break;
667             }
668
669             /* Finished with this mbuf; free it and move on. */
670             MFREE(m, m2);
671             m = m2;
672             if (m == NULL) {
673                 /* Finished a packet */
674                 sc->sc_if.if_opackets++;
675                 break;
676             }
677             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
678         }
679
680         /*
681          * Here we have either finished a packet (m == NULL)
682          * or filled up the output queue (m != NULL).
683          */
684         sc->sc_outm = m;
685         if (m)
686             break;
687     }
688
689     /*
690      * If there is stuff in the output queue, send it now.
691      * We are being called in lieu of ttstart and must do what it would.
692      */
693     if (tp->t_oproc != NULL)
694         (*tp->t_oproc)(tp);
695
696     /*
697      * This timeout is needed for operation on a pseudo-tty,
698      * because the pty code doesn't call pppstart after it has
699      * drained the t_outq.
700      */
701     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
702         timeout(ppp_timeout, (void *) sc, 1);
703         sc->sc_flags |= SC_TIMEOUT;
704     }
705
706     return 0;
707 }
708
709 /*
710  * Timeout routine - try to start some more output.
711  */
712 static void
713 ppp_timeout(x)
714     void *x;
715 {
716     struct ppp_softc *sc = (struct ppp_softc *) x;
717     struct tty *tp = (struct tty *) sc->sc_devp;
718     int s;
719
720     s = spltty();
721     sc->sc_flags &= ~SC_TIMEOUT;
722     pppstart(tp);
723     splx(s);
724 }
725
726 /*
727  * Allocate enough mbuf to handle current MRU.
728  */
729 static void
730 pppgetm(sc)
731     register struct ppp_softc *sc;
732 {
733     struct mbuf *m, **mp, *p;
734     int len;
735     int s;
736
737     s = spltty();
738     mp = &sc->sc_m;
739     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
740         if ((m = *mp) == NULL) {
741             MGET(m, M_DONTWAIT, MT_DATA);
742             if (m == NULL)
743                 break;
744             *mp = m;
745             MCLGET(m, p);
746         }
747         len -= M_DATASIZE(m);
748         mp = &m->m_next;
749     }
750     splx(s);
751 }
752
753 /*
754  * tty interface receiver interrupt.
755  */
756 static unsigned paritytab[8] = {
757     0x96696996, 0x69969669, 0x69969669, 0x96696996,
758     0x69969669, 0x96696996, 0x96696996, 0x69969669
759 };
760
761 int
762 pppinput(c, tp)
763     int c;
764     register struct tty *tp;
765 {
766     register struct ppp_softc *sc;
767     struct mbuf *m;
768     int ilen, s;
769     extern int tk_nin;
770
771     sc = (struct ppp_softc *) tp->t_sc;
772     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
773         return 0;
774
775     s = spltty();               /* should be unnecessary */
776     ++tk_nin;
777     ++sc->sc_bytesrcvd;
778
779     c &= 0xff;
780
781     if (sc->sc_flags & SC_XONXOFF) {
782         if (c == XOFF) {
783             if ((tp->t_state & TS_TTSTOP) == 0) {
784                 tp->t_state |= TS_TTSTOP;
785                 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
786             }
787             return 0;
788         }
789         if (c == XON) {
790             tp->t_state &= ~TS_TTSTOP;
791             if (tp->t_oproc != NULL)
792                 (*tp->t_oproc)(tp);
793             return 0;
794         }
795     }
796
797     if (c & 0x80)
798         sc->sc_flags |= SC_RCV_B7_1;
799     else
800         sc->sc_flags |= SC_RCV_B7_0;
801     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
802         sc->sc_flags |= SC_RCV_ODDP;
803     else
804         sc->sc_flags |= SC_RCV_EVNP;
805
806     if (sc->sc_flags & SC_LOG_RAWIN)
807         ppplogchar(sc, c);
808
809     if (c == PPP_FLAG) {
810         ilen = sc->sc_ilen;
811         sc->sc_ilen = 0;
812
813         if (sc->sc_rawin_count > 0) 
814             ppplogchar(sc, -1);
815
816         /*
817          * If SC_ESCAPED is set, then we've seen the packet
818          * abort sequence "}~".
819          */
820         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
821             || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
822             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
823             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
824                 if (sc->sc_flags & SC_DEBUG)
825                     printf("ppp%d: bad fcs %x\n", sc->sc_if.if_unit,
826                            sc->sc_fcs);
827                 sc->sc_if.if_ierrors++;
828             } else
829                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
830             splx(s);
831             return 0;
832         }
833
834         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
835             if (ilen) {
836                 if (sc->sc_flags & SC_DEBUG)
837                     printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
838                 sc->sc_if.if_ierrors++;
839                 sc->sc_flags |= SC_PKTLOST;
840             }
841             splx(s);
842             return 0;
843         }
844
845         /*
846          * Remove FCS trailer.  Somewhat painful...
847          */
848         ilen -= 2;
849         if (--sc->sc_mc->m_len == 0) {
850             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
851                 ;
852             sc->sc_mc = m;
853         }
854         sc->sc_mc->m_len--;
855
856         /* excise this mbuf chain */
857         m = sc->sc_m;
858         sc->sc_m = sc->sc_mc->m_next;
859         sc->sc_mc->m_next = NULL;
860
861         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
862         sc->sc_flags &= ~SC_PKTLOST;
863
864         pppgetm(sc);
865         splx(s);
866         return 0;
867     }
868
869     if (sc->sc_flags & SC_FLUSH) {
870         if (sc->sc_flags & SC_LOG_FLUSH)
871             ppplogchar(sc, c);
872         splx(s);
873         return 0;
874     }
875
876     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) {
877         splx(s);
878         return 0;
879     }
880
881     if (sc->sc_flags & SC_ESCAPED) {
882         sc->sc_flags &= ~SC_ESCAPED;
883         c ^= PPP_TRANS;
884     } else if (c == PPP_ESCAPE) {
885         sc->sc_flags |= SC_ESCAPED;
886         splx(s);
887         return 0;
888     }
889
890     /*
891      * Initialize buffer on first octet received.
892      * First octet could be address or protocol (when compressing
893      * address/control).
894      * Second octet is control.
895      * Third octet is first or second (when compressing protocol)
896      * octet of protocol.
897      * Fourth octet is second octet of protocol.
898      */
899     if (sc->sc_ilen == 0) {
900         /* reset the first input mbuf */
901         if (sc->sc_m == NULL) {
902             pppgetm(sc);
903             if (sc->sc_m == NULL) {
904                 if (sc->sc_flags & SC_DEBUG)
905                     printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
906                 goto flush;
907             }
908         }
909         m = sc->sc_m;
910         m->m_len = 0;
911         m->m_off = M_OFFSTART(m);
912         sc->sc_mc = m;
913         sc->sc_mp = mtod(m, char *);
914         sc->sc_fcs = PPP_INITFCS;
915         if (c != PPP_ALLSTATIONS) {
916             if (sc->sc_flags & SC_REJ_COMP_AC) {
917                 if (sc->sc_flags & SC_DEBUG)
918                     printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
919                            sc->sc_if.if_unit, c);
920                 goto flush;
921             }
922             *sc->sc_mp++ = PPP_ALLSTATIONS;
923             *sc->sc_mp++ = PPP_UI;
924             sc->sc_ilen += 2;
925             m->m_len += 2;
926         }
927     }
928     if (sc->sc_ilen == 1 && c != PPP_UI) {
929         if (sc->sc_flags & SC_DEBUG)
930             printf("ppp%d: missing UI (0x3), got 0x%x\n",
931                    sc->sc_if.if_unit, c);
932         goto flush;
933     }
934     if (sc->sc_ilen == 2 && (c & 1) == 1) {
935         /* a compressed protocol */
936         *sc->sc_mp++ = 0;
937         sc->sc_ilen++;
938         sc->sc_mc->m_len++;
939     }
940     if (sc->sc_ilen == 3 && (c & 1) == 0) {
941         if (sc->sc_flags & SC_DEBUG)
942             printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
943                    (sc->sc_mp[-1] << 8) + c);
944         goto flush;
945     }
946
947     /* packet beyond configured mru? */
948     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
949         if (sc->sc_flags & SC_DEBUG)
950             printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
951         goto flush;
952     }
953
954     /* is this mbuf full? */
955     m = sc->sc_mc;
956     if (M_TRAILINGSPACE(m) <= 0) {
957         if (m->m_next == NULL) {
958             pppgetm(sc);
959             if (m->m_next == NULL) {
960                 if (sc->sc_flags & SC_DEBUG)
961                     printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
962                 goto flush;
963             }
964         }
965         sc->sc_mc = m = m->m_next;
966         m->m_len = 0;
967         m->m_off = M_OFFSTART(m);
968         sc->sc_mp = mtod(m, char *);
969     }
970
971     ++m->m_len;
972     *sc->sc_mp++ = c;
973     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
974     splx(s);
975     return 0;
976
977  flush:
978     if (!(sc->sc_flags & SC_FLUSH)) {
979         sc->sc_if.if_ierrors++;
980         sc->sc_flags |= SC_FLUSH;
981         if (sc->sc_flags & SC_LOG_FLUSH)
982             ppplogchar(sc, c);
983     }
984     splx(s);
985     return 0;
986 }
987
988 #define MAX_DUMP_BYTES  128
989
990 static void
991 ppplogchar(sc, c)
992     struct ppp_softc *sc;
993     int c;
994 {
995     if (c >= 0)
996         sc->sc_rawin[sc->sc_rawin_count++] = c;
997     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
998         || c < 0 && sc->sc_rawin_count > 0) {
999         printf("ppp%d input: ", sc->sc_if.if_unit);
1000         pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1001         sc->sc_rawin_count = 0;
1002     }
1003 }
1004
1005 static void
1006 pppdumpb(b, l)
1007     u_char *b;
1008     int l;
1009 {
1010     char buf[3*MAX_DUMP_BYTES+4];
1011     char *bp = buf;
1012     static char digits[] = "0123456789abcdef";
1013
1014     while (l--) {
1015         if (bp >= buf + sizeof(buf) - 3) {
1016             *bp++ = '>';
1017             break;
1018         }
1019         *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1020         *bp++ = digits[*b++ & 0xf];
1021         *bp++ = ' ';
1022     }
1023
1024     *bp = 0;
1025     printf("%s\n", buf);
1026 }
1027
1028 #endif  /* NPPP > 0 */