fix strtok loop
[mpls-ppp.git] / netbsd-1.1 / ppp_tty.c
blobc7cd9107327d593893e52c1a64ccecd350b74159
1 /* $Id: ppp_tty.c,v 1.4 1997/04/30 05:47:38 paulus Exp $ */
3 /*
4 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
5 * tty devices.
7 * Copyright (c) 1989 Carnegie Mellon University.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by Carnegie Mellon University. The name of the
16 * University may not be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 * Drew D. Perkins
23 * Carnegie Mellon University
24 * 4910 Forbes Ave.
25 * Pittsburgh, PA 15213
26 * (412) 268-8576
27 * ddp@andrew.cmu.edu
29 * Based on:
30 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
32 * Copyright (c) 1987 Regents of the University of California.
33 * All rights reserved.
35 * Redistribution and use in source and binary forms are permitted
36 * provided that the above copyright notice and this paragraph are
37 * duplicated in all such forms and that any documentation,
38 * advertising materials, and other materials related to such
39 * distribution and use acknowledge that the software was developed
40 * by the University of California, Berkeley. The name of the
41 * University may not be used to endorse or promote products derived
42 * from this software without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
47 * Serial Line interface
49 * Rick Adams
50 * Center for Seismic Studies
51 * 1300 N 17th Street, Suite 1450
52 * Arlington, Virginia 22209
53 * (703)276-7900
54 * rick@seismo.ARPA
55 * seismo!rick
57 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
58 * Converted to 4.3BSD Beta by Chris Torek.
59 * Other changes made at Berkeley, based in part on code by Kirk Smith.
61 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
62 * Added VJ tcp header compression; more unified ioctls
64 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
65 * Cleaned up a lot of the mbuf-related code to fix bugs that
66 * caused system crashes and packet corruption. Changed pppstart
67 * so that it doesn't just give up with a "collision" if the whole
68 * packet doesn't fit in the output ring buffer.
70 * Added priority queueing for interactive IP packets, following
71 * the model of if_sl.c, plus hooks for bpf.
72 * Paul Mackerras (paulus@cs.anu.edu.au).
75 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
76 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
78 #include "ppp.h"
79 #if NPPP > 0
81 #define VJC
82 #define PPP_COMPRESS
84 #include <sys/param.h>
85 #include <sys/proc.h>
86 #include <sys/mbuf.h>
87 #include <sys/dkstat.h>
88 #include <sys/socket.h>
89 #include <sys/ioctl.h>
90 #include <sys/file.h>
91 #include <sys/tty.h>
92 #include <sys/kernel.h>
93 #include <sys/conf.h>
94 #include <sys/vnode.h>
95 #include <sys/systm.h>
97 #include <net/if.h>
98 #include <net/if_types.h>
100 #ifdef VJC
101 #include <netinet/in.h>
102 #include <netinet/in_systm.h>
103 #include <netinet/ip.h>
104 #include <net/slcompress.h>
105 #endif
107 #ifdef PPP_FILTER
108 #include <net/bpf.h>
109 #endif
110 #include <net/ppp_defs.h>
111 #include <net/if_ppp.h>
112 #include <net/if_pppvar.h>
114 int pppopen __P((dev_t dev, struct tty *tp));
115 int pppclose __P((struct tty *tp, int flag));
116 int pppread __P((struct tty *tp, struct uio *uio, int flag));
117 int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
118 int ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag,
119 struct proc *));
120 int pppinput __P((int c, struct tty *tp));
121 int pppstart __P((struct tty *tp, int));
123 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
124 static void pppasyncstart __P((struct ppp_softc *));
125 static void pppasyncctlp __P((struct ppp_softc *));
126 static void pppasyncrelinq __P((struct ppp_softc *));
127 static void ppp_timeout __P((void *));
128 static void pppgetm __P((struct ppp_softc *sc));
129 static void pppdumpb __P((u_char *b, int l));
130 static void ppplogchar __P((struct ppp_softc *, int));
133 * Some useful mbuf macros not in mbuf.h.
135 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
137 #define M_DATASTART(m) \
138 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
139 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
141 #define M_DATASIZE(m) \
142 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
143 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
146 * Does c need to be escaped?
148 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
151 * Procedures for using an async tty interface for PPP.
154 /* This is a NetBSD-1.0 or later kernel. */
155 #define CCOUNT(q) ((q)->c_cc)
157 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
158 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
161 * Line specific open routine for async tty devices.
162 * Attach the given tty to the first available ppp unit.
163 * Called from device open routine or ttioctl.
165 /* ARGSUSED */
167 pppopen(dev, tp)
168 dev_t dev;
169 register struct tty *tp;
171 struct proc *p = curproc; /* XXX */
172 register struct ppp_softc *sc;
173 int error, s;
175 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
176 return (error);
178 s = spltty();
180 if (tp->t_line == PPPDISC) {
181 sc = (struct ppp_softc *) tp->t_sc;
182 if (sc != NULL && sc->sc_devp == (void *) tp) {
183 splx(s);
184 return (0);
188 if ((sc = pppalloc(p->p_pid)) == NULL) {
189 splx(s);
190 return ENXIO;
193 if (sc->sc_relinq)
194 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
196 sc->sc_ilen = 0;
197 sc->sc_m = NULL;
198 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
199 sc->sc_asyncmap[0] = 0xffffffff;
200 sc->sc_asyncmap[3] = 0x60000000;
201 sc->sc_rasyncmap = 0;
202 sc->sc_devp = (void *) tp;
203 sc->sc_start = pppasyncstart;
204 sc->sc_ctlp = pppasyncctlp;
205 sc->sc_relinq = pppasyncrelinq;
206 sc->sc_outm = NULL;
207 pppgetm(sc);
208 sc->sc_if.if_flags |= IFF_RUNNING;
209 sc->sc_if.if_baudrate = tp->t_ospeed;
211 tp->t_sc = (caddr_t) sc;
212 ttyflush(tp, FREAD | FWRITE);
214 splx(s);
215 return (0);
219 * Line specific close routine, called from device close routine
220 * and from ttioctl.
221 * Detach the tty from the ppp unit.
222 * Mimics part of ttyclose().
225 pppclose(tp, flag)
226 struct tty *tp;
227 int flag;
229 register struct ppp_softc *sc;
230 int s;
232 s = spltty();
233 ttyflush(tp, FREAD|FWRITE);
234 tp->t_line = 0;
235 sc = (struct ppp_softc *) tp->t_sc;
236 if (sc != NULL) {
237 tp->t_sc = NULL;
238 if (tp == (struct tty *) sc->sc_devp) {
239 pppasyncrelinq(sc);
240 pppdealloc(sc);
243 splx(s);
244 return 0;
248 * Relinquish the interface unit to another device.
250 static void
251 pppasyncrelinq(sc)
252 struct ppp_softc *sc;
254 int s;
256 s = spltty();
257 if (sc->sc_outm) {
258 m_freem(sc->sc_outm);
259 sc->sc_outm = NULL;
261 if (sc->sc_m) {
262 m_freem(sc->sc_m);
263 sc->sc_m = NULL;
265 if (sc->sc_flags & SC_TIMEOUT) {
266 untimeout(ppp_timeout, (void *) sc);
267 sc->sc_flags &= ~SC_TIMEOUT;
269 splx(s);
273 * Line specific (tty) read routine.
276 pppread(tp, uio, flag)
277 register struct tty *tp;
278 struct uio *uio;
279 int flag;
281 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
282 struct mbuf *m, *m0;
283 register int s;
284 int error = 0;
286 if (sc == NULL)
287 return 0;
289 * Loop waiting for input, checking that nothing disasterous
290 * happens in the meantime.
292 s = spltty();
293 for (;;) {
294 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
295 splx(s);
296 return 0;
298 if (sc->sc_inq.ifq_head != NULL)
299 break;
300 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
301 && (tp->t_state & TS_ISOPEN)) {
302 splx(s);
303 return 0; /* end of file */
305 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
306 splx(s);
307 return (EWOULDBLOCK);
309 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
310 if (error) {
311 splx(s);
312 return error;
316 /* Pull place-holder byte out of canonical queue */
317 getc(&tp->t_canq);
319 /* Get the packet from the input queue */
320 IF_DEQUEUE(&sc->sc_inq, m0);
321 splx(s);
323 for (m = m0; m && uio->uio_resid; m = m->m_next)
324 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
325 break;
326 m_freem(m0);
327 return (error);
331 * Line specific (tty) write routine.
334 pppwrite(tp, uio, flag)
335 register struct tty *tp;
336 struct uio *uio;
337 int flag;
339 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
340 struct mbuf *m, *m0, **mp;
341 struct sockaddr dst;
342 int len, error;
344 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
345 return 0; /* wrote 0 bytes */
346 if (tp->t_line != PPPDISC)
347 return (EINVAL);
348 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
349 return EIO;
350 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
351 uio->uio_resid < PPP_HDRLEN)
352 return (EMSGSIZE);
353 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
354 MGET(m, M_WAIT, MT_DATA);
355 if ((*mp = m) == NULL) {
356 m_freem(m0);
357 return (ENOBUFS);
359 m->m_len = 0;
360 if (uio->uio_resid >= MCLBYTES / 2)
361 MCLGET(m, M_DONTWAIT);
362 len = M_TRAILINGSPACE(m);
363 if (len > uio->uio_resid)
364 len = uio->uio_resid;
365 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
366 m_freem(m0);
367 return (error);
369 m->m_len = len;
371 dst.sa_family = AF_UNSPEC;
372 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
373 m0->m_data += PPP_HDRLEN;
374 m0->m_len -= PPP_HDRLEN;
375 return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
379 * Line specific (tty) ioctl routine.
380 * This discipline requires that tty device drivers call
381 * the line specific l_ioctl routine from their ioctl routines.
383 /* ARGSUSED */
385 ppptioctl(tp, cmd, data, flag, p)
386 struct tty *tp;
387 u_long cmd;
388 caddr_t data;
389 int flag;
390 struct proc *p;
392 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
393 int error, s;
395 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
396 return -1;
398 error = 0;
399 switch (cmd) {
400 case PPPIOCSASYNCMAP:
401 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
402 break;
403 sc->sc_asyncmap[0] = *(u_int *)data;
404 break;
406 case PPPIOCGASYNCMAP:
407 *(u_int *)data = sc->sc_asyncmap[0];
408 break;
410 case PPPIOCSRASYNCMAP:
411 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
412 break;
413 sc->sc_rasyncmap = *(u_int *)data;
414 break;
416 case PPPIOCGRASYNCMAP:
417 *(u_int *)data = sc->sc_rasyncmap;
418 break;
420 case PPPIOCSXASYNCMAP:
421 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
422 break;
423 s = spltty();
424 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
425 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
426 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
427 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
428 splx(s);
429 break;
431 case PPPIOCGXASYNCMAP:
432 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
433 break;
435 default:
436 error = pppioctl(sc, cmd, data, flag, p);
437 if (error == 0 && cmd == PPPIOCSMRU)
438 pppgetm(sc);
441 return error;
445 * FCS lookup table as calculated by genfcstab.
447 static u_int16_t fcstab[256] = {
448 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
449 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
450 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
451 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
452 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
453 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
454 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
455 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
456 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
457 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
458 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
459 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
460 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
461 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
462 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
463 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
464 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
465 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
466 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
467 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
468 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
469 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
470 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
471 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
472 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
473 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
474 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
475 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
476 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
477 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
478 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
479 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
483 * Calculate a new FCS given the current FCS and the new data.
485 static u_int16_t
486 pppfcs(fcs, cp, len)
487 register u_int16_t fcs;
488 register u_char *cp;
489 register int len;
491 while (len--)
492 fcs = PPP_FCS(fcs, *cp++);
493 return (fcs);
497 * This gets called at splsoftnet from if_ppp.c at various times
498 * when there is data ready to be sent.
500 static void
501 pppasyncstart(sc)
502 register struct ppp_softc *sc;
504 register struct tty *tp = (struct tty *) sc->sc_devp;
505 register struct mbuf *m;
506 register int len;
507 register u_char *start, *stop, *cp;
508 int n, ndone, done, idle;
509 struct mbuf *m2;
510 int s;
512 idle = 0;
513 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
515 * See if we have an existing packet partly sent.
516 * If not, get a new packet and start sending it.
518 m = sc->sc_outm;
519 if (m == NULL) {
521 * Get another packet to be sent.
523 m = ppp_dequeue(sc);
524 if (m == NULL) {
525 idle = 1;
526 break;
530 * The extra PPP_FLAG will start up a new packet, and thus
531 * will flush any accumulated garbage. We do this whenever
532 * the line may have been idle for some time.
534 if (CCOUNT(&tp->t_outq) == 0) {
535 ++sc->sc_stats.ppp_obytes;
536 (void) putc(PPP_FLAG, &tp->t_outq);
539 /* Calculate the FCS for the first mbuf's worth. */
540 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
541 sc->sc_if.if_lastchange = time;
544 for (;;) {
545 start = mtod(m, u_char *);
546 len = m->m_len;
547 stop = start + len;
548 while (len > 0) {
550 * Find out how many bytes in the string we can
551 * handle without doing something special.
553 for (cp = start; cp < stop; cp++)
554 if (ESCAPE_P(*cp))
555 break;
556 n = cp - start;
557 if (n) {
558 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
559 ndone = n - b_to_q(start, n, &tp->t_outq);
560 len -= ndone;
561 start += ndone;
562 sc->sc_stats.ppp_obytes += ndone;
564 if (ndone < n)
565 break; /* packet doesn't fit */
568 * If there are characters left in the mbuf,
569 * the first one must be special.
570 * Put it out in a different form.
572 if (len) {
573 s = spltty();
574 if (putc(PPP_ESCAPE, &tp->t_outq)) {
575 splx(s);
576 break;
578 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
579 (void) unputc(&tp->t_outq);
580 splx(s);
581 break;
583 splx(s);
584 sc->sc_stats.ppp_obytes += 2;
585 start++;
586 len--;
591 * If we didn't empty this mbuf, remember where we're up to.
592 * If we emptied the last mbuf, try to add the FCS and closing
593 * flag, and if we can't, leave sc_outm pointing to m, but with
594 * m->m_len == 0, to remind us to output the FCS and flag later.
596 done = len == 0;
597 if (done && m->m_next == NULL) {
598 u_char *p, *q;
599 int c;
600 u_char endseq[8];
603 * We may have to escape the bytes in the FCS.
605 p = endseq;
606 c = ~sc->sc_outfcs & 0xFF;
607 if (ESCAPE_P(c)) {
608 *p++ = PPP_ESCAPE;
609 *p++ = c ^ PPP_TRANS;
610 } else
611 *p++ = c;
612 c = (~sc->sc_outfcs >> 8) & 0xFF;
613 if (ESCAPE_P(c)) {
614 *p++ = PPP_ESCAPE;
615 *p++ = c ^ PPP_TRANS;
616 } else
617 *p++ = c;
618 *p++ = PPP_FLAG;
621 * Try to output the FCS and flag. If the bytes
622 * don't all fit, back out.
624 s = spltty();
625 for (q = endseq; q < p; ++q)
626 if (putc(*q, &tp->t_outq)) {
627 done = 0;
628 for (; q > endseq; --q)
629 unputc(&tp->t_outq);
630 break;
632 splx(s);
633 if (done)
634 sc->sc_stats.ppp_obytes += q - endseq;
637 if (!done) {
638 /* remember where we got to */
639 m->m_data = start;
640 m->m_len = len;
641 break;
644 /* Finished with this mbuf; free it and move on. */
645 MFREE(m, m2);
646 m = m2;
647 if (m == NULL) {
648 /* Finished a packet */
649 break;
651 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
655 * If m == NULL, we have finished a packet.
656 * If m != NULL, we've either done as much work this time
657 * as we need to, or else we've filled up the output queue.
659 sc->sc_outm = m;
660 if (m)
661 break;
664 /* Call pppstart to start output again if necessary. */
665 s = spltty();
666 pppstart(tp, 0);
669 * This timeout is needed for operation on a pseudo-tty,
670 * because the pty code doesn't call pppstart after it has
671 * drained the t_outq.
673 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
674 timeout(ppp_timeout, (void *) sc, 1);
675 sc->sc_flags |= SC_TIMEOUT;
678 splx(s);
682 * This gets called when a received packet is placed on
683 * the inq, at splsoftnet.
685 static void
686 pppasyncctlp(sc)
687 struct ppp_softc *sc;
689 struct tty *tp;
690 int s;
692 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
693 s = spltty();
694 tp = (struct tty *) sc->sc_devp;
695 putc(0, &tp->t_canq);
696 ttwakeup(tp);
697 splx(s);
701 * Start output on async tty interface. If the transmit queue
702 * has drained sufficiently, arrange for pppasyncstart to be
703 * called later at splsoftnet.
704 * Called at spltty or higher.
707 pppstart(tp, force)
708 register struct tty *tp;
709 int force;
711 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
714 * If there is stuff in the output queue, send it now.
715 * We are being called in lieu of ttstart and must do what it would.
717 if (tp->t_oproc != NULL)
718 (*tp->t_oproc)(tp);
721 * If the transmit queue has drained and the tty has not hung up
722 * or been disconnected from the ppp unit, then tell if_ppp.c that
723 * we need more output.
725 if (CCOUNT(&tp->t_outq) >= PPP_LOWAT && !force)
726 return 0;
727 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
728 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
729 ppp_restart(sc);
732 return 0;
736 * Timeout routine - try to start some more output.
738 static void
739 ppp_timeout(x)
740 void *x;
742 struct ppp_softc *sc = (struct ppp_softc *) x;
743 struct tty *tp = (struct tty *) sc->sc_devp;
744 int s;
746 s = spltty();
747 sc->sc_flags &= ~SC_TIMEOUT;
748 pppstart(tp, 1);
749 splx(s);
753 * Allocate enough mbuf to handle current MRU.
755 static void
756 pppgetm(sc)
757 register struct ppp_softc *sc;
759 struct mbuf *m, **mp;
760 int len;
762 mp = &sc->sc_m;
763 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
764 if ((m = *mp) == NULL) {
765 MGETHDR(m, M_DONTWAIT, MT_DATA);
766 if (m == NULL)
767 break;
768 *mp = m;
769 MCLGET(m, M_DONTWAIT);
771 len -= M_DATASIZE(m);
772 mp = &m->m_next;
777 * tty interface receiver interrupt.
779 static unsigned paritytab[8] = {
780 0x96696996, 0x69969669, 0x69969669, 0x96696996,
781 0x69969669, 0x96696996, 0x96696996, 0x69969669
785 pppinput(c, tp)
786 int c;
787 register struct tty *tp;
789 register struct ppp_softc *sc;
790 struct mbuf *m;
791 int ilen, s;
793 sc = (struct ppp_softc *) tp->t_sc;
794 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
795 return 0;
797 ++tk_nin;
798 ++sc->sc_stats.ppp_ibytes;
800 if (c & TTY_FE) {
801 /* framing error or overrun on this char - abort packet */
802 if (sc->sc_flags & SC_DEBUG)
803 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
804 goto flush;
807 c &= 0xff;
810 * Handle software flow control of output.
812 if (tp->t_iflag & IXON) {
813 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
814 if ((tp->t_state & TS_TTSTOP) == 0) {
815 tp->t_state |= TS_TTSTOP;
816 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
818 return 0;
820 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
821 tp->t_state &= ~TS_TTSTOP;
822 if (tp->t_oproc != NULL)
823 (*tp->t_oproc)(tp);
824 return 0;
828 s = spltty();
829 if (c & 0x80)
830 sc->sc_flags |= SC_RCV_B7_1;
831 else
832 sc->sc_flags |= SC_RCV_B7_0;
833 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
834 sc->sc_flags |= SC_RCV_ODDP;
835 else
836 sc->sc_flags |= SC_RCV_EVNP;
837 splx(s);
839 if (sc->sc_flags & SC_LOG_RAWIN)
840 ppplogchar(sc, c);
842 if (c == PPP_FLAG) {
843 ilen = sc->sc_ilen;
844 sc->sc_ilen = 0;
846 if (sc->sc_rawin_count > 0)
847 ppplogchar(sc, -1);
850 * If SC_ESCAPED is set, then we've seen the packet
851 * abort sequence "}~".
853 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
854 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
855 s = spltty();
856 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
857 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
858 if (sc->sc_flags & SC_DEBUG)
859 printf("ppp%d: bad fcs %x, pkt len %d\n",
860 sc->sc_if.if_unit, sc->sc_fcs, ilen);
861 sc->sc_if.if_ierrors++;
862 sc->sc_stats.ppp_ierrors++;
863 } else
864 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
865 splx(s);
866 return 0;
869 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
870 if (ilen) {
871 if (sc->sc_flags & SC_DEBUG)
872 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
873 s = spltty();
874 sc->sc_if.if_ierrors++;
875 sc->sc_stats.ppp_ierrors++;
876 sc->sc_flags |= SC_PKTLOST;
877 splx(s);
879 return 0;
883 * Remove FCS trailer. Somewhat painful...
885 ilen -= 2;
886 if (--sc->sc_mc->m_len == 0) {
887 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
889 sc->sc_mc = m;
891 sc->sc_mc->m_len--;
893 /* excise this mbuf chain */
894 m = sc->sc_m;
895 sc->sc_m = sc->sc_mc->m_next;
896 sc->sc_mc->m_next = NULL;
898 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
899 if (sc->sc_flags & SC_PKTLOST) {
900 s = spltty();
901 sc->sc_flags &= ~SC_PKTLOST;
902 splx(s);
905 pppgetm(sc);
906 return 0;
909 if (sc->sc_flags & SC_FLUSH) {
910 if (sc->sc_flags & SC_LOG_FLUSH)
911 ppplogchar(sc, c);
912 return 0;
915 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
916 return 0;
918 s = spltty();
919 if (sc->sc_flags & SC_ESCAPED) {
920 sc->sc_flags &= ~SC_ESCAPED;
921 c ^= PPP_TRANS;
922 } else if (c == PPP_ESCAPE) {
923 sc->sc_flags |= SC_ESCAPED;
924 splx(s);
925 return 0;
927 splx(s);
930 * Initialize buffer on first octet received.
931 * First octet could be address or protocol (when compressing
932 * address/control).
933 * Second octet is control.
934 * Third octet is first or second (when compressing protocol)
935 * octet of protocol.
936 * Fourth octet is second octet of protocol.
938 if (sc->sc_ilen == 0) {
939 /* reset the first input mbuf */
940 if (sc->sc_m == NULL) {
941 pppgetm(sc);
942 if (sc->sc_m == NULL) {
943 if (sc->sc_flags & SC_DEBUG)
944 printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
945 goto flush;
948 m = sc->sc_m;
949 m->m_len = 0;
950 m->m_data = M_DATASTART(sc->sc_m);
951 sc->sc_mc = m;
952 sc->sc_mp = mtod(m, char *);
953 sc->sc_fcs = PPP_INITFCS;
954 if (c != PPP_ALLSTATIONS) {
955 if (sc->sc_flags & SC_REJ_COMP_AC) {
956 if (sc->sc_flags & SC_DEBUG)
957 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
958 sc->sc_if.if_unit, c);
959 goto flush;
961 *sc->sc_mp++ = PPP_ALLSTATIONS;
962 *sc->sc_mp++ = PPP_UI;
963 sc->sc_ilen += 2;
964 m->m_len += 2;
967 if (sc->sc_ilen == 1 && c != PPP_UI) {
968 if (sc->sc_flags & SC_DEBUG)
969 printf("ppp%d: missing UI (0x3), got 0x%x\n",
970 sc->sc_if.if_unit, c);
971 goto flush;
973 if (sc->sc_ilen == 2 && (c & 1) == 1) {
974 /* a compressed protocol */
975 *sc->sc_mp++ = 0;
976 sc->sc_ilen++;
977 sc->sc_mc->m_len++;
979 if (sc->sc_ilen == 3 && (c & 1) == 0) {
980 if (sc->sc_flags & SC_DEBUG)
981 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
982 (sc->sc_mp[-1] << 8) + c);
983 goto flush;
986 /* packet beyond configured mru? */
987 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
988 if (sc->sc_flags & SC_DEBUG)
989 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
990 goto flush;
993 /* is this mbuf full? */
994 m = sc->sc_mc;
995 if (M_TRAILINGSPACE(m) <= 0) {
996 if (m->m_next == NULL) {
997 pppgetm(sc);
998 if (m->m_next == NULL) {
999 if (sc->sc_flags & SC_DEBUG)
1000 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1001 goto flush;
1004 sc->sc_mc = m = m->m_next;
1005 m->m_len = 0;
1006 m->m_data = M_DATASTART(m);
1007 sc->sc_mp = mtod(m, char *);
1010 ++m->m_len;
1011 *sc->sc_mp++ = c;
1012 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1013 return 0;
1015 flush:
1016 if (!(sc->sc_flags & SC_FLUSH)) {
1017 s = spltty();
1018 sc->sc_if.if_ierrors++;
1019 sc->sc_stats.ppp_ierrors++;
1020 sc->sc_flags |= SC_FLUSH;
1021 splx(s);
1022 if (sc->sc_flags & SC_LOG_FLUSH)
1023 ppplogchar(sc, c);
1025 return 0;
1028 #define MAX_DUMP_BYTES 128
1030 static void
1031 ppplogchar(sc, c)
1032 struct ppp_softc *sc;
1033 int c;
1035 if (c >= 0)
1036 sc->sc_rawin[sc->sc_rawin_count++] = c;
1037 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1038 || (c < 0 && sc->sc_rawin_count > 0)) {
1039 printf("ppp%d input: ", sc->sc_if.if_unit);
1040 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1041 sc->sc_rawin_count = 0;
1045 static void
1046 pppdumpb(b, l)
1047 u_char *b;
1048 int l;
1050 char buf[3*MAX_DUMP_BYTES+4];
1051 char *bp = buf;
1052 static char digits[] = "0123456789abcdef";
1054 while (l--) {
1055 if (bp >= buf + sizeof(buf) - 3) {
1056 *bp++ = '>';
1057 break;
1059 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1060 *bp++ = digits[*b++ & 0xf];
1061 *bp++ = ' ';
1064 *bp = 0;
1065 printf("%s\n", buf);
1068 #endif /* NPPP > 0 */