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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet/] [ip_encap.c] - Blame information for rev 307

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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