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