Restore original EUID rather than 0 during option processing.
[mpls-ppp.git] / ultrix / ppp_tty.c
blob49f831647d09534dfc82a2581506dc6e5b8fd3dc
1 /*
2 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
3 * tty devices.
5 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
19 * 3. The name "Carnegie Mellon University" must not be used to
20 * endorse or promote products derived from this software without
21 * prior written permission. For permission or any legal
22 * details, please contact
23 * Office of Technology Transfer
24 * Carnegie Mellon University
25 * 5000 Forbes Avenue
26 * Pittsburgh, PA 15213-3890
27 * (412) 268-4387, fax: (412) 268-7395
28 * tech-transfer@andrew.cmu.edu
30 * 4. Redistributions of any form whatsoever must retain the following
31 * acknowledgment:
32 * "This product includes software developed by Computing Services
33 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
36 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
37 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
38 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
39 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
40 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
41 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43 * Drew D. Perkins
44 * Carnegie Mellon University
45 * 4910 Forbes Ave.
46 * Pittsburgh, PA 15213
47 * (412) 268-8576
48 * ddp@andrew.cmu.edu
50 * Based on:
51 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
53 * Copyright (c) 1987 Regents of the University of California.
54 * All rights reserved.
56 * Redistribution and use in source and binary forms are permitted
57 * provided that the above copyright notice and this paragraph are
58 * duplicated in all such forms and that any documentation,
59 * advertising materials, and other materials related to such
60 * distribution and use acknowledge that the software was developed
61 * by the University of California, Berkeley. The name of the
62 * University may not be used to endorse or promote products derived
63 * from this software without specific prior written permission.
64 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
65 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
66 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
68 * Serial Line interface
70 * Rick Adams
71 * Center for Seismic Studies
72 * 1300 N 17th Street, Suite 1450
73 * Arlington, Virginia 22209
74 * (703)276-7900
75 * rick@seismo.ARPA
76 * seismo!rick
78 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
79 * Converted to 4.3BSD Beta by Chris Torek.
80 * Other changes made at Berkeley, based in part on code by Kirk Smith.
82 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
83 * Added VJ tcp header compression; more unified ioctls
85 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
86 * Cleaned up a lot of the mbuf-related code to fix bugs that
87 * caused system crashes and packet corruption. Changed pppstart
88 * so that it doesn't just give up with a "collision" if the whole
89 * packet doesn't fit in the output ring buffer.
91 * Added priority queueing for interactive IP packets, following
92 * the model of if_sl.c, plus hooks for bpf.
93 * Paul Mackerras (paulus@cs.anu.edu.au).
95 * Ultrix port by Per Sundstrom <sundstrom@stkhlm.enet.dec.com>,
96 * Robert Olsson <robert@robur.slu.se> and Paul Mackerras.
99 /* $Id: ppp_tty.c,v 1.9 2002/12/06 09:49:16 paulus Exp $ */
100 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
101 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
103 #include "ppp.h"
104 #if NPPP > 0
106 #define VJC
107 #define PPP_COMPRESS
109 #include "../h/param.h"
110 #include "../h/user.h"
111 #include "../h/proc.h"
112 #include "../h/mbuf.h"
113 #include "../h/buf.h"
114 #include "../h/socket.h"
115 #include "../h/ioctl.h"
116 #include "../h/file.h"
117 #include "../h/tty.h"
118 #include "../h/kernel.h"
119 #include "../h/conf.h"
120 #include "../h/uio.h"
121 #include "../h/systm.h"
123 #include "../net/net/if.h"
124 #include "ppp_defs.h"
126 #ifdef VJC
127 #include "../net/netinet/in.h"
128 #include "../net/netinet/in_systm.h"
129 #include "../net/netinet/ip.h"
130 #include "slcompress.h"
131 #endif
133 #include "if_ppp.h"
134 #include "if_pppvar.h"
136 int pppopen __P((dev_t dev, struct tty *tp));
137 int pppclose __P((struct tty *tp, int flag));
138 int pppread __P((struct tty *tp, struct uio *uio, int flag));
139 int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
140 int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag));
141 int pppinput __P((int c, struct tty *tp));
142 int pppstart __P((struct tty *tp));
144 static u_short pppfcs __P((u_short fcs, u_char *cp, int len));
145 static void pppasyncstart __P((struct ppp_softc *));
146 static void pppasyncctlp __P((struct ppp_softc *));
147 static void pppasyncrelinq __P((struct ppp_softc *));
148 static void ppp_timeout __P((void *));
149 static void pppgetm __P((struct ppp_softc *sc));
150 static void pppdumpb __P((u_char *b, int l));
151 static void ppplogchar __P((struct ppp_softc *, int));
154 * Some useful mbuf macros not in mbuf.h.
156 #define M_IS_CLUSTER(m) ((m)->m_off > MMAXOFF)
158 #define M_TRAILINGSPACE(m) \
159 ((M_IS_CLUSTER(m) ? (u_int)(m)->m_clptr + M_CLUSTERSZ : MSIZE) \
160 - ((m)->m_off + (m)->m_len))
162 #define M_OFFSTART(m) \
163 (M_IS_CLUSTER(m) ? (u_int)(m)->m_clptr : MMINOFF)
165 #define M_DATASIZE(m) \
166 (M_IS_CLUSTER(m) ? M_CLUSTERSZ : 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.
178 * This is an Ultrix kernel, we've got clists.
180 #define CCOUNT(q) ((q)->c_cc)
182 #define t_sc T_LINEP
183 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
184 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
187 * Line specific open routine for async tty devices.
188 * Attach the given tty to the first available ppp unit.
189 * Called from device open routine or ttioctl.
191 /* ARGSUSED */
193 pppopen(dev, tp)
194 dev_t dev;
195 register struct tty *tp;
197 register struct ppp_softc *sc;
198 int error, s;
199 struct proc *p = u.u_procp;
201 if (!suser())
202 return EPERM;
204 s = spltty();
206 if (tp->t_line == PPPDISC) {
207 sc = (struct ppp_softc *) tp->t_sc;
208 if (sc != NULL && sc->sc_devp == (void *) tp) {
209 splx(s);
210 return (0);
214 if ((sc = pppalloc(p->p_pid)) == NULL) {
215 splx(s);
216 return ENXIO;
219 if (sc->sc_relinq)
220 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
222 sc->sc_ilen = 0;
223 sc->sc_m = NULL;
224 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
225 sc->sc_asyncmap[0] = 0xffffffff;
226 sc->sc_asyncmap[3] = 0x60000000;
227 sc->sc_rasyncmap = 0;
228 sc->sc_devp = (void *) tp;
229 sc->sc_start = pppasyncstart;
230 sc->sc_ctlp = pppasyncctlp;
231 sc->sc_relinq = pppasyncrelinq;
232 sc->sc_outm = NULL;
233 pppgetm(sc);
234 sc->sc_if.if_flags |= IFF_RUNNING;
236 tp->t_sc = (caddr_t) sc;
237 ttyflush(tp, FREAD | FWRITE);
239 splx(s);
240 return (0);
244 * Line specific close routine, called from device close routine
245 * and from ttioctl.
246 * Detach the tty from the ppp unit.
247 * Mimics part of ttyclose().
250 pppclose(tp, flag)
251 struct tty *tp;
252 int flag;
254 register struct ppp_softc *sc;
255 int s;
257 s = spltty();
258 ttyflush(tp, FREAD|FWRITE);
259 tp->t_line = 0;
260 sc = (struct ppp_softc *) tp->t_sc;
261 if (sc != NULL) {
262 tp->t_sc = NULL;
263 if (tp == (struct tty *) sc->sc_devp) {
264 pppasyncrelinq(sc);
265 pppdealloc(sc);
268 splx(s);
269 return 0;
273 * Relinquish the interface unit to another device.
275 static void
276 pppasyncrelinq(sc)
277 struct ppp_softc *sc;
279 int s;
281 s = spltty();
282 if (sc->sc_outm) {
283 m_freem(sc->sc_outm);
284 sc->sc_outm = NULL;
286 if (sc->sc_m) {
287 m_freem(sc->sc_m);
288 sc->sc_m = NULL;
290 if (sc->sc_flags & SC_TIMEOUT) {
291 untimeout(ppp_timeout, (void *) sc);
292 sc->sc_flags &= ~SC_TIMEOUT;
294 splx(s);
298 * Line specific (tty) read routine.
301 pppread(tp, uio, flag)
302 register struct tty *tp;
303 struct uio *uio;
304 int flag;
306 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
307 struct mbuf *m, *m0;
308 register int s;
309 int error = 0;
311 if (sc == NULL)
312 return 0;
314 * Loop waiting for input, checking that nothing disasterous
315 * happens in the meantime.
317 s = spltty();
318 for (;;) {
319 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
320 splx(s);
321 return 0;
323 if (sc->sc_inq.ifq_head != NULL)
324 break;
325 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
326 && (tp->t_state & TS_ISOPEN)) {
327 splx(s);
328 return 0; /* end of file */
330 if (tp->t_state & (TS_ASYNC | TS_NBIO)) {
331 splx(s);
332 return (EWOULDBLOCK);
334 sleep((caddr_t) &tp->t_rawq, TTIPRI);
337 /* Pull place-holder byte out of canonical queue */
338 getc(&tp->t_canq);
340 /* Get the packet from the input queue */
341 IF_DEQUEUE(&sc->sc_inq, m0);
342 splx(s);
344 for (m = m0; m && uio->uio_resid; m = m->m_next)
345 if (error = uiomove(mtod(m, u_char *), m->m_len, UIO_READ, uio))
346 break;
347 m_freem(m0);
348 return (error);
352 * Line specific (tty) write routine.
355 pppwrite(tp, uio, flag)
356 register struct tty *tp;
357 struct uio *uio;
358 int flag;
360 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
361 struct mbuf *m, *m0, **mp, *p;
362 struct sockaddr dst;
363 int len, error;
365 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
366 return 0; /* wrote 0 bytes */
367 if (tp->t_line != PPPDISC)
368 return (EINVAL);
369 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
370 return EIO;
371 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
372 uio->uio_resid < PPP_HDRLEN)
373 return (EMSGSIZE);
374 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
375 MGET(m, M_WAIT, MT_DATA);
376 if ((*mp = m) == NULL) {
377 m_freem(m0);
378 return (ENOBUFS);
380 if (uio->uio_resid >= CLBYTES / 2) {
381 MCLGET(m, p);
382 } else
383 m->m_len = MLEN;
384 len = MIN(m->m_len, uio->uio_resid);
385 if (error = uiomove(mtod(m, u_char *), len, UIO_WRITE, uio)) {
386 m_freem(m0);
387 return (error);
389 m->m_len = len;
391 dst.sa_family = AF_UNSPEC;
392 bcopy(mtod(m0, caddr_t), dst.sa_data, PPP_HDRLEN);
393 m0->m_off += PPP_HDRLEN;
394 m0->m_len -= PPP_HDRLEN;
395 return (pppoutput(&sc->sc_if, m0, &dst));
399 * Line specific (tty) ioctl routine.
400 * This discipline requires that tty device drivers call
401 * the line specific l_ioctl routine from their ioctl routines.
403 /* ARGSUSED */
405 ppptioctl(tp, cmd, data, flag)
406 struct tty *tp;
407 caddr_t data;
408 int cmd, flag;
410 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
411 int error, s;
413 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
414 return -1;
416 error = 0;
417 switch (cmd) {
418 case PPPIOCSASYNCMAP:
419 if (!suser())
420 return EPERM;
421 sc->sc_asyncmap[0] = *(u_int *)data;
422 break;
424 case PPPIOCGASYNCMAP:
425 *(u_int *)data = sc->sc_asyncmap[0];
426 break;
428 case PPPIOCSRASYNCMAP:
429 if (!suser())
430 return EPERM;
431 sc->sc_rasyncmap = *(u_int *)data;
432 break;
434 case PPPIOCGRASYNCMAP:
435 *(u_int *)data = sc->sc_rasyncmap;
436 break;
438 case PPPIOCSXASYNCMAP:
439 if (!suser())
440 return EPERM;
441 s = spltty();
442 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
443 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
444 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
445 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
446 splx(s);
447 break;
449 case PPPIOCGXASYNCMAP:
450 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
451 break;
453 default:
454 error = pppioctl(sc, cmd, data, flag);
455 if (error == 0 && cmd == PPPIOCSMRU)
456 pppgetm(sc);
459 return error;
463 * FCS lookup table as calculated by genfcstab.
465 static u_short fcstab[256] = {
466 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
467 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
468 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
469 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
470 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
471 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
472 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
473 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
474 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
475 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
476 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
477 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
478 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
479 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
480 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
481 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
482 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
483 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
484 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
485 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
486 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
487 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
488 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
489 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
490 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
491 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
492 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
493 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
494 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
495 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
496 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
497 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
501 * Calculate a new FCS given the current FCS and the new data.
503 static u_short
504 pppfcs(fcs, cp, len)
505 register u_short fcs;
506 register u_char *cp;
507 register int len;
509 while (len--)
510 fcs = PPP_FCS(fcs, *cp++);
511 return (fcs);
515 * This gets called at splnet from if_ppp.c at various times
516 * when there is data ready to be sent.
518 static void
519 pppasyncstart(sc)
520 register struct ppp_softc *sc;
522 register struct tty *tp = (struct tty *) sc->sc_devp;
523 register struct mbuf *m;
524 register int len;
525 register u_char *start, *stop, *cp;
526 int n, ndone, done, idle;
527 struct mbuf *m2;
528 int s;
530 idle = 0;
531 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
533 * See if we have an existing packet partly sent.
534 * If not, get a new packet and start sending it.
536 m = sc->sc_outm;
537 if (m == NULL) {
539 * Get another packet to be sent.
541 m = ppp_dequeue(sc);
542 if (m == NULL) {
543 idle = 1;
544 break;
548 * The extra PPP_FLAG will start up a new packet, and thus
549 * will flush any accumulated garbage. We do this whenever
550 * the line may have been idle for some time.
552 if (CCOUNT(&tp->t_outq) == 0) {
553 ++sc->sc_stats.ppp_obytes;
554 (void) putc(PPP_FLAG, &tp->t_outq);
557 /* Calculate the FCS for the first mbuf's worth. */
558 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
561 for (;;) {
562 start = mtod(m, u_char *);
563 len = m->m_len;
564 stop = start + len;
565 while (len > 0) {
567 * Find out how many bytes in the string we can
568 * handle without doing something special.
570 for (cp = start; cp < stop; cp++)
571 if (ESCAPE_P(*cp))
572 break;
573 n = cp - start;
574 if (n) {
575 ndone = n - b_to_q(start, n, &tp->t_outq);
576 len -= ndone;
577 start += ndone;
578 sc->sc_stats.ppp_obytes += ndone;
580 if (ndone < n)
581 break; /* packet doesn't fit */
584 * If there are characters left in the mbuf,
585 * the first one must be special.
586 * Put it out in a different form.
588 if (len) {
589 s = spltty();
590 if (putc(PPP_ESCAPE, &tp->t_outq))
591 break;
592 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
593 (void) unputc(&tp->t_outq);
594 splx(s);
595 break;
597 splx(s);
598 sc->sc_stats.ppp_obytes += 2;
599 start++;
600 len--;
605 * If we didn't empty this mbuf, remember where we're up to.
606 * If we emptied the last mbuf, try to add the FCS and closing
607 * flag, and if we can't, leave sc_outm pointing to m, but with
608 * m->m_len == 0, to remind us to output the FCS and flag later.
610 done = len == 0;
611 if (done && m->m_next == NULL) {
612 u_char *p, *q;
613 int c;
614 u_char endseq[8];
617 * We may have to escape the bytes in the FCS.
619 p = endseq;
620 c = ~sc->sc_outfcs & 0xFF;
621 if (ESCAPE_P(c)) {
622 *p++ = PPP_ESCAPE;
623 *p++ = c ^ PPP_TRANS;
624 } else
625 *p++ = c;
626 c = (~sc->sc_outfcs >> 8) & 0xFF;
627 if (ESCAPE_P(c)) {
628 *p++ = PPP_ESCAPE;
629 *p++ = c ^ PPP_TRANS;
630 } else
631 *p++ = c;
632 *p++ = PPP_FLAG;
635 * Try to output the FCS and flag. If the bytes
636 * don't all fit, back out.
638 s = spltty();
639 for (q = endseq; q < p; ++q)
640 if (putc(*q, &tp->t_outq)) {
641 done = 0;
642 for (; q > endseq; --q)
643 unputc(&tp->t_outq);
644 break;
646 splx(s);
647 if (done)
648 sc->sc_stats.ppp_obytes += q - endseq;
651 if (!done) {
652 m->m_off += m->m_len - len;
653 m->m_len = len;
654 break;
657 /* Finished with this mbuf; free it and move on. */
658 MFREE(m, m2);
659 m = m2;
660 if (m == NULL) {
661 /* Finished a packet */
662 break;
664 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
668 * If m == NULL, we have finished a packet.
669 * If m != NULL, we've either done as much work this time
670 * as we need to, or else we've filled up the output queue.
672 sc->sc_outm = m;
673 if (m)
674 break;
677 /* Call pppstart to start output again if necessary. */
678 s = spltty();
679 pppstart(tp);
682 * This timeout is needed for operation on a pseudo-tty,
683 * because the pty code doesn't call pppstart after it has
684 * drained the t_outq.
686 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
687 timeout(ppp_timeout, (void *) sc, 1);
688 sc->sc_flags |= SC_TIMEOUT;
691 splx(s);
695 * This gets called when a received packet is placed on
696 * the inq, at splnet.
698 static void
699 pppasyncctlp(sc)
700 struct ppp_softc *sc;
702 struct tty *tp;
703 int s;
705 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
706 s = spltty();
707 tp = (struct tty *) sc->sc_devp;
708 putc(0, &tp->t_canq);
709 ttwakeup(tp);
710 splx(s);
714 * Start output on async tty interface. If the transmit queue
715 * has drained sufficiently, arrange for pppasyncstart to be
716 * called later at splnet.
717 * Called at spltty or higher.
720 pppstart(tp)
721 register struct tty *tp;
723 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
726 * If there is stuff in the output queue, send it now.
727 * We are being called in lieu of ttstart and must do what it would.
729 if (tp->t_oproc != NULL)
730 (*tp->t_oproc)(tp);
733 * If the transmit queue has drained and the tty has not hung up
734 * or been disconnected from the ppp unit, then tell if_ppp.c that
735 * we need more output.
737 if (CCOUNT(&tp->t_outq) < PPP_LOWAT
738 && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
739 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
740 ppp_restart(sc);
743 return 0;
747 * Timeout routine - try to start some more output.
749 static void
750 ppp_timeout(x)
751 void *x;
753 struct ppp_softc *sc = (struct ppp_softc *) x;
754 struct tty *tp = (struct tty *) sc->sc_devp;
755 int s;
757 s = spltty();
758 sc->sc_flags &= ~SC_TIMEOUT;
759 pppstart(tp);
760 splx(s);
764 * Allocate enough mbuf to handle current MRU.
766 static void
767 pppgetm(sc)
768 register struct ppp_softc *sc;
770 struct mbuf *m, **mp, *p;
771 int len;
773 mp = &sc->sc_m;
774 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
775 if ((m = *mp) == NULL) {
776 MGET(m, M_DONTWAIT, MT_DATA);
777 if (m == NULL)
778 break;
779 *mp = m;
780 MCLGET(m, p);
782 len -= M_DATASIZE(m);
783 mp = &m->m_next;
788 * tty interface receiver interrupt.
790 static unsigned paritytab[8] = {
791 0x96696996, 0x69969669, 0x69969669, 0x96696996,
792 0x69969669, 0x96696996, 0x96696996, 0x69969669
796 pppinput(c, tp)
797 int c;
798 register struct tty *tp;
800 register struct ppp_softc *sc;
801 struct mbuf *m;
802 int ilen, s;
803 extern int tk_nin;
805 sc = (struct ppp_softc *) tp->t_sc;
806 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
807 return 0;
809 ++tk_nin;
810 ++sc->sc_stats.ppp_ibytes;
812 c &= 0xff;
815 * Handle software flow control of output.
817 if (tp->t_iflag & IXON) {
818 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != 0) {
819 if ((tp->t_state & TS_TTSTOP) == 0) {
820 tp->t_state |= TS_TTSTOP;
821 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
823 return 0;
825 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != 0) {
826 tp->t_state &= ~TS_TTSTOP;
827 if (tp->t_oproc != NULL)
828 (*tp->t_oproc)(tp);
829 return 0;
833 s = spltty();
834 if (c & 0x80)
835 sc->sc_flags |= SC_RCV_B7_1;
836 else
837 sc->sc_flags |= SC_RCV_B7_0;
838 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
839 sc->sc_flags |= SC_RCV_ODDP;
840 else
841 sc->sc_flags |= SC_RCV_EVNP;
842 splx(s);
844 if (sc->sc_flags & SC_LOG_RAWIN)
845 ppplogchar(sc, c);
847 if (c == PPP_FLAG) {
848 ilen = sc->sc_ilen;
849 sc->sc_ilen = 0;
851 if (sc->sc_rawin_count > 0)
852 ppplogchar(sc, -1);
855 * If SC_ESCAPED is set, then we've seen the packet
856 * abort sequence "}~".
858 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
859 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
860 s = spltty();
861 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
862 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
863 if (sc->sc_flags & SC_DEBUG)
864 printf("ppp%d: bad fcs %x, pkt len %d\n",
865 sc->sc_if.if_unit, sc->sc_fcs, ilen);
866 sc->sc_if.if_ierrors++;
867 sc->sc_stats.ppp_ierrors++;
868 } else
869 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
870 splx(s);
871 return 0;
874 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
875 if (ilen) {
876 if (sc->sc_flags & SC_DEBUG)
877 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
878 s = spltty();
879 sc->sc_if.if_ierrors++;
880 sc->sc_stats.ppp_ierrors++;
881 sc->sc_flags |= SC_PKTLOST;
882 splx(s);
884 return 0;
888 * Remove FCS trailer. Somewhat painful...
890 ilen -= 2;
891 if (--sc->sc_mc->m_len == 0) {
892 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
894 sc->sc_mc = m;
896 sc->sc_mc->m_len--;
898 /* excise this mbuf chain */
899 m = sc->sc_m;
900 sc->sc_m = sc->sc_mc->m_next;
901 sc->sc_mc->m_next = NULL;
903 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
904 if (sc->sc_flags & SC_PKTLOST) {
905 s = spltty();
906 sc->sc_flags &= ~SC_PKTLOST;
907 splx(s);
910 pppgetm(sc);
911 return 0;
914 if (sc->sc_flags & SC_FLUSH) {
915 if (sc->sc_flags & SC_LOG_FLUSH)
916 ppplogchar(sc, c);
917 return 0;
920 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
921 return 0;
923 s = spltty();
924 if (sc->sc_flags & SC_ESCAPED) {
925 sc->sc_flags &= ~SC_ESCAPED;
926 c ^= PPP_TRANS;
927 } else if (c == PPP_ESCAPE) {
928 sc->sc_flags |= SC_ESCAPED;
929 splx(s);
930 return 0;
932 splx(s);
935 * Initialize buffer on first octet received.
936 * First octet could be address or protocol (when compressing
937 * address/control).
938 * Second octet is control.
939 * Third octet is first or second (when compressing protocol)
940 * octet of protocol.
941 * Fourth octet is second octet of protocol.
943 if (sc->sc_ilen == 0) {
944 /* reset the first input mbuf */
945 if (sc->sc_m == NULL) {
946 pppgetm(sc);
947 if (sc->sc_m == NULL) {
948 if (sc->sc_flags & SC_DEBUG)
949 printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
950 goto flush;
953 m = sc->sc_m;
954 m->m_len = 0;
955 m->m_off = M_OFFSTART(m);
956 sc->sc_mc = m;
957 sc->sc_mp = mtod(m, char *);
958 sc->sc_fcs = PPP_INITFCS;
959 if (c != PPP_ALLSTATIONS) {
960 if (sc->sc_flags & SC_REJ_COMP_AC) {
961 if (sc->sc_flags & SC_DEBUG)
962 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
963 sc->sc_if.if_unit, c);
964 goto flush;
966 *sc->sc_mp++ = PPP_ALLSTATIONS;
967 *sc->sc_mp++ = PPP_UI;
968 sc->sc_ilen += 2;
969 m->m_len += 2;
972 if (sc->sc_ilen == 1 && c != PPP_UI) {
973 if (sc->sc_flags & SC_DEBUG)
974 printf("ppp%d: missing UI (0x3), got 0x%x\n",
975 sc->sc_if.if_unit, c);
976 goto flush;
978 if (sc->sc_ilen == 2 && (c & 1) == 1) {
979 /* a compressed protocol */
980 *sc->sc_mp++ = 0;
981 sc->sc_ilen++;
982 sc->sc_mc->m_len++;
984 if (sc->sc_ilen == 3 && (c & 1) == 0) {
985 if (sc->sc_flags & SC_DEBUG)
986 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
987 (sc->sc_mp[-1] << 8) + c);
988 goto flush;
991 /* packet beyond configured mru? */
992 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
993 if (sc->sc_flags & SC_DEBUG)
994 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
995 goto flush;
998 /* is this mbuf full? */
999 m = sc->sc_mc;
1000 if (M_TRAILINGSPACE(m) <= 0) {
1001 if (m->m_next == NULL) {
1002 pppgetm(sc);
1003 if (m->m_next == NULL) {
1004 if (sc->sc_flags & SC_DEBUG)
1005 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1006 goto flush;
1009 sc->sc_mc = m = m->m_next;
1010 m->m_len = 0;
1011 m->m_off = M_OFFSTART(m);
1012 sc->sc_mp = mtod(m, char *);
1015 ++m->m_len;
1016 *sc->sc_mp++ = c;
1017 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1018 return 0;
1020 flush:
1021 if (!(sc->sc_flags & SC_FLUSH)) {
1022 s = spltty();
1023 sc->sc_if.if_ierrors++;
1024 sc->sc_stats.ppp_ierrors++;
1025 sc->sc_flags |= SC_FLUSH;
1026 splx(s);
1027 if (sc->sc_flags & SC_LOG_FLUSH)
1028 ppplogchar(sc, c);
1030 return 0;
1033 #define MAX_DUMP_BYTES 128
1035 static void
1036 ppplogchar(sc, c)
1037 struct ppp_softc *sc;
1038 int c;
1040 if (c >= 0)
1041 sc->sc_rawin[sc->sc_rawin_count++] = c;
1042 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1043 || (c < 0 && sc->sc_rawin_count > 0)) {
1044 printf("ppp%d input: ", sc->sc_if.if_unit);
1045 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1046 sc->sc_rawin_count = 0;
1050 static void
1051 pppdumpb(b, l)
1052 u_char *b;
1053 int l;
1055 char buf[3*MAX_DUMP_BYTES+4];
1056 char *bp = buf;
1057 static char digits[] = "0123456789abcdef";
1059 while (l--) {
1060 if (bp >= buf + sizeof(buf) - 3) {
1061 *bp++ = '>';
1062 break;
1064 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1065 *bp++ = digits[*b++ & 0xf];
1066 *bp++ = ' ';
1069 *bp = 0;
1070 printf("%s\n", buf);
1073 #endif /* NPPP > 0 */