No empty .Rs/.Re
[netbsd-mini2440.git] / sys / net / ppp_tty.c
blob17d7311bd5c258edaeeb893343b7603a900bf79a
1 /* $NetBSD: ppp_tty.c,v 1.54 2009/04/15 20:44:25 elad Exp $ */
2 /* Id: ppp_tty.c,v 1.3 1996/07/01 01:04:11 paulus Exp */
4 /*
5 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
6 * tty devices.
8 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
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.
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
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/)."
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.
46 * Based on:
47 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
49 * Copyright (c) 1987 Regents of the University of California.
50 * All rights reserved.
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.
64 * Serial Line interface
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
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.
78 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
79 * Added VJ tcp header compression; more unified ioctls
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.
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).
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 */
95 #include <sys/cdefs.h>
96 __KERNEL_RCSID(0, "$NetBSD: ppp_tty.c,v 1.54 2009/04/15 20:44:25 elad Exp $");
98 #include "ppp.h"
100 #include "opt_ppp.h"
101 #define VJC
102 #define PPP_COMPRESS
104 #include <sys/param.h>
105 #include <sys/proc.h>
106 #include <sys/mbuf.h>
107 #include <sys/dkstat.h>
108 #include <sys/socket.h>
109 #include <sys/ioctl.h>
110 #include <sys/file.h>
111 #include <sys/tty.h>
112 #include <sys/kernel.h>
113 #include <sys/conf.h>
114 #include <sys/vnode.h>
115 #include <sys/systm.h>
116 #include <sys/kauth.h>
118 #include <net/if.h>
119 #include <net/if_types.h>
121 #ifdef VJC
122 #include <netinet/in.h>
123 #include <netinet/in_systm.h>
124 #include <netinet/ip.h>
125 #include <net/slcompress.h>
126 #endif
128 #include "bpfilter.h"
129 #if NBPFILTER > 0 || defined(PPP_FILTER)
130 #include <net/bpf.h>
131 #endif
132 #include <net/ppp_defs.h>
133 #include <net/if_ppp.h>
134 #include <net/if_pppvar.h>
136 static int pppopen(dev_t dev, struct tty *tp);
137 static int pppclose(struct tty *tp, int flag);
138 static int pppread(struct tty *tp, struct uio *uio, int flag);
139 static int pppwrite(struct tty *tp, struct uio *uio, int flag);
140 static int ppptioctl(struct tty *tp, u_long cmd, void *data, int flag,
141 struct lwp *);
142 static int pppinput(int c, struct tty *tp);
143 static int pppstart(struct tty *tp);
145 struct linesw ppp_disc = { /* XXX should be static */
146 .l_name = "ppp",
147 .l_open = pppopen,
148 .l_close = pppclose,
149 .l_read = pppread,
150 .l_write = pppwrite,
151 .l_ioctl = ppptioctl,
152 .l_rint = pppinput,
153 .l_start = pppstart,
154 .l_modem = ttymodem,
155 .l_poll = ttpoll
158 static void ppprcvframe(struct ppp_softc *sc, struct mbuf *m);
159 static uint16_t pppfcs(uint16_t fcs, const uint8_t *cp, int len);
160 static void pppsyncstart(struct ppp_softc *sc);
161 static void pppasyncstart(struct ppp_softc *);
162 static void pppasyncctlp(struct ppp_softc *);
163 static void pppasyncrelinq(struct ppp_softc *);
164 static void ppp_timeout(void *);
165 static void pppgetm(struct ppp_softc *sc);
166 static void pppdumpb(u_char *b, int l);
167 static void ppplogchar(struct ppp_softc *, int);
168 static void pppdumpframe(struct ppp_softc *sc, struct mbuf* m, int xmit);
171 * Some useful mbuf macros not in mbuf.h.
173 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
175 #define M_DATASTART(m) \
176 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
177 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
179 #define M_DATASIZE(m) \
180 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
181 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
184 * Does c need to be escaped?
186 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
189 * Procedures for using an async tty interface for PPP.
192 /* This is a NetBSD-1.0 or later kernel. */
193 #define CCOUNT(q) ((q)->c_cc)
195 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
196 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
199 * Line specific open routine for async tty devices.
200 * Attach the given tty to the first available ppp unit.
201 * Called from device open routine or ttioctl.
203 /* ARGSUSED */
204 static int
205 pppopen(dev_t dev, struct tty *tp)
207 struct lwp *l = curlwp; /* XXX */
208 struct ppp_softc *sc;
209 int error, s;
211 error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_PPP,
212 KAUTH_REQ_NETWORK_INTERFACE_PPP_ADD, NULL, NULL, NULL);
213 if (error)
214 return (error);
216 s = spltty();
218 if (tp->t_linesw == &ppp_disc) {
219 sc = (struct ppp_softc *) tp->t_sc;
220 if (sc != NULL && sc->sc_devp == (void *) tp) {
221 splx(s);
222 return (0);
226 if ((sc = pppalloc(l->l_proc->p_pid)) == NULL) {
227 splx(s);
228 return ENXIO;
231 if (sc->sc_relinq)
232 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
234 #if NBPFILTER > 0
235 /* Switch DLT to PPP-over-serial. */
236 bpf_change_type(&sc->sc_if, DLT_PPP_SERIAL, PPP_HDRLEN);
237 #endif
239 sc->sc_ilen = 0;
240 sc->sc_m = NULL;
241 memset(sc->sc_asyncmap, 0, sizeof(sc->sc_asyncmap));
242 sc->sc_asyncmap[0] = 0xffffffff;
243 sc->sc_asyncmap[3] = 0x60000000;
244 sc->sc_rasyncmap = 0;
245 sc->sc_devp = (void *) tp;
246 sc->sc_start = pppasyncstart;
247 sc->sc_ctlp = pppasyncctlp;
248 sc->sc_relinq = pppasyncrelinq;
249 sc->sc_outm = NULL;
250 pppgetm(sc);
251 sc->sc_if.if_flags |= IFF_RUNNING;
252 sc->sc_if.if_baudrate = tp->t_ospeed;
254 tp->t_sc = (void *) sc;
255 mutex_spin_enter(&tty_lock);
256 ttyflush(tp, FREAD | FWRITE);
257 mutex_spin_exit(&tty_lock);
259 splx(s);
260 return (0);
264 * Line specific close routine, called from device close routine
265 * and from ttioctl.
266 * Detach the tty from the ppp unit.
267 * Mimics part of ttyclose().
269 static int
270 pppclose(struct tty *tp, int flag)
272 struct ppp_softc *sc;
273 int s;
275 s = spltty();
276 mutex_spin_enter(&tty_lock);
277 ttyflush(tp, FREAD|FWRITE);
278 mutex_spin_exit(&tty_lock); /* XXX */
279 ttyldisc_release(tp->t_linesw);
280 tp->t_linesw = ttyldisc_default();
281 sc = (struct ppp_softc *) tp->t_sc;
282 if (sc != NULL) {
283 tp->t_sc = NULL;
284 if (tp == (struct tty *) sc->sc_devp) {
285 pppasyncrelinq(sc);
286 pppdealloc(sc);
289 splx(s);
290 return 0;
294 * Relinquish the interface unit to another device.
296 static void
297 pppasyncrelinq(struct ppp_softc *sc)
299 int s;
301 #if NBPFILTER > 0
302 /* Change DLT to back none. */
303 bpf_change_type(&sc->sc_if, DLT_NULL, 0);
304 #endif
306 s = spltty();
307 if (sc->sc_outm) {
308 m_freem(sc->sc_outm);
309 sc->sc_outm = NULL;
311 if (sc->sc_m) {
312 m_freem(sc->sc_m);
313 sc->sc_m = NULL;
315 if (sc->sc_flags & SC_TIMEOUT) {
316 callout_stop(&sc->sc_timo_ch);
317 sc->sc_flags &= ~SC_TIMEOUT;
319 splx(s);
323 * Line specific (tty) read routine.
325 static int
326 pppread(struct tty *tp, struct uio *uio, int flag)
328 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
329 struct mbuf *m, *m0;
330 int error = 0;
332 if (sc == NULL)
333 return 0;
335 * Loop waiting for input, checking that nothing disasterous
336 * happens in the meantime.
338 mutex_spin_enter(&tty_lock);
339 for (;;) {
340 if (tp != (struct tty *) sc->sc_devp ||
341 tp->t_linesw != &ppp_disc) {
342 mutex_spin_exit(&tty_lock);
343 return 0;
345 if (sc->sc_inq.ifq_head != NULL)
346 break;
347 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
348 && (tp->t_state & TS_ISOPEN)) {
349 mutex_spin_exit(&tty_lock);
350 return 0; /* end of file */
352 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
353 mutex_spin_exit(&tty_lock);
354 return (EWOULDBLOCK);
356 error = ttysleep(tp, &tp->t_rawcv, true, 0);
357 if (error) {
358 mutex_spin_exit(&tty_lock);
359 return error;
363 /* Pull place-holder byte out of canonical queue */
364 getc(&tp->t_canq);
366 /* Get the packet from the input queue */
367 IF_DEQUEUE(&sc->sc_inq, m0);
368 mutex_spin_exit(&tty_lock);
370 for (m = m0; m && uio->uio_resid; m = m->m_next)
371 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
372 break;
373 m_freem(m0);
374 return (error);
378 * Line specific (tty) write routine.
380 static int
381 pppwrite(struct tty *tp, struct uio *uio, int flag)
383 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
384 struct mbuf *m, *m0;
385 struct sockaddr dst;
386 int len, error;
388 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
389 return 0; /* wrote 0 bytes */
390 if (tp->t_linesw != &ppp_disc)
391 return (EINVAL);
392 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
393 return EIO;
394 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
395 uio->uio_resid < PPP_HDRLEN)
396 return (EMSGSIZE);
398 MGETHDR(m0, M_WAIT, MT_DATA);
399 if (m0 == NULL)
400 return ENOBUFS;
402 m0->m_len = 0;
403 m0->m_pkthdr.len = uio->uio_resid;
404 m0->m_pkthdr.rcvif = NULL;
406 if (uio->uio_resid >= MCLBYTES / 2)
407 MCLGET(m0, M_DONTWAIT);
409 for (m = m0; uio->uio_resid;) {
410 len = M_TRAILINGSPACE(m);
411 if (len > uio->uio_resid)
412 len = uio->uio_resid;
413 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
414 m_freem(m0);
415 return (error);
417 m->m_len = len;
419 if (uio->uio_resid == 0)
420 break;
422 MGET(m->m_next, M_WAIT, MT_DATA);
423 if (m->m_next == NULL) {
424 m_freem(m0);
425 return ENOBUFS;
427 m = m->m_next;
428 m->m_len = 0;
430 dst.sa_family = AF_UNSPEC;
431 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
432 m_adj(m0, PPP_HDRLEN);
433 return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
437 * Line specific (tty) ioctl routine.
438 * This discipline requires that tty device drivers call
439 * the line specific l_ioctl routine from their ioctl routines.
441 /* ARGSUSED */
442 static int
443 ppptioctl(struct tty *tp, u_long cmd, void *data, int flag, struct lwp *l)
445 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
446 int error, s;
448 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
449 return (EPASSTHROUGH);
451 error = 0;
452 switch (cmd) {
453 case TIOCRCVFRAME:
454 ppprcvframe(sc,*((struct mbuf **)data));
455 break;
457 case PPPIOCSASYNCMAP:
458 if ((error = kauth_authorize_device_tty(l->l_cred,
459 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
460 break;
461 sc->sc_asyncmap[0] = *(u_int *)data;
462 break;
464 case PPPIOCGASYNCMAP:
465 *(u_int *)data = sc->sc_asyncmap[0];
466 break;
468 case PPPIOCSRASYNCMAP:
469 if ((error = kauth_authorize_device_tty(l->l_cred,
470 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
471 break;
472 sc->sc_rasyncmap = *(u_int *)data;
473 break;
475 case PPPIOCGRASYNCMAP:
476 *(u_int *)data = sc->sc_rasyncmap;
477 break;
479 case PPPIOCSXASYNCMAP:
480 if ((error = kauth_authorize_device_tty(l->l_cred,
481 KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
482 break;
483 s = spltty();
484 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
485 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
486 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
487 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
488 splx(s);
489 break;
491 case PPPIOCGXASYNCMAP:
492 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
493 break;
495 default:
496 error = pppioctl(sc, cmd, data, flag, l);
497 if (error == 0 && cmd == PPPIOCSMRU)
498 pppgetm(sc);
501 return error;
504 /* receive a complete ppp frame from device in synchronous
505 * hdlc mode. caller gives up ownership of mbuf
507 static void
508 ppprcvframe(struct ppp_softc *sc, struct mbuf *m)
510 int len, s;
511 struct mbuf *n;
512 u_char hdr[4];
513 int hlen,count;
515 for (n=m,len=0;n != NULL;n = n->m_next)
516 len += n->m_len;
517 if (len==0) {
518 m_freem(m);
519 return;
522 /* extract PPP header from mbuf chain (1 to 4 bytes) */
523 for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) {
524 count = (sizeof(hdr)-hlen) < n->m_len ?
525 sizeof(hdr)-hlen : n->m_len;
526 bcopy(mtod(n,u_char*),&hdr[hlen],count);
527 hlen+=count;
530 s = spltty();
532 /* if AFCF compressed then prepend AFCF */
533 if (hdr[0] != PPP_ALLSTATIONS) {
534 if (sc->sc_flags & SC_REJ_COMP_AC) {
535 if (sc->sc_flags & SC_DEBUG)
536 printf(
537 "%s: garbage received: 0x%x (need 0xFF)\n",
538 sc->sc_if.if_xname, hdr[0]);
539 goto bail;
541 M_PREPEND(m,2,M_DONTWAIT);
542 if (m==NULL) {
543 splx(s);
544 return;
546 hdr[3] = hdr[1];
547 hdr[2] = hdr[0];
548 hdr[0] = PPP_ALLSTATIONS;
549 hdr[1] = PPP_UI;
550 len += 2;
553 /* if protocol field compressed, add MSB of protocol field = 0 */
554 if (hdr[2] & 1) {
555 /* a compressed protocol */
556 M_PREPEND(m,1,M_DONTWAIT);
557 if (m==NULL) {
558 splx(s);
559 return;
561 hdr[3] = hdr[2];
562 hdr[2] = 0;
563 len++;
566 /* valid LSB of protocol field has bit0 set */
567 if (!(hdr[3] & 1)) {
568 if (sc->sc_flags & SC_DEBUG)
569 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
570 (hdr[2] << 8) + hdr[3]);
571 goto bail;
574 /* packet beyond configured mru? */
575 if (len > sc->sc_mru + PPP_HDRLEN) {
576 if (sc->sc_flags & SC_DEBUG)
577 printf("%s: packet too big\n", sc->sc_if.if_xname);
578 goto bail;
581 /* add expanded 4 byte header to mbuf chain */
582 for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) {
583 count = (sizeof(hdr)-hlen) < n->m_len ?
584 sizeof(hdr)-hlen : n->m_len;
585 bcopy(&hdr[hlen],mtod(n,u_char*),count);
586 hlen+=count;
589 /* if_ppp.c requires the PPP header and IP header */
590 /* to be contiguous */
591 count = len < MHLEN ? len : MHLEN;
592 if (m->m_len < count) {
593 m = m_pullup(m,count);
594 if (m==NULL)
595 goto bail;
598 sc->sc_stats.ppp_ibytes += len;
600 if (sc->sc_flags & SC_LOG_RAWIN)
601 pppdumpframe(sc,m,0);
603 ppppktin(sc, m, 0);
604 splx(s);
605 return;
606 bail:
607 m_freem(m);
608 splx(s);
612 * FCS lookup table as calculated by genfcstab.
614 static const uint16_t fcstab[256] = {
615 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
616 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
617 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
618 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
619 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
620 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
621 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
622 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
623 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
624 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
625 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
626 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
627 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
628 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
629 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
630 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
631 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
632 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
633 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
634 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
635 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
636 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
637 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
638 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
639 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
640 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
641 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
642 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
643 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
644 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
645 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
646 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
650 * Calculate a new FCS given the current FCS and the new data.
652 static uint16_t
653 pppfcs(uint16_t fcs, const uint8_t *cp, int len)
655 while (len--)
656 fcs = PPP_FCS(fcs, *cp++);
657 return (fcs);
660 /* This gets called at splsoftnet from pppasyncstart at various times
661 * when there is data ready to be sent.
663 static void
664 pppsyncstart(struct ppp_softc *sc)
666 struct tty *tp = (struct tty *) sc->sc_devp;
667 struct mbuf *m, *n;
668 const struct cdevsw *cdev;
669 int len;
671 for(m = sc->sc_outm;;) {
672 if (m == NULL) {
673 m = ppp_dequeue(sc); /* get new packet */
674 if (m == NULL)
675 break; /* no more packets */
676 if (sc->sc_flags & SC_DEBUG)
677 pppdumpframe(sc,m,1);
679 for(n=m,len=0;n!=NULL;n=n->m_next)
680 len += n->m_len;
682 /* call device driver IOCTL to transmit a frame */
683 cdev = cdevsw_lookup(tp->t_dev);
684 if (cdev == NULL ||
685 (*cdev->d_ioctl)(tp->t_dev, TIOCXMTFRAME, (void *)&m,
686 0, 0)) {
687 /* busy or error, set as current packet */
688 sc->sc_outm = m;
689 break;
691 sc->sc_outm = m = NULL;
692 sc->sc_stats.ppp_obytes += len;
697 * This gets called at splsoftnet from if_ppp.c at various times
698 * when there is data ready to be sent.
700 static void
701 pppasyncstart(struct ppp_softc *sc)
703 struct tty *tp = (struct tty *) sc->sc_devp;
704 struct mbuf *m;
705 int len;
706 u_char *start, *stop, *cp;
707 int n, ndone, done, idle;
708 struct mbuf *m2;
710 if (sc->sc_flags & SC_SYNC){
711 pppsyncstart(sc);
712 return;
715 mutex_spin_enter(&tty_lock);
717 idle = 0;
718 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
720 * See if we have an existing packet partly sent.
721 * If not, get a new packet and start sending it.
723 m = sc->sc_outm;
724 if (m == NULL) {
726 * Get another packet to be sent.
728 m = ppp_dequeue(sc);
729 if (m == NULL) {
730 idle = 1;
731 break;
735 * The extra PPP_FLAG will start up a new packet, and thus
736 * will flush any accumulated garbage. We do this whenever
737 * the line may have been idle for some time.
739 if (CCOUNT(&tp->t_outq) == 0) {
740 ++sc->sc_stats.ppp_obytes;
741 (void) putc(PPP_FLAG, &tp->t_outq);
744 /* Calculate the FCS for the first mbuf's worth. */
745 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, uint8_t *), m->m_len);
748 for (;;) {
749 start = mtod(m, u_char *);
750 len = m->m_len;
751 stop = start + len;
752 while (len > 0) {
754 * Find out how many bytes in the string we can
755 * handle without doing something special.
757 for (cp = start; cp < stop; cp++)
758 if (ESCAPE_P(*cp))
759 break;
760 n = cp - start;
761 if (n) {
762 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
763 ndone = n - b_to_q(start, n, &tp->t_outq);
764 len -= ndone;
765 start += ndone;
766 sc->sc_stats.ppp_obytes += ndone;
768 if (ndone < n)
769 break; /* packet doesn't fit */
772 * If there are characters left in the mbuf,
773 * the first one must be special.
774 * Put it out in a different form.
776 if (len) {
777 if (putc(PPP_ESCAPE, &tp->t_outq))
778 break;
779 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
780 (void) unputc(&tp->t_outq);
781 break;
783 sc->sc_stats.ppp_obytes += 2;
784 start++;
785 len--;
790 * If we didn't empty this mbuf, remember where we're up to.
791 * If we emptied the last mbuf, try to add the FCS and closing
792 * flag, and if we can't, leave sc_outm pointing to m, but with
793 * m->m_len == 0, to remind us to output the FCS and flag later.
795 done = len == 0;
796 if (done && m->m_next == NULL) {
797 u_char *p, *q;
798 int c;
799 u_char endseq[8];
802 * We may have to escape the bytes in the FCS.
804 p = endseq;
805 c = ~sc->sc_outfcs & 0xFF;
806 if (ESCAPE_P(c)) {
807 *p++ = PPP_ESCAPE;
808 *p++ = c ^ PPP_TRANS;
809 } else
810 *p++ = c;
811 c = (~sc->sc_outfcs >> 8) & 0xFF;
812 if (ESCAPE_P(c)) {
813 *p++ = PPP_ESCAPE;
814 *p++ = c ^ PPP_TRANS;
815 } else
816 *p++ = c;
817 *p++ = PPP_FLAG;
820 * Try to output the FCS and flag. If the bytes
821 * don't all fit, back out.
823 for (q = endseq; q < p; ++q)
824 if (putc(*q, &tp->t_outq)) {
825 done = 0;
826 for (; q > endseq; --q)
827 unputc(&tp->t_outq);
828 break;
830 if (done)
831 sc->sc_stats.ppp_obytes += q - endseq;
834 if (!done) {
835 /* remember where we got to */
836 m->m_data = start;
837 m->m_len = len;
838 break;
841 /* Finished with this mbuf; free it and move on. */
842 MFREE(m, m2);
843 m = m2;
844 if (m == NULL) {
845 /* Finished a packet */
846 break;
848 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, uint8_t *), m->m_len);
852 * If m == NULL, we have finished a packet.
853 * If m != NULL, we've either done as much work this time
854 * as we need to, or else we've filled up the output queue.
856 sc->sc_outm = m;
857 if (m)
858 break;
861 /* Call pppstart to start output again if necessary. */
862 pppstart(tp);
865 * This timeout is needed for operation on a pseudo-tty,
866 * because the pty code doesn't call pppstart after it has
867 * drained the t_outq.
869 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
870 callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
871 sc->sc_flags |= SC_TIMEOUT;
874 mutex_spin_exit(&tty_lock);
878 * This gets called when a received packet is placed on
879 * the inq, at splsoftnet.
881 static void
882 pppasyncctlp(struct ppp_softc *sc)
884 struct tty *tp;
886 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
887 mutex_spin_enter(&tty_lock);
888 tp = (struct tty *) sc->sc_devp;
889 putc(0, &tp->t_canq);
890 ttwakeup(tp);
891 mutex_spin_exit(&tty_lock);
895 * Start output on async tty interface. If the transmit queue
896 * has drained sufficiently, arrange for pppasyncstart to be
897 * called later at splsoftnet.
898 * Called at spltty or higher.
900 static int
901 pppstart(struct tty *tp)
903 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
906 * If there is stuff in the output queue, send it now.
907 * We are being called in lieu of ttstart and must do what it would.
909 if (tp->t_oproc != NULL)
910 (*tp->t_oproc)(tp);
913 * If the transmit queue has drained and the tty has not hung up
914 * or been disconnected from the ppp unit, then tell if_ppp.c that
915 * we need more output.
917 if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
918 && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
919 return 0;
920 #ifdef ALTQ
922 * if ALTQ is enabled, don't invoke NETISR_PPP.
923 * pppintr() could loop without doing anything useful
924 * under rate-limiting.
926 if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd))
927 return 0;
928 #endif
929 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
930 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
931 ppp_restart(sc);
934 return 0;
938 * Timeout routine - try to start some more output.
940 static void
941 ppp_timeout(void *x)
943 struct ppp_softc *sc = (struct ppp_softc *) x;
944 struct tty *tp = (struct tty *) sc->sc_devp;
946 mutex_spin_enter(&tty_lock);
947 sc->sc_flags &= ~SC_TIMEOUT;
948 pppstart(tp);
949 mutex_spin_exit(&tty_lock);
953 * Allocate enough mbuf to handle current MRU.
955 static void
956 pppgetm(struct ppp_softc *sc)
958 struct mbuf *m, **mp;
959 int len;
961 mp = &sc->sc_m;
962 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
963 if ((m = *mp) == NULL) {
964 MGETHDR(m, M_DONTWAIT, MT_DATA);
965 if (m == NULL)
966 break;
967 *mp = m;
968 MCLGET(m, M_DONTWAIT);
970 len -= M_DATASIZE(m);
971 mp = &m->m_next;
976 * tty interface receiver interrupt.
978 static const unsigned paritytab[8] = {
979 0x96696996, 0x69969669, 0x69969669, 0x96696996,
980 0x69969669, 0x96696996, 0x96696996, 0x69969669
983 static int
984 pppinput(int c, struct tty *tp)
986 struct ppp_softc *sc;
987 struct mbuf *m;
988 const struct cdevsw *cdev;
989 int ilen, s;
991 sc = (struct ppp_softc *) tp->t_sc;
992 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
993 return 0;
995 ++tk_nin;
996 ++sc->sc_stats.ppp_ibytes;
998 if (c & TTY_FE) {
999 /* framing error or overrun on this char - abort packet */
1000 if (sc->sc_flags & SC_DEBUG)
1001 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
1002 goto flush;
1005 c &= 0xff;
1008 * Handle software flow control of output.
1010 if (tp->t_iflag & IXON) {
1011 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
1012 if ((tp->t_state & TS_TTSTOP) == 0) {
1013 tp->t_state |= TS_TTSTOP;
1014 cdev = cdevsw_lookup(tp->t_dev);
1015 if (cdev != NULL)
1016 (*cdev->d_stop)(tp, 0);
1018 return 0;
1020 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
1021 tp->t_state &= ~TS_TTSTOP;
1022 if (tp->t_oproc != NULL) {
1023 mutex_spin_enter(&tty_lock); /* XXX */
1024 (*tp->t_oproc)(tp);
1025 mutex_spin_exit(&tty_lock); /* XXX */
1027 return 0;
1031 s = spltty();
1032 if (c & 0x80)
1033 sc->sc_flags |= SC_RCV_B7_1;
1034 else
1035 sc->sc_flags |= SC_RCV_B7_0;
1036 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
1037 sc->sc_flags |= SC_RCV_ODDP;
1038 else
1039 sc->sc_flags |= SC_RCV_EVNP;
1040 splx(s);
1042 ppplogchar(sc, c);
1044 if (c == PPP_FLAG) {
1045 ilen = sc->sc_ilen;
1046 sc->sc_ilen = 0;
1048 if ((sc->sc_flags & SC_LOG_RAWIN) && sc->sc_rawin.count > 0)
1049 ppplogchar(sc, -1);
1052 * If SC_ESCAPED is set, then we've seen the packet
1053 * abort sequence "}~".
1055 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1056 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
1057 s = spltty();
1058 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1059 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1060 if (sc->sc_flags & SC_DEBUG)
1061 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
1062 sc->sc_fcs);
1063 sc->sc_if.if_ierrors++;
1064 sc->sc_stats.ppp_ierrors++;
1065 } else
1066 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1067 splx(s);
1068 return 0;
1071 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1072 if (ilen) {
1073 if (sc->sc_flags & SC_DEBUG)
1074 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
1075 s = spltty();
1076 sc->sc_if.if_ierrors++;
1077 sc->sc_stats.ppp_ierrors++;
1078 sc->sc_flags |= SC_PKTLOST;
1079 splx(s);
1081 return 0;
1085 * Remove FCS trailer. Somewhat painful...
1087 ilen -= 2;
1088 if (--sc->sc_mc->m_len == 0) {
1089 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1091 sc->sc_mc = m;
1093 sc->sc_mc->m_len--;
1095 /* excise this mbuf chain */
1096 m = sc->sc_m;
1097 sc->sc_m = sc->sc_mc->m_next;
1098 sc->sc_mc->m_next = NULL;
1100 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1101 if (sc->sc_flags & SC_PKTLOST) {
1102 s = spltty();
1103 sc->sc_flags &= ~SC_PKTLOST;
1104 splx(s);
1107 pppgetm(sc);
1108 return 0;
1111 if (sc->sc_flags & SC_FLUSH) {
1112 if (sc->sc_flags & SC_LOG_FLUSH)
1113 ppplogchar(sc, c);
1114 return 0;
1117 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1118 return 0;
1120 s = spltty();
1121 if (sc->sc_flags & SC_ESCAPED) {
1122 sc->sc_flags &= ~SC_ESCAPED;
1123 c ^= PPP_TRANS;
1124 } else if (c == PPP_ESCAPE) {
1125 sc->sc_flags |= SC_ESCAPED;
1126 splx(s);
1127 return 0;
1129 splx(s);
1132 * Initialize buffer on first octet received.
1133 * First octet could be address or protocol (when compressing
1134 * address/control).
1135 * Second octet is control.
1136 * Third octet is first or second (when compressing protocol)
1137 * octet of protocol.
1138 * Fourth octet is second octet of protocol.
1140 if (sc->sc_ilen == 0) {
1141 /* reset the first input mbuf */
1142 if (sc->sc_m == NULL) {
1143 pppgetm(sc);
1144 if (sc->sc_m == NULL) {
1145 if (sc->sc_flags & SC_DEBUG)
1146 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
1147 goto flush;
1150 m = sc->sc_m;
1151 m->m_len = 0;
1152 m->m_data = M_DATASTART(sc->sc_m);
1153 sc->sc_mc = m;
1154 sc->sc_mp = mtod(m, char *);
1155 sc->sc_fcs = PPP_INITFCS;
1156 if (c != PPP_ALLSTATIONS) {
1157 if (sc->sc_flags & SC_REJ_COMP_AC) {
1158 if (sc->sc_flags & SC_DEBUG)
1159 printf("%s: garbage received: 0x%x (need 0xFF)\n",
1160 sc->sc_if.if_xname, c);
1161 goto flush;
1163 *sc->sc_mp++ = PPP_ALLSTATIONS;
1164 *sc->sc_mp++ = PPP_UI;
1165 sc->sc_ilen += 2;
1166 m->m_len += 2;
1169 if (sc->sc_ilen == 1 && c != PPP_UI) {
1170 if (sc->sc_flags & SC_DEBUG)
1171 printf("%s: missing UI (0x3), got 0x%x\n",
1172 sc->sc_if.if_xname, c);
1173 goto flush;
1175 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1176 /* a compressed protocol */
1177 *sc->sc_mp++ = 0;
1178 sc->sc_ilen++;
1179 sc->sc_mc->m_len++;
1181 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1182 if (sc->sc_flags & SC_DEBUG)
1183 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1184 (sc->sc_mp[-1] << 8) + c);
1185 goto flush;
1188 /* packet beyond configured mru? */
1189 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1190 if (sc->sc_flags & SC_DEBUG)
1191 printf("%s: packet too big\n", sc->sc_if.if_xname);
1192 goto flush;
1195 /* is this mbuf full? */
1196 m = sc->sc_mc;
1197 if (M_TRAILINGSPACE(m) <= 0) {
1198 if (m->m_next == NULL) {
1199 pppgetm(sc);
1200 if (m->m_next == NULL) {
1201 if (sc->sc_flags & SC_DEBUG)
1202 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1203 goto flush;
1206 sc->sc_mc = m = m->m_next;
1207 m->m_len = 0;
1208 m->m_data = M_DATASTART(m);
1209 sc->sc_mp = mtod(m, char *);
1212 ++m->m_len;
1213 *sc->sc_mp++ = c;
1214 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1215 return 0;
1217 flush:
1218 if (!(sc->sc_flags & SC_FLUSH)) {
1219 s = spltty();
1220 sc->sc_if.if_ierrors++;
1221 sc->sc_stats.ppp_ierrors++;
1222 sc->sc_flags |= SC_FLUSH;
1223 splx(s);
1224 if (sc->sc_flags & SC_LOG_FLUSH)
1225 ppplogchar(sc, c);
1227 return 0;
1230 #define MAX_DUMP_BYTES 128
1232 static void
1233 ppplogchar(struct ppp_softc *sc, int c)
1235 if (c >= 0) {
1236 sc->sc_rawin.buf[sc->sc_rawin_start++] = c;
1237 if (sc->sc_rawin.count < sizeof(sc->sc_rawin.buf))
1238 sc->sc_rawin.count++;
1240 if (sc->sc_rawin_start >= sizeof(sc->sc_rawin.buf)
1241 || (c < 0 && sc->sc_rawin_start > 0)) {
1242 if (sc->sc_flags & (SC_LOG_FLUSH|SC_LOG_RAWIN)) {
1243 printf("%s input: ", sc->sc_if.if_xname);
1244 pppdumpb(sc->sc_rawin.buf, sc->sc_rawin_start);
1246 if (c < 0)
1247 sc->sc_rawin.count = 0;
1248 sc->sc_rawin_start = 0;
1252 static void
1253 pppdumpb(u_char *b, int l)
1255 char bf[3*MAX_DUMP_BYTES+4];
1256 char *bp = bf;
1258 while (l--) {
1259 if (bp >= bf + sizeof(bf) - 3) {
1260 *bp++ = '>';
1261 break;
1263 *bp++ = hexdigits[*b >> 4]; /* convert byte to ascii hex */
1264 *bp++ = hexdigits[*b++ & 0xf];
1265 *bp++ = ' ';
1268 *bp = 0;
1269 printf("%s\n", bf);
1272 static void
1273 pppdumpframe(struct ppp_softc *sc, struct mbuf *m, int xmit)
1275 int i,lcount,copycount,count;
1276 char lbuf[16];
1277 char *data;
1279 if (m == NULL)
1280 return;
1282 for(count=m->m_len,data=mtod(m,char*);m != NULL;) {
1283 /* build a line of output */
1284 for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) {
1285 if (!count) {
1286 m = m->m_next;
1287 if (m == NULL)
1288 break;
1289 count = m->m_len;
1290 data = mtod(m,char*);
1292 copycount = (count > sizeof(lbuf)-lcount) ?
1293 sizeof(lbuf)-lcount : count;
1294 bcopy(data,&lbuf[lcount],copycount);
1295 data += copycount;
1296 count -= copycount;
1299 /* output line (hex 1st, then ascii) */
1300 printf("%s %s:", sc->sc_if.if_xname,
1301 xmit ? "output" : "input ");
1302 for(i=0;i<lcount;i++)
1303 printf("%02x ",(u_char)lbuf[i]);
1304 for(;i<sizeof(lbuf);i++)
1305 printf(" ");
1306 for(i=0;i<lcount;i++)
1307 printf("%c",(lbuf[i] >= 040 &&
1308 lbuf[i] <= 0176) ? lbuf[i] : '.');
1309 printf("\n");