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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [ppp/] [current/] [src/] [if_ppp.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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