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