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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [bsd_tcpip/] [current/] [src/] [sys/] [netinet/] [ip_encap.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      src/sys/netinet/ip_encap.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 
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) 2002 Free Software Foundation, Inc.            
16
// -------------------------------------------                  
17
// ####BSDCOPYRIGHTEND####                                      
18
//==========================================================================
19
 
20
/*      $KAME: ip_encap.c,v 1.73 2001/10/02 08:30:58 itojun Exp $       */
21
 
22
/*
23
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
24
 * All rights reserved.
25
 *
26
 * Redistribution and use in source and binary forms, with or without
27
 * modification, are permitted provided that the following conditions
28
 * are met:
29
 * 1. Redistributions of source code must retain the above copyright
30
 *    notice, this list of conditions and the following disclaimer.
31
 * 2. Redistributions in binary form must reproduce the above copyright
32
 *    notice, this list of conditions and the following disclaimer in the
33
 *    documentation and/or other materials provided with the distribution.
34
 * 3. Neither the name of the project nor the names of its contributors
35
 *    may be used to endorse or promote products derived from this software
36
 *    without specific prior written permission.
37
 *
38
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
39
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
42
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48
 * SUCH DAMAGE.
49
 */
50
/*
51
 * My grandfather said that there's a devil inside tunnelling technology...
52
 *
53
 * We have surprisingly many protocols that want packets with IP protocol
54
 * #4 or #41.  Here's a list of protocols that want protocol #41:
55
 *      RFC1933 configured tunnel
56
 *      RFC1933 automatic tunnel
57
 *      RFC2401 IPsec tunnel
58
 *      RFC2473 IPv6 generic packet tunnelling
59
 *      RFC2529 6over4 tunnel
60
 *      RFC3056 6to4 tunnel
61
 *      isatap tunnel
62
 *      mobile-ip6 (uses RFC2473)
63
 * Here's a list of protocol that want protocol #4:
64
 *      RFC1853 IPv4-in-IPv4 tunnelling
65
 *      RFC2003 IPv4 encapsulation within IPv4
66
 *      RFC2344 reverse tunnelling for mobile-ip4
67
 *      RFC2401 IPsec tunnel
68
 * Well, what can I say.  They impose different en/decapsulation mechanism
69
 * from each other, so they need separate protocol handler.  The only one
70
 * we can easily determine by protocol # is IPsec, which always has
71
 * AH/ESP/IPComp header right after outer IP header.
72
 *
73
 * So, clearly good old protosw does not work for protocol #4 and #41.
74
 * The code will let you match protocol via src/dst address pair.
75
 */
76
/* XXX is M_NETADDR correct? */
77
 
78
/*
79
 * With USE_RADIX the code will use radix table for tunnel lookup, for
80
 * tunnels registered with encap_attach() with a addr/mask pair.
81
 * Faster on machines with thousands of tunnel registerations (= interfaces).
82
 *
83
 * The code assumes that radix table code can handle non-continuous netmask,
84
 * as it will pass radix table memory region with (src + dst) sockaddr pair.
85
 *
86
 * FreeBSD is excluded here as they make max_keylen a static variable, and
87
 * thus forbid definition of radix table other than proper domains.
88
 */
89
#include <sys/param.h>
90
#include <sys/socket.h>
91
#include <sys/sockio.h>
92
#include <sys/mbuf.h>
93
#include <sys/errno.h>
94
#include <sys/protosw.h>
95
#include <sys/queue.h>
96
 
97
#include <net/if.h>
98
#include <net/route.h>
99
 
100
#include <netinet/in.h>
101
#include <netinet/in_systm.h>
102
#include <netinet/ip.h>
103
#include <netinet/ip_var.h>
104
#include <netinet/ip_encap.h>
105
#ifdef MROUTING
106
#include <netinet/ip_mroute.h>
107
#endif /* MROUTING */
108
#ifdef __OpenBSD__
109
#include <netinet/ip_ipsp.h>
110
#endif
111
 
112
#ifdef INET6
113
#include <netinet/ip6.h>
114
#include <netinet6/ip6_var.h>
115
#include <netinet6/ip6protosw.h>
116
#include <netinet6/in6_var.h>
117
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)
118
#include <netinet/in_pcb.h>
119
#else
120
#include <netinet6/in6_pcb.h>
121
#endif
122
#include <netinet/icmp6.h>
123
#endif
124
 
