if_ppp.c revision 1.19 1 /* $NetBSD: if_ppp.c,v 1.19 1994/07/27 09:05:33 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 pppgetm(sc);
298
299 sc->sc_ilen = 0;
300 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
301 sc->sc_asyncmap[0] = 0xffffffff;
302 sc->sc_asyncmap[3] = 0x60000000;
303 sc->sc_rasyncmap = 0;
304 sc->sc_devp = (void *) tp;
305 sc->sc_start = pppasyncstart;
306
307 tp->t_sc = (caddr_t) sc;
308 ttyflush(tp, FREAD | FWRITE);
309
310 return (0);
311 }
312
313 /*
314 * Line specific close routine.
315 * Detach the tty from the ppp unit.
316 * Mimics part of ttyclose().
317 */
318 void
319 pppclose(tp, flag)
320 struct tty *tp;
321 int flag;
322 {
323 register struct ppp_softc *sc;
324 struct mbuf *m;
325 int s;
326
327 ttywflush(tp);
328 s = splimp(); /* paranoid; splnet probably ok */
329 tp->t_line = 0;
330 sc = (struct ppp_softc *)tp->t_sc;
331 if (sc != NULL) {
332 tp->t_sc = NULL;
333 if (tp == (struct tty *) sc->sc_devp) {
334 m_freem(sc->sc_outm);
335 sc->sc_outm = NULL;
336 m_freem(sc->sc_m);
337 sc->sc_m = NULL;
338 pppdealloc(sc);
339 }
340 }
341 splx(s);
342 }
343
344 /*
345 * Line specific (tty) read routine.
346 */
347 int
348 pppread(tp, uio, flag)
349 register struct tty *tp;
350 struct uio *uio;
351 int flag;
352 {
353 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
354 struct mbuf *m, *m0;
355 register int s;
356 int error = 0;
357
358 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
359 return 0; /* end of file */
360 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
361 return 0;
362 s = splimp();
363 while (sc->sc_inq.ifq_head == NULL && tp->t_line == PPPDISC) {
364 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
365 splx(s);
366 return (EWOULDBLOCK);
367 }
368 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
369 if (error) {
370 splx(s);
371 return error;
372 }
373 }
374 if (tp->t_line != PPPDISC) {
375 splx(s);
376 return (-1);
377 }
378
379 /* Pull place-holder byte out of canonical queue */
380 getc(&tp->t_canq);
381
382 /* Get the packet from the input queue */
383 IF_DEQUEUE(&sc->sc_inq, m0);
384 splx(s);
385
386 for (m = m0; m && uio->uio_resid; m = m->m_next)
387 if (error = uiomove(mtod(m, u_char *), m->m_len, uio))
388 break;
389 m_freem(m0);
390 return (error);
391 }
392
393 /*
394 * Line specific (tty) write routine.
395 */
396 int
397 pppwrite(tp, uio, flag)
398 register struct tty *tp;
399 struct uio *uio;
400 int flag;
401 {
402 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
403 struct mbuf *m, *m0, **mp;
404 struct sockaddr dst;
405 struct ppp_header *ph1, *ph2;
406 int len, error;
407
408 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
409 return 0; /* wrote 0 bytes */
410 if (tp->t_line != PPPDISC)
411 return (EINVAL);
412 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
413 return EIO;
414 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
415 uio->uio_resid < PPP_HDRLEN)
416 return (EMSGSIZE);
417 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
418 MGET(m, M_WAIT, MT_DATA);
419 if ((*mp = m) == NULL) {
420 m_freem(m0);
421 return (ENOBUFS);
422 }
423 m->m_len = 0;
424 if (uio->uio_resid >= MCLBYTES / 2)
425 MCLGET(m, M_DONTWAIT);
426 len = M_TRAILINGSPACE(m);
427 if (len > uio->uio_resid)
428 len = uio->uio_resid;
429 if (error = uiomove(mtod(m, u_char *), len, uio)) {
430 m_freem(m0);
431 return (error);
432 }
433 m->m_len = len;
434 }
435 dst.sa_family = AF_UNSPEC;
436 ph1 = (struct ppp_header *) &dst.sa_data;
437 ph2 = mtod(m0, struct ppp_header *);
438 *ph1 = *ph2;
439 m0->m_data += PPP_HDRLEN;
440 m0->m_len -= PPP_HDRLEN;
441 return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
442 }
443
444 /*
445 * Line specific (tty) ioctl routine.
446 * Provide a way to get the ppp unit number.
447 * This discipline requires that tty device drivers call
448 * the line specific l_ioctl routine from their ioctl routines.
449 */
450 /* ARGSUSED */
451 int
452 ppptioctl(tp, cmd, data, flag, p)
453 struct tty *tp;
454 caddr_t data;
455 int cmd, flag;
456 struct proc *p;
457 {
458 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
459 int s, error, flags, mru;
460
461 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
462 return -1;
463
464 switch (cmd) {
465 case FIONREAD:
466 *(int *)data = sc->sc_inq.ifq_len;
467 break;
468
469 case PPPIOCGUNIT:
470 *(int *)data = sc->sc_if.if_unit;
471 break;
472
473 case PPPIOCGFLAGS:
474 *(u_int *)data = sc->sc_flags;
475 break;
476
477 case PPPIOCSFLAGS:
478 if (error = suser(p->p_ucred, &p->p_acflag))
479 return (error);
480 flags = *(int *)data & SC_MASK;
481 s = splimp();
482 sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
483 splx(s);
484 break;
485
486 case PPPIOCSASYNCMAP:
487 if (error = suser(p->p_ucred, &p->p_acflag))
488 return (error);
489 sc->sc_asyncmap[0] = *(u_int *)data;
490 break;
491
492 case PPPIOCGASYNCMAP:
493 *(u_int *)data = sc->sc_asyncmap[0];
494 break;
495
496 case PPPIOCSRASYNCMAP:
497 if (error = suser(p->p_ucred, &p->p_acflag))
498 return (error);
499 sc->sc_rasyncmap = *(u_int *)data;
500 break;
501
502 case PPPIOCGRASYNCMAP:
503 *(u_int *)data = sc->sc_rasyncmap;
504 break;
505
506 case PPPIOCSXASYNCMAP:
507 if (error = suser(p->p_ucred, &p->p_acflag))
508 return (error);
509 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
510 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
511 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
512 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
513 break;
514
515 case PPPIOCGXASYNCMAP:
516 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
517 break;
518
519 case PPPIOCSMRU:
520 if (error = suser(p->p_ucred, &p->p_acflag))
521 return (error);
522 mru = *(int *)data;
523 if (mru >= PPP_MRU && mru <= PPP_MAXMRU) {
524 sc->sc_mru = mru;
525 pppgetm(sc);
526 }
527 break;
528
529 case PPPIOCGMRU:
530 *(int *)data = sc->sc_mru;
531 break;
532
533 #ifdef VJC
534 case PPPIOCSMAXCID:
535 if (error = suser(p->p_ucred, &p->p_acflag))
536 return (error);
537 sl_compress_init(&sc->sc_comp, *(int *)data);
538 break;
539 #endif
540
541 case PPPIOCXFERUNIT:
542 if (error = suser(p->p_ucred, &p->p_acflag))
543 return (error);
544 sc->sc_xfer = p->p_pid;
545 break;
546
547 default:
548 return (-1);
549 }
550 return (0);
551 }
552
553 /*
554 * FCS lookup table as calculated by genfcstab.
555 */
556 static u_short fcstab[256] = {
557 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
558 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
559 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
560 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
561 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
562 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
563 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
564 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
565 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
566 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
567 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
568 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
569 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
570 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
571 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
572 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
573 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
574 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
575 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
576 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
577 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
578 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
579 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
580 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
581 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
582 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
583 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
584 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
585 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
586 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
587 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
588 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
589 };
590
591 /*
592 * Calculate a new FCS given the current FCS and the new data.
593 */
594 static u_short
595 pppfcs(fcs, cp, len)
596 register u_short fcs;
597 register u_char *cp;
598 register int len;
599 {
600 while (len--)
601 fcs = PPP_FCS(fcs, *cp++);
602 return (fcs);
603 }
604
605 /*
606 * Queue a packet. Start transmission if not active.
607 * Packet is placed in Information field of PPP frame.
608 */
609 int
610 pppoutput(ifp, m0, dst, rtp)
611 struct ifnet *ifp;
612 struct mbuf *m0;
613 struct sockaddr *dst;
614 struct rtentry *rtp;
615 {
616 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
617 struct ppp_header *ph;
618 int protocol, address, control;
619 u_char *cp;
620 int s, error;
621 struct ip *ip;
622 struct ifqueue *ifq;
623
624 if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
625 || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) {
626 error = ENETDOWN; /* sort of */
627 goto bad;
628 }
629
630 /*
631 * Compute PPP header.
632 */
633 address = PPP_ALLSTATIONS;
634 control = PPP_UI;
635 ifq = &ifp->if_snd;
636 switch (dst->sa_family) {
637 #ifdef INET
638 case AF_INET:
639 protocol = PPP_IP;
640 if ((sc->sc_flags & SC_ENABLE_IP) == 0) {
641 error = ENETDOWN;
642 goto bad;
643 }
644
645 /*
646 * If this is a TCP packet to or from an "interactive" port,
647 * put the packet on the fastq instead.
648 */
649 if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
650 register int p = ntohl(((int *)ip)[ip->ip_hl]);
651 if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
652 ifq = &sc->sc_fastq;
653 }
654 break;
655 #endif
656 #ifdef NS
657 case AF_NS:
658 protocol = PPP_XNS;
659 break;
660 #endif
661 case AF_UNSPEC:
662 ph = (struct ppp_header *) dst->sa_data;
663 address = ph->ph_address;
664 control = ph->ph_control;
665 protocol = ntohs(ph->ph_protocol);
666 break;
667 default:
668 printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
669 error = EAFNOSUPPORT;
670 goto bad;
671 }
672
673 /*
674 * Add PPP header. If no space in first mbuf, allocate another.
675 * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
676 */
677 if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
678 m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT);
679 if (m0 == 0) {
680 error = ENOBUFS;
681 goto bad;
682 }
683 m0->m_len = 0;
684 } else
685 m0->m_data -= PPP_HDRLEN;
686
687 cp = mtod(m0, u_char *);
688 *cp++ = address;
689 *cp++ = control;
690 *cp++ = protocol >> 8;
691 *cp++ = protocol & 0xff;
692 m0->m_len += PPP_HDRLEN;
693
694 if (sc->sc_flags & SC_LOG_OUTPKT) {
695 printf("ppp%d output: ", ifp->if_unit);
696 pppdumpm(m0, -1);
697 }
698
699 #if NBPFILTER > 0
700 /* See if bpf wants to look at the packet. */
701 if (sc->sc_bpf)
702 bpf_mtap(sc->sc_bpf, m0);
703 #endif
704
705 /*
706 * Put the packet on the appropriate queue.
707 */
708 s = splimp();
709 if (IF_QFULL(ifq)) {
710 IF_DROP(ifq);
711 splx(s);
712 sc->sc_if.if_oerrors++;
713 error = ENOBUFS;
714 goto bad;
715 }
716 IF_ENQUEUE(ifq, m0);
717
718 /*
719 * Tell the device to send it out.
720 */
721 (*sc->sc_start)(sc);
722
723 splx(s);
724 return (0);
725
726 bad:
727 m_freem(m0);
728 return (error);
729 }
730
731 /*
732 * Grab another packet off a queue and apply VJ compression,
733 * address/control and/or protocol compression if appropriate.
734 */
735 struct mbuf *
736 ppp_dequeue(sc)
737 struct ppp_softc *sc;
738 {
739 int s;
740 struct mbuf *m, *mp;
741 u_char *cp;
742 int address, control, protocol;
743
744 s = splimp();
745 IF_DEQUEUE(&sc->sc_fastq, m);
746 if (m == NULL)
747 IF_DEQUEUE(&sc->sc_if.if_snd, m);
748 splx(s);
749 if (m == NULL)
750 return NULL;
751
752 /*
753 * Extract the ppp header of the new packet.
754 * The ppp header will be in one mbuf.
755 */
756 cp = mtod(m, u_char *);
757 address = cp[0];
758 control = cp[1];
759 protocol = (cp[2] << 8) + cp[3];
760
761 switch (protocol) {
762 #ifdef VJC
763 case PPP_IP:
764 /*
765 * If the packet is a TCP/IP packet, see if we can compress it.
766 */
767 if (sc->sc_flags & SC_COMP_TCP) {
768 struct ip *ip;
769 int type;
770
771 mp = m;
772 ip = (struct ip *) (cp + PPP_HDRLEN);
773 if (mp->m_len <= PPP_HDRLEN) {
774 mp = mp->m_next;
775 if (mp == NULL)
776 break;
777 ip = mtod(mp, struct ip *);
778 }
779 /* this code assumes the IP/TCP header is in one non-shared mbuf */
780 if (ip->ip_p == IPPROTO_TCP) {
781 type = sl_compress_tcp(mp, ip, &sc->sc_comp,
782 !(sc->sc_flags & SC_NO_TCP_CCID));
783 switch (type) {
784 case TYPE_UNCOMPRESSED_TCP:
785 protocol = PPP_VJC_UNCOMP;
786 break;
787 case TYPE_COMPRESSED_TCP:
788 protocol = PPP_VJC_COMP;
789 cp = mtod(m, u_char *);
790 cp[0] = address; /* header has moved */
791 cp[1] = control;
792 cp[2] = 0;
793 break;
794 }
795 cp[3] = protocol; /* update protocol in PPP header */
796 }
797 }
798 #endif /* VJC */
799 }
800
801 /*
802 * Compress the address/control and protocol, if possible.
803 */
804 if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
805 control == PPP_UI && protocol != PPP_ALLSTATIONS &&
806 protocol != PPP_LCP) {
807 /* can compress address/control */
808 m->m_data += 2;
809 m->m_len -= 2;
810 }
811 if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
812 /* can compress protocol */
813 if (mtod(m, u_char *) == cp) {
814 cp[2] = cp[1]; /* move address/control up */
815 cp[1] = cp[0];
816 }
817 ++m->m_data;
818 --m->m_len;
819 }
820
821 return m;
822 }
823
824 /*
825 * This gets called from pppoutput when a new packet is
826 * put on a queue.
827 */
828 static
829 pppasyncstart(sc)
830 register struct ppp_softc *sc;
831 {
832 register struct tty *tp = (struct tty *) sc->sc_devp;
833
834 pppstart(tp);
835 }
836
837 /*
838 * Start output on async tty interface. Get another datagram
839 * to send from the interface queue and start sending it.
840 */
841 void
842 pppstart(tp)
843 register struct tty *tp;
844 {
845 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
846 register struct mbuf *m;
847 register int len;
848 register u_char *start, *stop, *cp;
849 int n, s, ndone, done;
850 struct mbuf *m2;
851
852 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
853 /* sorry, I can't talk now */
854 return;
855 }
856 if (sc == NULL || tp != (struct tty *) sc->sc_devp) {
857 (*tp->t_oproc)(tp);
858 return;
859 }
860
861 for (;;) {
862 /*
863 * If there is more in the output queue, just send it now.
864 * We are being called in lieu of ttstart and must do what
865 * it would.
866 */
867 if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) {
868 (*tp->t_oproc)(tp);
869 if (CCOUNT(&tp->t_outq) > PPP_HIWAT)
870 return;
871 }
872
873 /*
874 * See if we have an existing packet partly sent.
875 * If not, get a new packet and start sending it.
876 * We take packets on the priority queue ahead of those
877 * on the normal queue.
878 */
879 m = sc->sc_outm;
880 if (m == NULL) {
881 /*
882 * Get another packet to be sent
883 */
884 m = ppp_dequeue(sc);
885 if (m == NULL)
886 return;
887
888 /*
889 * The extra PPP_FLAG will start up a new packet, and thus
890 * will flush any accumulated garbage. We do this whenever
891 * the line may have been idle for some time.
892 */
893 if (CCOUNT(&tp->t_outq) == 0) {
894 ++sc->sc_bytessent;
895 (void) putc(PPP_FLAG, &tp->t_outq);
896 }
897
898 /* Calculate the FCS for the first mbuf's worth. */
899 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
900 }
901
902 for (;;) {
903 start = mtod(m, u_char *);
904 len = m->m_len;
905 stop = start + len;
906 while (len > 0) {
907 /*
908 * Find out how many bytes in the string we can
909 * handle without doing something special.
910 */
911 for (cp = start; cp < stop; cp++)
912 if (ESCAPE_P(*cp))
913 break;
914 n = cp - start;
915 if (n) {
916 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
917 ndone = n - b_to_q(start, n, &tp->t_outq);
918 len -= ndone;
919 start += ndone;
920 sc->sc_bytessent += ndone;
921
922 if (ndone < n)
923 break; /* packet doesn't fit */
924 }
925 /*
926 * If there are characters left in the mbuf,
927 * the first one must be special..
928 * Put it out in a different form.
929 */
930 if (len) {
931 if (putc(PPP_ESCAPE, &tp->t_outq))
932 break;
933 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
934 (void) unputc(&tp->t_outq);
935 break;
936 }
937 sc->sc_bytessent += 2;
938 start++;
939 len--;
940 }
941 }
942 /*
943 * If we didn't empty this mbuf, remember where we're up to.
944 * If we emptied the last mbuf, try to add the FCS and closing
945 * flag, and if we can't, leave sc_outm pointing to m, but with
946 * m->m_len == 0, to remind us to output the FCS and flag later.
947 */
948 done = len == 0;
949 if (done && m->m_next == NULL) {
950 u_char *p, *q;
951 int c;
952 u_char endseq[8];
953
954 /*
955 * We may have to escape the bytes in the FCS.
956 */
957 p = endseq;
958 c = ~sc->sc_outfcs & 0xFF;
959 if (ESCAPE_P(c)) {
960 *p++ = PPP_ESCAPE;
961 *p++ = c ^ PPP_TRANS;
962 } else
963 *p++ = c;
964 c = (~sc->sc_outfcs >> 8) & 0xFF;
965 if (ESCAPE_P(c)) {
966 *p++ = PPP_ESCAPE;
967 *p++ = c ^ PPP_TRANS;
968 } else
969 *p++ = c;
970 *p++ = PPP_FLAG;
971
972 /*
973 * Try to output the FCS and flag. If the bytes
974 * don't all fit, back out.
975 */
976 for (q = endseq; q < p; ++q)
977 if (putc(*q, &tp->t_outq)) {
978 done = 0;
979 for (; q > endseq; --q)
980 unputc(&tp->t_outq);
981 break;
982 }
983 }
984
985 if (!done) {
986 m->m_data = start;
987 m->m_len = len;
988 sc->sc_outm = m;
989 if (tp->t_oproc != NULL)
990 (*tp->t_oproc)(tp);
991 return; /* can't do any more at the moment */
992 }
993
994 /* Finished with this mbuf; free it and move on. */
995 MFREE(m, m2);
996 if (m2 == NULL)
997 break;
998
999 m = m2;
1000 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
1001 }
1002
1003 /* Finished a packet */
1004 sc->sc_outm = NULL;
1005 sc->sc_bytessent++; /* account for closing flag */
1006 sc->sc_if.if_opackets++;
1007 sc->sc_if.if_obytes = sc->sc_bytessent;
1008 }
1009 }
1010
1011 /*
1012 * Allocate enough mbuf to handle current MRU.
1013 */
1014 static int
1015 pppgetm(sc)
1016 register struct ppp_softc *sc;
1017 {
1018 struct mbuf *m, **mp;
1019 int len;
1020 int s;
1021
1022 s = splimp();
1023 mp = &sc->sc_m;
1024 for (len = HDROFF + sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
1025 if ((m = *mp) == NULL) {
1026 MGETHDR(m, M_DONTWAIT, MT_DATA);
1027 if (m == NULL)
1028 break;
1029 *mp = m;
1030 MCLGET(m, M_DONTWAIT);
1031 }
1032 len -= M_DATASIZE(m);
1033 mp = &m->m_next;
1034 }
1035 splx(s);
1036 return len <= 0;
1037 }
1038
1039 /*
1040 * PPP packet input routine.
1041 * The caller has checked and removed the FCS and has inserted
1042 * the address/control bytes and the protocol high byte if they
1043 * were omitted. The data in the first mbuf should start HDROFF
1044 * bytes from the beginning of the mbuf data storage area.
1045 * The return value is 1 if the packet was put on sc->sc_inq,
1046 * 0 otherwise.
1047 */
1048 #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1049 TYPE_UNCOMPRESSED_TCP)
1050
1051 int
1052 ppppktin(sc, m)
1053 struct ppp_softc *sc;
1054 struct mbuf *m;
1055 {
1056 struct ifqueue *inq;
1057 int s, ilen, xlen, proto, rv;
1058 u_char *cp, adrs, ctrl;
1059 struct mbuf *mp;
1060
1061 sc->sc_if.if_ipackets++;
1062 rv = 0;
1063
1064 cp = mtod(m, u_char *);
1065 adrs = cp[0];
1066 ctrl = cp[1];
1067 proto = (cp[2] << 8) + cp[3];
1068
1069 ilen = 0;
1070 for (mp = m; mp != NULL; mp = mp->m_next)
1071 ilen += mp->m_len;
1072
1073 #ifdef VJC
1074 /*
1075 * See if we have a VJ-compressed packet to uncompress.
1076 */
1077 if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
1078 char *pkttype = proto == PPP_VJC_COMP? "": "un";
1079
1080 if (sc->sc_flags & SC_REJ_COMP_TCP) {
1081 if (sc->sc_flags & SC_DEBUG)
1082 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n",
1083 sc->sc_if.if_unit, pkttype, sc->sc_flags);
1084 m_freem(m);
1085 sc->sc_if.if_ierrors++;
1086 return 0;
1087 }
1088
1089 if (proto == PPP_VJC_COMP && m->m_data - M_DATASTART(m) < MAX_HDR) {
1090 /*
1091 * We don't have room in the mbuf to decompress this packet.
1092 * XXX For now we just drop the packet.
1093 */
1094 if (sc->sc_flags & SC_DEBUG)
1095 printf("ppp%d: no room to VJ-decompress packet\n",
1096 sc->sc_if.if_unit);
1097 m_freem(m);
1098 sc->sc_if.if_ierrors++;
1099 return 0;
1100 }
1101
1102 m->m_data += PPP_HDRLEN;
1103 m->m_len -= PPP_HDRLEN;
1104 ilen -= PPP_HDRLEN;
1105 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data),
1106 m->m_len, ilen,
1107 COMPTYPE(proto), &sc->sc_comp);
1108
1109 if (xlen == 0) {
1110 if (sc->sc_flags & SC_DEBUG)
1111 printf("ppp%d: sl_uncompress failed on type %scomp\n",
1112 sc->sc_if.if_unit, pkttype);
1113 m_freem(m);
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 pppgetm(sc);
1319 return;
1320 }
1321
1322 if (sc->sc_flags & SC_FLUSH) {
1323 if (sc->sc_flags & SC_LOG_FLUSH)
1324 ppplogchar(sc, c);
1325 return;
1326 }
1327
1328 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1329 return;
1330
1331 if (sc->sc_flags & SC_ESCAPED) {
1332 sc->sc_flags &= ~SC_ESCAPED;
1333 c ^= PPP_TRANS;
1334 } else if (c == PPP_ESCAPE) {
1335 sc->sc_flags |= SC_ESCAPED;
1336 return;
1337 }
1338
1339 /*
1340 * Initialize buffer on first octet received.
1341 * First octet could be address or protocol (when compressing
1342 * address/control).
1343 * Second octet is control.
1344 * Third octet is first or second (when compressing protocol)
1345 * octet of protocol.
1346 * Fourth octet is second octet of protocol.
1347 */
1348 if (sc->sc_ilen == 0) {
1349 /* reset the first input mbuf */
1350 if (sc->sc_m == NULL) {
1351 pppgetm(sc);
1352 if (sc->sc_m == NULL) {
1353 if (sc->sc_flags & SC_DEBUG)
1354 printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
1355 goto flush;
1356 }
1357 }
1358 m = sc->sc_m;
1359 m->m_len = 0;
1360 m->m_data = M_DATASTART(sc->sc_m);
1361 if (M_DATASIZE(sc->sc_m) >= HDROFF + PPP_HDRLEN)
1362 m->m_data += HDROFF; /* allow room for VJ decompression */
1363 sc->sc_mc = m;
1364 sc->sc_mp = mtod(m, char *);
1365 sc->sc_fcs = PPP_INITFCS;
1366 if (c != PPP_ALLSTATIONS) {
1367 if (sc->sc_flags & SC_REJ_COMP_AC) {
1368 if (sc->sc_flags & SC_DEBUG)
1369 printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
1370 sc->sc_if.if_unit, c);
1371 goto flush;
1372 }
1373 *sc->sc_mp++ = PPP_ALLSTATIONS;
1374 *sc->sc_mp++ = PPP_UI;
1375 sc->sc_ilen += 2;
1376 m->m_len += 2;
1377 }
1378 }
1379 if (sc->sc_ilen == 1 && c != PPP_UI) {
1380 if (sc->sc_flags & SC_DEBUG)
1381 printf("ppp%d: missing UI (0x3), got 0x%x\n",
1382 sc->sc_if.if_unit, c);
1383 goto flush;
1384 }
1385 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1386 /* a compressed protocol */
1387 *sc->sc_mp++ = 0;
1388 sc->sc_ilen++;
1389 sc->sc_mc->m_len++;
1390 }
1391 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1392 if (sc->sc_flags & SC_DEBUG)
1393 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1394 (sc->sc_mp[-1] << 8) + c);
1395 goto flush;
1396 }
1397
1398 /* packet beyond configured mru? */
1399 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1400 if (sc->sc_flags & SC_DEBUG)
1401 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
1402 goto flush;
1403 }
1404
1405 /* is this mbuf full? */
1406 m = sc->sc_mc;
1407 if (M_TRAILINGSPACE(m) <= 0) {
1408 if (m->m_next == NULL) {
1409 pppgetm(sc);
1410 if (m->m_next == NULL) {
1411 if (sc->sc_flags & SC_DEBUG)
1412 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1413 goto flush;
1414 }
1415 }
1416 sc->sc_mc = m = m->m_next;
1417 m->m_len = 0;
1418 m->m_data = M_DATASTART(m);
1419 sc->sc_mp = mtod(m, char *);
1420 }
1421
1422 ++m->m_len;
1423 *sc->sc_mp++ = c;
1424 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1425 return;
1426
1427 flush:
1428 if (!(sc->sc_flags & SC_FLUSH)) {
1429 sc->sc_if.if_ierrors++;
1430 sc->sc_flags |= SC_FLUSH;
1431 if (sc->sc_flags & SC_LOG_FLUSH)
1432 ppplogchar(sc, c);
1433 }
1434 }
1435
1436 /*
1437 * Process an ioctl request to interface.
1438 */
1439 pppioctl(ifp, cmd, data)
1440 register struct ifnet *ifp;
1441 int cmd;
1442 caddr_t data;
1443 {
1444 struct proc *p = curproc; /* XXX */
1445 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
1446 register struct ifaddr *ifa = (struct ifaddr *)data;
1447 register struct ifreq *ifr = (struct ifreq *)data;
1448 int s = splimp(), error = 0;
1449
1450
1451 switch (cmd) {
1452 case SIOCSIFFLAGS:
1453 if ((ifp->if_flags & IFF_RUNNING) == 0)
1454 ifp->if_flags &= ~IFF_UP;
1455 break;
1456
1457 case SIOCSIFADDR:
1458 if (ifa->ifa_addr->sa_family != AF_INET)
1459 error = EAFNOSUPPORT;
1460 break;
1461
1462 case SIOCSIFDSTADDR:
1463 if (ifa->ifa_addr->sa_family != AF_INET)
1464 error = EAFNOSUPPORT;
1465 break;
1466
1467 case SIOCSIFMTU:
1468 if (error = suser(p->p_ucred, &p->p_acflag))
1469 break;
1470 sc->sc_if.if_mtu = ifr->ifr_mtu;
1471 break;
1472
1473 case SIOCGIFMTU:
1474 ifr->ifr_mtu = sc->sc_if.if_mtu;
1475 break;
1476
1477 default:
1478 error = EINVAL;
1479 }
1480 splx(s);
1481 return (error);
1482 }
1483
1484 #define MAX_DUMP_BYTES 128
1485
1486 static void
1487 pppdumpm(m0, pktlen)
1488 struct mbuf *m0;
1489 int pktlen;
1490 {
1491 char buf[3*MAX_DUMP_BYTES+4];
1492 char *bp = buf;
1493 struct mbuf *m;
1494 static char digits[] = "0123456789abcdef";
1495
1496 for (m = m0; m && pktlen; m = m->m_next) {
1497 int l = m->m_len;
1498 u_char *rptr = (u_char *)m->m_data;
1499
1500 if (pktlen > 0) {
1501 if (l > pktlen)
1502 l = pktlen;
1503 pktlen -= l;
1504 }
1505 while (l--) {
1506 if (bp > buf + sizeof(buf) - 4)
1507 goto done;
1508 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1509 *bp++ = digits[*rptr++ & 0xf];
1510 }
1511
1512 if (m->m_next) {
1513 if (bp > buf + sizeof(buf) - 3)
1514 goto done;
1515 *bp++ = '|';
1516 } else
1517 *bp++ = ' ';
1518 }
1519 done:
1520 if (m && pktlen)
1521 *bp++ = '>';
1522 *bp = 0;
1523 printf("%s\n", buf);
1524 }
1525
1526 static void
1527 ppplogchar(sc, c)
1528 struct ppp_softc *sc;
1529 int c;
1530 {
1531 if (c >= 0)
1532 sc->sc_rawin[sc->sc_rawin_count++] = c;
1533 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1534 || c < 0 && sc->sc_rawin_count > 0) {
1535 printf("ppp%d input: ", sc->sc_if.if_unit);
1536 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1537 sc->sc_rawin_count = 0;
1538 }
1539 }
1540
1541 static void
1542 pppdumpb(b, l)
1543 u_char *b;
1544 int l;
1545 {
1546 char buf[3*MAX_DUMP_BYTES+4];
1547 char *bp = buf;
1548 static char digits[] = "0123456789abcdef";
1549
1550 while (l--) {
1551 if (bp >= buf + sizeof(buf) - 3) {
1552 *bp++ = '>';
1553 break;
1554 }
1555 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1556 *bp++ = digits[*b++ & 0xf];
1557 *bp++ = ' ';
1558 }
1559
1560 *bp = 0;
1561 printf("%s\n", buf);
1562 }
1563
1564
1565 #endif /* NPPP > 0 */
1566