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