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