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