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