if_ppp.c revision 1.10 1 /*
2 * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
3 *
4 * Copyright (c) 1989 Carnegie Mellon University.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by Carnegie Mellon University. The name of the
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * Drew D. Perkins
20 * Carnegie Mellon University
21 * 4910 Forbes Ave.
22 * Pittsburgh, PA 15213
23 * (412) 268-8576
24 * ddp (at) andrew.cmu.edu
25 *
26 * Based on:
27 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
28 *
29 * Copyright (c) 1987 Regents of the University of California.
30 * All rights reserved.
31 *
32 * Redistribution and use in source and binary forms are permitted
33 * provided that the above copyright notice and this paragraph are
34 * duplicated in all such forms and that any documentation,
35 * advertising materials, and other materials related to such
36 * distribution and use acknowledge that the software was developed
37 * by the University of California, Berkeley. The name of the
38 * University may not be used to endorse or promote products derived
39 * from this software without specific prior written permission.
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
41 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
42 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
43 *
44 * Serial Line interface
45 *
46 * Rick Adams
47 * Center for Seismic Studies
48 * 1300 N 17th Street, Suite 1450
49 * Arlington, Virginia 22209
50 * (703)276-7900
51 * rick (at) seismo.ARPA
52 * seismo!rick
53 *
54 * Pounded on heavily by Chris Torek (chris (at) mimsy.umd.edu, umcp-cs!chris).
55 * Converted to 4.3BSD Beta by Chris Torek.
56 * Other changes made at Berkeley, based in part on code by Kirk Smith.
57 *
58 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad (at) cayman.com)
59 * Added VJ tcp header compression; more unified ioctls
60 *
61 * Extensively modified by Paul Mackerras (paulus (at) cs.anu.edu.au).
62 * Cleaned up a lot of the mbuf-related code to fix bugs that
63 * caused system crashes and packet corruption. Changed pppstart
64 * so that it doesn't just give up with a collision if the whole
65 * packet doesn't fit in the output ring buffer.
66 *
67 * Added priority queueing for interactive IP packets, following
68 * the model of if_sl.c, plus hooks for bpf.
69 * Paul Mackerras (paulus (at) cs.anu.edu.au).
70 */
71
72 /* $Id: if_ppp.c,v 1.10 1994/05/24 02:33:56 cgd Exp $ */
73 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
74
75 #include "ppp.h"
76 #if NPPP > 0
77
78 #define VJC
79
80 #include <sys/param.h>
81 #include <sys/proc.h>
82 #include <sys/mbuf.h>
83 #include <sys/buf.h>
84 #include <sys/dkstat.h>
85 #include <sys/socket.h>
86 #include <sys/ioctl.h>
87 #include <sys/file.h>
88 #include <sys/tty.h>
89 #include <sys/kernel.h>
90 #include <sys/conf.h>
91 #include <sys/vnode.h>
92
93 #include <net/if.h>
94 #include <net/if_types.h>
95 #include <net/netisr.h>
96 #include <net/route.h>
97
98 #if INET
99 #include <netinet/in.h>
100 #include <netinet/in_systm.h>
101 #include <netinet/in_var.h>
102 #include <netinet/ip.h>
103 #endif
104
105 #include "bpfilter.h"
106 #if NBPFILTER > 0
107 #include <sys/time.h>
108 #include <net/bpf.h>
109 #endif
110
111 #ifdef VJC
112 #include <net/slcompress.h>
113 #define HDROFF MAX_HDR
114 /* HDROFF should really be 128, but other parts of the system will
115 panic on TCP+IP headers bigger than MAX_HDR = MHLEN (100). */
116
117 #else
118 #define HDROFF (0)
119 #endif
120
121 #include <net/if_ppp.h>
122 #include <machine/cpu.h>
123
124 /* This is a NetBSD-current kernel. */
125 #define CCOUNT(q) ((q)->c_cc)
126
127 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
128
129 struct ppp_softc ppp_softc[NPPP];
130
131 void pppattach __P((void));
132 int pppopen __P((dev_t dev, struct tty *tp));
133 void pppclose __P((struct tty *tp, int flag));
134 int pppread __P((struct tty *tp, struct uio *uio, int flag));
135 int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
136 int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag,
137 struct proc *));
138 int pppoutput __P((struct ifnet *ifp, struct mbuf *m0,
139 struct sockaddr *dst, struct rtentry *rtp));
140 void pppinput __P((int c, struct tty *tp));
141 int pppioctl __P((struct ifnet *ifp, int cmd, caddr_t data));
142 void pppstart __P((struct tty *tp));
143
144 static int pppasyncstart __P((struct ppp_softc *));
145 static u_short pppfcs __P((u_short fcs, u_char *cp, int len));
146 static int pppgetm __P((struct ppp_softc *sc));
147 static struct mbuf *ppp_btom __P((struct ppp_softc *sc));
148 static void pppdumpm __P((struct mbuf *m0, int pktlen));
149 static void pppdumpb __P((u_char *b, int l));
150 static void ppplogchar __P((struct ppp_softc *, int));
151
152 /*
153 * Some useful mbuf macros not in mbuf.h.
154 */
155 #define M_DATASTART(m) \
156 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf : \
157 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
158
159 #define M_DATASIZE(m) \
160 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_size : \
161 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
162
163 /*
164 * The following disgusting hack gets around the problem that IP TOS
165 * can't be set yet. We want to put "interactive" traffic on a high
166 * priority queue. To decide if traffic is interactive, we check that
167 * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
168 */
169 static u_short interactive_ports[8] = {
170 0, 513, 0, 0,
171 0, 21, 0, 23,
172 };
173 #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
174
175 /*
176 * Does c need to be escaped?
177 */
178 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
179
180 /*
181 * Called from boot code to establish ppp interfaces.
182 */
183 void
184 pppattach()
185 {
186 register struct ppp_softc *sc;
187 register int i = 0;
188
189 for (sc = ppp_softc; i < NPPP; sc++) {
190 sc->sc_if.if_name = "ppp";
191 sc->sc_if.if_unit = i++;
192 sc->sc_if.if_mtu = PPP_MTU;
193 sc->sc_if.if_flags = IFF_POINTOPOINT;
194 sc->sc_if.if_type = IFT_PPP;
195 sc->sc_if.if_hdrlen = PPP_HDRLEN;
196 sc->sc_if.if_ioctl = pppioctl;
197 sc->sc_if.if_output = pppoutput;
198 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
199 sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
200 sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
201 if_attach(&sc->sc_if);
202 #if NBPFILTER > 0
203 bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN);
204 #endif
205 }
206 }
207
208 /*
209 * Allocate a ppp interface unit and initialize it.
210 */
211 struct ppp_softc *
212 pppalloc(pid)
213 pid_t pid;
214 {
215 int nppp;
216 struct ppp_softc *sc;
217
218 for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
219 if (sc->sc_xfer == pid) {
220 sc->sc_xfer = 0;
221 break;
222 }
223 if (nppp >= NPPP)
224 for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
225 if (sc->sc_devp == NULL)
226 break;
227 if (nppp >= NPPP)
228 return NULL;
229
230 sc->sc_flags = 0;
231 sc->sc_mru = PPP_MRU;
232 #ifdef VJC
233 sl_compress_init(&sc->sc_comp, -1);
234 #endif
235 sc->sc_if.if_flags |= IFF_RUNNING;
236
237 return sc;
238 }
239
240 /*
241 * Deallocate a ppp unit.
242 */
243 pppdealloc(sc)
244 struct ppp_softc *sc;
245 {
246 struct mbuf *m;
247
248 if_down(&sc->sc_if);
249 sc->sc_devp = NULL;
250 sc->sc_xfer = 0;
251 for (;;) {
252 IF_DEQUEUE(&sc->sc_inq, m);
253 if (m == NULL)
254 break;
255 m_freem(m);
256 }
257 for (;;) {
258 IF_DEQUEUE(&sc->sc_fastq, m);
259 if (m == NULL)
260 break;
261 m_freem(m);
262 }
263 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
264 }
265
266 /*
267 * Line specific open routine for async tty devices.
268 * Attach the given tty to the first available ppp unit.
269 */
270 /* ARGSUSED */
271 int
272 pppopen(dev, tp)
273 dev_t dev;
274 register struct tty *tp;
275 {
276 struct proc *p = curproc; /* XXX */
277 register struct ppp_softc *sc;
278 int error, s, i;
279
280 if (error = suser(p->p_ucred, &p->p_acflag))
281 return (error);
282
283 if (tp->t_line == PPPDISC) {
284 sc = (struct ppp_softc *) tp->t_sc;
285 if (sc != NULL && sc->sc_devp == (void *) tp)
286 return (0);
287 }
288
289 if ((sc = pppalloc(p->p_pid)) == NULL)
290 return ENXIO;
291
292 if (sc->sc_outm != NULL) {
293 m_freem(sc->sc_outm);
294 sc->sc_outm = NULL;
295 }
296
297 if (pppgetm(sc) == 0) {
298 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
299 return (ENOBUFS);
300 }
301
302 sc->sc_ilen = 0;
303 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
304 sc->sc_asyncmap[0] = 0xffffffff;
305 sc->sc_asyncmap[3] = 0x60000000;
306 sc->sc_rasyncmap = 0;
307 sc->sc_devp = (void *) tp;
308 sc->sc_start = pppasyncstart;
309
310 tp->t_sc = (caddr_t) sc;
311 ttyflush(tp, FREAD | FWRITE);
312
313 return (0);
314 }
315
316 /*
317 * Line specific close routine.
318 * Detach the tty from the ppp unit.
319 * Mimics part of ttyclose().
320 */
321 void
322 pppclose(tp, flag)
323 struct tty *tp;
324 int flag;
325 {
326 register struct ppp_softc *sc;
327 struct mbuf *m;
328 int s;
329
330 ttywflush(tp);
331 s = splimp(); /* paranoid; splnet probably ok */
332 tp->t_line = 0;
333 sc = (struct ppp_softc *)tp->t_sc;
334 if (sc != NULL) {
335 tp->t_sc = NULL;
336 if (tp == (struct tty *) sc->sc_devp) {
337 m_freem(sc->sc_outm);
338 sc->sc_outm = NULL;
339 m_freem(sc->sc_m);
340 sc->sc_m = NULL;
341 pppdealloc(sc);
342 }
343 }
344 splx(s);
345 }
346
347 /*
348 * Line specific (tty) read routine.
349 */
350 int
351 pppread(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;
358 register int s;
359 int error = 0;
360
361 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
362 return 0; /* end of file */
363 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
364 return 0;
365 s = splimp();
366 while (sc->sc_inq.ifq_head == NULL && tp->t_line == PPPDISC) {
367 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
368 splx(s);
369 return (EWOULDBLOCK);
370 }
371 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
372 if (error)
373 return error;
374 }
375 if (tp->t_line != PPPDISC) {
376 splx(s);
377 return (-1);
378 }
379
380 /* Pull place-holder byte out of canonical queue */
381 getc(&tp->t_canq);
382
383 /* Get the packet from the input queue */
384 IF_DEQUEUE(&sc->sc_inq, m0);
385 splx(s);
386
387 for (m = m0; m && uio->uio_resid; m = m->m_next)
388 if (error = uiomove(mtod(m, u_char *), m->m_len, uio))
389 break;
390 m_freem(m0);
391 return (error);
392 }
393
394 /*
395 * Line specific (tty) write routine.
396 */
397 int
398 pppwrite(tp, uio, flag)
399 register struct tty *tp;
400 struct uio *uio;
401 int flag;
402 {
403 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
404 struct mbuf *m, *m0, **mp;
405 struct sockaddr dst;
406 struct ppp_header *ph1, *ph2;
407 int len, error;
408
409 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
410 return 0; /* wrote 0 bytes */
411 if (tp->t_line != PPPDISC)
412 return (EINVAL);
413 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
414 return EIO;
415 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
416 uio->uio_resid < PPP_HDRLEN)
417 return (EMSGSIZE);
418 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
419 MGET(m, M_WAIT, MT_DATA);
420 if ((*mp = m) == NULL) {
421 m_freem(m0);
422 return (ENOBUFS);
423 }
424 if (uio->uio_resid >= MCLBYTES / 2)
425 MCLGET(m, M_DONTWAIT);
426 len = min(M_TRAILINGSPACE(m), uio->uio_resid);
427 if (error = uiomove(mtod(m, u_char *), len, uio)) {
428 m_freem(m0);
429 return (error);
430 }
431 m->m_len = len;
432 }
433 dst.sa_family = AF_UNSPEC;
434 ph1 = (struct ppp_header *) &dst.sa_data;
435 ph2 = mtod(m0, struct ppp_header *);
436 *ph1 = *ph2;
437 m0->m_data += PPP_HDRLEN;
438 m0->m_len -= PPP_HDRLEN;
439 return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
440 }
441
442 /*
443 * Line specific (tty) ioctl routine.
444 * Provide a way to get the ppp unit number.
445 * This discipline requires that tty device drivers call
446 * the line specific l_ioctl routine from their ioctl routines.
447 */
448 /* ARGSUSED */
449 int
450 ppptioctl(tp, cmd, data, flag, p)
451 struct tty *tp;
452 caddr_t data;
453 int cmd, flag;
454 struct proc *p;
455 {
456 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
457 int s, error, flags, mru;
458
459 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
460 return -1;
461
462 switch (cmd) {
463 case FIONREAD:
464 *(int *)data = sc->sc_inq.ifq_len;
465 break;
466
467 case PPPIOCGUNIT:
468 *(int *)data = sc->sc_if.if_unit;
469 break;
470
471 case PPPIOCGFLAGS:
472 *(u_int *)data = sc->sc_flags;
473 break;
474
475 case PPPIOCSFLAGS:
476 if (error = suser(p->p_ucred, &p->p_acflag))
477 return (error);
478 flags = *(int *)data & SC_MASK;
479 s = splimp();
480 sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
481 splx(s);
482 break;
483
484 case PPPIOCSASYNCMAP:
485 if (error = suser(p->p_ucred, &p->p_acflag))
486 return (error);
487 sc->sc_asyncmap[0] = *(u_int *)data;
488 break;
489
490 case PPPIOCGASYNCMAP:
491 *(u_int *)data = sc->sc_asyncmap[0];
492 break;
493
494 case PPPIOCSRASYNCMAP:
495 if (error = suser(p->p_ucred, &p->p_acflag))
496 return (error);
497 sc->sc_rasyncmap = *(u_int *)data;
498 break;
499
500 case PPPIOCGRASYNCMAP:
501 *(u_int *)data = sc->sc_rasyncmap;
502 break;
503
504 case PPPIOCSXASYNCMAP:
505 if (error = suser(p->p_ucred, &p->p_acflag))
506 return (error);
507 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
508 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
509 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
510 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
511 break;
512
513 case PPPIOCGXASYNCMAP:
514 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
515 break;
516
517 case PPPIOCSMRU:
518 if (error = suser(p->p_ucred, &p->p_acflag))
519 return (error);
520 mru = *(int *)data;
521 if (mru >= PPP_MRU && mru <= PPP_MAXMRU) {
522 sc->sc_mru = mru;
523 if (pppgetm(sc) == 0) {
524 error = ENOBUFS;
525 sc->sc_mru = PPP_MRU;
526 if (pppgetm(sc) == 0)
527 sc->sc_if.if_flags &= ~IFF_UP;
528 }
529 }
530 break;
531
532 case PPPIOCGMRU:
533 *(int *)data = sc->sc_mru;
534 break;
535
536 #ifdef VJC
537 case PPPIOCSMAXCID:
538 if (error = suser(p->p_ucred, &p->p_acflag))
539 return (error);
540 sl_compress_init(&sc->sc_comp, *(int *)data);
541 break;
542 #endif
543
544 case PPPIOCXFERUNIT:
545 if (error = suser(p->p_ucred, &p->p_acflag))
546 return (error);
547 sc->sc_xfer = p->p_pid;
548 break;
549
550 default:
551 return (-1);
552 }
553 return (0);
554 }
555
556 /*
557 * FCS lookup table as calculated by genfcstab.
558 */
559 static u_short fcstab[256] = {
560 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
561 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
562 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
563 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
564 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
565 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
566 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
567 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
568 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
569 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
570 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
571 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
572 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
573 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
574 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
575 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
576 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
577 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
578 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
579 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
580 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
581 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
582 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
583 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
584 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
585 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
586 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
587 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
588 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
589 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
590 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
591 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
592 };
593
594 /*
595 * Calculate a new FCS given the current FCS and the new data.
596 */
597 static u_short
598 pppfcs(fcs, cp, len)
599 register u_short fcs;
600 register u_char *cp;
601 register int len;
602 {
603 while (len--)
604 fcs = PPP_FCS(fcs, *cp++);
605 return (fcs);
606 }
607
608 /*
609 * Queue a packet. Start transmission if not active.
610 * Packet is placed in Information field of PPP frame.
611 */
612 int
613 pppoutput(ifp, m0, dst, rtp)
614 struct ifnet *ifp;
615 struct mbuf *m0;
616 struct sockaddr *dst;
617 struct rtentry *rtp;
618 {
619 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
620 struct ppp_header *ph;
621 int protocol, address, control;
622 u_char *cp;
623 int s, error;
624 struct ip *ip;
625 struct ifqueue *ifq;
626
627 if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
628 || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) {
629 error = ENETDOWN; /* sort of */
630 goto bad;
631 }
632
633 /*
634 * Compute PPP header.
635 */
636 address = PPP_ALLSTATIONS;
637 control = PPP_UI;
638 ifq = &ifp->if_snd;
639 switch (dst->sa_family) {
640 #ifdef INET
641 case AF_INET:
642 protocol = PPP_IP;
643 if ((sc->sc_flags & SC_ENABLE_IP) == 0) {
644 error = ENETDOWN;
645 goto bad;
646 }
647
648 /*
649 * If this is a TCP packet to or from an "interactive" port,
650 * put the packet on the fastq instead.
651 */
652 if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
653 register int p = ntohl(((int *)ip)[ip->ip_hl]);
654 if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
655 ifq = &sc->sc_fastq;
656 }
657 break;
658 #endif
659 #ifdef NS
660 case AF_NS:
661 protocol = PPP_XNS;
662 break;
663 #endif
664 case AF_UNSPEC:
665 ph = (struct ppp_header *) dst->sa_data;
666 address = ph->ph_address;
667 control = ph->ph_control;
668 protocol = ntohs(ph->ph_protocol);
669 break;
670 default:
671 printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
672 error = EAFNOSUPPORT;
673 goto bad;
674 }
675
676 /*
677 * Add PPP header. If no space in first mbuf, allocate another.
678 * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
679 */
680 if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
681 m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT);
682 if (m0 == 0) {
683 error = ENOBUFS;
684 goto bad;
685 }
686 m0->m_len = 0;
687 } else
688 m0->m_data -= PPP_HDRLEN;
689
690 cp = mtod(m0, u_char *);
691 *cp++ = address;
692 *cp++ = control;
693 *cp++ = protocol >> 8;
694 *cp++ = protocol & 0xff;
695 m0->m_len += PPP_HDRLEN;
696
697 if (sc->sc_flags & SC_LOG_OUTPKT) {
698 printf("ppp%d output: ", ifp->if_unit);
699 pppdumpm(m0, -1);
700 }
701
702 #if NBPFILTER > 0
703 /* See if bpf wants to look at the packet. */
704 if (sc->sc_bpf)
705 bpf_mtap(sc->sc_bpf, m0);
706 #endif
707
708 /*
709 * Put the packet on the appropriate queue.
710 */
711 s = splimp();
712 if (IF_QFULL(ifq)) {
713 IF_DROP(ifq);
714 splx(s);
715 sc->sc_if.if_oerrors++;
716 error = ENOBUFS;
717 goto bad;
718 }
719 IF_ENQUEUE(ifq, m0);
720
721 /*
722 * Tell the device to send it out.
723 */
724 (*sc->sc_start)(sc);
725
726 splx(s);
727 return (0);
728
729 bad:
730 m_freem(m0);
731 return (error);
732 }
733
734 /*
735 * Grab another packet off a queue and apply VJ compression,
736 * address/control and/or protocol compression if appropriate.
737 */
738 struct mbuf *
739 ppp_dequeue(sc)
740 struct ppp_softc *sc;
741 {
742 int s;
743 struct mbuf *m;
744 u_char *cp;
745 int address, control, protocol;
746
747 s = splimp();
748 IF_DEQUEUE(&sc->sc_fastq, m);
749 if (m == NULL)
750 IF_DEQUEUE(&sc->sc_if.if_snd, m);
751 splx(s);
752 if (m == NULL)
753 return NULL;
754
755 /*
756 * Extract the ppp header of the new packet.
757 * The ppp header will be in one mbuf.
758 */
759 cp = mtod(m, u_char *);
760 address = cp[0];
761 control = cp[1];
762 protocol = (cp[2] << 8) + cp[3];
763
764 #ifdef VJC
765 /*
766 * If the packet is a TCP/IP packet, see if we can compress it.
767 */
768 if (protocol == PPP_IP && sc->sc_flags & SC_COMP_TCP) {
769 struct ip *ip;
770 int type;
771 struct mbuf *mp;
772
773 mp = m;
774 ip = (struct ip *) (cp + PPP_HDRLEN);
775 if (mp->m_len <= PPP_HDRLEN) {
776 mp = mp->m_next;
777 ip = mtod(mp, struct ip *);
778 }
779 /* this code assumes the IP/TCP header is in one non-shared mbuf */
780 if (ip->ip_p == IPPROTO_TCP) {
781 type = sl_compress_tcp(mp, ip, &sc->sc_comp,
782 !(sc->sc_flags & SC_NO_TCP_CCID));
783 switch (type) {
784 case TYPE_UNCOMPRESSED_TCP:
785 protocol = PPP_VJC_UNCOMP;
786 break;
787 case TYPE_COMPRESSED_TCP:
788 protocol = PPP_VJC_COMP;
789 cp = mtod(m, u_char *);
790 cp[0] = address; /* header has moved */
791 cp[1] = control;
792 cp[2] = 0;
793 break;
794 }
795 cp[3] = protocol; /* update protocol in PPP header */
796 }
797 }
798 #endif /* VJC */
799
800 #ifdef BSD_COMP
801 if (protocol < PPP_COMP && (sc->sc_flags & SC_BSD_COMP)) {
802 slen = m_totallen(m0);
803 clen = pf_bsd_comp(sc->sc_bsd_db, cbuf, proto, m0, slen);
804 }
805 #endif /* BSD_COMP */
806
807 /*
808 * Compress the address/control and protocol, if possible.
809 */
810 if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
811 control == PPP_UI && protocol != PPP_ALLSTATIONS &&
812 protocol != PPP_LCP) {
813 /* can compress address/control */
814 m->m_data += 2;
815 m->m_len -= 2;
816 }
817 if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
818 /* can compress protocol */
819 if (mtod(m, u_char *) == cp) {
820 cp[2] = cp[1]; /* move address/control up */
821 cp[1] = cp[0];
822 }
823 ++m->m_data;
824 --m->m_len;
825 }
826
827 return m;
828 }
829
830 /*
831 * This gets called from pppoutput when a new packet is
832 * put on a queue.
833 */
834 static
835 pppasyncstart(sc)
836 register struct ppp_softc *sc;
837 {
838 register struct tty *tp = (struct tty *) sc->sc_devp;
839
840 pppstart(tp);
841 }
842
843 /*
844 * Start output on async tty interface. Get another datagram
845 * to send from the interface queue and start sending it.
846 */
847 void
848 pppstart(tp)
849 register struct tty *tp;
850 {
851 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
852 register struct mbuf *m;
853 register int len;
854 register u_char *start, *stop, *cp;
855 int n, s, ndone, done;
856 struct mbuf *m2;
857
858 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
859 /* sorry, I can't talk now */
860 return;
861 }
862 if (sc == NULL || tp != (struct tty *) sc->sc_devp) {
863 (*tp->t_oproc)(tp);
864 return;
865 }
866
867 for (;;) {
868 /*
869 * If there is more in the output queue, just send it now.
870 * We are being called in lieu of ttstart and must do what
871 * it would.
872 */
873 if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) {
874 (*tp->t_oproc)(tp);
875 if (CCOUNT(&tp->t_outq) > PPP_HIWAT)
876 return;
877 }
878
879 /*
880 * See if we have an existing packet partly sent.
881 * If not, get a new packet and start sending it.
882 * We take packets on the priority queue ahead of those
883 * on the normal queue.
884 */
885 m = sc->sc_outm;
886 if (m == NULL) {
887 /*
888 * Get another packet to be sent
889 */
890 m = ppp_dequeue(sc);
891 if (m == NULL)
892 return;
893
894 /*
895 * The extra PPP_FLAG will start up a new packet, and thus
896 * will flush any accumulated garbage. We do this whenever
897 * the line may have been idle for some time.
898 */
899 if (CCOUNT(&tp->t_outq) == 0) {
900 ++sc->sc_bytessent;
901 (void) putc(PPP_FLAG, &tp->t_outq);
902 }
903
904 /* Calculate the FCS for the first mbuf's worth. */
905 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
906 }
907
908 for (;;) {
909 start = mtod(m, u_char *);
910 len = m->m_len;
911 stop = start + len;
912 while (len > 0) {
913 /*
914 * Find out how many bytes in the string we can
915 * handle without doing something special.
916 */
917 for (cp = start; cp < stop; cp++)
918 if (ESCAPE_P(*cp))
919 break;
920 n = cp - start;
921 if (n) {
922 #ifndef RB_LEN
923 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
924 ndone = n - b_to_q(start, n, &tp->t_outq);
925 #else
926 #ifdef NetBSD
927 /* NetBSD with 2-byte ring buffer entries */
928 ndone = rb_cwrite(&tp->t_out, start, n);
929 #else
930 /* 386BSD, FreeBSD */
931 int cc, nleft;
932 for (nleft = n; nleft > 0; nleft -= cc) {
933 if ((cc = RB_CONTIGPUT(&tp->t_out)) == 0)
934 break;
935 cc = min (cc, nleft);
936 bcopy((char *)start + n - nleft, tp->t_out.rb_tl, cc);
937 tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
938 tp->t_out.rb_tl + cc);
939 }
940 ndone = n - nleft;
941 #endif /* NetBSD */
942 #endif /* RB_LEN */
943 len -= ndone;
944 start += ndone;
945 sc->sc_bytessent += ndone;
946
947 if (ndone < n)
948 break; /* packet doesn't fit */
949 }
950 /*
951 * If there are characters left in the mbuf,
952 * the first one must be special..
953 * Put it out in a different form.
954 */
955 if (len) {
956 if (putc(PPP_ESCAPE, &tp->t_outq))
957 break;
958 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
959 (void) unputc(&tp->t_outq);
960 break;
961 }
962 sc->sc_bytessent += 2;
963 start++;
964 len--;
965 }
966 }
967 /*
968 * If we didn't empty this mbuf, remember where we're up to.
969 * If we emptied the last mbuf, try to add the FCS and closing
970 * flag, and if we can't, leave sc_outm pointing to m, but with
971 * m->m_len == 0, to remind us to output the FCS and flag later.
972 */
973 done = len == 0;
974 if (done && m->m_next == NULL) {
975 u_char *p, *q;
976 int c;
977 u_char endseq[8];
978
979 /*
980 * We may have to escape the bytes in the FCS.
981 */
982 p = endseq;
983 c = ~sc->sc_outfcs & 0xFF;
984 if (ESCAPE_P(c)) {
985 *p++ = PPP_ESCAPE;
986 *p++ = c ^ PPP_TRANS;
987 } else
988 *p++ = c;
989 c = (~sc->sc_outfcs >> 8) & 0xFF;
990 if (ESCAPE_P(c)) {
991 *p++ = PPP_ESCAPE;
992 *p++ = c ^ PPP_TRANS;
993 } else
994 *p++ = c;
995 *p++ = PPP_FLAG;
996
997 /*
998 * Try to output the FCS and flag. If the bytes
999 * don't all fit, back out.
1000 */
1001 for (q = endseq; q < p; ++q)
1002 if (putc(*q, &tp->t_outq)) {
1003 done = 0;
1004 for (; q > endseq; --q)
1005 unputc(&tp->t_outq);
1006 break;
1007 }
1008 }
1009
1010 if (!done) {
1011 m->m_data = start;
1012 m->m_len = len;
1013 sc->sc_outm = m;
1014 if (tp->t_oproc != NULL)
1015 (*tp->t_oproc)(tp);
1016 return; /* can't do any more at the moment */
1017 }
1018
1019 /* Finished with this mbuf; free it and move on. */
1020 MFREE(m, m2);
1021 if (m2 == NULL)
1022 break;
1023
1024 m = m2;
1025 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
1026 }
1027
1028 /* Finished a packet */
1029 sc->sc_outm = NULL;
1030 sc->sc_bytessent++; /* account for closing flag */
1031 sc->sc_if.if_opackets++;
1032 sc->sc_if.if_obytes = sc->sc_bytessent;
1033 }
1034 }
1035
1036 /*
1037 * Allocate enough mbuf to handle current MRU.
1038 */
1039 static int
1040 pppgetm(sc)
1041 register struct ppp_softc *sc;
1042 {
1043 struct mbuf *m, **mp;
1044 int len = HDROFF + sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN;
1045 int s;
1046
1047 s = splimp();
1048 for (mp = &sc->sc_m; (m = *mp) != NULL; mp = &m->m_next)
1049 if ((len -= M_DATASIZE(m)) <= 0) {
1050 splx(s);
1051 return (1);
1052 }
1053
1054 for (;; mp = &m->m_next) {
1055 MGETHDR(m, M_DONTWAIT, MT_DATA);
1056 if (m == 0) {
1057 m_freem(sc->sc_m);
1058 sc->sc_m = NULL;
1059 splx(s);
1060 printf("ppp%d: can't allocate mbuf\n", sc->sc_if.if_unit);
1061 return (0);
1062 }
1063 *mp = m;
1064 MCLGET(m, M_DONTWAIT);
1065 if ((len -= M_DATASIZE(m)) <= 0) {
1066 splx(s);
1067 return (1);
1068 }
1069 }
1070 }
1071
1072 /*
1073 * Copy mbuf chain. Would like to use m_copy(), but we need a real copy
1074 * of the data, not just copies of pointers to the data.
1075 */
1076 static struct mbuf *
1077 ppp_btom(sc)
1078 struct ppp_softc *sc;
1079 {
1080 register struct mbuf *m, **mp;
1081 struct mbuf *top = sc->sc_m;
1082
1083 /*
1084 * First check current mbuf. If we have more than a small mbuf,
1085 * return the whole cluster and set beginning of buffer to the
1086 * next mbuf.
1087 * Else, copy the current bytes into a small mbuf, attach the new
1088 * mbuf to the end of the chain and set beginning of buffer to the
1089 * current mbuf.
1090 */
1091
1092 if (sc->sc_mc->m_len > MHLEN) {
1093 sc->sc_m = sc->sc_mc->m_next;
1094 sc->sc_mc->m_next = NULL;
1095 }
1096 else {
1097 /* rather than waste a whole cluster on <= MHLEN bytes,
1098 alloc a small mbuf and copy to it */
1099 MGETHDR(m, M_DONTWAIT, MT_DATA);
1100 if (m == NULL)
1101 return (NULL);
1102
1103 bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t), sc->sc_mc->m_len);
1104 m->m_len = sc->sc_mc->m_len;
1105 for (mp = ⊤ *mp != sc->sc_mc; mp = &(*mp)->m_next)
1106 ;
1107 *mp = m;
1108 sc->sc_m = sc->sc_mc;
1109 }
1110
1111 /*
1112 * Try to allocate enough extra mbufs to handle the next packet.
1113 */
1114 if (pppgetm(sc) == 0) {
1115 m_freem(top);
1116 if (pppgetm(sc) == 0)
1117 sc->sc_if.if_flags &= ~IFF_UP;
1118 return (NULL);
1119 }
1120
1121 return (top);
1122 }
1123
1124 /*
1125 * PPP packet input routine.
1126 * The caller has checked and removed the FCS.
1127 * The return value is 1 if the packet was put on sc->sc_inq,
1128 * 0 otherwise.
1129 */
1130 #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1131 TYPE_UNCOMPRESSED_TCP)
1132
1133 int
1134 ppppktin(sc, m, ilen)
1135 struct ppp_softc *sc;
1136 struct mbuf *m;
1137 int ilen;
1138 {
1139 struct ifqueue *inq;
1140 int s, xlen, proto, rv;
1141 struct ppp_header hdr;
1142
1143 sc->sc_if.if_ipackets++;
1144 rv = 0;
1145
1146 hdr = *mtod(m, struct ppp_header *);
1147 proto = ntohs(hdr.ph_protocol);
1148
1149 #ifdef VJC
1150 /*
1151 * See if we have a VJ-compressed packet to uncompress.
1152 */
1153 if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
1154 char *pkttype = proto == PPP_VJC_COMP? "": "un";
1155
1156 if (sc->sc_flags & SC_REJ_COMP_TCP) {
1157 if (sc->sc_flags & SC_DEBUG)
1158 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n",
1159 sc->sc_if.if_unit, pkttype, sc->sc_flags);
1160 sc->sc_if.if_ierrors++;
1161 return 0;
1162 }
1163
1164 m->m_data += PPP_HDRLEN;
1165 m->m_len -= PPP_HDRLEN;
1166 ilen -= PPP_HDRLEN;
1167 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data),
1168 m->m_len, ilen,
1169 COMPTYPE(proto), &sc->sc_comp);
1170
1171 if (xlen == 0) {
1172 if (sc->sc_flags & SC_DEBUG)
1173 printf("ppp%d: sl_uncompress failed on type %scomp\n",
1174 sc->sc_if.if_unit, pkttype);
1175 sc->sc_if.if_ierrors++;
1176 return 0;
1177 }
1178
1179 /* adjust the first mbuf by the decompressed amt */
1180 xlen += PPP_HDRLEN;
1181 m->m_len += xlen - ilen;
1182 ilen = xlen;
1183 m->m_data -= PPP_HDRLEN;
1184 proto = PPP_IP;
1185
1186 /* put the ppp header back in place */
1187 hdr.ph_protocol = htons(PPP_IP);
1188 *mtod(m, struct ppp_header *) = hdr;
1189 }
1190 #endif /* VJC */
1191
1192 /* get this packet as an mbuf chain */
1193 if ((m = ppp_btom(sc)) == NULL) {
1194 sc->sc_if.if_ierrors++;
1195 return 0;
1196 }
1197 m->m_pkthdr.len = ilen;
1198 m->m_pkthdr.rcvif = &sc->sc_if;
1199
1200 #if NBPFILTER > 0
1201 /* See if bpf wants to look at the packet. */
1202 if (sc->sc_bpf)
1203 bpf_mtap(sc->sc_bpf, m);
1204 #endif
1205
1206 switch (proto) {
1207 #ifdef INET
1208 case PPP_IP:
1209 /*
1210 * IP packet - take off the ppp header and pass it up to IP.
1211 */
1212 if ((sc->sc_if.if_flags & IFF_UP) == 0
1213 || (sc->sc_flags & SC_ENABLE_IP) == 0) {
1214 /* interface is down - drop the packet. */
1215 m_freem(m);
1216 return 0;
1217 }
1218 m->m_pkthdr.len -= PPP_HDRLEN;
1219 m->m_data += PPP_HDRLEN;
1220 m->m_len -= PPP_HDRLEN;
1221 schednetisr(NETISR_IP);
1222 inq = &ipintrq;
1223 break;
1224 #endif
1225
1226 default:
1227 /*
1228 * Some other protocol - place on input queue for read().
1229 */
1230 inq = &sc->sc_inq;
1231 rv = 1;
1232 break;
1233 }
1234
1235 /*
1236 * Put the packet on the appropriate input queue.
1237 */
1238 s = splimp();
1239 if (IF_QFULL(inq)) {
1240 IF_DROP(inq);
1241 if (sc->sc_flags & SC_DEBUG)
1242 printf("ppp%d: queue full\n", sc->sc_if.if_unit);
1243 sc->sc_if.if_ierrors++;
1244 sc->sc_if.if_iqdrops++;
1245 m_freem(m);
1246 rv = 0;
1247 } else
1248 IF_ENQUEUE(inq, m);
1249
1250 splx(s);
1251 return rv;
1252 }
1253
1254 /*
1255 * tty interface receiver interrupt.
1256 */
1257 static unsigned paritytab[8] = {
1258 0x96696996, 0x69969669, 0x69969669, 0x96696996,
1259 0x69969669, 0x96696996, 0x96696996, 0x69969669
1260 };
1261
1262 void
1263 pppinput(c, tp)
1264 int c;
1265 register struct tty *tp;
1266 {
1267 register struct ppp_softc *sc;
1268 struct mbuf *m;
1269 int ilen;
1270
1271 tk_nin++;
1272 sc = (struct ppp_softc *) tp->t_sc;
1273 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
1274 return;
1275
1276 ++sc->sc_bytesrcvd;
1277
1278 if (c & TTY_FE) {
1279 /* framing error or overrun on this char - abort packet */
1280 if (sc->sc_flags & SC_DEBUG)
1281 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
1282 goto flush;
1283 }
1284
1285 c &= 0xff;
1286
1287 if (c & 0x80)
1288 sc->sc_flags |= SC_RCV_B7_1;
1289 else
1290 sc->sc_flags |= SC_RCV_B7_0;
1291 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
1292 sc->sc_flags |= SC_RCV_ODDP;
1293 else
1294 sc->sc_flags |= SC_RCV_EVNP;
1295
1296 if (sc->sc_flags & SC_LOG_RAWIN)
1297 ppplogchar(sc, c);
1298
1299 if (c == PPP_FLAG) {
1300 ilen = sc->sc_ilen;
1301 sc->sc_ilen = 0;
1302 sc->sc_if.if_ibytes = sc->sc_bytesrcvd;
1303
1304 if (sc->sc_rawin_count > 0)
1305 ppplogchar(sc, -1);
1306
1307 /*
1308 * If SC_ESCAPED is set, then we've seen the packet
1309 * abort sequence "}~".
1310 */
1311 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1312 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
1313 #ifdef VJC
1314 /*
1315 * If we've missed a packet, we must toss subsequent compressed
1316 * packets which don't have an explicit connection ID.
1317 */
1318 sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp);
1319 #endif
1320 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1321 if (sc->sc_flags & SC_DEBUG)
1322 printf("ppp%d: bad fcs\n", sc->sc_if.if_unit);
1323 sc->sc_if.if_ierrors++;
1324 } else
1325 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1326 return;
1327 }
1328
1329 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1330 if (ilen) {
1331 if (sc->sc_flags & SC_DEBUG)
1332 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
1333 sc->sc_if.if_ierrors++;
1334 }
1335 return;
1336 }
1337
1338 /*
1339 * Remove FCS trailer. Somewhat painful...
1340 */
1341 ilen -= 2;
1342 if (--sc->sc_mc->m_len == 0) {
1343 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1344 ;
1345 sc->sc_mc = m;
1346 }
1347 sc->sc_mc->m_len--;
1348
1349 m = sc->sc_m;
1350
1351 if (sc->sc_flags & SC_LOG_INPKT) {
1352 printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen);
1353 pppdumpm(m, ilen);
1354 }
1355
1356 if (ppppktin(sc, m, ilen)) {
1357 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
1358 putc(0, &tp->t_canq);
1359 ttwakeup(tp);
1360 }
1361 return;
1362 }
1363
1364 if (sc->sc_flags & SC_FLUSH) {
1365 if (sc->sc_flags & SC_LOG_FLUSH)
1366 ppplogchar(sc, c);
1367 return;
1368 }
1369
1370 if (c == PPP_ESCAPE) {
1371 sc->sc_flags |= SC_ESCAPED;
1372 return;
1373 }
1374 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1375 return;
1376
1377 if (sc->sc_flags & SC_ESCAPED) {
1378 sc->sc_flags &= ~SC_ESCAPED;
1379 c ^= PPP_TRANS;
1380 }
1381
1382 /*
1383 * Initialize buffer on first octet received.
1384 * First octet could be address or protocol (when compressing
1385 * address/control).
1386 * Second octet is control.
1387 * Third octet is first or second (when compressing protocol)
1388 * octet of protocol.
1389 * Fourth octet is second octet of protocol.
1390 */
1391 if (sc->sc_ilen == 0) {
1392 /* reset the first input mbuf */
1393 m = sc->sc_m;
1394 m->m_len = 0;
1395 m->m_data = M_DATASTART(sc->sc_m) + HDROFF;
1396 sc->sc_mc = m;
1397 sc->sc_mp = mtod(m, char *);
1398 sc->sc_fcs = PPP_INITFCS;
1399 if (c != PPP_ALLSTATIONS) {
1400 if (sc->sc_flags & SC_REJ_COMP_AC) {
1401 if (sc->sc_flags & SC_DEBUG)
1402 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
1403 sc->sc_if.if_unit, c);
1404 goto flush;
1405 }
1406 *sc->sc_mp++ = PPP_ALLSTATIONS;
1407 *sc->sc_mp++ = PPP_UI;
1408 sc->sc_ilen += 2;
1409 m->m_len += 2;
1410 }
1411 }
1412 if (sc->sc_ilen == 1 && c != PPP_UI) {
1413 if (sc->sc_flags & SC_DEBUG)
1414 printf("ppp%d: missing UI (0x3), got 0x%x\n",
1415 sc->sc_if.if_unit, c);
1416 goto flush;
1417 }
1418 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1419 /* a compressed protocol */
1420 *sc->sc_mp++ = 0;
1421 sc->sc_ilen++;
1422 sc->sc_mc->m_len++;
1423 }
1424 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1425 if (sc->sc_flags & SC_DEBUG)
1426 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1427 (sc->sc_mp[-1] << 8) + c);
1428 goto flush;
1429 }
1430
1431 /* packet beyond configured mru? */
1432 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1433 if (sc->sc_flags & SC_DEBUG)
1434 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
1435 goto flush;
1436 }
1437
1438 /* is this mbuf full? */
1439 m = sc->sc_mc;
1440 if (M_TRAILINGSPACE(m) <= 0) {
1441 sc->sc_mc = m = m->m_next;
1442 if (m == NULL) {
1443 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1444 goto flush;
1445 }
1446 m->m_len = 0;
1447 m->m_data = M_DATASTART(m);
1448 sc->sc_mp = mtod(m, char *);
1449 }
1450
1451 ++m->m_len;
1452 *sc->sc_mp++ = c;
1453 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1454 return;
1455
1456 flush:
1457 if (!(sc->sc_flags & SC_FLUSH)) {
1458 sc->sc_if.if_ierrors++;
1459 sc->sc_flags |= SC_FLUSH;
1460 if (sc->sc_flags & SC_LOG_FLUSH)
1461 ppplogchar(sc, c);
1462 }
1463 }
1464
1465 /*
1466 * Process an ioctl request to interface.
1467 */
1468 pppioctl(ifp, cmd, data)
1469 register struct ifnet *ifp;
1470 int cmd;
1471 caddr_t data;
1472 {
1473 struct proc *p = curproc; /* XXX */
1474 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
1475 register struct ifaddr *ifa = (struct ifaddr *)data;
1476 register struct ifreq *ifr = (struct ifreq *)data;
1477 int s = splimp(), error = 0;
1478
1479
1480 switch (cmd) {
1481 case SIOCSIFFLAGS:
1482 if ((ifp->if_flags & IFF_RUNNING) == 0)
1483 ifp->if_flags &= ~IFF_UP;
1484 break;
1485
1486 case SIOCSIFADDR:
1487 if (ifa->ifa_addr->sa_family != AF_INET)
1488 error = EAFNOSUPPORT;
1489 break;
1490
1491 case SIOCSIFDSTADDR:
1492 if (ifa->ifa_addr->sa_family != AF_INET)
1493 error = EAFNOSUPPORT;
1494 break;
1495
1496 case SIOCSIFMTU:
1497 if (error = suser(p->p_ucred, &p->p_acflag))
1498 return (error);
1499 sc->sc_if.if_mtu = ifr->ifr_mtu;
1500 break;
1501
1502 case SIOCGIFMTU:
1503 ifr->ifr_mtu = sc->sc_if.if_mtu;
1504 break;
1505
1506 default:
1507 error = EINVAL;
1508 }
1509 splx(s);
1510 return (error);
1511 }
1512
1513 #define MAX_DUMP_BYTES 128
1514
1515 static void
1516 pppdumpm(m0, pktlen)
1517 struct mbuf *m0;
1518 int pktlen;
1519 {
1520 char buf[3*MAX_DUMP_BYTES+4];
1521 char *bp = buf;
1522 struct mbuf *m;
1523 static char digits[] = "0123456789abcdef";
1524
1525 for (m = m0; m && pktlen; m = m->m_next) {
1526 int l = m->m_len;
1527 u_char *rptr = (u_char *)m->m_data;
1528
1529 if (pktlen > 0) {
1530 l = min(l, pktlen);
1531 pktlen -= l;
1532 }
1533 while (l--) {
1534 if (bp > buf + sizeof(buf) - 4)
1535 goto done;
1536 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1537 *bp++ = digits[*rptr++ & 0xf];
1538 }
1539
1540 if (m->m_next) {
1541 if (bp > buf + sizeof(buf) - 3)
1542 goto done;
1543 *bp++ = '|';
1544 } else
1545 *bp++ = ' ';
1546 }
1547 done:
1548 if (m && pktlen)
1549 *bp++ = '>';
1550 *bp = 0;
1551 printf("%s\n", buf);
1552 }
1553
1554 static void
1555 ppplogchar(sc, c)
1556 struct ppp_softc *sc;
1557 int c;
1558 {
1559 if (c >= 0)
1560 sc->sc_rawin[sc->sc_rawin_count++] = c;
1561 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1562 || c < 0 && sc->sc_rawin_count > 0) {
1563 printf("ppp%d input: ", sc->sc_if.if_unit);
1564 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1565 sc->sc_rawin_count = 0;
1566 }
1567 }
1568
1569 static void
1570 pppdumpb(b, l)
1571 u_char *b;
1572 int l;
1573 {
1574 char buf[3*MAX_DUMP_BYTES+4];
1575 char *bp = buf;
1576 static char digits[] = "0123456789abcdef";
1577
1578 while (l--) {
1579 if (bp >= buf + sizeof(buf) - 3) {
1580 *bp++ = '>';
1581 break;
1582 }
1583 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1584 *bp++ = digits[*b++ & 0xf];
1585 *bp++ = ' ';
1586 }
1587
1588 *bp = 0;
1589 printf("%s\n", buf);
1590 }
1591
1592
1593 #endif /* NPPP > 0 */
1594