125
#include <stdarg.h>
126
#include <sys/malloc.h>
127
 
128
/* to lookup a pair of address using radix tree */
129
struct sockaddr_pack {
130
        u_int8_t sp_len;
131
        u_int8_t sp_family;     /* not really used */
132
        /* followed by variable-length data */
133
} __attribute__((__packed__));
134
 
135
struct pack4 {
136
        struct sockaddr_pack p;
137
        struct sockaddr_in mine;
138
        struct sockaddr_in yours;
139
} __attribute__((__packed__));
140
struct pack6 {
141
        struct sockaddr_pack p;
142
        struct sockaddr_in6 mine;
143
        struct sockaddr_in6 yours;
144
} __attribute__((__packed__));
145
 
146
enum direction { INBOUND, OUTBOUND };
147
 
148
#ifdef INET
149
static struct encaptab *encap4_lookup __P((struct mbuf *, int, int,
150
        enum direction));
151
#endif
152
#ifdef INET6
153
static struct encaptab *encap6_lookup __P((struct mbuf *, int, int,
154
        enum direction));
155
#endif
156
static int encap_add __P((struct encaptab *));
157
static int encap_remove __P((struct encaptab *));
158
static int encap_afcheck __P((int, const struct sockaddr *, const struct sockaddr *));
159
#ifdef USE_RADIX
160
static struct radix_node_head *encap_rnh __P((int));
161
static int mask_matchlen __P((const struct sockaddr *));
162
#endif
163
#ifndef USE_RADIX
164
static int mask_match __P((const struct encaptab *, const struct sockaddr *,
165
                const struct sockaddr *));
166
#endif
167
static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
168
 
169
#ifndef LIST_HEAD_INITIALIZER
170
/* rely upon BSS initialization */
171
LIST_HEAD(, encaptab) encaptab;
172
#else
173
LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
174
#endif
175
 
176
#ifdef USE_RADIX
177
extern int max_keylen;  /* radix.c */
178
struct radix_node_head *encap_head[2];  /* 0 for AF_INET, 1 for AF_INET6 */
179
#endif
180
 
181
void
182
encap_init()
183
{
184
        static int initialized = 0;
185
 
186
        if (initialized)
187
                return;
188
        initialized++;
189
#if 0
190
        /*
191
         * we cannot use LIST_INIT() here, since drivers may want to call
192
         * encap_attach(), on driver attach.  encap_init() will be called
193
         * on AF_INET{,6} initialization, which happens after driver
194
         * initialization - using LIST_INIT() here can nuke encap_attach()
195
         * from drivers.
196
         */
197
        LIST_INIT(&encaptab);
198
#endif
199
 
200
#ifdef USE_RADIX
201
        /*
202
         * initialize radix lookup table.
203
         * max_keylen initialization should happen before the call to rn_init().
204
         */
205
        rn_inithead((void **)&encap_head[0], sizeof(struct sockaddr_pack) << 3);
206
        if (sizeof(struct pack4) > max_keylen)
207
                max_keylen = sizeof(struct pack4);
208
#ifdef INET6
209
        rn_inithead((void **)&encap_head[1], sizeof(struct sockaddr_pack) << 3);
210
        if (sizeof(struct pack6) > max_keylen)
211
                max_keylen = sizeof(struct pack6);
212
#endif
213
#endif
214
}
215
 
216
#ifdef INET
217
static struct encaptab *
218
encap4_lookup(m, off, proto, dir)
219
        struct mbuf *m;
220
        int off;
221
        int proto;
222
        enum direction dir;
223
{
224
        struct ip *ip;
225
        struct pack4 pack;
226
        struct encaptab *ep, *match;
227
        int prio, matchprio;
228
#ifdef USE_RADIX
229
        struct radix_node_head *rnh = encap_rnh(AF_INET);
230
        struct radix_node *rn;
231
#endif
232
 
233
#ifdef DIAGNOSTIC
234
        if (m->m_len < sizeof(*ip))
235
                panic("encap4_lookup");
236
#endif
237
        ip = mtod(m, struct ip *);
238
 
239
        bzero(&pack, sizeof(pack));
240
        pack.p.sp_len = sizeof(pack);
241
        pack.mine.sin_family = pack.yours.sin_family = AF_INET;
242
        pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in);
