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