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