243
        if (dir == INBOUND) {
244
                pack.mine.sin_addr = ip->ip_dst;
245
                pack.yours.sin_addr = ip->ip_src;
246
        } else {
247
                pack.mine.sin_addr = ip->ip_src;
248
                pack.yours.sin_addr = ip->ip_dst;
249
        }
250
 
251
        match = NULL;
252
        matchprio = 0;
253
 
254
#ifdef USE_RADIX
255
        rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
256
        if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
257
                match = (struct encaptab *)rn;
258
                matchprio = mask_matchlen(match->srcmask) +
259
                    mask_matchlen(match->dstmask);
260
        }
261
#endif
262
 
263
        for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
264
                if (ep->af != AF_INET)
265
                        continue;
266
                if (ep->proto >= 0 && ep->proto != proto)
267
                        continue;
268
                if (ep->func)
269
                        prio = (*ep->func)(m, off, proto, ep->arg);
270
                else {
271
#ifdef USE_RADIX
272
                        continue;
273
#else
274
                        prio = mask_match(ep, (struct sockaddr *)&pack.mine,
275
                            (struct sockaddr *)&pack.yours);
276
#endif
277
                }
278
 
279
                /*
280
                 * We prioritize the matches by using bit length of the
281
                 * matches.  mask_match() and user-supplied matching function
282
                 * should return the bit length of the matches (for example,
283
                 * if both src/dst are matched for IPv4, 64 should be returned).
284
                 * 0 or negative return value means "it did not match".
285
                 *
286
                 * The question is, since we have two "mask" portion, we
287
                 * cannot really define total order between entries.
288
                 * For example, which of these should be preferred?
289
                 * mask_match() returns 48 (32 + 16) for both of them.
290
                 *      src=3ffe::/16, dst=3ffe:501::/32
291
                 *      src=3ffe:501::/32, dst=3ffe::/16
292
                 *
293
                 * We need to loop through all the possible candidates
294
                 * to get the best match - the search takes O(n) for
295
                 * n attachments (i.e. interfaces).
296
                 *
297
                 * For radix-based lookup, I guess source takes precedence.
298
                 * See rn_{refines,lexobetter} for the correct answer.
299
                 */
300
                if (prio <= 0)
301
                        continue;
302
                if (prio > matchprio) {
303
                        matchprio = prio;
304
                        match = ep;
305
                }
306
        }
307
 
308
        return match;
309
#undef s
310
#undef d
311
}
312
 
313
void
314
#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)
315
encap4_input(struct mbuf *m, int off)
316
#else
317
#if __STDC__
318
encap4_input(struct mbuf *m, ...)
319
#else
320
encap4_input(m, va_alist)
321
        struct mbuf *m;
322
        va_dcl
323
#endif
324
#endif /* (defined(__FreeBSD__) && __FreeBSD__ >= 4) */
325
{
326
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)
327
        int off, proto;
328
        va_list ap;
329
#else
330
        int proto;
331
#endif /* !(defined(__FreeBSD__) && __FreeBSD__ >= 4) */
332
        const struct protosw *psw;
333
        struct encaptab *match;
334
 
335
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)
336
        va_start(ap, m);
337
        off = va_arg(ap, int);
338
#if !defined(__OpenBSD__)
339
        proto = va_arg(ap, int);
340
#endif
341
        va_end(ap);
342
#endif /* !(defined(__FreeBSD__) && __FreeBSD__ >= 4) */
343
 
344
#if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
345
        proto = mtod(m, struct ip *)->ip_p;
346
#endif
347
 
348
        match = encap4_lookup(m, off, proto, INBOUND);
349
 
350
        if (match) {
351
                /* found a match, "match" has the best one */
352
                psw = match->psw;
353
                if (psw && psw->pr_input) {
354
                        encap_fillarg(m, match);
355
#if defined(__FreeBSD__) && __FreeBSD__ >= 4
356
                        (*psw->pr_input)(m, off);
357
#else
358
                        (*psw->pr_input)(m, off, proto);
359
#endif
360
                } else
361
                        m_freem(m);
362
                return;
363
        }
364
 
365
        /* for backward compatibility - messy... */
366
#if defined(__NetBSD__)
367
        /* last resort: inject to raw socket */
368
        rip_input(m, off, proto);
369
#elif defined(__OpenBSD__)
370
# if defined(MROUTING) || defined(IPSEC)
371
        if (proto == IPPROTO_IPV4) {
372
                ip4_input(m, off, proto);
373
                return;
374
        }
