source: rtems/cpukit/libnetworking/net/if_ppp.c @ 3274c876

4.104.114.84.9
Last change on this file since 3274c876 was 3274c876, checked in by Joel Sherrill <joel.sherrill@…>, on Apr 28, 2005 at 9:49:50 PM

2005-04-28 Joel Sherrill <joel@…>

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