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