Media table reorganization.
[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/*
4c45483e 73 * $Id: if_ppp.c,v 1.4 1993/10/07 02:19:37 rgrimes 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"
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,
4c45483e 158 struct sockaddr *dst, struct rtentry *rt));
8b3438a6
RG
159void pppstart __P((struct tty *tp));
160void pppinput __P((int c, struct tty *tp));
161int pppioctl __P((struct ifnet *ifp, int cmd, caddr_t data));
162
163static u_short pppfcs __P((u_short fcs, u_char *cp, int len));
164static int pppinit __P((struct ppp_softc *sc));
165static struct mbuf *ppp_btom __P((struct ppp_softc *sc));
166static void pppdumpm __P((struct mbuf *m0, int pktlen));
167static void pppdumpb __P((u_char *b, int l));
168
169/*
170 * Some useful mbuf macros not in mbuf.h.
171 */
172#define M_DATASTART(m) \
173 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf : \
174 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
175
176#define M_DATASIZE(m) \
177 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_size : \
178 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
179
2875cbc6
RG
180/*
181 * The following disgusting hack gets around the problem that IP TOS
182 * can't be set yet. We want to put "interactive" traffic on a high
183 * priority queue. To decide if traffic is interactive, we check that
184 * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
185 */
186static u_short interactive_ports[8] = {
187 0, 513, 0, 0,
188 0, 21, 0, 23,
189};
190#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
191
192/*
193 * Does c need to be escaped?
194 */
195#define ESCAPE_P(c) (((c) == PPP_FLAG) || ((c) == PPP_ESCAPE) || \
196 (c) < 0x20 && (sc->sc_asyncmap & (1 << (c))))
197
8b3438a6
RG
198/*
199 * Called from boot code to establish ppp interfaces.
200 */
201void
202pppattach()
203{
204 register struct ppp_softc *sc;
205 register int i = 0;
206
207 for (sc = ppp_softc; i < NPPP; sc++) {
208 sc->sc_if.if_name = "ppp";
209 sc->sc_if.if_unit = i++;
210 sc->sc_if.if_mtu = PPP_MTU;
211 sc->sc_if.if_flags = IFF_POINTOPOINT;
212 sc->sc_if.if_type = IFT_PPP;
2875cbc6 213 sc->sc_if.if_hdrlen = PPP_HEADER_LEN;
8b3438a6
RG
214 sc->sc_if.if_ioctl = pppioctl;
215 sc->sc_if.if_output = pppoutput;
216 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
217 sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
2875cbc6 218 sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
8b3438a6 219 if_attach(&sc->sc_if);
2875cbc6
RG
220#if NBPFILTER > 0
221 bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HEADER_LEN);
222#endif
8b3438a6
RG
223 }
224}
225
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;
4c45483e 347 int error = 0;
8b3438a6
RG
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;
4c45483e 423 return (pppoutput(&sc->sc_if, m0, &dst, 0));
8b3438a6
RG
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
4c45483e
GW
572pppoutput(ifp, m0, dst, rt)
573 struct ifnet *ifp;
574 struct mbuf *m0;
575 struct sockaddr *dst;
576 struct rtentry *rt;
8b3438a6
RG
577{
578 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
8b3438a6 579 struct ppp_header *ph;
2875cbc6
RG
580 int protocol, address, control;
581 u_char *cp;
582 int s, error;
583 struct ip *ip;
584 struct ifqueue *ifq;
8b3438a6
RG
585
586 if (sc->sc_ttyp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
587 || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) {
588 error = ENETDOWN; /* sort of */
589 goto bad;
590 }
591 if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
592 error = EHOSTUNREACH;
593 goto bad;
594 }
595
596 /*
597 * Compute PPP header.
598 */
599 address = PPP_ALLSTATIONS;
600 control = PPP_UI;
2875cbc6 601 ifq = &ifp->if_snd;
8b3438a6
RG
602 switch (dst->sa_family) {
603#ifdef INET
604 case AF_INET:
605 protocol = PPP_IP;
2875cbc6
RG
606 /*
607 * If this is a TCP packet to or from an "interactive" port,
608 * put the packet on the fastq instead.
609 */
610 if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
611 register int p = ((int *)ip)[ip->ip_hl];
612 if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
613 ifq = &sc->sc_fastq;
8b3438a6 614 }
8b3438a6
RG
615 break;
616#endif
617#ifdef NS
618 case AF_NS:
619 protocol = PPP_XNS;
620 break;
621#endif
622 case AF_UNSPEC:
623 ph = (struct ppp_header *) dst->sa_data;
624 address = ph->ph_address;
625 control = ph->ph_control;
626 protocol = ntohs(ph->ph_protocol);
627 break;
628 default:
629 printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
630 error = EAFNOSUPPORT;
631 goto bad;
632 }
8b3438a6
RG
633
634 /*
635 * Add PPP header. If no space in first mbuf, allocate another.
2875cbc6 636 * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
8b3438a6 637 */
2875cbc6
RG
638 if (M_LEADINGSPACE(m0) < PPP_HEADER_LEN) {
639 m0 = m_prepend(m0, PPP_HEADER_LEN, M_DONTWAIT);
8b3438a6
RG
640 if (m0 == 0) {
641 error = ENOBUFS;
642 goto bad;
643 }
644 m0->m_len = 0;
645 } else
2875cbc6 646 m0->m_data -= PPP_HEADER_LEN;
8b3438a6
RG
647
648 cp = mtod(m0, u_char *);
2875cbc6
RG
649 *cp++ = address;
650 *cp++ = control;
651 *cp++ = protocol >> 8;
8b3438a6 652 *cp++ = protocol & 0xff;
2875cbc6 653 m0->m_len += PPP_HEADER_LEN;
8b3438a6
RG
654
655 if (ppp_async_out_debug) {
656 printf("ppp%d output: ", ifp->if_unit);
657 pppdumpm(m0, -1);
658 }
659
2875cbc6
RG
660#if NBPFILTER > 0
661 /* See if bpf wants to look at the packet. */
662 if (sc->sc_bpf)
663 bpf_mtap(sc->sc_bpf, m0);
664#endif
665
666 /*
667 * Put the packet on the appropriate queue.
668 */
8b3438a6 669 s = splimp();
2875cbc6
RG
670 if (IF_QFULL(ifq)) {
671 IF_DROP(ifq);
8b3438a6
RG
672 splx(s);
673 sc->sc_if.if_oerrors++;
674 error = ENOBUFS;
675 goto bad;
676 }
2875cbc6 677 IF_ENQUEUE(ifq, m0);
88b38551
RG
678 /*
679 * The next statement used to be subject to:
680 * if (CCOUNT(&sc->sc_ttyp->t_outq) == 0)
681 * which was removed so that we don't hang up completely
682 * if the serial transmitter loses an interrupt.
683 */
684 pppstart(sc->sc_ttyp);
8b3438a6
RG
685 splx(s);
686 return (0);
687
688bad:
689 m_freem(m0);
690 return (error);
691}
692
693/*
694 * Start output on interface. Get another datagram
695 * to send from the interface queue and map it to
696 * the interface before starting output.
697 */
698void
699pppstart(tp)
700 register struct tty *tp;
701{
702 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
703 register struct mbuf *m;
704 register int len;
705 register u_char *start, *stop, *cp;
2875cbc6 706 int n, s, ndone, done;
8b3438a6 707 struct mbuf *m2;
2875cbc6
RG
708 int address, control, protocol;
709 int compac, compprot, nb;
8b3438a6
RG
710
711 for (;;) {
712 /*
713 * If there is more in the output queue, just send it now.
714 * We are being called in lieu of ttstart and must do what
715 * it would.
716 */
717 if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) {
718 (*tp->t_oproc)(tp);
719 if (CCOUNT(&tp->t_outq) > PPP_HIWAT)
720 return;
721 }
722 /*
723 * This happens briefly when the line shuts down.
724 */
725 if (sc == NULL)
726 return;
727
728 /*
729 * See if we have an existing packet partly sent.
730 * If not, get a new packet and start sending it.
2875cbc6
RG
731 * We take packets on the priority queue ahead of those
732 * on the normal queue.
8b3438a6
RG
733 */
734 m = sc->sc_outm;
735 if (m == NULL) {
736 s = splimp();
2875cbc6
RG
737 IF_DEQUEUE(&sc->sc_fastq, m);
738 if (m == NULL)
739 IF_DEQUEUE(&sc->sc_if.if_snd, m);
8b3438a6
RG
740 splx(s);
741 if (m == NULL)
742 return;
743
2875cbc6
RG
744 /*
745 * Extract the ppp header of the new packet.
746 * The ppp header will be in one mbuf.
747 */
748 cp = mtod(m, u_char *);
749 address = *cp++;
750 control = *cp++;
751 protocol = *cp++;
752 protocol = (protocol << 8) + *cp++;
753 m->m_data += PPP_HEADER_LEN;
754 m->m_len -= PPP_HEADER_LEN;
755
756#ifdef VJC
757 /*
758 * If the packet is a TCP/IP packet, see if we can compress it.
759 */
760 if (protocol == PPP_IP && sc->sc_flags & SC_COMP_TCP) {
761 struct ip *ip;
762 int type;
763 struct mbuf *mp;
764
765 mp = m;
766 if (mp->m_len <= 0) {
767 mp = mp->m_next;
768 cp = mtod(mp, u_char *);
769 }
770 ip = (struct ip *) cp;
771 if (ip->ip_p == IPPROTO_TCP) {
772 type = sl_compress_tcp(mp, ip, &sc->sc_comp,
773 !(sc->sc_flags & SC_NO_TCP_CCID));
774 switch (type) {
775 case TYPE_UNCOMPRESSED_TCP:
776 protocol = PPP_VJC_UNCOMP;
777 break;
778 case TYPE_COMPRESSED_TCP:
779 protocol = PPP_VJC_COMP;
780 break;
781 }
782 }
783 }
784#endif
785
786 /*
787 * Compress the address/control and protocol, if possible.
788 */
789 compac = sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
790 control == PPP_UI && protocol != PPP_ALLSTATIONS &&
791 protocol != PPP_LCP;
792 compprot = sc->sc_flags & SC_COMP_PROT && protocol < 0x100;
793 nb = (compac ? 0 : 2) + (compprot ? 1 : 2);
794 m->m_data -= nb;
795 m->m_len += nb;
796
797 cp = mtod(m, u_char *);
798 if (!compac) {
799 *cp++ = address;
800 *cp++ = control;
801 }
802 if (!compprot)
803 *cp++ = protocol >> 8;
804 *cp++ = protocol;
805
8b3438a6
RG
806 /*
807 * The extra PPP_FLAG will start up a new packet, and thus
808 * will flush any accumulated garbage. We do this whenever
809 * the line may have been idle for some time.
810 */
811 if (CCOUNT(&tp->t_outq) == 0) {
812 ++sc->sc_bytessent;
813 (void) putc(PPP_FLAG, &tp->t_outq);
814 }
2875cbc6
RG
815
816 /* Calculate the FCS for the first mbuf's worth. */
817 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
8b3438a6
RG
818 }
819
2875cbc6 820 for (;;) {
8b3438a6
RG
821 start = mtod(m, u_char *);
822 len = m->m_len;
823 stop = start + len;
824 while (len > 0) {
825 /*
826 * Find out how many bytes in the string we can
827 * handle without doing something special.
828 */
829 for (cp = start; cp < stop; cp++)
2875cbc6 830 if (ESCAPE_P(*cp))
8b3438a6
RG
831 break;
832 n = cp - start;
833 if (n) {
834#ifndef RB_LEN
835 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
836 ndone = n - b_to_q(start, n, &tp->t_outq);
837#else
838#ifdef NetBSD
88b38551 839 /* NetBSD with 2-byte ring buffer entries */
8b3438a6
RG
840 ndone = rb_cwrite(&tp->t_out, start, n);
841#else
88b38551 842 /* 386BSD, FreeBSD */
8b3438a6
RG
843 int cc, nleft;
844 for (nleft = n; nleft > 0; nleft -= cc) {
845 if ((cc = RB_CONTIGPUT(&tp->t_out)) == 0)
846 break;
847 cc = min (cc, nleft);
88b38551 848 bcopy((char *)start + n - nleft, tp->t_out.rb_tl, cc);
8b3438a6
RG
849 tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
850 tp->t_out.rb_tl + cc);
851 }
852 ndone = n - nleft;
853#endif /* NetBSD */
854#endif /* RB_LEN */
855 len -= ndone;
856 start += ndone;
857 sc->sc_bytessent += ndone;
858
859 if (ndone < n)
860 break; /* packet doesn't fit */
861 }
862 /*
863 * If there are characters left in the mbuf,
864 * the first one must be special..
865 * Put it out in a different form.
866 */
867 if (len) {
868 if (putc(PPP_ESCAPE, &tp->t_outq))
869 break;
870 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
871 (void) unputc(&tp->t_outq);
872 break;
873 }
874 sc->sc_bytessent += 2;
875 start++;
876 len--;
877 }
878 }
879 /*
880 * If we didn't empty this mbuf, remember where we're up to.
2875cbc6
RG
881 * If we emptied the last mbuf, try to add the FCS and closing
882 * flag, and if we can't, leave sc_outm pointing to m, but with
883 * m->m_len == 0, to remind us to output the FCS and flag later.
8b3438a6 884 */
2875cbc6
RG
885 done = len == 0;
886 if (done && m->m_next == NULL) {
887 u_char *p, *q;
888 int c;
889 u_char endseq[8];
890
891 /*
892 * We may have to escape the bytes in the FCS.
893 */
894 p = endseq;
895 c = ~sc->sc_outfcs & 0xFF;
896 if (ESCAPE_P(c)) {
897 *p++ = PPP_ESCAPE;
898 *p++ = c ^ PPP_TRANS;
899 } else
900 *p++ = c;
901 c = (~sc->sc_outfcs >> 8) & 0xFF;
902 if (ESCAPE_P(c)) {
903 *p++ = PPP_ESCAPE;
904 *p++ = c ^ PPP_TRANS;
905 } else
906 *p++ = c;
907 *p++ = PPP_FLAG;
908
909 /*
910 * Try to output the FCS and flag. If the bytes
911 * don't all fit, back out.
912 */
913 for (q = endseq; q < p; ++q)
914 if (putc(*q, &tp->t_outq)) {
915 done = 0;
916 for (; q > endseq; --q)
917 unputc(&tp->t_outq);
918 break;
919 }
920 }
921
922 if (!done) {
8b3438a6
RG
923 m->m_data = start;
924 m->m_len = len;
925 sc->sc_outm = m;
926 if (tp->t_oproc != NULL)
927 (*tp->t_oproc)(tp);
928 return; /* can't do any more at the moment */
929 }
930
931 /* Finished with this mbuf; free it and move on. */
932 MFREE(m, m2);
2875cbc6
RG
933 if (m2 == NULL)
934 break;
935
8b3438a6 936 m = m2;
2875cbc6
RG
937 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
938 }
8b3438a6
RG
939
940 /* Finished a packet */
941 sc->sc_outm = NULL;
942 sc->sc_bytessent++; /* account for closing flag */
943 sc->sc_if.if_opackets++;
944 sc->sc_if.if_obytes = sc->sc_bytessent;
945 }
946}
947
948/*
2875cbc6 949 * Allocate enough mbuf to handle current MRU.
8b3438a6
RG
950 */
951static int
952pppinit(sc)
953 register struct ppp_softc *sc;
954{
955 struct mbuf *m, **mp;
2875cbc6 956 int len = HDROFF + sc->sc_mru + PPP_HEADER_LEN + PPP_FCS_LEN;
8b3438a6
RG
957 int s;
958
959 s = splimp();
960 for (mp = &sc->sc_m; (m = *mp) != NULL; mp = &m->m_next)
961 if ((len -= M_DATASIZE(m)) <= 0) {
962 splx(s);
963 return (1);
964 }
965
966 for (;; mp = &m->m_next) {
967 MGETHDR(m, M_DONTWAIT, MT_DATA);
968 if (m == 0) {
969 m_freem(sc->sc_m);
970 sc->sc_m = NULL;
971 splx(s);
2875cbc6 972 printf("ppp%d: can't allocate mbuf\n", sc->sc_if.if_unit);
8b3438a6
RG
973 return (0);
974 }
975 *mp = m;
976 MCLGET(m, M_DONTWAIT);
977 if ((len -= M_DATASIZE(m)) <= 0) {
978 splx(s);
979 return (1);
980 }
981 }
982}
983
984/*
985 * Copy mbuf chain. Would like to use m_copy(), but we need a real copy
986 * of the data, not just copies of pointers to the data.
987 */
988static struct mbuf *
989ppp_btom(sc)
990 struct ppp_softc *sc;
991{
992 register struct mbuf *m, **mp;
993 struct mbuf *top = sc->sc_m;
994
995 /*
996 * First check current mbuf. If we have more than a small mbuf,
997 * return the whole cluster and set beginning of buffer to the
998 * next mbuf.
999 * Else, copy the current bytes into a small mbuf, attach the new
1000 * mbuf to the end of the chain and set beginning of buffer to the
1001 * current mbuf.
1002 */
1003
1004 if (sc->sc_mc->m_len > MHLEN) {
1005 sc->sc_m = sc->sc_mc->m_next;
1006 sc->sc_mc->m_next = NULL;
1007 }
1008 else {
1009 /* rather than waste a whole cluster on <= MHLEN bytes,
1010 alloc a small mbuf and copy to it */
1011 MGETHDR(m, M_DONTWAIT, MT_DATA);
1012 if (m == NULL)
1013 return (NULL);
1014
2875cbc6 1015 bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t), sc->sc_mc->m_len);
8b3438a6
RG
1016 m->m_len = sc->sc_mc->m_len;
1017 for (mp = &top; *mp != sc->sc_mc; mp = &(*mp)->m_next)
1018 ;
1019 *mp = m;
1020 sc->sc_m = sc->sc_mc;
1021 }
1022
1023 /*
1024 * Try to allocate enough extra mbufs to handle the next packet.
1025 */
1026 if (pppinit(sc) == 0) {
1027 m_freem(top);
1028 if (pppinit(sc) == 0)
1029 sc->sc_if.if_flags &= ~IFF_UP;
1030 return (NULL);
1031 }
1032
1033 return (top);
1034}
1035
1036/*
1037 * tty interface receiver interrupt.
1038 */
1039#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1040 TYPE_UNCOMPRESSED_TCP)
1041
1042void
1043pppinput(c, tp)
1044 int c;
1045 register struct tty *tp;
1046{
1047 register struct ppp_softc *sc;
1048 struct mbuf *m;
1049 struct ifqueue *inq;
1050 int s, ilen, xlen, proto;
c0ace2fe 1051 struct ppp_header hdr;
8b3438a6
RG
1052
1053 tk_nin++;
1054 sc = (struct ppp_softc *)tp->t_sc;
1055 if (sc == NULL)
1056 return;
1057
1058 ++sc->sc_if.if_ibytes;
1059
2875cbc6 1060 if (c & TTY_FE) {
8b3438a6 1061 /* framing error or overrun on this char - abort packet */
2875cbc6
RG
1062 if (ppp_debug)
1063 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
8b3438a6 1064 goto flush;
2875cbc6 1065 }
8b3438a6
RG
1066
1067 c &= 0xff;
2875cbc6
RG
1068
1069 if (sc->sc_if.if_unit == ppp_raw_in_debug) {
1070 ppp_rawin[ppp_rawin_count++] = c;
1071 if (ppp_rawin_count >= sizeof(ppp_rawin)) {
1072 printf("raw ppp%d: ", ppp_raw_in_debug);
1073 pppdumpb(ppp_rawin, ppp_rawin_count);
1074 ppp_rawin_count = 0;
1075 }
1076 }
1077
8b3438a6
RG
1078 if (c == PPP_FLAG) {
1079 ilen = sc->sc_ilen;
1080 sc->sc_ilen = 0;
1081
1082 if (sc->sc_flags & SC_FLUSH
1083 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
1084#ifdef VJC
1085 /*
1086 * If we've missed a packet, we must toss subsequent compressed
1087 * packets which don't have an explicit connection ID.
1088 */
1089 sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp);
1090#endif
1091 if ((sc->sc_flags & SC_FLUSH) == 0){
1092 if (ppp_debug)
2875cbc6 1093 printf("ppp%d: bad fcs\n", sc->sc_if.if_unit);
8b3438a6
RG
1094 sc->sc_if.if_ierrors++;
1095 } else
1096 sc->sc_flags &= ~SC_FLUSH;
1097 return;
1098 }
1099
2875cbc6 1100 if (ilen < PPP_HEADER_LEN + PPP_FCS_LEN) {
8b3438a6
RG
1101 if (ilen) {
1102 if (ppp_debug)
2875cbc6 1103 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
8b3438a6
RG
1104 sc->sc_if.if_ierrors++;
1105 }
1106 return;
1107 }
1108
1109 /*
1110 * Remove FCS trailer. Somewhat painful...
1111 */
1112 ilen -= 2;
1113 if (--sc->sc_mc->m_len == 0) {
1114 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1115 ;
1116 sc->sc_mc = m;
1117 }
1118 sc->sc_mc->m_len--;
1119
1120 sc->sc_if.if_ipackets++;
1121 m = sc->sc_m;
1122
1123 if (ppp_async_in_debug) {
2875cbc6 1124 printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen);
8b3438a6
RG
1125 pppdumpm(m, ilen);
1126 }
1127
c0ace2fe
RG
1128 hdr = *mtod(m, struct ppp_header *);
1129 proto = ntohs(hdr.ph_protocol);
8b3438a6
RG
1130
1131#ifdef VJC
c0ace2fe
RG
1132 /*
1133 * See if we have a VJ-compressed packet to uncompress.
1134 */
1135 if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
1136 char *pkttype = proto == PPP_VJC_COMP? "": "un";
8b3438a6 1137
c0ace2fe 1138 if (sc->sc_flags & SC_REJ_COMP_TCP) {
8b3438a6
RG
1139 if (ppp_debug)
1140 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n",
1141 sc->sc_if.if_unit, pkttype, sc->sc_flags);
c0ace2fe
RG
1142 sc->sc_if.if_ierrors++;
1143 return;
8b3438a6 1144 }
c0ace2fe
RG
1145
1146 m->m_data += PPP_HEADER_LEN;
1147 m->m_len -= PPP_HEADER_LEN;
1148 ilen -= PPP_HEADER_LEN;
1149 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data),
1150 m->m_len, ilen,
1151 COMPTYPE(proto), &sc->sc_comp);
1152
1153 if (xlen == 0) {
1154 if (ppp_debug)
1155 printf("ppp%d: sl_uncompress failed on type %scomp\n",
1156 sc->sc_if.if_unit, pkttype);
1157 sc->sc_if.if_ierrors++;
1158 return;
1159 }
1160
1161 /* adjust the first mbuf by the decompressed amt */
1162 xlen += PPP_HEADER_LEN;
1163 m->m_len += xlen - ilen;
1164 ilen = xlen;
1165 m->m_data -= PPP_HEADER_LEN;
1166 proto = PPP_IP;
1167
1168#if NBPFILTER > 0
1169 /* put the ppp header back in place */
1170 hdr.ph_protocol = htons(PPP_IP);
1171 *mtod(m, struct ppp_header *) = hdr;
1172#endif /* NBPFILTER */
8b3438a6 1173 }
c0ace2fe 1174#endif /* VJC */
8b3438a6
RG
1175
1176 /* get this packet as an mbuf chain */
1177 if ((m = ppp_btom(sc)) == NULL) {
1178 sc->sc_if.if_ierrors++;
1179 return;
1180 }
1181 m->m_pkthdr.len = ilen;
1182 m->m_pkthdr.rcvif = &sc->sc_if;
1183
c0ace2fe
RG
1184#if NBPFILTER > 0
1185 /* See if bpf wants to look at the packet. */
1186 if (sc->sc_bpf)
1187 bpf_mtap(sc->sc_bpf, m);
1188#endif
1189
1190 switch (proto) {
1191#ifdef INET
1192 case PPP_IP:
1193 /*
1194 * IP packet - take off the ppp header and pass it up to IP.
1195 */
8b3438a6
RG
1196 if ((sc->sc_if.if_flags & IFF_UP) == 0) {
1197 /* interface is down - drop the packet. */
1198 m_freem(m);
1199 sc->sc_if.if_ierrors++;
1200 return;
1201 }
c0ace2fe
RG
1202 m->m_pkthdr.len -= PPP_HEADER_LEN;
1203 m->m_data += PPP_HEADER_LEN;
1204 m->m_len -= PPP_HEADER_LEN;
8b3438a6
RG
1205 schednetisr(NETISR_IP);
1206 inq = &ipintrq;
c0ace2fe
RG
1207 break;
1208#endif
8b3438a6 1209
c0ace2fe
RG
1210 default:
1211 /*
1212 * Some other protocol - place on input queue for read().
1213 * Put a placeholder byte in canq for ttselect()/ttnread().
1214 */
8b3438a6
RG
1215 putc(0, &tp->t_canq);
1216 ttwakeup(tp);
1217 inq = &sc->sc_inq;
c0ace2fe 1218 break;
8b3438a6
RG
1219 }
1220
c0ace2fe
RG
1221 /*
1222 * Put the packet on the appropriate input queue.
1223 */
8b3438a6
RG
1224 s = splimp();
1225 if (IF_QFULL(inq)) {
1226 IF_DROP(inq);
1227 if (ppp_debug)
2875cbc6 1228 printf("ppp%d: queue full\n", sc->sc_if.if_unit);
8b3438a6
RG
1229 sc->sc_if.if_ierrors++;
1230 sc->sc_if.if_iqdrops++;
1231 m_freem(m);
1232 } else
1233 IF_ENQUEUE(inq, m);
1234
1235 splx(s);
1236 return;
1237 }
2875cbc6 1238
8b3438a6
RG
1239 if (sc->sc_flags & SC_FLUSH)
1240 return;
1241 if (c == PPP_ESCAPE) {
1242 sc->sc_flags |= SC_ESCAPED;
1243 return;
1244 }
2875cbc6
RG
1245 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1246 return;
8b3438a6
RG
1247
1248 if (sc->sc_flags & SC_ESCAPED) {
1249 sc->sc_flags &= ~SC_ESCAPED;
1250 c ^= PPP_TRANS;
1251 }
1252
1253 /*
1254 * Initialize buffer on first octet received.
1255 * First octet could be address or protocol (when compressing
1256 * address/control).
1257 * Second octet is control.
1258 * Third octet is first or second (when compressing protocol)
1259 * octet of protocol.
1260 * Fourth octet is second octet of protocol.
1261 */
1262 if (sc->sc_ilen == 0) {
1263 /* reset the first input mbuf */
1264 m = sc->sc_m;
1265 m->m_len = 0;
1266 m->m_data = M_DATASTART(sc->sc_m) + HDROFF;
1267 sc->sc_mc = m;
1268 sc->sc_mp = mtod(m, char *);
1269 sc->sc_fcs = PPP_INITFCS;
1270 if (c != PPP_ALLSTATIONS) {
2875cbc6 1271 if (sc->sc_flags & SC_REJ_COMP_AC) {
8b3438a6 1272 if (ppp_debug)
2875cbc6
RG
1273 printf("ppp%d: missing ALLSTATIONS, got 0x%x; flags %x\n",
1274 sc->sc_if.if_unit, c, sc->sc_flags);
8b3438a6
RG
1275 goto flush;
1276 }
1277 *sc->sc_mp++ = PPP_ALLSTATIONS;
1278 *sc->sc_mp++ = PPP_UI;
1279 sc->sc_ilen += 2;
1280 m->m_len += 2;
1281 }
1282 }
1283 if (sc->sc_ilen == 1 && c != PPP_UI) {
1284 if (ppp_debug)
2875cbc6 1285 printf("ppp%d: missing UI, got 0x%x\n", sc->sc_if.if_unit, c);
8b3438a6
RG
1286 goto flush;
1287 }
1288 if (sc->sc_ilen == 2 && (c & 1) == 1) {
2875cbc6 1289 /* RFC1331 says we have to accept a compressed protocol */
8b3438a6
RG
1290 *sc->sc_mp++ = 0;
1291 sc->sc_ilen++;
1292 sc->sc_mc->m_len++;
1293 }
1294 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1295 if (ppp_debug)
2875cbc6
RG
1296 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1297 (sc->sc_mp[-1] << 8) + c);
8b3438a6
RG
1298 goto flush;
1299 }
1300
2875cbc6
RG
1301 /* packet beyond configured mru? */
1302 if (++sc->sc_ilen > sc->sc_mru + PPP_HEADER_LEN + PPP_FCS_LEN) {
8b3438a6 1303 if (ppp_debug)
2875cbc6 1304 printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
8b3438a6
RG
1305 goto flush;
1306 }
1307
1308 /* is this mbuf full? */
1309 m = sc->sc_mc;
1310 if (M_TRAILINGSPACE(m) <= 0) {
1311 sc->sc_mc = m = m->m_next;
1312 if (m == NULL) {
2875cbc6 1313 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
8b3438a6
RG
1314 goto flush;
1315 }
1316 m->m_len = 0;
1317 m->m_data = M_DATASTART(m);
1318 sc->sc_mp = mtod(m, char *);
1319 }
1320
1321 ++m->m_len;
1322 *sc->sc_mp++ = c;
1323 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1324 return;
1325
1326 flush:
1327 sc->sc_if.if_ierrors++;
1328 sc->sc_flags |= SC_FLUSH;
1329}
1330
1331/*
1332 * Process an ioctl request to interface.
1333 */
4c45483e 1334int
8b3438a6
RG
1335pppioctl(ifp, cmd, data)
1336 register struct ifnet *ifp;
1337 int cmd;
1338 caddr_t data;
1339{
1340 struct proc *p = curproc; /* XXX */
1341 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
1342 register struct ifaddr *ifa = (struct ifaddr *)data;
1343 register struct ifreq *ifr = (struct ifreq *)data;
1344 int s = splimp(), error = 0;
1345
1346
1347 switch (cmd) {
1348 case SIOCSIFFLAGS:
1349 if ((ifp->if_flags & IFF_RUNNING) == 0)
1350 ifp->if_flags &= ~IFF_UP;
1351 break;
1352
1353 case SIOCSIFADDR:
1354 if (ifa->ifa_addr->sa_family != AF_INET)
1355 error = EAFNOSUPPORT;
1356 break;
1357
1358 case SIOCSIFDSTADDR:
1359 if (ifa->ifa_addr->sa_family != AF_INET)
1360 error = EAFNOSUPPORT;
1361 break;
1362
1363 case SIOCSIFMTU:
1364 if (error = suser(p->p_ucred, &p->p_acflag))
1365 return (error);
1366 sc->sc_if.if_mtu = ifr->ifr_mtu;
8b3438a6
RG
1367 break;
1368
1369 case SIOCGIFMTU:
1370 ifr->ifr_mtu = sc->sc_if.if_mtu;
1371 break;
1372
1373 default:
1374 error = EINVAL;
1375 }
1376 splx(s);
1377 return (error);
1378}
1379
1380#define MAX_DUMP_BYTES 128
1381
1382static void
1383pppdumpm(m0, pktlen)
1384 struct mbuf *m0;
1385 int pktlen;
1386{
1387 char buf[2*MAX_DUMP_BYTES+4];
1388 char *bp = buf;
1389 struct mbuf *m;
1390 static char digits[] = "0123456789abcdef";
1391
1392 for (m = m0; m && pktlen; m = m->m_next) {
1393 int l = m->m_len;
1394 u_char *rptr = (u_char *)m->m_data;
1395
1396 if (pktlen > 0) {
1397 l = min(l, pktlen);
1398 pktlen -= l;
1399 }
1400 while (l--) {
1401 if (bp > buf + sizeof(buf) - 4)
1402 goto done;
1403 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1404 *bp++ = digits[*rptr++ & 0xf];
1405 }
1406
1407 if (m->m_next) {
1408 if (bp > buf + sizeof(buf) - 3)
1409 goto done;
1410 *bp++ = '|';
1411 }
1412 }
1413done:
1414 if (m && pktlen)
1415 *bp++ = '>';
1416 *bp = 0;
1417 printf("%s\n", buf);
1418}
1419
1420static void
1421pppdumpb(b, l)
1422 u_char *b;
1423 int l;
1424{
1425 char buf[2*MAX_DUMP_BYTES+4];
1426 char *bp = buf;
1427 static char digits[] = "0123456789abcdef";
1428
1429 while (l--) {
1430 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1431 *bp++ = digits[*b++ & 0xf];
1432 if (bp >= buf + sizeof(buf) - 2) {
1433 *bp++ = '>';
1434 break;
1435 }
1436 }
1437
1438 *bp = 0;
1439 printf("%s\n", buf);
1440}
1441
1442
1443#endif /* NPPP > 0 */