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