375
# endif
376
 
377
        /* last resort: inject to raw socket */
378
        rip_input(m, off, proto);
379
#elif (defined(__FreeBSD__) && __FreeBSD__ >= 5)
380
        /* last resort: inject to raw socket */
381
        rip_input(m, off);
382
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
383
#ifdef MROUTING
384
        if (proto == IPPROTO_IPV4) {
385
                ipip_input(m, off);
386
                return;
387
        }
388
#endif
389
 
390
        /* last resort: inject to raw socket */
391
        rip_input(m, off);
392
#else
393
#ifdef MROUTING
394
        if (proto == IPPROTO_IPV4) {
395
                ipip_input(m, off, proto);
396
                return;
397
        }
398
#endif
399
 
400
        /* last resort: inject to raw socket */
401
        rip_input(m, off, proto);
402
#endif
403
}
404
#endif
405
 
406
#ifdef INET6
407
static struct encaptab *
408
encap6_lookup(m, off, proto, dir)
409
        struct mbuf *m;
410
        int off;
411
        int proto;
412
        enum direction dir;
413
{
414
        struct ip6_hdr *ip6;
415
        struct pack6 pack;
416
        int prio, matchprio;
417
        struct encaptab *ep, *match;
418
#ifdef USE_RADIX
419
        struct radix_node_head *rnh = encap_rnh(AF_INET6);
420
        struct radix_node *rn;
421
#endif
422
 
423
#ifdef DIAGNOSTIC
424
        if (m->m_len < sizeof(*ip6))
425
                panic("encap6_lookup");
426
#endif
427
        ip6 = mtod(m, struct ip6_hdr *);
428
 
429
        bzero(&pack, sizeof(pack));
430
        pack.p.sp_len = sizeof(pack);
431
        pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6;
432
        pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6);
433
        if (dir == INBOUND) {
434
                pack.mine.sin6_addr = ip6->ip6_dst;
435
                pack.yours.sin6_addr = ip6->ip6_src;
436
        } else {
437
                pack.mine.sin6_addr = ip6->ip6_src;
438
                pack.yours.sin6_addr = ip6->ip6_dst;
439
        }
440
 
441
        match = NULL;
442
        matchprio = 0;
443
 
444
#ifdef USE_RADIX
445
        rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
446
        if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
447
                match = (struct encaptab *)rn;
448
                matchprio = mask_matchlen(match->srcmask) +
449
                    mask_matchlen(match->dstmask);
450
        }
451
#endif
452
 
453
        for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
454
                if (ep->af != AF_INET6)
455
                        continue;
456
                if (ep->proto >= 0 && ep->proto != proto)
457
                        continue;
458
                if (ep->func)
459
                        prio = (*ep->func)(m, off, proto, ep->arg);
460
                else {
461
#ifdef USE_RADIX
462
                        continue;
463
#else
464
                        prio = mask_match(ep, (struct sockaddr *)&pack.mine,
465
                            (struct sockaddr *)&pack.yours);
466
#endif
467
                }
468
 
469
                /* see encap4_lookup() for issues here */
470
                if (prio <= 0)
471
                        continue;
472
                if (prio > matchprio) {
473
                        matchprio = prio;
474
                        match = ep;
475
                }
476
        }
477
 
478
        return match;
479
#undef s
480
#undef d
481
}
482
 
483
int
484
encap6_input(mp, offp, proto)
485
        struct mbuf **mp;
486
        int *offp;
487
        int proto;
488
{
489
        struct mbuf *m = *mp;
490
        const struct ip6protosw *psw;
491
        struct encaptab *match;
492
 
493
        match = encap6_lookup(m, *offp, proto, INBOUND);
494
 
495
        if (match) {
496
                /* found a match */
497
                psw = (const struct ip6protosw *)match->psw;
498
                if (psw && psw->pr_input) {
499
                        encap_fillarg(m, match);
500
                        return (*psw->pr_input)(mp, offp, proto);
501
                } else {
502
                        m_freem(m);
503
                        return IPPROTO_DONE;
504
                }
505
        }
506
 
507
#ifdef __OpenBSD__
508
        /* last resort */
509
        return ip4_input6(mp, offp, 0); /* XXX last argument ignored */
510
#else
511
        /* last resort: inject to raw socket */
512
        return rip6_input(mp, offp, proto);
513
#endif
514
}
515
#endif
516
 
