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