]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/ppp_tty.c
This commit was generated by cvs2svn to compensate for changes in r80785,
[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 __P((dev_t dev, struct tty *tp));
98 static int      pppclose __P((struct tty *tp, int flag));
99 static int      pppread __P((struct tty *tp, struct uio *uio, int flag));
100 static int      pppwrite __P((struct tty *tp, struct uio *uio, int flag));
101 static int      ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag,
102                        struct proc *));
103 static int      pppinput __P((int c, struct tty *tp));
104 static int      pppstart __P((struct tty *tp));
105
106 static u_short  pppfcs __P((u_short fcs, u_char *cp, int len));
107 static void     pppasyncstart __P((struct ppp_softc *));
108 static void     pppasyncctlp __P((struct ppp_softc *));
109 static void     pppasyncrelinq __P((struct ppp_softc *));
110 static void     pppasyncsetmtu __P((struct ppp_softc *));
111 static void     ppp_timeout __P((void *));
112 static void     pppgetm __P((struct ppp_softc *sc));
113 static void     ppplogchar __P((struct ppp_softc *, int));
114
115 /* XXX called from if_ppp.c - layering violation */
116 void            pppasyncattach __P((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 proc *p = curproc;           /* XXX */
175     register struct ppp_softc *sc;
176     int error, s;
177
178     if ((error = suser(p)) != 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(p->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, p)
432     struct tty *tp;
433     u_long cmd;
434     caddr_t data;
435     int flag;
436     struct proc *p;
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(p)) != 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(p)) != 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(p)) != 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, p);
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     struct mbuf *m2;
553     int s;
554
555     idle = 0;
556     /* XXX assumes atomic access to *tp although we're not at spltty(). */
557     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
558         /*
559          * See if we have an existing packet partly sent.
560          * If not, get a new packet and start sending it.
561          */
562         m = sc->sc_outm;
563         if (m == NULL) {
564             /*
565              * Get another packet to be sent.
566              */
567             m = ppp_dequeue(sc);
568             if (m == NULL) {
569                 idle = 1;
570                 break;
571             }
572
573             /*
574              * The extra PPP_FLAG will start up a new packet, and thus
575              * will flush any accumulated garbage.  We do this whenever
576              * the line may have been idle for some time.
577              */
578             /* XXX as above. */
579             if (CCOUNT(&tp->t_outq) == 0) {
580                 ++sc->sc_stats.ppp_obytes;
581                 (void) putc(PPP_FLAG, &tp->t_outq);
582             }
583
584             /* Calculate the FCS for the first mbuf's worth. */
585             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
586             getmicrotime(&sc->sc_if.if_lastchange);
587         }
588
589         for (;;) {
590             start = mtod(m, u_char *);
591             len = m->m_len;
592             stop = start + len;
593             while (len > 0) {
594                 /*
595                  * Find out how many bytes in the string we can
596                  * handle without doing something special.
597                  */
598                 for (cp = start; cp < stop; cp++)
599                     if (ESCAPE_P(*cp))
600                         break;
601                 n = cp - start;
602                 if (n) {
603                     /* NetBSD (0.9 or later), 4.3-Reno or similar. */
604                     ndone = n - b_to_q(start, n, &tp->t_outq);
605                     len -= ndone;
606                     start += ndone;
607                     sc->sc_stats.ppp_obytes += ndone;
608
609                     if (ndone < n)
610                         break;  /* packet doesn't fit */
611                 }
612                 /*
613                  * If there are characters left in the mbuf,
614                  * the first one must be special.
615                  * Put it out in a different form.
616                  */
617                 if (len) {
618                     s = spltty();
619                     if (putc(PPP_ESCAPE, &tp->t_outq)) {
620                         splx(s);
621                         break;
622                     }
623                     if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
624                         (void) unputc(&tp->t_outq);
625                         splx(s);
626                         break;
627                     }
628                     splx(s);
629                     sc->sc_stats.ppp_obytes += 2;
630                     start++;
631                     len--;
632                 }
633             }
634
635             /*
636              * If we didn't empty this mbuf, remember where we're up to.
637              * If we emptied the last mbuf, try to add the FCS and closing
638              * flag, and if we can't, leave sc_outm pointing to m, but with
639              * m->m_len == 0, to remind us to output the FCS and flag later.
640              */
641             done = len == 0;
642             if (done && m->m_next == NULL) {
643                 u_char *p, *q;
644                 int c;
645                 u_char endseq[8];
646
647                 /*
648                  * We may have to escape the bytes in the FCS.
649                  */
650                 p = endseq;
651                 c = ~sc->sc_outfcs & 0xFF;
652                 if (ESCAPE_P(c)) {
653                     *p++ = PPP_ESCAPE;
654                     *p++ = c ^ PPP_TRANS;
655                 } else
656                     *p++ = c;
657                 c = (~sc->sc_outfcs >> 8) & 0xFF;
658                 if (ESCAPE_P(c)) {
659                     *p++ = PPP_ESCAPE;
660                     *p++ = c ^ PPP_TRANS;
661                 } else
662                     *p++ = c;
663                 *p++ = PPP_FLAG;
664
665                 /*
666                  * Try to output the FCS and flag.  If the bytes
667                  * don't all fit, back out.
668                  */
669                 s = spltty();
670                 for (q = endseq; q < p; ++q)
671                     if (putc(*q, &tp->t_outq)) {
672                         done = 0;
673                         for (; q > endseq; --q)
674                             unputc(&tp->t_outq);
675                         break;
676                     }
677                 splx(s);
678                 if (done)
679                     sc->sc_stats.ppp_obytes += q - endseq;
680             }
681
682             if (!done) {
683                 /* remember where we got to */
684                 m->m_data = start;
685                 m->m_len = len;
686                 break;
687             }
688
689             /* Finished with this mbuf; free it and move on. */
690             MFREE(m, m2);
691             m = m2;
692             if (m == NULL) {
693                 /* Finished a packet */
694                 break;
695             }
696             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
697         }
698
699         /*
700          * If m == NULL, we have finished a packet.
701          * If m != NULL, we've either done as much work this time
702          * as we need to, or else we've filled up the output queue.
703          */
704         sc->sc_outm = m;
705         if (m)
706             break;
707     }
708
709     /* Call pppstart to start output again if necessary. */
710     s = spltty();
711     pppstart(tp);
712
713     /*
714      * This timeout is needed for operation on a pseudo-tty,
715      * because the pty code doesn't call pppstart after it has
716      * drained the t_outq.
717      */
718     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
719         sc->sc_ch = timeout(ppp_timeout, (void *) sc, 1);
720         sc->sc_flags |= SC_TIMEOUT;
721     }
722
723     splx(s);
724 }
725
726 /*
727  * This gets called when a received packet is placed on
728  * the inq, at splsoftnet. The pppd daemon is to be woken up to do a read().
729  */
730 static void
731 pppasyncctlp(sc)
732     struct ppp_softc *sc;
733 {
734     struct tty *tp;
735     int s;
736
737     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
738     s = spltty();
739     tp = (struct tty *) sc->sc_devp;
740     putc(0, &tp->t_canq);
741     ttwakeup(tp);
742     splx(s);
743 }
744
745 /*
746  * Start output on async tty interface.  If the transmit queue
747  * has drained sufficiently, arrange for pppasyncstart to be
748  * called later at splsoftnet.
749  * Called at spltty or higher.
750  */
751 int
752 pppstart(tp)
753     register struct tty *tp;
754 {
755     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
756
757     /*
758      * Call output process whether or not there is any output.
759      * We are being called in lieu of ttstart and must do what it would.
760      */
761     if (tp->t_oproc != NULL)
762         (*tp->t_oproc)(tp);
763
764     /*
765      * If the transmit queue has drained and the tty has not hung up
766      * or been disconnected from the ppp unit, then tell if_ppp.c that
767      * we need more output.
768      */
769     if (CCOUNT(&tp->t_outq) < PPP_LOWAT
770         && !((tp->t_state & TS_CONNECTED) == 0)
771         && sc != NULL && tp == (struct tty *) sc->sc_devp) {
772         ppp_restart(sc);
773     }
774
775     return 0;
776 }
777
778 /*
779  * Timeout routine - try to start some more output.
780  */
781 static void
782 ppp_timeout(x)
783     void *x;
784 {
785     struct ppp_softc *sc = (struct ppp_softc *) x;
786     struct tty *tp = (struct tty *) sc->sc_devp;
787     int s;
788
789     s = spltty();
790     sc->sc_flags &= ~SC_TIMEOUT;
791     pppstart(tp);
792     splx(s);
793 }
794
795 /*
796  * Allocate enough mbuf to handle current MRU.
797  */
798 static void
799 pppgetm(sc)
800     register struct ppp_softc *sc;
801 {
802     struct mbuf *m, **mp;
803     int len;
804
805     mp = &sc->sc_m;
806     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
807         if ((m = *mp) == NULL) {
808             MGETHDR(m, M_DONTWAIT, MT_DATA);
809             if (m == NULL)
810                 break;
811             *mp = m;
812             MCLGET(m, M_DONTWAIT);
813         }
814         len -= M_DATASIZE(m);
815         mp = &m->m_next;
816     }
817 }
818
819 /*
820  * tty interface receiver interrupt.
821  */
822 static unsigned paritytab[8] = {
823     0x96696996, 0x69969669, 0x69969669, 0x96696996,
824     0x69969669, 0x96696996, 0x96696996, 0x69969669
825 };
826
827 /*
828  * Called when character is available from device driver.
829  * Only guaranteed to be at splsofttty() or spltty()
830  * This is safe to be called while the upper half's netisr is preempted.
831  */
832 static int
833 pppinput(c, tp)
834     int c;
835     register struct tty *tp;
836 {
837     register struct ppp_softc *sc;
838     struct mbuf *m;
839     int ilen, s;
840
841     sc = (struct ppp_softc *) tp->t_sc;
842     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
843         return 0;
844
845     ++tk_nin;
846     ++sc->sc_stats.ppp_ibytes;
847
848     if ((tp->t_state & TS_CONNECTED) == 0) {
849         if (sc->sc_flags & SC_DEBUG)
850             printf("ppp%d: no carrier\n", sc->sc_if.if_unit);
851         goto flush;
852     }
853
854     if (c & TTY_ERRORMASK) {
855         /* framing error or overrun on this char - abort packet */
856         if (sc->sc_flags & SC_DEBUG)
857             printf("ppp%d: line error %x\n", sc->sc_if.if_unit,
858                                                 c & TTY_ERRORMASK);
859         goto flush;
860     }
861
862     c &= TTY_CHARMASK;
863
864     /*
865      * Handle software flow control of output.
866      */
867     if (tp->t_iflag & IXON) {
868         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
869             if ((tp->t_state & TS_TTSTOP) == 0) {
870                 tp->t_state |= TS_TTSTOP;
871                 tp->t_stop(tp, 0);
872             }
873             return 0;
874         }
875         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
876             tp->t_state &= ~TS_TTSTOP;
877             if (tp->t_oproc != NULL)
878                 (*tp->t_oproc)(tp);
879             return 0;
880         }
881     }
882
883     s = spltty();
884     if (c & 0x80)
885         sc->sc_flags |= SC_RCV_B7_1;
886     else
887         sc->sc_flags |= SC_RCV_B7_0;
888     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
889         sc->sc_flags |= SC_RCV_ODDP;
890     else
891         sc->sc_flags |= SC_RCV_EVNP;
892     splx(s);
893
894     if (sc->sc_flags & SC_LOG_RAWIN)
895         ppplogchar(sc, c);
896
897     if (c == PPP_FLAG) {
898         ilen = sc->sc_ilen;
899         sc->sc_ilen = 0;
900
901         if (sc->sc_rawin_count > 0) 
902             ppplogchar(sc, -1);
903
904         /*
905          * If SC_ESCAPED is set, then we've seen the packet
906          * abort sequence "}~".
907          */
908         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
909             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
910             s = spltty();
911             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
912             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
913                 if (sc->sc_flags & SC_DEBUG)
914                     printf("ppp%d: bad fcs %x, pkt len %d\n",
915                            sc->sc_if.if_unit, sc->sc_fcs, ilen);
916                 sc->sc_if.if_ierrors++;
917                 sc->sc_stats.ppp_ierrors++;
918             } else
919                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
920             splx(s);
921             return 0;
922         }
923
924         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
925             if (ilen) {
926                 if (sc->sc_flags & SC_DEBUG)
927                     printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
928                 s = spltty();
929                 sc->sc_if.if_ierrors++;
930                 sc->sc_stats.ppp_ierrors++;
931                 sc->sc_flags |= SC_PKTLOST;
932                 splx(s);
933             }
934             return 0;
935         }
936
937         /*
938          * Remove FCS trailer.  Somewhat painful...
939          */
940         ilen -= 2;
941         if (--sc->sc_mc->m_len == 0) {
942             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
943                 ;
944             sc->sc_mc = m;
945         }
946         sc->sc_mc->m_len--;
947
948         /* excise this mbuf chain */
949         m = sc->sc_m;
950         sc->sc_m = sc->sc_mc->m_next;
951         sc->sc_mc->m_next = NULL;
952
953         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
954         if (sc->sc_flags & SC_PKTLOST) {
955             s = spltty();
956             sc->sc_flags &= ~SC_PKTLOST;
957             splx(s);
958         }
959
960         pppgetm(sc);
961         return 0;
962     }
963
964     if (sc->sc_flags & SC_FLUSH) {
965         if (sc->sc_flags & SC_LOG_FLUSH)
966             ppplogchar(sc, c);
967         return 0;
968     }
969
970     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
971         return 0;
972
973     s = spltty();
974     if (sc->sc_flags & SC_ESCAPED) {
975         sc->sc_flags &= ~SC_ESCAPED;
976         c ^= PPP_TRANS;
977     } else if (c == PPP_ESCAPE) {
978         sc->sc_flags |= SC_ESCAPED;
979         splx(s);
980         return 0;
981     }
982     splx(s);
983
984     /*
985      * Initialize buffer on first octet received.
986      * First octet could be address or protocol (when compressing
987      * address/control).
988      * Second octet is control.
989      * Third octet is first or second (when compressing protocol)
990      * octet of protocol.
991      * Fourth octet is second octet of protocol.
992      */
993     if (sc->sc_ilen == 0) {
994         /* reset the first input mbuf */
995         if (sc->sc_m == NULL) {
996             pppgetm(sc);
997             if (sc->sc_m == NULL) {
998                 if (sc->sc_flags & SC_DEBUG)
999                     printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
1000                 goto flush;
1001             }
1002         }
1003         m = sc->sc_m;
1004         m->m_len = 0;
1005         m->m_data = M_DATASTART(sc->sc_m);
1006         sc->sc_mc = m;
1007         sc->sc_mp = mtod(m, char *);
1008         sc->sc_fcs = PPP_INITFCS;
1009         if (c != PPP_ALLSTATIONS) {
1010             if (sc->sc_flags & SC_REJ_COMP_AC) {
1011                 if (sc->sc_flags & SC_DEBUG)
1012                     printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
1013                            sc->sc_if.if_unit, c);
1014                 goto flush;
1015             }
1016             *sc->sc_mp++ = PPP_ALLSTATIONS;
1017             *sc->sc_mp++ = PPP_UI;
1018             sc->sc_ilen += 2;
1019             m->m_len += 2;
1020         }
1021     }
1022     if (sc->sc_ilen == 1 && c != PPP_UI) {
1023         if (sc->sc_flags & SC_DEBUG)
1024             printf("ppp%d: missing UI (0x3), got 0x%x\n",
1025                    sc->sc_if.if_unit, c);
1026         goto flush;
1027     }
1028     if (sc->sc_ilen == 2 && (c & 1) == 1) {
1029         /* a compressed protocol */
1030         *sc->sc_mp++ = 0;
1031         sc->sc_ilen++;
1032         sc->sc_mc->m_len++;
1033     }
1034     if (sc->sc_ilen == 3 && (c & 1) == 0) {
1035         if (sc->sc_flags & SC_DEBUG)
1036             printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1037                    (sc->sc_mp[-1] << 8) + c);
1038         goto flush;
1039     }
1040
1041     /* packet beyond configured mru? */
1042     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1043         if (sc->sc_flags & SC_DEBUG)
1044             printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
1045         goto flush;
1046     }
1047
1048     /* is this mbuf full? */
1049     m = sc->sc_mc;
1050     if (M_TRAILINGSPACE(m) <= 0) {
1051         if (m->m_next == NULL) {
1052             pppgetm(sc);
1053             if (m->m_next == NULL) {
1054                 if (sc->sc_flags & SC_DEBUG)
1055                     printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1056                 goto flush;
1057             }
1058         }
1059         sc->sc_mc = m = m->m_next;
1060         m->m_len = 0;
1061         m->m_data = M_DATASTART(m);
1062         sc->sc_mp = mtod(m, char *);
1063     }
1064
1065     ++m->m_len;
1066     *sc->sc_mp++ = c;
1067     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1068     return 0;
1069
1070  flush:
1071     if (!(sc->sc_flags & SC_FLUSH)) {
1072         s = spltty();
1073         sc->sc_if.if_ierrors++;
1074         sc->sc_stats.ppp_ierrors++;
1075         sc->sc_flags |= SC_FLUSH;
1076         splx(s);
1077         if (sc->sc_flags & SC_LOG_FLUSH)
1078             ppplogchar(sc, c);
1079     }
1080     return 0;
1081 }
1082
1083 #define MAX_DUMP_BYTES  128
1084
1085 static void
1086 ppplogchar(sc, c)
1087     struct ppp_softc *sc;
1088     int c;
1089 {
1090     if (c >= 0)
1091         sc->sc_rawin[sc->sc_rawin_count++] = c;
1092     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1093         || (c < 0 && sc->sc_rawin_count > 0)) {
1094         printf("ppp%d input: %*D", sc->sc_if.if_unit,
1095                 sc->sc_rawin_count, sc->sc_rawin, " ");
1096         sc->sc_rawin_count = 0;
1097     }
1098 }