crit_exit() is called where crit_enter() is supposed to be.
[dragonfly.git] / sys / net / ppp_layer / ppp_tty.c
blob22cb9a4c5e2f1451996173f4ce2bc9eeb037896a
1 /*
2 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
3 * tty devices.
5 * Copyright (c) 1989 Carnegie Mellon University.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by Carnegie Mellon University. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 * Drew D. Perkins
21 * Carnegie Mellon University
22 * 4910 Forbes Ave.
23 * Pittsburgh, PA 15213
24 * (412) 268-8576
25 * ddp@andrew.cmu.edu
27 * Based on:
28 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
30 * Copyright (c) 1987 Regents of the University of California.
31 * All rights reserved.
33 * Redistribution and use in source and binary forms are permitted
34 * provided that the above copyright notice and this paragraph are
35 * duplicated in all such forms and that any documentation,
36 * advertising materials, and other materials related to such
37 * distribution and use acknowledge that the software was developed
38 * by the University of California, Berkeley. The name of the
39 * University may not be used to endorse or promote products derived
40 * from this software without specific prior written permission.
41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
42 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
43 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
45 * Serial Line interface
47 * Rick Adams
48 * Center for Seismic Studies
49 * 1300 N 17th Street, Suite 1450
50 * Arlington, Virginia 22209
51 * (703)276-7900
52 * rick@seismo.ARPA
53 * seismo!rick
55 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
56 * Converted to 4.3BSD Beta by Chris Torek.
57 * Other changes made at Berkeley, based in part on code by Kirk Smith.
59 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
60 * Added VJ tcp header compression; more unified ioctls
62 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
63 * Cleaned up a lot of the mbuf-related code to fix bugs that
64 * caused system crashes and packet corruption. Changed pppstart
65 * so that it doesn't just give up with a "collision" if the whole
66 * packet doesn't fit in the output ring buffer.
68 * Added priority queueing for interactive IP packets, following
69 * the model of if_sl.c, plus hooks for bpf.
70 * Paul Mackerras (paulus@cs.anu.edu.au).
73 /* $FreeBSD: src/sys/net/ppp_tty.c,v 1.43.2.1 2002/02/13 00:43:11 dillon Exp $ */
74 /* $DragonFly: src/sys/net/ppp_layer/ppp_tty.c,v 1.16 2006/01/30 14:16:16 y0netan1 Exp $ */
76 #include "opt_ppp.h" /* XXX for ppp_defs.h */
78 #define VJC /* XXX for ppp_defs.h */
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/proc.h>
83 #include <sys/mbuf.h>
84 #include <sys/dkstat.h>
85 #include <sys/socket.h>
86 #include <sys/fcntl.h>
87 #include <sys/thread2.h>
88 #include <sys/tty.h>
89 #include <sys/conf.h>
90 #include <sys/uio.h>
91 #include <sys/vnode.h>
93 #ifdef __i386__
94 #include <i386/isa/intr_machdep.h>
95 #endif
97 #include <net/if.h>
98 #include <net/ifq_var.h>
100 #ifdef PPP_FILTER
101 #include <net/bpf.h>
102 #endif
103 #include <net/ppp/if_ppp.h>
104 #include <net/ppp/if_pppvar.h>
106 static int pppopen (dev_t dev, struct tty *tp);
107 static int pppclose (struct tty *tp, int flag);
108 static int pppread (struct tty *tp, struct uio *uio, int flag);
109 static int pppwrite (struct tty *tp, struct uio *uio, int flag);
110 static int ppptioctl (struct tty *tp, u_long cmd, caddr_t data,
111 int flag, struct thread *);
112 static int pppinput (int c, struct tty *tp);
113 static int pppstart (struct tty *tp);
115 static u_short pppfcs (u_short fcs, u_char *cp, int len);
116 static void pppasyncstart (struct ppp_softc *);
117 static void pppasyncctlp (struct ppp_softc *);
118 static void pppasyncrelinq (struct ppp_softc *);
119 static void pppasyncsetmtu (struct ppp_softc *);
120 static void ppp_timeout (void *);
121 static void pppgetm (struct ppp_softc *sc);
122 static void ppplogchar (struct ppp_softc *, int);
124 /* XXX called from if_ppp.c - layering violation */
125 void pppasyncattach (void *);
128 * Some useful mbuf macros not in mbuf.h.
130 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
132 #define M_DATASTART(m) \
133 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
134 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
136 #define M_DATASIZE(m) \
137 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
138 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
141 * Does c need to be escaped?
143 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
146 * Procedures for using an async tty interface for PPP.
149 /* This is a FreeBSD-2.X kernel. */
150 #define CCOUNT(q) ((q)->c_cc)
151 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
152 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
155 * Define the PPP line discipline.
158 static struct linesw pppdisc = {
159 pppopen, pppclose, pppread, pppwrite,
160 ppptioctl, pppinput, pppstart, ttymodem,
161 PPP_FLAG
164 void
165 pppasyncattach(void *dummy)
167 /* register line discipline */
168 linesw[PPPDISC] = pppdisc;
172 * Line specific open routine for async tty devices.
173 * Attach the given tty to the first available ppp unit.
174 * Called from device open routine or ttioctl() at >= splsofttty()
176 /* ARGSUSED */
177 static int
178 pppopen(dev_t dev, struct tty *tp)
180 struct thread *td = curthread; /* XXX */
181 struct ppp_softc *sc;
182 int error;
184 if ((error = suser(td)) != 0)
185 return (error);
187 crit_enter();
189 if (tp->t_line == PPPDISC) {
190 sc = (struct ppp_softc *) tp->t_sc;
191 if (sc != NULL && sc->sc_devp == (void *) tp) {
192 crit_exit();
193 return (0);
197 if ((sc = pppalloc(td)) == NULL) {
198 crit_exit();
199 return ENXIO;
202 if (sc->sc_relinq)
203 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
205 sc->sc_ilen = 0;
206 sc->sc_m = NULL;
207 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
208 sc->sc_asyncmap[0] = 0xffffffff;
209 sc->sc_asyncmap[3] = 0x60000000;
210 sc->sc_rasyncmap = 0;
211 sc->sc_devp = (void *) tp;
212 sc->sc_start = pppasyncstart;
213 sc->sc_ctlp = pppasyncctlp;
214 sc->sc_relinq = pppasyncrelinq;
215 sc->sc_setmtu = pppasyncsetmtu;
216 sc->sc_outm = NULL;
217 pppgetm(sc);
218 sc->sc_if.if_flags |= IFF_RUNNING;
219 getmicrotime(&sc->sc_if.if_lastchange);
220 sc->sc_if.if_baudrate = tp->t_ospeed;
222 tp->t_sc = (caddr_t) sc;
223 ttyflush(tp, FREAD | FWRITE);
226 * Pre-allocate cblocks to the "just right" amount. The 1 byte t_canq
227 * allocation helps avoid the need for select and/or FIONREAD.
228 * We also pass 1 byte tokens through t_canq...
230 clist_alloc_cblocks(&tp->t_canq, 1, 1);
231 clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT,
232 sc->sc_if.if_mtu + PPP_HIWAT);
233 clist_alloc_cblocks(&tp->t_rawq, 0, 0);
235 crit_exit();
237 return (0);
241 * Line specific close routine, called from device close routine
242 * and from ttioctl at >= splsofttty().
243 * Detach the tty from the ppp unit.
244 * Mimics part of ttyclose().
246 static int
247 pppclose(struct tty *tp, int flag)
249 struct ppp_softc *sc;
251 crit_enter();
252 ttyflush(tp, FREAD | FWRITE);
253 clist_free_cblocks(&tp->t_canq);
254 clist_free_cblocks(&tp->t_outq);
255 tp->t_line = 0;
256 sc = (struct ppp_softc *) tp->t_sc;
257 if (sc != NULL) {
258 tp->t_sc = NULL;
259 if (tp == (struct tty *) sc->sc_devp) {
260 pppasyncrelinq(sc);
261 pppdealloc(sc);
264 crit_exit();
265 return 0;
269 * Relinquish the interface unit to another device.
271 static void
272 pppasyncrelinq(struct ppp_softc *sc)
274 crit_enter();
276 if (sc->sc_outm) {
277 m_freem(sc->sc_outm);
278 sc->sc_outm = NULL;
280 if (sc->sc_m) {
281 m_freem(sc->sc_m);
282 sc->sc_m = NULL;
284 if (sc->sc_flags & SC_TIMEOUT) {
285 callout_stop(&sc->sc_timeout);
286 sc->sc_flags &= ~SC_TIMEOUT;
289 crit_exit();
293 * This gets called from the upper layer to notify a mtu change
295 static void
296 pppasyncsetmtu(struct ppp_softc *sc)
298 struct tty *tp = (struct tty *) sc->sc_devp;
300 crit_enter();
301 if (tp != NULL)
302 clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT,
303 sc->sc_if.if_mtu + PPP_HIWAT);
304 crit_exit();
308 * Line specific (tty) read routine.
309 * called at zero spl from the device driver in the response to user-level
310 * reads on the tty file descriptor (ie: pppd).
312 static int
313 pppread(struct tty *tp, struct uio *uio, int flag)
315 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
316 struct mbuf *m, *m0;
317 int error = 0;
319 if (sc == NULL)
320 return 0;
322 * Loop waiting for input, checking that nothing disasterous
323 * happens in the meantime.
325 crit_enter();
326 for (;;) {
327 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
328 crit_exit();
329 return 0;
331 if (sc->sc_inq.ifq_head != NULL)
332 break;
333 if ((tp->t_state & TS_CONNECTED) == 0) {
334 crit_exit();
335 return 0; /* end of file */
337 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
338 crit_exit();
339 return (EWOULDBLOCK);
341 error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), PCATCH, "pppin", 0);
342 if (error) {
343 crit_exit();
344 return error;
348 /* Pull place-holder byte out of canonical queue */
349 getc(&tp->t_canq);
351 /* Get the packet from the input queue */
352 IF_DEQUEUE(&sc->sc_inq, m0);
353 crit_exit();
355 for (m = m0; m && uio->uio_resid; m = m->m_next)
356 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
357 break;
358 m_freem(m0);
359 return (error);
363 * Line specific (tty) write routine.
364 * called at zero spl from the device driver in the response to user-level
365 * writes on the tty file descriptor (ie: pppd).
367 static int
368 pppwrite(struct tty *tp, struct uio *uio, int flag)
370 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
371 struct mbuf *m, *m0, **mp;
372 struct sockaddr dst;
373 int len, error;
375 if ((tp->t_state & TS_CONNECTED) == 0)
376 return 0; /* wrote 0 bytes */
377 if (tp->t_line != PPPDISC)
378 return (EINVAL);
379 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
380 return EIO;
381 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
382 uio->uio_resid < PPP_HDRLEN)
383 return (EMSGSIZE);
385 crit_enter();
386 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
387 MGET(m, MB_WAIT, MT_DATA);
388 if ((*mp = m) == NULL) {
389 m_freem(m0);
390 crit_exit();
391 return (ENOBUFS);
393 m->m_len = 0;
394 if (uio->uio_resid >= MCLBYTES / 2)
395 MCLGET(m, MB_DONTWAIT);
396 len = M_TRAILINGSPACE(m);
397 if (len > uio->uio_resid)
398 len = uio->uio_resid;
399 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
400 m_freem(m0);
401 crit_exit();
402 return (error);
404 m->m_len = len;
406 dst.sa_family = AF_UNSPEC;
407 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
408 m0->m_data += PPP_HDRLEN;
409 m0->m_len -= PPP_HDRLEN;
411 /* call the upper layer to "transmit" it... */
412 error = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0);
413 crit_exit();
414 return (error);
418 * Line specific (tty) ioctl routine.
419 * This discipline requires that tty device drivers call
420 * the line specific l_ioctl routine from their ioctl routines.
422 /* ARGSUSED */
423 static int
424 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct thread *td)
426 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
427 int error;
429 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
430 return (ENOIOCTL);
432 error = 0;
433 switch (cmd) {
434 case PPPIOCSASYNCMAP:
435 if ((error = suser(td)) != 0)
436 break;
437 sc->sc_asyncmap[0] = *(u_int *)data;
438 break;
440 case PPPIOCGASYNCMAP:
441 *(u_int *)data = sc->sc_asyncmap[0];
442 break;
444 case PPPIOCSRASYNCMAP:
445 if ((error = suser(td)) != 0)
446 break;
447 sc->sc_rasyncmap = *(u_int *)data;
448 break;
450 case PPPIOCGRASYNCMAP:
451 *(u_int *)data = sc->sc_rasyncmap;
452 break;
454 case PPPIOCSXASYNCMAP:
455 if ((error = suser(td)) != 0)
456 break;
457 crit_enter();
458 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
459 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
460 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
461 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
462 crit_exit();
463 break;
465 case PPPIOCGXASYNCMAP:
466 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
467 break;
469 default:
470 error = pppioctl(sc, cmd, data, flag, td);
471 if (error == 0 && cmd == PPPIOCSMRU)
472 pppgetm(sc);
475 return error;
479 * FCS lookup table as calculated by genfcstab.
481 static u_short fcstab[256] = {
482 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
483 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
484 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
485 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
486 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
487 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
488 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
489 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
490 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
491 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
492 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
493 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
494 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
495 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
496 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
497 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
498 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
499 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
500 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
501 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
502 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
503 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
504 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
505 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
506 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
507 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
508 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
509 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
510 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
511 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
512 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
513 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
517 * Calculate a new FCS given the current FCS and the new data.
519 static u_short
520 pppfcs(u_short fcs, u_char *cp, int len)
522 while (len--)
523 fcs = PPP_FCS(fcs, *cp++);
524 return (fcs);
528 * This gets called at splsoftnet from if_ppp.c at various times
529 * when there is data ready to be sent.
531 static void
532 pppasyncstart(struct ppp_softc *sc)
534 struct tty *tp = (struct tty *) sc->sc_devp;
535 struct mbuf *m;
536 int len;
537 u_char *start, *stop, *cp;
538 int n, ndone, done, idle;
540 idle = 0;
541 /* XXX assumes atomic access to *tp although we're not at spltty(). */
542 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
544 * See if we have an existing packet partly sent.
545 * If not, get a new packet and start sending it.
547 m = sc->sc_outm;
548 if (m == NULL) {
550 * Get another packet to be sent.
552 m = ppp_dequeue(sc);
553 if (m == NULL) {
554 idle = 1;
555 break;
559 * The extra PPP_FLAG will start up a new packet, and thus
560 * will flush any accumulated garbage. We do this whenever
561 * the line may have been idle for some time.
563 /* XXX as above. */
564 if (CCOUNT(&tp->t_outq) == 0) {
565 ++sc->sc_stats.ppp_obytes;
566 putc(PPP_FLAG, &tp->t_outq);
569 /* Calculate the FCS for the first mbuf's worth. */
570 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
571 getmicrotime(&sc->sc_if.if_lastchange);
574 for (;;) {
575 start = mtod(m, u_char *);
576 len = m->m_len;
577 stop = start + len;
578 while (len > 0) {
580 * Find out how many bytes in the string we can
581 * handle without doing something special.
583 for (cp = start; cp < stop; cp++)
584 if (ESCAPE_P(*cp))
585 break;
586 n = cp - start;
587 if (n) {
588 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
589 ndone = n - b_to_q(start, n, &tp->t_outq);
590 len -= ndone;
591 start += ndone;
592 sc->sc_stats.ppp_obytes += ndone;
594 if (ndone < n)
595 break; /* packet doesn't fit */
598 * If there are characters left in the mbuf,
599 * the first one must be special.
600 * Put it out in a different form.
602 if (len) {
603 crit_enter();
604 if (putc(PPP_ESCAPE, &tp->t_outq)) {
605 crit_exit();
606 break;
608 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
609 unputc(&tp->t_outq);
610 crit_exit();
611 break;
613 crit_exit();
614 sc->sc_stats.ppp_obytes += 2;
615 start++;
616 len--;
621 * If we didn't empty this mbuf, remember where we're up to.
622 * If we emptied the last mbuf, try to add the FCS and closing
623 * flag, and if we can't, leave sc_outm pointing to m, but with
624 * m->m_len == 0, to remind us to output the FCS and flag later.
626 done = len == 0;
627 if (done && m->m_next == NULL) {
628 u_char *p, *q;
629 int c;
630 u_char endseq[8];
633 * We may have to escape the bytes in the FCS.
635 p = endseq;
636 c = ~sc->sc_outfcs & 0xFF;
637 if (ESCAPE_P(c)) {
638 *p++ = PPP_ESCAPE;
639 *p++ = c ^ PPP_TRANS;
640 } else
641 *p++ = c;
642 c = (~sc->sc_outfcs >> 8) & 0xFF;
643 if (ESCAPE_P(c)) {
644 *p++ = PPP_ESCAPE;
645 *p++ = c ^ PPP_TRANS;
646 } else
647 *p++ = c;
648 *p++ = PPP_FLAG;
651 * Try to output the FCS and flag. If the bytes
652 * don't all fit, back out.
654 crit_enter();
655 for (q = endseq; q < p; ++q)
656 if (putc(*q, &tp->t_outq)) {
657 done = 0;
658 for (; q > endseq; --q)
659 unputc(&tp->t_outq);
660 break;
662 crit_exit();
663 if (done)
664 sc->sc_stats.ppp_obytes += q - endseq;
667 if (!done) {
668 /* remember where we got to */
669 m->m_data = start;
670 m->m_len = len;
671 break;
674 /* Finished with this mbuf; free it and move on. */
675 m = m_free(m);
676 if (m == NULL) {
677 /* Finished a packet */
678 break;
680 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
684 * If m == NULL, we have finished a packet.
685 * If m != NULL, we've either done as much work this time
686 * as we need to, or else we've filled up the output queue.
688 sc->sc_outm = m;
689 if (m)
690 break;
693 /* Call pppstart to start output again if necessary. */
694 crit_enter();
695 pppstart(tp);
698 * This timeout is needed for operation on a pseudo-tty,
699 * because the pty code doesn't call pppstart after it has
700 * drained the t_outq.
702 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
703 callout_reset(&sc->sc_timeout, 1, ppp_timeout, sc);
704 sc->sc_flags |= SC_TIMEOUT;
707 crit_exit();
711 * This gets called when a received packet is placed on
712 * the inq, at splsoftnet. The pppd daemon is to be woken up to do a read().
714 static void
715 pppasyncctlp(struct ppp_softc *sc)
717 struct tty *tp;
719 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
720 crit_enter();
721 tp = (struct tty *) sc->sc_devp;
722 putc(0, &tp->t_canq);
723 ttwakeup(tp);
724 crit_exit();
728 * Start output on async tty interface. If the transmit queue
729 * has drained sufficiently, arrange for pppasyncstart to be
730 * called later at splsoftnet.
731 * Called at spltty or higher.
734 pppstart(struct tty *tp)
736 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
739 * Call output process whether or not there is any output.
740 * We are being called in lieu of ttstart and must do what it would.
742 if (tp->t_oproc != NULL)
743 (*tp->t_oproc)(tp);
746 * If ALTQ is enabled, don't invoke NETISR_PPP.
747 * pppintr() could loop without doing anything useful
748 * under rate-limiting.
750 if (ifq_is_enabled(&sc->sc_if.if_snd))
751 return 0;
754 * If the transmit queue has drained and the tty has not hung up
755 * or been disconnected from the ppp unit, then tell if_ppp.c that
756 * we need more output.
758 if (CCOUNT(&tp->t_outq) < PPP_LOWAT
759 && !((tp->t_state & TS_CONNECTED) == 0)
760 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
761 ppp_restart(sc);
764 return 0;
768 * Timeout routine - try to start some more output.
770 static void
771 ppp_timeout(void *x)
773 struct ppp_softc *sc = (struct ppp_softc *) x;
774 struct tty *tp = (struct tty *) sc->sc_devp;
776 crit_enter();
777 sc->sc_flags &= ~SC_TIMEOUT;
778 pppstart(tp);
779 crit_exit();
783 * Allocate enough mbuf to handle current MRU.
785 static void
786 pppgetm(struct ppp_softc *sc)
788 struct mbuf *m, **mp;
789 int len;
791 mp = &sc->sc_m;
792 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
793 if ((m = *mp) == NULL) {
794 MGETHDR(m, MB_DONTWAIT, MT_DATA);
795 if (m == NULL)
796 break;
797 *mp = m;
798 MCLGET(m, MB_DONTWAIT);
800 len -= M_DATASIZE(m);
801 mp = &m->m_next;
806 * tty interface receiver interrupt.
808 static unsigned paritytab[8] = {
809 0x96696996, 0x69969669, 0x69969669, 0x96696996,
810 0x69969669, 0x96696996, 0x96696996, 0x69969669
814 * Called when character is available from device driver.
815 * Only guaranteed to be at splsofttty() or spltty()
816 * This is safe to be called while the upper half's netisr is preempted.
818 static int
819 pppinput(int c, struct tty *tp)
821 struct ppp_softc *sc;
822 struct mbuf *m;
823 int ilen;
825 sc = (struct ppp_softc *) tp->t_sc;
826 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
827 return 0;
829 ++tk_nin;
830 ++sc->sc_stats.ppp_ibytes;
832 if ((tp->t_state & TS_CONNECTED) == 0) {
833 if (sc->sc_flags & SC_DEBUG)
834 printf("%s: no carrier\n", sc->sc_if.if_xname);
835 goto flush;
838 if (c & TTY_ERRORMASK) {
839 /* framing error or overrun on this char - abort packet */
840 if (sc->sc_flags & SC_DEBUG)
841 printf("%s: line error %x\n", sc->sc_if.if_xname,
842 c & TTY_ERRORMASK);
843 goto flush;
846 c &= TTY_CHARMASK;
849 * Handle software flow control of output.
851 if (tp->t_iflag & IXON) {
852 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
853 if ((tp->t_state & TS_TTSTOP) == 0) {
854 tp->t_state |= TS_TTSTOP;
855 tp->t_stop(tp, 0);
857 return 0;
859 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
860 tp->t_state &= ~TS_TTSTOP;
861 if (tp->t_oproc != NULL)
862 (*tp->t_oproc)(tp);
863 return 0;
867 crit_enter();
868 if (c & 0x80)
869 sc->sc_flags |= SC_RCV_B7_1;
870 else
871 sc->sc_flags |= SC_RCV_B7_0;
872 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
873 sc->sc_flags |= SC_RCV_ODDP;
874 else
875 sc->sc_flags |= SC_RCV_EVNP;
876 crit_exit();
878 if (sc->sc_flags & SC_LOG_RAWIN)
879 ppplogchar(sc, c);
881 if (c == PPP_FLAG) {
882 ilen = sc->sc_ilen;
883 sc->sc_ilen = 0;
885 if (sc->sc_rawin_count > 0)
886 ppplogchar(sc, -1);
889 * If SC_ESCAPED is set, then we've seen the packet
890 * abort sequence "}~".
892 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
893 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
894 crit_enter();
895 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
896 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
897 if (sc->sc_flags & SC_DEBUG)
898 printf("%s: bad fcs %x, pkt len %d\n",
899 sc->sc_if.if_xname, sc->sc_fcs, ilen);
900 sc->sc_if.if_ierrors++;
901 sc->sc_stats.ppp_ierrors++;
902 } else
903 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
904 crit_exit();
905 return 0;
908 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
909 if (ilen) {
910 if (sc->sc_flags & SC_DEBUG)
911 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
912 crit_enter();
913 sc->sc_if.if_ierrors++;
914 sc->sc_stats.ppp_ierrors++;
915 sc->sc_flags |= SC_PKTLOST;
916 crit_exit();
918 return 0;
922 * Remove FCS trailer. Somewhat painful...
924 ilen -= 2;
925 if (--sc->sc_mc->m_len == 0) {
926 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
928 sc->sc_mc = m;
930 sc->sc_mc->m_len--;
932 /* excise this mbuf chain */
933 m = sc->sc_m;
934 sc->sc_m = sc->sc_mc->m_next;
935 sc->sc_mc->m_next = NULL;
937 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
938 if (sc->sc_flags & SC_PKTLOST) {
939 crit_enter();
940 sc->sc_flags &= ~SC_PKTLOST;
941 crit_exit();
944 pppgetm(sc);
945 return 0;
948 if (sc->sc_flags & SC_FLUSH) {
949 if (sc->sc_flags & SC_LOG_FLUSH)
950 ppplogchar(sc, c);
951 return 0;
954 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
955 return 0;
957 crit_enter();
958 if (sc->sc_flags & SC_ESCAPED) {
959 sc->sc_flags &= ~SC_ESCAPED;
960 c ^= PPP_TRANS;
961 } else if (c == PPP_ESCAPE) {
962 sc->sc_flags |= SC_ESCAPED;
963 crit_exit();
964 return 0;
966 crit_exit();
969 * Initialize buffer on first octet received.
970 * First octet could be address or protocol (when compressing
971 * address/control).
972 * Second octet is control.
973 * Third octet is first or second (when compressing protocol)
974 * octet of protocol.
975 * Fourth octet is second octet of protocol.
977 if (sc->sc_ilen == 0) {
978 /* reset the first input mbuf */
979 if (sc->sc_m == NULL) {
980 pppgetm(sc);
981 if (sc->sc_m == NULL) {
982 if (sc->sc_flags & SC_DEBUG)
983 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
984 goto flush;
987 m = sc->sc_m;
988 m->m_len = 0;
989 m->m_data = M_DATASTART(sc->sc_m);
990 sc->sc_mc = m;
991 sc->sc_mp = mtod(m, char *);
992 sc->sc_fcs = PPP_INITFCS;
993 if (c != PPP_ALLSTATIONS) {
994 if (sc->sc_flags & SC_REJ_COMP_AC) {
995 if (sc->sc_flags & SC_DEBUG)
996 printf("%s: garbage received: 0x%x (need 0xFF)\n",
997 sc->sc_if.if_xname, c);
998 goto flush;
1000 *sc->sc_mp++ = PPP_ALLSTATIONS;
1001 *sc->sc_mp++ = PPP_UI;
1002 sc->sc_ilen += 2;
1003 m->m_len += 2;
1006 if (sc->sc_ilen == 1 && c != PPP_UI) {
1007 if (sc->sc_flags & SC_DEBUG)
1008 printf("%s: missing UI (0x3), got 0x%x\n",
1009 sc->sc_if.if_xname, c);
1010 goto flush;
1012 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1013 /* a compressed protocol */
1014 *sc->sc_mp++ = 0;
1015 sc->sc_ilen++;
1016 sc->sc_mc->m_len++;
1018 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1019 if (sc->sc_flags & SC_DEBUG)
1020 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1021 (sc->sc_mp[-1] << 8) + c);
1022 goto flush;
1025 /* packet beyond configured mru? */
1026 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1027 if (sc->sc_flags & SC_DEBUG)
1028 printf("%s: packet too big\n", sc->sc_if.if_xname);
1029 goto flush;
1032 /* is this mbuf full? */
1033 m = sc->sc_mc;
1034 if (M_TRAILINGSPACE(m) <= 0) {
1035 if (m->m_next == NULL) {
1036 pppgetm(sc);
1037 if (m->m_next == NULL) {
1038 if (sc->sc_flags & SC_DEBUG)
1039 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1040 goto flush;
1043 sc->sc_mc = m = m->m_next;
1044 m->m_len = 0;
1045 m->m_data = M_DATASTART(m);
1046 sc->sc_mp = mtod(m, char *);
1049 ++m->m_len;
1050 *sc->sc_mp++ = c;
1051 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1052 return 0;
1054 flush:
1055 if (!(sc->sc_flags & SC_FLUSH)) {
1056 crit_enter();
1057 sc->sc_if.if_ierrors++;
1058 sc->sc_stats.ppp_ierrors++;
1059 sc->sc_flags |= SC_FLUSH;
1060 crit_exit();
1061 if (sc->sc_flags & SC_LOG_FLUSH)
1062 ppplogchar(sc, c);
1064 return 0;
1067 #define MAX_DUMP_BYTES 128
1069 static void
1070 ppplogchar(struct ppp_softc *sc, int c)
1072 if (c >= 0)
1073 sc->sc_rawin[sc->sc_rawin_count++] = c;
1074 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1075 || (c < 0 && sc->sc_rawin_count > 0)) {
1076 printf("%s input: %*D", sc->sc_if.if_xname,
1077 sc->sc_rawin_count, sc->sc_rawin, " ");
1078 sc->sc_rawin_count = 0;