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