source: rtems/cpukit/libnetworking/net/if_ppp.c @ f48f64a

4.104.114.84.95
Last change on this file since f48f64a was 88d99508, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/18/05 at 16:36:20

2005-04-18 Ralf Corsepius <ralf.corsepius@…>

  • libnetworking/net/if.h: Update from FreeBSD.
  • libnetworking/net/if_loop.c: Reflect updates.
  • libnetworking/net/if_ppp.c: Reflect updates.
  • libnetworking/net/if_types.h: Update from FreeBSD.
  • Property mode set to 100644
File size: 43.2 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    struct mbuf *m, *mp;
1173    u_char *cp;
1174    int address, control, protocol;
1175
1176    /*
1177     * Grab a packet to send: first try the fast queue, then the
1178     * normal queue.
1179     */
1180    rtems_bsdnet_semaphore_obtain();
1181    IF_DEQUEUE(&sc->sc_fastq, m);
1182    if (m == NULL)
1183        IF_DEQUEUE(&sc->sc_if.if_snd, m);
1184    rtems_bsdnet_semaphore_release();
1185
1186    if (m == NULL)
1187        return NULL;
1188
1189    ++sc->sc_stats.ppp_opackets;
1190
1191    /*
1192     * Extract the ppp header of the new packet.
1193     * The ppp header will be in one mbuf.
1194     */
1195    cp = mtod(m, u_char *);
1196    address = PPP_ADDRESS(cp);
1197    control = PPP_CONTROL(cp);
1198    protocol = PPP_PROTOCOL(cp);
1199
1200    switch (protocol) {
1201    case PPP_IP:
1202#ifdef VJC
1203        /*
1204         * If the packet is a TCP/IP packet, see if we can compress it.
1205         */
1206        if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) {
1207            struct ip *ip;
1208            int type;
1209
1210            mp = m;
1211            ip = (struct ip *) (cp + PPP_HDRLEN);
1212            if (mp->m_len <= PPP_HDRLEN) {
1213                mp = mp->m_next;
1214                if (mp == NULL)
1215                    break;
1216                ip = mtod(mp, struct ip *);
1217            }
1218            /* this code assumes the IP/TCP header is in one non-shared mbuf */
1219            if (ip->ip_p == IPPROTO_TCP) {
1220                type = vj_compress_tcp(mp, ip, sc->sc_comp,
1221                                       !(sc->sc_flags & SC_NO_TCP_CCID));
1222                switch (type) {
1223                case TYPE_UNCOMPRESSED_TCP:
1224                    protocol = PPP_VJC_UNCOMP;
1225                    break;
1226                case TYPE_COMPRESSED_TCP:
1227                    protocol = PPP_VJC_COMP;
1228                    cp = mtod(m, u_char *);
1229                    cp[0] = address;    /* header has moved */
1230                    cp[1] = control;
1231                    cp[2] = 0;
1232                    break;
1233                }
1234                cp[3] = protocol;       /* update protocol in PPP header */
1235            }
1236        }
1237#endif  /* VJC */
1238        break;
1239
1240#ifdef PPP_COMPRESS
1241    case PPP_CCP:
1242        ppp_ccp(sc, m, 0);
1243        break;
1244#endif  /* PPP_COMPRESS */
1245    }
1246
1247#ifdef PPP_COMPRESS
1248    if (protocol != PPP_LCP && protocol != PPP_CCP
1249        && sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) {
1250        struct mbuf *mcomp = NULL;
1251        int slen, clen;
1252
1253        slen = 0;
1254        for (mp = m; mp != NULL; mp = mp->m_next)
1255            slen += mp->m_len;
1256        clen = (*sc->sc_xcomp->compress)
1257            (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN);
1258        if (mcomp != NULL) {
1259            if (sc->sc_flags & SC_CCP_UP) {
1260                /* Send the compressed packet instead of the original. */
1261                m_freem(m);
1262                m = mcomp;
1263                cp = mtod(m, u_char *);
1264                protocol = cp[3];
1265            } else {
1266                /* Can't transmit compressed packets until CCP is up. */
1267                m_freem(mcomp);
1268            }
1269        }
1270    }
1271#endif  /* PPP_COMPRESS */
1272
1273    /*
1274     * Compress the address/control and protocol, if possible.
1275     */
1276    if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
1277        control == PPP_UI && protocol != PPP_ALLSTATIONS &&
1278        protocol != PPP_LCP) {
1279        /* can compress address/control */
1280        m->m_data += 2;
1281        m->m_len -= 2;
1282    }
1283    if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
1284        /* can compress protocol */
1285        if (mtod(m, u_char *) == cp) {
1286            cp[2] = cp[1];      /* move address/control up */
1287            cp[1] = cp[0];
1288        }
1289        ++m->m_data;
1290        --m->m_len;
1291    }
1292
1293    return m;
1294}
1295
1296/*
1297 * Software interrupt routine, called at splsoftnet.
1298 */
1299void
1300pppintr(void)
1301{
1302}
1303
1304#ifdef PPP_COMPRESS
1305/*
1306 * Handle a CCP packet.  `rcvd' is 1 if the packet was received,
1307 * 0 if it is about to be transmitted.
1308 */
1309static void
1310ppp_ccp(sc, m, rcvd)
1311    struct ppp_softc *sc;
1312    struct mbuf *m;
1313    int rcvd;
1314{
1315    u_char *dp, *ep;
1316    struct mbuf *mp;
1317    int slen, s;
1318
1319    /*
1320     * Get a pointer to the data after the PPP header.
1321     */
1322    if (m->m_len <= PPP_HDRLEN) {
1323        mp = m->m_next;
1324        if (mp == NULL)
1325            return;
1326        dp = (mp != NULL)? mtod(mp, u_char *): NULL;
1327    } else {
1328        mp = m;
1329        dp = mtod(mp, u_char *) + PPP_HDRLEN;
1330    }
1331
1332    ep = mtod(mp, u_char *) + mp->m_len;
1333    if (dp + CCP_HDRLEN > ep)
1334        return;
1335    slen = CCP_LENGTH(dp);
1336    if (dp + slen > ep) {
1337        if (sc->sc_flags & SC_DEBUG)
1338            printf("if_ppp/ccp: not enough data in mbuf (%p+%x > %p+%x)\n",
1339                   dp, slen, mtod(mp, u_char *), mp->m_len);
1340        return;
1341    }
1342
1343    switch (CCP_CODE(dp)) {
1344    case CCP_CONFREQ:
1345    case CCP_TERMREQ:
1346    case CCP_TERMACK:
1347        /* CCP must be going down - disable compression */
1348        if (sc->sc_flags & SC_CCP_UP) {
1349            s = splimp();
1350            sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
1351            splx(s);
1352        }
1353        break;
1354
1355    case CCP_CONFACK:
1356        if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP)
1357            && slen >= CCP_HDRLEN + CCP_OPT_MINLEN
1358            && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) {
1359            if (!rcvd) {
1360                /* we're agreeing to send compressed packets. */
1361                if (sc->sc_xc_state != NULL
1362                    && (*sc->sc_xcomp->comp_init)
1363                        (sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
1364                         sc->sc_if.if_unit, 0, sc->sc_flags & SC_DEBUG)) {
1365                    s = splimp();
1366                    sc->sc_flags |= SC_COMP_RUN;
1367                    splx(s);
1368                }
1369            } else {
1370                /* peer is agreeing to send compressed packets. */
1371                if (sc->sc_rc_state != NULL
1372                    && (*sc->sc_rcomp->decomp_init)
1373                        (sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
1374                         sc->sc_if.if_unit, 0, sc->sc_mru,
1375                         sc->sc_flags & SC_DEBUG)) {
1376                    s = splimp();
1377                    sc->sc_flags |= SC_DECOMP_RUN;
1378                    sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
1379                    splx(s);
1380                }
1381            }
1382        }
1383        break;
1384
1385    case CCP_RESETACK:
1386        if (sc->sc_flags & SC_CCP_UP) {
1387            if (!rcvd) {
1388                if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN))
1389                    (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state);
1390            } else {
1391                if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
1392                    (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state);
1393                    s = splimp();
1394                    sc->sc_flags &= ~SC_DC_ERROR;
1395                    splx(s);
1396                }
1397            }
1398        }
1399        break;
1400    }
1401}
1402
1403/*
1404 * CCP is down; free (de)compressor state if necessary.
1405 */
1406static void
1407ppp_ccp_closed(sc)
1408    struct ppp_softc *sc;
1409{
1410    if (sc->sc_xc_state) {
1411        (*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
1412        sc->sc_xc_state = NULL;
1413    }
1414    if (sc->sc_rc_state) {
1415        (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
1416        sc->sc_rc_state = NULL;
1417    }
1418}
1419#endif /* PPP_COMPRESS */
1420
1421/*
1422 * Process a received PPP packet, doing decompression as necessary.
1423 * Should be called at splsoftnet.
1424 */
1425#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1426                         TYPE_UNCOMPRESSED_TCP)
1427
1428static struct mbuf *
1429ppp_inproc(sc, m)
1430    struct ppp_softc *sc;
1431    struct mbuf *m;
1432{
1433    struct mbuf  *mf = (struct mbuf *)0;
1434    struct ifnet *ifp = &sc->sc_if;
1435    struct ifqueue *inq;
1436    int s, ilen, proto, rv;
1437    u_char *cp, adrs, ctrl;
1438    struct mbuf *mp;
1439#ifdef PPP_COMPRESS
1440    struct mbuf *dmp = NULL;
1441#endif
1442#ifdef VJC
1443    u_char *iphdr;
1444    u_int hlen;
1445    int xlen;
1446#endif
1447
1448    sc->sc_stats.ppp_ipackets++;
1449
1450    if (sc->sc_flags & SC_LOG_INPKT) {
1451        ilen = 0;
1452        for (mp = m; mp != NULL; mp = mp->m_next)
1453            ilen += mp->m_len;
1454        printf("ppp%d: got %d bytes\n", ifp->if_unit, ilen);
1455        pppdumpm(m);
1456    }
1457
1458    cp = mtod(m, u_char *);
1459    adrs = PPP_ADDRESS(cp);
1460    ctrl = PPP_CONTROL(cp);
1461    proto = PPP_PROTOCOL(cp);
1462
1463    if (m->m_flags & M_ERRMARK) {
1464        m->m_flags &= ~M_ERRMARK;
1465        s = splimp();
1466        sc->sc_flags |= SC_VJ_RESET;
1467        splx(s);
1468    }
1469
1470#ifdef PPP_COMPRESS
1471    /*
1472     * Decompress this packet if necessary, update the receiver's
1473     * dictionary, or take appropriate action on a CCP packet.
1474     */
1475    if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)
1476        && !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) {
1477        /* decompress this packet */
1478        rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp);
1479        if (rv == DECOMP_OK) {
1480            m_freem(m);
1481            if (dmp == NULL) {
1482                /* no error, but no decompressed packet produced */
1483                return mf;
1484            }
1485            m = dmp;
1486            cp = mtod(m, u_char *);
1487            proto = PPP_PROTOCOL(cp);
1488
1489        } else {
1490            /*
1491             * An error has occurred in decompression.
1492             * Pass the compressed packet up to pppd, which may take
1493             * CCP down or issue a Reset-Req.
1494             */
1495            if (sc->sc_flags & SC_DEBUG)
1496                printf("ppp%d: decompress failed %d\n", ifp->if_unit, rv);
1497            s = splimp();
1498            sc->sc_flags |= SC_VJ_RESET;
1499            if (rv == DECOMP_ERROR)
1500                sc->sc_flags |= SC_DC_ERROR;
1501            else
1502                sc->sc_flags |= SC_DC_FERROR;
1503            splx(s);
1504        }
1505
1506    } else {
1507        if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
1508            (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m);
1509        }
1510        if (proto == PPP_CCP) {
1511            ppp_ccp(sc, m, 1);
1512        }
1513    }
1514#endif
1515
1516    ilen = 0;
1517    for (mp = m; mp != NULL; mp = mp->m_next)
1518        ilen += mp->m_len;
1519
1520#ifdef VJC
1521    if (sc->sc_flags & SC_VJ_RESET) {
1522        /*
1523         * If we've missed a packet, we must toss subsequent compressed
1524         * packets which don't have an explicit connection ID.
1525         */
1526        if (sc->sc_comp)
1527            vj_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp);
1528        s = splimp();
1529        sc->sc_flags &= ~SC_VJ_RESET;
1530        splx(s);
1531    }
1532
1533    /*
1534     * See if we have a VJ-compressed packet to uncompress.
1535     */
1536    if (proto == PPP_VJC_COMP) {
1537        if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
1538            goto bad;
1539
1540        xlen = vj_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
1541                                      ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP,
1542                                      sc->sc_comp, &iphdr, &hlen);
1543
1544        if (xlen <= 0) {
1545            if (sc->sc_flags & SC_DEBUG)
1546                printf("ppp%d: VJ uncompress failed on type comp\n",
1547                        ifp->if_unit);
1548            goto bad;
1549        }
1550
1551        /* Copy the PPP and IP headers into a new mbuf. */
1552        MGETHDR(mp, M_DONTWAIT, MT_DATA);
1553        if (mp == NULL)
1554            goto bad;
1555        mp->m_len = 0;
1556        mp->m_next = NULL;
1557        if (hlen + PPP_HDRLEN > MHLEN) {
1558            MCLGET(mp, M_DONTWAIT);
1559            if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) {
1560                m_freem(mp);
1561                goto bad;       /* lose if big headers and no clusters */
1562            }
1563        }
1564#ifdef MAC
1565        mac_create_mbuf_from_mbuf(m, mp);
1566#endif
1567        cp = mtod(mp, u_char *);
1568        cp[0] = adrs;
1569        cp[1] = ctrl;
1570        cp[2] = 0;
1571        cp[3] = PPP_IP;
1572        proto = PPP_IP;
1573        bcopy(iphdr, cp + PPP_HDRLEN, hlen);
1574        mp->m_len = hlen + PPP_HDRLEN;
1575
1576        /*
1577         * Trim the PPP and VJ headers off the old mbuf
1578         * and stick the new and old mbufs together.
1579         */
1580        m->m_data += PPP_HDRLEN + xlen;
1581        m->m_len -= PPP_HDRLEN + xlen;
1582        if (m->m_len <= M_TRAILINGSPACE(mp)) {
1583            bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len);
1584            mp->m_len += m->m_len;
1585            MFREE(m, mp->m_next);
1586        } else
1587            mp->m_next = m;
1588        m = mp;
1589        ilen += hlen - xlen;
1590
1591    } else if (proto == PPP_VJC_UNCOMP) {
1592        if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
1593            goto bad;
1594
1595        xlen = vj_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
1596                                      ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP,
1597                                      sc->sc_comp, &iphdr, &hlen);
1598
1599        if (xlen < 0) {
1600            if (sc->sc_flags & SC_DEBUG)
1601                printf("ppp%d: VJ uncompress failed on type uncomp\n",
1602                        ifp->if_unit);
1603            goto bad;
1604        }
1605
1606        proto = PPP_IP;
1607        cp[3] = PPP_IP;
1608    }
1609#endif /* VJC */
1610
1611    /*
1612     * If the packet will fit in a header mbuf, don't waste a
1613     * whole cluster on it.
1614     */
1615    if (ilen <= MHLEN && M_IS_CLUSTER(m)) {
1616        MGETHDR(mp, M_DONTWAIT, MT_DATA);
1617        if (mp != NULL) {
1618            m_copydata(m, 0, ilen, mtod(mp, caddr_t));
1619            /* instead of freeing - return cluster mbuf so it can be reused */
1620            /* m_freem(m); */
1621            mf = m;
1622            m = mp;
1623            m->m_len = ilen;
1624        }
1625    }
1626    m->m_pkthdr.len = ilen;
1627    m->m_pkthdr.rcvif = ifp;
1628
1629    if ((proto & 0x8000) == 0) {
1630#ifdef PPP_FILTER
1631        /*
1632         * See whether we want to pass this packet, and
1633         * if it counts as link activity.
1634         */
1635        adrs = *mtod(m, u_char *);      /* save address field */
1636        *mtod(m, u_char *) = 0;         /* indicate inbound */
1637        if (sc->sc_pass_filt.bf_insns != 0
1638            && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m,
1639                          ilen, 0) == 0) {
1640            /* drop this packet */
1641            m_freem(m);
1642            return mf;
1643        }
1644        if (sc->sc_active_filt.bf_insns == 0
1645            || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0))
1646            sc->sc_last_recv = time.tv_sec;
1647
1648        *mtod(m, u_char *) = adrs;
1649#else
1650        /*
1651         * Record the time that we received this packet.
1652         */
1653        microtime(&ppp_time);
1654        sc->sc_last_recv = ppp_time.tv_sec;
1655#endif /* PPP_FILTER */
1656    }
1657
1658#if NBPFILTER > 0
1659    /* See if bpf wants to look at the packet. */
1660    if (sc->sc_bpf)
1661        bpf_mtap(sc->sc_bpf, m);
1662#endif
1663
1664    rv = 0;
1665    switch (proto) {
1666#ifdef INET
1667    case PPP_IP:
1668        /*
1669         * IP packet - take off the ppp header and pass it up to IP.
1670         */
1671        if ((ifp->if_flags & IFF_UP) == 0
1672            || sc->sc_npmode[NP_IP] != NPMODE_PASS) {
1673            /* interface is down - drop the packet. */
1674            m_freem(m);
1675            return mf;
1676        }
1677        m->m_pkthdr.len -= PPP_HDRLEN;
1678        m->m_data += PPP_HDRLEN;
1679        m->m_len -= PPP_HDRLEN;
1680        schednetisr(NETISR_IP);
1681        inq = &ipintrq;
1682        break;
1683#endif
1684
1685    default:
1686        /*
1687         * Some other protocol - place on input queue for read().
1688         */
1689        inq = &sc->sc_inq;
1690        rv = 1;
1691        break;
1692    }
1693
1694    /*
1695     * Put the packet on the appropriate input queue.
1696     */
1697    s = splimp();
1698    if (IF_QFULL(inq)) {
1699        IF_DROP(inq);
1700        splx(s);
1701        if (sc->sc_flags & SC_DEBUG)
1702            printf("ppp%d: input queue full\n", ifp->if_unit);
1703        ifp->if_iqdrops++;
1704        goto bad;
1705    }
1706    IF_ENQUEUE(inq, m);
1707    splx(s);
1708
1709    ifp->if_ipackets++;
1710    ifp->if_ibytes += ilen;
1711    microtime(&ppp_time);
1712    ifp->if_lastchange = ppp_time;
1713
1714    if (rv) {
1715      (*sc->sc_ctlp)(sc);
1716    }
1717
1718    return mf;
1719
1720 bad:
1721    m_freem(m);
1722    sc->sc_if.if_ierrors++;
1723    sc->sc_stats.ppp_ierrors++;
1724    return mf;
1725}
1726
1727#define MAX_DUMP_BYTES  128
1728
1729static void
1730pppdumpm(m0)
1731    struct mbuf *m0;
1732{
1733    char buf[3*MAX_DUMP_BYTES+4];
1734    char *bp = buf;
1735    struct mbuf *m;
1736    static char digits[] = "0123456789abcdef";
1737
1738    for (m = m0; m; m = m->m_next) {
1739        int l = m->m_len;
1740        u_char *rptr = (u_char *)m->m_data;
1741
1742        while (l--) {
1743            if (bp > buf + sizeof(buf) - 4)
1744                goto done;
1745            *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1746            *bp++ = digits[*rptr++ & 0xf];
1747        }
1748
1749        if (m->m_next) {
1750            if (bp > buf + sizeof(buf) - 3)
1751                goto done;
1752            *bp++ = '|';
1753        } else
1754            *bp++ = ' ';
1755    }
1756done:
1757    if (m)
1758        *bp++ = '>';
1759    *bp = 0;
1760    printf("%s\n", buf);
1761}
1762
1763#endif  /* NPPP > 0 */
Note: See TracBrowser for help on using the repository browser.