if_ppp.c revision 1.8 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.8 1994/05/08 12:33:49 paulus 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));
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);
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));
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_setup(&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)
614 struct ifnet *ifp;
615 struct mbuf *m0;
616 struct sockaddr *dst;
617 {
618 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
619 struct ppp_header *ph;
620 int protocol, address, control;
621 u_char *cp;
622 int s, error;
623 struct ip *ip;
624 struct ifqueue *ifq;
625
626 if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
627 || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) {
628 error = ENETDOWN; /* sort of */
629 goto bad;
630 }
631
632 /*
633 * Compute PPP header.
634 */
635 address = PPP_ALLSTATIONS;
636 control = PPP_UI;
637 ifq = &ifp->if_snd;
638 switch (dst->sa_family) {
639 #ifdef INET
640 case AF_INET:
641 protocol = PPP_IP;
642 if ((sc->sc_flags & SC_ENABLE_IP) == 0) {
643 error = ENETDOWN;
644 goto bad;
645 }
646
647 /*
648 * If this is a TCP packet to or from an "interactive" port,
649 * put the packet on the fastq instead.
650 */
651 if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
652 register int p = ntohl(((int *)ip)[ip->ip_hl]);
653 if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
654 ifq = &sc->sc_fastq;
655 }
656 break;
657 #endif
658 #ifdef NS
659 case AF_NS:
660 protocol = PPP_XNS;
661 break;
662 #endif
663 case AF_UNSPEC:
664 ph = (struct ppp_header *) dst->sa_data;
665 address = ph->ph_address;
666 control = ph->ph_control;
667 protocol = ntohs(ph->ph_protocol);
668 break;
669 default:
670 printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
671 error = EAFNOSUPPORT;
672 goto bad;
673 }
674
675 /*
676 * Add PPP header. If no space in first mbuf, allocate another.
677 * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
678 */
679 if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
680 m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT);
681 if (m0 == 0) {
682 error = ENOBUFS;
683 goto bad;
684 }
685 m0->m_len = 0;
686 } else
687 m0->m_data -= PPP_HDRLEN;
688
689 cp = mtod(m0, u_char *);
690 *cp++ = address;
691 *cp++ = control;
692 *cp++ = protocol >> 8;
693 *cp++ = protocol & 0xff;
694 m0->m_len += PPP_HDRLEN;
695
696 if (sc->sc_flags & SC_LOG_OUTPKT) {
697 printf("ppp%d output: ", ifp->if_unit);
698 pppdumpm(m0, -1);
699 }
700
701 #if NBPFILTER > 0
702 /* See if bpf wants to look at the packet. */
703 if (sc->sc_bpf)
704 bpf_mtap(sc->sc_bpf, m0);
705 #endif
706
707 /*
708 * Put the packet on the appropriate queue.
709 */
710 s = splimp();
711 if (IF_QFULL(ifq)) {
712 IF_DROP(ifq);
713 splx(s);
714 sc->sc_if.if_oerrors++;
715 error = ENOBUFS;
716 goto bad;
717 }
718 IF_ENQUEUE(ifq, m0);
719
720 /*
721 * Tell the device to send it out.
722 */
723 (*sc->sc_start)(sc);
724
725 splx(s);
726 return (0);
727
728 bad:
729 m_freem(m0);
730 return (error);
731 }
732
733 /*
734 * Grab another packet off a queue and apply VJ compression,
735 * address/control and/or protocol compression if appropriate.
736 */
737 struct mbuf *
738 ppp_dequeue(sc)
739 struct ppp_softc *sc;
740 {
741 int s;
742 struct mbuf *m;
743 u_char *cp;
744 int address, control, protocol;
745
746 s = splimp();
747 IF_DEQUEUE(&sc->sc_fastq, m);
748 if (m == NULL)
749 IF_DEQUEUE(&sc->sc_if.if_snd, m);
750 splx(s);
751 if (m == NULL)
752 return NULL;
753
754 /*
755 * Extract the ppp header of the new packet.
756 * The ppp header will be in one mbuf.
757 */
758 cp = mtod(m, u_char *);
759 address = cp[0];
760 control = cp[1];
761 protocol = (cp[2] << 8) + cp[3];
762
763 #ifdef VJC
764 /*
765 * If the packet is a TCP/IP packet, see if we can compress it.
766 */
767 if (protocol == PPP_IP && sc->sc_flags & SC_COMP_TCP) {
768 struct ip *ip;
769 int type;
770 struct mbuf *mp;
771
772 mp = m;
773 ip = (struct ip *) (cp + PPP_HDRLEN);
774 if (mp->m_len <= PPP_HDRLEN) {
775 mp = mp->m_next;
776 ip = mtod(mp, struct ip *);
777 }
778 /* this code assumes the IP/TCP header is in one non-shared mbuf */
779 if (ip->ip_p == IPPROTO_TCP) {
780 type = sl_compress_tcp(mp, ip, &sc->sc_comp,
781 !(sc->sc_flags & SC_NO_TCP_CCID));
782 switch (type) {
783 case TYPE_UNCOMPRESSED_TCP:
784 protocol = PPP_VJC_UNCOMP;
785 break;
786 case TYPE_COMPRESSED_TCP:
787 protocol = PPP_VJC_COMP;
788 cp = mtod(m, u_char *);
789 cp[0] = address; /* header has moved */
790 cp[1] = control;
791 cp[2] = 0;
792 break;
793 }
794 cp[3] = protocol; /* update protocol in PPP header */
795 }
796 }
797 #endif /* VJC */
798
799 #ifdef BSD_COMP
800 if (protocol < PPP_COMP && (sc->sc_flags & SC_BSD_COMP)) {
801 slen = m_totallen(m0);
802 clen = pf_bsd_comp(sc->sc_bsd_db, cbuf, proto, m0, slen);
803 }
804 #endif /* BSD_COMP */
805
806 /*
807 * Compress the address/control and protocol, if possible.
808 */
809 if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
810 control == PPP_UI && protocol != PPP_ALLSTATIONS &&
811 protocol != PPP_LCP) {
812 /* can compress address/control */
813 m->m_data += 2;
814 m->m_len -= 2;
815 }
816 if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
817 /* can compress protocol */
818 if (mtod(m, u_char *) == cp) {
819 cp[2] = cp[1]; /* move address/control up */
820 cp[1] = cp[0];
821 }
822 ++m->m_data;
823 --m->m_len;
824 }
825
826 return m;
827 }
828
829 /*
830 * This gets called from pppoutput when a new packet is
831 * put on a queue.
832 */
833 static
834 pppasyncstart(sc)
835 register struct ppp_softc *sc;
836 {
837 register struct tty *tp = (struct tty *) sc->sc_devp;
838
839 pppstart(tp);
840 }
841
842 /*
843 * Start output on async tty interface. Get another datagram
844 * to send from the interface queue and start sending it.
845 */
846 void
847 pppstart(tp)
848 register struct tty *tp;
849 {
850 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
851 register struct mbuf *m;
852 register int len;
853 register u_char *start, *stop, *cp;
854 int n, s, ndone, done;
855 struct mbuf *m2;
856
857 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
858 /* sorry, I can't talk now */
859 return;
860 }
861 if (sc == NULL || tp != (struct tty *) sc->sc_devp) {
862 (*tp->t_oproc)(tp);
863 return;
864 }
865
866 for (;;) {
867 /*
868 * If there is more in the output queue, just send it now.
869 * We are being called in lieu of ttstart and must do what
870 * it would.
871 */
872 if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) {
873 (*tp->t_oproc)(tp);
874 if (CCOUNT(&tp->t_outq) > PPP_HIWAT)
875 return;
876 }
877
878 /*
879 * See if we have an existing packet partly sent.
880 * If not, get a new packet and start sending it.
881 * We take packets on the priority queue ahead of those
882 * on the normal queue.
883 */
884 m = sc->sc_outm;
885 if (m == NULL) {
886 /*
887 * Get another packet to be sent
888 */
889 m = ppp_dequeue(sc);
890 if (m == NULL)
891 return;
892
893 /*
894 * The extra PPP_FLAG will start up a new packet, and thus
895 * will flush any accumulated garbage. We do this whenever
896 * the line may have been idle for some time.
897 */
898 if (CCOUNT(&tp->t_outq) == 0) {
899 ++sc->sc_bytessent;
900 (void) putc(PPP_FLAG, &tp->t_outq);
901 }
902
903 /* Calculate the FCS for the first mbuf's worth. */
904 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
905 }
906
907 for (;;) {
908 start = mtod(m, u_char *);
909 len = m->m_len;
910 stop = start + len;
911 while (len > 0) {
912 /*
913 * Find out how many bytes in the string we can
914 * handle without doing something special.
915 */
916 for (cp = start; cp < stop; cp++)
917 if (ESCAPE_P(*cp))
918 break;
919 n = cp - start;
920 if (n) {
921 #ifndef RB_LEN
922 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
923 ndone = n - b_to_q(start, n, &tp->t_outq);
924 #else
925 #ifdef NetBSD
926 /* NetBSD with 2-byte ring buffer entries */
927 ndone = rb_cwrite(&tp->t_out, start, n);
928 #else
929 /* 386BSD, FreeBSD */
930 int cc, nleft;
931 for (nleft = n; nleft > 0; nleft -= cc) {
932 if ((cc = RB_CONTIGPUT(&tp->t_out)) == 0)
933 break;
934 cc = min (cc, nleft);
935 bcopy((char *)start + n - nleft, tp->t_out.rb_tl, cc);
936 tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
937 tp->t_out.rb_tl + cc);
938 }
939 ndone = n - nleft;
940 #endif /* NetBSD */
941 #endif /* RB_LEN */
942 len -= ndone;
943 start += ndone;
944 sc->sc_bytessent += ndone;
945
946 if (ndone < n)
947 break; /* packet doesn't fit */
948 }
949 /*
950 * If there are characters left in the mbuf,
951 * the first one must be special..
952 * Put it out in a different form.
953 */
954 if (len) {
955 if (putc(PPP_ESCAPE, &tp->t_outq))
956 break;
957 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
958 (void) unputc(&tp->t_outq);
959 break;
960 }
961 sc->sc_bytessent += 2;
962 start++;
963 len--;
964 }
965 }
966 /*
967 * If we didn't empty this mbuf, remember where we're up to.
968 * If we emptied the last mbuf, try to add the FCS and closing
969 * flag, and if we can't, leave sc_outm pointing to m, but with
970 * m->m_len == 0, to remind us to output the FCS and flag later.
971 */
972 done = len == 0;
973 if (done && m->m_next == NULL) {
974 u_char *p, *q;
975 int c;
976 u_char endseq[8];
977
978 /*
979 * We may have to escape the bytes in the FCS.
980 */
981 p = endseq;
982 c = ~sc->sc_outfcs & 0xFF;
983 if (ESCAPE_P(c)) {
984 *p++ = PPP_ESCAPE;
985 *p++ = c ^ PPP_TRANS;
986 } else
987 *p++ = c;
988 c = (~sc->sc_outfcs >> 8) & 0xFF;
989 if (ESCAPE_P(c)) {
990 *p++ = PPP_ESCAPE;
991 *p++ = c ^ PPP_TRANS;
992 } else
993 *p++ = c;
994 *p++ = PPP_FLAG;
995
996 /*
997 * Try to output the FCS and flag. If the bytes
998 * don't all fit, back out.
999 */
1000 for (q = endseq; q < p; ++q)
1001 if (putc(*q, &tp->t_outq)) {
1002 done = 0;
1003 for (; q > endseq; --q)
1004 unputc(&tp->t_outq);
1005 break;
1006 }
1007 }
1008
1009 if (!done) {
1010 m->m_data = start;
1011 m->m_len = len;
1012 sc->sc_outm = m;
1013 if (tp->t_oproc != NULL)
1014 (*tp->t_oproc)(tp);
1015 return; /* can't do any more at the moment */
1016 }
1017
1018 /* Finished with this mbuf; free it and move on. */
1019 MFREE(m, m2);
1020 if (m2 == NULL)
1021 break;
1022
1023 m = m2;
1024 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
1025 }
1026
1027 /* Finished a packet */
1028 sc->sc_outm = NULL;
1029 sc->sc_bytessent++; /* account for closing flag */
1030 sc->sc_if.if_opackets++;
1031 sc->sc_if.if_obytes = sc->sc_bytessent;
1032 }
1033 }
1034
1035 /*
1036 * Allocate enough mbuf to handle current MRU.
1037 */
1038 static int
1039 pppgetm(sc)
1040 register struct ppp_softc *sc;
1041 {
1042 struct mbuf *m, **mp;
1043 int len = HDROFF + sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN;
1044 int s;
1045
1046 s = splimp();
1047 for (mp = &sc->sc_m; (m = *mp) != NULL; mp = &m->m_next)
1048 if ((len -= M_DATASIZE(m)) <= 0) {
1049 splx(s);
1050 return (1);
1051 }
1052
1053 for (;; mp = &m->m_next) {
1054 MGETHDR(m, M_DONTWAIT, MT_DATA);
1055 if (m == 0) {
1056 m_freem(sc->sc_m);
1057 sc->sc_m = NULL;
1058 splx(s);
1059 printf("ppp%d: can't allocate mbuf\n", sc->sc_if.if_unit);
1060 return (0);
1061 }
1062 *mp = m;
1063 MCLGET(m, M_DONTWAIT);
1064 if ((len -= M_DATASIZE(m)) <= 0) {
1065 splx(s);
1066 return (1);
1067 }
1068 }
1069 }
1070
1071 /*
1072 * Copy mbuf chain. Would like to use m_copy(), but we need a real copy
1073 * of the data, not just copies of pointers to the data.
1074 */
1075 static struct mbuf *
1076 ppp_btom(sc)
1077 struct ppp_softc *sc;
1078 {
1079 register struct mbuf *m, **mp;
1080 struct mbuf *top = sc->sc_m;
1081
1082 /*
1083 * First check current mbuf. If we have more than a small mbuf,
1084 * return the whole cluster and set beginning of buffer to the
1085 * next mbuf.
1086 * Else, copy the current bytes into a small mbuf, attach the new
1087 * mbuf to the end of the chain and set beginning of buffer to the
1088 * current mbuf.
1089 */
1090
1091 if (sc->sc_mc->m_len > MHLEN) {
1092 sc->sc_m = sc->sc_mc->m_next;
1093 sc->sc_mc->m_next = NULL;
1094 }
1095 else {
1096 /* rather than waste a whole cluster on <= MHLEN bytes,
1097 alloc a small mbuf and copy to it */
1098 MGETHDR(m, M_DONTWAIT, MT_DATA);
1099 if (m == NULL)
1100 return (NULL);
1101
1102 bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t), sc->sc_mc->m_len);
1103 m->m_len = sc->sc_mc->m_len;
1104 for (mp = ⊤ *mp != sc->sc_mc; mp = &(*mp)->m_next)
1105 ;
1106 *mp = m;
1107 sc->sc_m = sc->sc_mc;
1108 }
1109
1110 /*
1111 * Try to allocate enough extra mbufs to handle the next packet.
1112 */
1113 if (pppgetm(sc) == 0) {
1114 m_freem(top);
1115 if (pppgetm(sc) == 0)
1116 sc->sc_if.if_flags &= ~IFF_UP;
1117 return (NULL);
1118 }
1119
1120 return (top);
1121 }
1122
1123 /*
1124 * PPP packet input routine.
1125 * The caller has checked and removed the FCS.
1126 * The return value is 1 if the packet was put on sc->sc_inq,
1127 * 0 otherwise.
1128 */
1129 #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1130 TYPE_UNCOMPRESSED_TCP)
1131
1132 int
1133 ppppktin(sc, m, ilen)
1134 struct ppp_softc *sc;
1135 struct mbuf *m;
1136 int ilen;
1137 {
1138 struct ifqueue *inq;
1139 int s, xlen, proto, rv;
1140 struct ppp_header hdr;
1141
1142 sc->sc_if.if_ipackets++;
1143 rv = 0;
1144
1145 hdr = *mtod(m, struct ppp_header *);
1146 proto = ntohs(hdr.ph_protocol);
1147
1148 #ifdef VJC
1149 /*
1150 * See if we have a VJ-compressed packet to uncompress.
1151 */
1152 if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
1153 char *pkttype = proto == PPP_VJC_COMP? "": "un";
1154
1155 if (sc->sc_flags & SC_REJ_COMP_TCP) {
1156 if (sc->sc_flags & SC_DEBUG)
1157 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n",
1158 sc->sc_if.if_unit, pkttype, sc->sc_flags);
1159 sc->sc_if.if_ierrors++;
1160 return 0;
1161 }
1162
1163 m->m_data += PPP_HDRLEN;
1164 m->m_len -= PPP_HDRLEN;
1165 ilen -= PPP_HDRLEN;
1166 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data),
1167 m->m_len, ilen,
1168 COMPTYPE(proto), &sc->sc_comp);
1169
1170 if (xlen == 0) {
1171 if (sc->sc_flags & SC_DEBUG)
1172 printf("ppp%d: sl_uncompress failed on type %scomp\n",
1173 sc->sc_if.if_unit, pkttype);
1174 sc->sc_if.if_ierrors++;
1175 return 0;
1176 }
1177
1178 /* adjust the first mbuf by the decompressed amt */
1179 xlen += PPP_HDRLEN;
1180 m->m_len += xlen - ilen;
1181 ilen = xlen;
1182 m->m_data -= PPP_HDRLEN;
1183 proto = PPP_IP;
1184
1185 /* put the ppp header back in place */
1186 hdr.ph_protocol = htons(PPP_IP);
1187 *mtod(m, struct ppp_header *) = hdr;
1188 }
1189 #endif /* VJC */
1190
1191 /* get this packet as an mbuf chain */
1192 if ((m = ppp_btom(sc)) == NULL) {
1193 sc->sc_if.if_ierrors++;
1194 return 0;
1195 }
1196 m->m_pkthdr.len = ilen;
1197 m->m_pkthdr.rcvif = &sc->sc_if;
1198
1199 #if NBPFILTER > 0
1200 /* See if bpf wants to look at the packet. */
1201 if (sc->sc_bpf)
1202 bpf_mtap(sc->sc_bpf, m);
1203 #endif
1204
1205 switch (proto) {
1206 #ifdef INET
1207 case PPP_IP:
1208 /*
1209 * IP packet - take off the ppp header and pass it up to IP.
1210 */
1211 if ((sc->sc_if.if_flags & IFF_UP) == 0
1212 || (sc->sc_flags & SC_ENABLE_IP) == 0) {
1213 /* interface is down - drop the packet. */
1214 m_freem(m);
1215 return 0;
1216 }
1217 m->m_pkthdr.len -= PPP_HDRLEN;
1218 m->m_data += PPP_HDRLEN;
1219 m->m_len -= PPP_HDRLEN;
1220 schednetisr(NETISR_IP);
1221 inq = &ipintrq;
1222 break;
1223 #endif
1224
1225 default:
1226 /*
1227 * Some other protocol - place on input queue for read().
1228 */
1229 inq = &sc->sc_inq;
1230 rv = 1;
1231 break;
1232 }
1233
1234 /*
1235 * Put the packet on the appropriate input queue.
1236 */
1237 s = splimp();
1238 if (IF_QFULL(inq)) {
1239 IF_DROP(inq);
1240 if (sc->sc_flags & SC_DEBUG)
1241 printf("ppp%d: queue full\n", sc->sc_if.if_unit);
1242 sc->sc_if.if_ierrors++;
1243 sc->sc_if.if_iqdrops++;
1244 m_freem(m);
1245 rv = 0;
1246 } else
1247 IF_ENQUEUE(inq, m);
1248
1249 splx(s);
1250 return rv;
1251 }
1252
1253 /*
1254 * tty interface receiver interrupt.
1255 */
1256 static unsigned paritytab[8] = {
1257 0x96696996, 0x69969669, 0x69969669, 0x96696996,
1258 0x69969669, 0x96696996, 0x96696996, 0x69969669
1259 };
1260
1261 void
1262 pppinput(c, tp)
1263 int c;
1264 register struct tty *tp;
1265 {
1266 register struct ppp_softc *sc;
1267 struct mbuf *m;
1268 int ilen;
1269
1270 tk_nin++;
1271 sc = (struct ppp_softc *) tp->t_sc;
1272 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
1273 return;
1274
1275 ++sc->sc_bytesrcvd;
1276
1277 if (c & TTY_FE) {
1278 /* framing error or overrun on this char - abort packet */
1279 if (sc->sc_flags & SC_DEBUG)
1280 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
1281 goto flush;
1282 }
1283
1284 c &= 0xff;
1285
1286 if (c & 0x80)
1287 sc->sc_flags |= SC_RCV_B7_1;
1288 else
1289 sc->sc_flags |= SC_RCV_B7_0;
1290 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
1291 sc->sc_flags |= SC_RCV_ODDP;
1292 else
1293 sc->sc_flags |= SC_RCV_EVNP;
1294
1295 if (sc->sc_flags & SC_LOG_RAWIN)
1296 ppplogchar(sc, c);
1297
1298 if (c == PPP_FLAG) {
1299 ilen = sc->sc_ilen;
1300 sc->sc_ilen = 0;
1301 sc->sc_if.if_ibytes = sc->sc_bytesrcvd;
1302
1303 if (sc->sc_rawin_count > 0)
1304 ppplogchar(sc, -1);
1305
1306 /*
1307 * If SC_ESCAPED is set, then we've seen the packet
1308 * abort sequence "}~".
1309 */
1310 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1311 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
1312 #ifdef VJC
1313 /*
1314 * If we've missed a packet, we must toss subsequent compressed
1315 * packets which don't have an explicit connection ID.
1316 */
1317 sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp);
1318 #endif
1319 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1320 if (sc->sc_flags & SC_DEBUG)
1321 printf("ppp%d: bad fcs\n", sc->sc_if.if_unit);
1322 sc->sc_if.if_ierrors++;
1323 } else
1324 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1325 return;
1326 }
1327
1328 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1329 if (ilen) {
1330 if (sc->sc_flags & SC_DEBUG)
1331 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
1332 sc->sc_if.if_ierrors++;
1333 }
1334 return;
1335 }
1336
1337 /*
1338 * Remove FCS trailer. Somewhat painful...
1339 */
1340 ilen -= 2;
1341 if (--sc->sc_mc->m_len == 0) {
1342 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1343 ;
1344 sc->sc_mc = m;
1345 }
1346 sc->sc_mc->m_len--;
1347
1348 m = sc->sc_m;
1349
1350 if (sc->sc_flags & SC_LOG_INPKT) {
1351 printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen);
1352 pppdumpm(m, ilen);
1353 }
1354
1355 if (ppppktin(sc, m, ilen)) {
1356 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
1357 putc(0, &tp->t_canq);
1358 ttwakeup(tp);
1359 }
1360 return;
1361 }
1362
1363 if (sc->sc_flags & SC_FLUSH) {
1364 if (sc->sc_flags & SC_LOG_FLUSH)
1365 ppplogchar(sc, c);
1366 return;
1367 }
1368
1369 if (c == PPP_ESCAPE) {
1370 sc->sc_flags |= SC_ESCAPED;
1371 return;
1372 }
1373 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1374 return;
1375
1376 if (sc->sc_flags & SC_ESCAPED) {
1377 sc->sc_flags &= ~SC_ESCAPED;
1378 c ^= PPP_TRANS;
1379 }
1380
1381 /*
1382 * Initialize buffer on first octet received.
1383 * First octet could be address or protocol (when compressing
1384 * address/control).
1385 * Second octet is control.
1386 * Third octet is first or second (when compressing protocol)
1387 * octet of protocol.
1388 * Fourth octet is second octet of protocol.
1389 */
1390 if (sc->sc_ilen == 0) {
1391 /* reset the first input mbuf */
1392 m = sc->sc_m;
1393 m->m_len = 0;
1394 m->m_data = M_DATASTART(sc->sc_m) + HDROFF;
1395 sc->sc_mc = m;
1396 sc->sc_mp = mtod(m, char *);
1397 sc->sc_fcs = PPP_INITFCS;
1398 if (c != PPP_ALLSTATIONS) {
1399 if (sc->sc_flags & SC_REJ_COMP_AC) {
1400 if (sc->sc_flags & SC_DEBUG)
1401 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
1402 sc->sc_if.if_unit, c);
1403 goto flush;
1404 }
1405 *sc->sc_mp++ = PPP_ALLSTATIONS;
1406 *sc->sc_mp++ = PPP_UI;
1407 sc->sc_ilen += 2;
1408 m->m_len += 2;
1409 }
1410 }
1411 if (sc->sc_ilen == 1 && c != PPP_UI) {
1412 if (sc->sc_flags & SC_DEBUG)
1413 printf("ppp%d: missing UI (0x3), got 0x%x\n",
1414 sc->sc_if.if_unit, c);
1415 goto flush;
1416 }
1417 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1418 /* a compressed protocol */
1419 *sc->sc_mp++ = 0;
1420 sc->sc_ilen++;
1421 sc->sc_mc->m_len++;
1422 }
1423 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1424 if (sc->sc_flags & SC_DEBUG)
1425 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1426 (sc->sc_mp[-1] << 8) + c);
1427 goto flush;
1428 }
1429
1430 /* packet beyond configured mru? */
1431 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1432 if (sc->sc_flags & SC_DEBUG)
1433 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
1434 goto flush;
1435 }
1436
1437 /* is this mbuf full? */
1438 m = sc->sc_mc;
1439 if (M_TRAILINGSPACE(m) <= 0) {
1440 sc->sc_mc = m = m->m_next;
1441 if (m == NULL) {
1442 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1443 goto flush;
1444 }
1445 m->m_len = 0;
1446 m->m_data = M_DATASTART(m);
1447 sc->sc_mp = mtod(m, char *);
1448 }
1449
1450 ++m->m_len;
1451 *sc->sc_mp++ = c;
1452 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1453 return;
1454
1455 flush:
1456 if (!(sc->sc_flags & SC_FLUSH)) {
1457 sc->sc_if.if_ierrors++;
1458 sc->sc_flags |= SC_FLUSH;
1459 if (sc->sc_flags & SC_LOG_FLUSH)
1460 ppplogchar(sc, c);
1461 }
1462 }
1463
1464 /*
1465 * Process an ioctl request to interface.
1466 */
1467 pppioctl(ifp, cmd, data)
1468 register struct ifnet *ifp;
1469 int cmd;
1470 caddr_t data;
1471 {
1472 struct proc *p = curproc; /* XXX */
1473 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
1474 register struct ifaddr *ifa = (struct ifaddr *)data;
1475 register struct ifreq *ifr = (struct ifreq *)data;
1476 int s = splimp(), error = 0;
1477
1478
1479 switch (cmd) {
1480 case SIOCSIFFLAGS:
1481 if ((ifp->if_flags & IFF_RUNNING) == 0)
1482 ifp->if_flags &= ~IFF_UP;
1483 break;
1484
1485 case SIOCSIFADDR:
1486 if (ifa->ifa_addr->sa_family != AF_INET)
1487 error = EAFNOSUPPORT;
1488 break;
1489
1490 case SIOCSIFDSTADDR:
1491 if (ifa->ifa_addr->sa_family != AF_INET)
1492 error = EAFNOSUPPORT;
1493 break;
1494
1495 case SIOCSIFMTU:
1496 if (error = suser(p->p_ucred, &p->p_acflag))
1497 return (error);
1498 sc->sc_if.if_mtu = ifr->ifr_mtu;
1499 break;
1500
1501 case SIOCGIFMTU:
1502 ifr->ifr_mtu = sc->sc_if.if_mtu;
1503 break;
1504
1505 default:
1506 error = EINVAL;
1507 }
1508 splx(s);
1509 return (error);
1510 }
1511
1512 #define MAX_DUMP_BYTES 128
1513
1514 static void
1515 pppdumpm(m0, pktlen)
1516 struct mbuf *m0;
1517 int pktlen;
1518 {
1519 char buf[3*MAX_DUMP_BYTES+4];
1520 char *bp = buf;
1521 struct mbuf *m;
1522 static char digits[] = "0123456789abcdef";
1523
1524 for (m = m0; m && pktlen; m = m->m_next) {
1525 int l = m->m_len;
1526 u_char *rptr = (u_char *)m->m_data;
1527
1528 if (pktlen > 0) {
1529 l = min(l, pktlen);
1530 pktlen -= l;
1531 }
1532 while (l--) {
1533 if (bp > buf + sizeof(buf) - 4)
1534 goto done;
1535 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1536 *bp++ = digits[*rptr++ & 0xf];
1537 }
1538
1539 if (m->m_next) {
1540 if (bp > buf + sizeof(buf) - 3)
1541 goto done;
1542 *bp++ = '|';
1543 } else
1544 *bp++ = ' ';
1545 }
1546 done:
1547 if (m && pktlen)
1548 *bp++ = '>';
1549 *bp = 0;
1550 printf("%s\n", buf);
1551 }
1552
1553 static void
1554 ppplogchar(sc, c)
1555 struct ppp_softc *sc;
1556 int c;
1557 {
1558 if (c >= 0)
1559 sc->sc_rawin[sc->sc_rawin_count++] = c;
1560 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1561 || c < 0 && sc->sc_rawin_count > 0) {
1562 printf("ppp%d input: ", sc->sc_if.if_unit);
1563 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1564 sc->sc_rawin_count = 0;
1565 }
1566 }
1567
1568 static void
1569 pppdumpb(b, l)
1570 u_char *b;
1571 int l;
1572 {
1573 char buf[3*MAX_DUMP_BYTES+4];
1574 char *bp = buf;
1575 static char digits[] = "0123456789abcdef";
1576
1577 while (l--) {
1578 if (bp >= buf + sizeof(buf) - 3) {
1579 *bp++ = '>';
1580 break;
1581 }
1582 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1583 *bp++ = digits[*b++ & 0xf];
1584 *bp++ = ' ';
1585 }
1586
1587 *bp = 0;
1588 printf("%s\n", buf);
1589 }
1590
1591
1592 #endif /* NPPP > 0 */
1593