ppp_tty.c revision 1.30.4.1 1 /* $NetBSD: ppp_tty.c,v 1.30.4.1 2002/05/16 03:58:47 gehenna 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.30.4.1 2002/05/16 03:58:47 gehenna 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; /* 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 const struct cdevsw *cdev;
639 int len;
640
641 for(m = sc->sc_outm;;) {
642 if (m == NULL) {
643 m = ppp_dequeue(sc); /* get new packet */
644 if (m == NULL)
645 break; /* no more packets */
646 if (sc->sc_flags & SC_DEBUG)
647 pppdumpframe(sc,m,1);
648 }
649 for(n=m,len=0;n!=NULL;n=n->m_next)
650 len += n->m_len;
651
652 /* call device driver IOCTL to transmit a frame */
653 cdev = cdevsw_lookup(tp->t_dev);
654 if (cdev == NULL ||
655 (*cdev->d_ioctl)(tp->t_dev, TIOCXMTFRAME, (caddr_t)&m,
656 0, 0)) {
657 /* busy or error, set as current packet */
658 sc->sc_outm = m;
659 break;
660 }
661 sc->sc_outm = m = NULL;
662 sc->sc_stats.ppp_obytes += len;
663 }
664 }
665
666 /*
667 * This gets called at splsoftnet from if_ppp.c at various times
668 * when there is data ready to be sent.
669 */
670 static void
671 pppasyncstart(sc)
672 struct ppp_softc *sc;
673 {
674 struct tty *tp = (struct tty *) sc->sc_devp;
675 struct mbuf *m;
676 int len;
677 u_char *start, *stop, *cp;
678 int n, ndone, done, idle;
679 struct mbuf *m2;
680 int s;
681
682 if (sc->sc_flags & SC_SYNC){
683 pppsyncstart(sc);
684 return;
685 }
686
687 idle = 0;
688 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
689 /*
690 * See if we have an existing packet partly sent.
691 * If not, get a new packet and start sending it.
692 */
693 m = sc->sc_outm;
694 if (m == NULL) {
695 /*
696 * Get another packet to be sent.
697 */
698 m = ppp_dequeue(sc);
699 if (m == NULL) {
700 idle = 1;
701 break;
702 }
703
704 /*
705 * The extra PPP_FLAG will start up a new packet, and thus
706 * will flush any accumulated garbage. We do this whenever
707 * the line may have been idle for some time.
708 */
709 if (CCOUNT(&tp->t_outq) == 0) {
710 ++sc->sc_stats.ppp_obytes;
711 (void) putc(PPP_FLAG, &tp->t_outq);
712 }
713
714 /* Calculate the FCS for the first mbuf's worth. */
715 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
716 }
717
718 for (;;) {
719 start = mtod(m, u_char *);
720 len = m->m_len;
721 stop = start + len;
722 while (len > 0) {
723 /*
724 * Find out how many bytes in the string we can
725 * handle without doing something special.
726 */
727 for (cp = start; cp < stop; cp++)
728 if (ESCAPE_P(*cp))
729 break;
730 n = cp - start;
731 if (n) {
732 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
733 ndone = n - b_to_q(start, n, &tp->t_outq);
734 len -= ndone;
735 start += ndone;
736 sc->sc_stats.ppp_obytes += ndone;
737
738 if (ndone < n)
739 break; /* packet doesn't fit */
740 }
741 /*
742 * If there are characters left in the mbuf,
743 * the first one must be special.
744 * Put it out in a different form.
745 */
746 if (len) {
747 s = spltty();
748 if (putc(PPP_ESCAPE, &tp->t_outq)) {
749 splx(s);
750 break;
751 }
752 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
753 (void) unputc(&tp->t_outq);
754 splx(s);
755 break;
756 }
757 splx(s);
758 sc->sc_stats.ppp_obytes += 2;
759 start++;
760 len--;
761 }
762 }
763
764 /*
765 * If we didn't empty this mbuf, remember where we're up to.
766 * If we emptied the last mbuf, try to add the FCS and closing
767 * flag, and if we can't, leave sc_outm pointing to m, but with
768 * m->m_len == 0, to remind us to output the FCS and flag later.
769 */
770 done = len == 0;
771 if (done && m->m_next == NULL) {
772 u_char *p, *q;
773 int c;
774 u_char endseq[8];
775
776 /*
777 * We may have to escape the bytes in the FCS.
778 */
779 p = endseq;
780 c = ~sc->sc_outfcs & 0xFF;
781 if (ESCAPE_P(c)) {
782 *p++ = PPP_ESCAPE;
783 *p++ = c ^ PPP_TRANS;
784 } else
785 *p++ = c;
786 c = (~sc->sc_outfcs >> 8) & 0xFF;
787 if (ESCAPE_P(c)) {
788 *p++ = PPP_ESCAPE;
789 *p++ = c ^ PPP_TRANS;
790 } else
791 *p++ = c;
792 *p++ = PPP_FLAG;
793
794 /*
795 * Try to output the FCS and flag. If the bytes
796 * don't all fit, back out.
797 */
798 s = spltty();
799 for (q = endseq; q < p; ++q)
800 if (putc(*q, &tp->t_outq)) {
801 done = 0;
802 for (; q > endseq; --q)
803 unputc(&tp->t_outq);
804 break;
805 }
806 splx(s);
807 if (done)
808 sc->sc_stats.ppp_obytes += q - endseq;
809 }
810
811 if (!done) {
812 /* remember where we got to */
813 m->m_data = start;
814 m->m_len = len;
815 break;
816 }
817
818 /* Finished with this mbuf; free it and move on. */
819 MFREE(m, m2);
820 m = m2;
821 if (m == NULL) {
822 /* Finished a packet */
823 break;
824 }
825 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
826 }
827
828 /*
829 * If m == NULL, we have finished a packet.
830 * If m != NULL, we've either done as much work this time
831 * as we need to, or else we've filled up the output queue.
832 */
833 sc->sc_outm = m;
834 if (m)
835 break;
836 }
837
838 /* Call pppstart to start output again if necessary. */
839 s = spltty();
840 pppstart(tp);
841
842 /*
843 * This timeout is needed for operation on a pseudo-tty,
844 * because the pty code doesn't call pppstart after it has
845 * drained the t_outq.
846 */
847 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
848 callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
849 sc->sc_flags |= SC_TIMEOUT;
850 }
851
852 splx(s);
853 }
854
855 /*
856 * This gets called when a received packet is placed on
857 * the inq, at splsoftnet.
858 */
859 static void
860 pppasyncctlp(sc)
861 struct ppp_softc *sc;
862 {
863 struct tty *tp;
864 int s;
865
866 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
867 s = spltty();
868 tp = (struct tty *) sc->sc_devp;
869 putc(0, &tp->t_canq);
870 ttwakeup(tp);
871 splx(s);
872 }
873
874 /*
875 * Start output on async tty interface. If the transmit queue
876 * has drained sufficiently, arrange for pppasyncstart to be
877 * called later at splsoftnet.
878 * Called at spltty or higher.
879 */
880 int
881 pppstart(tp)
882 struct tty *tp;
883 {
884 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
885
886 /*
887 * If there is stuff in the output queue, send it now.
888 * We are being called in lieu of ttstart and must do what it would.
889 */
890 if (tp->t_oproc != NULL)
891 (*tp->t_oproc)(tp);
892
893 /*
894 * If the transmit queue has drained and the tty has not hung up
895 * or been disconnected from the ppp unit, then tell if_ppp.c that
896 * we need more output.
897 */
898 if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
899 && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
900 return 0;
901 #ifdef ALTQ
902 /*
903 * if ALTQ is enabled, don't invoke NETISR_PPP.
904 * pppintr() could loop without doing anything useful
905 * under rate-limiting.
906 */
907 if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd))
908 return 0;
909 #endif
910 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
911 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
912 ppp_restart(sc);
913 }
914
915 return 0;
916 }
917
918 /*
919 * Timeout routine - try to start some more output.
920 */
921 static void
922 ppp_timeout(x)
923 void *x;
924 {
925 struct ppp_softc *sc = (struct ppp_softc *) x;
926 struct tty *tp = (struct tty *) sc->sc_devp;
927 int s;
928
929 s = spltty();
930 sc->sc_flags &= ~SC_TIMEOUT;
931 pppstart(tp);
932 splx(s);
933 }
934
935 /*
936 * Allocate enough mbuf to handle current MRU.
937 */
938 static void
939 pppgetm(sc)
940 struct ppp_softc *sc;
941 {
942 struct mbuf *m, **mp;
943 int len;
944
945 mp = &sc->sc_m;
946 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
947 if ((m = *mp) == NULL) {
948 MGETHDR(m, M_DONTWAIT, MT_DATA);
949 if (m == NULL)
950 break;
951 *mp = m;
952 MCLGET(m, M_DONTWAIT);
953 }
954 len -= M_DATASIZE(m);
955 mp = &m->m_next;
956 }
957 }
958
959 /*
960 * tty interface receiver interrupt.
961 */
962 static const unsigned paritytab[8] = {
963 0x96696996, 0x69969669, 0x69969669, 0x96696996,
964 0x69969669, 0x96696996, 0x96696996, 0x69969669
965 };
966
967 int
968 pppinput(c, tp)
969 int c;
970 struct tty *tp;
971 {
972 struct ppp_softc *sc;
973 struct mbuf *m;
974 const struct cdevsw *cdev;
975 int ilen, s;
976
977 sc = (struct ppp_softc *) tp->t_sc;
978 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
979 return 0;
980
981 ++tk_nin;
982 ++sc->sc_stats.ppp_ibytes;
983
984 if (c & TTY_FE) {
985 /* framing error or overrun on this char - abort packet */
986 if (sc->sc_flags & SC_DEBUG)
987 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
988 goto flush;
989 }
990
991 c &= 0xff;
992
993 /*
994 * Handle software flow control of output.
995 */
996 if (tp->t_iflag & IXON) {
997 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
998 if ((tp->t_state & TS_TTSTOP) == 0) {
999 tp->t_state |= TS_TTSTOP;
1000 cdev = cdevsw_lookup(tp->t_dev);
1001 if (cdev != NULL)
1002 (*cdev->d_stop)(tp, 0);
1003 }
1004 return 0;
1005 }
1006 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
1007 tp->t_state &= ~TS_TTSTOP;
1008 if (tp->t_oproc != NULL)
1009 (*tp->t_oproc)(tp);
1010 return 0;
1011 }
1012 }
1013
1014 s = spltty();
1015 if (c & 0x80)
1016 sc->sc_flags |= SC_RCV_B7_1;
1017 else
1018 sc->sc_flags |= SC_RCV_B7_0;
1019 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
1020 sc->sc_flags |= SC_RCV_ODDP;
1021 else
1022 sc->sc_flags |= SC_RCV_EVNP;
1023 splx(s);
1024
1025 if (sc->sc_flags & SC_LOG_RAWIN)
1026 ppplogchar(sc, c);
1027
1028 if (c == PPP_FLAG) {
1029 ilen = sc->sc_ilen;
1030 sc->sc_ilen = 0;
1031
1032 if (sc->sc_rawin_count > 0)
1033 ppplogchar(sc, -1);
1034
1035 /*
1036 * If SC_ESCAPED is set, then we've seen the packet
1037 * abort sequence "}~".
1038 */
1039 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1040 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
1041 s = spltty();
1042 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1043 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1044 if (sc->sc_flags & SC_DEBUG)
1045 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
1046 sc->sc_fcs);
1047 sc->sc_if.if_ierrors++;
1048 sc->sc_stats.ppp_ierrors++;
1049 } else
1050 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1051 splx(s);
1052 return 0;
1053 }
1054
1055 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1056 if (ilen) {
1057 if (sc->sc_flags & SC_DEBUG)
1058 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
1059 s = spltty();
1060 sc->sc_if.if_ierrors++;
1061 sc->sc_stats.ppp_ierrors++;
1062 sc->sc_flags |= SC_PKTLOST;
1063 splx(s);
1064 }
1065 return 0;
1066 }
1067
1068 /*
1069 * Remove FCS trailer. Somewhat painful...
1070 */
1071 ilen -= 2;
1072 if (--sc->sc_mc->m_len == 0) {
1073 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1074 ;
1075 sc->sc_mc = m;
1076 }
1077 sc->sc_mc->m_len--;
1078
1079 /* excise this mbuf chain */
1080 m = sc->sc_m;
1081 sc->sc_m = sc->sc_mc->m_next;
1082 sc->sc_mc->m_next = NULL;
1083
1084 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1085 if (sc->sc_flags & SC_PKTLOST) {
1086 s = spltty();
1087 sc->sc_flags &= ~SC_PKTLOST;
1088 splx(s);
1089 }
1090
1091 pppgetm(sc);
1092 return 0;
1093 }
1094
1095 if (sc->sc_flags & SC_FLUSH) {
1096 if (sc->sc_flags & SC_LOG_FLUSH)
1097 ppplogchar(sc, c);
1098 return 0;
1099 }
1100
1101 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1102 return 0;
1103
1104 s = spltty();
1105 if (sc->sc_flags & SC_ESCAPED) {
1106 sc->sc_flags &= ~SC_ESCAPED;
1107 c ^= PPP_TRANS;
1108 } else if (c == PPP_ESCAPE) {
1109 sc->sc_flags |= SC_ESCAPED;
1110 splx(s);
1111 return 0;
1112 }
1113 splx(s);
1114
1115 /*
1116 * Initialize buffer on first octet received.
1117 * First octet could be address or protocol (when compressing
1118 * address/control).
1119 * Second octet is control.
1120 * Third octet is first or second (when compressing protocol)
1121 * octet of protocol.
1122 * Fourth octet is second octet of protocol.
1123 */
1124 if (sc->sc_ilen == 0) {
1125 /* reset the first input mbuf */
1126 if (sc->sc_m == NULL) {
1127 pppgetm(sc);
1128 if (sc->sc_m == NULL) {
1129 if (sc->sc_flags & SC_DEBUG)
1130 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
1131 goto flush;
1132 }
1133 }
1134 m = sc->sc_m;
1135 m->m_len = 0;
1136 m->m_data = M_DATASTART(sc->sc_m);
1137 sc->sc_mc = m;
1138 sc->sc_mp = mtod(m, char *);
1139 sc->sc_fcs = PPP_INITFCS;
1140 if (c != PPP_ALLSTATIONS) {
1141 if (sc->sc_flags & SC_REJ_COMP_AC) {
1142 if (sc->sc_flags & SC_DEBUG)
1143 printf("%s: garbage received: 0x%x (need 0xFF)\n",
1144 sc->sc_if.if_xname, c);
1145 goto flush;
1146 }
1147 *sc->sc_mp++ = PPP_ALLSTATIONS;
1148 *sc->sc_mp++ = PPP_UI;
1149 sc->sc_ilen += 2;
1150 m->m_len += 2;
1151 }
1152 }
1153 if (sc->sc_ilen == 1 && c != PPP_UI) {
1154 if (sc->sc_flags & SC_DEBUG)
1155 printf("%s: missing UI (0x3), got 0x%x\n",
1156 sc->sc_if.if_xname, c);
1157 goto flush;
1158 }
1159 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1160 /* a compressed protocol */
1161 *sc->sc_mp++ = 0;
1162 sc->sc_ilen++;
1163 sc->sc_mc->m_len++;
1164 }
1165 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1166 if (sc->sc_flags & SC_DEBUG)
1167 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1168 (sc->sc_mp[-1] << 8) + c);
1169 goto flush;
1170 }
1171
1172 /* packet beyond configured mru? */
1173 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1174 if (sc->sc_flags & SC_DEBUG)
1175 printf("%s: packet too big\n", sc->sc_if.if_xname);
1176 goto flush;
1177 }
1178
1179 /* is this mbuf full? */
1180 m = sc->sc_mc;
1181 if (M_TRAILINGSPACE(m) <= 0) {
1182 if (m->m_next == NULL) {
1183 pppgetm(sc);
1184 if (m->m_next == NULL) {
1185 if (sc->sc_flags & SC_DEBUG)
1186 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1187 goto flush;
1188 }
1189 }
1190 sc->sc_mc = m = m->m_next;
1191 m->m_len = 0;
1192 m->m_data = M_DATASTART(m);
1193 sc->sc_mp = mtod(m, char *);
1194 }
1195
1196 ++m->m_len;
1197 *sc->sc_mp++ = c;
1198 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1199 return 0;
1200
1201 flush:
1202 if (!(sc->sc_flags & SC_FLUSH)) {
1203 s = spltty();
1204 sc->sc_if.if_ierrors++;
1205 sc->sc_stats.ppp_ierrors++;
1206 sc->sc_flags |= SC_FLUSH;
1207 splx(s);
1208 if (sc->sc_flags & SC_LOG_FLUSH)
1209 ppplogchar(sc, c);
1210 }
1211 return 0;
1212 }
1213
1214 #define MAX_DUMP_BYTES 128
1215
1216 static void
1217 ppplogchar(sc, c)
1218 struct ppp_softc *sc;
1219 int c;
1220 {
1221 if (c >= 0)
1222 sc->sc_rawin[sc->sc_rawin_count++] = c;
1223 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1224 || (c < 0 && sc->sc_rawin_count > 0)) {
1225 printf("%s input: ", sc->sc_if.if_xname);
1226 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1227 sc->sc_rawin_count = 0;
1228 }
1229 }
1230
1231 static void
1232 pppdumpb(b, l)
1233 u_char *b;
1234 int l;
1235 {
1236 char buf[3*MAX_DUMP_BYTES+4];
1237 char *bp = buf;
1238 static char digits[] = "0123456789abcdef";
1239
1240 while (l--) {
1241 if (bp >= buf + sizeof(buf) - 3) {
1242 *bp++ = '>';
1243 break;
1244 }
1245 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1246 *bp++ = digits[*b++ & 0xf];
1247 *bp++ = ' ';
1248 }
1249
1250 *bp = 0;
1251 printf("%s\n", buf);
1252 }
1253
1254 static void
1255 pppdumpframe(sc, m, xmit)
1256 struct ppp_softc *sc;
1257 struct mbuf* m;
1258 int xmit;
1259 {
1260 int i,lcount,copycount,count;
1261 char lbuf[16];
1262 char *data;
1263
1264 if (m == NULL)
1265 return;
1266
1267 for(count=m->m_len,data=mtod(m,char*);m != NULL;) {
1268 /* build a line of output */
1269 for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) {
1270 if (!count) {
1271 m = m->m_next;
1272 if (m == NULL)
1273 break;
1274 count = m->m_len;
1275 data = mtod(m,char*);
1276 }
1277 copycount = (count > sizeof(lbuf)-lcount) ?
1278 sizeof(lbuf)-lcount : count;
1279 bcopy(data,&lbuf[lcount],copycount);
1280 data += copycount;
1281 count -= copycount;
1282 }
1283
1284 /* output line (hex 1st, then ascii) */
1285 printf("%s %s:", sc->sc_if.if_xname,
1286 xmit ? "output" : "input ");
1287 for(i=0;i<lcount;i++)
1288 printf("%02x ",(u_char)lbuf[i]);
1289 for(;i<sizeof(lbuf);i++)
1290 printf(" ");
1291 for(i=0;i<lcount;i++)
1292 printf("%c",(lbuf[i] >= 040 &&
1293 lbuf[i] <= 0176) ? lbuf[i] : '.');
1294 printf("\n");
1295 }
1296 }
1297