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