ppp_tty.c revision 1.12 1 /* $NetBSD: ppp_tty.c,v 1.12 1997/03/24 21:23:10 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 splx(s);
577 break;
578 }
579 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
580 (void) unputc(&tp->t_outq);
581 splx(s);
582 break;
583 }
584 splx(s);
585 sc->sc_stats.ppp_obytes += 2;
586 start++;
587 len--;
588 }
589 }
590
591 /*
592 * If we didn't empty this mbuf, remember where we're up to.
593 * If we emptied the last mbuf, try to add the FCS and closing
594 * flag, and if we can't, leave sc_outm pointing to m, but with
595 * m->m_len == 0, to remind us to output the FCS and flag later.
596 */
597 done = len == 0;
598 if (done && m->m_next == NULL) {
599 u_char *p, *q;
600 int c;
601 u_char endseq[8];
602
603 /*
604 * We may have to escape the bytes in the FCS.
605 */
606 p = endseq;
607 c = ~sc->sc_outfcs & 0xFF;
608 if (ESCAPE_P(c)) {
609 *p++ = PPP_ESCAPE;
610 *p++ = c ^ PPP_TRANS;
611 } else
612 *p++ = c;
613 c = (~sc->sc_outfcs >> 8) & 0xFF;
614 if (ESCAPE_P(c)) {
615 *p++ = PPP_ESCAPE;
616 *p++ = c ^ PPP_TRANS;
617 } else
618 *p++ = c;
619 *p++ = PPP_FLAG;
620
621 /*
622 * Try to output the FCS and flag. If the bytes
623 * don't all fit, back out.
624 */
625 s = spltty();
626 for (q = endseq; q < p; ++q)
627 if (putc(*q, &tp->t_outq)) {
628 done = 0;
629 for (; q > endseq; --q)
630 unputc(&tp->t_outq);
631 break;
632 }
633 splx(s);
634 if (done)
635 sc->sc_stats.ppp_obytes += q - endseq;
636 }
637
638 if (!done) {
639 /* remember where we got to */
640 m->m_data = start;
641 m->m_len = len;
642 break;
643 }
644
645 /* Finished with this mbuf; free it and move on. */
646 MFREE(m, m2);
647 m = m2;
648 if (m == NULL) {
649 /* Finished a packet */
650 break;
651 }
652 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
653 }
654
655 /*
656 * If m == NULL, we have finished a packet.
657 * If m != NULL, we've either done as much work this time
658 * as we need to, or else we've filled up the output queue.
659 */
660 sc->sc_outm = m;
661 if (m)
662 break;
663 }
664
665 /* Call pppstart to start output again if necessary. */
666 s = spltty();
667 pppstart(tp);
668
669 /*
670 * This timeout is needed for operation on a pseudo-tty,
671 * because the pty code doesn't call pppstart after it has
672 * drained the t_outq.
673 */
674 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
675 timeout(ppp_timeout, (void *) sc, 1);
676 sc->sc_flags |= SC_TIMEOUT;
677 }
678
679 splx(s);
680 }
681
682 /*
683 * This gets called when a received packet is placed on
684 * the inq, at splsoftnet.
685 */
686 static void
687 pppasyncctlp(sc)
688 struct ppp_softc *sc;
689 {
690 struct tty *tp;
691 int s;
692
693 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
694 s = spltty();
695 tp = (struct tty *) sc->sc_devp;
696 putc(0, &tp->t_canq);
697 ttwakeup(tp);
698 splx(s);
699 }
700
701 /*
702 * Start output on async tty interface. If the transmit queue
703 * has drained sufficiently, arrange for pppasyncstart to be
704 * called later at splsoftnet.
705 * Called at spltty or higher.
706 */
707 int
708 pppstart(tp)
709 register struct tty *tp;
710 {
711 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
712
713 /*
714 * If there is stuff in the output queue, send it now.
715 * We are being called in lieu of ttstart and must do what it would.
716 */
717 if (tp->t_oproc != NULL)
718 (*tp->t_oproc)(tp);
719
720 /*
721 * If the transmit queue has drained and the tty has not hung up
722 * or been disconnected from the ppp unit, then tell if_ppp.c that
723 * we need more output.
724 */
725 if (CCOUNT(&tp->t_outq) < PPP_LOWAT
726 && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
727 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
728 ppp_restart(sc);
729 }
730
731 return 0;
732 }
733
734 /*
735 * Timeout routine - try to start some more output.
736 */
737 static void
738 ppp_timeout(x)
739 void *x;
740 {
741 struct ppp_softc *sc = (struct ppp_softc *) x;
742 struct tty *tp = (struct tty *) sc->sc_devp;
743 int s;
744
745 s = spltty();
746 sc->sc_flags &= ~SC_TIMEOUT;
747 pppstart(tp);
748 splx(s);
749 }
750
751 /*
752 * Allocate enough mbuf to handle current MRU.
753 */
754 static void
755 pppgetm(sc)
756 register struct ppp_softc *sc;
757 {
758 struct mbuf *m, **mp;
759 int len;
760
761 mp = &sc->sc_m;
762 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
763 if ((m = *mp) == NULL) {
764 MGETHDR(m, M_DONTWAIT, MT_DATA);
765 if (m == NULL)
766 break;
767 *mp = m;
768 MCLGET(m, M_DONTWAIT);
769 }
770 len -= M_DATASIZE(m);
771 mp = &m->m_next;
772 }
773 }
774
775 /*
776 * tty interface receiver interrupt.
777 */
778 static unsigned paritytab[8] = {
779 0x96696996, 0x69969669, 0x69969669, 0x96696996,
780 0x69969669, 0x96696996, 0x96696996, 0x69969669
781 };
782
783 int
784 pppinput(c, tp)
785 int c;
786 register struct tty *tp;
787 {
788 register struct ppp_softc *sc;
789 struct mbuf *m;
790 int ilen, s;
791
792 sc = (struct ppp_softc *) tp->t_sc;
793 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
794 return 0;
795
796 ++tk_nin;
797 ++sc->sc_stats.ppp_ibytes;
798
799 if (c & TTY_FE) {
800 /* framing error or overrun on this char - abort packet */
801 if (sc->sc_flags & SC_DEBUG)
802 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
803 goto flush;
804 }
805
806 c &= 0xff;
807
808 /*
809 * Handle software flow control of output.
810 */
811 if (tp->t_iflag & IXON) {
812 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
813 if ((tp->t_state & TS_TTSTOP) == 0) {
814 tp->t_state |= TS_TTSTOP;
815 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
816 }
817 return 0;
818 }
819 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
820 tp->t_state &= ~TS_TTSTOP;
821 if (tp->t_oproc != NULL)
822 (*tp->t_oproc)(tp);
823 return 0;
824 }
825 }
826
827 s = spltty();
828 if (c & 0x80)
829 sc->sc_flags |= SC_RCV_B7_1;
830 else
831 sc->sc_flags |= SC_RCV_B7_0;
832 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
833 sc->sc_flags |= SC_RCV_ODDP;
834 else
835 sc->sc_flags |= SC_RCV_EVNP;
836 splx(s);
837
838 if (sc->sc_flags & SC_LOG_RAWIN)
839 ppplogchar(sc, c);
840
841 if (c == PPP_FLAG) {
842 ilen = sc->sc_ilen;
843 sc->sc_ilen = 0;
844
845 if (sc->sc_rawin_count > 0)
846 ppplogchar(sc, -1);
847
848 /*
849 * If SC_ESCAPED is set, then we've seen the packet
850 * abort sequence "}~".
851 */
852 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
853 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
854 s = spltty();
855 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
856 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
857 if (sc->sc_flags & SC_DEBUG)
858 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
859 sc->sc_fcs);
860 sc->sc_if.if_ierrors++;
861 sc->sc_stats.ppp_ierrors++;
862 } else
863 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
864 splx(s);
865 return 0;
866 }
867
868 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
869 if (ilen) {
870 if (sc->sc_flags & SC_DEBUG)
871 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
872 s = spltty();
873 sc->sc_if.if_ierrors++;
874 sc->sc_stats.ppp_ierrors++;
875 sc->sc_flags |= SC_PKTLOST;
876 splx(s);
877 }
878 return 0;
879 }
880
881 /*
882 * Remove FCS trailer. Somewhat painful...
883 */
884 ilen -= 2;
885 if (--sc->sc_mc->m_len == 0) {
886 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
887 ;
888 sc->sc_mc = m;
889 }
890 sc->sc_mc->m_len--;
891
892 /* excise this mbuf chain */
893 m = sc->sc_m;
894 sc->sc_m = sc->sc_mc->m_next;
895 sc->sc_mc->m_next = NULL;
896
897 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
898 if (sc->sc_flags & SC_PKTLOST) {
899 s = spltty();
900 sc->sc_flags &= ~SC_PKTLOST;
901 splx(s);
902 }
903
904 pppgetm(sc);
905 return 0;
906 }
907
908 if (sc->sc_flags & SC_FLUSH) {
909 if (sc->sc_flags & SC_LOG_FLUSH)
910 ppplogchar(sc, c);
911 return 0;
912 }
913
914 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
915 return 0;
916
917 s = spltty();
918 if (sc->sc_flags & SC_ESCAPED) {
919 sc->sc_flags &= ~SC_ESCAPED;
920 c ^= PPP_TRANS;
921 } else if (c == PPP_ESCAPE) {
922 sc->sc_flags |= SC_ESCAPED;
923 splx(s);
924 return 0;
925 }
926 splx(s);
927
928 /*
929 * Initialize buffer on first octet received.
930 * First octet could be address or protocol (when compressing
931 * address/control).
932 * Second octet is control.
933 * Third octet is first or second (when compressing protocol)
934 * octet of protocol.
935 * Fourth octet is second octet of protocol.
936 */
937 if (sc->sc_ilen == 0) {
938 /* reset the first input mbuf */
939 if (sc->sc_m == NULL) {
940 pppgetm(sc);
941 if (sc->sc_m == NULL) {
942 if (sc->sc_flags & SC_DEBUG)
943 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
944 goto flush;
945 }
946 }
947 m = sc->sc_m;
948 m->m_len = 0;
949 m->m_data = M_DATASTART(sc->sc_m);
950 sc->sc_mc = m;
951 sc->sc_mp = mtod(m, char *);
952 sc->sc_fcs = PPP_INITFCS;
953 if (c != PPP_ALLSTATIONS) {
954 if (sc->sc_flags & SC_REJ_COMP_AC) {
955 if (sc->sc_flags & SC_DEBUG)
956 printf("%s: garbage received: 0x%x (need 0xFF)\n",
957 sc->sc_if.if_xname, c);
958 goto flush;
959 }
960 *sc->sc_mp++ = PPP_ALLSTATIONS;
961 *sc->sc_mp++ = PPP_UI;
962 sc->sc_ilen += 2;
963 m->m_len += 2;
964 }
965 }
966 if (sc->sc_ilen == 1 && c != PPP_UI) {
967 if (sc->sc_flags & SC_DEBUG)
968 printf("%s: missing UI (0x3), got 0x%x\n",
969 sc->sc_if.if_xname, c);
970 goto flush;
971 }
972 if (sc->sc_ilen == 2 && (c & 1) == 1) {
973 /* a compressed protocol */
974 *sc->sc_mp++ = 0;
975 sc->sc_ilen++;
976 sc->sc_mc->m_len++;
977 }
978 if (sc->sc_ilen == 3 && (c & 1) == 0) {
979 if (sc->sc_flags & SC_DEBUG)
980 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
981 (sc->sc_mp[-1] << 8) + c);
982 goto flush;
983 }
984
985 /* packet beyond configured mru? */
986 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
987 if (sc->sc_flags & SC_DEBUG)
988 printf("%s: packet too big\n", sc->sc_if.if_xname);
989 goto flush;
990 }
991
992 /* is this mbuf full? */
993 m = sc->sc_mc;
994 if (M_TRAILINGSPACE(m) <= 0) {
995 if (m->m_next == NULL) {
996 pppgetm(sc);
997 if (m->m_next == NULL) {
998 if (sc->sc_flags & SC_DEBUG)
999 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1000 goto flush;
1001 }
1002 }
1003 sc->sc_mc = m = m->m_next;
1004 m->m_len = 0;
1005 m->m_data = M_DATASTART(m);
1006 sc->sc_mp = mtod(m, char *);
1007 }
1008
1009 ++m->m_len;
1010 *sc->sc_mp++ = c;
1011 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1012 return 0;
1013
1014 flush:
1015 if (!(sc->sc_flags & SC_FLUSH)) {
1016 s = spltty();
1017 sc->sc_if.if_ierrors++;
1018 sc->sc_stats.ppp_ierrors++;
1019 sc->sc_flags |= SC_FLUSH;
1020 splx(s);
1021 if (sc->sc_flags & SC_LOG_FLUSH)
1022 ppplogchar(sc, c);
1023 }
1024 return 0;
1025 }
1026
1027 #define MAX_DUMP_BYTES 128
1028
1029 static void
1030 ppplogchar(sc, c)
1031 struct ppp_softc *sc;
1032 int c;
1033 {
1034 if (c >= 0)
1035 sc->sc_rawin[sc->sc_rawin_count++] = c;
1036 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1037 || (c < 0 && sc->sc_rawin_count > 0)) {
1038 printf("%s input: ", sc->sc_if.if_xname);
1039 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1040 sc->sc_rawin_count = 0;
1041 }
1042 }
1043
1044 static void
1045 pppdumpb(b, l)
1046 u_char *b;
1047 int l;
1048 {
1049 char buf[3*MAX_DUMP_BYTES+4];
1050 char *bp = buf;
1051 static char digits[] = "0123456789abcdef";
1052
1053 while (l--) {
1054 if (bp >= buf + sizeof(buf) - 3) {
1055 *bp++ = '>';
1056 break;
1057 }
1058 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1059 *bp++ = digits[*b++ & 0xf];
1060 *bp++ = ' ';
1061 }
1062
1063 *bp = 0;
1064 printf("%s\n", buf);
1065 }
1066
1067 #endif /* NPPP > 0 */
1068