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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet6/] [ip6_forward.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/ip6_forward.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: ip6_forward.c,v 1.87 2001/12/18 01:30:43 keiichi 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
#include <sys/param.h>
54
#include <sys/malloc.h>
55
#include <sys/mbuf.h>
56
#include <sys/domain.h>
57
#include <sys/protosw.h>
58
#include <sys/socket.h>
59
#include <sys/errno.h>
60
 
61
#include <net/if.h>
62
#include <net/route.h>
63
 
64
#include <netinet/in.h>
65
#include <netinet/in_var.h>
66
#include <netinet/in_systm.h>
67
#include <netinet/ip.h>
68
#include <netinet/ip_var.h>
69
#include <netinet6/in6_var.h>
70
#include <netinet/ip6.h>
71
#include <netinet6/ip6_var.h>
72
#include <netinet/icmp6.h>
73
#include <netinet6/nd6.h>
74
 
75
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)
76
#include <netinet/in_pcb.h>
77
#endif
78
#if !((defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802))
79
#include <netinet6/in6_pcb.h>
80
#endif
81
 
82
#ifdef __OpenBSD__
83
#if NPF > 0
84
#include <net/pfvar.h>
85
#endif
86
#endif
87
 
88
#ifdef __OpenBSD__ /* KAME IPSEC */
89
#undef IPSEC
90
#endif
91
 
92
#ifdef IPSEC
93
#include <netinet6/ipsec.h>
94
#include <netkey/key.h>
95
#endif /* IPSEC */
96
 
97
#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
98
#include <netinet6/ip6_fw.h>
99
#endif
100
#if defined(__NetBSD__) && defined(PFIL_HOOKS)
101
#include <net/pfil.h>
102
#endif
103
 
104
#ifdef MIP6
105
#include <netinet6/mip6.h>
106
extern struct mip6_bc_list mip6_bc_list;
107
#endif /* MIP6 */
108
 
109
//#include <net/net_osdep.h>
110
 
111
#ifdef NEW_STRUCT_ROUTE
112
struct  route ip6_forward_rt;
113
#else
114
struct  route_in6 ip6_forward_rt;
115
#endif
116
 
117
#ifdef MEASURE_PERFORMANCE
118
#define OURS_CHECK_ALG_RTABLE 0 /* XXX: duplicated def. */
119
 
120
extern int ip6_logentry;
121
extern int ip6_logsize;
122
extern unsigned long long ip6_performance_log[];
123
extern long long ip6_performance_log2[];
124
extern int ip6_ours_check_algorithm;
125
 
126
int ip6_forward_cache_miss;
127
 
128
static unsigned long long ctr_beg, ctr_end;
129
 
130
static __inline unsigned long long read_tsc __P((void));
131
static __inline void add_performance_log2 __P((unsigned long long));
132
 
133
/* XXX: duplicated code */
134
static __inline unsigned long long
135
read_tsc(void)
136
{
137
     unsigned int h,l;
138
     /* read Pentium counter */
139
     __asm__(".byte 0x0f,0x31" :"=a" (l), "=d" (h));
140
     return ((unsigned long long)h<<32) | l;
141
}
142
 
143
static __inline void
144
add_performance_log2(val)
145
        unsigned long long val;
146
{
147
        ip6_performance_log[ip6_logentry] += val;
148
        ip6_performance_log2[ip6_logentry] = val;
149
}
150
#endif
151
 
152
/*
153
 * Forward a packet.  If some error occurs return the sender
154
 * an icmp packet.  Note we can't always generate a meaningful
155
 * icmp message because icmp doesn't have a large enough repertoire
156
 * of codes and types.
157
 *
158
 * If not forwarding, just drop the packet.  This could be confusing
159
 * if ipforwarding was zero but some routing protocol was advancing
160
 * us as a gateway to somewhere.  However, we must let the routing
161
 * protocol deal with that.
162
 *
163
 */
164
 
165
void
166
ip6_forward(m, srcrt)
167
        struct mbuf *m;
168
        int srcrt;
