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