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