169
{
170
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
171
        struct sockaddr_in6 *dst;
172
        struct rtentry *rt;
173
        int error, type = 0, code = 0;
174
        struct mbuf *mcopy = NULL;
175
        struct ifnet *origifp;  /* maybe unnecessary */
176
        int64_t srczone, dstzone;
177
#ifdef IPSEC
178
        struct secpolicy *sp = NULL;
179
#endif
180
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
181
        long time_second = time.tv_sec;
182
#endif
183
 
184
#ifdef IPSEC
185
        /*
186
         * Check AH/ESP integrity.
187
         */
188
        /*
189
         * Don't increment ip6s_cantforward because this is the check
190
         * before forwarding packet actually.
191
         */
192
        if (ipsec6_in_reject(m, NULL)) {
193
                ipsec6stat.in_polvio++;
194
                m_freem(m);
195
                return;
196
        }
197
#endif /* IPSEC */
198
 
199
        /*
200
         * Do not forward packets to multicast destination (should be handled
201
         * by ip6_mforward().
202
         * Do not forward packets with unspecified source.  It was discussed
203
         * in July 2000, on ipngwg mailing list.
204
         */
205
        if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
206
            IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
207
            IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
208
                ip6stat.ip6s_cantforward++;
209
                /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
210
                if (ip6_log_time + ip6_log_interval < time_second) {
211
                        ip6_log_time = time_second;
212
                        log(LOG_DEBUG,
213
                            "cannot forward "
214
                            "from %s to %s nxt %d received on %s\n",
215
                            ip6_sprintf(&ip6->ip6_src),
216
                            ip6_sprintf(&ip6->ip6_dst),
217
                            ip6->ip6_nxt,
218
                            if_name(m->m_pkthdr.rcvif));
219
                }
220
                m_freem(m);
221
                return;
222
        }
223
 
224
        if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
225
                /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
226
                icmp6_error(m, ICMP6_TIME_EXCEEDED,
227
                                ICMP6_TIME_EXCEED_TRANSIT, 0);
228
                return;
229
        }
230
        ip6->ip6_hlim -= IPV6_HLIMDEC;
231
 
232
        /*
233
         * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
234
         * size of IPv6 + ICMPv6 headers) bytes of the packet in case
235
         * we need to generate an ICMP6 message to the src.
236
         * Thanks to M_EXT, in most cases copy will not occur.
237
         *
238
         * It is important to save it before IPsec processing as IPsec
239
         * processing may modify the mbuf.
240
         */
241
        mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
242
 
243
#ifdef IPSEC
244
        /* get a security policy for this packet */
245
        sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING,
246
            &error);
247
        if (sp == NULL) {
248
                ipsec6stat.out_inval++;
249
                ip6stat.ip6s_cantforward++;
250
                if (mcopy) {
251
#if 0
252
                        /* XXX: what icmp ? */
253
#else
254
                        m_freem(mcopy);
255
#endif
256
                }
257
                m_freem(m);
258
                return;
259
        }
260
 
261
        error = 0;
262
 
263
        /* check policy */
264
        switch (sp->policy) {
265
        case IPSEC_POLICY_DISCARD:
266
                /*
267
                 * This packet is just discarded.
268
                 */
269
                ipsec6stat.out_polvio++;
270
                ip6stat.ip6s_cantforward++;
271
                key_freesp(sp);
272
                if (mcopy) {
273
#if 0
274
                        /* XXX: what icmp ? */
275
#else
276
                        m_freem(mcopy);
277
#endif
278
                }
279
                m_freem(m);
280
                return;
281
 
282
        case IPSEC_POLICY_BYPASS:
283
        case IPSEC_POLICY_NONE:
284
                /* no need to do IPsec. */
285
                key_freesp(sp);
286
                goto skip_ipsec;
287
 
288
        case IPSEC_POLICY_IPSEC:
289
                if (sp->req == NULL) {
290
                        /* XXX should be panic ? */
291
                        printf("ip6_forward: No IPsec request specified.\n");
292
                        ip6stat.ip6s_cantforward++;
293
                        key_freesp(sp);
294
                        if (mcopy) {
295
#if 0
296
                                /* XXX: what icmp ? */
297
#else
298
                                m_freem(mcopy);
299
#endif
300
                        }
301
                        m_freem(m);
302
                        return;
303
                }
304
                /* do IPsec */
305
                break;
306
 
307
        case IPSEC_POLICY_ENTRUST:
308
        default:
309
                /* should be panic ?? */
310
                printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
311
                key_freesp(sp);
312
                goto skip_ipsec;
313
        }
