source: rtems/c/src/libnetworking/net/if_ppp.c @ f4c118d

4.104.114.84.95
Last change on this file since f4c118d was f4c118d, checked in by Joel Sherrill <joel.sherrill@…>, on 03/27/02 at 14:36:07

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

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