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