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