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