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