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