xref: /openbsd/sys/net/ppp_tty.c (revision 8529ddd3)
1 /*	$OpenBSD: ppp_tty.c,v 1.32 2015/04/10 13:58:20 dlg 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/socket.h>
105 #include <sys/timeout.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_var.h>
116 #include <net/if_types.h>
117 
118 #ifdef VJC
119 #include <netinet/in.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_t dev, struct tty *tp)
183 {
184     struct proc *p = curproc;		/* XXX */
185     struct ppp_softc *sc;
186     int error, s;
187 
188     if ((error = suser(p, 0)) != 0)
189 	return (error);
190 
191     s = spltty();
192 
193     if (tp->t_line == PPPDISC) {
194 	sc = (struct ppp_softc *) tp->t_sc;
195 	if (sc != NULL && sc->sc_devp == (void *) tp) {
196 	    splx(s);
197 	    return (0);
198 	}
199     }
200 
201     if ((sc = pppalloc(p->p_p->ps_pid)) == NULL) {
202 	splx(s);
203 	return ENXIO;
204     }
205 
206     if (sc->sc_relinq)
207 	(*sc->sc_relinq)(sc);	/* get previous owner to relinquish the unit */
208 
209     timeout_set(&sc->sc_timo, ppp_timeout, sc);
210     sc->sc_ilen = 0;
211     sc->sc_m = NULL;
212     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
213     sc->sc_asyncmap[0] = 0xffffffff;
214     sc->sc_asyncmap[3] = 0x60000000;
215     sc->sc_rasyncmap = 0;
216     sc->sc_devp = (void *) tp;
217     sc->sc_start = pppasyncstart;
218     sc->sc_ctlp = pppasyncctlp;
219     sc->sc_relinq = pppasyncrelinq;
220     sc->sc_outm = NULL;
221     pppgetm(sc);
222     sc->sc_if.if_flags |= IFF_RUNNING;
223     sc->sc_if.if_baudrate = tp->t_ospeed;
224 
225     tp->t_sc = (caddr_t) sc;
226     ttyflush(tp, FREAD | FWRITE);
227 
228     splx(s);
229     return (0);
230 }
231 
232 /*
233  * Line specific close routine, called from device close routine
234  * and from ttioctl.
235  * Detach the tty from the ppp unit.
236  * Mimics part of ttyclose().
237  */
238 int
239 pppclose(struct tty *tp, int flag)
240 {
241     struct ppp_softc *sc;
242     int s;
243 
244     s = spltty();
245     ttyflush(tp, FREAD|FWRITE);
246     tp->t_line = 0;
247     sc = (struct ppp_softc *) tp->t_sc;
248     if (sc != NULL) {
249 	tp->t_sc = NULL;
250 	if (tp == (struct tty *) sc->sc_devp) {
251 	    pppasyncrelinq(sc);
252 	    pppdealloc(sc);
253 	}
254     }
255     splx(s);
256     return 0;
257 }
258 
259 /*
260  * Relinquish the interface unit to another device.
261  */
262 void
263 pppasyncrelinq(struct ppp_softc *sc)
264 {
265     int s;
266 
267     s = spltty();
268     if (sc->sc_outm) {
269 	m_freem(sc->sc_outm);
270 	sc->sc_outm = NULL;
271     }
272     if (sc->sc_m) {
273 	m_freem(sc->sc_m);
274 	sc->sc_m = NULL;
275     }
276     if (sc->sc_flags & SC_TIMEOUT) {
277 	timeout_del(&sc->sc_timo);
278 	sc->sc_flags &= ~SC_TIMEOUT;
279     }
280     splx(s);
281 }
282 
283 /*
284  * Line specific (tty) read routine.
285  */
286 int
287 pppread(struct tty *tp, struct uio *uio, int flag)
288 {
289     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
290     struct mbuf *m, *m0;
291     int s;
292     int error = 0;
293 
294     if (sc == NULL)
295 	return 0;
296     /*
297      * Loop waiting for input, checking that nothing disasterous
298      * happens in the meantime.
299      */
300     s = spltty();
301     for (;;) {
302 	if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
303 	    splx(s);
304 	    return 0;
305 	}
306 	/* Get the packet from the input queue */
307 	m0 = mq_dequeue(&sc->sc_inq);
308 	if (m0 != NULL)
309 	    break;
310 	if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
311 	    && (tp->t_state & TS_ISOPEN)) {
312 	    splx(s);
313 	    return 0;		/* end of file */
314 	}
315 	if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
316 	    splx(s);
317 	    return (EWOULDBLOCK);
318 	}
319 	error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
320 	if (error) {
321 	    splx(s);
322 	    return error;
323 	}
324     }
325 
326     /* Pull place-holder byte out of canonical queue */
327     getc(&tp->t_canq);
328     splx(s);
329 
330     for (m = m0; m && uio->uio_resid; m = m->m_next)
331 	if ((error = uiomovei(mtod(m, u_char *), m->m_len, uio)) != 0)
332 	    break;
333     m_freem(m0);
334     return (error);
335 }
336 
337 /*
338  * Line specific (tty) write routine.
339  */
340 int
341 pppwrite(struct tty *tp, struct uio *uio, int flag)
342 {
343     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
344     struct mbuf *m, *m0, **mp;
345     struct sockaddr dst;
346     int len, error;
347 
348     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
349 	return 0;		/* wrote 0 bytes */
350     if (tp->t_line != PPPDISC)
351 	return (EINVAL);
352     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
353 	return EIO;
354     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
355 	uio->uio_resid < PPP_HDRLEN)
356 	return (EMSGSIZE);
357     for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
358 	if (mp == &m0) {
359 	    MGETHDR(m, M_WAIT, MT_DATA);
360 	    m->m_pkthdr.len = uio->uio_resid - PPP_HDRLEN;
361 	    m->m_pkthdr.rcvif = NULL;
362 	} else
363 	    MGET(m, M_WAIT, MT_DATA);
364 	*mp = m;
365 	m->m_len = 0;
366 	if (uio->uio_resid >= MCLBYTES / 2)
367 	    MCLGET(m, M_DONTWAIT);
368 	len = M_TRAILINGSPACE(m);
369 	if (len > uio->uio_resid)
370 	    len = uio->uio_resid;
371 	if ((error = uiomovei(mtod(m, u_char *), len, uio)) != 0) {
372 	    m_freem(m0);
373 	    return (error);
374 	}
375 	m->m_len = len;
376     }
377     dst.sa_family = AF_UNSPEC;
378     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
379     m0->m_data += PPP_HDRLEN;
380     m0->m_len -= PPP_HDRLEN;
381     return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
382 }
383 
384 /*
385  * Line specific (tty) ioctl routine.
386  * This discipline requires that tty device drivers call
387  * the line specific l_ioctl routine from their ioctl routines.
388  */
389 /* ARGSUSED */
390 int
391 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
392 {
393     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
394     int error, s;
395 
396     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
397 	return -1;
398 
399     error = 0;
400     switch (cmd) {
401     case PPPIOCSASYNCMAP:
402 	if ((error = suser(p, 0)) != 0)
403 	    break;
404 	sc->sc_asyncmap[0] = *(u_int *)data;
405 	break;
406 
407     case PPPIOCGASYNCMAP:
408 	*(u_int *)data = sc->sc_asyncmap[0];
409 	break;
410 
411     case PPPIOCSRASYNCMAP:
412 	if ((error = suser(p, 0)) != 0)
413 	    break;
414 	sc->sc_rasyncmap = *(u_int *)data;
415 	break;
416 
417     case PPPIOCGRASYNCMAP:
418 	*(u_int *)data = sc->sc_rasyncmap;
419 	break;
420 
421     case PPPIOCSXASYNCMAP:
422 	if ((error = suser(p, 0)) != 0)
423 	    break;
424 	s = spltty();
425 	bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
426 	sc->sc_asyncmap[1] = 0;		    /* mustn't escape 0x20 - 0x3f */
427 	sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
428 	sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
429 	splx(s);
430 	break;
431 
432     case PPPIOCGXASYNCMAP:
433 	bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
434 	break;
435 
436     default:
437 	error = pppioctl(sc, cmd, data, flag, p);
438 	if (error == 0 && cmd == PPPIOCSMRU)
439 	    pppgetm(sc);
440     }
441 
442     return error;
443 }
444 
445 /*
446  * FCS lookup table as calculated by genfcstab.
447  */
448 static u_int16_t fcstab[256] = {
449 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
450 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
451 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
452 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
453 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
454 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
455 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
456 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
457 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
458 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
459 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
460 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
461 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
462 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
463 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
464 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
465 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
466 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
467 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
468 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
469 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
470 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
471 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
472 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
473 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
474 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
475 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
476 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
477 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
478 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
479 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
480 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
481 };
482 
483 /*
484  * Calculate a new FCS given the current FCS and the new data.
485  */
486 u_int16_t
487 pppfcs(u_int16_t fcs, u_char *cp, int len)
488 {
489     while (len--)
490 	fcs = PPP_FCS(fcs, *cp++);
491     return (fcs);
492 }
493 
494 /*
495  * This gets called from pppoutput when a new packet is
496  * put on a queue, at splsoftnet.
497  */
498 void
499 pppasyncstart(struct ppp_softc *sc)
500 {
501     struct tty *tp = (struct tty *) sc->sc_devp;
502     struct mbuf *m;
503     int len;
504     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(struct ppp_softc *sc)
683 {
684     struct tty *tp;
685     int s;
686 
687     /* Put a placeholder byte in canq for ttpoll()/ttnread(). */
688     s = spltty();
689     tp = (struct tty *) sc->sc_devp;
690     putc(0, &tp->t_canq);
691     ttwakeup(tp);
692     splx(s);
693 }
694 
695 /*
696  * Start output on async tty interface.  If the transmit queue
697  * has drained sufficiently, arrange for pppasyncstart to be
698  * called later at splsoftnet.
699  */
700 int
701 pppstart(struct tty *tp, int force)
702 {
703     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
704 
705     /*
706      * If there is stuff in the output queue, send it now.
707      * We are being called in lieu of ttstart and must do what it would.
708      */
709     if (tp->t_oproc != NULL)
710 	(*tp->t_oproc)(tp);
711 
712     /*
713      * If the transmit queue has drained and the tty has not hung up
714      * or been disconnected from the ppp unit, then tell if_ppp.c that
715      * we need more output.
716      */
717     if ((CCOUNT(&tp->t_outq) < PPP_LOWAT || force)
718 	&& !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
719 	&& sc != NULL && tp == (struct tty *) sc->sc_devp) {
720 	ppp_restart(sc);
721     }
722 
723     return 0;
724 }
725 
726 /*
727  * Timeout routine - try to start some more output.
728  */
729 void
730 ppp_timeout(void *x)
731 {
732     struct ppp_softc *sc = (struct ppp_softc *) x;
733     struct tty *tp = (struct tty *) sc->sc_devp;
734     int s;
735 
736     s = spltty();
737     sc->sc_flags &= ~SC_TIMEOUT;
738     pppstart(tp, 1);
739     splx(s);
740 }
741 
742 /*
743  * Allocate enough mbuf to handle current MRU.
744  */
745 void
746 pppgetm(struct ppp_softc *sc)
747 {
748     struct mbuf *m, **mp;
749     int len;
750     int s;
751 
752     s = spltty();
753     mp = &sc->sc_m;
754     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
755 	if ((m = *mp) == NULL) {
756 	    MGETHDR(m, M_DONTWAIT, MT_DATA);
757 	    if (m == NULL)
758 		break;
759 	    *mp = m;
760 	    MCLGET(m, M_DONTWAIT);
761 	}
762 	len -= M_DATASIZE(m);
763 	mp = &m->m_next;
764     }
765     splx(s);
766 }
767 
768 /*
769  * tty interface receiver interrupt.
770  */
771 static unsigned int paritytab[8] = {
772     0x96696996, 0x69969669, 0x69969669, 0x96696996,
773     0x69969669, 0x96696996, 0x96696996, 0x69969669
774 };
775 
776 int
777 pppinput(int c, struct tty *tp)
778 {
779     struct ppp_softc *sc;
780     struct mbuf *m;
781     int ilen, s;
782 
783     sc = (struct ppp_softc *) tp->t_sc;
784     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
785 	return 0;
786 
787     ++tk_nin;
788     ++sc->sc_stats.ppp_ibytes;
789 
790     if (c & TTY_FE) {
791 	/* framing error or overrun on this char - abort packet */
792 	if (sc->sc_flags & SC_DEBUG)
793 	    printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
794 	goto flush;
795     }
796 
797     c &= 0xff;
798 
799     /*
800      * Handle software flow control of output.
801      */
802     if (tp->t_iflag & IXON) {
803 	if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
804 	    if ((tp->t_state & TS_TTSTOP) == 0) {
805 		tp->t_state |= TS_TTSTOP;
806 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
807 	    }
808 	    return 0;
809 	}
810 	if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
811 	    tp->t_state &= ~TS_TTSTOP;
812 	    if (tp->t_oproc != NULL)
813 		(*tp->t_oproc)(tp);
814 	    return 0;
815 	}
816     }
817 
818     s = spltty();
819     if (c & 0x80)
820 	sc->sc_flags |= SC_RCV_B7_1;
821     else
822 	sc->sc_flags |= SC_RCV_B7_0;
823     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
824 	sc->sc_flags |= SC_RCV_ODDP;
825     else
826 	sc->sc_flags |= SC_RCV_EVNP;
827     splx(s);
828 
829     if (sc->sc_flags & SC_LOG_RAWIN)
830 	ppplogchar(sc, c);
831 
832     if (c == PPP_FLAG) {
833 	ilen = sc->sc_ilen;
834 	sc->sc_ilen = 0;
835 
836 	if (sc->sc_rawin_count > 0)
837 	    ppplogchar(sc, -1);
838 
839 	/*
840 	 * If SC_ESCAPED is set, then we've seen the packet
841 	 * abort sequence "}~".
842 	 */
843 	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
844 	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
845 	    s = spltty();
846 	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
847 	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
848 		if (sc->sc_flags & SC_DEBUG)
849 		    printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
850 			sc->sc_fcs);
851 		sc->sc_if.if_ierrors++;
852 		sc->sc_stats.ppp_ierrors++;
853 	    } else
854 		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
855 	    splx(s);
856 	    return 0;
857 	}
858 
859 	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
860 	    if (ilen) {
861 		if (sc->sc_flags & SC_DEBUG)
862 		    printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
863 		s = spltty();
864 		sc->sc_if.if_ierrors++;
865 		sc->sc_stats.ppp_ierrors++;
866 		sc->sc_flags |= SC_PKTLOST;
867 		splx(s);
868 	    }
869 	    return 0;
870 	}
871 
872 	/*
873 	 * Remove FCS trailer.  Somewhat painful...
874 	 */
875 	ilen -= 2;
876 	if (--sc->sc_mc->m_len == 0) {
877 	    for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
878 		;
879 	    sc->sc_mc = m;
880 	}
881 	sc->sc_mc->m_len--;
882 
883 	/* excise this mbuf chain */
884 	m = sc->sc_m;
885 	sc->sc_m = sc->sc_mc->m_next;
886 	sc->sc_mc->m_next = NULL;
887 
888 	ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
889 	if (sc->sc_flags & SC_PKTLOST) {
890 	    s = spltty();
891 	    sc->sc_flags &= ~SC_PKTLOST;
892 	    splx(s);
893 	}
894 
895 	pppgetm(sc);
896 	return 0;
897     }
898 
899     if (sc->sc_flags & SC_FLUSH) {
900 	if (sc->sc_flags & SC_LOG_FLUSH)
901 	    ppplogchar(sc, c);
902 	return 0;
903     }
904 
905     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
906 	return 0;
907 
908     s = spltty();
909     if (sc->sc_flags & SC_ESCAPED) {
910 	sc->sc_flags &= ~SC_ESCAPED;
911 	c ^= PPP_TRANS;
912     } else if (c == PPP_ESCAPE) {
913 	sc->sc_flags |= SC_ESCAPED;
914 	splx(s);
915 	return 0;
916     }
917     splx(s);
918 
919     /*
920      * Initialize buffer on first octet received.
921      * First octet could be address or protocol (when compressing
922      * address/control).
923      * Second octet is control.
924      * Third octet is first or second (when compressing protocol)
925      * octet of protocol.
926      * Fourth octet is second octet of protocol.
927      */
928     if (sc->sc_ilen == 0) {
929 	/* reset the first input mbuf */
930 	if (sc->sc_m == NULL) {
931 	    pppgetm(sc);
932 	    if (sc->sc_m == NULL) {
933 		if (sc->sc_flags & SC_DEBUG)
934 		    printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
935 		goto flush;
936 	    }
937 	}
938 	m = sc->sc_m;
939 	m->m_len = 0;
940 	m->m_data = M_DATASTART(sc->sc_m);
941 	sc->sc_mc = m;
942 	sc->sc_mp = mtod(m, char *);
943 	sc->sc_fcs = PPP_INITFCS;
944 	if (c != PPP_ALLSTATIONS) {
945 	    if (sc->sc_flags & SC_REJ_COMP_AC) {
946 		if (sc->sc_flags & SC_DEBUG)
947 		    printf("%s: garbage received: 0x%x (need 0xFF)\n",
948 			sc->sc_if.if_xname, c);
949 		goto flush;
950 	    }
951 	    *sc->sc_mp++ = PPP_ALLSTATIONS;
952 	    *sc->sc_mp++ = PPP_UI;
953 	    sc->sc_ilen += 2;
954 	    m->m_len += 2;
955 	}
956     }
957     if (sc->sc_ilen == 1 && c != PPP_UI) {
958 	if (sc->sc_flags & SC_DEBUG)
959 	    printf("%s: missing UI (0x3), got 0x%x\n",
960 		sc->sc_if.if_xname, c);
961 	goto flush;
962     }
963     if (sc->sc_ilen == 2 && (c & 1) == 1) {
964 	/* a compressed protocol */
965 	*sc->sc_mp++ = 0;
966 	sc->sc_ilen++;
967 	sc->sc_mc->m_len++;
968     }
969     if (sc->sc_ilen == 3 && (c & 1) == 0) {
970 	if (sc->sc_flags & SC_DEBUG)
971 	    printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
972 		(sc->sc_mp[-1] << 8) + c);
973 	goto flush;
974     }
975 
976     /* packet beyond configured mru? */
977     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
978 	if (sc->sc_flags & SC_DEBUG)
979 	    printf("%s: packet too big\n", sc->sc_if.if_xname);
980 	goto flush;
981     }
982 
983     /* is this mbuf full? */
984     m = sc->sc_mc;
985     if (M_TRAILINGSPACE(m) <= 0) {
986 	if (m->m_next == NULL) {
987 	    pppgetm(sc);
988 	    if (m->m_next == NULL) {
989 		if (sc->sc_flags & SC_DEBUG)
990 		    printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
991 		goto flush;
992 	    }
993 	}
994 	sc->sc_mc = m = m->m_next;
995 	m->m_len = 0;
996 	m->m_data = M_DATASTART(m);
997 	sc->sc_mp = mtod(m, char *);
998     }
999 
1000     ++m->m_len;
1001     *sc->sc_mp++ = c;
1002     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1003     return 0;
1004 
1005  flush:
1006     if (!(sc->sc_flags & SC_FLUSH)) {
1007 	s = spltty();
1008 	sc->sc_if.if_ierrors++;
1009 	sc->sc_stats.ppp_ierrors++;
1010 	sc->sc_flags |= SC_FLUSH;
1011 	splx(s);
1012 	if (sc->sc_flags & SC_LOG_FLUSH)
1013 	    ppplogchar(sc, c);
1014     }
1015     return 0;
1016 }
1017 
1018 #define MAX_DUMP_BYTES	128
1019 
1020 void
1021 ppplogchar(struct ppp_softc *sc, int c)
1022 {
1023     if (c >= 0)
1024 	sc->sc_rawin[sc->sc_rawin_count++] = c;
1025     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1026 	|| (c < 0 && sc->sc_rawin_count > 0)) {
1027 	printf("%s input: ", sc->sc_if.if_xname);
1028 	pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1029 	sc->sc_rawin_count = 0;
1030     }
1031 }
1032 
1033 void
1034 pppdumpb(u_char *b, int l)
1035 {
1036     char buf[3*MAX_DUMP_BYTES+4];
1037     char *bp = buf;
1038     static char digits[] = "0123456789abcdef";
1039 
1040     while (l--) {
1041 	if (bp >= buf + sizeof(buf) - 3) {
1042 	    *bp++ = '>';
1043 	    break;
1044 	}
1045 	*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1046 	*bp++ = digits[*b++ & 0xf];
1047 	*bp++ = ' ';
1048     }
1049 
1050     *bp = 0;
1051     printf("%s\n", buf);
1052 }
1053 
1054 #endif	/* NPPP > 0 */
1055