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