2007-05-23 21:14:59 +04:00
|
|
|
/* $NetBSD: ip6_forward.c,v 1.58 2007/05/23 17:15:02 christos Exp $ */
|
2002-09-11 12:15:37 +04:00
|
|
|
/* $KAME: ip6_forward.c,v 1.109 2002/09/11 08:10:17 sakane Exp $ */
|
1999-07-04 01:24:45 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2000-05-19 05:40:18 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the project nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
2000-05-19 05:40:18 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
2001-11-13 03:56:55 +03:00
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2007-05-23 21:14:59 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.58 2007/05/23 17:15:02 christos Exp $");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-07-16 11:57:55 +04:00
|
|
|
#include "opt_ipsec.h"
|
2001-06-12 19:12:33 +04:00
|
|
|
#include "opt_pfil_hooks.h"
|
2000-07-16 11:57:55 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/domain.h>
|
|
|
|
#include <sys/protosw.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_var.h>
|
2000-01-31 17:18:52 +03:00
|
|
|
#include <netinet/ip_var.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/ip6.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/ip6_var.h>
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
#include <netinet6/scope6_var.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/icmp6.h>
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <netinet6/nd6.h>
|
|
|
|
|
2000-07-16 11:57:55 +04:00
|
|
|
#ifdef IPSEC
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <netinet6/ipsec.h>
|
|
|
|
#include <netkey/key.h>
|
2000-07-16 11:57:55 +04:00
|
|
|
#endif /* IPSEC */
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
#include <netipsec/ipsec.h>
|
|
|
|
#include <netipsec/ipsec6.h>
|
|
|
|
#include <netipsec/key.h>
|
|
|
|
#include <netipsec/xform.h>
|
|
|
|
#endif /* FAST_IPSEC */
|
|
|
|
|
2001-06-12 19:12:33 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
#include <net/pfil.h>
|
|
|
|
#endif
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <net/net_osdep.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
struct route ip6_forward_rt;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2001-06-12 19:12:33 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
extern struct pfil_head inet6_pfil_hook; /* XXX */
|
|
|
|
#endif
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Forward a packet. If some error occurs return the sender
|
|
|
|
* an icmp packet. Note we can't always generate a meaningful
|
|
|
|
* icmp message because icmp doesn't have a large enough repertoire
|
|
|
|
* of codes and types.
|
|
|
|
*
|
|
|
|
* If not forwarding, just drop the packet. This could be confusing
|
|
|
|
* if ipforwarding was zero but some routing protocol was advancing
|
|
|
|
* us as a gateway to somewhere. However, we must let the routing
|
|
|
|
* protocol deal with that.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_forward(struct mbuf *m, int srcrt)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
1999-12-13 18:17:17 +03:00
|
|
|
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
const struct sockaddr_in6 *dst;
|
2001-02-10 07:14:26 +03:00
|
|
|
struct rtentry *rt;
|
2004-06-24 19:01:51 +04:00
|
|
|
int error = 0, type = 0, code = 0;
|
1999-12-13 18:17:17 +03:00
|
|
|
struct mbuf *mcopy = NULL;
|
2000-05-19 05:40:18 +04:00
|
|
|
struct ifnet *origifp; /* maybe unnecessary */
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
u_int32_t inzone, outzone;
|
|
|
|
struct in6_addr src_in6, dst_in6;
|
2000-07-16 11:57:55 +04:00
|
|
|
#ifdef IPSEC
|
1999-12-13 18:17:17 +03:00
|
|
|
struct secpolicy *sp = NULL;
|
2003-10-02 16:13:44 +04:00
|
|
|
int ipsecrt = 0;
|
1999-12-13 18:17:17 +03:00
|
|
|
#endif
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
struct secpolicy *sp = NULL;
|
|
|
|
int needipsec = 0;
|
|
|
|
int s;
|
|
|
|
#endif
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2000-07-16 11:57:55 +04:00
|
|
|
#ifdef IPSEC
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* Check AH/ESP integrity.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Don't increment ip6s_cantforward because this is the check
|
|
|
|
* before forwarding packet actually.
|
|
|
|
*/
|
|
|
|
if (ipsec6_in_reject(m, NULL)) {
|
|
|
|
ipsec6stat.in_polvio++;
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
2001-10-24 10:36:37 +04:00
|
|
|
#endif /* IPSEC */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-07-27 19:53:51 +04:00
|
|
|
/*
|
|
|
|
* Do not forward packets to multicast destination (should be handled
|
|
|
|
* by ip6_mforward().
|
|
|
|
* Do not forward packets with unspecified source. It was discussed
|
|
|
|
* in July 2000, on ipngwg mailing list.
|
|
|
|
*/
|
2000-02-26 11:39:18 +03:00
|
|
|
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
|
2000-07-27 19:53:51 +04:00
|
|
|
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
|
|
|
|
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
ip6stat.ip6s_cantforward++;
|
1999-12-13 18:17:17 +03:00
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
|
2006-06-08 02:33:33 +04:00
|
|
|
if (ip6_log_time + ip6_log_interval < time_second) {
|
|
|
|
ip6_log_time = time_second;
|
1999-06-28 10:36:47 +04:00
|
|
|
log(LOG_DEBUG,
|
|
|
|
"cannot forward "
|
|
|
|
"from %s to %s nxt %d received on %s\n",
|
2000-02-26 11:39:18 +03:00
|
|
|
ip6_sprintf(&ip6->ip6_src),
|
|
|
|
ip6_sprintf(&ip6->ip6_dst),
|
1999-06-28 10:36:47 +04:00
|
|
|
ip6->ip6_nxt,
|
1999-12-13 18:17:17 +03:00
|
|
|
if_name(m->m_pkthdr.rcvif));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
|
1999-12-13 18:17:17 +03:00
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
|
1999-06-28 10:36:47 +04:00
|
|
|
icmp6_error(m, ICMP6_TIME_EXCEEDED,
|
|
|
|
ICMP6_TIME_EXCEED_TRANSIT, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ip6->ip6_hlim -= IPV6_HLIMDEC;
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
|
|
|
|
* size of IPv6 + ICMPv6 headers) bytes of the packet in case
|
|
|
|
* we need to generate an ICMP6 message to the src.
|
|
|
|
* Thanks to M_EXT, in most cases copy will not occur.
|
|
|
|
*
|
|
|
|
* It is important to save it before IPsec processing as IPsec
|
|
|
|
* processing may modify the mbuf.
|
|
|
|
*/
|
|
|
|
mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
|
|
|
|
|
2000-07-16 11:57:55 +04:00
|
|
|
#ifdef IPSEC
|
1999-12-13 18:17:17 +03:00
|
|
|
/* get a security policy for this packet */
|
2003-07-03 09:03:53 +04:00
|
|
|
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND,
|
|
|
|
IP_FORWARDING, &error);
|
1999-12-13 18:17:17 +03:00
|
|
|
if (sp == NULL) {
|
|
|
|
ipsec6stat.out_inval++;
|
|
|
|
ip6stat.ip6s_cantforward++;
|
|
|
|
if (mcopy) {
|
|
|
|
#if 0
|
|
|
|
/* XXX: what icmp ? */
|
|
|
|
#else
|
|
|
|
m_freem(mcopy);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
|
|
|
|
/* check policy */
|
|
|
|
switch (sp->policy) {
|
|
|
|
case IPSEC_POLICY_DISCARD:
|
|
|
|
/*
|
|
|
|
* This packet is just discarded.
|
|
|
|
*/
|
|
|
|
ipsec6stat.out_polvio++;
|
|
|
|
ip6stat.ip6s_cantforward++;
|
|
|
|
key_freesp(sp);
|
|
|
|
if (mcopy) {
|
|
|
|
#if 0
|
|
|
|
/* XXX: what icmp ? */
|
|
|
|
#else
|
|
|
|
m_freem(mcopy);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_BYPASS:
|
|
|
|
case IPSEC_POLICY_NONE:
|
|
|
|
/* no need to do IPsec. */
|
|
|
|
key_freesp(sp);
|
|
|
|
goto skip_ipsec;
|
2000-06-30 23:46:05 +04:00
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
case IPSEC_POLICY_IPSEC:
|
|
|
|
if (sp->req == NULL) {
|
|
|
|
/* XXX should be panic ? */
|
|
|
|
printf("ip6_forward: No IPsec request specified.\n");
|
|
|
|
ip6stat.ip6s_cantforward++;
|
|
|
|
key_freesp(sp);
|
|
|
|
if (mcopy) {
|
|
|
|
#if 0
|
|
|
|
/* XXX: what icmp ? */
|
|
|
|
#else
|
|
|
|
m_freem(mcopy);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* do IPsec */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
|
|
|
default:
|
|
|
|
/* should be panic ?? */
|
|
|
|
printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
|
|
|
|
key_freesp(sp);
|
|
|
|
goto skip_ipsec;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2002-09-11 12:15:37 +04:00
|
|
|
struct ipsecrequest *isr = NULL;
|
1999-12-13 18:17:17 +03:00
|
|
|
struct ipsec_output_state state;
|
|
|
|
|
2002-09-11 12:15:37 +04:00
|
|
|
/*
|
|
|
|
* when the kernel forwards a packet, it is not proper to apply
|
|
|
|
* IPsec transport mode to the packet is not proper. this check
|
|
|
|
* avoid from this.
|
|
|
|
* at present, if there is even a transport mode SA request in the
|
|
|
|
* security policy, the kernel does not apply IPsec to the packet.
|
|
|
|
* this check is not enough because the following case is valid.
|
|
|
|
* ipsec esp/tunnel/xxx-xxx/require esp/transport//require;
|
|
|
|
*/
|
|
|
|
for (isr = sp->req; isr; isr = isr->next) {
|
2004-01-16 08:12:08 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_ANY)
|
|
|
|
goto doipsectunnel;
|
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
|
|
|
|
goto doipsectunnel;
|
2002-09-11 12:15:37 +04:00
|
|
|
}
|
2004-01-16 08:12:08 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if there's no need for tunnel mode IPsec, skip.
|
|
|
|
*/
|
|
|
|
if (!isr)
|
|
|
|
goto skip_ipsec;
|
2005-02-27 01:45:09 +03:00
|
|
|
|
2004-01-16 08:12:08 +03:00
|
|
|
doipsectunnel:
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* All the extension headers will become inaccessible
|
|
|
|
* (since they can be encrypted).
|
|
|
|
* Don't panic, we need no more updates to extension headers
|
|
|
|
* on inner IPv6 packet (since they are now encapsulated).
|
|
|
|
*
|
|
|
|
* IPv6 [ESP|AH] IPv6 [extension headers] payload
|
|
|
|
*/
|
|
|
|
bzero(&state, sizeof(state));
|
|
|
|
state.m = m;
|
|
|
|
state.ro = NULL; /* update at ipsec6_output_tunnel() */
|
|
|
|
state.dst = NULL; /* update at ipsec6_output_tunnel() */
|
|
|
|
|
|
|
|
error = ipsec6_output_tunnel(&state, sp, 0);
|
|
|
|
|
|
|
|
m = state.m;
|
|
|
|
key_freesp(sp);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
/* mbuf is already reclaimed in ipsec6_output_tunnel. */
|
|
|
|
switch (error) {
|
|
|
|
case EHOSTUNREACH:
|
|
|
|
case ENETUNREACH:
|
|
|
|
case EMSGSIZE:
|
|
|
|
case ENOBUFS:
|
|
|
|
case ENOMEM:
|
|
|
|
break;
|
|
|
|
default:
|
2006-06-29 20:56:31 +04:00
|
|
|
printf("ip6_forward (ipsec): error code %d\n", error);
|
2002-06-07 08:18:11 +04:00
|
|
|
/* FALLTHROUGH */
|
1999-12-13 18:17:17 +03:00
|
|
|
case ENOENT:
|
|
|
|
/* don't show these error codes to the user */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ip6stat.ip6s_cantforward++;
|
|
|
|
if (mcopy) {
|
|
|
|
#if 0
|
|
|
|
/* XXX: what icmp ? */
|
|
|
|
#else
|
|
|
|
m_freem(mcopy);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
2003-10-02 16:13:44 +04:00
|
|
|
|
2004-01-16 08:12:08 +03:00
|
|
|
if (ip6 != mtod(m, struct ip6_hdr *)) {
|
|
|
|
/*
|
|
|
|
* now tunnel mode headers are added. we are originating
|
2005-02-27 01:45:09 +03:00
|
|
|
* packet instead of forwarding the packet.
|
2004-01-16 08:12:08 +03:00
|
|
|
*/
|
|
|
|
ip6_output(m, NULL, NULL, IPV6_FORWARDING/*XXX*/, NULL, NULL,
|
|
|
|
NULL);
|
2004-07-16 05:12:02 +04:00
|
|
|
goto freecopy;
|
2004-01-16 08:12:08 +03:00
|
|
|
}
|
|
|
|
|
2003-10-02 16:13:44 +04:00
|
|
|
/* adjust pointer */
|
2003-10-02 23:32:41 +04:00
|
|
|
rt = state.ro ? state.ro->ro_rt : NULL;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
dst = (const struct sockaddr_in6 *)state.dst;
|
2003-10-29 13:12:43 +03:00
|
|
|
if (dst != NULL && rt != NULL) {
|
2003-10-02 16:13:44 +04:00
|
|
|
ipsecrt = 1;
|
2003-10-29 13:12:43 +03:00
|
|
|
goto skip_routing;
|
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
|
|
|
skip_ipsec:
|
2000-07-16 11:57:55 +04:00
|
|
|
#endif /* IPSEC */
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
/* Check the security policy (SP) for the packet */
|
|
|
|
|
|
|
|
sp = ipsec6_check_policy(m,NULL,0,&needipsec,&error);
|
|
|
|
if (error != 0) {
|
|
|
|
/*
|
|
|
|
* Hack: -EINVAL is used to signal that a packet
|
|
|
|
* should be silently discarded. This is typically
|
|
|
|
* because we asked key management for an SA and
|
|
|
|
* it was delayed (e.g. kicked up to IKE).
|
|
|
|
*/
|
|
|
|
if (error == -EINVAL)
|
|
|
|
error = 0;
|
|
|
|
goto freecopy;
|
|
|
|
}
|
|
|
|
#endif /* FAST_IPSEC */
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
if (!srcrt) {
|
|
|
|
/*
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
* rtcache_getdst(ip6_forward_rt)->sin6_addr is equal to
|
|
|
|
* ip6->ip6_dst
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
rtcache_check(&ip6_forward_rt);
|
2006-12-02 21:59:17 +03:00
|
|
|
if (ip6_forward_rt.ro_rt == NULL) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
rtcache_init(&ip6_forward_rt);
|
2006-12-16 00:18:52 +03:00
|
|
|
|
|
|
|
if (ip6_forward_rt.ro_rt == NULL) {
|
|
|
|
ip6stat.ip6s_noroute++;
|
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
|
|
|
|
if (mcopy) {
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
1999-12-13 18:17:17 +03:00
|
|
|
ICMP6_DST_UNREACH_NOROUTE, 0);
|
2006-12-16 00:18:52 +03:00
|
|
|
}
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2006-12-16 00:18:52 +03:00
|
|
|
} else {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
union {
|
|
|
|
struct sockaddr dst;
|
|
|
|
struct sockaddr_in6 dst6;
|
|
|
|
} u;
|
|
|
|
|
|
|
|
sockaddr_in6_init(&u.dst6, &ip6->ip6_dst, 0, 0, 0);
|
|
|
|
if (rtcache_lookup(&ip6_forward_rt, &u.dst) == NULL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
ip6stat.ip6s_noroute++;
|
1999-12-13 18:17:17 +03:00
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
|
|
|
|
if (mcopy) {
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_NOROUTE, 0);
|
|
|
|
}
|
|
|
|
m_freem(m);
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
dst = satocsin6(rtcache_getdst(&ip6_forward_rt));
|
1999-06-28 10:36:47 +04:00
|
|
|
rt = ip6_forward_rt.ro_rt;
|
2003-10-02 16:13:44 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
skip_routing:;
|
|
|
|
#endif /* IPSEC */
|
2000-02-26 11:39:18 +03:00
|
|
|
|
|
|
|
/*
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
* Source scope check: if a packet can't be delivered to its
|
|
|
|
* destination for the reason that the destination is beyond the scope
|
|
|
|
* of the source address, discard the packet and return an icmp6
|
|
|
|
* destination unreachable error with Code 2 (beyond scope of source
|
|
|
|
* address). We use a local copy of ip6_src, since in6_setscope()
|
|
|
|
* will possibly modify its first argument.
|
|
|
|
* [draft-ietf-ipngwg-icmp-v3-07, Section 3.1]
|
2000-02-26 11:39:18 +03:00
|
|
|
*/
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
src_in6 = ip6->ip6_src;
|
|
|
|
if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) {
|
|
|
|
/* XXX: this should not happen */
|
|
|
|
ip6stat.ip6s_cantforward++;
|
|
|
|
ip6stat.ip6s_badscope++;
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
|
|
|
|
ip6stat.ip6s_cantforward++;
|
|
|
|
ip6stat.ip6s_badscope++;
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (inzone != outzone
|
2003-10-03 08:30:31 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
&& !ipsecrt
|
|
|
|
#endif
|
|
|
|
) {
|
2000-02-26 11:39:18 +03:00
|
|
|
ip6stat.ip6s_cantforward++;
|
|
|
|
ip6stat.ip6s_badscope++;
|
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
|
|
|
|
|
2006-06-08 02:33:33 +04:00
|
|
|
if (ip6_log_time + ip6_log_interval < time_second) {
|
|
|
|
ip6_log_time = time_second;
|
2000-02-26 11:39:18 +03:00
|
|
|
log(LOG_DEBUG,
|
|
|
|
"cannot forward "
|
|
|
|
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
|
|
|
|
ip6_sprintf(&ip6->ip6_src),
|
|
|
|
ip6_sprintf(&ip6->ip6_dst),
|
|
|
|
ip6->ip6_nxt,
|
|
|
|
if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
|
|
|
|
}
|
|
|
|
if (mcopy)
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
2007-02-10 12:43:05 +03:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
/*
|
|
|
|
* If we need to encapsulate the packet, do it here
|
|
|
|
* ipsec6_proces_packet will send the packet using ip6_output
|
|
|
|
*/
|
|
|
|
if (needipsec) {
|
|
|
|
s = splsoftnet();
|
|
|
|
error = ipsec6_process_packet(m,sp->req);
|
|
|
|
splx(s);
|
|
|
|
if (mcopy)
|
|
|
|
goto freecopy;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2000-02-26 11:39:18 +03:00
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* Destination scope check: if a packet is going to break the scope
|
|
|
|
* zone of packet's destination address, discard it. This case should
|
|
|
|
* usually be prevented by appropriately-configured routing table, but
|
|
|
|
* we need an explicit check because we may mistakenly forward the
|
|
|
|
* packet to a different zone by (e.g.) a default route.
|
|
|
|
*/
|
|
|
|
dst_in6 = ip6->ip6_dst;
|
|
|
|
if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
|
|
|
|
in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
|
|
|
|
inzone != outzone) {
|
|
|
|
ip6stat.ip6s_cantforward++;
|
|
|
|
ip6stat.ip6s_badscope++;
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
|
|
|
|
if (mcopy) {
|
|
|
|
u_long mtu;
|
2000-07-16 11:57:55 +04:00
|
|
|
#ifdef IPSEC
|
2005-05-30 01:43:51 +04:00
|
|
|
struct secpolicy *xsp;
|
2000-01-31 17:18:52 +03:00
|
|
|
int ipsecerror;
|
|
|
|
size_t ipsechdrsiz;
|
|
|
|
#endif
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
mtu = IN6_LINKMTU(rt->rt_ifp);
|
2000-07-16 11:57:55 +04:00
|
|
|
#ifdef IPSEC
|
2000-01-31 17:18:52 +03:00
|
|
|
/*
|
|
|
|
* When we do IPsec tunnel ingress, we need to play
|
2002-05-29 11:53:39 +04:00
|
|
|
* with the link value (decrement IPsec header size
|
2000-01-31 17:18:52 +03:00
|
|
|
* from mtu value). The code is much simpler than v4
|
|
|
|
* case, as we have the outgoing interface for
|
|
|
|
* encapsulated packet as "rt->rt_ifp".
|
|
|
|
*/
|
2005-05-30 01:43:51 +04:00
|
|
|
xsp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
|
2000-01-31 17:18:52 +03:00
|
|
|
IP_FORWARDING, &ipsecerror);
|
2005-05-30 01:43:51 +04:00
|
|
|
if (xsp) {
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsechdrsiz = ipsec6_hdrsiz(mcopy,
|
|
|
|
IPSEC_DIR_OUTBOUND, NULL);
|
|
|
|
if (ipsechdrsiz < mtu)
|
|
|
|
mtu -= ipsechdrsiz;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-05-19 05:40:18 +04:00
|
|
|
* if mtu becomes less than minimum MTU,
|
2000-01-31 17:18:52 +03:00
|
|
|
* tell minimum MTU (and I'll need to fragment it).
|
|
|
|
*/
|
|
|
|
if (mtu < IPV6_MMTU)
|
|
|
|
mtu = IPV6_MMTU;
|
|
|
|
#endif
|
1999-12-13 18:17:17 +03:00
|
|
|
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
|
|
|
|
}
|
|
|
|
m_freem(m);
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (rt->rt_flags & RTF_GATEWAY)
|
|
|
|
dst = (struct sockaddr_in6 *)rt->rt_gateway;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are to forward the packet using the same interface
|
|
|
|
* as one we got the packet from, perhaps we should send a redirect
|
|
|
|
* to sender to shortcut a hop.
|
|
|
|
* Only send redirect if source is sending directly to us,
|
|
|
|
* and if packet was not source routed (or has any options).
|
|
|
|
* Also, don't send redirect if forwarding using a route
|
|
|
|
* modified by a redirect.
|
|
|
|
*/
|
2003-08-07 12:52:32 +04:00
|
|
|
if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && ip6_sendredirects &&
|
2003-10-02 16:13:44 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
!ipsecrt &&
|
|
|
|
#endif
|
2001-06-22 16:33:05 +04:00
|
|
|
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
|
2001-07-18 13:24:26 +04:00
|
|
|
if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) &&
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
nd6_is_addr_neighbor(
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
satocsin6(rtcache_getdst(&ip6_forward_rt)),
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
rt->rt_ifp)) {
|
2001-06-22 16:33:05 +04:00
|
|
|
/*
|
|
|
|
* If the incoming interface is equal to the outgoing
|
2001-07-18 13:24:26 +04:00
|
|
|
* one, the link attached to the interface is
|
|
|
|
* point-to-point, and the IPv6 destination is
|
|
|
|
* regarded as on-link on the link, then it will be
|
|
|
|
* highly probable that the destination address does
|
|
|
|
* not exist on the link and that the packet is going
|
|
|
|
* to loop. Thus, we immediately drop the packet and
|
|
|
|
* send an ICMPv6 error message.
|
|
|
|
* For other routing loops, we dare to let the packet
|
|
|
|
* go to the loop, so that a remote diagnosing host
|
|
|
|
* can detect the loop by traceroute.
|
2001-06-22 16:33:05 +04:00
|
|
|
* type/code is based on suggestion by Rich Draves.
|
|
|
|
* not sure if it is the best pick.
|
|
|
|
*/
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_ADDR, 0);
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
type = ND_REDIRECT;
|
2001-06-22 16:33:05 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-05-19 05:40:18 +04:00
|
|
|
/*
|
|
|
|
* Fake scoped addresses. Note that even link-local source or
|
|
|
|
* destinaion can appear, if the originating node just sends the
|
|
|
|
* packet to us (without address resolution for the destination).
|
|
|
|
* Since both icmp6_error and icmp6_redirect_output fill the embedded
|
2001-02-10 07:14:26 +03:00
|
|
|
* link identifiers, we can do this stuff after making a copy for
|
|
|
|
* returning an error.
|
2000-05-19 05:40:18 +04:00
|
|
|
*/
|
|
|
|
if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
|
|
|
|
/*
|
|
|
|
* See corresponding comments in ip6_output.
|
|
|
|
* XXX: but is it possible that ip6_forward() sends a packet
|
|
|
|
* to a loopback interface? I don't think so, and thus
|
|
|
|
* I bark here. (jinmei@kame.net)
|
2000-06-03 18:36:32 +04:00
|
|
|
* XXX: it is common to route invalid packets to loopback.
|
2000-06-30 23:46:05 +04:00
|
|
|
* also, the codepath will be visited on use of ::1 in
|
|
|
|
* rthdr. (itojun)
|
2000-05-19 05:40:18 +04:00
|
|
|
*/
|
2000-06-30 23:46:05 +04:00
|
|
|
#if 1
|
|
|
|
if (0)
|
|
|
|
#else
|
|
|
|
if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
|
|
|
|
#endif
|
|
|
|
{
|
2000-06-03 18:36:32 +04:00
|
|
|
printf("ip6_forward: outgoing interface is loopback. "
|
|
|
|
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
|
|
|
|
ip6_sprintf(&ip6->ip6_src),
|
|
|
|
ip6_sprintf(&ip6->ip6_dst),
|
|
|
|
ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
|
|
|
|
if_name(rt->rt_ifp));
|
|
|
|
}
|
2000-06-30 23:46:05 +04:00
|
|
|
|
2001-03-30 15:08:56 +04:00
|
|
|
/* we can just use rcvif in forwarding. */
|
|
|
|
origifp = m->m_pkthdr.rcvif;
|
2000-05-19 05:40:18 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
origifp = rt->rt_ifp;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* clear embedded scope identifiers if necessary.
|
|
|
|
* in6_clearscope will touch the addresses only when necessary.
|
|
|
|
*/
|
|
|
|
in6_clearscope(&ip6->ip6_src);
|
|
|
|
in6_clearscope(&ip6->ip6_dst);
|
2000-05-19 05:40:18 +04:00
|
|
|
|
2001-06-12 19:12:33 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
/*
|
|
|
|
* Run through list of hooks for output packets.
|
|
|
|
*/
|
|
|
|
if ((error = pfil_run_hooks(&inet6_pfil_hook, &m, rt->rt_ifp,
|
2003-06-30 07:30:50 +04:00
|
|
|
PFIL_OUT)) != 0)
|
2001-06-12 19:12:33 +04:00
|
|
|
goto senderr;
|
|
|
|
if (m == NULL)
|
|
|
|
goto freecopy;
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
#endif /* PFIL_HOOKS */
|
|
|
|
|
2000-05-19 05:40:18 +04:00
|
|
|
error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
|
1999-12-13 18:17:17 +03:00
|
|
|
if (error) {
|
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
|
1999-06-28 10:36:47 +04:00
|
|
|
ip6stat.ip6s_cantforward++;
|
1999-12-13 18:17:17 +03:00
|
|
|
} else {
|
1999-06-28 10:36:47 +04:00
|
|
|
ip6stat.ip6s_forward++;
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (type)
|
|
|
|
ip6stat.ip6s_redirectsent++;
|
|
|
|
else {
|
2007-03-08 01:20:04 +03:00
|
|
|
#ifdef GATEWAY
|
|
|
|
if (m->m_flags & M_CANFASTFWD)
|
|
|
|
ip6flow_create(&ip6_forward_rt, m);
|
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
if (mcopy)
|
|
|
|
goto freecopy;
|
|
|
|
}
|
|
|
|
}
|
2001-06-12 19:12:33 +04:00
|
|
|
|
2001-06-12 21:55:52 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
2001-06-12 19:12:33 +04:00
|
|
|
senderr:
|
2001-06-12 21:55:52 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
if (mcopy == NULL)
|
|
|
|
return;
|
|
|
|
switch (error) {
|
|
|
|
case 0:
|
|
|
|
if (type == ND_REDIRECT) {
|
|
|
|
icmp6_redirect_output(mcopy, rt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
goto freecopy;
|
|
|
|
|
|
|
|
case EMSGSIZE:
|
|
|
|
/* xxx MTU is constant in PPP? */
|
|
|
|
goto freecopy;
|
|
|
|
|
|
|
|
case ENOBUFS:
|
|
|
|
/* Tell source to slow down like source quench in IP? */
|
|
|
|
goto freecopy;
|
|
|
|
|
|
|
|
case ENETUNREACH: /* shouldn't happen, checked above */
|
|
|
|
case EHOSTUNREACH:
|
|
|
|
case ENETDOWN:
|
|
|
|
case EHOSTDOWN:
|
|
|
|
default:
|
|
|
|
type = ICMP6_DST_UNREACH;
|
|
|
|
code = ICMP6_DST_UNREACH_ADDR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
icmp6_error(mcopy, type, code, 0);
|
|
|
|
return;
|
|
|
|
|
|
|
|
freecopy:
|
|
|
|
m_freem(mcopy);
|
1999-12-13 18:17:17 +03:00
|
|
|
return;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|