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