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