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