517
static int
518
encap_add(ep)
519
        struct encaptab *ep;
520
{
521
#ifdef USE_RADIX
522
        struct radix_node_head *rnh = encap_rnh(ep->af);
523
#endif
524
        int error = 0;
525
 
526
        LIST_INSERT_HEAD(&encaptab, ep, chain);
527
#ifdef USE_RADIX
528
        if (!ep->func && rnh) {
529
                if (!rnh->rnh_addaddr((caddr_t)ep->addrpack,
530
                    (caddr_t)ep->maskpack, rnh, ep->nodes)) {
531
                        error = EEXIST;
532
                        goto fail;
533
                }
534
        }
535
#endif
536
        return error;
537
 
538
#ifdef USE_RADIX
539
 fail:
540
        LIST_REMOVE(ep, chain);
541
        return error;
542
#endif
543
}
544
 
545
static int
546
encap_remove(ep)
547
        struct encaptab *ep;
548
{
549
#ifdef USE_RADIX
550
        struct radix_node_head *rnh = encap_rnh(ep->af);
551
#endif
552
        int error = 0;
553
 
554
        LIST_REMOVE(ep, chain);
555
#ifdef USE_RADIX
556
        if (!ep->func && rnh) {
557
                if (!rnh->rnh_deladdr((caddr_t)ep->addrpack,
558
                    (caddr_t)ep->maskpack, rnh))
559
                        error = ESRCH;
560
        }
561
#endif
562
        return error;
563
}
564
 
565
static int
566
encap_afcheck(af, sp, dp)
567
        int af;
568
        const struct sockaddr *sp;
569
        const struct sockaddr *dp;
570
{
571
        if (sp && dp) {
572
                if (sp->sa_len != dp->sa_len)
573
                        return EINVAL;
574
                if (af != sp->sa_family || af != dp->sa_family)
575
                        return EINVAL;
576
        } else if (!sp && !dp)
577
                ;
578
        else
579
                return EINVAL;
580
 
581
        switch (af) {
582
        case AF_INET:
583
                if (sp && sp->sa_len != sizeof(struct sockaddr_in))
584
                        return EINVAL;
585
                if (dp && dp->sa_len != sizeof(struct sockaddr_in))
586
                        return EINVAL;
587
                break;
588
#ifdef INET6
589
        case AF_INET6:
590
                if (sp && sp->sa_len != sizeof(struct sockaddr_in6))
591
                        return EINVAL;
592
                if (dp && dp->sa_len != sizeof(struct sockaddr_in6))
593
                        return EINVAL;
594
                break;
595
#endif
596
        default:
597
                return EAFNOSUPPORT;
598
        }
599
 
600
        return 0;
601
}
602
 
603
/*
604
 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
605
 * length of mask (sm and dm) is assumed to be same as sp/dp.
606
 * Return value will be necessary as input (cookie) for encap_detach().
607
 */
608
const struct encaptab *
609
encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
610
        int af;
611
        int proto;
612
        const struct sockaddr *sp, *sm;
613
        const struct sockaddr *dp, *dm;
614
        const struct protosw *psw;
615
        void *arg;
616
{
617
        struct encaptab *ep;
618
        int error;
619
        int s;
620
        size_t l;
621
        struct pack4 *pack4;
622
#ifdef INET6
623
        struct pack6 *pack6;
624
#endif
625
 
626
#if defined(__NetBSD__) || defined(__OpenBSD__)
627
        s = splsoftnet();
628
#else
629
        s = splnet();
630
#endif
631
        /* sanity check on args */
632
        error = encap_afcheck(af, sp, dp);
633
        if (error)
634
                goto fail;
635
 
636
        /* check if anyone have already attached with exactly same config */
637
        for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
638
                if (ep->af != af)
639
                        continue;
640
                if (ep->proto != proto)
641
                        continue;
642
                if (ep->func)
643
                        continue;
644
#ifdef DIAGNOSTIC
645
                if (!ep->src || !ep->dst || !ep->srcmask || !ep->dstmask)
646
                        panic("null pointers in encaptab");
647
#endif
648
                if (ep->src->sa_len != sp->sa_len ||
649
                    bcmp(ep->src, sp, sp->sa_len) != 0 ||
650
                    bcmp(ep->srcmask, sm, sp->sa_len) != 0)
651
                        continue;
652
                if (ep->dst->sa_len != dp->sa_len ||
653
                    bcmp(ep->dst, dp, dp->sa_len) != 0 ||
654
                    bcmp(ep->dstmask, dm, dp->sa_len) != 0)
655
                        continue;
656
 
657
                error = EEXIST;
658
                goto fail;
659
        }
