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