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