source: rtems/c/src/exec/libnetworking/net/if_ppp.c @ cb1e8a46

4.104.114.84.95
Last change on this file since cb1e8a46 was cb1e8a46, checked in by Joel Sherrill <joel.sherrill@…>, on 02/27/02 at 22:43:31

2002-02-27 Ilya Alexeev <ilya@…>

  • net/if_ppp.c, pppd/auth.c, pppd/chat.c, pppd/pppd.h, pppd/sys-rtems.c: Add server with pap-authorization capabilities as well as eliminate some warnings.
  • Property mode set to 100644
File size: 42.7 KB
Line 
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.
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).
70 */
71
72/* $Id$ */
73/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
74/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
75
76#include "ppp.h"
77#if NPPP > 0
78
79#include <termios.h>
80#include <rtems/termiostypes.h>
81#include <rtems/rtems_bsdnet.h>
82#include <sys/param.h>
83#include <sys/systm.h>
84#include <sys/proc.h>
85#include <sys/mbuf.h>
86#include <sys/socket.h>
87#include <sys/ioctl.h>
88#include <sys/kernel.h>
89#include <sys/time.h>
90#include <sys/malloc.h>
91
92#include <net/if.h>
93#include <net/if_types.h>
94#include <net/netisr.h>
95#include <net/route.h>
96#ifdef PPP_FILTER
97#include <net/bpf.h>
98#endif
99
100#if INET
101#include <netinet/in.h>
102#include <netinet/in_systm.h>
103#include <netinet/in_var.h>
104#include <netinet/ip.h>
105#endif
106
107#include "bpfilter.h"
108#if NBPFILTER > 0
109#include <net/bpf.h>
110#endif
111
112#ifdef VJC
113#include <net/pppcompress.h>
114#endif
115
116#include <net/ppp_defs.h>
117#include <net/if_ppp.h>
118#include <net/if_pppvar.h>
119#include <machine/cpu.h>
120
121#define splsoftnet      splnet
122
123#ifdef PPP_COMPRESS
124#define PACKETPTR       struct mbuf *
125#include <net/ppp-comp.h>
126#endif
127
128static int      pppsioctl __P((struct ifnet *, int, caddr_t));
129static void     ppp_requeue __P((struct ppp_softc *));
130#ifdef PPP_COMPRESS
131static void     ppp_ccp __P((struct ppp_softc *, struct mbuf *m, int rcvd));
132static void     ppp_ccp_closed __P((struct ppp_softc *));
133#endif
134static struct mbuf *ppp_inproc __P((struct ppp_softc *, struct mbuf *));
135static void     pppdumpm __P((struct mbuf *m0));
136
137/*
138 * Some useful mbuf macros not in mbuf.h.
139 */
140#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
141
142#define M_DATASTART(m)  \
143        (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
144            (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
145
146#define M_DATASIZE(m)   \
147        (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
148            (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
149
150/*
151 * We steal two bits in the mbuf m_flags, to mark high-priority packets
152 * for output, and received packets following lost/corrupted packets.
153 */
154#define M_HIGHPRI       0x2000  /* output packet for sc_fastq */
155#define M_ERRMARK       0x4000  /* steal a bit in mbuf m_flags */
156
157
158#ifdef PPP_COMPRESS
159/*
160 * List of compressors we know about.
161 * We leave some space so maybe we can modload compressors.
162 */
163
164extern struct compressor ppp_bsd_compress;
165extern struct compressor ppp_deflate, ppp_deflate_draft;
166
167struct compressor *ppp_compressors[8] = {
168#if DO_BSD_COMPRESS
169    &ppp_bsd_compress,
170#endif
171#if DO_DEFLATE
172    &ppp_deflate,
173    &ppp_deflate_draft,
174#endif
175    NULL
176};
177#endif /* PPP_COMPRESS */
178
179extern struct ifqueue    ipintrq;
180static struct timeval    ppp_time;
181
182TEXT_SET(pseudo_set, ppp_rxdaemon);
183
184
185static rtems_task ppp_rxdaemon(rtems_task_argument arg)
186{
187  rtems_event_set             events;
188  rtems_interrupt_level       level;
189  struct ppp_softc           *sc = (struct ppp_softc *)arg;
190  struct mbuf                *mp = (struct mbuf      *)0;
191  struct mbuf                *m;
192
193  /* enter processing loop */
194  while ( 1 ) {
195    /* wait for event */
196    rtems_event_receive(RX_PACKET|RX_MBUF|RX_EMPTY,RTEMS_WAIT|RTEMS_EVENT_ANY,RTEMS_NO_TIMEOUT,&events);
197    if ( events & RX_EMPTY ) {
198      printf("RX: QUEUE is EMPTY\n");
199      events &= ~RX_EMPTY;
200    }
201
202    if ( events ) {
203      /* get the network semaphore */
204      rtems_bsdnet_semaphore_obtain();
205
206      /* check to see if new packet was received */
207      if ( events & RX_PACKET ) {
208        /* get received packet mbuf chain */
209        rtems_interrupt_disable(level);
210        IF_DEQUEUE(&sc->sc_rawq, m);
211        rtems_interrupt_enable(level);
212
213        /* ensure packet was retrieved */
214        if ( m != (struct mbuf *)0 ) {
215          /* process the received packet */
216          mp = ppp_inproc(sc, m);
217        }
218      }
219
220      /* allocate a new mbuf to replace one */
221      if ( mp == NULL ) {
222        pppallocmbuf(sc, &mp);
223      }
224
225      /* place mbuf on freeq */
226      rtems_interrupt_disable(level);
227      IF_ENQUEUE(&sc->sc_freeq, mp);
228      rtems_interrupt_enable(level);
229      mp = (struct mbuf *)0;
230
231      /* release the network semaphore */
232      rtems_bsdnet_semaphore_release();
233
234      /* check to see if queue is empty */
235      if ( sc->sc_rawq.ifq_head ) {
236        /* queue is not empty - post another event */
237        rtems_event_send(sc->sc_rxtask, RX_PACKET);
238      }
239    }
240  }
241}
242
243static rtems_task ppp_txdaemon(rtems_task_argument arg)
244{
245  rtems_event_set             events;
246  char                        cFrame   = (char              )PPP_FLAG;
247  int                         iprocess = (int               )0;
248  struct ppp_softc           *sc       = (struct ppp_softc *)arg;
249  struct mbuf                *mp;
250  struct mbuf                *mf;
251  struct mbuf                *m;
252  struct rtems_termios_tty   *tp;
253
254  /* enter processing loop */
255  while ( 1 ) {
256    /* wait for event */
257    rtems_event_receive(TX_PACKET|TX_TRANSMIT,RTEMS_WAIT|RTEMS_EVENT_ANY,RTEMS_NO_TIMEOUT,&events);
258    if ( events & TX_TRANSMIT ) {
259      /* received event from interrupt handler - free current mbuf */
260      rtems_bsdnet_semaphore_obtain();
261      m_freem(sc->sc_outm);
262      rtems_bsdnet_semaphore_release();
263
264      /* chain is done - clear the values */
265      sc->sc_outm  = (struct mbuf *)0;
266      sc->sc_outmc = (struct mbuf *)0;
267
268      /* now set flag to fake receive of TX_PACKET event */
269      /* this will check to see if we have any pending packets */
270      events |= TX_PACKET;
271    }
272
273    /* received event from pppasyncstart */
274    if ( events & TX_PACKET ) {
275      /* ensure we are not busy */
276      if ( sc->sc_outm == (struct mbuf *)0 ) {
277        /* try dequeuing a packet */
278        sc->sc_outm = ppp_dequeue(sc);
279        if ( sc->sc_outm == NULL ) {
280          /* clear output flags */
281          sc->sc_outflag      = 0;
282          sc->sc_if.if_flags &= ~IFF_OACTIVE;
283        }
284        else {
285          /* set flag to start process */
286          iprocess            = 1;
287          sc->sc_outflag      = SC_TX_BUSY;
288          sc->sc_if.if_flags |= IFF_OACTIVE;
289        }
290      }
291    }
292
293    /* check to see if there is any processing required */
294    if ( iprocess ) {
295      /* clear process flag */
296      iprocess = (int)0;
297
298      /* initialize output values */
299      sc->sc_outfcs    = PPP_INITFCS;
300      sc->sc_outbuf    = (u_char *)0;
301      sc->sc_outlen    = (short   )0;
302      sc->sc_outoff    = (short   )0;
303      sc->sc_outfcslen = (short   )0;
304
305      /* loop over all mbufs in chain */
306      mf     = NULL;
307      mp     = NULL;
308      m      = sc->sc_outm;
309      while (( m != (struct mbuf *)0 ) && ( m->m_len > 0 )) {
310        /* check to see if first mbuf value has been set */
311        if ( sc->sc_outmc == (struct mbuf *)0 ) {
312          /* set values to start with this mbuf */
313          sc->sc_outmc  = m;
314          sc->sc_outlen = m->m_len;
315          sc->sc_outbuf = mtod(m, u_char *);
316        }
317
318        /* update the FCS value and then check next packet length */
319        sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
320
321        /* check next packet to see if it is empty */
322        while (( m->m_next != NULL ) && ( m->m_next->m_len == 0 )) {
323          /* next mbuf is zero length */
324          /* add empty mbuf to free chain */
325          if ( mp == NULL ) {
326            /* item is head of free list */
327            mf = m->m_next;
328            mp = mf;
329          }
330          else {
331            /* add item to end of the free list */
332            mp->m_next = m->m_next;
333            mp         = m->m_next;
334          }
335
336          /* remove empty item from process chain */
337          m->m_next  = m->m_next->m_next;
338          mp->m_next = NULL;
339        }
340
341        /* move to next packet */
342        m = m->m_next;
343      }
344
345      /* ensure there is data to be sent out */
346      tp = (struct rtems_termios_tty *)sc->sc_devp;
347      if (( tp != NULL ) && ( sc->sc_outmc != (struct mbuf *)0 )) {
348        /* place FCS value into buffer */
349        sc->sc_outfcsbuf[sc->sc_outfcslen++] = ~sc->sc_outfcs & 0xff;
350        sc->sc_outfcsbuf[sc->sc_outfcslen++] = (~sc->sc_outfcs >> 8) & 0xff;
351        microtime(&sc->sc_if.if_lastchange);
352 
353        /* write out frame byte to start the transmission */
354        (*tp->device.write)(tp->minor, &cFrame, 1);
355      }
356
357      /* check to see if we need to free some empty mbufs */
358      if ( mf != (struct mbuf *)0 ) {
359        /* free empty mbufs */
360        rtems_bsdnet_semaphore_obtain();
361        m_freem(mf);
362        rtems_bsdnet_semaphore_release();
363      }
364    }
365  }
366}
367
368static void ppp_init(struct ppp_softc *sc)
369{
370  rtems_status_code   status;
371  rtems_unsigned32    priority = 100;
372
373  /* determine priority value */
374  if ( rtems_bsdnet_config.network_task_priority ) {
375    priority = rtems_bsdnet_config.network_task_priority;
376  }
377
378  /* check to see if we need to start up daemons */
379  if ( sc->sc_rxtask == 0 ) {
380    /* start rx daemon task */
381    status = rtems_task_create(rtems_build_name('R','x','P','0'), priority, 2048,
382                               RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
383                               RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
384                               &sc->sc_rxtask);
385    if (status != RTEMS_SUCCESSFUL) {
386      rtems_fatal_error_occurred(status);
387    }
388    else {
389      status = rtems_task_start(sc->sc_rxtask, ppp_rxdaemon, (rtems_task_argument)sc);
390      if (status != RTEMS_SUCCESSFUL) {
391        rtems_fatal_error_occurred(status);
392      }
393    }
394
395    /* start tx daemon task */
396    status = rtems_task_create(rtems_build_name('T','x','P','0'), priority, 2048,
397                               RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
398                               RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
399                               &sc->sc_txtask);
400    if (status != RTEMS_SUCCESSFUL) {
401      rtems_fatal_error_occurred(status);
402    }
403    else {
404      status = rtems_task_start(sc->sc_txtask, ppp_txdaemon, (rtems_task_argument)sc);
405      if (status != RTEMS_SUCCESSFUL) {
406        rtems_fatal_error_occurred(status);
407      }
408    }
409  }
410
411  /* mark driver running and output inactive */
412  sc->sc_if.if_flags |= IFF_RUNNING;
413}
414
415/*
416 * Called from boot code to establish ppp interfaces.
417 */
418int rtems_ppp_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
419{
420    int                 i = (int)0;
421    struct ppp_softc   *sc;
422
423    for (sc = ppp_softc; i < NPPP; sc++) {
424        sc->sc_if.if_name = "ppp";
425        sc->sc_if.if_unit = i++;
426        sc->sc_if.if_mtu = PPP_MTU;
427        sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
428        sc->sc_if.if_type = IFT_PPP;
429        sc->sc_if.if_hdrlen = PPP_HDRLEN;
430        sc->sc_if.if_ioctl = pppsioctl;
431        sc->sc_if.if_output = pppoutput;
432        sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
433        sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
434        sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
435        sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN;
436        sc->sc_freeq.ifq_maxlen = NUM_MBUFQ;
437
438        /* initialize and attach */
439        ppp_init(sc);
440        if_attach(&sc->sc_if);
441#if NBPFILTER > 0
442        bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN);
443#endif
444    }
445
446    return ( 1 );
447}
448
449/*
450 * Allocate a ppp interface unit and initialize it.
451 */
452struct ppp_softc *
453pppalloc(pid)
454    pid_t pid;
455{
456    int nppp, i;
457    struct ppp_softc *sc;
458
459    for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
460        if (sc->sc_xfer == pid) {
461            sc->sc_xfer = 0;
462            return sc;
463        }
464    for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
465        if (sc->sc_devp == NULL)
466            break;
467    if (nppp >= NPPP)
468        return NULL;
469
470    sc->sc_flags = 0;
471    sc->sc_mru = PPP_MRU;
472    sc->sc_relinq = NULL;
473    bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats));
474#ifdef VJC
475    MALLOC(sc->sc_comp, struct vjcompress *, sizeof(struct vjcompress),
476           M_DEVBUF, M_NOWAIT);
477    if (sc->sc_comp)
478        vj_compress_init(sc->sc_comp, -1);
479#endif
480#ifdef PPP_COMPRESS
481    sc->sc_xc_state = NULL;
482    sc->sc_rc_state = NULL;
483#endif /* PPP_COMPRESS */
484    for (i = 0; i < NUM_NP; ++i)
485        sc->sc_npmode[i] = NPMODE_ERROR;
486    sc->sc_npqueue = NULL;
487    sc->sc_npqtail = &sc->sc_npqueue;
488    microtime(&ppp_time);
489    sc->sc_last_sent = sc->sc_last_recv = ppp_time.tv_sec;
490
491    return sc;
492}
493
494/*
495 * Deallocate a ppp unit.  Must be called at splsoftnet or higher.
496 */
497void
498pppdealloc(sc)
499    struct ppp_softc *sc;
500{
501    struct mbuf *m;
502    rtems_interrupt_level       level;
503
504    if_down(&sc->sc_if);
505    sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
506    sc->sc_devp = NULL;
507    sc->sc_xfer = 0;
508
509    rtems_interrupt_disable(level);
510    if ( sc->sc_m != NULL ) {
511        m_freem(sc->sc_m);
512        sc->sc_m = (struct mbuf *)0;
513    }
514    if ( sc->sc_outm != NULL ) {
515        m_freem(sc->sc_outm);
516        sc->sc_outm    = (struct mbuf *)0;
517        sc->sc_outmc   = (struct mbuf *)0;
518        sc->sc_outflag = 0;
519    }
520    do {
521      IF_DEQUEUE(&sc->sc_freeq, m);
522      if (m != NULL) {
523        m_freem(m);
524      }
525    } while ( m != NULL );
526    do {
527      IF_DEQUEUE(&sc->sc_rawq, m);
528      if (m != NULL) {
529        m_freem(m);
530      }
531    } while ( m != NULL );
532    rtems_interrupt_enable(level);
533
534    for (;;) {
535        IF_DEQUEUE(&sc->sc_inq, m);
536        if (m == NULL)
537            break;
538        m_freem(m);
539    }
540    for (;;) {
541        IF_DEQUEUE(&sc->sc_fastq, m);
542        if (m == NULL)
543            break;
544        m_freem(m);
545    }
546    while ((m = sc->sc_npqueue) != NULL) {
547        sc->sc_npqueue = m->m_nextpkt;
548        m_freem(m);
549    }
550#ifdef PPP_COMPRESS
551    ppp_ccp_closed(sc);
552    sc->sc_xc_state = NULL;
553    sc->sc_rc_state = NULL;
554#endif /* PPP_COMPRESS */
555#ifdef PPP_FILTER
556    if (sc->sc_pass_filt.bf_insns != 0) {
557        FREE(sc->sc_pass_filt.bf_insns, M_DEVBUF);
558        sc->sc_pass_filt.bf_insns = 0;
559        sc->sc_pass_filt.bf_len = 0;
560    }
561    if (sc->sc_active_filt.bf_insns != 0) {
562        FREE(sc->sc_active_filt.bf_insns, M_DEVBUF);
563        sc->sc_active_filt.bf_insns = 0;
564        sc->sc_active_filt.bf_len = 0;
565    }
566#endif /* PPP_FILTER */
567#ifdef VJC
568    if (sc->sc_comp != 0) {
569        FREE(sc->sc_comp, M_DEVBUF);
570        sc->sc_comp = 0;
571    }
572#endif
573}
574
575/*
576 * Ioctl routine for generic ppp devices.
577 */
578int
579pppioctl(sc, cmd, data, flag, p)
580    struct ppp_softc *sc;
581    int cmd;
582    caddr_t data;
583    int flag;
584    struct proc *p;
585{
586    int s, flags, mru, npx, taskid;
587    struct npioctl *npi;
588    time_t t;
589#ifdef PPP_FILTER
590    int error;
591    struct bpf_program *bp, *nbp;
592    struct bpf_insn *newcode, *oldcode;
593    int newcodelen;
594#endif /* PPP_FILTER */
595#ifdef  PPP_COMPRESS
596    int nb;
597    struct ppp_option_data *odp;
598    struct compressor **cp;
599    u_char ccp_option[CCP_MAX_OPTION_LENGTH];
600#endif
601
602    switch (cmd) {
603    case FIONREAD:
604        *(int *)data = sc->sc_inq.ifq_len;
605        break;
606
607    case PPPIOCSTASK:
608        taskid = *(int *)data;
609        sc->sc_pppdtask = taskid;
610        break;
611
612    case PPPIOCGUNIT:
613        *(int *)data = sc->sc_if.if_unit;
614        break;
615
616    case PPPIOCGFLAGS:
617        *(u_int *)data = sc->sc_flags;
618        break;
619
620    case PPPIOCSFLAGS:
621        flags = *(int *)data & SC_MASK;
622        s = splsoftnet();
623#ifdef PPP_COMPRESS
624        if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN))
625            ppp_ccp_closed(sc);
626#endif
627        s = splimp();
628        sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
629        splx(s);
630        break;
631
632    case PPPIOCSMRU:
633        mru = *(int *)data;
634        if ( mru >= MCLBYTES ) {
635          /* error - currently only handle 1 culster sized MRU */
636          /* if we want to handle up to PPP_MAXMRU then we */
637          /*   need to reallocate all mbufs on the freeq */
638          /*   this can only be done with iterrupts disabled */
639          return ( -1 );
640        }
641        else if ( mru >= PPP_MRU ) {
642          /* update the size */
643          sc->sc_mru = mru;
644        }
645        break;
646
647    case PPPIOCGMRU:
648        *(int *)data = sc->sc_mru;
649        break;
650
651#ifdef VJC
652    case PPPIOCSMAXCID:
653        if (sc->sc_comp) {
654            s = splsoftnet();
655            vj_compress_init(sc->sc_comp, *(int *)data);
656            splx(s);
657        }
658        break;
659#endif
660
661    case PPPIOCXFERUNIT:
662        sc->sc_xfer = 0; /* Always root p->p_pid;*/
663        break;
664
665#ifdef PPP_COMPRESS
666    case PPPIOCSCOMPRESS:
667        odp = (struct ppp_option_data *) data;
668        nb = odp->length;
669        if (nb > sizeof(ccp_option))
670            nb = sizeof(ccp_option);
671        if ((error = copyin(odp->ptr, ccp_option, nb)) != 0)
672            return (error);
673        if (ccp_option[1] < 2)  /* preliminary check on the length byte */
674            return (EINVAL);
675        for (cp = ppp_compressors; *cp != NULL; ++cp)
676            if ((*cp)->compress_proto == ccp_option[0]) {
677                /*
678                 * Found a handler for the protocol - try to allocate
679                 * a compressor or decompressor.
680                 */
681                error = 0;
682                if (odp->transmit) {
683                    s = splsoftnet();
684                    if (sc->sc_xc_state != NULL)
685                        (*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
686                    sc->sc_xcomp = *cp;
687                    sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb);
688                    if (sc->sc_xc_state == NULL) {
689                        if (sc->sc_flags & SC_DEBUG)
690                            printf("ppp%d: comp_alloc failed\n",
691                               sc->sc_if.if_unit);
692                        error = ENOBUFS;
693                    }
694                    splimp();
695                    sc->sc_flags &= ~SC_COMP_RUN;
696                    splx(s);
697                } else {
698                    s = splsoftnet();
699                    if (sc->sc_rc_state != NULL)
700                        (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
701                    sc->sc_rcomp = *cp;
702                    sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb);
703                    if (sc->sc_rc_state == NULL) {
704                        if (sc->sc_flags & SC_DEBUG)
705                            printf("ppp%d: decomp_alloc failed\n",
706                               sc->sc_if.if_unit);
707                        error = ENOBUFS;
708                    }
709                    splimp();
710                    sc->sc_flags &= ~SC_DECOMP_RUN;
711                    splx(s);
712                }
713                return (error);
714            }
715        if (sc->sc_flags & SC_DEBUG)
716            printf("ppp%d: no compressor for [%x %x %x], %x\n",
717                   sc->sc_if.if_unit, ccp_option[0], ccp_option[1],
718                   ccp_option[2], nb);
719        return (EINVAL);        /* no handler found */
720#endif /* PPP_COMPRESS */
721
722    case PPPIOCGNPMODE:
723    case PPPIOCSNPMODE:
724        npi = (struct npioctl *) data;
725        switch (npi->protocol) {
726        case PPP_IP:
727            npx = NP_IP;
728            break;
729        default:
730            return EINVAL;
731        }
732        if (cmd == PPPIOCGNPMODE) {
733            npi->mode = sc->sc_npmode[npx];
734        } else {
735            if (npi->mode != sc->sc_npmode[npx]) {
736                s = splsoftnet();
737                sc->sc_npmode[npx] = npi->mode;
738                if (npi->mode != NPMODE_QUEUE) {
739                    ppp_requeue(sc);
740                    (*sc->sc_start)(sc);
741                }
742                splx(s);
743            }
744        }
745        break;
746
747    case PPPIOCGIDLE:
748        s = splsoftnet();
749        microtime(&ppp_time);
750        t = ppp_time.tv_sec;
751        ((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent;
752        ((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv;
753        splx(s);
754        break;
755
756#ifdef PPP_FILTER
757    case PPPIOCSPASS:
758    case PPPIOCSACTIVE:
759        nbp = (struct bpf_program *) data;
760        if ((unsigned) nbp->bf_len > BPF_MAXINSNS)
761            return EINVAL;
762        newcodelen = nbp->bf_len * sizeof(struct bpf_insn);
763        if (newcodelen != 0) {
764            MALLOC(newcode, struct bpf_insn *, newcodelen, M_DEVBUF, M_WAITOK);
765            if (newcode == 0) {
766                return EINVAL;          /* or sumpin */
767            }
768            if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode,
769                               newcodelen)) != 0) {
770                FREE(newcode, M_DEVBUF);
771                return error;
772            }
773            if (!bpf_validate(newcode, nbp->bf_len)) {
774                FREE(newcode, M_DEVBUF);
775                return EINVAL;
776            }
777        } else
778            newcode = 0;
779        bp = (cmd == PPPIOCSPASS)? &sc->sc_pass_filt: &sc->sc_active_filt;
780        oldcode = bp->bf_insns;
781        s = splimp();
782        bp->bf_len = nbp->bf_len;
783        bp->bf_insns = newcode;
784        splx(s);
785        if (oldcode != 0)
786            FREE(oldcode, M_DEVBUF);
787        break;
788#endif
789
790    default:
791        return (-1);
792    }
793    return (0);
794}
795
796/*
797 * Process an ioctl request to the ppp network interface.
798 */
799static int
800pppsioctl(ifp, cmd, data)
801    register struct ifnet *ifp;
802    int cmd;
803    caddr_t data;
804{
805    /*struct proc *p = curproc;*/       /* XXX */
806    register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
807    register struct ifaddr *ifa = (struct ifaddr *)data;
808    register struct ifreq *ifr = (struct ifreq *)data;
809    struct ppp_stats *psp;
810#ifdef  PPP_COMPRESS
811    struct ppp_comp_stats *pcp;
812#endif
813    int s = splimp(), error = 0;
814
815    switch (cmd) {
816    case SIOCSIFFLAGS:
817        if ((ifp->if_flags & IFF_RUNNING) == 0)
818            ifp->if_flags &= ~IFF_UP;
819        break;
820
821    case SIOCSIFADDR:
822        if (ifa->ifa_addr->sa_family != AF_INET)
823            error = EAFNOSUPPORT;
824        break;
825
826    case SIOCSIFDSTADDR:
827        if (ifa->ifa_addr->sa_family != AF_INET)
828            error = EAFNOSUPPORT;
829        break;
830
831    case SIOCSIFMTU:
832        sc->sc_if.if_mtu = ifr->ifr_mtu;
833        break;
834
835    case SIOCGIFMTU:
836        ifr->ifr_mtu = sc->sc_if.if_mtu;
837        break;
838
839    case SIOCADDMULTI:
840    case SIOCDELMULTI:
841        if (ifr == 0) {
842            error = EAFNOSUPPORT;
843            break;
844        }
845        switch(ifr->ifr_addr.sa_family) {
846#ifdef INET
847        case AF_INET:
848            break;
849#endif
850        default:
851            error = EAFNOSUPPORT;
852            break;
853        }
854        break;
855
856    case SIO_RTEMS_SHOW_STATS:
857        printf("              MRU:%-8u",   sc->sc_mru);
858        printf("   Bytes received:%-8u",   sc->sc_stats.ppp_ibytes);
859        printf(" Packets received:%-8u",   sc->sc_stats.ppp_ipackets);
860        printf("   Receive errors:%-8u\n", sc->sc_stats.ppp_ierrors);
861        printf("       Bytes sent:%-8u",   sc->sc_stats.ppp_obytes);
862        printf("     Packets sent:%-8u",   sc->sc_stats.ppp_opackets);
863        printf("  Transmit errors:%-8u\n", sc->sc_stats.ppp_oerrors);
864        break;
865
866    case SIOCGPPPSTATS:
867        psp = &((struct ifpppstatsreq *) data)->stats;
868        bzero(psp, sizeof(*psp));
869        psp->p = sc->sc_stats;
870#if defined(VJC) && !defined(SL_NO_STATS)
871        if (sc->sc_comp) {
872            psp->vj.vjs_packets = sc->sc_comp->sls_packets;
873            psp->vj.vjs_compressed = sc->sc_comp->sls_compressed;
874            psp->vj.vjs_searches = sc->sc_comp->sls_searches;
875            psp->vj.vjs_misses = sc->sc_comp->sls_misses;
876            psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin;
877            psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin;
878            psp->vj.vjs_errorin = sc->sc_comp->sls_errorin;
879            psp->vj.vjs_tossed = sc->sc_comp->sls_tossed;
880        }
881#endif /* VJC */
882        break;
883
884#ifdef PPP_COMPRESS
885    case SIOCGPPPCSTATS:
886        pcp = &((struct ifpppcstatsreq *) data)->stats;
887        bzero(pcp, sizeof(*pcp));
888        if (sc->sc_xc_state != NULL)
889            (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c);
890        if (sc->sc_rc_state != NULL)
891            (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d);
892        break;
893#endif /* PPP_COMPRESS */
894
895    default:
896        error = EINVAL;
897    }
898    splx(s);
899    return (error);
900}
901
902/*
903 * Queue a packet.  Start transmission if not active.
904 * Packet is placed in Information field of PPP frame.
905 */
906int
907pppoutput(ifp, m0, dst, rtp)
908    struct ifnet *ifp;
909    struct mbuf *m0;
910    struct sockaddr *dst;
911    struct rtentry *rtp;
912{
913    register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
914    int protocol, address, control;
915    u_char *cp;
916    int s, error;
917    struct ip *ip;
918    struct ifqueue *ifq;
919    enum NPmode mode;
920    int len;
921    struct mbuf *m;
922
923    if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
924        || ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) {
925        error = ENETDOWN;       /* sort of */
926        goto bad;
927    }
928
929    /*
930     * Compute PPP header.
931     */
932    m0->m_flags &= ~M_HIGHPRI;
933    switch (dst->sa_family) {
934#ifdef INET
935    case AF_INET:
936        address = PPP_ALLSTATIONS;
937        control = PPP_UI;
938        protocol = PPP_IP;
939        mode = sc->sc_npmode[NP_IP];
940
941        /*
942         * If this packet has the "low delay" bit set in the IP header,
943         * put it on the fastq instead.
944         */
945        ip = mtod(m0, struct ip *);
946        if (ip->ip_tos & IPTOS_LOWDELAY)
947            m0->m_flags |= M_HIGHPRI;
948        break;
949#endif
950    case AF_UNSPEC:
951        address = PPP_ADDRESS(dst->sa_data);
952        control = PPP_CONTROL(dst->sa_data);
953        protocol = PPP_PROTOCOL(dst->sa_data);
954        mode = NPMODE_PASS;
955        break;
956    default:
957        printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
958        error = EAFNOSUPPORT;
959        goto bad;
960    }
961
962    /*
963     * Drop this packet, or return an error, if necessary.
964     */
965    if (mode == NPMODE_ERROR) {
966        error = ENETDOWN;
967        goto bad;
968    }
969    if (mode == NPMODE_DROP) {
970        error = 0;
971        goto bad;
972    }
973
974    /*
975     * Add PPP header.  If no space in first mbuf, allocate another.
976     * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
977     */
978    if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
979        m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT);
980        if (m0 == 0) {
981            error = ENOBUFS;
982            goto bad;
983        }
984        m0->m_len = 0;
985    } else
986        m0->m_data -= PPP_HDRLEN;
987
988    cp = mtod(m0, u_char *);
989    *cp++ = address;
990    *cp++ = control;
991    *cp++ = protocol >> 8;
992    *cp++ = protocol & 0xff;
993    m0->m_len += PPP_HDRLEN;
994
995    len = 0;
996    for (m = m0; m != 0; m = m->m_next)
997        len += m->m_len;
998
999    if (sc->sc_flags & SC_LOG_OUTPKT) {
1000        printf("ppp%d output: ", ifp->if_unit);
1001        pppdumpm(m0);
1002    }
1003
1004    if ((protocol & 0x8000) == 0) {
1005#ifdef PPP_FILTER
1006        /*
1007         * Apply the pass and active filters to the packet,
1008         * but only if it is a data packet.
1009         */
1010        *mtod(m0, u_char *) = 1;        /* indicates outbound */
1011        if (sc->sc_pass_filt.bf_insns != 0
1012            && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0,
1013                          len, 0) == 0) {
1014            error = 0;          /* drop this packet */
1015            goto bad;
1016        }
1017
1018        /*
1019         * Update the time we sent the most recent packet.
1020         */
1021        if (sc->sc_active_filt.bf_insns == 0
1022            || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0))
1023            sc->sc_last_sent = time.tv_sec;
1024
1025        *mtod(m0, u_char *) = address;
1026#else
1027        /*
1028         * Update the time we sent the most recent data packet.
1029         */
1030        microtime(&ppp_time);
1031        sc->sc_last_sent = ppp_time.tv_sec;
1032#endif /* PPP_FILTER */
1033    }
1034
1035#if NBPFILTER > 0
1036    /*
1037     * See if bpf wants to look at the packet.
1038     */
1039    if (sc->sc_bpf)
1040        bpf_mtap(sc->sc_bpf, m0);
1041#endif
1042
1043    /*
1044     * Put the packet on the appropriate queue.
1045     */
1046    s = splsoftnet();
1047    if (mode == NPMODE_QUEUE) {
1048        /* XXX we should limit the number of packets on this queue */
1049        *sc->sc_npqtail = m0;
1050        m0->m_nextpkt = NULL;
1051        sc->sc_npqtail = &m0->m_nextpkt;
1052    } else {
1053        ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd;
1054        if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) {
1055            IF_DROP(ifq);
1056            splx(s);
1057            sc->sc_if.if_oerrors++;
1058            sc->sc_stats.ppp_oerrors++;
1059            error = ENOBUFS;
1060            goto bad;
1061        }
1062        IF_ENQUEUE(ifq, m0);
1063        (*sc->sc_start)(sc);
1064    }
1065    ifp->if_lastchange = ppp_time;
1066    ifp->if_opackets++;
1067    ifp->if_obytes += len;
1068
1069    splx(s);
1070    return (0);
1071
1072bad:
1073    m_freem(m0);
1074    return (error);
1075}
1076
1077/*
1078 * After a change in the NPmode for some NP, move packets from the
1079 * npqueue to the send queue or the fast queue as appropriate.
1080 * Should be called at splsoftnet.
1081 */
1082static void
1083ppp_requeue(sc)
1084    struct ppp_softc *sc;
1085{
1086    struct mbuf *m, **mpp;
1087    struct ifqueue *ifq;
1088    enum NPmode mode;
1089
1090    for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) {
1091        switch (PPP_PROTOCOL(mtod(m, u_char *))) {
1092        case PPP_IP:
1093            mode = sc->sc_npmode[NP_IP];
1094            break;
1095        default:
1096            mode = NPMODE_PASS;
1097        }
1098
1099        switch (mode) {
1100        case NPMODE_PASS:
1101            /*
1102             * This packet can now go on one of the queues to be sent.
1103             */
1104            *mpp = m->m_nextpkt;
1105            m->m_nextpkt = NULL;
1106            ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd;
1107            if (IF_QFULL(ifq)) {
1108                IF_DROP(ifq);
1109                sc->sc_if.if_oerrors++;
1110                sc->sc_stats.ppp_oerrors++;
1111            } else
1112                IF_ENQUEUE(ifq, m);
1113            break;
1114
1115        case NPMODE_DROP:
1116        case NPMODE_ERROR:
1117            *mpp = m->m_nextpkt;
1118            m_freem(m);
1119            break;
1120
1121        case NPMODE_QUEUE:
1122            mpp = &m->m_nextpkt;
1123            break;
1124        }
1125    }
1126    sc->sc_npqtail = mpp;
1127}
1128
1129/*
1130 * Get a packet to send.  This procedure is intended to be called at
1131 * splsoftnet, since it may involve time-consuming operations such as
1132 * applying VJ compression, packet compression, address/control and/or
1133 * protocol field compression to the packet.
1134 */
1135struct mbuf *
1136ppp_dequeue(sc)
1137    struct ppp_softc *sc;
1138{
1139    struct mbuf *m;
1140#ifdef VJC
1141    struct mbuf *mp;
1142#endif
1143    u_char *cp;
1144    int address, control, protocol;
1145
1146    /*
1147     * Grab a packet to send: first try the fast queue, then the
1148     * normal queue.
1149     */
1150    rtems_bsdnet_semaphore_obtain();
1151    IF_DEQUEUE(&sc->sc_fastq, m);
1152    if (m == NULL)
1153        IF_DEQUEUE(&sc->sc_if.if_snd, m);
1154    rtems_bsdnet_semaphore_release();
1155
1156    if (m == NULL)
1157        return NULL;
1158
1159    ++sc->sc_stats.ppp_opackets;
1160
1161    /*
1162     * Extract the ppp header of the new packet.
1163     * The ppp header will be in one mbuf.
1164     */
1165    cp = mtod(m, u_char *);
1166    address = PPP_ADDRESS(cp);
1167    control = PPP_CONTROL(cp);
1168    protocol = PPP_PROTOCOL(cp);
1169
1170    switch (protocol) {
1171    case PPP_IP:
1172#ifdef VJC
1173        /*
1174         * If the packet is a TCP/IP packet, see if we can compress it.
1175         */
1176        if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) {
1177            struct ip *ip;
1178            int type;
1179
1180            mp = m;
1181            ip = (struct ip *) (cp + PPP_HDRLEN);
1182            if (mp->m_len <= PPP_HDRLEN) {
1183                mp = mp->m_next;
1184                if (mp == NULL)
1185                    break;
1186                ip = mtod(mp, struct ip *);
1187            }
1188            /* this code assumes the IP/TCP header is in one non-shared mbuf */
1189            if (ip->ip_p == IPPROTO_TCP) {
1190                type = vj_compress_tcp(mp, ip, sc->sc_comp,
1191                                       !(sc->sc_flags & SC_NO_TCP_CCID));
1192                switch (type) {
1193                case TYPE_UNCOMPRESSED_TCP:
1194                    protocol = PPP_VJC_UNCOMP;
1195                    break;
1196                case TYPE_COMPRESSED_TCP:
1197                    protocol = PPP_VJC_COMP;
1198                    cp = mtod(m, u_char *);
1199                    cp[0] = address;    /* header has moved */
1200                    cp[1] = control;
1201                    cp[2] = 0;
1202                    break;
1203                }
1204                cp[3] = protocol;       /* update protocol in PPP header */
1205            }
1206        }
1207#endif  /* VJC */
1208        break;
1209
1210#ifdef PPP_COMPRESS
1211    case PPP_CCP:
1212        ppp_ccp(sc, m, 0);
1213        break;
1214#endif  /* PPP_COMPRESS */
1215    }
1216
1217#ifdef PPP_COMPRESS
1218    if (protocol != PPP_LCP && protocol != PPP_CCP
1219        && sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) {
1220        struct mbuf *mcomp = NULL;
1221        int slen, clen;
1222
1223        slen = 0;
1224        for (mp = m; mp != NULL; mp = mp->m_next)
1225            slen += mp->m_len;
1226        clen = (*sc->sc_xcomp->compress)
1227            (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN);
1228        if (mcomp != NULL) {
1229            if (sc->sc_flags & SC_CCP_UP) {
1230                /* Send the compressed packet instead of the original. */
1231                m_freem(m);
1232                m = mcomp;
1233                cp = mtod(m, u_char *);
1234                protocol = cp[3];
1235            } else {
1236                /* Can't transmit compressed packets until CCP is up. */
1237                m_freem(mcomp);
1238            }
1239        }
1240    }
1241#endif  /* PPP_COMPRESS */
1242
1243    /*
1244     * Compress the address/control and protocol, if possible.
1245     */
1246    if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
1247        control == PPP_UI && protocol != PPP_ALLSTATIONS &&
1248        protocol != PPP_LCP) {
1249        /* can compress address/control */
1250        m->m_data += 2;
1251        m->m_len -= 2;
1252    }
1253    if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
1254        /* can compress protocol */
1255        if (mtod(m, u_char *) == cp) {
1256            cp[2] = cp[1];      /* move address/control up */
1257            cp[1] = cp[0];
1258        }
1259        ++m->m_data;
1260        --m->m_len;
1261    }
1262
1263    return m;
1264}
1265
1266/*
1267 * Software interrupt routine, called at splsoftnet.
1268 */
1269void
1270pppintr(void)
1271{
1272}
1273
1274#ifdef PPP_COMPRESS
1275/*
1276 * Handle a CCP packet.  `rcvd' is 1 if the packet was received,
1277 * 0 if it is about to be transmitted.
1278 */
1279static void
1280ppp_ccp(sc, m, rcvd)
1281    struct ppp_softc *sc;
1282    struct mbuf *m;
1283    int rcvd;
1284{
1285    u_char *dp, *ep;
1286    struct mbuf *mp;
1287    int slen, s;
1288
1289    /*
1290     * Get a pointer to the data after the PPP header.
1291     */
1292    if (m->m_len <= PPP_HDRLEN) {
1293        mp = m->m_next;
1294        if (mp == NULL)
1295            return;
1296        dp = (mp != NULL)? mtod(mp, u_char *): NULL;
1297    } else {
1298        mp = m;
1299        dp = mtod(mp, u_char *) + PPP_HDRLEN;
1300    }
1301
1302    ep = mtod(mp, u_char *) + mp->m_len;
1303    if (dp + CCP_HDRLEN > ep)
1304        return;
1305    slen = CCP_LENGTH(dp);
1306    if (dp + slen > ep) {
1307        if (sc->sc_flags & SC_DEBUG)
1308            printf("if_ppp/ccp: not enough data in mbuf (%p+%x > %p+%x)\n",
1309                   dp, slen, mtod(mp, u_char *), mp->m_len);
1310        return;
1311    }
1312
1313    switch (CCP_CODE(dp)) {
1314    case CCP_CONFREQ:
1315    case CCP_TERMREQ:
1316    case CCP_TERMACK:
1317        /* CCP must be going down - disable compression */
1318        if (sc->sc_flags & SC_CCP_UP) {
1319            s = splimp();
1320            sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
1321            splx(s);
1322        }
1323        break;
1324
1325    case CCP_CONFACK:
1326        if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP)
1327            && slen >= CCP_HDRLEN + CCP_OPT_MINLEN
1328            && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) {
1329            if (!rcvd) {
1330                /* we're agreeing to send compressed packets. */
1331                if (sc->sc_xc_state != NULL
1332                    && (*sc->sc_xcomp->comp_init)
1333                        (sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
1334                         sc->sc_if.if_unit, 0, sc->sc_flags & SC_DEBUG)) {
1335                    s = splimp();
1336                    sc->sc_flags |= SC_COMP_RUN;
1337                    splx(s);
1338                }
1339            } else {
1340                /* peer is agreeing to send compressed packets. */
1341                if (sc->sc_rc_state != NULL
1342                    && (*sc->sc_rcomp->decomp_init)
1343                        (sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
1344                         sc->sc_if.if_unit, 0, sc->sc_mru,
1345                         sc->sc_flags & SC_DEBUG)) {
1346                    s = splimp();
1347                    sc->sc_flags |= SC_DECOMP_RUN;
1348                    sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
1349                    splx(s);
1350                }
1351            }
1352        }
1353        break;
1354
1355    case CCP_RESETACK:
1356        if (sc->sc_flags & SC_CCP_UP) {
1357            if (!rcvd) {
1358                if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN))
1359                    (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state);
1360            } else {
1361                if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
1362                    (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state);
1363                    s = splimp();
1364                    sc->sc_flags &= ~SC_DC_ERROR;
1365                    splx(s);
1366                }
1367            }
1368        }
1369        break;
1370    }
1371}
1372
1373/*
1374 * CCP is down; free (de)compressor state if necessary.
1375 */
1376static void
1377ppp_ccp_closed(sc)
1378    struct ppp_softc *sc;
1379{
1380    if (sc->sc_xc_state) {
1381        (*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
1382        sc->sc_xc_state = NULL;
1383    }
1384    if (sc->sc_rc_state) {
1385        (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
1386        sc->sc_rc_state = NULL;
1387    }
1388}
1389#endif /* PPP_COMPRESS */
1390
1391/*
1392 * Process a received PPP packet, doing decompression as necessary.
1393 * Should be called at splsoftnet.
1394 */
1395#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1396                         TYPE_UNCOMPRESSED_TCP)
1397
1398static struct mbuf *
1399ppp_inproc(sc, m)
1400    struct ppp_softc *sc;
1401    struct mbuf *m;
1402{
1403    struct mbuf  *mf = (struct mbuf *)0;
1404    struct ifnet *ifp = &sc->sc_if;
1405    struct ifqueue *inq;
1406    int s, ilen, proto, rv;
1407    u_char *cp, adrs, ctrl;
1408    struct mbuf *mp;
1409#ifdef PPP_COMPRESS
1410    struct mbuf *dmp = NULL;
1411#endif
1412#ifdef VJC
1413    u_char *iphdr;
1414    u_int hlen;
1415    int xlen;
1416#endif
1417
1418    sc->sc_stats.ppp_ipackets++;
1419
1420    if (sc->sc_flags & SC_LOG_INPKT) {
1421        ilen = 0;
1422        for (mp = m; mp != NULL; mp = mp->m_next)
1423            ilen += mp->m_len;
1424        printf("ppp%d: got %d bytes\n", ifp->if_unit, ilen);
1425        pppdumpm(m);
1426    }
1427
1428    cp = mtod(m, u_char *);
1429    adrs = PPP_ADDRESS(cp);
1430    ctrl = PPP_CONTROL(cp);
1431    proto = PPP_PROTOCOL(cp);
1432
1433    if (m->m_flags & M_ERRMARK) {
1434        m->m_flags &= ~M_ERRMARK;
1435        s = splimp();
1436        sc->sc_flags |= SC_VJ_RESET;
1437        splx(s);
1438    }
1439
1440#ifdef PPP_COMPRESS
1441    /*
1442     * Decompress this packet if necessary, update the receiver's
1443     * dictionary, or take appropriate action on a CCP packet.
1444     */
1445    if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)
1446        && !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) {
1447        /* decompress this packet */
1448        rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp);
1449        if (rv == DECOMP_OK) {
1450            m_freem(m);
1451            if (dmp == NULL) {
1452                /* no error, but no decompressed packet produced */
1453                return mf;
1454            }
1455            m = dmp;
1456            cp = mtod(m, u_char *);
1457            proto = PPP_PROTOCOL(cp);
1458
1459        } else {
1460            /*
1461             * An error has occurred in decompression.
1462             * Pass the compressed packet up to pppd, which may take
1463             * CCP down or issue a Reset-Req.
1464             */
1465            if (sc->sc_flags & SC_DEBUG)
1466                printf("ppp%d: decompress failed %d\n", ifp->if_unit, rv);
1467            s = splimp();
1468            sc->sc_flags |= SC_VJ_RESET;
1469            if (rv == DECOMP_ERROR)
1470                sc->sc_flags |= SC_DC_ERROR;
1471            else
1472                sc->sc_flags |= SC_DC_FERROR;
1473            splx(s);
1474        }
1475
1476    } else {
1477        if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
1478            (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m);
1479        }
1480        if (proto == PPP_CCP) {
1481            ppp_ccp(sc, m, 1);
1482        }
1483    }
1484#endif
1485
1486    ilen = 0;
1487    for (mp = m; mp != NULL; mp = mp->m_next)
1488        ilen += mp->m_len;
1489
1490#ifdef VJC
1491    if (sc->sc_flags & SC_VJ_RESET) {
1492        /*
1493         * If we've missed a packet, we must toss subsequent compressed
1494         * packets which don't have an explicit connection ID.
1495         */
1496        if (sc->sc_comp)
1497            vj_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp);
1498        s = splimp();
1499        sc->sc_flags &= ~SC_VJ_RESET;
1500        splx(s);
1501    }
1502
1503    /*
1504     * See if we have a VJ-compressed packet to uncompress.
1505     */
1506    if (proto == PPP_VJC_COMP) {
1507        if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
1508            goto bad;
1509
1510        xlen = vj_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
1511                                      ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP,
1512                                      sc->sc_comp, &iphdr, &hlen);
1513
1514        if (xlen <= 0) {
1515            if (sc->sc_flags & SC_DEBUG)
1516                printf("ppp%d: VJ uncompress failed on type comp\n",
1517                        ifp->if_unit);
1518            goto bad;
1519        }
1520
1521        /* Copy the PPP and IP headers into a new mbuf. */
1522        MGETHDR(mp, M_DONTWAIT, MT_DATA);
1523        if (mp == NULL)
1524            goto bad;
1525        mp->m_len = 0;
1526        mp->m_next = NULL;
1527        if (hlen + PPP_HDRLEN > MHLEN) {
1528            MCLGET(mp, M_DONTWAIT);
1529            if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) {
1530                m_freem(mp);
1531                goto bad;       /* lose if big headers and no clusters */
1532            }
1533        }
1534        cp = mtod(mp, u_char *);
1535        cp[0] = adrs;
1536        cp[1] = ctrl;
1537        cp[2] = 0;
1538        cp[3] = PPP_IP;
1539        proto = PPP_IP;
1540        bcopy(iphdr, cp + PPP_HDRLEN, hlen);
1541        mp->m_len = hlen + PPP_HDRLEN;
1542
1543        /*
1544         * Trim the PPP and VJ headers off the old mbuf
1545         * and stick the new and old mbufs together.
1546         */
1547        m->m_data += PPP_HDRLEN + xlen;
1548        m->m_len -= PPP_HDRLEN + xlen;
1549        if (m->m_len <= M_TRAILINGSPACE(mp)) {
1550            bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len);
1551            mp->m_len += m->m_len;
1552            MFREE(m, mp->m_next);
1553        } else
1554            mp->m_next = m;
1555        m = mp;
1556        ilen += hlen - xlen;
1557
1558    } else if (proto == PPP_VJC_UNCOMP) {
1559        if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
1560            goto bad;
1561
1562        xlen = vj_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
1563                                      ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP,
1564                                      sc->sc_comp, &iphdr, &hlen);
1565
1566        if (xlen < 0) {
1567            if (sc->sc_flags & SC_DEBUG)
1568                printf("ppp%d: VJ uncompress failed on type uncomp\n",
1569                        ifp->if_unit);
1570            goto bad;
1571        }
1572
1573        proto = PPP_IP;
1574        cp[3] = PPP_IP;
1575    }
1576#endif /* VJC */
1577
1578    /*
1579     * If the packet will fit in a header mbuf, don't waste a
1580     * whole cluster on it.
1581     */
1582    if (ilen <= MHLEN && M_IS_CLUSTER(m)) {
1583        MGETHDR(mp, M_DONTWAIT, MT_DATA);
1584        if (mp != NULL) {
1585            m_copydata(m, 0, ilen, mtod(mp, caddr_t));
1586            /* instead of freeing - return cluster mbuf so it can be reused */
1587            /* m_freem(m); */
1588            mf = m;
1589            m = mp;
1590            m->m_len = ilen;
1591        }
1592    }
1593    m->m_pkthdr.len = ilen;
1594    m->m_pkthdr.rcvif = ifp;
1595
1596    if ((proto & 0x8000) == 0) {
1597#ifdef PPP_FILTER
1598        /*
1599         * See whether we want to pass this packet, and
1600         * if it counts as link activity.
1601         */
1602        adrs = *mtod(m, u_char *);      /* save address field */
1603        *mtod(m, u_char *) = 0;         /* indicate inbound */
1604        if (sc->sc_pass_filt.bf_insns != 0
1605            && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m,
1606                          ilen, 0) == 0) {
1607            /* drop this packet */
1608            m_freem(m);
1609            return mf;
1610        }
1611        if (sc->sc_active_filt.bf_insns == 0
1612            || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0))
1613            sc->sc_last_recv = time.tv_sec;
1614
1615        *mtod(m, u_char *) = adrs;
1616#else
1617        /*
1618         * Record the time that we received this packet.
1619         */
1620        microtime(&ppp_time);
1621        sc->sc_last_recv = ppp_time.tv_sec;
1622#endif /* PPP_FILTER */
1623    }
1624
1625#if NBPFILTER > 0
1626    /* See if bpf wants to look at the packet. */
1627    if (sc->sc_bpf)
1628        bpf_mtap(sc->sc_bpf, m);
1629#endif
1630
1631    rv = 0;
1632    switch (proto) {
1633#ifdef INET
1634    case PPP_IP:
1635        /*
1636         * IP packet - take off the ppp header and pass it up to IP.
1637         */
1638        if ((ifp->if_flags & IFF_UP) == 0
1639            || sc->sc_npmode[NP_IP] != NPMODE_PASS) {
1640            /* interface is down - drop the packet. */
1641            m_freem(m);
1642            return mf;
1643        }
1644        m->m_pkthdr.len -= PPP_HDRLEN;
1645        m->m_data += PPP_HDRLEN;
1646        m->m_len -= PPP_HDRLEN;
1647        schednetisr(NETISR_IP);
1648        inq = &ipintrq;
1649        break;
1650#endif
1651
1652    default:
1653        /*
1654         * Some other protocol - place on input queue for read().
1655         */
1656        inq = &sc->sc_inq;
1657        rv = 1;
1658        break;
1659    }
1660
1661    /*
1662     * Put the packet on the appropriate input queue.
1663     */
1664    s = splimp();
1665    if (IF_QFULL(inq)) {
1666        IF_DROP(inq);
1667        splx(s);
1668        if (sc->sc_flags & SC_DEBUG)
1669            printf("ppp%d: input queue full\n", ifp->if_unit);
1670        ifp->if_iqdrops++;
1671        goto bad;
1672    }
1673    IF_ENQUEUE(inq, m);
1674    splx(s);
1675
1676    ifp->if_ipackets++;
1677    ifp->if_ibytes += ilen;
1678    microtime(&ppp_time);
1679    ifp->if_lastchange = ppp_time;
1680
1681    if (rv) {
1682      (*sc->sc_ctlp)(sc);
1683    }
1684
1685    return mf;
1686
1687 bad:
1688    m_freem(m);
1689    sc->sc_if.if_ierrors++;
1690    sc->sc_stats.ppp_ierrors++;
1691    return mf;
1692}
1693
1694#define MAX_DUMP_BYTES  128
1695
1696static void
1697pppdumpm(m0)
1698    struct mbuf *m0;
1699{
1700    char buf[3*MAX_DUMP_BYTES+4];
1701    char *bp = buf;
1702    struct mbuf *m;
1703    static char digits[] = "0123456789abcdef";
1704
1705    for (m = m0; m; m = m->m_next) {
1706        int l = m->m_len;
1707        u_char *rptr = (u_char *)m->m_data;
1708
1709        while (l--) {
1710            if (bp > buf + sizeof(buf) - 4)
1711                goto done;
1712            *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1713            *bp++ = digits[*rptr++ & 0xf];
1714        }
1715
1716        if (m->m_next) {
1717            if (bp > buf + sizeof(buf) - 3)
1718                goto done;
1719            *bp++ = '|';
1720        } else
1721            *bp++ = ' ';
1722    }
1723done:
1724    if (m)
1725        *bp++ = '>';
1726    *bp = 0;
1727    printf("%s\n", buf);
1728}
1729
1730#endif  /* NPPP > 0 */
Note: See TracBrowser for help on using the repository browser.