660
 
661
        switch (af) {
662
        case AF_INET:
663
                l = sizeof(*pack4);
664
                break;
665
#ifdef INET6
666
        case AF_INET6:
667
                l = sizeof(*pack6);
668
                break;
669
#endif
670
        default:
671
                goto fail;
672
        }
673
 
674
#ifdef DIAGNOSTIC
675
        /* if l exceeds the value sa_len can possibly express, it's wrong. */
676
        if (l > (1 << (8 * sizeof(ep->addrpack->sa_len)))) {
677
                error = EINVAL;
678
                goto fail;
679
        }
680
#endif
681
 
682
        ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);  /* M_NETADDR ok? */
683
        if (ep == NULL) {
684
                error = ENOBUFS;
685
                goto fail;
686
        }
687
        bzero(ep, sizeof(*ep));
688
        ep->addrpack = malloc(l, M_NETADDR, M_NOWAIT);
689
        if (ep->addrpack == NULL) {
690
                error = ENOBUFS;
691
                goto gc;
692
        }
693
        ep->maskpack = malloc(l, M_NETADDR, M_NOWAIT);
694
        if (ep->maskpack == NULL) {
695
                error = ENOBUFS;
696
                goto gc;
697
        }
698
 
699
        ep->af = af;
700
        ep->proto = proto;
701
        ep->addrpack->sa_len = l & 0xff;
702
        ep->maskpack->sa_len = l & 0xff;
703
        switch (af) {
704
        case AF_INET:
705
                pack4 = (struct pack4 *)ep->addrpack;
706
                ep->src = (struct sockaddr *)&pack4->mine;
707
                ep->dst = (struct sockaddr *)&pack4->yours;
708
                pack4 = (struct pack4 *)ep->maskpack;
709
                ep->srcmask = (struct sockaddr *)&pack4->mine;
710
                ep->dstmask = (struct sockaddr *)&pack4->yours;
711
                break;
712
#ifdef INET6
713
        case AF_INET6:
714
                pack6 = (struct pack6 *)ep->addrpack;
715
                ep->src = (struct sockaddr *)&pack6->mine;
716
                ep->dst = (struct sockaddr *)&pack6->yours;
717
                pack6 = (struct pack6 *)ep->maskpack;
718
                ep->srcmask = (struct sockaddr *)&pack6->mine;
719
                ep->dstmask = (struct sockaddr *)&pack6->yours;
720
                break;
721
#endif
722
        }
723
 
724
        bcopy(sp, ep->src, sp->sa_len);
725
        bcopy(sm, ep->srcmask, sp->sa_len);
726
        bcopy(dp, ep->dst, dp->sa_len);
727
        bcopy(dm, ep->dstmask, dp->sa_len);
728
        ep->psw = psw;
729
        ep->arg = arg;
730
 
731
        error = encap_add(ep);
732
        if (error)
733
                goto gc;
734
 
735
        error = 0;
736
        splx(s);
737
        return ep;
738
 
739
gc:
740
        if (ep->addrpack)
741
                free(ep->addrpack, M_NETADDR);
742
        if (ep->maskpack)
743
                free(ep->maskpack, M_NETADDR);
744
        if (ep)
745
                free(ep, M_NETADDR);
746
fail:
747
        splx(s);
748
        return NULL;
749
}
750
 
751
const struct encaptab *
752
encap_attach_func(af, proto, func, psw, arg)
753
        int af;
754
        int proto;
755
        int (*func) __P((const struct mbuf *, int, int, void *));
756
        const struct protosw *psw;
757
        void *arg;
758
{
759
        struct encaptab *ep;
760
        int error;
761
        int s;
762
 
763
#if defined(__NetBSD__) || defined(__OpenBSD__)
764
        s = splsoftnet();
765
#else
766
        s = splnet();
767
#endif
768
        /* sanity check on args */
769
        if (!func) {
770
                error = EINVAL;
771
                goto fail;
772
        }
773
 
774
        error = encap_afcheck(af, NULL, NULL);
775
        if (error)
776
                goto fail;
777
 
778
        ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);  /*XXX*/
