if_ppp.c revision 1.16 1 /* $NetBSD: if_ppp.c,v 1.16 1994/07/18 23:45:33 paulus 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 if (sc->sc_m != NULL) {
1041 m_freem(sc->sc_m);
1042 sc->sc_m = NULL;
1043 }
1044 splx(s);
1045 printf("ppp%d: can't allocate mbuf\n", sc->sc_if.if_unit);
1046 return (0);
1047 }
1048 *mp = m;
1049 MCLGET(m, M_DONTWAIT);
1050 if ((m->m_flags & M_EXT) == 0) {
1051 m_freem(sc->sc_m);
1052 sc->sc_m = NULL;
1053 splx(s);
1054 printf("ppp%d: can't allocate mbuf cluster\n", sc->sc_if.if_unit);
1055 return (0);
1056 }
1057 if ((len -= M_DATASIZE(m)) <= 0) {
1058 splx(s);
1059 return (1);
1060 }
1061 }
1062 }
1063
1064 /*
1065 * PPP packet input routine.
1066 * The caller has checked and removed the FCS and has inserted
1067 * the address/control bytes and the protocol high byte if they
1068 * were omitted. The data in the first mbuf should start HDROFF
1069 * bytes from the beginning of the mbuf data storage area.
1070 * The return value is 1 if the packet was put on sc->sc_inq,
1071 * 0 otherwise.
1072 */
1073 #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1074 TYPE_UNCOMPRESSED_TCP)
1075
1076 int
1077 ppppktin(sc, m)
1078 struct ppp_softc *sc;
1079 struct mbuf *m;
1080 {
1081 struct ifqueue *inq;
1082 int s, ilen, xlen, proto, rv;
1083 u_char *cp, adrs, ctrl;
1084 struct mbuf *mp;
1085
1086 sc->sc_if.if_ipackets++;
1087 rv = 0;
1088
1089 cp = mtod(m, u_char *);
1090 adrs = cp[0];
1091 ctrl = cp[1];
1092 proto = (cp[2] << 8) + cp[3];
1093
1094 ilen = 0;
1095 for (mp = m; mp != NULL; mp = mp->m_next)
1096 ilen += mp->m_len;
1097
1098 #ifdef VJC
1099 /*
1100 * See if we have a VJ-compressed packet to uncompress.
1101 */
1102 if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
1103 char *pkttype = proto == PPP_VJC_COMP? "": "un";
1104
1105 if (sc->sc_flags & SC_REJ_COMP_TCP) {
1106 if (sc->sc_flags & SC_DEBUG)
1107 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n",
1108 sc->sc_if.if_unit, pkttype, sc->sc_flags);
1109 sc->sc_if.if_ierrors++;
1110 return 0;
1111 }
1112
1113 m->m_data += PPP_HDRLEN;
1114 m->m_len -= PPP_HDRLEN;
1115 ilen -= PPP_HDRLEN;
1116 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data),
1117 m->m_len, ilen,
1118 COMPTYPE(proto), &sc->sc_comp);
1119
1120 if (xlen == 0) {
1121 if (sc->sc_flags & SC_DEBUG)
1122 printf("ppp%d: sl_uncompress failed on type %scomp\n",
1123 sc->sc_if.if_unit, pkttype);
1124 sc->sc_if.if_ierrors++;
1125 return 0;
1126 }
1127
1128 /* adjust the first mbuf by the decompressed amt */
1129 xlen += PPP_HDRLEN;
1130 m->m_len += xlen - ilen;
1131 ilen = xlen;
1132 m->m_data -= PPP_HDRLEN;
1133 proto = PPP_IP;
1134
1135 /* put the ppp header back in place */
1136 if (cp != mtod(m, u_char *)) {
1137 cp = mtod(m, u_char *);
1138 cp[0] = adrs;
1139 cp[1] = ctrl;
1140 cp[2] = 0;
1141 }
1142 cp[3] = PPP_IP;
1143 }
1144 #endif /* VJC */
1145
1146 /*
1147 * If the packet will fit in a header mbuf, don't waste a
1148 * whole cluster on it.
1149 */
1150 if (ilen <= MHLEN) {
1151 MGETHDR(mp, M_DONTWAIT, MT_DATA);
1152 if (mp != NULL) {
1153 m_copydata(m, 0, ilen, mtod(mp, caddr_t));
1154 m_freem(m);
1155 m = mp;
1156 m->m_len = ilen;
1157 }
1158 }
1159 m->m_pkthdr.len = ilen;
1160 m->m_pkthdr.rcvif = &sc->sc_if;
1161
1162 #if NBPFILTER > 0
1163 /* See if bpf wants to look at the packet. */
1164 if (sc->sc_bpf)
1165 bpf_mtap(sc->sc_bpf, m);
1166 #endif
1167
1168 switch (proto) {
1169 #ifdef INET
1170 case PPP_IP:
1171 /*
1172 * IP packet - take off the ppp header and pass it up to IP.
1173 */
1174 if ((sc->sc_if.if_flags & IFF_UP) == 0
1175 || (sc->sc_flags & SC_ENABLE_IP) == 0) {
1176 /* interface is down - drop the packet. */
1177 m_freem(m);
1178 return 0;
1179 }
1180 m->m_pkthdr.len -= PPP_HDRLEN;
1181 m->m_data += PPP_HDRLEN;
1182 m->m_len -= PPP_HDRLEN;
1183 schednetisr(NETISR_IP);
1184 inq = &ipintrq;
1185 break;
1186 #endif
1187
1188 default:
1189 /*
1190 * Some other protocol - place on input queue for read().
1191 */
1192 inq = &sc->sc_inq;
1193 rv = 1;
1194 break;
1195 }
1196
1197 /*
1198 * Put the packet on the appropriate input queue.
1199 */
1200 s = splimp();
1201 if (IF_QFULL(inq)) {
1202 IF_DROP(inq);
1203 if (sc->sc_flags & SC_DEBUG)
1204 printf("ppp%d: queue full\n", sc->sc_if.if_unit);
1205 sc->sc_if.if_ierrors++;
1206 sc->sc_if.if_iqdrops++;
1207 m_freem(m);
1208 rv = 0;
1209 } else
1210 IF_ENQUEUE(inq, m);
1211
1212 splx(s);
1213 return rv;
1214 }
1215
1216 /*
1217 * tty interface receiver interrupt.
1218 */
1219 static unsigned paritytab[8] = {
1220 0x96696996, 0x69969669, 0x69969669, 0x96696996,
1221 0x69969669, 0x96696996, 0x96696996, 0x69969669
1222 };
1223
1224 void
1225 pppinput(c, tp)
1226 int c;
1227 register struct tty *tp;
1228 {
1229 register struct ppp_softc *sc;
1230 struct mbuf *m;
1231 int ilen;
1232
1233 tk_nin++;
1234 sc = (struct ppp_softc *) tp->t_sc;
1235 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
1236 return;
1237
1238 ++sc->sc_bytesrcvd;
1239
1240 if (c & TTY_FE) {
1241 /* framing error or overrun on this char - abort packet */
1242 if (sc->sc_flags & SC_DEBUG)
1243 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
1244 goto flush;
1245 }
1246
1247 c &= 0xff;
1248
1249 if (c & 0x80)
1250 sc->sc_flags |= SC_RCV_B7_1;
1251 else
1252 sc->sc_flags |= SC_RCV_B7_0;
1253 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
1254 sc->sc_flags |= SC_RCV_ODDP;
1255 else
1256 sc->sc_flags |= SC_RCV_EVNP;
1257
1258 if (sc->sc_flags & SC_LOG_RAWIN)
1259 ppplogchar(sc, c);
1260
1261 if (c == PPP_FLAG) {
1262 ilen = sc->sc_ilen;
1263 sc->sc_ilen = 0;
1264 sc->sc_if.if_ibytes = sc->sc_bytesrcvd;
1265
1266 if (sc->sc_rawin_count > 0)
1267 ppplogchar(sc, -1);
1268
1269 /*
1270 * If SC_ESCAPED is set, then we've seen the packet
1271 * abort sequence "}~".
1272 */
1273 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1274 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
1275 #ifdef VJC
1276 /*
1277 * If we've missed a packet, we must toss subsequent compressed
1278 * packets which don't have an explicit connection ID.
1279 */
1280 sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp);
1281 #endif
1282 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1283 if (sc->sc_flags & SC_DEBUG)
1284 printf("ppp%d: bad fcs %x\n", sc->sc_if.if_unit,
1285 sc->sc_fcs);
1286 sc->sc_if.if_ierrors++;
1287 } else
1288 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1289 return;
1290 }
1291
1292 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1293 if (ilen) {
1294 if (sc->sc_flags & SC_DEBUG)
1295 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
1296 sc->sc_if.if_ierrors++;
1297 }
1298 return;
1299 }
1300
1301 /*
1302 * Remove FCS trailer. Somewhat painful...
1303 */
1304 ilen -= 2;
1305 if (--sc->sc_mc->m_len == 0) {
1306 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1307 ;
1308 sc->sc_mc = m;
1309 }
1310 sc->sc_mc->m_len--;
1311
1312 /* excise this mbuf chain */
1313 m = sc->sc_m;
1314 sc->sc_m = sc->sc_mc->m_next;
1315 sc->sc_mc->m_next = NULL;
1316
1317 if (sc->sc_flags & SC_LOG_INPKT) {
1318 printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen);
1319 pppdumpm(m, ilen);
1320 }
1321
1322 if (ppppktin(sc, m)) {
1323 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
1324 putc(0, &tp->t_canq);
1325 ttwakeup(tp);
1326 }
1327
1328 if (!pppgetm(sc))
1329 sc->sc_if.if_flags &= ~IFF_UP;
1330
1331 return;
1332 }
1333
1334 if (sc->sc_flags & SC_FLUSH) {
1335 if (sc->sc_flags & SC_LOG_FLUSH)
1336 ppplogchar(sc, c);
1337 return;
1338 }
1339
1340 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1341 return;
1342
1343 if (sc->sc_flags & SC_ESCAPED) {
1344 sc->sc_flags &= ~SC_ESCAPED;
1345 c ^= PPP_TRANS;
1346 } else if (c == PPP_ESCAPE) {
1347 sc->sc_flags |= SC_ESCAPED;
1348 return;
1349 }
1350
1351 /*
1352 * Initialize buffer on first octet received.
1353 * First octet could be address or protocol (when compressing
1354 * address/control).
1355 * Second octet is control.
1356 * Third octet is first or second (when compressing protocol)
1357 * octet of protocol.
1358 * Fourth octet is second octet of protocol.
1359 */
1360 if (sc->sc_ilen == 0) {
1361 /* reset the first input mbuf */
1362 m = sc->sc_m;
1363 m->m_len = 0;
1364 m->m_data = M_DATASTART(sc->sc_m) + HDROFF;
1365 sc->sc_mc = m;
1366 sc->sc_mp = mtod(m, char *);
1367 sc->sc_fcs = PPP_INITFCS;
1368 if (c != PPP_ALLSTATIONS) {
1369 if (sc->sc_flags & SC_REJ_COMP_AC) {
1370 if (sc->sc_flags & SC_DEBUG)
1371 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
1372 sc->sc_if.if_unit, c);
1373 goto flush;
1374 }
1375 *sc->sc_mp++ = PPP_ALLSTATIONS;
1376 *sc->sc_mp++ = PPP_UI;
1377 sc->sc_ilen += 2;
1378 m->m_len += 2;
1379 }
1380 }
1381 if (sc->sc_ilen == 1 && c != PPP_UI) {
1382 if (sc->sc_flags & SC_DEBUG)
1383 printf("ppp%d: missing UI (0x3), got 0x%x\n",
1384 sc->sc_if.if_unit, c);
1385 goto flush;
1386 }
1387 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1388 /* a compressed protocol */
1389 *sc->sc_mp++ = 0;
1390 sc->sc_ilen++;
1391 sc->sc_mc->m_len++;
1392 }
1393 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1394 if (sc->sc_flags & SC_DEBUG)
1395 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1396 (sc->sc_mp[-1] << 8) + c);
1397 goto flush;
1398 }
1399
1400 /* packet beyond configured mru? */
1401 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1402 if (sc->sc_flags & SC_DEBUG)
1403 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
1404 goto flush;
1405 }
1406
1407 /* is this mbuf full? */
1408 m = sc->sc_mc;
1409 if (M_TRAILINGSPACE(m) <= 0) {
1410 sc->sc_mc = m = m->m_next;
1411 if (m == NULL) {
1412 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1413 goto flush;
1414 }
1415 m->m_len = 0;
1416 m->m_data = M_DATASTART(m);
1417 sc->sc_mp = mtod(m, char *);
1418 }
1419
1420 ++m->m_len;
1421 *sc->sc_mp++ = c;
1422 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1423 return;
1424
1425 flush:
1426 if (!(sc->sc_flags & SC_FLUSH)) {
1427 sc->sc_if.if_ierrors++;
1428 sc->sc_flags |= SC_FLUSH;
1429 if (sc->sc_flags & SC_LOG_FLUSH)
1430 ppplogchar(sc, c);
1431 }
1432 }
1433
1434 /*
1435 * Process an ioctl request to interface.
1436 */
1437 pppioctl(ifp, cmd, data)
1438 register struct ifnet *ifp;
1439 int cmd;
1440 caddr_t data;
1441 {
1442 struct proc *p = curproc; /* XXX */
1443 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
1444 register struct ifaddr *ifa = (struct ifaddr *)data;
1445 register struct ifreq *ifr = (struct ifreq *)data;
1446 int s = splimp(), error = 0;
1447
1448
1449 switch (cmd) {
1450 case SIOCSIFFLAGS:
1451 if ((ifp->if_flags & IFF_RUNNING) == 0)
1452 ifp->if_flags &= ~IFF_UP;
1453 break;
1454
1455 case SIOCSIFADDR:
1456 if (ifa->ifa_addr->sa_family != AF_INET)
1457 error = EAFNOSUPPORT;
1458 break;
1459
1460 case SIOCSIFDSTADDR:
1461 if (ifa->ifa_addr->sa_family != AF_INET)
1462 error = EAFNOSUPPORT;
1463 break;
1464
1465 case SIOCSIFMTU:
1466 if (error = suser(p->p_ucred, &p->p_acflag))
1467 break;
1468 sc->sc_if.if_mtu = ifr->ifr_mtu;
1469 break;
1470
1471 case SIOCGIFMTU:
1472 ifr->ifr_mtu = sc->sc_if.if_mtu;
1473 break;
1474
1475 default:
1476 error = EINVAL;
1477 }
1478 splx(s);
1479 return (error);
1480 }
1481
1482 #define MAX_DUMP_BYTES 128
1483
1484 static void
1485 pppdumpm(m0, pktlen)
1486 struct mbuf *m0;
1487 int pktlen;
1488 {
1489 char buf[3*MAX_DUMP_BYTES+4];
1490 char *bp = buf;
1491 struct mbuf *m;
1492 static char digits[] = "0123456789abcdef";
1493
1494 for (m = m0; m && pktlen; m = m->m_next) {
1495 int l = m->m_len;
1496 u_char *rptr = (u_char *)m->m_data;
1497
1498 if (pktlen > 0) {
1499 if (l > pktlen)
1500 l = pktlen;
1501 pktlen -= l;
1502 }
1503 while (l--) {
1504 if (bp > buf + sizeof(buf) - 4)
1505 goto done;
1506 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1507 *bp++ = digits[*rptr++ & 0xf];
1508 }
1509
1510 if (m->m_next) {
1511 if (bp > buf + sizeof(buf) - 3)
1512 goto done;
1513 *bp++ = '|';
1514 } else
1515 *bp++ = ' ';
1516 }
1517 done:
1518 if (m && pktlen)
1519 *bp++ = '>';
1520 *bp = 0;
1521 printf("%s\n", buf);
1522 }
1523
1524 static void
1525 ppplogchar(sc, c)
1526 struct ppp_softc *sc;
1527 int c;
1528 {
1529 if (c >= 0)
1530 sc->sc_rawin[sc->sc_rawin_count++] = c;
1531 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1532 || c < 0 && sc->sc_rawin_count > 0) {
1533 printf("ppp%d input: ", sc->sc_if.if_unit);
1534 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1535 sc->sc_rawin_count = 0;
1536 }
1537 }
1538
1539 static void
1540 pppdumpb(b, l)
1541 u_char *b;
1542 int l;
1543 {
1544 char buf[3*MAX_DUMP_BYTES+4];
1545 char *bp = buf;
1546 static char digits[] = "0123456789abcdef";
1547
1548 while (l--) {
1549 if (bp >= buf + sizeof(buf) - 3) {
1550 *bp++ = '>';
1551 break;
1552 }
1553 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1554 *bp++ = digits[*b++ & 0xf];
1555 *bp++ = ' ';
1556 }
1557
1558 *bp = 0;
1559 printf("%s\n", buf);
1560 }
1561
1562
1563 #endif /* NPPP > 0 */
1564