mods from Steve Perkins
[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.8 1996/09/26 06:19:26 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 splnet.
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 splnet.
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     c &= 0xff;
790
791     /*
792      * Handle software flow control of output.
793      */
794     if (tp->t_iflag & IXON) {
795         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != 0) {
796             if ((tp->t_state & TS_TTSTOP) == 0) {
797                 tp->t_state |= TS_TTSTOP;
798                 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
799             }
800             return 0;
801         }
802         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != 0) {
803             tp->t_state &= ~TS_TTSTOP;
804             if (tp->t_oproc != NULL)
805                 (*tp->t_oproc)(tp);
806             return 0;
807         }
808     }
809
810     s = spltty();
811     if (c & 0x80)
812         sc->sc_flags |= SC_RCV_B7_1;
813     else
814         sc->sc_flags |= SC_RCV_B7_0;
815     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
816         sc->sc_flags |= SC_RCV_ODDP;
817     else
818         sc->sc_flags |= SC_RCV_EVNP;
819     splx(s);
820
821     if (sc->sc_flags & SC_LOG_RAWIN)
822         ppplogchar(sc, c);
823
824     if (c == PPP_FLAG) {
825         ilen = sc->sc_ilen;
826         sc->sc_ilen = 0;
827
828         if (sc->sc_rawin_count > 0) 
829             ppplogchar(sc, -1);
830
831         /*
832          * If SC_ESCAPED is set, then we've seen the packet
833          * abort sequence "}~".
834          */
835         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
836             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
837             s = spltty();
838             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
839             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
840                 if (sc->sc_flags & SC_DEBUG)
841                     printf("ppp%d: bad fcs %x, pkt len %d\n",
842                            sc->sc_if.if_unit, sc->sc_fcs, ilen);
843                 sc->sc_if.if_ierrors++;
844                 sc->sc_stats.ppp_ierrors++;
845             } else
846                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
847             splx(s);
848             return 0;
849         }
850
851         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
852             if (ilen) {
853                 if (sc->sc_flags & SC_DEBUG)
854                     printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
855                 s = spltty();
856                 sc->sc_if.if_ierrors++;
857                 sc->sc_stats.ppp_ierrors++;
858                 sc->sc_flags |= SC_PKTLOST;
859                 splx(s);
860             }
861             return 0;
862         }
863
864         /*
865          * Remove FCS trailer.  Somewhat painful...
866          */
867         ilen -= 2;
868         if (--sc->sc_mc->m_len == 0) {
869             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
870                 ;
871             sc->sc_mc = m;
872         }
873         sc->sc_mc->m_len--;
874
875         /* excise this mbuf chain */
876         m = sc->sc_m;
877         sc->sc_m = sc->sc_mc->m_next;
878         sc->sc_mc->m_next = NULL;
879
880         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
881         if (sc->sc_flags & SC_PKTLOST) {
882             s = spltty();
883             sc->sc_flags &= ~SC_PKTLOST;
884             splx(s);
885         }
886
887         pppgetm(sc);
888         return 0;
889     }
890
891     if (sc->sc_flags & SC_FLUSH) {
892         if (sc->sc_flags & SC_LOG_FLUSH)
893             ppplogchar(sc, c);
894         return 0;
895     }
896
897     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
898         return 0;
899
900     s = spltty();
901     if (sc->sc_flags & SC_ESCAPED) {
902         sc->sc_flags &= ~SC_ESCAPED;
903         c ^= PPP_TRANS;
904     } else if (c == PPP_ESCAPE) {
905         sc->sc_flags |= SC_ESCAPED;
906         splx(s);
907         return 0;
908     }
909     splx(s);
910
911     /*
912      * Initialize buffer on first octet received.
913      * First octet could be address or protocol (when compressing
914      * address/control).
915      * Second octet is control.
916      * Third octet is first or second (when compressing protocol)
917      * octet of protocol.
918      * Fourth octet is second octet of protocol.
919      */
920     if (sc->sc_ilen == 0) {
921         /* reset the first input mbuf */
922         if (sc->sc_m == NULL) {
923             pppgetm(sc);
924             if (sc->sc_m == NULL) {
925                 if (sc->sc_flags & SC_DEBUG)
926                     printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
927                 goto flush;
928             }
929         }
930         m = sc->sc_m;
931         m->m_len = 0;
932         m->m_off = M_OFFSTART(m);
933         sc->sc_mc = m;
934         sc->sc_mp = mtod(m, char *);
935         sc->sc_fcs = PPP_INITFCS;
936         if (c != PPP_ALLSTATIONS) {
937             if (sc->sc_flags & SC_REJ_COMP_AC) {
938                 if (sc->sc_flags & SC_DEBUG)
939                     printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
940                            sc->sc_if.if_unit, c);
941                 goto flush;
942             }
943             *sc->sc_mp++ = PPP_ALLSTATIONS;
944             *sc->sc_mp++ = PPP_UI;
945             sc->sc_ilen += 2;
946             m->m_len += 2;
947         }
948     }
949     if (sc->sc_ilen == 1 && c != PPP_UI) {
950         if (sc->sc_flags & SC_DEBUG)
951             printf("ppp%d: missing UI (0x3), got 0x%x\n",
952                    sc->sc_if.if_unit, c);
953         goto flush;
954     }
955     if (sc->sc_ilen == 2 && (c & 1) == 1) {
956         /* a compressed protocol */
957         *sc->sc_mp++ = 0;
958         sc->sc_ilen++;
959         sc->sc_mc->m_len++;
960     }
961     if (sc->sc_ilen == 3 && (c & 1) == 0) {
962         if (sc->sc_flags & SC_DEBUG)
963             printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
964                    (sc->sc_mp[-1] << 8) + c);
965         goto flush;
966     }
967
968     /* packet beyond configured mru? */
969     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
970         if (sc->sc_flags & SC_DEBUG)
971             printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
972         goto flush;
973     }
974
975     /* is this mbuf full? */
976     m = sc->sc_mc;
977     if (M_TRAILINGSPACE(m) <= 0) {
978         if (m->m_next == NULL) {
979             pppgetm(sc);
980             if (m->m_next == NULL) {
981                 if (sc->sc_flags & SC_DEBUG)
982                     printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
983                 goto flush;
984             }
985         }
986         sc->sc_mc = m = m->m_next;
987         m->m_len = 0;
988         m->m_off = M_OFFSTART(m);
989         sc->sc_mp = mtod(m, char *);
990     }
991
992     ++m->m_len;
993     *sc->sc_mp++ = c;
994     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
995     return 0;
996
997  flush:
998     if (!(sc->sc_flags & SC_FLUSH)) {
999         s = spltty();
1000         sc->sc_if.if_ierrors++;
1001         sc->sc_stats.ppp_ierrors++;
1002         sc->sc_flags |= SC_FLUSH;
1003         splx(s);
1004         if (sc->sc_flags & SC_LOG_FLUSH)
1005             ppplogchar(sc, c);
1006     }
1007     return 0;
1008 }
1009
1010 #define MAX_DUMP_BYTES  128
1011
1012 static void
1013 ppplogchar(sc, c)
1014     struct ppp_softc *sc;
1015     int c;
1016 {
1017     if (c >= 0)
1018         sc->sc_rawin[sc->sc_rawin_count++] = c;
1019     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1020         || (c < 0 && sc->sc_rawin_count > 0)) {
1021         printf("ppp%d input: ", sc->sc_if.if_unit);
1022         pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1023         sc->sc_rawin_count = 0;
1024     }
1025 }
1026
1027 static void
1028 pppdumpb(b, l)
1029     u_char *b;
1030     int l;
1031 {
1032     char buf[3*MAX_DUMP_BYTES+4];
1033     char *bp = buf;
1034     static char digits[] = "0123456789abcdef";
1035
1036     while (l--) {
1037         if (bp >= buf + sizeof(buf) - 3) {
1038             *bp++ = '>';
1039             break;
1040         }
1041         *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1042         *bp++ = digits[*b++ & 0xf];
1043         *bp++ = ' ';
1044     }
1045
1046     *bp = 0;
1047     printf("%s\n", buf);
1048 }
1049
1050 #endif  /* NPPP > 0 */