Reduce ifnet.if_serializer contention on output path:
[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.25 2008/05/14 11:59:23 sephe 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         if (mp == &m0) {
384                 MGETHDR(m, MB_WAIT, MT_DATA);
385                 m->m_pkthdr.len = uio->uio_resid - PPP_HDRLEN;
386                 m->m_pkthdr.rcvif = NULL;
387         } else {
388                 MGET(m, MB_WAIT, MT_DATA);
389         }
390         if ((*mp = m) == NULL) {
391             m_freem(m0);
392             crit_exit();
393             return (ENOBUFS);
394         }
395         m->m_len = 0;
396         if (uio->uio_resid >= MCLBYTES / 2)
397             MCLGET(m, MB_DONTWAIT);
398         len = M_TRAILINGSPACE(m);
399         if (len > uio->uio_resid)
400             len = uio->uio_resid;
401         if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
402             m_freem(m0);
403             crit_exit();
404             return (error);
405         }
406         m->m_len = len;
407     }
408     dst.sa_family = AF_UNSPEC;
409     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
410     m0->m_data += PPP_HDRLEN;
411     m0->m_len -= PPP_HDRLEN;
412
413     /* call the upper layer to "transmit" it... */
414     error = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0);
415     crit_exit();
416     return (error);
417 }
418
419 /*
420  * Line specific (tty) ioctl routine.
421  * This discipline requires that tty device drivers call
422  * the line specific l_ioctl routine from their ioctl routines.
423  */
424 /* ARGSUSED */
425 static int
426 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct ucred *cr)
427 {
428     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
429     int error;
430
431     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
432         return (ENOIOCTL);
433
434     error = 0;
435     switch (cmd) {
436     case PPPIOCSASYNCMAP:
437         if ((error = suser_cred(cr, 0)) != 0)
438             break;
439         sc->sc_asyncmap[0] = *(u_int *)data;
440         break;
441
442     case PPPIOCGASYNCMAP:
443         *(u_int *)data = sc->sc_asyncmap[0];
444         break;
445
446     case PPPIOCSRASYNCMAP:
447         if ((error = suser_cred(cr, 0)) != 0)
448             break;
449         sc->sc_rasyncmap = *(u_int *)data;
450         break;
451
452     case PPPIOCGRASYNCMAP:
453         *(u_int *)data = sc->sc_rasyncmap;
454         break;
455
456     case PPPIOCSXASYNCMAP:
457         if ((error = suser_cred(cr, 0)) != 0)
458             break;
459         crit_enter();
460         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
461         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
462         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
463         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
464         crit_exit();
465         break;
466
467     case PPPIOCGXASYNCMAP:
468         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
469         break;
470
471     default:
472         error = pppioctl(sc, cmd, data, flag, cr);
473         if (error == 0 && cmd == PPPIOCSMRU)
474             pppgetm(sc);
475     }
476
477     return error;
478 }
479
480 /*
481  * FCS lookup table as calculated by genfcstab.
482  */
483 static u_short fcstab[256] = {
484         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
485         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
486         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
487         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
488         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
489         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
490         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
491         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
492         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
493         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
494         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
495         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
496         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
497         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
498         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
499         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
500         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
501         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
502         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
503         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
504         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
505         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
506         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
507         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
508         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
509         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
510         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
511         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
512         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
513         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
514         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
515         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
516 };
517
518 /*
519  * Calculate a new FCS given the current FCS and the new data.
520  */
521 static u_short
522 pppfcs(u_short fcs, u_char *cp, int len)
523 {
524     while (len--)
525         fcs = PPP_FCS(fcs, *cp++);
526     return (fcs);
527 }
528
529 /*
530  * This gets called at splsoftnet from if_ppp.c at various times
531  * when there is data ready to be sent.
532  */
533 static void
534 pppasyncstart(struct ppp_softc *sc)
535 {
536     struct tty *tp = (struct tty *) sc->sc_devp;
537     struct mbuf *m;
538     int len;
539     u_char *start, *stop, *cp;
540     int n, ndone, done, idle;
541
542     idle = 0;
543     /* XXX assumes atomic access to *tp although we're not at spltty(). */
544     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
545         /*
546          * See if we have an existing packet partly sent.
547          * If not, get a new packet and start sending it.
548          */
549         m = sc->sc_outm;
550         if (m == NULL) {
551             /*
552              * Get another packet to be sent.
553              */
554             m = ppp_dequeue(sc);
555             if (m == NULL) {
556                 idle = 1;
557                 break;
558             }
559
560             /*
561              * The extra PPP_FLAG will start up a new packet, and thus
562              * will flush any accumulated garbage.  We do this whenever
563              * the line may have been idle for some time.
564              */
565             /* XXX as above. */
566             if (CCOUNT(&tp->t_outq) == 0) {
567                 ++sc->sc_stats.ppp_obytes;
568                 clist_putc(PPP_FLAG, &tp->t_outq);
569             }
570
571             /* Calculate the FCS for the first mbuf's worth. */
572             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
573             getmicrotime(&sc->sc_if.if_lastchange);
574         }
575
576         for (;;) {
577             start = mtod(m, u_char *);
578             len = m->m_len;
579             stop = start + len;
580             while (len > 0) {
581                 /*
582                  * Find out how many bytes in the string we can
583                  * handle without doing something special.
584                  */
585                 for (cp = start; cp < stop; cp++)
586                     if (ESCAPE_P(*cp))
587                         break;
588                 n = cp - start;
589                 if (n) {
590                     /* NetBSD (0.9 or later), 4.3-Reno or similar. */
591                     ndone = n - b_to_q(start, n, &tp->t_outq);
592                     len -= ndone;
593                     start += ndone;
594                     sc->sc_stats.ppp_obytes += ndone;
595
596                     if (ndone < n)
597                         break;  /* packet doesn't fit */
598                 }
599                 /*
600                  * If there are characters left in the mbuf,
601                  * the first one must be special.
602                  * Put it out in a different form.
603                  */
604                 if (len) {
605                     crit_enter();
606                     if (clist_putc(PPP_ESCAPE, &tp->t_outq)) {
607                         crit_exit();
608                         break;
609                     }
610                     if (clist_putc(*start ^ PPP_TRANS, &tp->t_outq)) {
611                         clist_unputc(&tp->t_outq);
612                         crit_exit();
613                         break;
614                     }
615                     crit_exit();
616                     sc->sc_stats.ppp_obytes += 2;
617                     start++;
618                     len--;
619                 }
620             }
621
622             /*
623              * If we didn't empty this mbuf, remember where we're up to.
624              * If we emptied the last mbuf, try to add the FCS and closing
625              * flag, and if we can't, leave sc_outm pointing to m, but with
626              * m->m_len == 0, to remind us to output the FCS and flag later.
627              */
628             done = len == 0;
629             if (done && m->m_next == NULL) {
630                 u_char *p, *q;
631                 int c;
632                 u_char endseq[8];
633
634                 /*
635                  * We may have to escape the bytes in the FCS.
636                  */
637                 p = endseq;
638                 c = ~sc->sc_outfcs & 0xFF;
639                 if (ESCAPE_P(c)) {
640                     *p++ = PPP_ESCAPE;
641                     *p++ = c ^ PPP_TRANS;
642                 } else
643                     *p++ = c;
644                 c = (~sc->sc_outfcs >> 8) & 0xFF;
645                 if (ESCAPE_P(c)) {
646                     *p++ = PPP_ESCAPE;
647                     *p++ = c ^ PPP_TRANS;
648                 } else
649                     *p++ = c;
650                 *p++ = PPP_FLAG;
651
652                 /*
653                  * Try to output the FCS and flag.  If the bytes
654                  * don't all fit, back out.
655                  */
656                 crit_enter();
657                 for (q = endseq; q < p; ++q)
658                     if (clist_putc(*q, &tp->t_outq)) {
659                         done = 0;
660                         for (; q > endseq; --q)
661                             clist_unputc(&tp->t_outq);
662                         break;
663                     }
664                 crit_exit();
665                 if (done)
666                     sc->sc_stats.ppp_obytes += q - endseq;
667             }
668
669             if (!done) {
670                 /* remember where we got to */
671                 m->m_data = start;
672                 m->m_len = len;
673                 break;
674             }
675
676             /* Finished with this mbuf; free it and move on. */
677             m = m_free(m);
678             if (m == NULL) {
679                 /* Finished a packet */
680                 break;
681             }
682             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
683         }
684
685         /*
686          * If m == NULL, we have finished a packet.
687          * If m != NULL, we've either done as much work this time
688          * as we need to, or else we've filled up the output queue.
689          */
690         sc->sc_outm = m;
691         if (m)
692             break;
693     }
694
695     /* Call pppstart to start output again if necessary. */
696     crit_enter();
697     pppstart(tp);
698
699     /*
700      * This timeout is needed for operation on a pseudo-tty,
701      * because the pty code doesn't call pppstart after it has
702      * drained the t_outq.
703      */
704     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
705         callout_reset(&sc->sc_timeout, 1, ppp_timeout, sc);
706         sc->sc_flags |= SC_TIMEOUT;
707     }
708
709     crit_exit();
710 }
711
712 /*
713  * This gets called when a received packet is placed on
714  * the inq, at splsoftnet. The pppd daemon is to be woken up to do a read().
715  */
716 static void
717 pppasyncctlp(struct ppp_softc *sc)
718 {
719     struct tty *tp;
720
721     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
722     crit_enter();
723     tp = (struct tty *) sc->sc_devp;
724     clist_putc(0, &tp->t_canq);
725     ttwakeup(tp);
726     crit_exit();
727 }
728
729 /*
730  * Start output on async tty interface.  If the transmit queue
731  * has drained sufficiently, arrange for pppasyncstart to be
732  * called later at splsoftnet.
733  * Called at spltty or higher.
734  */
735 int
736 pppstart(struct tty *tp)
737 {
738     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
739
740     /*
741      * Call output process whether or not there is any output.
742      * We are being called in lieu of ttstart and must do what it would.
743      */
744     if (tp->t_oproc != NULL)
745         (*tp->t_oproc)(tp);
746
747     /*
748      * If ALTQ is enabled, don't invoke NETISR_PPP.
749      * pppintr() could loop without doing anything useful
750      * under rate-limiting.
751      */
752     if (ifq_is_enabled(&sc->sc_if.if_snd))
753         return 0;
754
755     /*
756      * If the transmit queue has drained and the tty has not hung up
757      * or been disconnected from the ppp unit, then tell if_ppp.c that
758      * we need more output.
759      */
760     if (CCOUNT(&tp->t_outq) < PPP_LOWAT
761         && !((tp->t_state & TS_CONNECTED) == 0)
762         && sc != NULL && tp == (struct tty *) sc->sc_devp) {
763         ppp_restart(sc);
764     }
765
766     return 0;
767 }
768
769 /*
770  * Timeout routine - try to start some more output.
771  */
772 static void
773 ppp_timeout(void *x)
774 {
775     struct ppp_softc *sc = (struct ppp_softc *) x;
776     struct tty *tp = (struct tty *) sc->sc_devp;
777
778     crit_enter();
779     sc->sc_flags &= ~SC_TIMEOUT;
780     pppstart(tp);
781     crit_exit();
782 }
783
784 /*
785  * Allocate enough mbuf to handle current MRU.
786  */
787 static void
788 pppgetm(struct ppp_softc *sc)
789 {
790     struct mbuf *m, **mp;
791     int len;
792
793     mp = &sc->sc_m;
794     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
795         if ((m = *mp) == NULL) {
796             MGETHDR(m, MB_DONTWAIT, MT_DATA);
797             if (m == NULL)
798                 break;
799             *mp = m;
800             MCLGET(m, MB_DONTWAIT);
801         }
802         len -= M_DATASIZE(m);
803         mp = &m->m_next;
804     }
805 }
806
807 /*
808  * tty interface receiver interrupt.
809  */
810 static unsigned paritytab[8] = {
811     0x96696996, 0x69969669, 0x69969669, 0x96696996,
812     0x69969669, 0x96696996, 0x96696996, 0x69969669
813 };
814
815 /*
816  * Called when character is available from device driver.
817  * Only guaranteed to be at splsofttty() or spltty()
818  * This is safe to be called while the upper half's netisr is preempted.
819  */
820 static int
821 pppinput(int c, struct tty *tp)
822 {
823     struct ppp_softc *sc;
824     struct mbuf *m;
825     int ilen;
826
827     sc = (struct ppp_softc *) tp->t_sc;
828     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
829         return 0;
830
831     ++tk_nin;
832     ++sc->sc_stats.ppp_ibytes;
833
834     if ((tp->t_state & TS_CONNECTED) == 0) {
835         if (sc->sc_flags & SC_DEBUG)
836             kprintf("%s: no carrier\n", sc->sc_if.if_xname);
837         goto flush;
838     }
839
840     if (c & TTY_ERRORMASK) {
841         /* framing error or overrun on this char - abort packet */
842         if (sc->sc_flags & SC_DEBUG)
843             kprintf("%s: line error %x\n", sc->sc_if.if_xname,
844                                                 c & TTY_ERRORMASK);
845         goto flush;
846     }
847
848     c &= TTY_CHARMASK;
849
850     /*
851      * Handle software flow control of output.
852      */
853     if (tp->t_iflag & IXON) {
854         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
855             if ((tp->t_state & TS_TTSTOP) == 0) {
856                 tp->t_state |= TS_TTSTOP;
857                 tp->t_stop(tp, 0);
858             }
859             return 0;
860         }
861         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
862             tp->t_state &= ~TS_TTSTOP;
863             if (tp->t_oproc != NULL)
864                 (*tp->t_oproc)(tp);
865             return 0;
866         }
867     }
868
869     crit_enter();
870     if (c & 0x80)
871         sc->sc_flags |= SC_RCV_B7_1;
872     else
873         sc->sc_flags |= SC_RCV_B7_0;
874     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
875         sc->sc_flags |= SC_RCV_ODDP;
876     else
877         sc->sc_flags |= SC_RCV_EVNP;
878     crit_exit();
879
880     if (sc->sc_flags & SC_LOG_RAWIN)
881         ppplogchar(sc, c);
882
883     if (c == PPP_FLAG) {
884         ilen = sc->sc_ilen;
885         sc->sc_ilen = 0;
886
887         if (sc->sc_rawin_count > 0) 
888             ppplogchar(sc, -1);
889
890         /*
891          * If SC_ESCAPED is set, then we've seen the packet
892          * abort sequence "}~".
893          */
894         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
895             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
896             crit_enter();
897             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
898             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
899                 if (sc->sc_flags & SC_DEBUG)
900                     kprintf("%s: bad fcs %x, pkt len %d\n",
901                            sc->sc_if.if_xname, sc->sc_fcs, ilen);
902                 sc->sc_if.if_ierrors++;
903                 sc->sc_stats.ppp_ierrors++;
904             } else
905                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
906             crit_exit();
907             return 0;
908         }
909
910         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
911             if (ilen) {
912                 if (sc->sc_flags & SC_DEBUG)
913                     kprintf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
914                 crit_enter();
915                 sc->sc_if.if_ierrors++;
916                 sc->sc_stats.ppp_ierrors++;
917                 sc->sc_flags |= SC_PKTLOST;
918                 crit_exit();
919             }
920             return 0;
921         }
922
923         /*
924          * Remove FCS trailer.  Somewhat painful...
925          */
926         ilen -= 2;
927         if (--sc->sc_mc->m_len == 0) {
928             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
929                 ;
930             sc->sc_mc = m;
931         }
932         sc->sc_mc->m_len--;
933
934         /* excise this mbuf chain */
935         m = sc->sc_m;
936         sc->sc_m = sc->sc_mc->m_next;
937         sc->sc_mc->m_next = NULL;
938
939         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
940         if (sc->sc_flags & SC_PKTLOST) {
941             crit_enter();
942             sc->sc_flags &= ~SC_PKTLOST;
943             crit_exit();
944         }
945
946         pppgetm(sc);
947         return 0;
948     }
949
950     if (sc->sc_flags & SC_FLUSH) {
951         if (sc->sc_flags & SC_LOG_FLUSH)
952             ppplogchar(sc, c);
953         return 0;
954     }
955
956     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
957         return 0;
958
959     crit_enter();
960     if (sc->sc_flags & SC_ESCAPED) {
961         sc->sc_flags &= ~SC_ESCAPED;
962         c ^= PPP_TRANS;
963     } else if (c == PPP_ESCAPE) {
964         sc->sc_flags |= SC_ESCAPED;
965         crit_exit();
966         return 0;
967     }
968     crit_exit();
969
970     /*
971      * Initialize buffer on first octet received.
972      * First octet could be address or protocol (when compressing
973      * address/control).
974      * Second octet is control.
975      * Third octet is first or second (when compressing protocol)
976      * octet of protocol.
977      * Fourth octet is second octet of protocol.
978      */
979     if (sc->sc_ilen == 0) {
980         /* reset the first input mbuf */
981         if (sc->sc_m == NULL) {
982             pppgetm(sc);
983             if (sc->sc_m == NULL) {
984                 if (sc->sc_flags & SC_DEBUG)
985                     kprintf("%s: no input mbufs!\n", sc->sc_if.if_xname);
986                 goto flush;
987             }
988         }
989         m = sc->sc_m;
990         m->m_len = 0;
991         m->m_data = M_DATASTART(sc->sc_m);
992         sc->sc_mc = m;
993         sc->sc_mp = mtod(m, char *);
994         sc->sc_fcs = PPP_INITFCS;
995         if (c != PPP_ALLSTATIONS) {
996             if (sc->sc_flags & SC_REJ_COMP_AC) {
997                 if (sc->sc_flags & SC_DEBUG)
998                     kprintf("%s: garbage received: 0x%x (need 0xFF)\n",
999                            sc->sc_if.if_xname, c);
1000                 goto flush;
1001             }
1002             *sc->sc_mp++ = PPP_ALLSTATIONS;
1003             *sc->sc_mp++ = PPP_UI;
1004             sc->sc_ilen += 2;
1005             m->m_len += 2;
1006         }
1007     }
1008     if (sc->sc_ilen == 1 && c != PPP_UI) {
1009         if (sc->sc_flags & SC_DEBUG)
1010             kprintf("%s: missing UI (0x3), got 0x%x\n",
1011                    sc->sc_if.if_xname, c);
1012         goto flush;
1013     }
1014     if (sc->sc_ilen == 2 && (c & 1) == 1) {
1015         /* a compressed protocol */
1016         *sc->sc_mp++ = 0;
1017         sc->sc_ilen++;
1018         sc->sc_mc->m_len++;
1019     }
1020     if (sc->sc_ilen == 3 && (c & 1) == 0) {
1021         if (sc->sc_flags & SC_DEBUG)
1022             kprintf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1023                    (sc->sc_mp[-1] << 8) + c);
1024         goto flush;
1025     }
1026
1027     /* packet beyond configured mru? */
1028     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1029         if (sc->sc_flags & SC_DEBUG)
1030             kprintf("%s: packet too big\n", sc->sc_if.if_xname);
1031         goto flush;
1032     }
1033
1034     /* is this mbuf full? */
1035     m = sc->sc_mc;
1036     if (M_TRAILINGSPACE(m) <= 0) {
1037         if (m->m_next == NULL) {
1038             pppgetm(sc);
1039             if (m->m_next == NULL) {
1040                 if (sc->sc_flags & SC_DEBUG)
1041                     kprintf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1042                 goto flush;
1043             }
1044         }
1045         sc->sc_mc = m = m->m_next;
1046         m->m_len = 0;
1047         m->m_data = M_DATASTART(m);
1048         sc->sc_mp = mtod(m, char *);
1049     }
1050
1051     ++m->m_len;
1052     *sc->sc_mp++ = c;
1053     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1054     return 0;
1055
1056  flush:
1057     if (!(sc->sc_flags & SC_FLUSH)) {
1058         crit_enter();
1059         sc->sc_if.if_ierrors++;
1060         sc->sc_stats.ppp_ierrors++;
1061         sc->sc_flags |= SC_FLUSH;
1062         crit_exit();
1063         if (sc->sc_flags & SC_LOG_FLUSH)
1064             ppplogchar(sc, c);
1065     }
1066     return 0;
1067 }
1068
1069 #define MAX_DUMP_BYTES  128
1070
1071 static void
1072 ppplogchar(struct ppp_softc *sc, int c)
1073 {
1074     if (c >= 0)
1075         sc->sc_rawin[sc->sc_rawin_count++] = c;
1076     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1077         || (c < 0 && sc->sc_rawin_count > 0)) {
1078         kprintf("%s input: %*D", sc->sc_if.if_xname,
1079                 sc->sc_rawin_count, sc->sc_rawin, " ");
1080         sc->sc_rawin_count = 0;
1081     }
1082 }