Updates to help it compile with glibc 2
[mpls-ppp.git] / netbsd-1.2 / ppp_tty.c
blob5596a4c0b9060215eae31284a8bf808e1b9cdfe4
1 /* $NetBSD: ppp_tty.c,v 1.12 1997/03/24 21:23:10 christos 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) 1989 Carnegie Mellon University.
9 * All rights reserved.
11 * Redistribution and use in source and binary forms are permitted
12 * provided that the above copyright notice and this paragraph are
13 * duplicated in all such forms and that any documentation,
14 * advertising materials, and other materials related to such
15 * distribution and use acknowledge that the software was developed
16 * by Carnegie Mellon University. The name of the
17 * University may not be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * Drew D. Perkins
24 * Carnegie Mellon University
25 * 4910 Forbes Ave.
26 * Pittsburgh, PA 15213
27 * (412) 268-8576
28 * ddp@andrew.cmu.edu
30 * Based on:
31 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
33 * Copyright (c) 1987 Regents of the University of California.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms are permitted
37 * provided that the above copyright notice and this paragraph are
38 * duplicated in all such forms and that any documentation,
39 * advertising materials, and other materials related to such
40 * distribution and use acknowledge that the software was developed
41 * by the University of California, Berkeley. The name of the
42 * University may not be used to endorse or promote products derived
43 * from this software without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
45 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
46 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
48 * Serial Line interface
50 * Rick Adams
51 * Center for Seismic Studies
52 * 1300 N 17th Street, Suite 1450
53 * Arlington, Virginia 22209
54 * (703)276-7900
55 * rick@seismo.ARPA
56 * seismo!rick
58 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
59 * Converted to 4.3BSD Beta by Chris Torek.
60 * Other changes made at Berkeley, based in part on code by Kirk Smith.
62 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
63 * Added VJ tcp header compression; more unified ioctls
65 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
66 * Cleaned up a lot of the mbuf-related code to fix bugs that
67 * caused system crashes and packet corruption. Changed pppstart
68 * so that it doesn't just give up with a "collision" if the whole
69 * packet doesn't fit in the output ring buffer.
71 * Added priority queueing for interactive IP packets, following
72 * the model of if_sl.c, plus hooks for bpf.
73 * Paul Mackerras (paulus@cs.anu.edu.au).
76 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
77 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
79 #include "ppp.h"
80 #if NPPP > 0
82 #define VJC
83 #define PPP_COMPRESS
85 #include <sys/param.h>
86 #include <sys/proc.h>
87 #include <sys/mbuf.h>
88 #include <sys/dkstat.h>
89 #include <sys/socket.h>
90 #include <sys/ioctl.h>
91 #include <sys/file.h>
92 #include <sys/tty.h>
93 #include <sys/kernel.h>
94 #include <sys/conf.h>
95 #include <sys/vnode.h>
96 #include <sys/systm.h>
98 #include <net/if.h>
99 #include <net/if_types.h>
101 #ifdef VJC
102 #include <netinet/in.h>
103 #include <netinet/in_systm.h>
104 #include <netinet/ip.h>
105 #include <net/slcompress.h>
106 #endif
108 #ifdef PPP_FILTER
109 #include <net/bpf.h>
110 #endif
111 #include <net/ppp_defs.h>
112 #include <net/if_ppp.h>
113 #include <net/if_pppvar.h>
115 int pppopen __P((dev_t dev, struct tty *tp));
116 int pppclose __P((struct tty *tp, int flag));
117 int pppread __P((struct tty *tp, struct uio *uio, int flag));
118 int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
119 int ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag,
120 struct proc *));
121 int pppinput __P((int c, struct tty *tp));
122 int pppstart __P((struct tty *tp, int));
124 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
125 static void pppasyncstart __P((struct ppp_softc *));
126 static void pppasyncctlp __P((struct ppp_softc *));
127 static void pppasyncrelinq __P((struct ppp_softc *));
128 static void ppp_timeout __P((void *));
129 static void pppgetm __P((struct ppp_softc *sc));
130 static void pppdumpb __P((u_char *b, int l));
131 static void ppplogchar __P((struct ppp_softc *, int));
134 * Some useful mbuf macros not in mbuf.h.
136 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
138 #define M_DATASTART(m) \
139 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
140 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
142 #define M_DATASIZE(m) \
143 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
144 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
147 * Does c need to be escaped?
149 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
152 * Procedures for using an async tty interface for PPP.
155 /* This is a NetBSD-1.0 or later kernel. */
156 #define CCOUNT(q) ((q)->c_cc)
158 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
159 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
162 * Line specific open routine for async tty devices.
163 * Attach the given tty to the first available ppp unit.
164 * Called from device open routine or ttioctl.
166 /* ARGSUSED */
168 pppopen(dev, tp)
169 dev_t dev;
170 register struct tty *tp;
172 struct proc *p = curproc; /* XXX */
173 register struct ppp_softc *sc;
174 int error, s;
176 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
177 return (error);
179 s = spltty();
181 if (tp->t_line == PPPDISC) {
182 sc = (struct ppp_softc *) tp->t_sc;
183 if (sc != NULL && sc->sc_devp == (void *) tp) {
184 splx(s);
185 return (0);
189 if ((sc = pppalloc(p->p_pid)) == NULL) {
190 splx(s);
191 return ENXIO;
194 if (sc->sc_relinq)
195 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
197 sc->sc_ilen = 0;
198 sc->sc_m = NULL;
199 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
200 sc->sc_asyncmap[0] = 0xffffffff;
201 sc->sc_asyncmap[3] = 0x60000000;
202 sc->sc_rasyncmap = 0;
203 sc->sc_devp = (void *) tp;
204 sc->sc_start = pppasyncstart;
205 sc->sc_ctlp = pppasyncctlp;
206 sc->sc_relinq = pppasyncrelinq;
207 sc->sc_outm = NULL;
208 pppgetm(sc);
209 sc->sc_if.if_flags |= IFF_RUNNING;
210 sc->sc_if.if_baudrate = tp->t_ospeed;
212 tp->t_sc = (caddr_t) sc;
213 ttyflush(tp, FREAD | FWRITE);
215 splx(s);
216 return (0);
220 * Line specific close routine, called from device close routine
221 * and from ttioctl.
222 * Detach the tty from the ppp unit.
223 * Mimics part of ttyclose().
226 pppclose(tp, flag)
227 struct tty *tp;
228 int flag;
230 register struct ppp_softc *sc;
231 int s;
233 s = spltty();
234 ttyflush(tp, FREAD|FWRITE);
235 tp->t_line = 0;
236 sc = (struct ppp_softc *) tp->t_sc;
237 if (sc != NULL) {
238 tp->t_sc = NULL;
239 if (tp == (struct tty *) sc->sc_devp) {
240 pppasyncrelinq(sc);
241 pppdealloc(sc);
244 splx(s);
245 return 0;
249 * Relinquish the interface unit to another device.
251 static void
252 pppasyncrelinq(sc)
253 struct ppp_softc *sc;
255 int s;
257 s = spltty();
258 if (sc->sc_outm) {
259 m_freem(sc->sc_outm);
260 sc->sc_outm = NULL;
262 if (sc->sc_m) {
263 m_freem(sc->sc_m);
264 sc->sc_m = NULL;
266 if (sc->sc_flags & SC_TIMEOUT) {
267 untimeout(ppp_timeout, (void *) sc);
268 sc->sc_flags &= ~SC_TIMEOUT;
270 splx(s);
274 * Line specific (tty) read routine.
277 pppread(tp, uio, flag)
278 register struct tty *tp;
279 struct uio *uio;
280 int flag;
282 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
283 struct mbuf *m, *m0;
284 register int s;
285 int error = 0;
287 if (sc == NULL)
288 return 0;
290 * Loop waiting for input, checking that nothing disasterous
291 * happens in the meantime.
293 s = spltty();
294 for (;;) {
295 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
296 splx(s);
297 return 0;
299 if (sc->sc_inq.ifq_head != NULL)
300 break;
301 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
302 && (tp->t_state & TS_ISOPEN)) {
303 splx(s);
304 return 0; /* end of file */
306 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
307 splx(s);
308 return (EWOULDBLOCK);
310 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
311 if (error) {
312 splx(s);
313 return error;
317 /* Pull place-holder byte out of canonical queue */
318 getc(&tp->t_canq);
320 /* Get the packet from the input queue */
321 IF_DEQUEUE(&sc->sc_inq, m0);
322 splx(s);
324 for (m = m0; m && uio->uio_resid; m = m->m_next)
325 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
326 break;
327 m_freem(m0);
328 return (error);
332 * Line specific (tty) write routine.
335 pppwrite(tp, uio, flag)
336 register struct tty *tp;
337 struct uio *uio;
338 int flag;
340 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
341 struct mbuf *m, *m0, **mp;
342 struct sockaddr dst;
343 int len, error;
345 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
346 return 0; /* wrote 0 bytes */
347 if (tp->t_line != PPPDISC)
348 return (EINVAL);
349 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
350 return EIO;
351 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
352 uio->uio_resid < PPP_HDRLEN)
353 return (EMSGSIZE);
354 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
355 MGET(m, M_WAIT, MT_DATA);
356 if ((*mp = m) == NULL) {
357 m_freem(m0);
358 return (ENOBUFS);
360 m->m_len = 0;
361 if (uio->uio_resid >= MCLBYTES / 2)
362 MCLGET(m, M_DONTWAIT);
363 len = M_TRAILINGSPACE(m);
364 if (len > uio->uio_resid)
365 len = uio->uio_resid;
366 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
367 m_freem(m0);
368 return (error);
370 m->m_len = len;
372 dst.sa_family = AF_UNSPEC;
373 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
374 m0->m_data += PPP_HDRLEN;
375 m0->m_len -= PPP_HDRLEN;
376 return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
380 * Line specific (tty) ioctl routine.
381 * This discipline requires that tty device drivers call
382 * the line specific l_ioctl routine from their ioctl routines.
384 /* ARGSUSED */
386 ppptioctl(tp, cmd, data, flag, p)
387 struct tty *tp;
388 u_long cmd;
389 caddr_t data;
390 int flag;
391 struct proc *p;
393 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
394 int error, s;
396 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
397 return -1;
399 error = 0;
400 switch (cmd) {
401 case PPPIOCSASYNCMAP:
402 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
403 break;
404 sc->sc_asyncmap[0] = *(u_int *)data;
405 break;
407 case PPPIOCGASYNCMAP:
408 *(u_int *)data = sc->sc_asyncmap[0];
409 break;
411 case PPPIOCSRASYNCMAP:
412 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
413 break;
414 sc->sc_rasyncmap = *(u_int *)data;
415 break;
417 case PPPIOCGRASYNCMAP:
418 *(u_int *)data = sc->sc_rasyncmap;
419 break;
421 case PPPIOCSXASYNCMAP:
422 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
423 break;
424 s = spltty();
425 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
426 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
427 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
428 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
429 splx(s);
430 break;
432 case PPPIOCGXASYNCMAP:
433 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
434 break;
436 default:
437 error = pppioctl(sc, cmd, data, flag, p);
438 if (error == 0 && cmd == PPPIOCSMRU)
439 pppgetm(sc);
442 return error;
446 * FCS lookup table as calculated by genfcstab.
448 static u_int16_t fcstab[256] = {
449 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
450 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
451 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
452 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
453 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
454 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
455 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
456 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
457 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
458 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
459 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
460 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
461 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
462 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
463 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
464 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
465 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
466 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
467 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
468 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
469 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
470 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
471 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
472 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
473 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
474 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
475 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
476 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
477 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
478 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
479 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
480 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
484 * Calculate a new FCS given the current FCS and the new data.
486 static u_int16_t
487 pppfcs(fcs, cp, len)
488 register u_int16_t fcs;
489 register u_char *cp;
490 register int len;
492 while (len--)
493 fcs = PPP_FCS(fcs, *cp++);
494 return (fcs);
498 * This gets called at splsoftnet from if_ppp.c at various times
499 * when there is data ready to be sent.
501 static void
502 pppasyncstart(sc)
503 register struct ppp_softc *sc;
505 register struct tty *tp = (struct tty *) sc->sc_devp;
506 register struct mbuf *m;
507 register int len;
508 register u_char *start, *stop, *cp;
509 int n, ndone, done, idle;
510 struct mbuf *m2;
511 int s;
513 idle = 0;
514 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
516 * See if we have an existing packet partly sent.
517 * If not, get a new packet and start sending it.
519 m = sc->sc_outm;
520 if (m == NULL) {
522 * Get another packet to be sent.
524 m = ppp_dequeue(sc);
525 if (m == NULL) {
526 idle = 1;
527 break;
531 * The extra PPP_FLAG will start up a new packet, and thus
532 * will flush any accumulated garbage. We do this whenever
533 * the line may have been idle for some time.
535 if (CCOUNT(&tp->t_outq) == 0) {
536 ++sc->sc_stats.ppp_obytes;
537 (void) putc(PPP_FLAG, &tp->t_outq);
540 /* Calculate the FCS for the first mbuf's worth. */
541 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
542 sc->sc_if.if_lastchange = time;
545 for (;;) {
546 start = mtod(m, u_char *);
547 len = m->m_len;
548 stop = start + len;
549 while (len > 0) {
551 * Find out how many bytes in the string we can
552 * handle without doing something special.
554 for (cp = start; cp < stop; cp++)
555 if (ESCAPE_P(*cp))
556 break;
557 n = cp - start;
558 if (n) {
559 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
560 ndone = n - b_to_q(start, n, &tp->t_outq);
561 len -= ndone;
562 start += ndone;
563 sc->sc_stats.ppp_obytes += ndone;
565 if (ndone < n)
566 break; /* packet doesn't fit */
569 * If there are characters left in the mbuf,
570 * the first one must be special.
571 * Put it out in a different form.
573 if (len) {
574 s = spltty();
575 if (putc(PPP_ESCAPE, &tp->t_outq)) {
576 splx(s);
577 break;
579 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
580 (void) unputc(&tp->t_outq);
581 splx(s);
582 break;
584 splx(s);
585 sc->sc_stats.ppp_obytes += 2;
586 start++;
587 len--;
592 * If we didn't empty this mbuf, remember where we're up to.
593 * If we emptied the last mbuf, try to add the FCS and closing
594 * flag, and if we can't, leave sc_outm pointing to m, but with
595 * m->m_len == 0, to remind us to output the FCS and flag later.
597 done = len == 0;
598 if (done && m->m_next == NULL) {
599 u_char *p, *q;
600 int c;
601 u_char endseq[8];
604 * We may have to escape the bytes in the FCS.
606 p = endseq;
607 c = ~sc->sc_outfcs & 0xFF;
608 if (ESCAPE_P(c)) {
609 *p++ = PPP_ESCAPE;
610 *p++ = c ^ PPP_TRANS;
611 } else
612 *p++ = c;
613 c = (~sc->sc_outfcs >> 8) & 0xFF;
614 if (ESCAPE_P(c)) {
615 *p++ = PPP_ESCAPE;
616 *p++ = c ^ PPP_TRANS;
617 } else
618 *p++ = c;
619 *p++ = PPP_FLAG;
622 * Try to output the FCS and flag. If the bytes
623 * don't all fit, back out.
625 s = spltty();
626 for (q = endseq; q < p; ++q)
627 if (putc(*q, &tp->t_outq)) {
628 done = 0;
629 for (; q > endseq; --q)
630 unputc(&tp->t_outq);
631 break;
633 splx(s);
634 if (done)
635 sc->sc_stats.ppp_obytes += q - endseq;
638 if (!done) {
639 /* remember where we got to */
640 m->m_data = start;
641 m->m_len = len;
642 break;
645 /* Finished with this mbuf; free it and move on. */
646 MFREE(m, m2);
647 m = m2;
648 if (m == NULL) {
649 /* Finished a packet */
650 break;
652 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
656 * If m == NULL, we have finished a packet.
657 * If m != NULL, we've either done as much work this time
658 * as we need to, or else we've filled up the output queue.
660 sc->sc_outm = m;
661 if (m)
662 break;
665 /* Call pppstart to start output again if necessary. */
666 s = spltty();
667 pppstart(tp, 0);
670 * This timeout is needed for operation on a pseudo-tty,
671 * because the pty code doesn't call pppstart after it has
672 * drained the t_outq.
674 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
675 timeout(ppp_timeout, (void *) sc, 1);
676 sc->sc_flags |= SC_TIMEOUT;
679 splx(s);
683 * This gets called when a received packet is placed on
684 * the inq, at splsoftnet.
686 static void
687 pppasyncctlp(sc)
688 struct ppp_softc *sc;
690 struct tty *tp;
691 int s;
693 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
694 s = spltty();
695 tp = (struct tty *) sc->sc_devp;
696 putc(0, &tp->t_canq);
697 ttwakeup(tp);
698 splx(s);
702 * Start output on async tty interface. If the transmit queue
703 * has drained sufficiently, arrange for pppasyncstart to be
704 * called later at splsoftnet.
705 * Called at spltty or higher.
708 pppstart(tp, force)
709 register struct tty *tp;
710 int force;
712 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
715 * If there is stuff in the output queue, send it now.
716 * We are being called in lieu of ttstart and must do what it would.
718 if (tp->t_oproc != NULL)
719 (*tp->t_oproc)(tp);
722 * If the transmit queue has drained and the tty has not hung up
723 * or been disconnected from the ppp unit, then tell if_ppp.c that
724 * we need more output.
726 if (CCOUNT(&tp->t_outq) >= PPP_LOWAT && !force)
727 return 0;
728 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
729 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
730 ppp_restart(sc);
733 return 0;
737 * Timeout routine - try to start some more output.
739 static void
740 ppp_timeout(x)
741 void *x;
743 struct ppp_softc *sc = (struct ppp_softc *) x;
744 struct tty *tp = (struct tty *) sc->sc_devp;
745 int s;
747 s = spltty();
748 sc->sc_flags &= ~SC_TIMEOUT;
749 pppstart(tp, 1);
750 splx(s);
754 * Allocate enough mbuf to handle current MRU.
756 static void
757 pppgetm(sc)
758 register struct ppp_softc *sc;
760 struct mbuf *m, **mp;
761 int len;
763 mp = &sc->sc_m;
764 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
765 if ((m = *mp) == NULL) {
766 MGETHDR(m, M_DONTWAIT, MT_DATA);
767 if (m == NULL)
768 break;
769 *mp = m;
770 MCLGET(m, M_DONTWAIT);
772 len -= M_DATASIZE(m);
773 mp = &m->m_next;
778 * tty interface receiver interrupt.
780 static unsigned paritytab[8] = {
781 0x96696996, 0x69969669, 0x69969669, 0x96696996,
782 0x69969669, 0x96696996, 0x96696996, 0x69969669
786 pppinput(c, tp)
787 int c;
788 register struct tty *tp;
790 register struct ppp_softc *sc;
791 struct mbuf *m;
792 int ilen, s;
794 sc = (struct ppp_softc *) tp->t_sc;
795 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
796 return 0;
798 ++tk_nin;
799 ++sc->sc_stats.ppp_ibytes;
801 if (c & TTY_FE) {
802 /* framing error or overrun on this char - abort packet */
803 if (sc->sc_flags & SC_DEBUG)
804 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
805 goto flush;
808 c &= 0xff;
811 * Handle software flow control of output.
813 if (tp->t_iflag & IXON) {
814 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
815 if ((tp->t_state & TS_TTSTOP) == 0) {
816 tp->t_state |= TS_TTSTOP;
817 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
819 return 0;
821 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
822 tp->t_state &= ~TS_TTSTOP;
823 if (tp->t_oproc != NULL)
824 (*tp->t_oproc)(tp);
825 return 0;
829 s = spltty();
830 if (c & 0x80)
831 sc->sc_flags |= SC_RCV_B7_1;
832 else
833 sc->sc_flags |= SC_RCV_B7_0;
834 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
835 sc->sc_flags |= SC_RCV_ODDP;
836 else
837 sc->sc_flags |= SC_RCV_EVNP;
838 splx(s);
840 if (sc->sc_flags & SC_LOG_RAWIN)
841 ppplogchar(sc, c);
843 if (c == PPP_FLAG) {
844 ilen = sc->sc_ilen;
845 sc->sc_ilen = 0;
847 if (sc->sc_rawin_count > 0)
848 ppplogchar(sc, -1);
851 * If SC_ESCAPED is set, then we've seen the packet
852 * abort sequence "}~".
854 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
855 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
856 s = spltty();
857 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
858 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
859 if (sc->sc_flags & SC_DEBUG)
860 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
861 sc->sc_fcs);
862 sc->sc_if.if_ierrors++;
863 sc->sc_stats.ppp_ierrors++;
864 } else
865 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
866 splx(s);
867 return 0;
870 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
871 if (ilen) {
872 if (sc->sc_flags & SC_DEBUG)
873 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
874 s = spltty();
875 sc->sc_if.if_ierrors++;
876 sc->sc_stats.ppp_ierrors++;
877 sc->sc_flags |= SC_PKTLOST;
878 splx(s);
880 return 0;
884 * Remove FCS trailer. Somewhat painful...
886 ilen -= 2;
887 if (--sc->sc_mc->m_len == 0) {
888 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
890 sc->sc_mc = m;
892 sc->sc_mc->m_len--;
894 /* excise this mbuf chain */
895 m = sc->sc_m;
896 sc->sc_m = sc->sc_mc->m_next;
897 sc->sc_mc->m_next = NULL;
899 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
900 if (sc->sc_flags & SC_PKTLOST) {
901 s = spltty();
902 sc->sc_flags &= ~SC_PKTLOST;
903 splx(s);
906 pppgetm(sc);
907 return 0;
910 if (sc->sc_flags & SC_FLUSH) {
911 if (sc->sc_flags & SC_LOG_FLUSH)
912 ppplogchar(sc, c);
913 return 0;
916 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
917 return 0;
919 s = spltty();
920 if (sc->sc_flags & SC_ESCAPED) {
921 sc->sc_flags &= ~SC_ESCAPED;
922 c ^= PPP_TRANS;
923 } else if (c == PPP_ESCAPE) {
924 sc->sc_flags |= SC_ESCAPED;
925 splx(s);
926 return 0;
928 splx(s);
931 * Initialize buffer on first octet received.
932 * First octet could be address or protocol (when compressing
933 * address/control).
934 * Second octet is control.
935 * Third octet is first or second (when compressing protocol)
936 * octet of protocol.
937 * Fourth octet is second octet of protocol.
939 if (sc->sc_ilen == 0) {
940 /* reset the first input mbuf */
941 if (sc->sc_m == NULL) {
942 pppgetm(sc);
943 if (sc->sc_m == NULL) {
944 if (sc->sc_flags & SC_DEBUG)
945 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
946 goto flush;
949 m = sc->sc_m;
950 m->m_len = 0;
951 m->m_data = M_DATASTART(sc->sc_m);
952 sc->sc_mc = m;
953 sc->sc_mp = mtod(m, char *);
954 sc->sc_fcs = PPP_INITFCS;
955 if (c != PPP_ALLSTATIONS) {
956 if (sc->sc_flags & SC_REJ_COMP_AC) {
957 if (sc->sc_flags & SC_DEBUG)
958 printf("%s: garbage received: 0x%x (need 0xFF)\n",
959 sc->sc_if.if_xname, c);
960 goto flush;
962 *sc->sc_mp++ = PPP_ALLSTATIONS;
963 *sc->sc_mp++ = PPP_UI;
964 sc->sc_ilen += 2;
965 m->m_len += 2;
968 if (sc->sc_ilen == 1 && c != PPP_UI) {
969 if (sc->sc_flags & SC_DEBUG)
970 printf("%s: missing UI (0x3), got 0x%x\n",
971 sc->sc_if.if_xname, c);
972 goto flush;
974 if (sc->sc_ilen == 2 && (c & 1) == 1) {
975 /* a compressed protocol */
976 *sc->sc_mp++ = 0;
977 sc->sc_ilen++;
978 sc->sc_mc->m_len++;
980 if (sc->sc_ilen == 3 && (c & 1) == 0) {
981 if (sc->sc_flags & SC_DEBUG)
982 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
983 (sc->sc_mp[-1] << 8) + c);
984 goto flush;
987 /* packet beyond configured mru? */
988 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
989 if (sc->sc_flags & SC_DEBUG)
990 printf("%s: packet too big\n", sc->sc_if.if_xname);
991 goto flush;
994 /* is this mbuf full? */
995 m = sc->sc_mc;
996 if (M_TRAILINGSPACE(m) <= 0) {
997 if (m->m_next == NULL) {
998 pppgetm(sc);
999 if (m->m_next == NULL) {
1000 if (sc->sc_flags & SC_DEBUG)
1001 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1002 goto flush;
1005 sc->sc_mc = m = m->m_next;
1006 m->m_len = 0;
1007 m->m_data = M_DATASTART(m);
1008 sc->sc_mp = mtod(m, char *);
1011 ++m->m_len;
1012 *sc->sc_mp++ = c;
1013 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1014 return 0;
1016 flush:
1017 if (!(sc->sc_flags & SC_FLUSH)) {
1018 s = spltty();
1019 sc->sc_if.if_ierrors++;
1020 sc->sc_stats.ppp_ierrors++;
1021 sc->sc_flags |= SC_FLUSH;
1022 splx(s);
1023 if (sc->sc_flags & SC_LOG_FLUSH)
1024 ppplogchar(sc, c);
1026 return 0;
1029 #define MAX_DUMP_BYTES 128
1031 static void
1032 ppplogchar(sc, c)
1033 struct ppp_softc *sc;
1034 int c;
1036 if (c >= 0)
1037 sc->sc_rawin[sc->sc_rawin_count++] = c;
1038 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1039 || (c < 0 && sc->sc_rawin_count > 0)) {
1040 printf("%s input: ", sc->sc_if.if_xname);
1041 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1042 sc->sc_rawin_count = 0;
1046 static void
1047 pppdumpb(b, l)
1048 u_char *b;
1049 int l;
1051 char buf[3*MAX_DUMP_BYTES+4];
1052 char *bp = buf;
1053 static char digits[] = "0123456789abcdef";
1055 while (l--) {
1056 if (bp >= buf + sizeof(buf) - 3) {
1057 *bp++ = '>';
1058 break;
1060 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1061 *bp++ = digits[*b++ & 0xf];
1062 *bp++ = ' ';
1065 *bp = 0;
1066 printf("%s\n", buf);
1069 #endif /* NPPP > 0 */