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