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