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