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