source: rtems/cpukit/libnetworking/net/if_ppp.c @ 36799d4

4.104.114.84.95
Last change on this file since 36799d4 was 36799d4, checked in by Joel Sherrill <joel.sherrill@…>, on 01/03/03 at 18:09:57

2002-11-26 Chris Johns <cjohns@…>

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