Log a message when we succeed or fail in authenticating ourselves
[mpls-ppp.git] / netbsd-1.2 / ppp_tty.c
blob71a0673f67f4e065f065193775d97ff7f1860718
1 /* $NetBSD: ppp_tty.c,v 1.14 1998/08/02 15:09:50 sommerfe Exp $ */
2 /* $Id: ppp_tty.c,v 1.4 2002/12/06 12:03:44 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 * Drew D. Perkins
47 * Carnegie Mellon University
48 * 4910 Forbes Ave.
49 * Pittsburgh, PA 15213
50 * (412) 268-8576
51 * ddp@andrew.cmu.edu
53 * Based on:
54 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
56 * Copyright (c) 1987 Regents of the University of California.
57 * All rights reserved.
59 * Redistribution and use in source and binary forms are permitted
60 * provided that the above copyright notice and this paragraph are
61 * duplicated in all such forms and that any documentation,
62 * advertising materials, and other materials related to such
63 * distribution and use acknowledge that the software was developed
64 * by the University of California, Berkeley. The name of the
65 * University may not be used to endorse or promote products derived
66 * from this software without specific prior written permission.
67 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
68 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
69 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
71 * Serial Line interface
73 * Rick Adams
74 * Center for Seismic Studies
75 * 1300 N 17th Street, Suite 1450
76 * Arlington, Virginia 22209
77 * (703)276-7900
78 * rick@seismo.ARPA
79 * seismo!rick
81 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
82 * Converted to 4.3BSD Beta by Chris Torek.
83 * Other changes made at Berkeley, based in part on code by Kirk Smith.
85 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
86 * Added VJ tcp header compression; more unified ioctls
88 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
89 * Cleaned up a lot of the mbuf-related code to fix bugs that
90 * caused system crashes and packet corruption. Changed pppstart
91 * so that it doesn't just give up with a "collision" if the whole
92 * packet doesn't fit in the output ring buffer.
94 * Added priority queueing for interactive IP packets, following
95 * the model of if_sl.c, plus hooks for bpf.
96 * Paul Mackerras (paulus@cs.anu.edu.au).
99 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
100 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
102 #include "ppp.h"
103 #if NPPP > 0
105 #define VJC
106 #define PPP_COMPRESS
108 #include <sys/param.h>
109 #include <sys/proc.h>
110 #include <sys/mbuf.h>
111 #include <sys/dkstat.h>
112 #include <sys/socket.h>
113 #include <sys/ioctl.h>
114 #include <sys/file.h>
115 #include <sys/tty.h>
116 #include <sys/kernel.h>
117 #include <sys/conf.h>
118 #include <sys/vnode.h>
119 #include <sys/systm.h>
121 #include <net/if.h>
122 #include <net/if_types.h>
124 #ifdef VJC
125 #include <netinet/in.h>
126 #include <netinet/in_systm.h>
127 #include <netinet/ip.h>
128 #include <net/slcompress.h>
129 #endif
131 #ifdef PPP_FILTER
132 #include <net/bpf.h>
133 #endif
134 #include <net/ppp_defs.h>
135 #include <net/if_ppp.h>
136 #include <net/if_pppvar.h>
138 int pppopen __P((dev_t dev, struct tty *tp));
139 int pppclose __P((struct tty *tp, int flag));
140 int pppread __P((struct tty *tp, struct uio *uio, int flag));
141 int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
142 int ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag,
143 struct proc *));
144 int pppinput __P((int c, struct tty *tp));
145 int pppstart __P((struct tty *tp));
147 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
148 static void pppasyncstart __P((struct ppp_softc *));
149 static void pppasyncctlp __P((struct ppp_softc *));
150 static void pppasyncrelinq __P((struct ppp_softc *));
151 static void ppp_timeout __P((void *));
152 static void pppgetm __P((struct ppp_softc *sc));
153 static void pppdumpb __P((u_char *b, int l));
154 static void ppplogchar __P((struct ppp_softc *, int));
157 * Some useful mbuf macros not in mbuf.h.
159 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
161 #define M_DATASTART(m) \
162 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
163 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
165 #define M_DATASIZE(m) \
166 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
167 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
170 * Does c need to be escaped?
172 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
175 * Procedures for using an async tty interface for PPP.
178 /* This is a NetBSD-1.0 or later kernel. */
179 #define CCOUNT(q) ((q)->c_cc)
181 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
182 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
185 * Line specific open routine for async tty devices.
186 * Attach the given tty to the first available ppp unit.
187 * Called from device open routine or ttioctl.
189 /* ARGSUSED */
191 pppopen(dev, tp)
192 dev_t dev;
193 register struct tty *tp;
195 struct proc *p = curproc; /* XXX */
196 register struct ppp_softc *sc;
197 int error, s;
199 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
200 return (error);
202 s = spltty();
204 if (tp->t_line == PPPDISC) {
205 sc = (struct ppp_softc *) tp->t_sc;
206 if (sc != NULL && sc->sc_devp == (void *) tp) {
207 splx(s);
208 return (0);
212 if ((sc = pppalloc(p->p_pid)) == NULL) {
213 splx(s);
214 return ENXIO;
217 if (sc->sc_relinq)
218 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
220 sc->sc_ilen = 0;
221 sc->sc_m = NULL;
222 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
223 sc->sc_asyncmap[0] = 0xffffffff;
224 sc->sc_asyncmap[3] = 0x60000000;
225 sc->sc_rasyncmap = 0;
226 sc->sc_devp = (void *) tp;
227 sc->sc_start = pppasyncstart;
228 sc->sc_ctlp = pppasyncctlp;
229 sc->sc_relinq = pppasyncrelinq;
230 sc->sc_outm = NULL;
231 pppgetm(sc);
232 sc->sc_if.if_flags |= IFF_RUNNING;
233 sc->sc_if.if_baudrate = tp->t_ospeed;
235 tp->t_sc = (caddr_t) sc;
236 ttyflush(tp, FREAD | FWRITE);
238 splx(s);
239 return (0);
243 * Line specific close routine, called from device close routine
244 * and from ttioctl.
245 * Detach the tty from the ppp unit.
246 * Mimics part of ttyclose().
249 pppclose(tp, flag)
250 struct tty *tp;
251 int flag;
253 register struct ppp_softc *sc;
254 int s;
256 s = spltty();
257 ttyflush(tp, FREAD|FWRITE);
258 tp->t_line = 0;
259 sc = (struct ppp_softc *) tp->t_sc;
260 if (sc != NULL) {
261 tp->t_sc = NULL;
262 if (tp == (struct tty *) sc->sc_devp) {
263 pppasyncrelinq(sc);
264 pppdealloc(sc);
267 splx(s);
268 return 0;
272 * Relinquish the interface unit to another device.
274 static void
275 pppasyncrelinq(sc)
276 struct ppp_softc *sc;
278 int s;
280 s = spltty();
281 if (sc->sc_outm) {
282 m_freem(sc->sc_outm);
283 sc->sc_outm = NULL;
285 if (sc->sc_m) {
286 m_freem(sc->sc_m);
287 sc->sc_m = NULL;
289 if (sc->sc_flags & SC_TIMEOUT) {
290 untimeout(ppp_timeout, (void *) sc);
291 sc->sc_flags &= ~SC_TIMEOUT;
293 splx(s);
297 * Line specific (tty) read routine.
300 pppread(tp, uio, flag)
301 register struct tty *tp;
302 struct uio *uio;
303 int flag;
305 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
306 struct mbuf *m, *m0;
307 register int s;
308 int error = 0;
310 if (sc == NULL)
311 return 0;
313 * Loop waiting for input, checking that nothing disasterous
314 * happens in the meantime.
316 s = spltty();
317 for (;;) {
318 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
319 splx(s);
320 return 0;
322 if (sc->sc_inq.ifq_head != NULL)
323 break;
324 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
325 && (tp->t_state & TS_ISOPEN)) {
326 splx(s);
327 return 0; /* end of file */
329 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
330 splx(s);
331 return (EWOULDBLOCK);
333 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
334 if (error) {
335 splx(s);
336 return error;
340 /* Pull place-holder byte out of canonical queue */
341 getc(&tp->t_canq);
343 /* Get the packet from the input queue */
344 IF_DEQUEUE(&sc->sc_inq, m0);
345 splx(s);
347 for (m = m0; m && uio->uio_resid; m = m->m_next)
348 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
349 break;
350 m_freem(m0);
351 return (error);
355 * Line specific (tty) write routine.
358 pppwrite(tp, uio, flag)
359 register struct tty *tp;
360 struct uio *uio;
361 int flag;
363 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
364 struct mbuf *m, *m0, **mp;
365 struct sockaddr dst;
366 int len, error;
368 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
369 return 0; /* wrote 0 bytes */
370 if (tp->t_line != PPPDISC)
371 return (EINVAL);
372 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
373 return EIO;
374 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
375 uio->uio_resid < PPP_HDRLEN)
376 return (EMSGSIZE);
377 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
378 MGET(m, M_WAIT, MT_DATA);
379 if ((*mp = m) == NULL) {
380 m_freem(m0);
381 return (ENOBUFS);
383 m->m_len = 0;
384 if (uio->uio_resid >= MCLBYTES / 2)
385 MCLGET(m, M_DONTWAIT);
386 len = M_TRAILINGSPACE(m);
387 if (len > uio->uio_resid)
388 len = uio->uio_resid;
389 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
390 m_freem(m0);
391 return (error);
393 m->m_len = len;
395 dst.sa_family = AF_UNSPEC;
396 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
397 m0->m_data += PPP_HDRLEN;
398 m0->m_len -= PPP_HDRLEN;
399 return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
403 * Line specific (tty) ioctl routine.
404 * This discipline requires that tty device drivers call
405 * the line specific l_ioctl routine from their ioctl routines.
407 /* ARGSUSED */
409 ppptioctl(tp, cmd, data, flag, p)
410 struct tty *tp;
411 u_long cmd;
412 caddr_t data;
413 int flag;
414 struct proc *p;
416 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
417 int error, s;
419 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
420 return -1;
422 error = 0;
423 switch (cmd) {
424 case PPPIOCSASYNCMAP:
425 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
426 break;
427 sc->sc_asyncmap[0] = *(u_int *)data;
428 break;
430 case PPPIOCGASYNCMAP:
431 *(u_int *)data = sc->sc_asyncmap[0];
432 break;
434 case PPPIOCSRASYNCMAP:
435 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
436 break;
437 sc->sc_rasyncmap = *(u_int *)data;
438 break;
440 case PPPIOCGRASYNCMAP:
441 *(u_int *)data = sc->sc_rasyncmap;
442 break;
444 case PPPIOCSXASYNCMAP:
445 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
446 break;
447 s = spltty();
448 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
449 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
450 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
451 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
452 splx(s);
453 break;
455 case PPPIOCGXASYNCMAP:
456 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
457 break;
459 default:
460 error = pppioctl(sc, cmd, data, flag, p);
461 if (error == 0 && cmd == PPPIOCSMRU)
462 pppgetm(sc);
465 return error;
469 * FCS lookup table as calculated by genfcstab.
471 static u_int16_t fcstab[256] = {
472 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
473 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
474 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
475 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
476 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
477 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
478 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
479 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
480 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
481 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
482 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
483 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
484 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
485 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
486 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
487 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
488 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
489 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
490 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
491 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
492 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
493 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
494 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
495 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
496 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
497 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
498 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
499 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
500 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
501 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
502 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
503 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
507 * Calculate a new FCS given the current FCS and the new data.
509 static u_int16_t
510 pppfcs(fcs, cp, len)
511 register u_int16_t fcs;
512 register u_char *cp;
513 register int len;
515 while (len--)
516 fcs = PPP_FCS(fcs, *cp++);
517 return (fcs);
521 * This gets called at splsoftnet from if_ppp.c at various times
522 * when there is data ready to be sent.
524 static void
525 pppasyncstart(sc)
526 register struct ppp_softc *sc;
528 register struct tty *tp = (struct tty *) sc->sc_devp;
529 register struct mbuf *m;
530 register int len;
531 register u_char *start, *stop, *cp;
532 int n, ndone, done, idle;
533 struct mbuf *m2;
534 int s;
536 idle = 0;
537 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
539 * See if we have an existing packet partly sent.
540 * If not, get a new packet and start sending it.
542 m = sc->sc_outm;
543 if (m == NULL) {
545 * Get another packet to be sent.
547 m = ppp_dequeue(sc);
548 if (m == NULL) {
549 idle = 1;
550 break;
554 * The extra PPP_FLAG will start up a new packet, and thus
555 * will flush any accumulated garbage. We do this whenever
556 * the line may have been idle for some time.
558 if (CCOUNT(&tp->t_outq) == 0) {
559 ++sc->sc_stats.ppp_obytes;
560 (void) putc(PPP_FLAG, &tp->t_outq);
563 /* Calculate the FCS for the first mbuf's worth. */
564 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
565 sc->sc_if.if_lastchange = time;
568 for (;;) {
569 start = mtod(m, u_char *);
570 len = m->m_len;
571 stop = start + len;
572 while (len > 0) {
574 * Find out how many bytes in the string we can
575 * handle without doing something special.
577 for (cp = start; cp < stop; cp++)
578 if (ESCAPE_P(*cp))
579 break;
580 n = cp - start;
581 if (n) {
582 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
583 ndone = n - b_to_q(start, n, &tp->t_outq);
584 len -= ndone;
585 start += ndone;
586 sc->sc_stats.ppp_obytes += ndone;
588 if (ndone < n)
589 break; /* packet doesn't fit */
592 * If there are characters left in the mbuf,
593 * the first one must be special.
594 * Put it out in a different form.
596 if (len) {
597 s = spltty();
598 if (putc(PPP_ESCAPE, &tp->t_outq)) {
599 splx(s);
600 break;
602 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
603 (void) unputc(&tp->t_outq);
604 splx(s);
605 break;
607 splx(s);
608 sc->sc_stats.ppp_obytes += 2;
609 start++;
610 len--;
615 * If we didn't empty this mbuf, remember where we're up to.
616 * If we emptied the last mbuf, try to add the FCS and closing
617 * flag, and if we can't, leave sc_outm pointing to m, but with
618 * m->m_len == 0, to remind us to output the FCS and flag later.
620 done = len == 0;
621 if (done && m->m_next == NULL) {
622 u_char *p, *q;
623 int c;
624 u_char endseq[8];
627 * We may have to escape the bytes in the FCS.
629 p = endseq;
630 c = ~sc->sc_outfcs & 0xFF;
631 if (ESCAPE_P(c)) {
632 *p++ = PPP_ESCAPE;
633 *p++ = c ^ PPP_TRANS;
634 } else
635 *p++ = c;
636 c = (~sc->sc_outfcs >> 8) & 0xFF;
637 if (ESCAPE_P(c)) {
638 *p++ = PPP_ESCAPE;
639 *p++ = c ^ PPP_TRANS;
640 } else
641 *p++ = c;
642 *p++ = PPP_FLAG;
645 * Try to output the FCS and flag. If the bytes
646 * don't all fit, back out.
648 s = spltty();
649 for (q = endseq; q < p; ++q)
650 if (putc(*q, &tp->t_outq)) {
651 done = 0;
652 for (; q > endseq; --q)
653 unputc(&tp->t_outq);
654 break;
656 splx(s);
657 if (done)
658 sc->sc_stats.ppp_obytes += q - endseq;
661 if (!done) {
662 /* remember where we got to */
663 m->m_data = start;
664 m->m_len = len;
665 break;
668 /* Finished with this mbuf; free it and move on. */
669 MFREE(m, m2);
670 m = m2;
671 if (m == NULL) {
672 /* Finished a packet */
673 break;
675 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
679 * If m == NULL, we have finished a packet.
680 * If m != NULL, we've either done as much work this time
681 * as we need to, or else we've filled up the output queue.
683 sc->sc_outm = m;
684 if (m)
685 break;
688 /* Call pppstart to start output again if necessary. */
689 s = spltty();
690 pppstart(tp);
693 * This timeout is needed for operation on a pseudo-tty,
694 * because the pty code doesn't call pppstart after it has
695 * drained the t_outq.
697 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
698 timeout(ppp_timeout, (void *) sc, 1);
699 sc->sc_flags |= SC_TIMEOUT;
702 splx(s);
706 * This gets called when a received packet is placed on
707 * the inq, at splsoftnet.
709 static void
710 pppasyncctlp(sc)
711 struct ppp_softc *sc;
713 struct tty *tp;
714 int s;
716 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
717 s = spltty();
718 tp = (struct tty *) sc->sc_devp;
719 putc(0, &tp->t_canq);
720 ttwakeup(tp);
721 splx(s);
725 * Start output on async tty interface. If the transmit queue
726 * has drained sufficiently, arrange for pppasyncstart to be
727 * called later at splsoftnet.
728 * Called at spltty or higher.
731 pppstart(tp)
732 register struct tty *tp;
734 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
737 * If there is stuff in the output queue, send it now.
738 * We are being called in lieu of ttstart and must do what it would.
740 if (tp->t_oproc != NULL)
741 (*tp->t_oproc)(tp);
744 * If the transmit queue has drained and the tty has not hung up
745 * or been disconnected from the ppp unit, then tell if_ppp.c that
746 * we need more output.
748 if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
749 && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
750 return 0;
751 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
752 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
753 ppp_restart(sc);
756 return 0;
760 * Timeout routine - try to start some more output.
762 static void
763 ppp_timeout(x)
764 void *x;
766 struct ppp_softc *sc = (struct ppp_softc *) x;
767 struct tty *tp = (struct tty *) sc->sc_devp;
768 int s;
770 s = spltty();
771 sc->sc_flags &= ~SC_TIMEOUT;
772 pppstart(tp);
773 splx(s);
777 * Allocate enough mbuf to handle current MRU.
779 static void
780 pppgetm(sc)
781 register struct ppp_softc *sc;
783 struct mbuf *m, **mp;
784 int len;
786 mp = &sc->sc_m;
787 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
788 if ((m = *mp) == NULL) {
789 MGETHDR(m, M_DONTWAIT, MT_DATA);
790 if (m == NULL)
791 break;
792 *mp = m;
793 MCLGET(m, M_DONTWAIT);
795 len -= M_DATASIZE(m);
796 mp = &m->m_next;
801 * tty interface receiver interrupt.
803 static unsigned paritytab[8] = {
804 0x96696996, 0x69969669, 0x69969669, 0x96696996,
805 0x69969669, 0x96696996, 0x96696996, 0x69969669
809 pppinput(c, tp)
810 int c;
811 register struct tty *tp;
813 register struct ppp_softc *sc;
814 struct mbuf *m;
815 int ilen, s;
817 sc = (struct ppp_softc *) tp->t_sc;
818 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
819 return 0;
821 ++tk_nin;
822 ++sc->sc_stats.ppp_ibytes;
824 if (c & TTY_FE) {
825 /* framing error or overrun on this char - abort packet */
826 if (sc->sc_flags & SC_DEBUG)
827 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
828 goto flush;
831 c &= 0xff;
834 * Handle software flow control of output.
836 if (tp->t_iflag & IXON) {
837 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
838 if ((tp->t_state & TS_TTSTOP) == 0) {
839 tp->t_state |= TS_TTSTOP;
840 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
842 return 0;
844 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
845 tp->t_state &= ~TS_TTSTOP;
846 if (tp->t_oproc != NULL)
847 (*tp->t_oproc)(tp);
848 return 0;
852 s = spltty();
853 if (c & 0x80)
854 sc->sc_flags |= SC_RCV_B7_1;
855 else
856 sc->sc_flags |= SC_RCV_B7_0;
857 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
858 sc->sc_flags |= SC_RCV_ODDP;
859 else
860 sc->sc_flags |= SC_RCV_EVNP;
861 splx(s);
863 if (sc->sc_flags & SC_LOG_RAWIN)
864 ppplogchar(sc, c);
866 if (c == PPP_FLAG) {
867 ilen = sc->sc_ilen;
868 sc->sc_ilen = 0;
870 if (sc->sc_rawin_count > 0)
871 ppplogchar(sc, -1);
874 * If SC_ESCAPED is set, then we've seen the packet
875 * abort sequence "}~".
877 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
878 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
879 s = spltty();
880 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
881 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
882 if (sc->sc_flags & SC_DEBUG)
883 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
884 sc->sc_fcs);
885 sc->sc_if.if_ierrors++;
886 sc->sc_stats.ppp_ierrors++;
887 } else
888 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
889 splx(s);
890 return 0;
893 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
894 if (ilen) {
895 if (sc->sc_flags & SC_DEBUG)
896 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
897 s = spltty();
898 sc->sc_if.if_ierrors++;
899 sc->sc_stats.ppp_ierrors++;
900 sc->sc_flags |= SC_PKTLOST;
901 splx(s);
903 return 0;
907 * Remove FCS trailer. Somewhat painful...
909 ilen -= 2;
910 if (--sc->sc_mc->m_len == 0) {
911 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
913 sc->sc_mc = m;
915 sc->sc_mc->m_len--;
917 /* excise this mbuf chain */
918 m = sc->sc_m;
919 sc->sc_m = sc->sc_mc->m_next;
920 sc->sc_mc->m_next = NULL;
922 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
923 if (sc->sc_flags & SC_PKTLOST) {
924 s = spltty();
925 sc->sc_flags &= ~SC_PKTLOST;
926 splx(s);
929 pppgetm(sc);
930 return 0;
933 if (sc->sc_flags & SC_FLUSH) {
934 if (sc->sc_flags & SC_LOG_FLUSH)
935 ppplogchar(sc, c);
936 return 0;
939 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
940 return 0;
942 s = spltty();
943 if (sc->sc_flags & SC_ESCAPED) {
944 sc->sc_flags &= ~SC_ESCAPED;
945 c ^= PPP_TRANS;
946 } else if (c == PPP_ESCAPE) {
947 sc->sc_flags |= SC_ESCAPED;
948 splx(s);
949 return 0;
951 splx(s);
954 * Initialize buffer on first octet received.
955 * First octet could be address or protocol (when compressing
956 * address/control).
957 * Second octet is control.
958 * Third octet is first or second (when compressing protocol)
959 * octet of protocol.
960 * Fourth octet is second octet of protocol.
962 if (sc->sc_ilen == 0) {
963 /* reset the first input mbuf */
964 if (sc->sc_m == NULL) {
965 pppgetm(sc);
966 if (sc->sc_m == NULL) {
967 if (sc->sc_flags & SC_DEBUG)
968 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
969 goto flush;
972 m = sc->sc_m;
973 m->m_len = 0;
974 m->m_data = M_DATASTART(sc->sc_m);
975 sc->sc_mc = m;
976 sc->sc_mp = mtod(m, char *);
977 sc->sc_fcs = PPP_INITFCS;
978 if (c != PPP_ALLSTATIONS) {
979 if (sc->sc_flags & SC_REJ_COMP_AC) {
980 if (sc->sc_flags & SC_DEBUG)
981 printf("%s: garbage received: 0x%x (need 0xFF)\n",
982 sc->sc_if.if_xname, c);
983 goto flush;
985 *sc->sc_mp++ = PPP_ALLSTATIONS;
986 *sc->sc_mp++ = PPP_UI;
987 sc->sc_ilen += 2;
988 m->m_len += 2;
991 if (sc->sc_ilen == 1 && c != PPP_UI) {
992 if (sc->sc_flags & SC_DEBUG)
993 printf("%s: missing UI (0x3), got 0x%x\n",
994 sc->sc_if.if_xname, c);
995 goto flush;
997 if (sc->sc_ilen == 2 && (c & 1) == 1) {
998 /* a compressed protocol */
999 *sc->sc_mp++ = 0;
1000 sc->sc_ilen++;
1001 sc->sc_mc->m_len++;
1003 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1004 if (sc->sc_flags & SC_DEBUG)
1005 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1006 (sc->sc_mp[-1] << 8) + c);
1007 goto flush;
1010 /* packet beyond configured mru? */
1011 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1012 if (sc->sc_flags & SC_DEBUG)
1013 printf("%s: packet too big\n", sc->sc_if.if_xname);
1014 goto flush;
1017 /* is this mbuf full? */
1018 m = sc->sc_mc;
1019 if (M_TRAILINGSPACE(m) <= 0) {
1020 if (m->m_next == NULL) {
1021 pppgetm(sc);
1022 if (m->m_next == NULL) {
1023 if (sc->sc_flags & SC_DEBUG)
1024 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1025 goto flush;
1028 sc->sc_mc = m = m->m_next;
1029 m->m_len = 0;
1030 m->m_data = M_DATASTART(m);
1031 sc->sc_mp = mtod(m, char *);
1034 ++m->m_len;
1035 *sc->sc_mp++ = c;
1036 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1037 return 0;
1039 flush:
1040 if (!(sc->sc_flags & SC_FLUSH)) {
1041 s = spltty();
1042 sc->sc_if.if_ierrors++;
1043 sc->sc_stats.ppp_ierrors++;
1044 sc->sc_flags |= SC_FLUSH;
1045 splx(s);
1046 if (sc->sc_flags & SC_LOG_FLUSH)
1047 ppplogchar(sc, c);
1049 return 0;
1052 #define MAX_DUMP_BYTES 128
1054 static void
1055 ppplogchar(sc, c)
1056 struct ppp_softc *sc;
1057 int c;
1059 if (c >= 0)
1060 sc->sc_rawin[sc->sc_rawin_count++] = c;
1061 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1062 || (c < 0 && sc->sc_rawin_count > 0)) {
1063 printf("%s input: ", sc->sc_if.if_xname);
1064 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1065 sc->sc_rawin_count = 0;
1069 static void
1070 pppdumpb(b, l)
1071 u_char *b;
1072 int l;
1074 char buf[3*MAX_DUMP_BYTES+4];
1075 char *bp = buf;
1076 static char digits[] = "0123456789abcdef";
1078 while (l--) {
1079 if (bp >= buf + sizeof(buf) - 3) {
1080 *bp++ = '>';
1081 break;
1083 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1084 *bp++ = digits[*b++ & 0xf];
1085 *bp++ = ' ';
1088 *bp = 0;
1089 printf("%s\n", buf);
1092 #endif /* NPPP > 0 */