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