314
 
315
    {
316
        struct ipsec_output_state state;
317
 
318
        /*
319
         * All the extension headers will become inaccessible
320
         * (since they can be encrypted).
321
         * Don't panic, we need no more updates to extension headers
322
         * on inner IPv6 packet (since they are now encapsulated).
323
         *
324
         * IPv6 [ESP|AH] IPv6 [extension headers] payload
325
         */
326
        bzero(&state, sizeof(state));
327
        state.m = m;
328
        state.ro = NULL;        /* update at ipsec6_output_tunnel() */
329
        state.dst = NULL;       /* update at ipsec6_output_tunnel() */
330
 
331
        error = ipsec6_output_tunnel(&state, sp, 0);
332
 
333
        m = state.m;
334
        key_freesp(sp);
335
 
336
        if (error) {
337
                /* mbuf is already reclaimed in ipsec6_output_tunnel. */
338
                switch (error) {
339
                case EHOSTUNREACH:
340
                case ENETUNREACH:
341
                case EMSGSIZE:
342
                case ENOBUFS:
343
                case ENOMEM:
344
                        break;
345
                default:
346
                        printf("ip6_output (ipsec): error code %d\n", error);
347
                        /* fall through */
348
                case ENOENT:
349
                        /* don't show these error codes to the user */
350
                        break;
351
                }
352
                ip6stat.ip6s_cantforward++;
353
                if (mcopy) {
354
#if 0
355
                        /* XXX: what icmp ? */
356
#else
357
                        m_freem(mcopy);
358
#endif
359
                }
360
                m_freem(m);
361
                return;
362
        }
363
    }
364
    skip_ipsec:
365
#endif /* IPSEC */
366
 
367
#ifdef MIP6
368
        {
369
                /*
370
                 * intercept and tunnel packets for home addresses
371
                 * which we are acting as a home agent for.
372
                 */
373
                struct mip6_bc *mbc;
374
 
375
                mbc = mip6_bc_list_find_withphaddr(&mip6_bc_list,
376
                                                   &ip6->ip6_dst);
377
                if (mbc &&
378
                    (mbc->mbc_flags & IP6_BUF_HOME) &&
379
                    (mbc->mbc_encap != NULL)) {
380
                        /*
381
                         * if we have a binding cache entry for the
382
                         * ip6_dst, we are acting as a home agent for
383
                         * that node.  before sending a packet as a
384
                         * tunneled packet, we must make sure that
385
                         * encaptab is ready.  if dad is enabled and
386
                         * not completed yet, encaptab will be NULL.
387
                         */
388
                        if (mip6_tunnel_output(&m, mbc) != 0) {
389
                                ip6stat.ip6s_cantforward++;
390
                        }
391
                        if (mcopy)
392
                                m_freem(mcopy);
393
                        return;
394
                }
395
        }
396
#endif /* MIP6 */
397
 
398
        dst = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst;
