xref: /openbsd/sys/net/ppp_tty.c (revision 895cab01)
1 /*	$OpenBSD: ppp_tty.c,v 1.55 2024/08/17 09:52:11 denis 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/fcntl.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 #include <sys/rwlock.h>
114 #include <sys/pool.h>
115 
116 #include <net/if.h>
117 #include <net/if_var.h>
118 
119 #ifdef VJC
120 #include <netinet/in.h>
121 #include <netinet/ip.h>
122 #include <net/slcompress.h>
123 #endif
124 
125 #include <net/bpf.h>
126 #include <net/ppp_defs.h>
127 #include <net/if_ppp.h>
128 #include <net/if_pppvar.h>
129 
130 int	pppstart_internal(struct tty *tp, int);
131 
132 u_int16_t pppfcs(u_int16_t fcs, u_char *cp, int len);
133 void	pppasyncstart(struct ppp_softc *);
134 void	pppasyncctlp(struct ppp_softc *);
135 void	pppasyncrelinq(struct ppp_softc *);
136 void	ppp_timeout(void *);
137 void	ppppkt(struct ppp_softc *sc);
138 void	pppdumpb(u_char *b, int l);
139 void	ppplogchar(struct ppp_softc *, int);
140 
141 struct rwlock ppp_pkt_init = RWLOCK_INITIALIZER("ppppktini");
142 struct pool ppp_pkts;
143 
144 #define PKT_MAXLEN(_sc) ((_sc)->sc_mru + PPP_HDRLEN + PPP_FCSLEN)
145 
146 /*
147  * Does c need to be escaped?
148  */
149 #define ESCAPE_P(c)	(sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
150 
151 /*
152  * Procedures for using an async tty interface for PPP.
153  */
154 
155 /* This is a NetBSD-1.0 or later kernel. */
156 #define CCOUNT(q)	((q)->c_cc)
157 
158 /*
159  * Line specific open routine for async tty devices.
160  * Attach the given tty to the first available ppp unit.
161  * Called from device open routine or ttioctl.
162  */
163 int
pppopen(dev_t dev,struct tty * tp,struct proc * p)164 pppopen(dev_t dev, struct tty *tp, struct proc *p)
165 {
166     struct ppp_softc *sc;
167     int error, s;
168 
169     if ((error = suser(p)) != 0)
170 	return (error);
171 
172     rw_enter_write(&ppp_pkt_init);
173     if (ppp_pkts.pr_size == 0) {
174 	extern const struct kmem_pa_mode kp_dma_contig;
175 
176 	pool_init(&ppp_pkts, sizeof(struct ppp_pkt), 0,
177 	  IPL_TTY, 0, "ppppkts", NULL); /* IPL_SOFTTTY */
178 	pool_set_constraints(&ppp_pkts, &kp_dma_contig);
179     }
180     rw_exit_write(&ppp_pkt_init);
181 
182     s = spltty();
183 
184     if (tp->t_line == PPPDISC) {
185 	sc = (struct ppp_softc *) tp->t_sc;
186 	if (sc != NULL && sc->sc_devp == (void *) tp) {
187 	    splx(s);
188 	    return (0);
189 	}
190     }
191 
192     if ((sc = pppalloc(p->p_p->ps_pid)) == NULL) {
193 	splx(s);
194 	return ENXIO;
195     }
196 
197     if (sc->sc_relinq)
198 	(*sc->sc_relinq)(sc);	/* get previous owner to relinquish the unit */
199 
200     timeout_set(&sc->sc_timo, ppp_timeout, sc);
201     sc->sc_ilen = 0;
202     sc->sc_pkt = NULL;
203     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
204     sc->sc_asyncmap[0] = 0xffffffff;
205     sc->sc_asyncmap[3] = 0x60000000;
206     sc->sc_rasyncmap = 0;
207     sc->sc_devp = (void *) tp;
208     sc->sc_start = pppasyncstart;
209     sc->sc_ctlp = pppasyncctlp;
210     sc->sc_relinq = pppasyncrelinq;
211     sc->sc_outm = NULL;
212     ppppkt(sc);
213     sc->sc_if.if_flags |= IFF_RUNNING;
214     sc->sc_if.if_baudrate = tp->t_ospeed;
215 
216     tp->t_sc = (caddr_t) sc;
217     ttyflush(tp, FREAD | FWRITE);
218 
219     splx(s);
220     return (0);
221 }
222 
223 /*
224  * Line specific close routine, called from device close routine
225  * and from ttioctl.
226  * Detach the tty from the ppp unit.
227  * Mimics part of ttyclose().
228  */
229 int
pppclose(struct tty * tp,int flag,struct proc * p)230 pppclose(struct tty *tp, int flag, struct proc *p)
231 {
232     struct ppp_softc *sc;
233     int s;
234 
235     s = spltty();
236     ttyflush(tp, FREAD|FWRITE);
237     tp->t_line = 0;
238     sc = (struct ppp_softc *) tp->t_sc;
239     if (sc != NULL) {
240 	tp->t_sc = NULL;
241 	if (tp == (struct tty *) sc->sc_devp) {
242 	    pppasyncrelinq(sc);
243 	    pppdealloc(sc);
244 	}
245     }
246     splx(s);
247     return 0;
248 }
249 
250 /*
251  * Relinquish the interface unit to another device.
252  */
253 void
pppasyncrelinq(struct ppp_softc * sc)254 pppasyncrelinq(struct ppp_softc *sc)
255 {
256     int s;
257 
258     KERNEL_LOCK();
259     s = spltty();
260     m_freem(sc->sc_outm);
261     sc->sc_outm = NULL;
262 
263     if (sc->sc_pkt != NULL) {
264 	ppp_pkt_free(sc->sc_pkt);
265 	sc->sc_pkt = sc->sc_pktc = NULL;
266     }
267     if (sc->sc_flags & SC_TIMEOUT) {
268 	timeout_del(&sc->sc_timo);
269 	sc->sc_flags &= ~SC_TIMEOUT;
270     }
271     splx(s);
272     KERNEL_UNLOCK();
273 }
274 
275 /*
276  * Line specific (tty) read routine.
277  */
278 int
pppread(struct tty * tp,struct uio * uio,int flag)279 pppread(struct tty *tp, struct uio *uio, int flag)
280 {
281     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
282     struct mbuf *m, *m0;
283     int s;
284     int error = 0;
285 
286     if (sc == NULL)
287 	return 0;
288     /*
289      * Loop waiting for input, checking that nothing disastrous
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 	/* Get the packet from the input queue */
299 	m0 = mq_dequeue(&sc->sc_inq);
300 	if (m0 != NULL)
301 	    break;
302 	if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
303 	    && (tp->t_state & TS_ISOPEN)) {
304 	    splx(s);
305 	    return 0;		/* end of file */
306 	}
307 	if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
308 	    splx(s);
309 	    return (EWOULDBLOCK);
310 	}
311 	error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin);
312 	if (error) {
313 	    splx(s);
314 	    return error;
315 	}
316     }
317 
318     /* Pull place-holder byte out of canonical queue */
319     getc(&tp->t_canq);
320     splx(s);
321 
322     for (m = m0; m && uio->uio_resid; m = m->m_next)
323 	if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
324 	    break;
325     m_freem(m0);
326     return (error);
327 }
328 
329 /*
330  * Line specific (tty) write routine.
331  */
332 int
pppwrite(struct tty * tp,struct uio * uio,int flag)333 pppwrite(struct tty *tp, struct uio *uio, int flag)
334 {
335     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
336     struct mbuf *m, *m0, **mp;
337     struct sockaddr dst;
338     u_int len;
339     int error;
340 
341     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
342 	return 0;		/* wrote 0 bytes */
343     if (tp->t_line != PPPDISC)
344 	return (EINVAL);
345     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
346 	return EIO;
347     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
348 	uio->uio_resid < PPP_HDRLEN)
349 	return (EMSGSIZE);
350     for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
351 	if (mp == &m0) {
352 	    MGETHDR(m, M_WAIT, MT_DATA);
353 	    m->m_pkthdr.len = uio->uio_resid - PPP_HDRLEN;
354 	    m->m_pkthdr.ph_ifidx = 0;
355 	} else
356 	    MGET(m, M_WAIT, MT_DATA);
357 	*mp = m;
358 	m->m_len = 0;
359 	if (uio->uio_resid >= MCLBYTES / 2)
360 	    MCLGET(m, M_DONTWAIT);
361 	len = m_trailingspace(m);
362 	if (len > uio->uio_resid)
363 	    len = uio->uio_resid;
364 	if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
365 	    m_freem(m0);
366 	    return (error);
367 	}
368 	m->m_len = len;
369     }
370     dst.sa_family = AF_UNSPEC;
371     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
372     m0->m_data += PPP_HDRLEN;
373     m0->m_len -= PPP_HDRLEN;
374     m0->m_pkthdr.ph_rtableid = sc->sc_if.if_rdomain;
375     return sc->sc_if.if_output(&sc->sc_if, m0, &dst, NULL);
376 }
377 
378 /*
379  * Line specific (tty) ioctl routine.
380  * This discipline requires that tty device drivers call
381  * the line specific l_ioctl routine from their ioctl routines.
382  */
383 int
ppptioctl(struct tty * tp,u_long cmd,caddr_t data,int flag,struct proc * p)384 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
385 {
386     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
387     int error, s;
388 
389     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
390 	return -1;
391 
392     error = 0;
393     switch (cmd) {
394     case PPPIOCSASYNCMAP:
395 	if ((error = suser(p)) != 0)
396 	    break;
397 	sc->sc_asyncmap[0] = *(u_int *)data;
398 	break;
399 
400     case PPPIOCGASYNCMAP:
401 	*(u_int *)data = sc->sc_asyncmap[0];
402 	break;
403 
404     case PPPIOCSRASYNCMAP:
405 	if ((error = suser(p)) != 0)
406 	    break;
407 	sc->sc_rasyncmap = *(u_int *)data;
408 	break;
409 
410     case PPPIOCGRASYNCMAP:
411 	*(u_int *)data = sc->sc_rasyncmap;
412 	break;
413 
414     case PPPIOCSXASYNCMAP:
415 	if ((error = suser(p)) != 0)
416 	    break;
417 	s = spltty();
418 	bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
419 	sc->sc_asyncmap[1] = 0;		    /* mustn't escape 0x20 - 0x3f */
420 	sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
421 	sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
422 	splx(s);
423 	break;
424 
425     case PPPIOCGXASYNCMAP:
426 	bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
427 	break;
428 
429     default:
430 	NET_LOCK();
431 	error = pppioctl(sc, cmd, data, flag, p);
432 	NET_UNLOCK();
433 	if (error == 0 && cmd == PPPIOCSMRU)
434 	    ppppkt(sc);
435     }
436 
437     return error;
438 }
439 
440 /*
441  * FCS lookup table as calculated by genfcstab.
442  */
443 static u_int16_t fcstab[256] = {
444 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
445 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
446 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
447 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
448 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
449 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
450 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
451 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
452 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
453 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
454 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
455 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
456 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
457 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
458 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
459 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
460 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
461 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
462 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
463 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
464 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
465 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
466 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
467 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
468 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
469 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
470 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
471 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
472 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
473 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
474 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
475 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
476 };
477 
478 /*
479  * Calculate a new FCS given the current FCS and the new data.
480  */
481 u_int16_t
pppfcs(u_int16_t fcs,u_char * cp,int len)482 pppfcs(u_int16_t fcs, u_char *cp, int len)
483 {
484     while (len--)
485 	fcs = PPP_FCS(fcs, *cp++);
486     return (fcs);
487 }
488 
489 /*
490  * This gets called from pppoutput when a new packet is
491  * put on a queue.
492  */
493 void
pppasyncstart(struct ppp_softc * sc)494 pppasyncstart(struct ppp_softc *sc)
495 {
496     struct tty *tp = (struct tty *) sc->sc_devp;
497     struct mbuf *m;
498     int len;
499     u_char *start, *stop, *cp;
500     int n, ndone, done, idle;
501     struct mbuf *m2;
502     int s;
503 
504     KERNEL_LOCK();
505     idle = 0;
506     while (CCOUNT(&tp->t_outq) < tp->t_hiwat) {
507 	/*
508 	 * See if we have an existing packet partly sent.
509 	 * If not, get a new packet and start sending it.
510 	 */
511 	m = sc->sc_outm;
512 	if (m == NULL) {
513 	    /*
514 	     * Get another packet to be sent.
515 	     */
516 	    m = ppp_dequeue(sc);
517 	    if (m == NULL) {
518 		idle = 1;
519 		break;
520 	    }
521 
522 	    /*
523 	     * The extra PPP_FLAG will start up a new packet, and thus
524 	     * will flush any accumulated garbage.  We do this whenever
525 	     * the line may have been idle for some time.
526 	     */
527 	    if (CCOUNT(&tp->t_outq) == 0) {
528 		++sc->sc_stats.ppp_obytes;
529 		(void) putc(PPP_FLAG, &tp->t_outq);
530 	    }
531 
532 	    /* Calculate the FCS for the first mbuf's worth. */
533 	    sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
534 	}
535 
536 	for (;;) {
537 	    start = mtod(m, u_char *);
538 	    len = m->m_len;
539 	    stop = start + len;
540 	    while (len > 0) {
541 		/*
542 		 * Find out how many bytes in the string we can
543 		 * handle without doing something special.
544 		 */
545 		for (cp = start; cp < stop; cp++)
546 		    if (ESCAPE_P(*cp))
547 			break;
548 		n = cp - start;
549 		if (n) {
550 		    /* NetBSD (0.9 or later), 4.3-Reno or similar. */
551 		    ndone = n - b_to_q(start, n, &tp->t_outq);
552 		    len -= ndone;
553 		    start += ndone;
554 		    sc->sc_stats.ppp_obytes += ndone;
555 
556 		    if (ndone < n)
557 			break;	/* packet doesn't fit */
558 		}
559 		/*
560 		 * If there are characters left in the mbuf,
561 		 * the first one must be special.
562 		 * Put it out in a different form.
563 		 */
564 		if (len) {
565 		    s = spltty();
566 		    if (putc(PPP_ESCAPE, &tp->t_outq)) {
567 			splx(s);
568 			break;
569 		    }
570 		    if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
571 			(void) unputc(&tp->t_outq);
572 			splx(s);
573 			break;
574 		    }
575 		    splx(s);
576 		    sc->sc_stats.ppp_obytes += 2;
577 		    start++;
578 		    len--;
579 		}
580 	    }
581 
582 	    /*
583 	     * If we didn't empty this mbuf, remember where we're up to.
584 	     * If we emptied the last mbuf, try to add the FCS and closing
585 	     * flag, and if we can't, leave sc_outm pointing to m, but with
586 	     * m->m_len == 0, to remind us to output the FCS and flag later.
587 	     */
588 	    done = len == 0;
589 	    if (done && m->m_next == NULL) {
590 		u_char *p, *q;
591 		int c;
592 		u_char endseq[8];
593 
594 		/*
595 		 * We may have to escape the bytes in the FCS.
596 		 */
597 		p = endseq;
598 		c = ~sc->sc_outfcs & 0xFF;
599 		if (ESCAPE_P(c)) {
600 		    *p++ = PPP_ESCAPE;
601 		    *p++ = c ^ PPP_TRANS;
602 		} else
603 		    *p++ = c;
604 		c = (~sc->sc_outfcs >> 8) & 0xFF;
605 		if (ESCAPE_P(c)) {
606 		    *p++ = PPP_ESCAPE;
607 		    *p++ = c ^ PPP_TRANS;
608 		} else
609 		    *p++ = c;
610 		*p++ = PPP_FLAG;
611 
612 		/*
613 		 * Try to output the FCS and flag.  If the bytes
614 		 * don't all fit, back out.
615 		 */
616 		s = spltty();
617 		for (q = endseq; q < p; ++q)
618 		    if (putc(*q, &tp->t_outq)) {
619 			done = 0;
620 			for (; q > endseq; --q)
621 			    unputc(&tp->t_outq);
622 			break;
623 		    }
624 		splx(s);
625 		if (done)
626 		    sc->sc_stats.ppp_obytes += q - endseq;
627 	    }
628 
629 	    if (!done) {
630 		/* remember where we got to */
631 		m->m_data = start;
632 		m->m_len = len;
633 		break;
634 	    }
635 
636 	    /* Finished with this mbuf; free it and move on. */
637 	    m2 = m_free(m);
638 	    m = m2;
639 	    if (m == NULL) {
640 		/* Finished a packet */
641 		break;
642 	    }
643 	    sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
644 	}
645 
646 	/*
647 	 * If m == NULL, we have finished a packet.
648 	 * If m != NULL, we've either done as much work this time
649 	 * as we need to, or else we've filled up the output queue.
650 	 */
651 	sc->sc_outm = m;
652 	if (m)
653 	    break;
654     }
655 
656     /* Call pppstart to start output again if necessary. */
657     s = spltty();
658     pppstart_internal(tp, 0);
659 
660     /*
661      * This timeout is needed for operation on a pseudo-tty,
662      * because the pty code doesn't call pppstart after it has
663      * drained the t_outq.
664      */
665     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
666 	timeout_add(&sc->sc_timo, 1);
667 	sc->sc_flags |= SC_TIMEOUT;
668     }
669 
670     splx(s);
671     KERNEL_UNLOCK();
672 }
673 
674 /*
675  * This gets called when a received packet is placed on
676  * the inq.
677  */
678 void
pppasyncctlp(struct ppp_softc * sc)679 pppasyncctlp(struct ppp_softc *sc)
680 {
681     struct tty *tp;
682     int s;
683 
684     KERNEL_LOCK();
685     /* Put a placeholder byte in canq for ttpoll()/ttnread(). */
686     s = spltty();
687     tp = (struct tty *) sc->sc_devp;
688     putc(0, &tp->t_canq);
689     ttwakeup(tp);
690     splx(s);
691     KERNEL_UNLOCK();
692 }
693 
694 /*
695  * Start output on async tty interface.  If the transmit queue
696  * has drained sufficiently, arrange for pppasyncstart to be
697  * called later.
698  */
699 int
pppstart_internal(struct tty * tp,int force)700 pppstart_internal(struct tty *tp, int force)
701 {
702     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
703 
704     /*
705      * If there is stuff in the output queue, send it now.
706      * We are being called in lieu of ttstart and must do what it would.
707      */
708     if (tp->t_oproc != NULL)
709 	(*tp->t_oproc)(tp);
710 
711     /*
712      * If the transmit queue has drained and the tty has not hung up
713      * or been disconnected from the ppp unit, then tell if_ppp.c that
714      * we need more output.
715      */
716     if ((CCOUNT(&tp->t_outq) < tp->t_lowat || force)
717 	&& !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
718 	&& sc != NULL && tp == (struct tty *) sc->sc_devp) {
719 	ppp_restart(sc);
720     }
721 
722     return 0;
723 }
724 
725 int
pppstart(struct tty * tp)726 pppstart(struct tty *tp)
727 {
728 	return pppstart_internal(tp, 0);
729 }
730 
731 /*
732  * Timeout routine - try to start some more output.
733  */
734 void
ppp_timeout(void * x)735 ppp_timeout(void *x)
736 {
737     struct ppp_softc *sc = (struct ppp_softc *) x;
738     struct tty *tp = (struct tty *) sc->sc_devp;
739     int s;
740 
741     s = spltty();
742     sc->sc_flags &= ~SC_TIMEOUT;
743     pppstart_internal(tp, 1);
744     splx(s);
745 }
746 
747 /*
748  * Allocate enough mbuf to handle current MRU.
749  */
750 void
ppppkt(struct ppp_softc * sc)751 ppppkt(struct ppp_softc *sc)
752 {
753     struct ppp_pkt **pktp, *pkt;
754     int len;
755     int s;
756 
757     s = spltty();
758     pktp = &sc->sc_pkt;
759     for (len = PKT_MAXLEN(sc); len > 0; len -= sizeof(pkt->p_buf)) {
760 	pkt = *pktp;
761 	if (pkt == NULL) {
762 	    pkt = pool_get(&ppp_pkts, PR_NOWAIT);
763 	    if (pkt == NULL)
764 		break;
765 	    PKT_NEXT(pkt) = NULL;
766 	    PKT_PREV(pkt) = *pktp;
767 	    PKT_LEN(pkt) = 0;
768 	    *pktp = pkt;
769 	}
770 	pktp = &PKT_NEXT(pkt);
771     }
772     splx(s);
773 }
774 
775 void
ppp_pkt_free(struct ppp_pkt * pkt)776 ppp_pkt_free(struct ppp_pkt *pkt)
777 {
778 	struct ppp_pkt *next;
779 
780 	while (pkt != NULL) {
781 		next = PKT_NEXT(pkt);
782 		pool_put(&ppp_pkts, pkt);
783 		pkt = next;
784 	}
785 }
786 
787 /*
788  * tty interface receiver interrupt.
789  */
790 static unsigned int paritytab[8] = {
791     0x96696996, 0x69969669, 0x69969669, 0x96696996,
792     0x69969669, 0x96696996, 0x96696996, 0x69969669
793 };
794 
795 int
pppinput(int c,struct tty * tp)796 pppinput(int c, struct tty *tp)
797 {
798     struct ppp_softc *sc;
799     struct ppp_pkt *pkt;
800     int ilen, s;
801 
802     sc = (struct ppp_softc *) tp->t_sc;
803     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
804 	return 0;
805 
806     ++tk_nin;
807     ++sc->sc_stats.ppp_ibytes;
808 
809     if (c & TTY_FE) {
810 	/* framing error or overrun on this char - abort packet */
811 	if (sc->sc_flags & SC_DEBUG)
812 	    printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
813 	goto flush;
814     }
815 
816     c &= 0xff;
817 
818     /*
819      * Handle software flow control of output.
820      */
821     if (tp->t_iflag & IXON) {
822 	if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
823 	    if ((tp->t_state & TS_TTSTOP) == 0) {
824 		tp->t_state |= TS_TTSTOP;
825 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
826 	    }
827 	    return 0;
828 	}
829 	if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
830 	    tp->t_state &= ~TS_TTSTOP;
831 	    if (tp->t_oproc != NULL)
832 		(*tp->t_oproc)(tp);
833 	    return 0;
834 	}
835     }
836 
837     s = spltty();
838     if (c & 0x80)
839 	sc->sc_flags |= SC_RCV_B7_1;
840     else
841 	sc->sc_flags |= SC_RCV_B7_0;
842     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
843 	sc->sc_flags |= SC_RCV_ODDP;
844     else
845 	sc->sc_flags |= SC_RCV_EVNP;
846     splx(s);
847 
848     if (sc->sc_flags & SC_LOG_RAWIN)
849 	ppplogchar(sc, c);
850 
851     if (c == PPP_FLAG) {
852 	ilen = sc->sc_ilen;
853 	sc->sc_ilen = 0;
854 
855 	if (sc->sc_rawin_count > 0)
856 	    ppplogchar(sc, -1);
857 
858 	/*
859 	 * If SC_ESCAPED is set, then we've seen the packet
860 	 * abort sequence "}~".
861 	 */
862 	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
863 	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
864 	    s = spltty();
865 	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
866 	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
867 		if (sc->sc_flags & SC_DEBUG)
868 		    printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
869 			sc->sc_fcs);
870 		sc->sc_if.if_ierrors++;
871 		sc->sc_stats.ppp_ierrors++;
872 	    } else
873 		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
874 	    splx(s);
875 	    return 0;
876 	}
877 
878 	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
879 	    if (ilen) {
880 		if (sc->sc_flags & SC_DEBUG)
881 		    printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
882 		s = spltty();
883 		sc->sc_if.if_ierrors++;
884 		sc->sc_stats.ppp_ierrors++;
885 		sc->sc_flags |= SC_PKTLOST;
886 		splx(s);
887 	    }
888 	    return 0;
889 	}
890 
891 	/*
892 	 * Remove FCS trailer.
893 	 */
894 	ilen -= 2;
895 	pkt = sc->sc_pktc;
896 	if (--PKT_LEN(pkt) == 0) {
897             pkt = PKT_PREV(pkt);
898 	    sc->sc_pktc = pkt;
899 	}
900 	PKT_LEN(pkt)--;
901 
902 	/* excise this mbuf chain */
903 	pkt = sc->sc_pkt;
904 	sc->sc_pkt = sc->sc_pktc = PKT_NEXT(sc->sc_pktc);
905 	PKT_NEXT(pkt) = NULL;
906 
907 	ppppktin(sc, pkt, sc->sc_flags & SC_PKTLOST);
908 	if (sc->sc_flags & SC_PKTLOST) {
909 	    s = spltty();
910 	    sc->sc_flags &= ~SC_PKTLOST;
911 	    splx(s);
912 	}
913 
914 	ppppkt(sc);
915 	return 0;
916     }
917 
918     if (sc->sc_flags & SC_FLUSH) {
919 	if (sc->sc_flags & SC_LOG_FLUSH)
920 	    ppplogchar(sc, c);
921 	return 0;
922     }
923 
924     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
925 	return 0;
926 
927     s = spltty();
928     if (sc->sc_flags & SC_ESCAPED) {
929 	sc->sc_flags &= ~SC_ESCAPED;
930 	c ^= PPP_TRANS;
931     } else if (c == PPP_ESCAPE) {
932 	sc->sc_flags |= SC_ESCAPED;
933 	splx(s);
934 	return 0;
935     }
936     splx(s);
937 
938     /*
939      * Initialize buffer on first octet received.
940      * First octet could be address or protocol (when compressing
941      * address/control).
942      * Second octet is control.
943      * Third octet is first or second (when compressing protocol)
944      * octet of protocol.
945      * Fourth octet is second octet of protocol.
946      */
947     if (sc->sc_ilen == 0) {
948 	/* reset the first input mbuf */
949 	if (sc->sc_pkt == NULL) {
950 	    ppppkt(sc);
951 	    if (sc->sc_pkt == NULL) {
952 		if (sc->sc_flags & SC_DEBUG)
953 		    printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
954 		goto flush;
955 	    }
956 	}
957 	pkt = sc->sc_pkt;
958 	PKT_LEN(pkt) = 0;
959 	sc->sc_pktc = pkt;
960 	sc->sc_pktp = pkt->p_buf;
961 	sc->sc_fcs = PPP_INITFCS;
962 	if (c != PPP_ALLSTATIONS) {
963 	    if (sc->sc_flags & SC_REJ_COMP_AC) {
964 		if (sc->sc_flags & SC_DEBUG)
965 		    printf("%s: garbage received: 0x%x (need 0xFF)\n",
966 			sc->sc_if.if_xname, c);
967 		goto flush;
968 	    }
969 	    *sc->sc_pktp++ = PPP_ALLSTATIONS;
970 	    *sc->sc_pktp++ = PPP_UI;
971 	    sc->sc_ilen += 2;
972 	    PKT_LEN(pkt) += 2;
973 	}
974     }
975     if (sc->sc_ilen == 1 && c != PPP_UI) {
976 	if (sc->sc_flags & SC_DEBUG)
977 	    printf("%s: missing UI (0x3), got 0x%x\n",
978 		sc->sc_if.if_xname, c);
979 	goto flush;
980     }
981     if (sc->sc_ilen == 2 && (c & 1) == 1) {
982 	/* a compressed protocol */
983 	*sc->sc_pktp++ = 0;
984 	sc->sc_ilen++;
985 	PKT_LEN(sc->sc_pktc)++;
986     }
987     if (sc->sc_ilen == 3 && (c & 1) == 0) {
988 	if (sc->sc_flags & SC_DEBUG)
989 	    printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
990 		(sc->sc_pktp[-1] << 8) + c);
991 	goto flush;
992     }
993 
994     /* packet beyond configured mru? */
995     if (++sc->sc_ilen > PKT_MAXLEN(sc)) {
996 	if (sc->sc_flags & SC_DEBUG)
997 	    printf("%s: packet too big\n", sc->sc_if.if_xname);
998 	goto flush;
999     }
1000 
1001     /* is this packet full? */
1002     pkt = sc->sc_pktc;
1003     if (PKT_LEN(pkt) >= sizeof(pkt->p_buf)) {
1004 	if (PKT_NEXT(pkt) == NULL) {
1005 	    ppppkt(sc);
1006 	    if (PKT_NEXT(pkt) == NULL) {
1007 		if (sc->sc_flags & SC_DEBUG)
1008 		    printf("%s: too few input packets!\n", sc->sc_if.if_xname);
1009 		goto flush;
1010 	    }
1011 	}
1012 	sc->sc_pktc = pkt = PKT_NEXT(pkt);
1013 	PKT_LEN(pkt) = 0;
1014 	sc->sc_pktp = pkt->p_buf;
1015     }
1016 
1017     ++PKT_LEN(pkt);
1018     *sc->sc_pktp++ = c;
1019     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1020     return 0;
1021 
1022  flush:
1023     if (!(sc->sc_flags & SC_FLUSH)) {
1024 	s = spltty();
1025 	sc->sc_if.if_ierrors++;
1026 	sc->sc_stats.ppp_ierrors++;
1027 	sc->sc_flags |= SC_FLUSH;
1028 	splx(s);
1029 	if (sc->sc_flags & SC_LOG_FLUSH)
1030 	    ppplogchar(sc, c);
1031     }
1032     return 0;
1033 }
1034 
1035 #define MAX_DUMP_BYTES	128
1036 
1037 void
ppplogchar(struct ppp_softc * sc,int c)1038 ppplogchar(struct ppp_softc *sc, int c)
1039 {
1040     if (c >= 0)
1041 	sc->sc_rawin[sc->sc_rawin_count++] = c;
1042     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1043 	|| (c < 0 && sc->sc_rawin_count > 0)) {
1044 	printf("%s input: ", sc->sc_if.if_xname);
1045 	pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1046 	sc->sc_rawin_count = 0;
1047     }
1048 }
1049 
1050 void
pppdumpb(u_char * b,int l)1051 pppdumpb(u_char *b, int l)
1052 {
1053     char buf[3*MAX_DUMP_BYTES+4];
1054     char *bp = buf;
1055     static char digits[] = "0123456789abcdef";
1056 
1057     while (l--) {
1058 	if (bp >= buf + sizeof(buf) - 3) {
1059 	    *bp++ = '>';
1060 	    break;
1061 	}
1062 	*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1063 	*bp++ = digits[*b++ & 0xf];
1064 	*bp++ = ' ';
1065     }
1066 
1067     *bp = 0;
1068     printf("%s\n", buf);
1069 }
1070 
1071 #endif	/* NPPP > 0 */
1072