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