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