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