Update for 2.4.4 release
[mpls-ppp.git] / netbsd-1.1 / ppp_tty.c
blobd24b9907bfdb7654f7c7a625e5719db9fef00e51
1 /* $Id: ppp_tty.c,v 1.5 2002/12/06 12:03:44 paulus Exp $ */
3 /*
4 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
5 * tty devices.
7 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
21 * 3. The name "Carnegie Mellon University" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For permission or any legal
24 * details, please contact
25 * Office of Technology Transfer
26 * Carnegie Mellon University
27 * 5000 Forbes Avenue
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
33 * acknowledgment:
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
45 * Drew D. Perkins
46 * Carnegie Mellon University
47 * 4910 Forbes Ave.
48 * Pittsburgh, PA 15213
49 * (412) 268-8576
50 * ddp@andrew.cmu.edu
52 * Based on:
53 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
55 * Copyright (c) 1987 Regents of the University of California.
56 * All rights reserved.
58 * Redistribution and use in source and binary forms are permitted
59 * provided that the above copyright notice and this paragraph are
60 * duplicated in all such forms and that any documentation,
61 * advertising materials, and other materials related to such
62 * distribution and use acknowledge that the software was developed
63 * by the University of California, Berkeley. The name of the
64 * University may not be used to endorse or promote products derived
65 * from this software without specific prior written permission.
66 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
67 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
68 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
70 * Serial Line interface
72 * Rick Adams
73 * Center for Seismic Studies
74 * 1300 N 17th Street, Suite 1450
75 * Arlington, Virginia 22209
76 * (703)276-7900
77 * rick@seismo.ARPA
78 * seismo!rick
80 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
81 * Converted to 4.3BSD Beta by Chris Torek.
82 * Other changes made at Berkeley, based in part on code by Kirk Smith.
84 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
85 * Added VJ tcp header compression; more unified ioctls
87 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
88 * Cleaned up a lot of the mbuf-related code to fix bugs that
89 * caused system crashes and packet corruption. Changed pppstart
90 * so that it doesn't just give up with a "collision" if the whole
91 * packet doesn't fit in the output ring buffer.
93 * Added priority queueing for interactive IP packets, following
94 * the model of if_sl.c, plus hooks for bpf.
95 * Paul Mackerras (paulus@cs.anu.edu.au).
98 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
99 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
101 #include "ppp.h"
102 #if NPPP > 0
104 #define VJC
105 #define PPP_COMPRESS
107 #include <sys/param.h>
108 #include <sys/proc.h>
109 #include <sys/mbuf.h>
110 #include <sys/dkstat.h>
111 #include <sys/socket.h>
112 #include <sys/ioctl.h>
113 #include <sys/file.h>
114 #include <sys/tty.h>
115 #include <sys/kernel.h>
116 #include <sys/conf.h>
117 #include <sys/vnode.h>
118 #include <sys/systm.h>
120 #include <net/if.h>
121 #include <net/if_types.h>
123 #ifdef VJC
124 #include <netinet/in.h>
125 #include <netinet/in_systm.h>
126 #include <netinet/ip.h>
127 #include <net/slcompress.h>
128 #endif
130 #ifdef PPP_FILTER
131 #include <net/bpf.h>
132 #endif
133 #include <net/ppp_defs.h>
134 #include <net/if_ppp.h>
135 #include <net/if_pppvar.h>
137 int pppopen __P((dev_t dev, struct tty *tp));
138 int pppclose __P((struct tty *tp, int flag));
139 int pppread __P((struct tty *tp, struct uio *uio, int flag));
140 int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
141 int ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag,
142 struct proc *));
143 int pppinput __P((int c, struct tty *tp));
144 int pppstart __P((struct tty *tp, int));
146 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
147 static void pppasyncstart __P((struct ppp_softc *));
148 static void pppasyncctlp __P((struct ppp_softc *));
149 static void pppasyncrelinq __P((struct ppp_softc *));
150 static void ppp_timeout __P((void *));
151 static void pppgetm __P((struct ppp_softc *sc));
152 static void pppdumpb __P((u_char *b, int l));
153 static void ppplogchar __P((struct ppp_softc *, int));
156 * Some useful mbuf macros not in mbuf.h.
158 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
160 #define M_DATASTART(m) \
161 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
162 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
164 #define M_DATASIZE(m) \
165 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
166 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
169 * Does c need to be escaped?
171 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
174 * Procedures for using an async tty interface for PPP.
177 /* This is a NetBSD-1.0 or later kernel. */
178 #define CCOUNT(q) ((q)->c_cc)
180 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
181 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
184 * Line specific open routine for async tty devices.
185 * Attach the given tty to the first available ppp unit.
186 * Called from device open routine or ttioctl.
188 /* ARGSUSED */
190 pppopen(dev, tp)
191 dev_t dev;
192 register struct tty *tp;
194 struct proc *p = curproc; /* XXX */
195 register struct ppp_softc *sc;
196 int error, s;
198 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
199 return (error);
201 s = spltty();
203 if (tp->t_line == PPPDISC) {
204 sc = (struct ppp_softc *) tp->t_sc;
205 if (sc != NULL && sc->sc_devp == (void *) tp) {
206 splx(s);
207 return (0);
211 if ((sc = pppalloc(p->p_pid)) == NULL) {
212 splx(s);
213 return ENXIO;
216 if (sc->sc_relinq)
217 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
219 sc->sc_ilen = 0;
220 sc->sc_m = NULL;
221 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
222 sc->sc_asyncmap[0] = 0xffffffff;
223 sc->sc_asyncmap[3] = 0x60000000;
224 sc->sc_rasyncmap = 0;
225 sc->sc_devp = (void *) tp;
226 sc->sc_start = pppasyncstart;
227 sc->sc_ctlp = pppasyncctlp;
228 sc->sc_relinq = pppasyncrelinq;
229 sc->sc_outm = NULL;
230 pppgetm(sc);
231 sc->sc_if.if_flags |= IFF_RUNNING;
232 sc->sc_if.if_baudrate = tp->t_ospeed;
234 tp->t_sc = (caddr_t) sc;
235 ttyflush(tp, FREAD | FWRITE);
237 splx(s);
238 return (0);
242 * Line specific close routine, called from device close routine
243 * and from ttioctl.
244 * Detach the tty from the ppp unit.
245 * Mimics part of ttyclose().
248 pppclose(tp, flag)
249 struct tty *tp;
250 int flag;
252 register struct ppp_softc *sc;
253 int s;
255 s = spltty();
256 ttyflush(tp, FREAD|FWRITE);
257 tp->t_line = 0;
258 sc = (struct ppp_softc *) tp->t_sc;
259 if (sc != NULL) {
260 tp->t_sc = NULL;
261 if (tp == (struct tty *) sc->sc_devp) {
262 pppasyncrelinq(sc);
263 pppdealloc(sc);
266 splx(s);
267 return 0;
271 * Relinquish the interface unit to another device.
273 static void
274 pppasyncrelinq(sc)
275 struct ppp_softc *sc;
277 int s;
279 s = spltty();
280 if (sc->sc_outm) {
281 m_freem(sc->sc_outm);
282 sc->sc_outm = NULL;
284 if (sc->sc_m) {
285 m_freem(sc->sc_m);
286 sc->sc_m = NULL;
288 if (sc->sc_flags & SC_TIMEOUT) {
289 untimeout(ppp_timeout, (void *) sc);
290 sc->sc_flags &= ~SC_TIMEOUT;
292 splx(s);
296 * Line specific (tty) read routine.
299 pppread(tp, uio, flag)
300 register struct tty *tp;
301 struct uio *uio;
302 int flag;
304 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
305 struct mbuf *m, *m0;
306 register int s;
307 int error = 0;
309 if (sc == NULL)
310 return 0;
312 * Loop waiting for input, checking that nothing disasterous
313 * happens in the meantime.
315 s = spltty();
316 for (;;) {
317 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
318 splx(s);
319 return 0;
321 if (sc->sc_inq.ifq_head != NULL)
322 break;
323 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
324 && (tp->t_state & TS_ISOPEN)) {
325 splx(s);
326 return 0; /* end of file */
328 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
329 splx(s);
330 return (EWOULDBLOCK);
332 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
333 if (error) {
334 splx(s);
335 return error;
339 /* Pull place-holder byte out of canonical queue */
340 getc(&tp->t_canq);
342 /* Get the packet from the input queue */
343 IF_DEQUEUE(&sc->sc_inq, m0);
344 splx(s);
346 for (m = m0; m && uio->uio_resid; m = m->m_next)
347 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
348 break;
349 m_freem(m0);
350 return (error);
354 * Line specific (tty) write routine.
357 pppwrite(tp, uio, flag)
358 register struct tty *tp;
359 struct uio *uio;
360 int flag;
362 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
363 struct mbuf *m, *m0, **mp;
364 struct sockaddr dst;
365 int len, error;
367 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
368 return 0; /* wrote 0 bytes */
369 if (tp->t_line != PPPDISC)
370 return (EINVAL);
371 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
372 return EIO;
373 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
374 uio->uio_resid < PPP_HDRLEN)
375 return (EMSGSIZE);
376 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
377 MGET(m, M_WAIT, MT_DATA);
378 if ((*mp = m) == NULL) {
379 m_freem(m0);
380 return (ENOBUFS);
382 m->m_len = 0;
383 if (uio->uio_resid >= MCLBYTES / 2)
384 MCLGET(m, M_DONTWAIT);
385 len = M_TRAILINGSPACE(m);
386 if (len > uio->uio_resid)
387 len = uio->uio_resid;
388 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
389 m_freem(m0);
390 return (error);
392 m->m_len = len;
394 dst.sa_family = AF_UNSPEC;
395 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
396 m0->m_data += PPP_HDRLEN;
397 m0->m_len -= PPP_HDRLEN;
398 return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
402 * Line specific (tty) ioctl routine.
403 * This discipline requires that tty device drivers call
404 * the line specific l_ioctl routine from their ioctl routines.
406 /* ARGSUSED */
408 ppptioctl(tp, cmd, data, flag, p)
409 struct tty *tp;
410 u_long cmd;
411 caddr_t data;
412 int flag;
413 struct proc *p;
415 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
416 int error, s;
418 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
419 return -1;
421 error = 0;
422 switch (cmd) {
423 case PPPIOCSASYNCMAP:
424 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
425 break;
426 sc->sc_asyncmap[0] = *(u_int *)data;
427 break;
429 case PPPIOCGASYNCMAP:
430 *(u_int *)data = sc->sc_asyncmap[0];
431 break;
433 case PPPIOCSRASYNCMAP:
434 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
435 break;
436 sc->sc_rasyncmap = *(u_int *)data;
437 break;
439 case PPPIOCGRASYNCMAP:
440 *(u_int *)data = sc->sc_rasyncmap;
441 break;
443 case PPPIOCSXASYNCMAP:
444 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
445 break;
446 s = spltty();
447 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
448 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
449 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
450 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
451 splx(s);
452 break;
454 case PPPIOCGXASYNCMAP:
455 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
456 break;
458 default:
459 error = pppioctl(sc, cmd, data, flag, p);
460 if (error == 0 && cmd == PPPIOCSMRU)
461 pppgetm(sc);
464 return error;
468 * FCS lookup table as calculated by genfcstab.
470 static u_int16_t fcstab[256] = {
471 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
472 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
473 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
474 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
475 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
476 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
477 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
478 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
479 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
480 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
481 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
482 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
483 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
484 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
485 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
486 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
487 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
488 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
489 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
490 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
491 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
492 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
493 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
494 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
495 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
496 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
497 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
498 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
499 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
500 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
501 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
502 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
506 * Calculate a new FCS given the current FCS and the new data.
508 static u_int16_t
509 pppfcs(fcs, cp, len)
510 register u_int16_t fcs;
511 register u_char *cp;
512 register int len;
514 while (len--)
515 fcs = PPP_FCS(fcs, *cp++);
516 return (fcs);
520 * This gets called at splsoftnet from if_ppp.c at various times
521 * when there is data ready to be sent.
523 static void
524 pppasyncstart(sc)
525 register struct ppp_softc *sc;
527 register struct tty *tp = (struct tty *) sc->sc_devp;
528 register struct mbuf *m;
529 register int len;
530 register u_char *start, *stop, *cp;
531 int n, ndone, done, idle;
532 struct mbuf *m2;
533 int s;
535 idle = 0;
536 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
538 * See if we have an existing packet partly sent.
539 * If not, get a new packet and start sending it.
541 m = sc->sc_outm;
542 if (m == NULL) {
544 * Get another packet to be sent.
546 m = ppp_dequeue(sc);
547 if (m == NULL) {
548 idle = 1;
549 break;
553 * The extra PPP_FLAG will start up a new packet, and thus
554 * will flush any accumulated garbage. We do this whenever
555 * the line may have been idle for some time.
557 if (CCOUNT(&tp->t_outq) == 0) {
558 ++sc->sc_stats.ppp_obytes;
559 (void) putc(PPP_FLAG, &tp->t_outq);
562 /* Calculate the FCS for the first mbuf's worth. */
563 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
564 sc->sc_if.if_lastchange = time;
567 for (;;) {
568 start = mtod(m, u_char *);
569 len = m->m_len;
570 stop = start + len;
571 while (len > 0) {
573 * Find out how many bytes in the string we can
574 * handle without doing something special.
576 for (cp = start; cp < stop; cp++)
577 if (ESCAPE_P(*cp))
578 break;
579 n = cp - start;
580 if (n) {
581 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
582 ndone = n - b_to_q(start, n, &tp->t_outq);
583 len -= ndone;
584 start += ndone;
585 sc->sc_stats.ppp_obytes += ndone;
587 if (ndone < n)
588 break; /* packet doesn't fit */
591 * If there are characters left in the mbuf,
592 * the first one must be special.
593 * Put it out in a different form.
595 if (len) {
596 s = spltty();
597 if (putc(PPP_ESCAPE, &tp->t_outq)) {
598 splx(s);
599 break;
601 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
602 (void) unputc(&tp->t_outq);
603 splx(s);
604 break;
606 splx(s);
607 sc->sc_stats.ppp_obytes += 2;
608 start++;
609 len--;
614 * If we didn't empty this mbuf, remember where we're up to.
615 * If we emptied the last mbuf, try to add the FCS and closing
616 * flag, and if we can't, leave sc_outm pointing to m, but with
617 * m->m_len == 0, to remind us to output the FCS and flag later.
619 done = len == 0;
620 if (done && m->m_next == NULL) {
621 u_char *p, *q;
622 int c;
623 u_char endseq[8];
626 * We may have to escape the bytes in the FCS.
628 p = endseq;
629 c = ~sc->sc_outfcs & 0xFF;
630 if (ESCAPE_P(c)) {
631 *p++ = PPP_ESCAPE;
632 *p++ = c ^ PPP_TRANS;
633 } else
634 *p++ = c;
635 c = (~sc->sc_outfcs >> 8) & 0xFF;
636 if (ESCAPE_P(c)) {
637 *p++ = PPP_ESCAPE;
638 *p++ = c ^ PPP_TRANS;
639 } else
640 *p++ = c;
641 *p++ = PPP_FLAG;
644 * Try to output the FCS and flag. If the bytes
645 * don't all fit, back out.
647 s = spltty();
648 for (q = endseq; q < p; ++q)
649 if (putc(*q, &tp->t_outq)) {
650 done = 0;
651 for (; q > endseq; --q)
652 unputc(&tp->t_outq);
653 break;
655 splx(s);
656 if (done)
657 sc->sc_stats.ppp_obytes += q - endseq;
660 if (!done) {
661 /* remember where we got to */
662 m->m_data = start;
663 m->m_len = len;
664 break;
667 /* Finished with this mbuf; free it and move on. */
668 MFREE(m, m2);
669 m = m2;
670 if (m == NULL) {
671 /* Finished a packet */
672 break;
674 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
678 * If m == NULL, we have finished a packet.
679 * If m != NULL, we've either done as much work this time
680 * as we need to, or else we've filled up the output queue.
682 sc->sc_outm = m;
683 if (m)
684 break;
687 /* Call pppstart to start output again if necessary. */
688 s = spltty();
689 pppstart(tp, 0);
692 * This timeout is needed for operation on a pseudo-tty,
693 * because the pty code doesn't call pppstart after it has
694 * drained the t_outq.
696 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
697 timeout(ppp_timeout, (void *) sc, 1);
698 sc->sc_flags |= SC_TIMEOUT;
701 splx(s);
705 * This gets called when a received packet is placed on
706 * the inq, at splsoftnet.
708 static void
709 pppasyncctlp(sc)
710 struct ppp_softc *sc;
712 struct tty *tp;
713 int s;
715 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
716 s = spltty();
717 tp = (struct tty *) sc->sc_devp;
718 putc(0, &tp->t_canq);
719 ttwakeup(tp);
720 splx(s);
724 * Start output on async tty interface. If the transmit queue
725 * has drained sufficiently, arrange for pppasyncstart to be
726 * called later at splsoftnet.
727 * Called at spltty or higher.
730 pppstart(tp, force)
731 register struct tty *tp;
732 int force;
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 && !force)
749 return 0;
750 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
751 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
752 ppp_restart(sc);
755 return 0;
759 * Timeout routine - try to start some more output.
761 static void
762 ppp_timeout(x)
763 void *x;
765 struct ppp_softc *sc = (struct ppp_softc *) x;
766 struct tty *tp = (struct tty *) sc->sc_devp;
767 int s;
769 s = spltty();
770 sc->sc_flags &= ~SC_TIMEOUT;
771 pppstart(tp, 1);
772 splx(s);
776 * Allocate enough mbuf to handle current MRU.
778 static void
779 pppgetm(sc)
780 register struct ppp_softc *sc;
782 struct mbuf *m, **mp;
783 int len;
785 mp = &sc->sc_m;
786 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
787 if ((m = *mp) == NULL) {
788 MGETHDR(m, M_DONTWAIT, MT_DATA);
789 if (m == NULL)
790 break;
791 *mp = m;
792 MCLGET(m, M_DONTWAIT);
794 len -= M_DATASIZE(m);
795 mp = &m->m_next;
800 * tty interface receiver interrupt.
802 static unsigned paritytab[8] = {
803 0x96696996, 0x69969669, 0x69969669, 0x96696996,
804 0x69969669, 0x96696996, 0x96696996, 0x69969669
808 pppinput(c, tp)
809 int c;
810 register struct tty *tp;
812 register struct ppp_softc *sc;
813 struct mbuf *m;
814 int ilen, s;
816 sc = (struct ppp_softc *) tp->t_sc;
817 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
818 return 0;
820 ++tk_nin;
821 ++sc->sc_stats.ppp_ibytes;
823 if (c & TTY_FE) {
824 /* framing error or overrun on this char - abort packet */
825 if (sc->sc_flags & SC_DEBUG)
826 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
827 goto flush;
830 c &= 0xff;
833 * Handle software flow control of output.
835 if (tp->t_iflag & IXON) {
836 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
837 if ((tp->t_state & TS_TTSTOP) == 0) {
838 tp->t_state |= TS_TTSTOP;
839 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
841 return 0;
843 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
844 tp->t_state &= ~TS_TTSTOP;
845 if (tp->t_oproc != NULL)
846 (*tp->t_oproc)(tp);
847 return 0;
851 s = spltty();
852 if (c & 0x80)
853 sc->sc_flags |= SC_RCV_B7_1;
854 else
855 sc->sc_flags |= SC_RCV_B7_0;
856 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
857 sc->sc_flags |= SC_RCV_ODDP;
858 else
859 sc->sc_flags |= SC_RCV_EVNP;
860 splx(s);
862 if (sc->sc_flags & SC_LOG_RAWIN)
863 ppplogchar(sc, c);
865 if (c == PPP_FLAG) {
866 ilen = sc->sc_ilen;
867 sc->sc_ilen = 0;
869 if (sc->sc_rawin_count > 0)
870 ppplogchar(sc, -1);
873 * If SC_ESCAPED is set, then we've seen the packet
874 * abort sequence "}~".
876 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
877 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
878 s = spltty();
879 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
880 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
881 if (sc->sc_flags & SC_DEBUG)
882 printf("ppp%d: bad fcs %x, pkt len %d\n",
883 sc->sc_if.if_unit, sc->sc_fcs, ilen);
884 sc->sc_if.if_ierrors++;
885 sc->sc_stats.ppp_ierrors++;
886 } else
887 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
888 splx(s);
889 return 0;
892 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
893 if (ilen) {
894 if (sc->sc_flags & SC_DEBUG)
895 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
896 s = spltty();
897 sc->sc_if.if_ierrors++;
898 sc->sc_stats.ppp_ierrors++;
899 sc->sc_flags |= SC_PKTLOST;
900 splx(s);
902 return 0;
906 * Remove FCS trailer. Somewhat painful...
908 ilen -= 2;
909 if (--sc->sc_mc->m_len == 0) {
910 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
912 sc->sc_mc = m;
914 sc->sc_mc->m_len--;
916 /* excise this mbuf chain */
917 m = sc->sc_m;
918 sc->sc_m = sc->sc_mc->m_next;
919 sc->sc_mc->m_next = NULL;
921 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
922 if (sc->sc_flags & SC_PKTLOST) {
923 s = spltty();
924 sc->sc_flags &= ~SC_PKTLOST;
925 splx(s);
928 pppgetm(sc);
929 return 0;
932 if (sc->sc_flags & SC_FLUSH) {
933 if (sc->sc_flags & SC_LOG_FLUSH)
934 ppplogchar(sc, c);
935 return 0;
938 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
939 return 0;
941 s = spltty();
942 if (sc->sc_flags & SC_ESCAPED) {
943 sc->sc_flags &= ~SC_ESCAPED;
944 c ^= PPP_TRANS;
945 } else if (c == PPP_ESCAPE) {
946 sc->sc_flags |= SC_ESCAPED;
947 splx(s);
948 return 0;
950 splx(s);
953 * Initialize buffer on first octet received.
954 * First octet could be address or protocol (when compressing
955 * address/control).
956 * Second octet is control.
957 * Third octet is first or second (when compressing protocol)
958 * octet of protocol.
959 * Fourth octet is second octet of protocol.
961 if (sc->sc_ilen == 0) {
962 /* reset the first input mbuf */
963 if (sc->sc_m == NULL) {
964 pppgetm(sc);
965 if (sc->sc_m == NULL) {
966 if (sc->sc_flags & SC_DEBUG)
967 printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
968 goto flush;
971 m = sc->sc_m;
972 m->m_len = 0;
973 m->m_data = M_DATASTART(sc->sc_m);
974 sc->sc_mc = m;
975 sc->sc_mp = mtod(m, char *);
976 sc->sc_fcs = PPP_INITFCS;
977 if (c != PPP_ALLSTATIONS) {
978 if (sc->sc_flags & SC_REJ_COMP_AC) {
979 if (sc->sc_flags & SC_DEBUG)
980 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
981 sc->sc_if.if_unit, c);
982 goto flush;
984 *sc->sc_mp++ = PPP_ALLSTATIONS;
985 *sc->sc_mp++ = PPP_UI;
986 sc->sc_ilen += 2;
987 m->m_len += 2;
990 if (sc->sc_ilen == 1 && c != PPP_UI) {
991 if (sc->sc_flags & SC_DEBUG)
992 printf("ppp%d: missing UI (0x3), got 0x%x\n",
993 sc->sc_if.if_unit, c);
994 goto flush;
996 if (sc->sc_ilen == 2 && (c & 1) == 1) {
997 /* a compressed protocol */
998 *sc->sc_mp++ = 0;
999 sc->sc_ilen++;
1000 sc->sc_mc->m_len++;
1002 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1003 if (sc->sc_flags & SC_DEBUG)
1004 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1005 (sc->sc_mp[-1] << 8) + c);
1006 goto flush;
1009 /* packet beyond configured mru? */
1010 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1011 if (sc->sc_flags & SC_DEBUG)
1012 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
1013 goto flush;
1016 /* is this mbuf full? */
1017 m = sc->sc_mc;
1018 if (M_TRAILINGSPACE(m) <= 0) {
1019 if (m->m_next == NULL) {
1020 pppgetm(sc);
1021 if (m->m_next == NULL) {
1022 if (sc->sc_flags & SC_DEBUG)
1023 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1024 goto flush;
1027 sc->sc_mc = m = m->m_next;
1028 m->m_len = 0;
1029 m->m_data = M_DATASTART(m);
1030 sc->sc_mp = mtod(m, char *);
1033 ++m->m_len;
1034 *sc->sc_mp++ = c;
1035 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1036 return 0;
1038 flush:
1039 if (!(sc->sc_flags & SC_FLUSH)) {
1040 s = spltty();
1041 sc->sc_if.if_ierrors++;
1042 sc->sc_stats.ppp_ierrors++;
1043 sc->sc_flags |= SC_FLUSH;
1044 splx(s);
1045 if (sc->sc_flags & SC_LOG_FLUSH)
1046 ppplogchar(sc, c);
1048 return 0;
1051 #define MAX_DUMP_BYTES 128
1053 static void
1054 ppplogchar(sc, c)
1055 struct ppp_softc *sc;
1056 int c;
1058 if (c >= 0)
1059 sc->sc_rawin[sc->sc_rawin_count++] = c;
1060 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1061 || (c < 0 && sc->sc_rawin_count > 0)) {
1062 printf("ppp%d input: ", sc->sc_if.if_unit);
1063 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1064 sc->sc_rawin_count = 0;
1068 static void
1069 pppdumpb(b, l)
1070 u_char *b;
1071 int l;
1073 char buf[3*MAX_DUMP_BYTES+4];
1074 char *bp = buf;
1075 static char digits[] = "0123456789abcdef";
1077 while (l--) {
1078 if (bp >= buf + sizeof(buf) - 3) {
1079 *bp++ = '>';
1080 break;
1082 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1083 *bp++ = digits[*b++ & 0xf];
1084 *bp++ = ' ';
1087 *bp = 0;
1088 printf("%s\n", buf);
1091 #endif /* NPPP > 0 */