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