1. Remove a rather strangely gratuitous bit of profanity
[unix-history] / sys / net / if_ppp.c
CommitLineData
8b3438a6
RG
1/*
2 * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
3 *
4 * Copyright (c) 1989 Carnegie Mellon University.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by Carnegie Mellon University. The name of the
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * Drew D. Perkins
20 * Carnegie Mellon University
21 * 4910 Forbes Ave.
22 * Pittsburgh, PA 15213
23 * (412) 268-8576
24 * ddp@andrew.cmu.edu
25 *
26 * Based on:
27 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
28 *
29 * Copyright (c) 1987 Regents of the University of California.
30 * All rights reserved.
31 *
32 * Redistribution and use in source and binary forms are permitted
33 * provided that the above copyright notice and this paragraph are
34 * duplicated in all such forms and that any documentation,
35 * advertising materials, and other materials related to such
36 * distribution and use acknowledge that the software was developed
37 * by the University of California, Berkeley. The name of the
38 * University may not be used to endorse or promote products derived
39 * from this software without specific prior written permission.
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
41 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
42 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
43 *
44 * Serial Line interface
45 *
46 * Rick Adams
47 * Center for Seismic Studies
48 * 1300 N 17th Street, Suite 1450
49 * Arlington, Virginia 22209
50 * (703)276-7900
51 * rick@seismo.ARPA
52 * seismo!rick
53 *
54 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
55 * Converted to 4.3BSD Beta by Chris Torek.
56 * Other changes made at Berkeley, based in part on code by Kirk Smith.
57 *
58 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
59 * Added VJ tcp header compression; more unified ioctls
60 *
61 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
62 * Cleaned up a lot of the mbuf-related code to fix bugs that
63 * caused system crashes and packet corruption. Changed pppstart
64 * so that it doesn't just give up with a collision if the whole
65 * packet doesn't fit in the output ring buffer.
2875cbc6
RG
66 *
67 * Added priority queueing for interactive IP packets, following
68 * the model of if_sl.c, plus hooks for bpf.
69 * Paul Mackerras (paulus@cs.anu.edu.au).
8b3438a6
RG
70 */
71
72/*
45abd37c 73 * $Id: if_ppp.c,v 1.12 1994/04/01 10:13:19 jkh Exp $
c0ace2fe 74 * From: if_ppp.c,v 1.22 1993/08/31 23:20:40 paulus Exp
2875cbc6 75 * From: if_ppp.c,v 1.21 1993/08/29 11:22:37 paulus Exp
8b3438a6
RG
76 * From: if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp
77 */
78
79#include "ppp.h"
80#if NPPP > 0
81
82#define VJC
83
84#include "param.h"
85#include "systm.h"
86#include "proc.h"
87#include "mbuf.h"
8b3438a6
RG
88#include "socket.h"
89#include "ioctl.h"
90#include "file.h"
91#include "tty.h"
92#include "kernel.h"
93#include "conf.h"
3228baa0 94#include "dkstat.h"
8b4b7d90 95#include "pppdefs.h"
8b3438a6
RG
96
97#include "if.h"
98#include "if_types.h"
99#include "netisr.h"
100#include "route.h"
101#if INET
102#include "../netinet/in.h"
103#include "../netinet/in_systm.h"
104#include "../netinet/in_var.h"
105#include "../netinet/ip.h"
106#endif
107
2875cbc6
RG
108#include "bpfilter.h"
109#if NBPFILTER > 0
110#include "time.h"
111#include "bpf.h"
112#endif
113
8b3438a6
RG
114/*
115 * Here we try to tell whether we are in a 386BSD kernel, or
116 * in a NetBSD/Net-2/4.3-Reno kernel.
117 */
118#ifndef RB_LEN
119/* NetBSD, 4.3-Reno or similar */
120#define CCOUNT(q) ((q)->c_cc)
45abd37c 121#define TSA_HUP_OR_INPUT(tp) ((caddr_t)&tp->t_rawq)
8b3438a6
RG
122
123#else
124/* 386BSD, Jolitz-style ring buffers */
125#define t_outq t_out
8b3438a6
RG
126#define t_canq t_can
127#define CCOUNT(q) (RB_LEN(q))
128#endif
129
130#ifdef VJC
131#include "slcompress.h"
132#define HDROFF MAX_HDR
133/* HDROFF should really be 128, but other parts of the system will
134 panic on TCP+IP headers bigger than MAX_HDR = MHLEN (100). */
135
136#else
137#define HDROFF (0)
138#endif
139
140#include "if_ppp.h"
141#include "machine/mtpr.h"
142
143struct ppp_softc ppp_softc[NPPP];
144int ppp_async_out_debug = 0;
145int ppp_async_in_debug = 0;
146int ppp_debug = 0;
2875cbc6
RG
147int ppp_raw_in_debug = -1;
148char ppp_rawin[32];
149int ppp_rawin_count;
8b3438a6
RG
150
151void pppattach __P((void));
152int pppopen __P((dev_t dev, struct tty *tp));
153void pppclose __P((struct tty *tp, int flag));
154int pppread __P((struct tty *tp, struct uio *uio, int flag));
155int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
156int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag));
157int pppoutput __P((struct ifnet *ifp, struct mbuf *m0,
4c45483e 158 struct sockaddr *dst, struct rtentry *rt));
8b3438a6
RG
159void pppstart __P((struct tty *tp));
160void pppinput __P((int c, struct tty *tp));
161int pppioctl __P((struct ifnet *ifp, int cmd, caddr_t data));
162
163static u_short pppfcs __P((u_short fcs, u_char *cp, int len));
164static int pppinit __P((struct ppp_softc *sc));
165static struct mbuf *ppp_btom __P((struct ppp_softc *sc));
166static void pppdumpm __P((struct mbuf *m0, int pktlen));
167static void pppdumpb __P((u_char *b, int l));
168
169/*
170 * Some useful mbuf macros not in mbuf.h.
171 */
172#define M_DATASTART(m) \
173 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf : \
174 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
175
176#define M_DATASIZE(m) \
177 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_size : \
178 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
179
2875cbc6
RG
180/*
181 * The following disgusting hack gets around the problem that IP TOS
182 * can't be set yet. We want to put "interactive" traffic on a high
183 * priority queue. To decide if traffic is interactive, we check that
184 * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
185 */
186static u_short interactive_ports[8] = {
187 0, 513, 0, 0,
188 0, 21, 0, 23,
189};
190#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
191
192/*
193 * Does c need to be escaped?
194 */
195#define ESCAPE_P(c) (((c) == PPP_FLAG) || ((c) == PPP_ESCAPE) || \
196 (c) < 0x20 && (sc->sc_asyncmap & (1 << (c))))
197
8b3438a6
RG
198/*
199 * Called from boot code to establish ppp interfaces.
200 */
201void
202pppattach()
203{
204 register struct ppp_softc *sc;
205 register int i = 0;
206
207 for (sc = ppp_softc; i < NPPP; sc++) {
208 sc->sc_if.if_name = "ppp";
209 sc->sc_if.if_unit = i++;
210 sc->sc_if.if_mtu = PPP_MTU;
211 sc->sc_if.if_flags = IFF_POINTOPOINT;
212 sc->sc_if.if_type = IFT_PPP;
2875cbc6 213 sc->sc_if.if_hdrlen = PPP_HEADER_LEN;
8b3438a6
RG
214 sc->sc_if.if_ioctl = pppioctl;
215 sc->sc_if.if_output = pppoutput;
216 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
217 sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
2875cbc6 218 sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
8b3438a6 219 if_attach(&sc->sc_if);
2875cbc6
RG
220#if NBPFILTER > 0
221 bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HEADER_LEN);
222#endif
8b3438a6
RG
223 }
224}
225
3228baa0
GW
226TEXT_SET(pseudo_set, pppattach);
227
8b3438a6
RG
228/*
229 * Line specific open routine.
230 * Attach the given tty to the first available ppp unit.
231 */
232/* ARGSUSED */
233int
234pppopen(dev, tp)
235 dev_t dev;
236 register struct tty *tp;
237{
238 struct proc *p = curproc; /* XXX */
239 register struct ppp_softc *sc;
240 register int nppp;
241 int error, s;
242
243 if (error = suser(p->p_ucred, &p->p_acflag))
244 return (error);
245
246 if (tp->t_line == PPPDISC)
247 return (0);
248
249 for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
2875cbc6
RG
250 if (sc->sc_ttyp == NULL)
251 break;
252 if (nppp >= NPPP)
45abd37c 253 return (ENXIO);
2875cbc6
RG
254
255 sc->sc_flags = 0;
256 sc->sc_ilen = 0;
fde1aeb2 257 sc->sc_asyncmap = ~0;
2875cbc6
RG
258 sc->sc_rasyncmap = 0;
259 sc->sc_mru = PPP_MRU;
8b3438a6 260#ifdef VJC
2875cbc6 261 sl_compress_init(&sc->sc_comp);
8b3438a6 262#endif
2875cbc6
RG
263 if (pppinit(sc) == 0) {
264 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
265 return (ENOBUFS);
266 }
267 tp->t_sc = (caddr_t)sc;
268 sc->sc_ttyp = tp;
269 sc->sc_outm = NULL;
270 ttyflush(tp, FREAD | FWRITE);
271 sc->sc_if.if_flags |= IFF_RUNNING;
8b3438a6
RG
272
273#ifdef PPP_OUTQ_SIZE
2875cbc6
RG
274 /* N.B. this code is designed *only* for use in NetBSD */
275 s = spltty();
276 /* get rid of the default outq clist buffer */
277 clfree(&tp->t_outq);
278 /* and get a new one, without quoting support, much larger */
279 clalloc(&tp->t_outq, PPP_OUTQ_SIZE, 0);
280 splx (s);
8b3438a6
RG
281#endif /* PPP_OUTQ_SIZE */
282
2875cbc6 283 return (0);
8b3438a6
RG
284}
285
286/*
287 * Line specific close routine.
288 * Detach the tty from the ppp unit.
289 * Mimics part of ttyclose().
290 */
291void
292pppclose(tp, flag)
293 struct tty *tp;
294 int flag;
295{
296 register struct ppp_softc *sc;
297 struct mbuf *m;
298 int s;
299
31a29b9d 300 ttywflush(tp);
8b3438a6
RG
301 s = splimp(); /* paranoid; splnet probably ok */
302 tp->t_line = 0;
303 sc = (struct ppp_softc *)tp->t_sc;
304 if (sc != NULL) {
305 if_down(&sc->sc_if);
306 sc->sc_ttyp = NULL;
307 tp->t_sc = NULL;
308 m_freem(sc->sc_outm);
309 sc->sc_outm = NULL;
310 m_freem(sc->sc_m);
311 sc->sc_m = NULL;
312 for (;;) {
313 IF_DEQUEUE(&sc->sc_inq, m);
314 if (m == NULL)
315 break;
316 m_freem(m);
317 }
2875cbc6
RG
318 for (;;) {
319 IF_DEQUEUE(&sc->sc_fastq, m);
320 if (m == NULL)
321 break;
322 m_freem(m);
323 }
8b3438a6
RG
324 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
325
326#ifdef PPP_OUTQ_SIZE
327 /* reinstall default clist-buffer for outq
328 XXXX should really remember old value and restore that!! */
329 clfree(&tp->t_outq);
330 clalloc(&tp->t_outq, 1024, 0);
331#endif /* PPP_OUTQ_SIZE */
332
333 }
334 splx(s);
335}
336
337/*
338 * Line specific (tty) read routine.
339 */
340int
341pppread(tp, uio, flag)
342 register struct tty *tp;
343 struct uio *uio;
344 int flag;
345{
346 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
347 struct mbuf *m, *m0;
45abd37c
AC
348 int s;
349 int error;
8b3438a6 350
8b3438a6 351 s = splimp();
45abd37c
AC
352 for (;;) {
353 if (tp->t_line != PPPDISC) {
354 splx(s);
355 return (ENXIO);
356 }
357 if (!CAN_DO_IO(tp)) {
358 splx(s);
359 return (EIO);
360 }
361 if (sc->sc_inq.ifq_head != NULL)
362 break;
8b3438a6
RG
363 if (tp->t_state & TS_ASYNC) {
364 splx(s);
365 return (EWOULDBLOCK);
366 }
45abd37c
AC
367 error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, "pppin", 0);
368 if (error) {
369 splx(s);
370 return (error);
371 }
8b3438a6
RG
372 }
373
374 /* Pull place-holder byte out of canonical queue */
6cc15668 375 getc(tp->t_canq);
8b3438a6
RG
376
377 /* Get the packet from the input queue */
378 IF_DEQUEUE(&sc->sc_inq, m0);
379 splx(s);
380
45abd37c 381 error = 0;
8b3438a6
RG
382 for (m = m0; m && uio->uio_resid; m = m->m_next)
383 if (error = uiomove(mtod(m, u_char *), m->m_len, uio))
384 break;
385 m_freem(m0);
386 return (error);
387}
388
389/*
390 * Line specific (tty) write routine.
391 */
392int
393pppwrite(tp, uio, flag)
394 register struct tty *tp;
395 struct uio *uio;
396 int flag;
397{
398 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
399 struct mbuf *m, *m0, **mp;
400 struct sockaddr dst;
401 struct ppp_header *ph1, *ph2;
45abd37c 402 int len, error, s;
8b3438a6 403
8b3438a6 404 if (tp->t_line != PPPDISC)
45abd37c
AC
405 return (ENXIO);
406
407 /*
408 * XXX the locking is probably too strong, and/or the order of checking
409 * for errors requires an inconvenient number of splx()'s. pppoutput()
410 * does its own locking, but we must hold at least an spltty() lock to
411 * preserve the validity of the test of TS_CARR_ON in CAN_DO_IO().
412 */
413 s = splimp();
414
415 if (!CAN_DO_IO(tp)) {
416 splx(s);
417 return (EIO);
418 }
2875cbc6 419 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HEADER_LEN ||
45abd37c
AC
420 uio->uio_resid < PPP_HEADER_LEN) {
421 splx(s);
8b3438a6 422 return (EMSGSIZE);
45abd37c 423 }
8b3438a6
RG
424 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
425 MGET(m, M_WAIT, MT_DATA);
426 if ((*mp = m) == NULL) {
427 m_freem(m0);
45abd37c 428 splx(s);
8b3438a6
RG
429 return (ENOBUFS);
430 }
431 if (uio->uio_resid >= MCLBYTES / 2)
432 MCLGET(m, M_DONTWAIT);
433 len = MIN(M_TRAILINGSPACE(m), uio->uio_resid);
434 if (error = uiomove(mtod(m, u_char *), len, uio)) {
435 m_freem(m0);
45abd37c 436 splx(s);
8b3438a6
RG
437 return (error);
438 }
439 m->m_len = len;
440 }
441 dst.sa_family = AF_UNSPEC;
442 ph1 = (struct ppp_header *) &dst.sa_data;
443 ph2 = mtod(m0, struct ppp_header *);
444 *ph1 = *ph2;
2875cbc6
RG
445 m0->m_data += PPP_HEADER_LEN;
446 m0->m_len -= PPP_HEADER_LEN;
45abd37c
AC
447 error = pppoutput(&sc->sc_if, m0, &dst, 0);
448 splx(s);
449 return (error);
8b3438a6
RG
450}
451
452/*
453 * Line specific (tty) ioctl routine.
454 * Provide a way to get the ppp unit number.
455 * This discipline requires that tty device drivers call
456 * the line specific l_ioctl routine from their ioctl routines.
457 */
458/* ARGSUSED */
459int
460ppptioctl(tp, cmd, data, flag)
461 struct tty *tp;
462 caddr_t data;
463 int cmd, flag;
464{
465 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
466 struct proc *p = curproc; /* XXX */
2875cbc6 467 int s, error, flags, mru;
8b3438a6
RG
468
469 switch (cmd) {
470#if 0 /* this is handled (properly) by ttioctl */
471 case TIOCGETD:
472 *(int *)data = sc->sc_if.if_unit;
473 break;
474#endif
475 case FIONREAD:
476 *(int *)data = sc->sc_inq.ifq_len;
477 break;
478
479 case PPPIOCGUNIT:
480 *(int *)data = sc->sc_if.if_unit;
481 break;
482
483 case PPPIOCGFLAGS:
484 *(u_int *)data = sc->sc_flags;
485 break;
486
487 case PPPIOCSFLAGS:
488 if (error = suser(p->p_ucred, &p->p_acflag))
489 return (error);
2875cbc6 490 flags = *(int *)data & SC_MASK;
8b3438a6 491 s = splimp();
2875cbc6 492 sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
8b3438a6
RG
493 splx(s);
494 break;
495
496 case PPPIOCSASYNCMAP:
497 if (error = suser(p->p_ucred, &p->p_acflag))
498 return (error);
499 sc->sc_asyncmap = *(u_int *)data;
500 break;
501
502 case PPPIOCGASYNCMAP:
503 *(u_int *)data = sc->sc_asyncmap;
504 break;
505
2875cbc6
RG
506 case PPPIOCSRASYNCMAP:
507 if (error = suser(p->p_ucred, &p->p_acflag))
508 return (error);
509 sc->sc_rasyncmap = *(u_int *)data;
510 break;
511
512 case PPPIOCGRASYNCMAP:
513 *(u_int *)data = sc->sc_rasyncmap;
514 break;
515
516 case PPPIOCSMRU:
517 if (error = suser(p->p_ucred, &p->p_acflag))
518 return (error);
519 mru = *(int *)data;
520 if (mru >= PPP_MRU && mru <= PPP_MAXMRU) {
521 sc->sc_mru = mru;
522 if (pppinit(sc) == 0) {
523 error = ENOBUFS;
524 sc->sc_mru = PPP_MRU;
525 if (pppinit(sc) == 0)
526 sc->sc_if.if_flags &= ~IFF_UP;
527 }
528 }
529 break;
530
531 case PPPIOCGMRU:
532 *(int *)data = sc->sc_mru;
533 break;
534
8b3438a6
RG
535 default:
536 return (-1);
537 }
538 return (0);
539}
540
541/*
542 * FCS lookup table as calculated by genfcstab.
543 */
544static u_short fcstab[256] = {
545 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
546 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
547 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
548 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
549 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
550 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
551 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
552 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
553 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
554 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
555 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
556 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
557 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
558 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
559 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
560 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
561 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
562 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
563 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
564 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
565 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
566 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
567 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
568 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
569 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
570 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
571 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
572 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
573 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
574 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
575 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
576 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
577};
578
579/*
580 * Calculate a new FCS given the current FCS and the new data.
581 */
582static u_short
583pppfcs(fcs, cp, len)
584 register u_short fcs;
585 register u_char *cp;
586 register int len;
587{
588 while (len--)
589 fcs = PPP_FCS(fcs, *cp++);
590 return (fcs);
591}
592
593/*
594 * Queue a packet. Start transmission if not active.
595 * Packet is placed in Information field of PPP frame.
596 */
597int
4c45483e
GW
598pppoutput(ifp, m0, dst, rt)
599 struct ifnet *ifp;
600 struct mbuf *m0;
601 struct sockaddr *dst;
602 struct rtentry *rt;
8b3438a6
RG
603{
604 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
8b3438a6 605 struct ppp_header *ph;
2875cbc6
RG
606 int protocol, address, control;
607 u_char *cp;
608 int s, error;
609 struct ip *ip;
610 struct ifqueue *ifq;
8b3438a6
RG
611
612 if (sc->sc_ttyp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
613 || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) {
614 error = ENETDOWN; /* sort of */
615 goto bad;
616 }
4146e002 617 if (!CAN_DO_IO(sc->sc_ttyp)) {
8b3438a6
RG
618 error = EHOSTUNREACH;
619 goto bad;
620 }
621
622 /*
623 * Compute PPP header.
624 */
625 address = PPP_ALLSTATIONS;
626 control = PPP_UI;
2875cbc6 627 ifq = &ifp->if_snd;
8b3438a6
RG
628 switch (dst->sa_family) {
629#ifdef INET
630 case AF_INET:
631 protocol = PPP_IP;
2875cbc6
RG
632 /*
633 * If this is a TCP packet to or from an "interactive" port,
634 * put the packet on the fastq instead.
635 */
636 if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
637 register int p = ((int *)ip)[ip->ip_hl];
638 if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
639 ifq = &sc->sc_fastq;
8b3438a6 640 }
8b3438a6
RG
641 break;
642#endif
643#ifdef NS
644 case AF_NS:
645 protocol = PPP_XNS;
646 break;
647#endif
648 case AF_UNSPEC:
649 ph = (struct ppp_header *) dst->sa_data;
650 address = ph->ph_address;
651 control = ph->ph_control;
652 protocol = ntohs(ph->ph_protocol);
653 break;
654 default:
655 printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
656 error = EAFNOSUPPORT;
657 goto bad;
658 }
8b3438a6
RG
659
660 /*
661 * Add PPP header. If no space in first mbuf, allocate another.
2875cbc6 662 * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
8b3438a6 663 */
2875cbc6
RG
664 if (M_LEADINGSPACE(m0) < PPP_HEADER_LEN) {
665 m0 = m_prepend(m0, PPP_HEADER_LEN, M_DONTWAIT);
8b3438a6
RG
666 if (m0 == 0) {
667 error = ENOBUFS;
668 goto bad;
669 }
670 m0->m_len = 0;
671 } else
2875cbc6 672 m0->m_data -= PPP_HEADER_LEN;
8b3438a6
RG
673
674 cp = mtod(m0, u_char *);
2875cbc6
RG
675 *cp++ = address;
676 *cp++ = control;
677 *cp++ = protocol >> 8;
8b3438a6 678 *cp++ = protocol & 0xff;
2875cbc6 679 m0->m_len += PPP_HEADER_LEN;
8b3438a6
RG
680
681 if (ppp_async_out_debug) {
682 printf("ppp%d output: ", ifp->if_unit);
683 pppdumpm(m0, -1);
684 }
685
2875cbc6
RG
686#if NBPFILTER > 0
687 /* See if bpf wants to look at the packet. */
688 if (sc->sc_bpf)
689 bpf_mtap(sc->sc_bpf, m0);
690#endif
691
692 /*
693 * Put the packet on the appropriate queue.
694 */
8b3438a6 695 s = splimp();
2875cbc6
RG
696 if (IF_QFULL(ifq)) {
697 IF_DROP(ifq);
8b3438a6
RG
698 splx(s);
699 sc->sc_if.if_oerrors++;
700 error = ENOBUFS;
701 goto bad;
702 }
2875cbc6 703 IF_ENQUEUE(ifq, m0);
88b38551
RG
704 /*
705 * The next statement used to be subject to:
706 * if (CCOUNT(&sc->sc_ttyp->t_outq) == 0)
707 * which was removed so that we don't hang up completely
708 * if the serial transmitter loses an interrupt.
709 */
710 pppstart(sc->sc_ttyp);
8b3438a6
RG
711 splx(s);
712 return (0);
713
714bad:
715 m_freem(m0);
716 return (error);
717}
718
719/*
720 * Start output on interface. Get another datagram
721 * to send from the interface queue and map it to
722 * the interface before starting output.
723 */
724void
725pppstart(tp)
726 register struct tty *tp;
727{
728 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
729 register struct mbuf *m;
730 register int len;
731 register u_char *start, *stop, *cp;
2875cbc6 732 int n, s, ndone, done;
8b3438a6 733 struct mbuf *m2;
2875cbc6
RG
734 int address, control, protocol;
735 int compac, compprot, nb;
8b3438a6
RG
736
737 for (;;) {
738 /*
45abd37c 739 * Call output process whether or not there is any output.
8b3438a6
RG
740 * We are being called in lieu of ttstart and must do what
741 * it would.
742 */
45abd37c
AC
743 (*tp->t_oproc)(tp);
744 if (CCOUNT(tp->t_outq) > PPP_HIWAT)
745 return;
746
8b3438a6
RG
747 /*
748 * This happens briefly when the line shuts down.
749 */
750 if (sc == NULL)
751 return;
752
753 /*
754 * See if we have an existing packet partly sent.
755 * If not, get a new packet and start sending it.
2875cbc6
RG
756 * We take packets on the priority queue ahead of those
757 * on the normal queue.
8b3438a6
RG
758 */
759 m = sc->sc_outm;
760 if (m == NULL) {
761 s = splimp();
2875cbc6
RG
762 IF_DEQUEUE(&sc->sc_fastq, m);
763 if (m == NULL)
764 IF_DEQUEUE(&sc->sc_if.if_snd, m);
8b3438a6
RG
765 splx(s);
766 if (m == NULL)
767 return;
768
2875cbc6
RG
769 /*
770 * Extract the ppp header of the new packet.
771 * The ppp header will be in one mbuf.
772 */
773 cp = mtod(m, u_char *);
774 address = *cp++;
775 control = *cp++;
776 protocol = *cp++;
777 protocol = (protocol << 8) + *cp++;
778 m->m_data += PPP_HEADER_LEN;
779 m->m_len -= PPP_HEADER_LEN;
780
781#ifdef VJC
782 /*
783 * If the packet is a TCP/IP packet, see if we can compress it.
784 */
785 if (protocol == PPP_IP && sc->sc_flags & SC_COMP_TCP) {
786 struct ip *ip;
787 int type;
788 struct mbuf *mp;
789
790 mp = m;
791 if (mp->m_len <= 0) {
792 mp = mp->m_next;
793 cp = mtod(mp, u_char *);
794 }
795 ip = (struct ip *) cp;
796 if (ip->ip_p == IPPROTO_TCP) {
797 type = sl_compress_tcp(mp, ip, &sc->sc_comp,
798 !(sc->sc_flags & SC_NO_TCP_CCID));
799 switch (type) {
800 case TYPE_UNCOMPRESSED_TCP:
801 protocol = PPP_VJC_UNCOMP;
802 break;
803 case TYPE_COMPRESSED_TCP:
804 protocol = PPP_VJC_COMP;
805 break;
806 }
807 }
808 }
809#endif
810
811 /*
812 * Compress the address/control and protocol, if possible.
813 */
814 compac = sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
815 control == PPP_UI && protocol != PPP_ALLSTATIONS &&
816 protocol != PPP_LCP;
817 compprot = sc->sc_flags & SC_COMP_PROT && protocol < 0x100;
818 nb = (compac ? 0 : 2) + (compprot ? 1 : 2);
819 m->m_data -= nb;
820 m->m_len += nb;
821
822 cp = mtod(m, u_char *);
823 if (!compac) {
824 *cp++ = address;
825 *cp++ = control;
826 }
827 if (!compprot)
828 *cp++ = protocol >> 8;
829 *cp++ = protocol;
830
8b3438a6
RG
831 /*
832 * The extra PPP_FLAG will start up a new packet, and thus
833 * will flush any accumulated garbage. We do this whenever
834 * the line may have been idle for some time.
835 */
6cc15668 836 if (CCOUNT(tp->t_outq) == 0) {
8b3438a6 837 ++sc->sc_bytessent;
6cc15668 838 (void) putc(PPP_FLAG, tp->t_outq);
8b3438a6 839 }
2875cbc6
RG
840
841 /* Calculate the FCS for the first mbuf's worth. */
842 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
8b3438a6
RG
843 }
844
2875cbc6 845 for (;;) {
8b3438a6
RG
846 start = mtod(m, u_char *);
847 len = m->m_len;
848 stop = start + len;
849 while (len > 0) {
850 /*
851 * Find out how many bytes in the string we can
852 * handle without doing something special.
853 */
854 for (cp = start; cp < stop; cp++)
2875cbc6 855 if (ESCAPE_P(*cp))
8b3438a6
RG
856 break;
857 n = cp - start;
858 if (n) {
859#ifndef RB_LEN
860 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
6cc15668 861 ndone = n - b_to_q(start, n, tp->t_outq);
8b3438a6
RG
862#else
863#ifdef NetBSD
88b38551 864 /* NetBSD with 2-byte ring buffer entries */
8b3438a6
RG
865 ndone = rb_cwrite(&tp->t_out, start, n);
866#else
88b38551 867 /* 386BSD, FreeBSD */
8b3438a6
RG
868 int cc, nleft;
869 for (nleft = n; nleft > 0; nleft -= cc) {
6cc15668 870 if ((cc = RB_CONTIGPUT(tp->t_out)) == 0)
8b3438a6
RG
871 break;
872 cc = min (cc, nleft);
6cc15668
GR
873 bcopy((char *)start + n - nleft, tp->t_out->rb_tl, cc);
874 tp->t_out->rb_tl = RB_ROLLOVER(tp->t_out,
875 tp->t_out->rb_tl + cc);
8b3438a6
RG
876 }
877 ndone = n - nleft;
878#endif /* NetBSD */
879#endif /* RB_LEN */
880 len -= ndone;
881 start += ndone;
882 sc->sc_bytessent += ndone;
883
884 if (ndone < n)
885 break; /* packet doesn't fit */
886 }
887 /*
888 * If there are characters left in the mbuf,
889 * the first one must be special..
890 * Put it out in a different form.
891 */
892 if (len) {
6cc15668 893 if (putc(PPP_ESCAPE, tp->t_outq))
8b3438a6 894 break;
6cc15668
GR
895 if (putc(*start ^ PPP_TRANS, tp->t_outq)) {
896 (void) unputc(tp->t_outq);
8b3438a6
RG
897 break;
898 }
899 sc->sc_bytessent += 2;
900 start++;
901 len--;
902 }
903 }
904 /*
905 * If we didn't empty this mbuf, remember where we're up to.
2875cbc6
RG
906 * If we emptied the last mbuf, try to add the FCS and closing
907 * flag, and if we can't, leave sc_outm pointing to m, but with
908 * m->m_len == 0, to remind us to output the FCS and flag later.
8b3438a6 909 */
2875cbc6
RG
910 done = len == 0;
911 if (done && m->m_next == NULL) {
912 u_char *p, *q;
913 int c;
914 u_char endseq[8];
915
916 /*
917 * We may have to escape the bytes in the FCS.
918 */
919 p = endseq;
920 c = ~sc->sc_outfcs & 0xFF;
921 if (ESCAPE_P(c)) {
922 *p++ = PPP_ESCAPE;
923 *p++ = c ^ PPP_TRANS;
924 } else
925 *p++ = c;
926 c = (~sc->sc_outfcs >> 8) & 0xFF;
927 if (ESCAPE_P(c)) {
928 *p++ = PPP_ESCAPE;
929 *p++ = c ^ PPP_TRANS;
930 } else
931 *p++ = c;
932 *p++ = PPP_FLAG;
933
934 /*
935 * Try to output the FCS and flag. If the bytes
936 * don't all fit, back out.
937 */
938 for (q = endseq; q < p; ++q)
6cc15668 939 if (putc(*q, tp->t_outq)) {
2875cbc6
RG
940 done = 0;
941 for (; q > endseq; --q)
6cc15668 942 unputc(tp->t_outq);
2875cbc6
RG
943 break;
944 }
945 }
946
947 if (!done) {
8b3438a6
RG
948 m->m_data = start;
949 m->m_len = len;
950 sc->sc_outm = m;
951 if (tp->t_oproc != NULL)
952 (*tp->t_oproc)(tp);
953 return; /* can't do any more at the moment */
954 }
955
956 /* Finished with this mbuf; free it and move on. */
957 MFREE(m, m2);
2875cbc6
RG
958 if (m2 == NULL)
959 break;
960
8b3438a6 961 m = m2;
2875cbc6
RG
962 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
963 }
8b3438a6
RG
964
965 /* Finished a packet */
966 sc->sc_outm = NULL;
967 sc->sc_bytessent++; /* account for closing flag */
968 sc->sc_if.if_opackets++;
969 sc->sc_if.if_obytes = sc->sc_bytessent;
970 }
971}
972
973/*
2875cbc6 974 * Allocate enough mbuf to handle current MRU.
8b3438a6
RG
975 */
976static int
977pppinit(sc)
978 register struct ppp_softc *sc;
979{
980 struct mbuf *m, **mp;
2875cbc6 981 int len = HDROFF + sc->sc_mru + PPP_HEADER_LEN + PPP_FCS_LEN;
8b3438a6
RG
982 int s;
983
984 s = splimp();
985 for (mp = &sc->sc_m; (m = *mp) != NULL; mp = &m->m_next)
986 if ((len -= M_DATASIZE(m)) <= 0) {
987 splx(s);
988 return (1);
989 }
990
991 for (;; mp = &m->m_next) {
992 MGETHDR(m, M_DONTWAIT, MT_DATA);
993 if (m == 0) {
994 m_freem(sc->sc_m);
995 sc->sc_m = NULL;
996 splx(s);
2875cbc6 997 printf("ppp%d: can't allocate mbuf\n", sc->sc_if.if_unit);
8b3438a6
RG
998 return (0);
999 }
1000 *mp = m;
1001 MCLGET(m, M_DONTWAIT);
1002 if ((len -= M_DATASIZE(m)) <= 0) {
1003 splx(s);
1004 return (1);
1005 }
1006 }
1007}
1008
1009/*
1010 * Copy mbuf chain. Would like to use m_copy(), but we need a real copy
1011 * of the data, not just copies of pointers to the data.
1012 */
1013static struct mbuf *
1014ppp_btom(sc)
1015 struct ppp_softc *sc;
1016{
1017 register struct mbuf *m, **mp;
1018 struct mbuf *top = sc->sc_m;
1019
1020 /*
1021 * First check current mbuf. If we have more than a small mbuf,
1022 * return the whole cluster and set beginning of buffer to the
1023 * next mbuf.
1024 * Else, copy the current bytes into a small mbuf, attach the new
1025 * mbuf to the end of the chain and set beginning of buffer to the
1026 * current mbuf.
1027 */
1028
1029 if (sc->sc_mc->m_len > MHLEN) {
1030 sc->sc_m = sc->sc_mc->m_next;
1031 sc->sc_mc->m_next = NULL;
1032 }
1033 else {
1034 /* rather than waste a whole cluster on <= MHLEN bytes,
1035 alloc a small mbuf and copy to it */
1036 MGETHDR(m, M_DONTWAIT, MT_DATA);
1037 if (m == NULL)
1038 return (NULL);
1039
2875cbc6 1040 bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t), sc->sc_mc->m_len);
8b3438a6
RG
1041 m->m_len = sc->sc_mc->m_len;
1042 for (mp = &top; *mp != sc->sc_mc; mp = &(*mp)->m_next)
1043 ;
1044 *mp = m;
1045 sc->sc_m = sc->sc_mc;
1046 }
1047
1048 /*
1049 * Try to allocate enough extra mbufs to handle the next packet.
1050 */
1051 if (pppinit(sc) == 0) {
1052 m_freem(top);
1053 if (pppinit(sc) == 0)
1054 sc->sc_if.if_flags &= ~IFF_UP;
1055 return (NULL);
1056 }
1057
1058 return (top);
1059}
1060
1061/*
1062 * tty interface receiver interrupt.
1063 */
1064#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1065 TYPE_UNCOMPRESSED_TCP)
1066
1067void
1068pppinput(c, tp)
1069 int c;
1070 register struct tty *tp;
1071{
1072 register struct ppp_softc *sc;
1073 struct mbuf *m;
1074 struct ifqueue *inq;
1075 int s, ilen, xlen, proto;
c0ace2fe 1076 struct ppp_header hdr;
8b3438a6
RG
1077
1078 tk_nin++;
1079 sc = (struct ppp_softc *)tp->t_sc;
1080 if (sc == NULL)
1081 return;
1082
1083 ++sc->sc_if.if_ibytes;
1084
2875cbc6 1085 if (c & TTY_FE) {
8b3438a6 1086 /* framing error or overrun on this char - abort packet */
2875cbc6
RG
1087 if (ppp_debug)
1088 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
8b3438a6 1089 goto flush;
2875cbc6 1090 }
8b3438a6
RG
1091
1092 c &= 0xff;
2875cbc6
RG
1093
1094 if (sc->sc_if.if_unit == ppp_raw_in_debug) {
1095 ppp_rawin[ppp_rawin_count++] = c;
1096 if (ppp_rawin_count >= sizeof(ppp_rawin)) {
1097 printf("raw ppp%d: ", ppp_raw_in_debug);
1098 pppdumpb(ppp_rawin, ppp_rawin_count);
1099 ppp_rawin_count = 0;
1100 }
1101 }
1102
8b3438a6
RG
1103 if (c == PPP_FLAG) {
1104 ilen = sc->sc_ilen;
1105 sc->sc_ilen = 0;
1106
1107 if (sc->sc_flags & SC_FLUSH
1108 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
1109#ifdef VJC
1110 /*
1111 * If we've missed a packet, we must toss subsequent compressed
1112 * packets which don't have an explicit connection ID.
1113 */
1114 sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp);
1115#endif
1116 if ((sc->sc_flags & SC_FLUSH) == 0){
1117 if (ppp_debug)
2875cbc6 1118 printf("ppp%d: bad fcs\n", sc->sc_if.if_unit);
8b3438a6
RG
1119 sc->sc_if.if_ierrors++;
1120 } else
1121 sc->sc_flags &= ~SC_FLUSH;
1122 return;
1123 }
1124
2875cbc6 1125 if (ilen < PPP_HEADER_LEN + PPP_FCS_LEN) {
8b3438a6
RG
1126 if (ilen) {
1127 if (ppp_debug)
2875cbc6 1128 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
8b3438a6
RG
1129 sc->sc_if.if_ierrors++;
1130 }
1131 return;
1132 }
1133
1134 /*
1135 * Remove FCS trailer. Somewhat painful...
1136 */
1137 ilen -= 2;
1138 if (--sc->sc_mc->m_len == 0) {
1139 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1140 ;
1141 sc->sc_mc = m;
1142 }
1143 sc->sc_mc->m_len--;
1144
1145 sc->sc_if.if_ipackets++;
1146 m = sc->sc_m;
1147
1148 if (ppp_async_in_debug) {
2875cbc6 1149 printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen);
8b3438a6
RG
1150 pppdumpm(m, ilen);
1151 }
1152
c0ace2fe
RG
1153 hdr = *mtod(m, struct ppp_header *);
1154 proto = ntohs(hdr.ph_protocol);
8b3438a6
RG
1155
1156#ifdef VJC
c0ace2fe
RG
1157 /*
1158 * See if we have a VJ-compressed packet to uncompress.
1159 */
1160 if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
1161 char *pkttype = proto == PPP_VJC_COMP? "": "un";
8b3438a6 1162
c0ace2fe 1163 if (sc->sc_flags & SC_REJ_COMP_TCP) {
8b3438a6
RG
1164 if (ppp_debug)
1165 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n",
1166 sc->sc_if.if_unit, pkttype, sc->sc_flags);
c0ace2fe
RG
1167 sc->sc_if.if_ierrors++;
1168 return;
8b3438a6 1169 }
c0ace2fe
RG
1170
1171 m->m_data += PPP_HEADER_LEN;
1172 m->m_len -= PPP_HEADER_LEN;
1173 ilen -= PPP_HEADER_LEN;
1174 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data),
1175 m->m_len, ilen,
1176 COMPTYPE(proto), &sc->sc_comp);
1177
1178 if (xlen == 0) {
1179 if (ppp_debug)
1180 printf("ppp%d: sl_uncompress failed on type %scomp\n",
1181 sc->sc_if.if_unit, pkttype);
1182 sc->sc_if.if_ierrors++;
1183 return;
1184 }
1185
1186 /* adjust the first mbuf by the decompressed amt */
1187 xlen += PPP_HEADER_LEN;
1188 m->m_len += xlen - ilen;
1189 ilen = xlen;
1190 m->m_data -= PPP_HEADER_LEN;
1191 proto = PPP_IP;
1192
1193#if NBPFILTER > 0
1194 /* put the ppp header back in place */
1195 hdr.ph_protocol = htons(PPP_IP);
1196 *mtod(m, struct ppp_header *) = hdr;
1197#endif /* NBPFILTER */
8b3438a6 1198 }
c0ace2fe 1199#endif /* VJC */
8b3438a6
RG
1200
1201 /* get this packet as an mbuf chain */
1202 if ((m = ppp_btom(sc)) == NULL) {
1203 sc->sc_if.if_ierrors++;
1204 return;
1205 }
1206 m->m_pkthdr.len = ilen;
1207 m->m_pkthdr.rcvif = &sc->sc_if;
1208
c0ace2fe
RG
1209#if NBPFILTER > 0
1210 /* See if bpf wants to look at the packet. */
1211 if (sc->sc_bpf)
1212 bpf_mtap(sc->sc_bpf, m);
1213#endif
1214
1215 switch (proto) {
1216#ifdef INET
1217 case PPP_IP:
1218 /*
1219 * IP packet - take off the ppp header and pass it up to IP.
1220 */
8b3438a6
RG
1221 if ((sc->sc_if.if_flags & IFF_UP) == 0) {
1222 /* interface is down - drop the packet. */
1223 m_freem(m);
1224 sc->sc_if.if_ierrors++;
1225 return;
1226 }
c0ace2fe
RG
1227 m->m_pkthdr.len -= PPP_HEADER_LEN;
1228 m->m_data += PPP_HEADER_LEN;
1229 m->m_len -= PPP_HEADER_LEN;
8b3438a6
RG
1230 schednetisr(NETISR_IP);
1231 inq = &ipintrq;
c0ace2fe
RG
1232 break;
1233#endif
8b3438a6 1234
c0ace2fe
RG
1235 default:
1236 /*
1237 * Some other protocol - place on input queue for read().
1238 * Put a placeholder byte in canq for ttselect()/ttnread().
1239 */
6cc15668 1240 putc(0, tp->t_canq);
8b3438a6
RG
1241 ttwakeup(tp);
1242 inq = &sc->sc_inq;
c0ace2fe 1243 break;
8b3438a6
RG
1244 }
1245
c0ace2fe
RG
1246 /*
1247 * Put the packet on the appropriate input queue.
1248 */
8b3438a6
RG
1249 s = splimp();
1250 if (IF_QFULL(inq)) {
1251 IF_DROP(inq);
1252 if (ppp_debug)
2875cbc6 1253 printf("ppp%d: queue full\n", sc->sc_if.if_unit);
8b3438a6
RG
1254 sc->sc_if.if_ierrors++;
1255 sc->sc_if.if_iqdrops++;
1256 m_freem(m);
1257 } else
1258 IF_ENQUEUE(inq, m);
1259
1260 splx(s);
1261 return;
1262 }
2875cbc6 1263
8b3438a6
RG
1264 if (sc->sc_flags & SC_FLUSH)
1265 return;
1266 if (c == PPP_ESCAPE) {
1267 sc->sc_flags |= SC_ESCAPED;
1268 return;
1269 }
2875cbc6
RG
1270 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1271 return;
8b3438a6
RG
1272
1273 if (sc->sc_flags & SC_ESCAPED) {
1274 sc->sc_flags &= ~SC_ESCAPED;
1275 c ^= PPP_TRANS;
1276 }
1277
1278 /*
1279 * Initialize buffer on first octet received.
1280 * First octet could be address or protocol (when compressing
1281 * address/control).
1282 * Second octet is control.
1283 * Third octet is first or second (when compressing protocol)
1284 * octet of protocol.
1285 * Fourth octet is second octet of protocol.
1286 */
1287 if (sc->sc_ilen == 0) {
1288 /* reset the first input mbuf */
1289 m = sc->sc_m;
1290 m->m_len = 0;
1291 m->m_data = M_DATASTART(sc->sc_m) + HDROFF;
1292 sc->sc_mc = m;
1293 sc->sc_mp = mtod(m, char *);
1294 sc->sc_fcs = PPP_INITFCS;
1295 if (c != PPP_ALLSTATIONS) {
2875cbc6 1296 if (sc->sc_flags & SC_REJ_COMP_AC) {
8b3438a6 1297 if (ppp_debug)
2875cbc6
RG
1298 printf("ppp%d: missing ALLSTATIONS, got 0x%x; flags %x\n",
1299 sc->sc_if.if_unit, c, sc->sc_flags);
8b3438a6
RG
1300 goto flush;
1301 }
1302 *sc->sc_mp++ = PPP_ALLSTATIONS;
1303 *sc->sc_mp++ = PPP_UI;
1304 sc->sc_ilen += 2;
1305 m->m_len += 2;
1306 }
1307 }
1308 if (sc->sc_ilen == 1 && c != PPP_UI) {
1309 if (ppp_debug)
2875cbc6 1310 printf("ppp%d: missing UI, got 0x%x\n", sc->sc_if.if_unit, c);
8b3438a6
RG
1311 goto flush;
1312 }
1313 if (sc->sc_ilen == 2 && (c & 1) == 1) {
2875cbc6 1314 /* RFC1331 says we have to accept a compressed protocol */
8b3438a6
RG
1315 *sc->sc_mp++ = 0;
1316 sc->sc_ilen++;
1317 sc->sc_mc->m_len++;
1318 }
1319 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1320 if (ppp_debug)
2875cbc6
RG
1321 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1322 (sc->sc_mp[-1] << 8) + c);
8b3438a6
RG
1323 goto flush;
1324 }
1325
2875cbc6
RG
1326 /* packet beyond configured mru? */
1327 if (++sc->sc_ilen > sc->sc_mru + PPP_HEADER_LEN + PPP_FCS_LEN) {
8b3438a6 1328 if (ppp_debug)
2875cbc6 1329 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
8b3438a6
RG
1330 goto flush;
1331 }
1332
1333 /* is this mbuf full? */
1334 m = sc->sc_mc;
1335 if (M_TRAILINGSPACE(m) <= 0) {
1336 sc->sc_mc = m = m->m_next;
1337 if (m == NULL) {
2875cbc6 1338 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
8b3438a6
RG
1339 goto flush;
1340 }
1341 m->m_len = 0;
1342 m->m_data = M_DATASTART(m);
1343 sc->sc_mp = mtod(m, char *);
1344 }
1345
1346 ++m->m_len;
1347 *sc->sc_mp++ = c;
1348 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1349 return;
1350
1351 flush:
1352 sc->sc_if.if_ierrors++;
1353 sc->sc_flags |= SC_FLUSH;
1354}
1355
1356/*
1357 * Process an ioctl request to interface.
1358 */
4c45483e 1359int
8b3438a6
RG
1360pppioctl(ifp, cmd, data)
1361 register struct ifnet *ifp;
1362 int cmd;
1363 caddr_t data;
1364{
1365 struct proc *p = curproc; /* XXX */
1366 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
1367 register struct ifaddr *ifa = (struct ifaddr *)data;
1368 register struct ifreq *ifr = (struct ifreq *)data;
1369 int s = splimp(), error = 0;
1370
1371
1372 switch (cmd) {
1373 case SIOCSIFFLAGS:
1374 if ((ifp->if_flags & IFF_RUNNING) == 0)
1375 ifp->if_flags &= ~IFF_UP;
1376 break;
1377
1378 case SIOCSIFADDR:
1379 if (ifa->ifa_addr->sa_family != AF_INET)
1380 error = EAFNOSUPPORT;
1381 break;
1382
1383 case SIOCSIFDSTADDR:
1384 if (ifa->ifa_addr->sa_family != AF_INET)
1385 error = EAFNOSUPPORT;
1386 break;
1387
1388 case SIOCSIFMTU:
1389 if (error = suser(p->p_ucred, &p->p_acflag))
1390 return (error);
1391 sc->sc_if.if_mtu = ifr->ifr_mtu;
8b3438a6
RG
1392 break;
1393
1394 case SIOCGIFMTU:
1395 ifr->ifr_mtu = sc->sc_if.if_mtu;
1396 break;
1397
1398 default:
1399 error = EINVAL;
1400 }
1401 splx(s);
1402 return (error);
1403}
1404
1405#define MAX_DUMP_BYTES 128
1406
1407static void
1408pppdumpm(m0, pktlen)
1409 struct mbuf *m0;
1410 int pktlen;
1411{
1412 char buf[2*MAX_DUMP_BYTES+4];
1413 char *bp = buf;
1414 struct mbuf *m;
1415 static char digits[] = "0123456789abcdef";
1416
1417 for (m = m0; m && pktlen; m = m->m_next) {
1418 int l = m->m_len;
1419 u_char *rptr = (u_char *)m->m_data;
1420
1421 if (pktlen > 0) {
1422 l = min(l, pktlen);
1423 pktlen -= l;
1424 }
1425 while (l--) {
1426 if (bp > buf + sizeof(buf) - 4)
1427 goto done;
1428 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1429 *bp++ = digits[*rptr++ & 0xf];
1430 }
1431
1432 if (m->m_next) {
1433 if (bp > buf + sizeof(buf) - 3)
1434 goto done;
1435 *bp++ = '|';
1436 }
1437 }
1438done:
1439 if (m && pktlen)
1440 *bp++ = '>';
1441 *bp = 0;
1442 printf("%s\n", buf);
1443}
1444
1445static void
1446pppdumpb(b, l)
1447 u_char *b;
1448 int l;
1449{
1450 char buf[2*MAX_DUMP_BYTES+4];
1451 char *bp = buf;
1452 static char digits[] = "0123456789abcdef";
1453
1454 while (l--) {
1455 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1456 *bp++ = digits[*b++ & 0xf];
1457 if (bp >= buf + sizeof(buf) - 2) {
1458 *bp++ = '>';
1459 break;
1460 }
1461 }
1462
1463 *bp = 0;
1464 printf("%s\n", buf);
1465}
1466
1467
1468#endif /* NPPP > 0 */