source: rtems/c/src/exec/libnetworking/net/if_ppp.c @ c52f1c7

4.104.114.84.95
Last change on this file since c52f1c7 was 0286b9f, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/02 at 21:42:11

2001-01-31 Mike Siers <mikes@…>

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