779
        if (ep == NULL) {
780
                error = ENOBUFS;
781
                goto fail;
782
        }
783
        bzero(ep, sizeof(*ep));
784
 
785
        ep->af = af;
786
        ep->proto = proto;
787
        ep->func = func;
788
        ep->psw = psw;
789
        ep->arg = arg;
790
 
791
        error = encap_add(ep);
792
        if (error)
793
                goto fail;
794
 
795
        error = 0;
796
        splx(s);
797
        return ep;
798
 
799
fail:
800
        splx(s);
801
        return NULL;
802
}
803
 
804
/* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */
805
 
806
#ifdef INET6
807
#if defined(HAVE_NRL_INPCB) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
808
#undef in6_rtchange
809
#define in6_rtchange    in_rtchange
810
#define in6pcb          inpcb
811
#endif
812
 
813
void
814
encap6_ctlinput(cmd, sa, d0)
815
        int cmd;
816
        struct sockaddr *sa;
817
        void *d0;
818
{
819
        void *d = d0;
820
        struct ip6_hdr *ip6 CYGBLD_ATTRIB_UNUSED;
821
        struct mbuf *m CYGBLD_ATTRIB_UNUSED;
822
        int off CYGBLD_ATTRIB_UNUSED;
823
        struct ip6ctlparam *ip6cp = NULL;
824
        int nxt;
825
        struct encaptab *ep;
826
        const struct ip6protosw *psw;
827
 
828
        if (sa->sa_family != AF_INET6 ||
829
            sa->sa_len != sizeof(struct sockaddr_in6))
830
                return;
831
 
832
        if ((unsigned)cmd >= PRC_NCMDS)
833
                return;
834
        if (cmd == PRC_HOSTDEAD)
835
                d = NULL;
836
#if defined(__NetBSD__) || defined(__OpenBSD__)
837
        else if (cmd == PRC_MSGSIZE)
838
                ; /* special code is present, see below */
839
#endif
840
        else if (inet6ctlerrmap[cmd] == 0)
841
                return;
842
 
843
        /* if the parameter is from icmp6, decode it. */
844
        if (d != NULL) {
845
                ip6cp = (struct ip6ctlparam *)d;
846
                m = ip6cp->ip6c_m;
847
                ip6 = ip6cp->ip6c_ip6;
848
                off = ip6cp->ip6c_off;
849
                nxt = ip6cp->ip6c_nxt;
850
        } else {
851
                m = NULL;
852
                ip6 = NULL;
853
                nxt = -1;
854
        }
855
 
856
#if defined(__NetBSD__) || defined(__OpenBSD__)
857
        if (ip6 && cmd == PRC_MSGSIZE) {
858
                int valid = 0;
859
                struct encaptab *match;
860
 
861
                /*
862
                 * Check to see if we have a valid encap configuration.
863
                 */
864
                match = encap6_lookup(m, off, nxt, OUTBOUND);
865
 
866
                if (match)
867
                        valid++;
868
 
869
                /*
870
                 * Depending on the value of "valid" and routing table
871
                 * size (mtudisc_{hi,lo}wat), we will:
872
                 * - recalcurate the new MTU and create the
873
                 *   corresponding routing entry, or
874
                 * - ignore the MTU change notification.
875
                 */
876
                icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
877
        }
878
#endif
879
 
880
        /* inform all listeners */
881
        for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
882
                if (ep->af != AF_INET6)
883
                        continue;
884
                if (ep->proto >= 0 && ep->proto != nxt)
885
                        continue;
886
 
887
                /* should optimize by looking at address pairs */
888
 
889
                /* XXX need to pass ep->arg or ep itself to listeners */
890
                psw = (const struct ip6protosw *)ep->psw;
891
                if (psw && psw->pr_ctlinput)
892
                        (*psw->pr_ctlinput)(cmd, sa, d);
893
        }
894
 
895
        rip6_ctlinput(cmd, sa, d0);
896
}
897
#endif
898
 
899
int
900
encap_detach(cookie)
901
        const struct encaptab *cookie;
902
{
903
        const struct encaptab *ep = cookie;
904
        struct encaptab *p;
905
        int error;
906
 
907
        for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
908
                if (p == ep) {
909
                        error = encap_remove(p);
910
                        if (error)
911
                                return error;
912
                        if (!ep->func) {
913
                                free(p->addrpack, M_NETADDR);
914
                                free(p->maskpack, M_NETADDR);
915
                        }
916
                        free(p, M_NETADDR);     /*XXX*/
917
                        return 0;
918
                }
919
        }
