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