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