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