399
        if (!srcrt) {
400
#ifdef MEASURE_PERFORMANCE
401
                ctr_beg = read_tsc();
402
#endif
403
 
404
                /*
405
                 * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
406
                 */
407
                if (ip6_forward_rt.ro_rt == 0 ||
408
                    (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0
409
#ifdef MEASURE_PERFORMANCE
410
                    || (ip6_ours_check_algorithm != OURS_CHECK_ALG_RTABLE &&
411
                        !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr))
412
#endif
413
                        ) {
414
                        if (ip6_forward_rt.ro_rt) {
415
                                RTFREE(ip6_forward_rt.ro_rt);
416
                                ip6_forward_rt.ro_rt = 0;
417
                        }
418
#ifdef MEASURE_PERFORMANCE
419
                        ip6_forward_cache_miss++;
420
                        bzero(dst, sizeof(*dst));
421
                        dst->sin6_family = AF_INET6;
422
                        dst->sin6_len = sizeof(*dst);
423
                        dst->sin6_addr = ip6->ip6_dst;
424
#endif
425
                        /* this probably fails but give it a try again */
426
#ifdef __FreeBSD__
427
                        rtalloc_ign((struct route *)&ip6_forward_rt,
428
                                    RTF_PRCLONING);
429
#else
430
                        rtalloc((struct route *)&ip6_forward_rt);
431
#endif
432
                }
433
 
434
#ifdef MEASURE_PERFORMANCE
435
                ctr_end = read_tsc();
436
#ifdef MEASURE_PERFORMANCE_UDPONLY
437
                if (ip6->ip6_nxt == IPPROTO_UDP)
438
#endif
439
                        add_performance_log2(ctr_end - ctr_beg);
440
#endif
441
 
442
                if (ip6_forward_rt.ro_rt == 0) {
443
                        ip6stat.ip6s_noroute++;
444
                        in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
445
                        if (mcopy) {
446
                                icmp6_error(mcopy, ICMP6_DST_UNREACH,
447
                                            ICMP6_DST_UNREACH_NOROUTE, 0);
448
                        }
449
                        m_freem(m);
450
                        return;
451
                }
452
        } else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
453
                 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
454
                if (ip6_forward_rt.ro_rt) {
455
                        RTFREE(ip6_forward_rt.ro_rt);
456
                        ip6_forward_rt.ro_rt = 0;
457
                }
458
                bzero(dst, sizeof(*dst));
459
                dst->sin6_len = sizeof(struct sockaddr_in6);
460
                dst->sin6_family = AF_INET6;
461
                dst->sin6_addr = ip6->ip6_dst;
462
 
463
#ifdef __FreeBSD__
464
                rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);
465
#else
466
                rtalloc((struct route *)&ip6_forward_rt);
467
#endif
468
                if (ip6_forward_rt.ro_rt == 0) {
469
                        ip6stat.ip6s_noroute++;
470
                        in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
471
                        if (mcopy) {
472
                                icmp6_error(mcopy, ICMP6_DST_UNREACH,
473
                                            ICMP6_DST_UNREACH_NOROUTE, 0);
474
                        }
475
                        m_freem(m);
476
                        return;
477
                }
478
        }
479
        rt = ip6_forward_rt.ro_rt;
480
 
481
        /*
482
         * Scope check: if a packet can't be delivered to its destination
483
         * for the reason that the destination is beyond the scope of the
484
         * source address, discard the packet and return an icmp6 destination
485
         * unreachable error with Code 2 (beyond scope of source address).
486
         * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
487
         */
488
        if ((srczone = in6_addr2zoneid(m->m_pkthdr.rcvif, &ip6->ip6_src)) < 0
489
            || (dstzone = in6_addr2zoneid(rt->rt_ifp, &ip6->ip6_src)) < 0) {
490
                /* XXX: will this really happen?  should return an icmp error? */
491
                ip6stat.ip6s_cantforward++;
492
                ip6stat.ip6s_badscope++;
493
                m_freem(m);
494
                return;
495
        }
