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