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