496
        if (srczone != dstzone) {
497
                ip6stat.ip6s_cantforward++;
498
                ip6stat.ip6s_badscope++;
499
                in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
500
 
501
                if (ip6_log_time + ip6_log_interval < time_second) {
502
                        ip6_log_time = time_second;
503
                        log(LOG_DEBUG,
504
                            "cannot forward "
505
                            "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
506
                            ip6_sprintf(&ip6->ip6_src),
507
                            ip6_sprintf(&ip6->ip6_dst),
508
                            ip6->ip6_nxt,
509
                            if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
510
                }
511
                if (mcopy)
512
                        icmp6_error(mcopy, ICMP6_DST_UNREACH,
513
                                    ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
514
                m_freem(m);
515
                return;
516
        }
517
 
518
        if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) {
519
                in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
520
                if (mcopy) {
521
                        u_long mtu;
522
#ifdef IPSEC
523
                        struct secpolicy *sp;
524
                        int ipsecerror;
525
                        size_t ipsechdrsiz;
526
#endif
527
 
528
                        mtu = rt->rt_ifp->if_mtu;
529
#ifdef IPSEC
530
                        /*
531
                         * When we do IPsec tunnel ingress, we need to play
532
                         * with if_mtu value (decrement IPsec header size
533
                         * from mtu value).  The code is much simpler than v4
534
                         * case, as we have the outgoing interface for
535
                         * encapsulated packet as "rt->rt_ifp".
536
                         */
537
                        sp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
538
                                IP_FORWARDING, &ipsecerror);
539
                        if (sp) {
540
                                ipsechdrsiz = ipsec6_hdrsiz(mcopy,
541
                                        IPSEC_DIR_OUTBOUND, NULL);
542
                                if (ipsechdrsiz < mtu)
543
                                        mtu -= ipsechdrsiz;
544
                        }
545
 
546
                        /*
547
                         * if mtu becomes less than minimum MTU,
548
                         * tell minimum MTU (and I'll need to fragment it).
549
                         */
550
                        if (mtu < IPV6_MMTU)
551
                                mtu = IPV6_MMTU;
552
#endif
553
                        icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
554
                }
555
                m_freem(m);
556
                return;
557
        }
558
 
559
        if (rt->rt_flags & RTF_GATEWAY)
560
                dst = (struct sockaddr_in6 *)rt->rt_gateway;
561
 
562
        /*
563
         * If we are to forward the packet using the same interface
564
         * as one we got the packet from, perhaps we should send a redirect
565
         * to sender to shortcut a hop.
566
         * Only send redirect if source is sending directly to us,
567
         * and if packet was not source routed (or has any options).
568
         * Also, don't send redirect if forwarding using a route
569
         * modified by a redirect.
570
         */
571
        if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
572
            (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
573
                if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) &&
574
                    nd6_is_addr_neighbor((struct sockaddr_in6 *)&ip6_forward_rt.ro_dst, rt->rt_ifp)) {
575
                        /*
576
                         * If the incoming interface is equal to the outgoing
577
                         * one, the link attached to the interface is
578
                         * point-to-point, and the IPv6 destination is
579
                         * regarded as on-link on the link, then it will be
580
                         * highly probable that the destination address does
581
                         * not exist on the link and that the packet is going
582
                         * to loop.  Thus, we immediately drop the packet and
583
                         * send an ICMPv6 error message.
584
                         * For other routing loops, we dare to let the packet
585
                         * go to the loop, so that a remote diagnosing host
586
                         * can detect the loop by traceroute.
587
                         * type/code is based on suggestion by Rich Draves.
588
                         * not sure if it is the best pick.
589
                         */
590
                        icmp6_error(mcopy, ICMP6_DST_UNREACH,
591
                                    ICMP6_DST_UNREACH_ADDR, 0);
592
                        m_freem(m);
593
                        return;
594
                }
595
                type = ND_REDIRECT;
596
        }
597
 
598
#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
599
        /*
600
         * Check with the firewall...
601
         */
602
#if defined(__FreeBSD__) && __FreeBSD__ >= 4
603
        if (ip6_fw_enable && ip6_fw_chk_ptr) {
604
#else
605
        if (ip6_fw_chk_ptr) {
606
#endif
607
                /* If ipfw says divert, we have to just drop packet */
608
                if ((*ip6_fw_chk_ptr)(&ip6, rt->rt_ifp, &m)) {
609
                        m_freem(m);
610
                        goto freecopy;
611
                }
612
                if (!m)
613
                        goto freecopy;
614
        }
615
#endif
616
 
617
        /*
618
         * Fake scoped addresses. Note that even link-local source or
619
         * destinaion can appear, if the originating node just sends the
620
         * packet to us (without address resolution for the destination).
621
         * Since both icmp6_error and icmp6_redirect_output fill the embedded
622
         * link identifiers, we can do this stuff after making a copy for
623
         * returning an error.
624
         */
625
        if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
626
                /*
627
                 * See corresponding comments in ip6_output.
628
                 * XXX: but is it possible that ip6_forward() sends a packet
629
                 *      to a loopback interface? I don't think so, and thus
630
                 *      I bark here. (jinmei@kame.net)
631
                 * XXX: it is common to route invalid packets to loopback.
632
                 *      also, the codepath will be visited on use of ::1 in
633
                 *      rthdr. (itojun)
634
                 */
635
#if 1
636
                if (0)
637
#else
638
                if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
639
#endif
640
                {
641
                        printf("ip6_forward: outgoing interface is loopback. "
642
                               "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
643
                               ip6_sprintf(&ip6->ip6_src),
644
                               ip6_sprintf(&ip6->ip6_dst),
645
                               ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
646
                               if_name(rt->rt_ifp));
647
                }
648
 
649
                /* we can just use rcvif in forwarding. */
650
                origifp = m->m_pkthdr.rcvif;
651
        }
