part2 ppX fix for altq/pf.
[dfdiff.git] / sys / net / ppp_layer / ppp_tty.c
blobf6beccfea0671dd3af671d7f1138a6a505e12e64
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.24 2007/08/24 16:06:37 dillon 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 #include <net/if.h>
94 #include <net/ifq_var.h>
96 #ifdef PPP_FILTER
97 #include <net/bpf.h>
98 #endif
99 #include <net/ppp/if_ppp.h>
100 #include <net/ppp/if_pppvar.h>
102 static int pppopen (cdev_t dev, struct tty *tp);
103 static int pppclose (struct tty *tp, int flag);
104 static int pppread (struct tty *tp, struct uio *uio, int flag);
105 static int pppwrite (struct tty *tp, struct uio *uio, int flag);
106 static int ppptioctl (struct tty *tp, u_long cmd, caddr_t data,
107 int flag, struct ucred *);
108 static int pppinput (int c, struct tty *tp);
109 static int pppstart (struct tty *tp);
111 static u_short pppfcs (u_short fcs, u_char *cp, int len);
112 static void pppasyncstart (struct ppp_softc *);
113 static void pppasyncctlp (struct ppp_softc *);
114 static void pppasyncrelinq (struct ppp_softc *);
115 static void pppasyncsetmtu (struct ppp_softc *);
116 static void ppp_timeout (void *);
117 static void pppgetm (struct ppp_softc *sc);
118 static void ppplogchar (struct ppp_softc *, int);
120 /* XXX called from if_ppp.c - layering violation */
121 void pppasyncattach (void *);
124 * Some useful mbuf macros not in mbuf.h.
126 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
128 #define M_DATASTART(m) \
129 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
130 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
132 #define M_DATASIZE(m) \
133 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
134 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
137 * Does c need to be escaped?
139 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
142 * Procedures for using an async tty interface for PPP.
145 /* This is a FreeBSD-2.X kernel. */
146 #define CCOUNT(q) ((q)->c_cc)
147 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
148 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
151 * Define the PPP line discipline.
154 static struct linesw pppdisc = {
155 pppopen, pppclose, pppread, pppwrite,
156 ppptioctl, pppinput, pppstart, ttymodem,
157 PPP_FLAG
160 void
161 pppasyncattach(void *dummy)
163 /* register line discipline */
164 linesw[PPPDISC] = pppdisc;
168 * Line specific open routine for async tty devices.
169 * Attach the given tty to the first available ppp unit.
170 * Called from device open routine or ttioctl() at >= splsofttty()
172 /* ARGSUSED */
173 static int
174 pppopen(cdev_t dev, struct tty *tp)
176 struct thread *td = curthread; /* XXX */
177 struct ppp_softc *sc;
178 int error;
180 if ((error = suser(td)) != 0)
181 return (error);
183 crit_enter();
185 if (tp->t_line == PPPDISC) {
186 sc = (struct ppp_softc *) tp->t_sc;
187 if (sc != NULL && sc->sc_devp == (void *) tp) {
188 crit_exit();
189 return (0);
193 if ((sc = pppalloc(td)) == NULL) {
194 crit_exit();
195 return ENXIO;
198 if (sc->sc_relinq)
199 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
201 sc->sc_ilen = 0;
202 sc->sc_m = NULL;
203 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
204 sc->sc_asyncmap[0] = 0xffffffff;
205 sc->sc_asyncmap[3] = 0x60000000;
206 sc->sc_rasyncmap = 0;
207 sc->sc_devp = (void *) tp;
208 sc->sc_start = pppasyncstart;
209 sc->sc_ctlp = pppasyncctlp;
210 sc->sc_relinq = pppasyncrelinq;
211 sc->sc_setmtu = pppasyncsetmtu;
212 sc->sc_outm = NULL;
213 pppgetm(sc);
214 sc->sc_if.if_flags |= IFF_RUNNING;
215 getmicrotime(&sc->sc_if.if_lastchange);
216 sc->sc_if.if_baudrate = tp->t_ospeed;
218 tp->t_sc = (caddr_t) sc;
219 ttyflush(tp, FREAD | FWRITE);
222 * Pre-allocate cblocks to the "just right" amount. The 1 byte t_canq
223 * allocation helps avoid the need for select and/or FIONREAD.
224 * We also pass 1 byte tokens through t_canq...
226 clist_alloc_cblocks(&tp->t_canq, 1, 1);
227 clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT,
228 sc->sc_if.if_mtu + PPP_HIWAT);
229 clist_alloc_cblocks(&tp->t_rawq, 0, 0);
231 crit_exit();
233 return (0);
237 * Line specific close routine, called from device close routine
238 * and from ttioctl at >= splsofttty().
239 * Detach the tty from the ppp unit.
240 * Mimics part of ttyclose().
242 static int
243 pppclose(struct tty *tp, int flag)
245 struct ppp_softc *sc;
247 crit_enter();
248 ttyflush(tp, FREAD | FWRITE);
249 clist_free_cblocks(&tp->t_canq);
250 clist_free_cblocks(&tp->t_outq);
251 tp->t_line = 0;
252 sc = (struct ppp_softc *) tp->t_sc;
253 if (sc != NULL) {
254 tp->t_sc = NULL;
255 if (tp == (struct tty *) sc->sc_devp) {
256 pppasyncrelinq(sc);
257 pppdealloc(sc);
260 crit_exit();
261 return 0;
265 * Relinquish the interface unit to another device.
267 static void
268 pppasyncrelinq(struct ppp_softc *sc)
270 crit_enter();
272 if (sc->sc_outm) {
273 m_freem(sc->sc_outm);
274 sc->sc_outm = NULL;
276 if (sc->sc_m) {
277 m_freem(sc->sc_m);
278 sc->sc_m = NULL;
280 if (sc->sc_flags & SC_TIMEOUT) {
281 callout_stop(&sc->sc_timeout);
282 sc->sc_flags &= ~SC_TIMEOUT;
285 crit_exit();
289 * This gets called from the upper layer to notify a mtu change
291 static void
292 pppasyncsetmtu(struct ppp_softc *sc)
294 struct tty *tp = (struct tty *) sc->sc_devp;
296 crit_enter();
297 if (tp != NULL)
298 clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT,
299 sc->sc_if.if_mtu + PPP_HIWAT);
300 crit_exit();
304 * Line specific (tty) read routine.
305 * called at zero spl from the device driver in the response to user-level
306 * reads on the tty file descriptor (ie: pppd).
308 static int
309 pppread(struct tty *tp, struct uio *uio, int flag)
311 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
312 struct mbuf *m, *m0;
313 int error = 0;
315 if (sc == NULL)
316 return 0;
318 * Loop waiting for input, checking that nothing disasterous
319 * happens in the meantime.
321 crit_enter();
322 for (;;) {
323 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
324 crit_exit();
325 return 0;
327 if (sc->sc_inq.ifq_head != NULL)
328 break;
329 if ((tp->t_state & TS_CONNECTED) == 0) {
330 crit_exit();
331 return 0; /* end of file */
333 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
334 crit_exit();
335 return (EWOULDBLOCK);
337 error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), PCATCH, "pppin", 0);
338 if (error) {
339 crit_exit();
340 return error;
344 /* Pull place-holder byte out of canonical queue */
345 clist_getc(&tp->t_canq);
347 /* Get the packet from the input queue */
348 IF_DEQUEUE(&sc->sc_inq, m0);
349 crit_exit();
351 for (m = m0; m && uio->uio_resid; m = m->m_next)
352 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
353 break;
354 m_freem(m0);
355 return (error);
359 * Line specific (tty) write routine.
360 * called at zero spl from the device driver in the response to user-level
361 * writes on the tty file descriptor (ie: pppd).
363 static int
364 pppwrite(struct tty *tp, struct uio *uio, int flag)
366 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
367 struct mbuf *m, *m0, **mp;
368 struct sockaddr dst;
369 int len, error;
371 if ((tp->t_state & TS_CONNECTED) == 0)
372 return 0; /* wrote 0 bytes */
373 if (tp->t_line != PPPDISC)
374 return (EINVAL);
375 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
376 return EIO;
377 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
378 uio->uio_resid < PPP_HDRLEN)
379 return (EMSGSIZE);
381 crit_enter();
382 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
383 if (mp == &m0) {
384 MGETHDR(m, MB_WAIT, MT_DATA);
385 m->m_pkthdr.len = uio->uio_resid - PPP_HDRLEN;
386 m->m_pkthdr.rcvif = NULL;
387 } else {
388 MGET(m, MB_WAIT, MT_DATA);
390 if ((*mp = m) == NULL) {
391 m_freem(m0);
392 crit_exit();
393 return (ENOBUFS);
395 m->m_len = 0;
396 if (uio->uio_resid >= MCLBYTES / 2)
397 MCLGET(m, MB_DONTWAIT);
398 len = M_TRAILINGSPACE(m);
399 if (len > uio->uio_resid)
400 len = uio->uio_resid;
401 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
402 m_freem(m0);
403 crit_exit();
404 return (error);
406 m->m_len = len;
408 dst.sa_family = AF_UNSPEC;
409 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
410 m0->m_data += PPP_HDRLEN;
411 m0->m_len -= PPP_HDRLEN;
413 /* call the upper layer to "transmit" it... */
414 lwkt_serialize_enter(sc->sc_if.if_serializer);
415 error = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0);
416 lwkt_serialize_exit(sc->sc_if.if_serializer);
417 crit_exit();
418 return (error);
422 * Line specific (tty) ioctl routine.
423 * This discipline requires that tty device drivers call
424 * the line specific l_ioctl routine from their ioctl routines.
426 /* ARGSUSED */
427 static int
428 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct ucred *cr)
430 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
431 int error;
433 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
434 return (ENOIOCTL);
436 error = 0;
437 switch (cmd) {
438 case PPPIOCSASYNCMAP:
439 if ((error = suser_cred(cr, 0)) != 0)
440 break;
441 sc->sc_asyncmap[0] = *(u_int *)data;
442 break;
444 case PPPIOCGASYNCMAP:
445 *(u_int *)data = sc->sc_asyncmap[0];
446 break;
448 case PPPIOCSRASYNCMAP:
449 if ((error = suser_cred(cr, 0)) != 0)
450 break;
451 sc->sc_rasyncmap = *(u_int *)data;
452 break;
454 case PPPIOCGRASYNCMAP:
455 *(u_int *)data = sc->sc_rasyncmap;
456 break;
458 case PPPIOCSXASYNCMAP:
459 if ((error = suser_cred(cr, 0)) != 0)
460 break;
461 crit_enter();
462 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
463 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
464 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
465 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
466 crit_exit();
467 break;
469 case PPPIOCGXASYNCMAP:
470 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
471 break;
473 default:
474 error = pppioctl(sc, cmd, data, flag, cr);
475 if (error == 0 && cmd == PPPIOCSMRU)
476 pppgetm(sc);
479 return error;
483 * FCS lookup table as calculated by genfcstab.
485 static u_short fcstab[256] = {
486 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
487 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
488 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
489 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
490 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
491 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
492 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
493 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
494 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
495 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
496 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
497 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
498 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
499 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
500 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
501 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
502 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
503 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
504 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
505 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
506 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
507 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
508 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
509 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
510 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
511 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
512 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
513 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
514 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
515 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
516 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
517 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
521 * Calculate a new FCS given the current FCS and the new data.
523 static u_short
524 pppfcs(u_short fcs, u_char *cp, int len)
526 while (len--)
527 fcs = PPP_FCS(fcs, *cp++);
528 return (fcs);
532 * This gets called at splsoftnet from if_ppp.c at various times
533 * when there is data ready to be sent.
535 static void
536 pppasyncstart(struct ppp_softc *sc)
538 struct tty *tp = (struct tty *) sc->sc_devp;
539 struct mbuf *m;
540 int len;
541 u_char *start, *stop, *cp;
542 int n, ndone, done, idle;
544 idle = 0;
545 /* XXX assumes atomic access to *tp although we're not at spltty(). */
546 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
548 * See if we have an existing packet partly sent.
549 * If not, get a new packet and start sending it.
551 m = sc->sc_outm;
552 if (m == NULL) {
554 * Get another packet to be sent.
556 m = ppp_dequeue(sc);
557 if (m == NULL) {
558 idle = 1;
559 break;
563 * The extra PPP_FLAG will start up a new packet, and thus
564 * will flush any accumulated garbage. We do this whenever
565 * the line may have been idle for some time.
567 /* XXX as above. */
568 if (CCOUNT(&tp->t_outq) == 0) {
569 ++sc->sc_stats.ppp_obytes;
570 clist_putc(PPP_FLAG, &tp->t_outq);
573 /* Calculate the FCS for the first mbuf's worth. */
574 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
575 getmicrotime(&sc->sc_if.if_lastchange);
578 for (;;) {
579 start = mtod(m, u_char *);
580 len = m->m_len;
581 stop = start + len;
582 while (len > 0) {
584 * Find out how many bytes in the string we can
585 * handle without doing something special.
587 for (cp = start; cp < stop; cp++)
588 if (ESCAPE_P(*cp))
589 break;
590 n = cp - start;
591 if (n) {
592 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
593 ndone = n - b_to_q(start, n, &tp->t_outq);
594 len -= ndone;
595 start += ndone;
596 sc->sc_stats.ppp_obytes += ndone;
598 if (ndone < n)
599 break; /* packet doesn't fit */
602 * If there are characters left in the mbuf,
603 * the first one must be special.
604 * Put it out in a different form.
606 if (len) {
607 crit_enter();
608 if (clist_putc(PPP_ESCAPE, &tp->t_outq)) {
609 crit_exit();
610 break;
612 if (clist_putc(*start ^ PPP_TRANS, &tp->t_outq)) {
613 clist_unputc(&tp->t_outq);
614 crit_exit();
615 break;
617 crit_exit();
618 sc->sc_stats.ppp_obytes += 2;
619 start++;
620 len--;
625 * If we didn't empty this mbuf, remember where we're up to.
626 * If we emptied the last mbuf, try to add the FCS and closing
627 * flag, and if we can't, leave sc_outm pointing to m, but with
628 * m->m_len == 0, to remind us to output the FCS and flag later.
630 done = len == 0;
631 if (done && m->m_next == NULL) {
632 u_char *p, *q;
633 int c;
634 u_char endseq[8];
637 * We may have to escape the bytes in the FCS.
639 p = endseq;
640 c = ~sc->sc_outfcs & 0xFF;
641 if (ESCAPE_P(c)) {
642 *p++ = PPP_ESCAPE;
643 *p++ = c ^ PPP_TRANS;
644 } else
645 *p++ = c;
646 c = (~sc->sc_outfcs >> 8) & 0xFF;
647 if (ESCAPE_P(c)) {
648 *p++ = PPP_ESCAPE;
649 *p++ = c ^ PPP_TRANS;
650 } else
651 *p++ = c;
652 *p++ = PPP_FLAG;
655 * Try to output the FCS and flag. If the bytes
656 * don't all fit, back out.
658 crit_enter();
659 for (q = endseq; q < p; ++q)
660 if (clist_putc(*q, &tp->t_outq)) {
661 done = 0;
662 for (; q > endseq; --q)
663 clist_unputc(&tp->t_outq);
664 break;
666 crit_exit();
667 if (done)
668 sc->sc_stats.ppp_obytes += q - endseq;
671 if (!done) {
672 /* remember where we got to */
673 m->m_data = start;
674 m->m_len = len;
675 break;
678 /* Finished with this mbuf; free it and move on. */
679 m = m_free(m);
680 if (m == NULL) {
681 /* Finished a packet */
682 break;
684 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
688 * If m == NULL, we have finished a packet.
689 * If m != NULL, we've either done as much work this time
690 * as we need to, or else we've filled up the output queue.
692 sc->sc_outm = m;
693 if (m)
694 break;
697 /* Call pppstart to start output again if necessary. */
698 crit_enter();
699 pppstart(tp);
702 * This timeout is needed for operation on a pseudo-tty,
703 * because the pty code doesn't call pppstart after it has
704 * drained the t_outq.
706 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
707 callout_reset(&sc->sc_timeout, 1, ppp_timeout, sc);
708 sc->sc_flags |= SC_TIMEOUT;
711 crit_exit();
715 * This gets called when a received packet is placed on
716 * the inq, at splsoftnet. The pppd daemon is to be woken up to do a read().
718 static void
719 pppasyncctlp(struct ppp_softc *sc)
721 struct tty *tp;
723 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
724 crit_enter();
725 tp = (struct tty *) sc->sc_devp;
726 clist_putc(0, &tp->t_canq);
727 ttwakeup(tp);
728 crit_exit();
732 * Start output on async tty interface. If the transmit queue
733 * has drained sufficiently, arrange for pppasyncstart to be
734 * called later at splsoftnet.
735 * Called at spltty or higher.
738 pppstart(struct tty *tp)
740 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
743 * Call output process whether or not there is any output.
744 * We are being called in lieu of ttstart and must do what it would.
746 if (tp->t_oproc != NULL)
747 (*tp->t_oproc)(tp);
750 * If ALTQ is enabled, don't invoke NETISR_PPP.
751 * pppintr() could loop without doing anything useful
752 * under rate-limiting.
754 if (ifq_is_enabled(&sc->sc_if.if_snd))
755 return 0;
758 * If the transmit queue has drained and the tty has not hung up
759 * or been disconnected from the ppp unit, then tell if_ppp.c that
760 * we need more output.
762 if (CCOUNT(&tp->t_outq) < PPP_LOWAT
763 && !((tp->t_state & TS_CONNECTED) == 0)
764 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
765 ppp_restart(sc);
768 return 0;
772 * Timeout routine - try to start some more output.
774 static void
775 ppp_timeout(void *x)
777 struct ppp_softc *sc = (struct ppp_softc *) x;
778 struct tty *tp = (struct tty *) sc->sc_devp;
780 crit_enter();
781 sc->sc_flags &= ~SC_TIMEOUT;
782 pppstart(tp);
783 crit_exit();
787 * Allocate enough mbuf to handle current MRU.
789 static void
790 pppgetm(struct ppp_softc *sc)
792 struct mbuf *m, **mp;
793 int len;
795 mp = &sc->sc_m;
796 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
797 if ((m = *mp) == NULL) {
798 MGETHDR(m, MB_DONTWAIT, MT_DATA);
799 if (m == NULL)
800 break;
801 *mp = m;
802 MCLGET(m, MB_DONTWAIT);
804 len -= M_DATASIZE(m);
805 mp = &m->m_next;
810 * tty interface receiver interrupt.
812 static unsigned paritytab[8] = {
813 0x96696996, 0x69969669, 0x69969669, 0x96696996,
814 0x69969669, 0x96696996, 0x96696996, 0x69969669
818 * Called when character is available from device driver.
819 * Only guaranteed to be at splsofttty() or spltty()
820 * This is safe to be called while the upper half's netisr is preempted.
822 static int
823 pppinput(int c, struct tty *tp)
825 struct ppp_softc *sc;
826 struct mbuf *m;
827 int ilen;
829 sc = (struct ppp_softc *) tp->t_sc;
830 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
831 return 0;
833 ++tk_nin;
834 ++sc->sc_stats.ppp_ibytes;
836 if ((tp->t_state & TS_CONNECTED) == 0) {
837 if (sc->sc_flags & SC_DEBUG)
838 kprintf("%s: no carrier\n", sc->sc_if.if_xname);
839 goto flush;
842 if (c & TTY_ERRORMASK) {
843 /* framing error or overrun on this char - abort packet */
844 if (sc->sc_flags & SC_DEBUG)
845 kprintf("%s: line error %x\n", sc->sc_if.if_xname,
846 c & TTY_ERRORMASK);
847 goto flush;
850 c &= TTY_CHARMASK;
853 * Handle software flow control of output.
855 if (tp->t_iflag & IXON) {
856 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
857 if ((tp->t_state & TS_TTSTOP) == 0) {
858 tp->t_state |= TS_TTSTOP;
859 tp->t_stop(tp, 0);
861 return 0;
863 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
864 tp->t_state &= ~TS_TTSTOP;
865 if (tp->t_oproc != NULL)
866 (*tp->t_oproc)(tp);
867 return 0;
871 crit_enter();
872 if (c & 0x80)
873 sc->sc_flags |= SC_RCV_B7_1;
874 else
875 sc->sc_flags |= SC_RCV_B7_0;
876 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
877 sc->sc_flags |= SC_RCV_ODDP;
878 else
879 sc->sc_flags |= SC_RCV_EVNP;
880 crit_exit();
882 if (sc->sc_flags & SC_LOG_RAWIN)
883 ppplogchar(sc, c);
885 if (c == PPP_FLAG) {
886 ilen = sc->sc_ilen;
887 sc->sc_ilen = 0;
889 if (sc->sc_rawin_count > 0)
890 ppplogchar(sc, -1);
893 * If SC_ESCAPED is set, then we've seen the packet
894 * abort sequence "}~".
896 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
897 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
898 crit_enter();
899 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
900 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
901 if (sc->sc_flags & SC_DEBUG)
902 kprintf("%s: bad fcs %x, pkt len %d\n",
903 sc->sc_if.if_xname, sc->sc_fcs, ilen);
904 sc->sc_if.if_ierrors++;
905 sc->sc_stats.ppp_ierrors++;
906 } else
907 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
908 crit_exit();
909 return 0;
912 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
913 if (ilen) {
914 if (sc->sc_flags & SC_DEBUG)
915 kprintf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
916 crit_enter();
917 sc->sc_if.if_ierrors++;
918 sc->sc_stats.ppp_ierrors++;
919 sc->sc_flags |= SC_PKTLOST;
920 crit_exit();
922 return 0;
926 * Remove FCS trailer. Somewhat painful...
928 ilen -= 2;
929 if (--sc->sc_mc->m_len == 0) {
930 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
932 sc->sc_mc = m;
934 sc->sc_mc->m_len--;
936 /* excise this mbuf chain */
937 m = sc->sc_m;
938 sc->sc_m = sc->sc_mc->m_next;
939 sc->sc_mc->m_next = NULL;
941 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
942 if (sc->sc_flags & SC_PKTLOST) {
943 crit_enter();
944 sc->sc_flags &= ~SC_PKTLOST;
945 crit_exit();
948 pppgetm(sc);
949 return 0;
952 if (sc->sc_flags & SC_FLUSH) {
953 if (sc->sc_flags & SC_LOG_FLUSH)
954 ppplogchar(sc, c);
955 return 0;
958 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
959 return 0;
961 crit_enter();
962 if (sc->sc_flags & SC_ESCAPED) {
963 sc->sc_flags &= ~SC_ESCAPED;
964 c ^= PPP_TRANS;
965 } else if (c == PPP_ESCAPE) {
966 sc->sc_flags |= SC_ESCAPED;
967 crit_exit();
968 return 0;
970 crit_exit();
973 * Initialize buffer on first octet received.
974 * First octet could be address or protocol (when compressing
975 * address/control).
976 * Second octet is control.
977 * Third octet is first or second (when compressing protocol)
978 * octet of protocol.
979 * Fourth octet is second octet of protocol.
981 if (sc->sc_ilen == 0) {
982 /* reset the first input mbuf */
983 if (sc->sc_m == NULL) {
984 pppgetm(sc);
985 if (sc->sc_m == NULL) {
986 if (sc->sc_flags & SC_DEBUG)
987 kprintf("%s: no input mbufs!\n", sc->sc_if.if_xname);
988 goto flush;
991 m = sc->sc_m;
992 m->m_len = 0;
993 m->m_data = M_DATASTART(sc->sc_m);
994 sc->sc_mc = m;
995 sc->sc_mp = mtod(m, char *);
996 sc->sc_fcs = PPP_INITFCS;
997 if (c != PPP_ALLSTATIONS) {
998 if (sc->sc_flags & SC_REJ_COMP_AC) {
999 if (sc->sc_flags & SC_DEBUG)
1000 kprintf("%s: garbage received: 0x%x (need 0xFF)\n",
1001 sc->sc_if.if_xname, c);
1002 goto flush;
1004 *sc->sc_mp++ = PPP_ALLSTATIONS;
1005 *sc->sc_mp++ = PPP_UI;
1006 sc->sc_ilen += 2;
1007 m->m_len += 2;
1010 if (sc->sc_ilen == 1 && c != PPP_UI) {
1011 if (sc->sc_flags & SC_DEBUG)
1012 kprintf("%s: missing UI (0x3), got 0x%x\n",
1013 sc->sc_if.if_xname, c);
1014 goto flush;
1016 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1017 /* a compressed protocol */
1018 *sc->sc_mp++ = 0;
1019 sc->sc_ilen++;
1020 sc->sc_mc->m_len++;
1022 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1023 if (sc->sc_flags & SC_DEBUG)
1024 kprintf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1025 (sc->sc_mp[-1] << 8) + c);
1026 goto flush;
1029 /* packet beyond configured mru? */
1030 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1031 if (sc->sc_flags & SC_DEBUG)
1032 kprintf("%s: packet too big\n", sc->sc_if.if_xname);
1033 goto flush;
1036 /* is this mbuf full? */
1037 m = sc->sc_mc;
1038 if (M_TRAILINGSPACE(m) <= 0) {
1039 if (m->m_next == NULL) {
1040 pppgetm(sc);
1041 if (m->m_next == NULL) {
1042 if (sc->sc_flags & SC_DEBUG)
1043 kprintf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1044 goto flush;
1047 sc->sc_mc = m = m->m_next;
1048 m->m_len = 0;
1049 m->m_data = M_DATASTART(m);
1050 sc->sc_mp = mtod(m, char *);
1053 ++m->m_len;
1054 *sc->sc_mp++ = c;
1055 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1056 return 0;
1058 flush:
1059 if (!(sc->sc_flags & SC_FLUSH)) {
1060 crit_enter();
1061 sc->sc_if.if_ierrors++;
1062 sc->sc_stats.ppp_ierrors++;
1063 sc->sc_flags |= SC_FLUSH;
1064 crit_exit();
1065 if (sc->sc_flags & SC_LOG_FLUSH)
1066 ppplogchar(sc, c);
1068 return 0;
1071 #define MAX_DUMP_BYTES 128
1073 static void
1074 ppplogchar(struct ppp_softc *sc, int c)
1076 if (c >= 0)
1077 sc->sc_rawin[sc->sc_rawin_count++] = c;
1078 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1079 || (c < 0 && sc->sc_rawin_count > 0)) {
1080 kprintf("%s input: %*D", sc->sc_if.if_xname,
1081 sc->sc_rawin_count, sc->sc_rawin, " ");
1082 sc->sc_rawin_count = 0;