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