652
        else
653
                origifp = rt->rt_ifp;
654
#ifndef SCOPEDROUTING
655
        /*
656
         * clear embedded scope identifiers if necessary.
657
         * in6_clearscope will touch the addresses only when necessary.
658
         */
659
        in6_clearscope(&ip6->ip6_src);
660
        in6_clearscope(&ip6->ip6_dst);
661
#endif
662
 
663
#if defined(__NetBSD__) && defined(PFIL_HOOKS)
664
    {
665
        struct packet_filter_hook *pfh;
666
        struct mbuf *m1;
667
        int rv;
668
 
669
        /*
670
         * Run through list of hooks for output packets.
671
         */
672
        m1 = m;
673
        pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
674
        for (; pfh; pfh = pfh->pfil_link.tqe_next)
675
                if (pfh->pfil_func) {
676
                        rv = pfh->pfil_func(ip6, sizeof(*ip6), rt->rt_ifp, 1, &m1);
677
                        if (rv) {
678
                                error = EHOSTUNREACH;
679
                                goto senderr;
680
                        }
681
                        m = m1;
682
                        if (m == NULL)
683
                                goto freecopy;
684
                        ip6 = mtod(m, struct ip6_hdr *);
685
                }
686
    }
687
#endif /* PFIL_HOOKS */
688
 
689
#if defined(__OpenBSD__) && NPF > 0
690
        if (pf_test6(PF_OUT, rt->rt_ifp, &m) != PF_PASS) {
691
                m_freem(m);
692
                goto senderr;
693
        }
694
        ip6 = mtod(m, struct ip6_hdr *);
695
#endif
696
 
697
        error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
698
        if (error) {
699
                in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
700
                ip6stat.ip6s_cantforward++;
701
        } else {
702
                ip6stat.ip6s_forward++;
703
                in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
704
                if (type)
705
                        ip6stat.ip6s_redirectsent++;
706
                else {
707
                        if (mcopy)
708
                                goto freecopy;
709
                }
710
        }
711
 
712
#if (defined(__NetBSD__) && defined(PFIL_HOOKS)) || (defined(__OpenBSD__) && NPF > 0)
713
 senderr:
714
#endif
715
        if (mcopy == NULL)
716
                return;
717
        switch (error) {
718
        case 0:
719
#if 1
720
                if (type == ND_REDIRECT) {
721
                        icmp6_redirect_output(mcopy, rt);
722
                        return;
723
                }
724
#endif
725
                goto freecopy;
726
 
727
        case EMSGSIZE:
728
                /* xxx MTU is constant in PPP? */
729
                goto freecopy;
730
 
731
        case ENOBUFS:
732
                /* Tell source to slow down like source quench in IP? */
733
                goto freecopy;
734
 
735
        case ENETUNREACH:       /* shouldn't happen, checked above */
736
        case EHOSTUNREACH:
737
        case ENETDOWN:
738
        case EHOSTDOWN:
739
        default:
740
                type = ICMP6_DST_UNREACH;
741
                code = ICMP6_DST_UNREACH_ADDR;
742
                break;
743
        }
744
        icmp6_error(mcopy, type, code, 0);
745
        return;
746
 
747
 freecopy:
748
        m_freem(mcopy);
749
        return;
750
}

powered by: WebSVN 2.1.0

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