920
 
921
        return ENOENT;
922
}
923
 
924
#ifdef USE_RADIX
925
static struct radix_node_head *
926
encap_rnh(af)
927
        int af;
928
{
929
 
930
        switch (af) {
931
        case AF_INET:
932
                return encap_head[0];
933
#ifdef INET6
934
        case AF_INET6:
935
                return encap_head[1];
936
#endif
937
        default:
938
                return NULL;
939
        }
940
}
941
 
942
static int
943
mask_matchlen(sa)
944
        const struct sockaddr *sa;
945
{
946
        const char *p, *ep;
947
        int l;
948
 
949
        p = (const char *)sa;
950
        ep = p + sa->sa_len;
951
        p += 2; /* sa_len + sa_family */
952
 
953
        l = 0;
954
        while (p < ep) {
955
                l += (*p ? 8 : 0);       /* estimate */
956
                p++;
957
        }
958
        return l;
959
}
960
#endif
961
 
962
#ifndef USE_RADIX
963
static int
964
mask_match(ep, sp, dp)
965
        const struct encaptab *ep;
966
        const struct sockaddr *sp;
967
        const struct sockaddr *dp;
968
{
969
        struct sockaddr_storage s;
970
        struct sockaddr_storage d;
971
        int i;
972
        const u_int8_t *p, *q;
973
        u_int8_t *r;
974
        int matchlen;
975
 
976
#ifdef DIAGNOSTIC
977
        if (ep->func)
978
                panic("wrong encaptab passed to mask_match");
979
#endif
980
        if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
981
                return 0;
982
        if (sp->sa_family != ep->af || dp->sa_family != ep->af)
983
                return 0;
984
        if (sp->sa_len != ep->src->sa_len || dp->sa_len != ep->dst->sa_len)
985
                return 0;
986
 
987
        matchlen = 0;
988
 
989
        p = (const u_int8_t *)sp;
990
        q = (const u_int8_t *)ep->srcmask;
991
        r = (u_int8_t *)&s;
992
        for (i = 0 ; i < sp->sa_len; i++) {
993
                r[i] = p[i] & q[i];
994
                /* XXX estimate */
995
                matchlen += (q[i] ? 8 : 0);
996
        }
997
 
998
        p = (const u_int8_t *)dp;
999
        q = (const u_int8_t *)ep->dstmask;
1000
        r = (u_int8_t *)&d;
1001
        for (i = 0 ; i < dp->sa_len; i++) {
1002
                r[i] = p[i] & q[i];
1003
                /* XXX rough estimate */
1004
                matchlen += (q[i] ? 8 : 0);
1005
        }
1006
 
1007
        /* need to overwrite len/family portion as we don't compare them */
1008
        s.ss_len = sp->sa_len;
1009
        s.ss_family = sp->sa_family;
1010
        d.ss_len = dp->sa_len;
1011
        d.ss_family = dp->sa_family;
1012
 
1013
        if (bcmp(&s, ep->src, ep->src->sa_len) == 0 &&
1014
            bcmp(&d, ep->dst, ep->dst->sa_len) == 0) {
1015
                return matchlen;
1016
        } else
1017
                return 0;
1018
}
1019
#endif
1020
 
1021
static void
1022
encap_fillarg(m, ep)
1023
        struct mbuf *m;
1024
        const struct encaptab *ep;
1025
{
1026
        struct mbuf *n;
1027
 
1028
        n = m_aux_add(m, AF_INET, IPPROTO_IPV4);
1029
        if (n) {
1030
                *mtod(n, void **) = ep->arg;
1031
                n->m_len = sizeof(void *);
1032
        }
1033
}
1034
 
1035
void *
1036
encap_getarg(m)
1037
        struct mbuf *m;
1038
{
1039
        void *p;
1040
        struct mbuf *n;
1041
 
1042
        p = NULL;
1043
        n = m_aux_find(m, AF_INET, IPPROTO_IPV4);
1044
        if (n) {
1045
                if (n->m_len == sizeof(void *))
1046
                        p = *mtod(n, void **);
1047
                m_aux_delete(m, n);
1048
        }
1049
        return p;
1050
}

powered by: WebSVN 2.1.0

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