OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libnetworking/] [net/] [if_ppp.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.