Some mods from Bruce Evans
[ppp.git] / freebsd-2.0 / 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.3 1995/08/16 01:36:40 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, ttymodem
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 (sc == NULL)
291         return 0;
292     /*
293      * Loop waiting for input, checking that nothing disasterous
294      * happens in the meantime.
295      */
296     s = splimp();
297     for (;;) {
298         if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
299             splx(s);
300             return 0;
301         }
302         if (sc->sc_inq.ifq_head != NULL)
303             break;
304         if ((tp->t_state & TS_CONNECTED) == 0 && (tp->t_state & TS_ISOPEN)) {
305             splx(s);
306             return 0;           /* end of file */
307         }
308         if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
309             splx(s);
310             return (EWOULDBLOCK);
311         }
312         error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, "pppin", 0);
313         if (error) {
314             splx(s);
315             return error;
316         }
317     }
318
319     /* Pull place-holder byte out of canonical queue */
320     getc(&tp->t_canq);
321
322     /* Get the packet from the input queue */
323     IF_DEQUEUE(&sc->sc_inq, m0);
324     splx(s);
325
326     for (m = m0; m && uio->uio_resid; m = m->m_next)
327         if (error = uiomove(mtod(m, u_char *), m->m_len, uio))
328             break;
329     m_freem(m0);
330     return (error);
331 }
332
333 /*
334  * Line specific (tty) write routine.
335  */
336 int
337 pppwrite(tp, uio, flag)
338     register struct tty *tp;
339     struct uio *uio;
340     int flag;
341 {
342     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
343     struct mbuf *m, *m0, **mp;
344     struct sockaddr dst;
345     int len, error;
346
347     if ((tp->t_state & TS_CONNECTED) == 0)
348         return 0;               /* wrote 0 bytes */
349     if (tp->t_line != PPPDISC)
350         return (EINVAL);
351     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
352         return EIO;
353     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
354         uio->uio_resid < PPP_HDRLEN)
355         return (EMSGSIZE);
356     for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
357         MGET(m, M_WAIT, MT_DATA);
358         if ((*mp = m) == NULL) {
359             m_freem(m0);
360             return (ENOBUFS);
361         }
362         m->m_len = 0;
363         if (uio->uio_resid >= MCLBYTES / 2)
364             MCLGET(m, M_DONTWAIT);
365         len = M_TRAILINGSPACE(m);
366         if (len > uio->uio_resid)
367             len = uio->uio_resid;
368         if (error = uiomove(mtod(m, u_char *), len, uio)) {
369             m_freem(m0);
370             return (error);
371         }
372         m->m_len = len;
373     }
374     dst.sa_family = AF_UNSPEC;
375     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
376     m0->m_data += PPP_HDRLEN;
377     m0->m_len -= PPP_HDRLEN;
378     return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
379 }
380
381 /*
382  * Line specific (tty) ioctl routine.
383  * This discipline requires that tty device drivers call
384  * the line specific l_ioctl routine from their ioctl routines.
385  */
386 /* ARGSUSED */
387 int
388 ppptioctl(tp, cmd, data, flag, p)
389     struct tty *tp;
390     caddr_t data;
391     int cmd, flag;
392     struct proc *p;
393 {
394     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
395     int error, s;
396
397     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
398         return -1;
399
400     error = 0;
401     switch (cmd) {
402     case PPPIOCSASYNCMAP:
403         if (error = suser(p->p_ucred, &p->p_acflag))
404             break;
405         sc->sc_asyncmap[0] = *(u_int *)data;
406         break;
407
408     case PPPIOCGASYNCMAP:
409         *(u_int *)data = sc->sc_asyncmap[0];
410         break;
411
412     case PPPIOCSRASYNCMAP:
413         if (error = suser(p->p_ucred, &p->p_acflag))
414             break;
415         sc->sc_rasyncmap = *(u_int *)data;
416         break;
417
418     case PPPIOCGRASYNCMAP:
419         *(u_int *)data = sc->sc_rasyncmap;
420         break;
421
422     case PPPIOCSXASYNCMAP:
423         if (error = suser(p->p_ucred, &p->p_acflag))
424             break;
425         s = spltty();
426         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
427         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
428         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
429         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
430         splx(s);
431         break;
432
433     case PPPIOCGXASYNCMAP:
434         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
435         break;
436
437     default:
438         error = pppioctl(sc, cmd, data, flag, p);
439         if (error == 0 && cmd == PPPIOCSMRU)
440             pppgetm(sc);
441     }
442
443     return error;
444 }
445
446 /*
447  * FCS lookup table as calculated by genfcstab.
448  */
449 static u_short fcstab[256] = {
450         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
451         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
452         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
453         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
454         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
455         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
456         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
457         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
458         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
459         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
460         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
461         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
462         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
463         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
464         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
465         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
466         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
467         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
468         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
469         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
470         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
471         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
472         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
473         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
474         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
475         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
476         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
477         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
478         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
479         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
480         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
481         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
482 };
483
484 /*
485  * Calculate a new FCS given the current FCS and the new data.
486  */
487 static u_short
488 pppfcs(fcs, cp, len)
489     register u_short fcs;
490     register u_char *cp;
491     register int len;
492 {
493     while (len--)
494         fcs = PPP_FCS(fcs, *cp++);
495     return (fcs);
496 }
497
498 /*
499  * This gets called from pppoutput when a new packet is
500  * put on a queue.
501  */
502 static void
503 pppasyncstart(sc)
504     register struct ppp_softc *sc;
505 {
506     register struct tty *tp = (struct tty *) sc->sc_devp;
507     int s;
508
509     s = splimp();
510     pppstart(tp);
511     splx(s);
512 }
513
514 /*
515  * This gets called when a received packet is placed on
516  * the inq.
517  */
518 static void
519 pppasyncctlp(sc)
520     struct ppp_softc *sc;
521 {
522     struct tty *tp;
523
524     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
525     tp = (struct tty *) sc->sc_devp;
526     putc(0, &tp->t_canq);
527     ttwakeup(tp);
528 }
529
530 /*
531  * Start output on async tty interface.  Get another datagram
532  * to send from the interface queue and start sending it.
533  */
534 int
535 pppstart(tp)
536     register struct tty *tp;
537 {
538     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
539     register struct mbuf *m;
540     register int len;
541     register u_char *start, *stop, *cp;
542     int n, s, ndone, done, idle;
543     struct mbuf *m2;
544
545     if ((tp->t_state & TS_CONNECTED) == 0
546         || sc == NULL || tp != (struct tty *) sc->sc_devp) {
547         if (tp->t_oproc != NULL)
548             (*tp->t_oproc)(tp);
549         return 0;
550     }
551
552     idle = 0;
553     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
554         /*
555          * See if we have an existing packet partly sent.
556          * If not, get a new packet and start sending it.
557          */
558         m = sc->sc_outm;
559         if (m == NULL) {
560             /*
561              * Get another packet to be sent.
562              */
563             m = ppp_dequeue(sc);
564             if (m == NULL) {
565                 idle = 1;
566                 break;
567             }
568
569             /*
570              * The extra PPP_FLAG will start up a new packet, and thus
571              * will flush any accumulated garbage.  We do this whenever
572              * the line may have been idle for some time.
573              */
574             if (CCOUNT(&tp->t_outq) == 0) {
575                 ++sc->sc_bytessent;
576                 (void) putc(PPP_FLAG, &tp->t_outq);
577             }
578
579             /* Calculate the FCS for the first mbuf's worth. */
580             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
581         }
582
583         for (;;) {
584             start = mtod(m, u_char *);
585             len = m->m_len;
586             stop = start + len;
587             while (len > 0) {
588                 /*
589                  * Find out how many bytes in the string we can
590                  * handle without doing something special.
591                  */
592                 for (cp = start; cp < stop; cp++)
593                     if (ESCAPE_P(*cp))
594                         break;
595                 n = cp - start;
596                 if (n) {
597                     /* NetBSD (0.9 or later), 4.3-Reno or similar. */
598                     ndone = n - b_to_q(start, n, &tp->t_outq);
599                     len -= ndone;
600                     start += ndone;
601                     sc->sc_bytessent += ndone;
602
603                     if (ndone < n)
604                         break;  /* packet doesn't fit */
605                 }
606                 /*
607                  * If there are characters left in the mbuf,
608                  * the first one must be special..
609                  * Put it out in a different form.
610                  */
611                 if (len) {
612                     if (putc(PPP_ESCAPE, &tp->t_outq))
613                         break;
614                     if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
615                         (void) unputc(&tp->t_outq);
616                         break;
617                     }
618                     sc->sc_bytessent += 2;
619                     start++;
620                     len--;
621                 }
622             }
623
624             /*
625              * If we didn't empty this mbuf, remember where we're up to.
626              * If we emptied the last mbuf, try to add the FCS and closing
627              * flag, and if we can't, leave sc_outm pointing to m, but with
628              * m->m_len == 0, to remind us to output the FCS and flag later.
629              */
630             done = len == 0;
631             if (done && m->m_next == NULL) {
632                 u_char *p, *q;
633                 int c;
634                 u_char endseq[8];
635
636                 /*
637                  * We may have to escape the bytes in the FCS.
638                  */
639                 p = endseq;
640                 c = ~sc->sc_outfcs & 0xFF;
641                 if (ESCAPE_P(c)) {
642                     *p++ = PPP_ESCAPE;
643                     *p++ = c ^ PPP_TRANS;
644                 } else
645                     *p++ = c;
646                 c = (~sc->sc_outfcs >> 8) & 0xFF;
647                 if (ESCAPE_P(c)) {
648                     *p++ = PPP_ESCAPE;
649                     *p++ = c ^ PPP_TRANS;
650                 } else
651                     *p++ = c;
652                 *p++ = PPP_FLAG;
653
654                 /*
655                  * Try to output the FCS and flag.  If the bytes
656                  * don't all fit, back out.
657                  */
658                 for (q = endseq; q < p; ++q)
659                     if (putc(*q, &tp->t_outq)) {
660                         done = 0;
661                         for (; q > endseq; --q)
662                             unputc(&tp->t_outq);
663                         break;
664                     }
665                 sc->sc_bytessent += q - endseq;
666             }
667
668             if (!done) {
669                 /* remember where we got to */
670                 m->m_data = start;
671                 m->m_len = len;
672                 break;
673             }
674
675             /* Finished with this mbuf; free it and move on. */
676             MFREE(m, m2);
677             m = m2;
678             if (m == NULL) {
679                 /* Finished a packet */
680                 sc->sc_if.if_opackets++;
681                 sc->sc_if.if_obytes = sc->sc_bytessent;
682                 break;
683             }
684             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
685         }
686
687         /*
688          * Here we have either finished a packet (m == NULL)
689          * or filled up the output queue (m != NULL).
690          */
691         sc->sc_outm = m;
692         if (m)
693             break;
694     }
695
696     /*
697      * Send anything that may be in the output queue.
698      * We are being called in lieu of ttstart and must do what it would.
699      */
700     if (tp->t_oproc != NULL)
701         (*tp->t_oproc)(tp);
702
703     /*
704      * This timeout is needed for operation on a pseudo-tty,
705      * because the pty code doesn't call pppstart after it has
706      * drained the t_outq.
707      */
708     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
709         timeout(ppp_timeout, (void *) sc, 1);
710         sc->sc_flags |= SC_TIMEOUT;
711     }
712
713     return 0;
714 }
715
716 /*
717  * Timeout routine - try to start some more output.
718  */
719 static void
720 ppp_timeout(x)
721     void *x;
722 {
723     struct ppp_softc *sc = (struct ppp_softc *) x;
724     struct tty *tp = (struct tty *) sc->sc_devp;
725     int s;
726
727     s = splimp();
728     sc->sc_flags &= ~SC_TIMEOUT;
729     pppstart(tp);
730     splx(s);
731 }
732
733 /*
734  * Allocate enough mbuf to handle current MRU.
735  */
736 static void
737 pppgetm(sc)
738     register struct ppp_softc *sc;
739 {
740     struct mbuf *m, **mp;
741     int len;
742     int s;
743
744     s = splimp();
745     mp = &sc->sc_m;
746     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
747         if ((m = *mp) == NULL) {
748             MGETHDR(m, M_DONTWAIT, MT_DATA);
749             if (m == NULL)
750                 break;
751             *mp = m;
752             MCLGET(m, M_DONTWAIT);
753         }
754         len -= M_DATASIZE(m);
755         mp = &m->m_next;
756     }
757     splx(s);
758 }
759
760 /*
761  * tty interface receiver interrupt.
762  */
763 static unsigned paritytab[8] = {
764     0x96696996, 0x69969669, 0x69969669, 0x96696996,
765     0x69969669, 0x96696996, 0x96696996, 0x69969669
766 };
767
768 int
769 pppinput(c, tp)
770     int c;
771     register struct tty *tp;
772 {
773     register struct ppp_softc *sc;
774     struct mbuf *m;
775     int ilen, s;
776
777     sc = (struct ppp_softc *) tp->t_sc;
778     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
779         return 0;
780
781     s = spltty();
782     ++tk_nin;
783     ++sc->sc_bytesrcvd;
784
785     if (c & TTY_FE) {
786         /* framing error or overrun on this char - abort packet */
787         if (sc->sc_flags & SC_DEBUG)
788             printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
789         goto flush;
790     }
791
792     c &= 0xff;
793
794     if (c & 0x80)
795         sc->sc_flags |= SC_RCV_B7_1;
796     else
797         sc->sc_flags |= SC_RCV_B7_0;
798     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
799         sc->sc_flags |= SC_RCV_ODDP;
800     else
801         sc->sc_flags |= SC_RCV_EVNP;
802
803     if (sc->sc_flags & SC_LOG_RAWIN)
804         ppplogchar(sc, c);
805
806     if (c == PPP_FLAG) {
807         ilen = sc->sc_ilen;
808         sc->sc_ilen = 0;
809         sc->sc_if.if_ibytes = sc->sc_bytesrcvd;
810
811         if (sc->sc_rawin_count > 0) 
812             ppplogchar(sc, -1);
813
814         /*
815          * If SC_ESCAPED is set, then we've seen the packet
816          * abort sequence "}~".
817          */
818         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
819             || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
820             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
821             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
822                 if (sc->sc_flags & SC_DEBUG)
823                     printf("ppp%d: bad fcs %x\n", sc->sc_if.if_unit,
824                            sc->sc_fcs);
825                 sc->sc_if.if_ierrors++;
826             } else
827                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
828             splx(s);
829             return 0;
830         }
831
832         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
833             if (ilen) {
834                 if (sc->sc_flags & SC_DEBUG)
835                     printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
836                 sc->sc_if.if_ierrors++;
837                 sc->sc_flags |= SC_PKTLOST;
838             }
839             splx(s);
840             return 0;
841         }
842
843         /*
844          * Remove FCS trailer.  Somewhat painful...
845          */
846         ilen -= 2;
847         if (--sc->sc_mc->m_len == 0) {
848             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
849                 ;
850             sc->sc_mc = m;
851         }
852         sc->sc_mc->m_len--;
853
854         /* excise this mbuf chain */
855         m = sc->sc_m;
856         sc->sc_m = sc->sc_mc->m_next;
857         sc->sc_mc->m_next = NULL;
858
859         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
860         sc->sc_flags &= ~SC_PKTLOST;
861
862         pppgetm(sc);
863         splx(s);
864         return 0;
865     }
866
867     if (sc->sc_flags & SC_FLUSH) {
868         if (sc->sc_flags & SC_LOG_FLUSH)
869             ppplogchar(sc, c);
870         splx(s);
871         return 0;
872     }
873
874     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) {
875         splx(s);
876         return 0;
877     }
878
879     if (sc->sc_flags & SC_ESCAPED) {
880         sc->sc_flags &= ~SC_ESCAPED;
881         c ^= PPP_TRANS;
882     } else if (c == PPP_ESCAPE) {
883         sc->sc_flags |= SC_ESCAPED;
884         splx(s);
885         return 0;
886     }
887
888     /*
889      * Initialize buffer on first octet received.
890      * First octet could be address or protocol (when compressing
891      * address/control).
892      * Second octet is control.
893      * Third octet is first or second (when compressing protocol)
894      * octet of protocol.
895      * Fourth octet is second octet of protocol.
896      */
897     if (sc->sc_ilen == 0) {
898         /* reset the first input mbuf */
899         if (sc->sc_m == NULL) {
900             pppgetm(sc);
901             if (sc->sc_m == NULL) {
902                 if (sc->sc_flags & SC_DEBUG)
903                     printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
904                 goto flush;
905             }
906         }
907         m = sc->sc_m;
908         m->m_len = 0;
909         m->m_data = M_DATASTART(sc->sc_m);
910         sc->sc_mc = m;
911         sc->sc_mp = mtod(m, char *);
912         sc->sc_fcs = PPP_INITFCS;
913         if (c != PPP_ALLSTATIONS) {
914             if (sc->sc_flags & SC_REJ_COMP_AC) {
915                 if (sc->sc_flags & SC_DEBUG)
916                     printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
917                            sc->sc_if.if_unit, c);
918                 goto flush;
919             }
920             *sc->sc_mp++ = PPP_ALLSTATIONS;
921             *sc->sc_mp++ = PPP_UI;
922             sc->sc_ilen += 2;
923             m->m_len += 2;
924         }
925     }
926     if (sc->sc_ilen == 1 && c != PPP_UI) {
927         if (sc->sc_flags & SC_DEBUG)
928             printf("ppp%d: missing UI (0x3), got 0x%x\n",
929                    sc->sc_if.if_unit, c);
930         goto flush;
931     }
932     if (sc->sc_ilen == 2 && (c & 1) == 1) {
933         /* a compressed protocol */
934         *sc->sc_mp++ = 0;
935         sc->sc_ilen++;
936         sc->sc_mc->m_len++;
937     }
938     if (sc->sc_ilen == 3 && (c & 1) == 0) {
939         if (sc->sc_flags & SC_DEBUG)
940             printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
941                    (sc->sc_mp[-1] << 8) + c);
942         goto flush;
943     }
944
945     /* packet beyond configured mru? */
946     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
947         if (sc->sc_flags & SC_DEBUG)
948             printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
949         goto flush;
950     }
951
952     /* is this mbuf full? */
953     m = sc->sc_mc;
954     if (M_TRAILINGSPACE(m) <= 0) {
955         if (m->m_next == NULL) {
956             pppgetm(sc);
957             if (m->m_next == NULL) {
958                 if (sc->sc_flags & SC_DEBUG)
959                     printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
960                 goto flush;
961             }
962         }
963         sc->sc_mc = m = m->m_next;
964         m->m_len = 0;
965         m->m_data = M_DATASTART(m);
966         sc->sc_mp = mtod(m, char *);
967     }
968
969     ++m->m_len;
970     *sc->sc_mp++ = c;
971     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
972     splx(s);
973     return 0;
974
975  flush:
976     if (!(sc->sc_flags & SC_FLUSH)) {
977         sc->sc_if.if_ierrors++;
978         sc->sc_flags |= SC_FLUSH;
979         if (sc->sc_flags & SC_LOG_FLUSH)
980             ppplogchar(sc, c);
981     }
982     splx(s);
983     return 0;
984 }
985
986 #define MAX_DUMP_BYTES  128
987
988 static void
989 ppplogchar(sc, c)
990     struct ppp_softc *sc;
991     int c;
992 {
993     if (c >= 0)
994         sc->sc_rawin[sc->sc_rawin_count++] = c;
995     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
996         || c < 0 && sc->sc_rawin_count > 0) {
997         printf("ppp%d input: ", sc->sc_if.if_unit);
998         pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
999         sc->sc_rawin_count = 0;
1000     }
1001 }
1002
1003 static void
1004 pppdumpb(b, l)
1005     u_char *b;
1006     int l;
1007 {
1008     char buf[3*MAX_DUMP_BYTES+4];
1009     char *bp = buf;
1010     static char digits[] = "0123456789abcdef";
1011
1012     while (l--) {
1013         if (bp >= buf + sizeof(buf) - 3) {
1014             *bp++ = '>';
1015             break;
1016         }
1017         *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1018         *bp++ = digits[*b++ & 0xf];
1019         *bp++ = ' ';
1020     }
1021
1022     *bp = 0;
1023     printf("%s\n", buf);
1024 }
1025
1026 #endif  /* NPPP > 0 */