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