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