update for 2.3.8
[ppp.git] / netbsd-1.1 / ppp_tty.c
1 /*      $Id: ppp_tty.c,v 1.4 1997/04/30 05:47:38 paulus Exp $   */
2
3 /*
4  * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
5  *             tty devices.
6  *
7  * Copyright (c) 1989 Carnegie Mellon University.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that the above copyright notice and this paragraph are
12  * duplicated in all such forms and that any documentation,
13  * advertising materials, and other materials related to such
14  * distribution and use acknowledge that the software was developed
15  * by Carnegie Mellon University.  The name of the
16  * University may not be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  *
22  * Drew D. Perkins
23  * Carnegie Mellon University
24  * 4910 Forbes Ave.
25  * Pittsburgh, PA 15213
26  * (412) 268-8576
27  * ddp@andrew.cmu.edu
28  *
29  * Based on:
30  *      @(#)if_sl.c     7.6.1.2 (Berkeley) 2/15/89
31  *
32  * Copyright (c) 1987 Regents of the University of California.
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms are permitted
36  * provided that the above copyright notice and this paragraph are
37  * duplicated in all such forms and that any documentation,
38  * advertising materials, and other materials related to such
39  * distribution and use acknowledge that the software was developed
40  * by the University of California, Berkeley.  The name of the
41  * University may not be used to endorse or promote products derived
42  * from this software without specific prior written permission.
43  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
46  *
47  * Serial Line interface
48  *
49  * Rick Adams
50  * Center for Seismic Studies
51  * 1300 N 17th Street, Suite 1450
52  * Arlington, Virginia 22209
53  * (703)276-7900
54  * rick@seismo.ARPA
55  * seismo!rick
56  *
57  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
58  * Converted to 4.3BSD Beta by Chris Torek.
59  * Other changes made at Berkeley, based in part on code by Kirk Smith.
60  *
61  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
62  * Added VJ tcp header compression; more unified ioctls
63  *
64  * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
65  * Cleaned up a lot of the mbuf-related code to fix bugs that
66  * caused system crashes and packet corruption.  Changed pppstart
67  * so that it doesn't just give up with a "collision" if the whole
68  * packet doesn't fit in the output ring buffer.
69  *
70  * Added priority queueing for interactive IP packets, following
71  * the model of if_sl.c, plus hooks for bpf.
72  * Paul Mackerras (paulus@cs.anu.edu.au).
73  */
74
75 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
76 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
77
78 #include "ppp.h"
79 #if NPPP > 0
80
81 #define VJC
82 #define PPP_COMPRESS
83
84 #include <sys/param.h>
85 #include <sys/proc.h>
86 #include <sys/mbuf.h>
87 #include <sys/dkstat.h>
88 #include <sys/socket.h>
89 #include <sys/ioctl.h>
90 #include <sys/file.h>
91 #include <sys/tty.h>
92 #include <sys/kernel.h>
93 #include <sys/conf.h>
94 #include <sys/vnode.h>
95 #include <sys/systm.h>
96
97 #include <net/if.h>
98 #include <net/if_types.h>
99
100 #ifdef VJC
101 #include <netinet/in.h>
102 #include <netinet/in_systm.h>
103 #include <netinet/ip.h>
104 #include <net/slcompress.h>
105 #endif
106
107 #ifdef PPP_FILTER
108 #include <net/bpf.h>
109 #endif
110 #include <net/ppp_defs.h>
111 #include <net/if_ppp.h>
112 #include <net/if_pppvar.h>
113
114 int     pppopen __P((dev_t dev, struct tty *tp));
115 int     pppclose __P((struct tty *tp, int flag));
116 int     pppread __P((struct tty *tp, struct uio *uio, int flag));
117 int     pppwrite __P((struct tty *tp, struct uio *uio, int flag));
118 int     ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag,
119                        struct proc *));
120 int     pppinput __P((int c, struct tty *tp));
121 int     pppstart __P((struct tty *tp, int));
122
123 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
124 static void     pppasyncstart __P((struct ppp_softc *));
125 static void     pppasyncctlp __P((struct ppp_softc *));
126 static void     pppasyncrelinq __P((struct ppp_softc *));
127 static void     ppp_timeout __P((void *));
128 static void     pppgetm __P((struct ppp_softc *sc));
129 static void     pppdumpb __P((u_char *b, int l));
130 static void     ppplogchar __P((struct ppp_softc *, int));
131
132 /*
133  * Some useful mbuf macros not in mbuf.h.
134  */
135 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
136
137 #define M_DATASTART(m)  \
138         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
139             (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
140
141 #define M_DATASIZE(m)   \
142         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
143             (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
144
145 /*
146  * Does c need to be escaped?
147  */
148 #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
149
150 /*
151  * Procedures for using an async tty interface for PPP.
152  */
153
154 /* This is a NetBSD-1.0 or later kernel. */
155 #define CCOUNT(q)       ((q)->c_cc)
156
157 #define PPP_LOWAT       100     /* Process more output when < LOWAT on queue */
158 #define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
159
160 /*
161  * Line specific open routine for async tty devices.
162  * Attach the given tty to the first available ppp unit.
163  * Called from device open routine or ttioctl.
164  */
165 /* ARGSUSED */
166 int
167 pppopen(dev, tp)
168     dev_t dev;
169     register struct tty *tp;
170 {
171     struct proc *p = curproc;           /* XXX */
172     register struct ppp_softc *sc;
173     int error, s;
174
175     if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
176         return (error);
177
178     s = spltty();
179
180     if (tp->t_line == PPPDISC) {
181         sc = (struct ppp_softc *) tp->t_sc;
182         if (sc != NULL && sc->sc_devp == (void *) tp) {
183             splx(s);
184             return (0);
185         }
186     }
187
188     if ((sc = pppalloc(p->p_pid)) == NULL) {
189         splx(s);
190         return ENXIO;
191     }
192
193     if (sc->sc_relinq)
194         (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
195
196     sc->sc_ilen = 0;
197     sc->sc_m = NULL;
198     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
199     sc->sc_asyncmap[0] = 0xffffffff;
200     sc->sc_asyncmap[3] = 0x60000000;
201     sc->sc_rasyncmap = 0;
202     sc->sc_devp = (void *) tp;
203     sc->sc_start = pppasyncstart;
204     sc->sc_ctlp = pppasyncctlp;
205     sc->sc_relinq = pppasyncrelinq;
206     sc->sc_outm = NULL;
207     pppgetm(sc);
208     sc->sc_if.if_flags |= IFF_RUNNING;
209     sc->sc_if.if_baudrate = tp->t_ospeed;
210
211     tp->t_sc = (caddr_t) sc;
212     ttyflush(tp, FREAD | FWRITE);
213
214     splx(s);
215     return (0);
216 }
217
218 /*
219  * Line specific close routine, called from device close routine
220  * and from ttioctl.
221  * Detach the tty from the ppp unit.
222  * Mimics part of ttyclose().
223  */
224 int
225 pppclose(tp, flag)
226     struct tty *tp;
227     int flag;
228 {
229     register struct ppp_softc *sc;
230     int s;
231
232     s = spltty();
233     ttyflush(tp, FREAD|FWRITE);
234     tp->t_line = 0;
235     sc = (struct ppp_softc *) tp->t_sc;
236     if (sc != NULL) {
237         tp->t_sc = NULL;
238         if (tp == (struct tty *) sc->sc_devp) {
239             pppasyncrelinq(sc);
240             pppdealloc(sc);
241         }
242     }
243     splx(s);
244     return 0;
245 }
246
247 /*
248  * Relinquish the interface unit to another device.
249  */
250 static void
251 pppasyncrelinq(sc)
252     struct ppp_softc *sc;
253 {
254     int s;
255
256     s = spltty();
257     if (sc->sc_outm) {
258         m_freem(sc->sc_outm);
259         sc->sc_outm = NULL;
260     }
261     if (sc->sc_m) {
262         m_freem(sc->sc_m);
263         sc->sc_m = NULL;
264     }
265     if (sc->sc_flags & SC_TIMEOUT) {
266         untimeout(ppp_timeout, (void *) sc);
267         sc->sc_flags &= ~SC_TIMEOUT;
268     }
269     splx(s);
270 }
271
272 /*
273  * Line specific (tty) read routine.
274  */
275 int
276 pppread(tp, uio, flag)
277     register struct tty *tp;
278     struct uio *uio;
279     int flag;
280 {
281     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
282     struct mbuf *m, *m0;
283     register int s;
284     int error = 0;
285
286     if (sc == NULL)
287         return 0;
288     /*
289      * Loop waiting for input, checking that nothing disasterous
290      * happens in the meantime.
291      */
292     s = spltty();
293     for (;;) {
294         if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
295             splx(s);
296             return 0;
297         }
298         if (sc->sc_inq.ifq_head != NULL)
299             break;
300         if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
301             && (tp->t_state & TS_ISOPEN)) {
302             splx(s);
303             return 0;           /* end of file */
304         }
305         if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
306             splx(s);
307             return (EWOULDBLOCK);
308         }
309         error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
310         if (error) {
311             splx(s);
312             return error;
313         }
314     }
315
316     /* Pull place-holder byte out of canonical queue */
317     getc(&tp->t_canq);
318
319     /* Get the packet from the input queue */
320     IF_DEQUEUE(&sc->sc_inq, m0);
321     splx(s);
322
323     for (m = m0; m && uio->uio_resid; m = m->m_next)
324         if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
325             break;
326     m_freem(m0);
327     return (error);
328 }
329
330 /*
331  * Line specific (tty) write routine.
332  */
333 int
334 pppwrite(tp, uio, flag)
335     register struct tty *tp;
336     struct uio *uio;
337     int flag;
338 {
339     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
340     struct mbuf *m, *m0, **mp;
341     struct sockaddr dst;
342     int len, error;
343
344     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
345         return 0;               /* wrote 0 bytes */
346     if (tp->t_line != PPPDISC)
347         return (EINVAL);
348     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
349         return EIO;
350     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
351         uio->uio_resid < PPP_HDRLEN)
352         return (EMSGSIZE);
353     for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
354         MGET(m, M_WAIT, MT_DATA);
355         if ((*mp = m) == NULL) {
356             m_freem(m0);
357             return (ENOBUFS);
358         }
359         m->m_len = 0;
360         if (uio->uio_resid >= MCLBYTES / 2)
361             MCLGET(m, M_DONTWAIT);
362         len = M_TRAILINGSPACE(m);
363         if (len > uio->uio_resid)
364             len = uio->uio_resid;
365         if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
366             m_freem(m0);
367             return (error);
368         }
369         m->m_len = len;
370     }
371     dst.sa_family = AF_UNSPEC;
372     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
373     m0->m_data += PPP_HDRLEN;
374     m0->m_len -= PPP_HDRLEN;
375     return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
376 }
377
378 /*
379  * Line specific (tty) ioctl routine.
380  * This discipline requires that tty device drivers call
381  * the line specific l_ioctl routine from their ioctl routines.
382  */
383 /* ARGSUSED */
384 int
385 ppptioctl(tp, cmd, data, flag, p)
386     struct tty *tp;
387     u_long cmd;
388     caddr_t data;
389     int flag;
390     struct proc *p;
391 {
392     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
393     int error, s;
394
395     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
396         return -1;
397
398     error = 0;
399     switch (cmd) {
400     case PPPIOCSASYNCMAP:
401         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
402             break;
403         sc->sc_asyncmap[0] = *(u_int *)data;
404         break;
405
406     case PPPIOCGASYNCMAP:
407         *(u_int *)data = sc->sc_asyncmap[0];
408         break;
409
410     case PPPIOCSRASYNCMAP:
411         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
412             break;
413         sc->sc_rasyncmap = *(u_int *)data;
414         break;
415
416     case PPPIOCGRASYNCMAP:
417         *(u_int *)data = sc->sc_rasyncmap;
418         break;
419
420     case PPPIOCSXASYNCMAP:
421         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
422             break;
423         s = spltty();
424         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
425         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
426         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
427         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
428         splx(s);
429         break;
430
431     case PPPIOCGXASYNCMAP:
432         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
433         break;
434
435     default:
436         error = pppioctl(sc, cmd, data, flag, p);
437         if (error == 0 && cmd == PPPIOCSMRU)
438             pppgetm(sc);
439     }
440
441     return error;
442 }
443
444 /*
445  * FCS lookup table as calculated by genfcstab.
446  */
447 static u_int16_t fcstab[256] = {
448         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
449         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
450         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
451         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
452         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
453         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
454         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
455         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
456         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
457         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
458         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
459         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
460         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
461         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
462         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
463         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
464         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
465         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
466         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
467         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
468         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
469         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
470         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
471         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
472         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
473         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
474         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
475         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
476         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
477         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
478         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
479         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
480 };
481
482 /*
483  * Calculate a new FCS given the current FCS and the new data.
484  */
485 static u_int16_t
486 pppfcs(fcs, cp, len)
487     register u_int16_t fcs;
488     register u_char *cp;
489     register int len;
490 {
491     while (len--)
492         fcs = PPP_FCS(fcs, *cp++);
493     return (fcs);
494 }
495
496 /*
497  * This gets called at splsoftnet from if_ppp.c at various times
498  * when there is data ready to be sent.
499  */
500 static void
501 pppasyncstart(sc)
502     register struct ppp_softc *sc;
503 {
504     register struct tty *tp = (struct tty *) sc->sc_devp;
505     register struct mbuf *m;
506     register int len;
507     register u_char *start, *stop, *cp;
508     int n, ndone, done, idle;
509     struct mbuf *m2;
510     int s;
511
512     idle = 0;
513     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
514         /*
515          * See if we have an existing packet partly sent.
516          * If not, get a new packet and start sending it.
517          */
518         m = sc->sc_outm;
519         if (m == NULL) {
520             /*
521              * Get another packet to be sent.
522              */
523             m = ppp_dequeue(sc);
524             if (m == NULL) {
525                 idle = 1;
526                 break;
527             }
528
529             /*
530              * The extra PPP_FLAG will start up a new packet, and thus
531              * will flush any accumulated garbage.  We do this whenever
532              * the line may have been idle for some time.
533              */
534             if (CCOUNT(&tp->t_outq) == 0) {
535                 ++sc->sc_stats.ppp_obytes;
536                 (void) putc(PPP_FLAG, &tp->t_outq);
537             }
538
539             /* Calculate the FCS for the first mbuf's worth. */
540             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
541             sc->sc_if.if_lastchange = time;
542         }
543
544         for (;;) {
545             start = mtod(m, u_char *);
546             len = m->m_len;
547             stop = start + len;
548             while (len > 0) {
549                 /*
550                  * Find out how many bytes in the string we can
551                  * handle without doing something special.
552                  */
553                 for (cp = start; cp < stop; cp++)
554                     if (ESCAPE_P(*cp))
555                         break;
556                 n = cp - start;
557                 if (n) {
558                     /* NetBSD (0.9 or later), 4.3-Reno or similar. */
559                     ndone = n - b_to_q(start, n, &tp->t_outq);
560                     len -= ndone;
561                     start += ndone;
562                     sc->sc_stats.ppp_obytes += ndone;
563
564                     if (ndone < n)
565                         break;  /* packet doesn't fit */
566                 }
567                 /*
568                  * If there are characters left in the mbuf,
569                  * the first one must be special.
570                  * Put it out in a different form.
571                  */
572                 if (len) {
573                     s = spltty();
574                     if (putc(PPP_ESCAPE, &tp->t_outq)) {
575                         splx(s);
576                         break;
577                     }
578                     if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
579                         (void) unputc(&tp->t_outq);
580                         splx(s);
581                         break;
582                     }
583                     splx(s);
584                     sc->sc_stats.ppp_obytes += 2;
585                     start++;
586                     len--;
587                 }
588             }
589
590             /*
591              * If we didn't empty this mbuf, remember where we're up to.
592              * If we emptied the last mbuf, try to add the FCS and closing
593              * flag, and if we can't, leave sc_outm pointing to m, but with
594              * m->m_len == 0, to remind us to output the FCS and flag later.
595              */
596             done = len == 0;
597             if (done && m->m_next == NULL) {
598                 u_char *p, *q;
599                 int c;
600                 u_char endseq[8];
601
602                 /*
603                  * We may have to escape the bytes in the FCS.
604                  */
605                 p = endseq;
606                 c = ~sc->sc_outfcs & 0xFF;
607                 if (ESCAPE_P(c)) {
608                     *p++ = PPP_ESCAPE;
609                     *p++ = c ^ PPP_TRANS;
610                 } else
611                     *p++ = c;
612                 c = (~sc->sc_outfcs >> 8) & 0xFF;
613                 if (ESCAPE_P(c)) {
614                     *p++ = PPP_ESCAPE;
615                     *p++ = c ^ PPP_TRANS;
616                 } else
617                     *p++ = c;
618                 *p++ = PPP_FLAG;
619
620                 /*
621                  * Try to output the FCS and flag.  If the bytes
622                  * don't all fit, back out.
623                  */
624                 s = spltty();
625                 for (q = endseq; q < p; ++q)
626                     if (putc(*q, &tp->t_outq)) {
627                         done = 0;
628                         for (; q > endseq; --q)
629                             unputc(&tp->t_outq);
630                         break;
631                     }
632                 splx(s);
633                 if (done)
634                     sc->sc_stats.ppp_obytes += q - endseq;
635             }
636
637             if (!done) {
638                 /* remember where we got to */
639                 m->m_data = start;
640                 m->m_len = len;
641                 break;
642             }
643
644             /* Finished with this mbuf; free it and move on. */
645             MFREE(m, m2);
646             m = m2;
647             if (m == NULL) {
648                 /* Finished a packet */
649                 break;
650             }
651             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
652         }
653
654         /*
655          * If m == NULL, we have finished a packet.
656          * If m != NULL, we've either done as much work this time
657          * as we need to, or else we've filled up the output queue.
658          */
659         sc->sc_outm = m;
660         if (m)
661             break;
662     }
663
664     /* Call pppstart to start output again if necessary. */
665     s = spltty();
666     pppstart(tp, 0);
667
668     /*
669      * This timeout is needed for operation on a pseudo-tty,
670      * because the pty code doesn't call pppstart after it has
671      * drained the t_outq.
672      */
673     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
674         timeout(ppp_timeout, (void *) sc, 1);
675         sc->sc_flags |= SC_TIMEOUT;
676     }
677
678     splx(s);
679 }
680
681 /*
682  * This gets called when a received packet is placed on
683  * the inq, at splsoftnet.
684  */
685 static void
686 pppasyncctlp(sc)
687     struct ppp_softc *sc;
688 {
689     struct tty *tp;
690     int s;
691
692     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
693     s = spltty();
694     tp = (struct tty *) sc->sc_devp;
695     putc(0, &tp->t_canq);
696     ttwakeup(tp);
697     splx(s);
698 }
699
700 /*
701  * Start output on async tty interface.  If the transmit queue
702  * has drained sufficiently, arrange for pppasyncstart to be
703  * called later at splsoftnet.
704  * Called at spltty or higher.
705  */
706 int
707 pppstart(tp, force)
708     register struct tty *tp;
709     int force;
710 {
711     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
712
713     /*
714      * If there is stuff in the output queue, send it now.
715      * We are being called in lieu of ttstart and must do what it would.
716      */
717     if (tp->t_oproc != NULL)
718         (*tp->t_oproc)(tp);
719
720     /*
721      * If the transmit queue has drained and the tty has not hung up
722      * or been disconnected from the ppp unit, then tell if_ppp.c that
723      * we need more output.
724      */
725     if (CCOUNT(&tp->t_outq) >= PPP_LOWAT && !force)
726         return 0;
727     if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
728         && sc != NULL && tp == (struct tty *) sc->sc_devp) {
729         ppp_restart(sc);
730     }
731
732     return 0;
733 }
734
735 /*
736  * Timeout routine - try to start some more output.
737  */
738 static void
739 ppp_timeout(x)
740     void *x;
741 {
742     struct ppp_softc *sc = (struct ppp_softc *) x;
743     struct tty *tp = (struct tty *) sc->sc_devp;
744     int s;
745
746     s = spltty();
747     sc->sc_flags &= ~SC_TIMEOUT;
748     pppstart(tp, 1);
749     splx(s);
750 }
751
752 /*
753  * Allocate enough mbuf to handle current MRU.
754  */
755 static void
756 pppgetm(sc)
757     register struct ppp_softc *sc;
758 {
759     struct mbuf *m, **mp;
760     int len;
761
762     mp = &sc->sc_m;
763     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
764         if ((m = *mp) == NULL) {
765             MGETHDR(m, M_DONTWAIT, MT_DATA);
766             if (m == NULL)
767                 break;
768             *mp = m;
769             MCLGET(m, M_DONTWAIT);
770         }
771         len -= M_DATASIZE(m);
772         mp = &m->m_next;
773     }
774 }
775
776 /*
777  * tty interface receiver interrupt.
778  */
779 static unsigned paritytab[8] = {
780     0x96696996, 0x69969669, 0x69969669, 0x96696996,
781     0x69969669, 0x96696996, 0x96696996, 0x69969669
782 };
783
784 int
785 pppinput(c, tp)
786     int c;
787     register struct tty *tp;
788 {
789     register struct ppp_softc *sc;
790     struct mbuf *m;
791     int ilen, s;
792
793     sc = (struct ppp_softc *) tp->t_sc;
794     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
795         return 0;
796
797     ++tk_nin;
798     ++sc->sc_stats.ppp_ibytes;
799
800     if (c & TTY_FE) {
801         /* framing error or overrun on this char - abort packet */
802         if (sc->sc_flags & SC_DEBUG)
803             printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
804         goto flush;
805     }
806
807     c &= 0xff;
808
809     /*
810      * Handle software flow control of output.
811      */
812     if (tp->t_iflag & IXON) {
813         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
814             if ((tp->t_state & TS_TTSTOP) == 0) {
815                 tp->t_state |= TS_TTSTOP;
816                 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
817             }
818             return 0;
819         }
820         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
821             tp->t_state &= ~TS_TTSTOP;
822             if (tp->t_oproc != NULL)
823                 (*tp->t_oproc)(tp);
824             return 0;
825         }
826     }
827
828     s = spltty();
829     if (c & 0x80)
830         sc->sc_flags |= SC_RCV_B7_1;
831     else
832         sc->sc_flags |= SC_RCV_B7_0;
833     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
834         sc->sc_flags |= SC_RCV_ODDP;
835     else
836         sc->sc_flags |= SC_RCV_EVNP;
837     splx(s);
838
839     if (sc->sc_flags & SC_LOG_RAWIN)
840         ppplogchar(sc, c);
841
842     if (c == PPP_FLAG) {
843         ilen = sc->sc_ilen;
844         sc->sc_ilen = 0;
845
846         if (sc->sc_rawin_count > 0) 
847             ppplogchar(sc, -1);
848
849         /*
850          * If SC_ESCAPED is set, then we've seen the packet
851          * abort sequence "}~".
852          */
853         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
854             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
855             s = spltty();
856             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
857             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
858                 if (sc->sc_flags & SC_DEBUG)
859                     printf("ppp%d: bad fcs %x, pkt len %d\n",
860                            sc->sc_if.if_unit, sc->sc_fcs, ilen);
861                 sc->sc_if.if_ierrors++;
862                 sc->sc_stats.ppp_ierrors++;
863             } else
864                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
865             splx(s);
866             return 0;
867         }
868
869         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
870             if (ilen) {
871                 if (sc->sc_flags & SC_DEBUG)
872                     printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
873                 s = spltty();
874                 sc->sc_if.if_ierrors++;
875                 sc->sc_stats.ppp_ierrors++;
876                 sc->sc_flags |= SC_PKTLOST;
877                 splx(s);
878             }
879             return 0;
880         }
881
882         /*
883          * Remove FCS trailer.  Somewhat painful...
884          */
885         ilen -= 2;
886         if (--sc->sc_mc->m_len == 0) {
887             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
888                 ;
889             sc->sc_mc = m;
890         }
891         sc->sc_mc->m_len--;
892
893         /* excise this mbuf chain */
894         m = sc->sc_m;
895         sc->sc_m = sc->sc_mc->m_next;
896         sc->sc_mc->m_next = NULL;
897
898         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
899         if (sc->sc_flags & SC_PKTLOST) {
900             s = spltty();
901             sc->sc_flags &= ~SC_PKTLOST;
902             splx(s);
903         }
904
905         pppgetm(sc);
906         return 0;
907     }
908
909     if (sc->sc_flags & SC_FLUSH) {
910         if (sc->sc_flags & SC_LOG_FLUSH)
911             ppplogchar(sc, c);
912         return 0;
913     }
914
915     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
916         return 0;
917
918     s = spltty();
919     if (sc->sc_flags & SC_ESCAPED) {
920         sc->sc_flags &= ~SC_ESCAPED;
921         c ^= PPP_TRANS;
922     } else if (c == PPP_ESCAPE) {
923         sc->sc_flags |= SC_ESCAPED;
924         splx(s);
925         return 0;
926     }
927     splx(s);
928
929     /*
930      * Initialize buffer on first octet received.
931      * First octet could be address or protocol (when compressing
932      * address/control).
933      * Second octet is control.
934      * Third octet is first or second (when compressing protocol)
935      * octet of protocol.
936      * Fourth octet is second octet of protocol.
937      */
938     if (sc->sc_ilen == 0) {
939         /* reset the first input mbuf */
940         if (sc->sc_m == NULL) {
941             pppgetm(sc);
942             if (sc->sc_m == NULL) {
943                 if (sc->sc_flags & SC_DEBUG)
944                     printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
945                 goto flush;
946             }
947         }
948         m = sc->sc_m;
949         m->m_len = 0;
950         m->m_data = M_DATASTART(sc->sc_m);
951         sc->sc_mc = m;
952         sc->sc_mp = mtod(m, char *);
953         sc->sc_fcs = PPP_INITFCS;
954         if (c != PPP_ALLSTATIONS) {
955             if (sc->sc_flags & SC_REJ_COMP_AC) {
956                 if (sc->sc_flags & SC_DEBUG)
957                     printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
958                            sc->sc_if.if_unit, c);
959                 goto flush;
960             }
961             *sc->sc_mp++ = PPP_ALLSTATIONS;
962             *sc->sc_mp++ = PPP_UI;
963             sc->sc_ilen += 2;
964             m->m_len += 2;
965         }
966     }
967     if (sc->sc_ilen == 1 && c != PPP_UI) {
968         if (sc->sc_flags & SC_DEBUG)
969             printf("ppp%d: missing UI (0x3), got 0x%x\n",
970                    sc->sc_if.if_unit, c);
971         goto flush;
972     }
973     if (sc->sc_ilen == 2 && (c & 1) == 1) {
974         /* a compressed protocol */
975         *sc->sc_mp++ = 0;
976         sc->sc_ilen++;
977         sc->sc_mc->m_len++;
978     }
979     if (sc->sc_ilen == 3 && (c & 1) == 0) {
980         if (sc->sc_flags & SC_DEBUG)
981             printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
982                    (sc->sc_mp[-1] << 8) + c);
983         goto flush;
984     }
985
986     /* packet beyond configured mru? */
987     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
988         if (sc->sc_flags & SC_DEBUG)
989             printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
990         goto flush;
991     }
992
993     /* is this mbuf full? */
994     m = sc->sc_mc;
995     if (M_TRAILINGSPACE(m) <= 0) {
996         if (m->m_next == NULL) {
997             pppgetm(sc);
998             if (m->m_next == NULL) {
999                 if (sc->sc_flags & SC_DEBUG)
1000                     printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1001                 goto flush;
1002             }
1003         }
1004         sc->sc_mc = m = m->m_next;
1005         m->m_len = 0;
1006         m->m_data = M_DATASTART(m);
1007         sc->sc_mp = mtod(m, char *);
1008     }
1009
1010     ++m->m_len;
1011     *sc->sc_mp++ = c;
1012     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1013     return 0;
1014
1015  flush:
1016     if (!(sc->sc_flags & SC_FLUSH)) {
1017         s = spltty();
1018         sc->sc_if.if_ierrors++;
1019         sc->sc_stats.ppp_ierrors++;
1020         sc->sc_flags |= SC_FLUSH;
1021         splx(s);
1022         if (sc->sc_flags & SC_LOG_FLUSH)
1023             ppplogchar(sc, c);
1024     }
1025     return 0;
1026 }
1027
1028 #define MAX_DUMP_BYTES  128
1029
1030 static void
1031 ppplogchar(sc, c)
1032     struct ppp_softc *sc;
1033     int c;
1034 {
1035     if (c >= 0)
1036         sc->sc_rawin[sc->sc_rawin_count++] = c;
1037     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1038         || (c < 0 && sc->sc_rawin_count > 0)) {
1039         printf("ppp%d input: ", sc->sc_if.if_unit);
1040         pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1041         sc->sc_rawin_count = 0;
1042     }
1043 }
1044
1045 static void
1046 pppdumpb(b, l)
1047     u_char *b;
1048     int l;
1049 {
1050     char buf[3*MAX_DUMP_BYTES+4];
1051     char *bp = buf;
1052     static char digits[] = "0123456789abcdef";
1053
1054     while (l--) {
1055         if (bp >= buf + sizeof(buf) - 3) {
1056             *bp++ = '>';
1057             break;
1058         }
1059         *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1060         *bp++ = digits[*b++ & 0xf];
1061         *bp++ = ' ';
1062     }
1063
1064     *bp = 0;
1065     printf("%s\n", buf);
1066 }
1067
1068 #endif  /* NPPP > 0 */