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