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