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