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