source: rtems/cpukit/libnetworking/net/if_ppp.c @ 048dcd2b

4.104.114.84.95
Last change on this file since 048dcd2b was 1f788a3, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/15/04 at 13:53:12

Remove stray white spaces.

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