summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authoritojun <itojun@NetBSD.org>2000-06-03 14:36:32 +0000
committeritojun <itojun@NetBSD.org>2000-06-03 14:36:32 +0000
commit9d853e8a4f8fa3e53db092f9f7fc62a6a4574ac3 (patch)
treec03059b4646054eb9b2ab87f0734c6e36bd16261 /sys
parent07af7409462461d6bff49e5cfb04cda71d10c94e (diff)
sync with kame.
- use latest source address selection code - in6_src.c. - correct frag header insertion. - deep copy ip6 header portion in ip6_mloopback to avoid overwrite. - do not bark when we forward packet to loopback. - some cosmetics.
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files3
-rw-r--r--sys/netinet6/in6_pcb.c326
-rw-r--r--sys/netinet6/in6_src.c388
-rw-r--r--sys/netinet6/ip6_forward.c20
-rw-r--r--sys/netinet6/ip6_output.c62
5 files changed, 463 insertions, 336 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 0c19456827f..81f8bf127a0 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.369 2000/05/30 00:48:47 matt Exp $
+# $NetBSD: files,v 1.370 2000/06/03 14:36:32 itojun Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -861,6 +861,7 @@ file netinet6/in6_ifattach.c inet6
file netinet6/in6_pcb.c inet6
file netinet6/in6_prefix.c inet6
file netinet6/in6_proto.c inet6
+file netinet6/in6_src.c inet6
file netinet6/ip6_forward.c inet6
file netinet6/ip6_input.c inet6
file netinet6/ip6_mroute.c inet6
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index ca01a52e4b2..9610d39f15c 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -1,10 +1,10 @@
-/* $NetBSD: in6_pcb.c,v 1.22 2000/05/29 00:03:18 itojun Exp $ */
-/* $KAME: in6_pcb.c,v 1.43 2000/05/28 23:25:07 itojun Exp $ */
+/* $NetBSD: in6_pcb.c,v 1.23 2000/06/03 14:36:35 itojun Exp $ */
+/* $KAME: in6_pcb.c,v 1.44 2000/06/02 12:14:50 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 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.
- *
+ *
* 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
@@ -191,7 +191,7 @@ in6_pcbbind(in6p, nam)
htons(in6p->in6p_moptions->im6o_multicast_ifp->if_index);
} else if (sin6->sin6_scope_id) {
/* boundary check */
- if (sin6->sin6_scope_id < 0
+ if (sin6->sin6_scope_id < 0
|| if_index < sin6->sin6_scope_id) {
return ENXIO; /* XXX EINVAL? */
}
@@ -291,78 +291,6 @@ in6_pcbbind(in6p, nam)
}
/*
- * Find an empty port and set it to the specified PCB.
- */
-int
-in6_pcbsetport(laddr, in6p)
- struct in6_addr *laddr;
- struct in6pcb *in6p;
-{
- struct socket *so = in6p->in6p_socket;
- struct in6pcb *head = in6p->in6p_head;
- u_int16_t last_port, lport = 0;
- int wild = 0;
- void *t;
- u_int16_t min, max;
-#ifndef IPNOPRIVPORTS
- struct proc *p = curproc; /*XXX*/
-#endif
-
- /* XXX: this is redundant when called from in6_pcbbind */
- if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
- ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
- (so->so_options & SO_ACCEPTCONN) == 0))
- wild = IN6PLOOKUP_WILDCARD;
-
- if (in6p->in6p_flags & IN6P_LOWPORT) {
-#ifndef IPNOPRIVPORTS
- if (p == 0 || (suser(p->p_ucred, &p->p_acflag) != 0))
- return (EACCES);
-#endif
- min = IPV6PORT_RESERVEDMIN;
- max = IPV6PORT_RESERVEDMAX;
- } else {
- min = IPV6PORT_ANONMIN;
- max = IPV6PORT_ANONMAX;
- }
-
- /* value out of range */
- if (head->in6p_lport < min)
- head->in6p_lport = min;
- else if (head->in6p_lport > max)
- head->in6p_lport = min;
- last_port = head->in6p_lport;
- goto startover; /*to randomize*/
- for (;;) {
- lport = htons(head->in6p_lport);
- if (IN6_IS_ADDR_V4MAPPED(laddr)) {
-#if 0
- t = in_pcblookup_bind(&tcbtable,
- (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
- lport);
-#else
- t = NULL;
-#endif
- } else {
- t = in6_pcblookup(head, &zeroin6_addr, 0, laddr,
- lport, wild);
- }
- if (t == 0)
- break;
- startover:
- if (head->in6p_lport >= max)
- head->in6p_lport = min;
- else
- head->in6p_lport++;
- if (head->in6p_lport == last_port)
- return (EADDRINUSE);
- }
-
- in6p->in6p_lport = lport;
- return(0); /* success */
-}
-
-/*
* Connect from a socket to a specified address.
* Both address and port must be specified in argument sin6.
* If don't have a local address for this socket yet,
@@ -421,7 +349,7 @@ in6_pcbconnect(in6p, nam)
ifp = ifindex2ifnet[in6p->in6p_moptions->im6o_multicast_ifp->if_index];
} else if (sin6->sin6_scope_id) {
/* boundary check */
- if (sin6->sin6_scope_id < 0
+ if (sin6->sin6_scope_id < 0
|| if_index < sin6->sin6_scope_id) {
return ENXIO; /* XXX EINVAL? */
}
@@ -498,227 +426,6 @@ in6_pcbconnect(in6p, nam)
return(0);
}
-/*
- * Return an IPv6 address, which is the most appropriate for given
- * destination and user specified options.
- * If necessary, this function lookups the routing table and return
- * an entry to the caller for later use.
- */
-struct in6_addr *
-in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
- struct sockaddr_in6 *dstsock;
- struct ip6_pktopts *opts;
- struct ip6_moptions *mopts;
- struct route_in6 *ro;
- struct in6_addr *laddr;
- int *errorp;
-{
- struct in6_addr *dst;
- struct in6_ifaddr *ia6 = 0;
- struct in6_pktinfo *pi = NULL;
-
- dst = &dstsock->sin6_addr;
- *errorp = 0;
-
- /*
- * If the source address is explicitly specified by the caller,
- * use it.
- */
- if (opts && (pi = opts->ip6po_pktinfo) &&
- !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
- return(&pi->ipi6_addr);
-
- /*
- * If the source address is not specified but the socket(if any)
- * is already bound, use the bound address.
- */
- if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
- return(laddr);
-
- /*
- * If the caller doesn't specify the source address but
- * the outgoing interface, use an address associated with
- * the interface.
- */
- if (pi && pi->ipi6_ifindex) {
- /* XXX boundary check is assumed to be already done. */
- ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
- dst);
- if (ia6 == 0) {
- *errorp = EADDRNOTAVAIL;
- return(0);
- }
- return(&satosin6(&ia6->ia_addr)->sin6_addr);
- }
-
- /*
- * If the destination address is a link-local unicast address or
- * a multicast address, and if the outgoing interface is specified
- * by the sin6_scope_id filed, use an address associated with the
- * interface.
- * XXX: We're now trying to define more specific semantics of
- * sin6_scope_id field, so this part will be rewritten in
- * the near future.
- */
- if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
- dstsock->sin6_scope_id) {
- /*
- * I'm not sure if boundary check for scope_id is done
- * somewhere...
- */
- if (dstsock->sin6_scope_id < 0 ||
- if_index < dstsock->sin6_scope_id) {
- *errorp = ENXIO; /* XXX: better error? */
- return(0);
- }
- ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
- dst);
- if (ia6 == 0) {
- *errorp = EADDRNOTAVAIL;
- return(0);
- }
- return(&satosin6(&ia6->ia_addr)->sin6_addr);
- }
-
- /*
- * If the destination address is a multicast address and
- * the outgoing interface for the address is specified
- * by the caller, use an address associated with the interface.
- * There is a sanity check here; if the destination has node-local
- * scope, the outgoing interfacde should be a loopback address.
- * Even if the outgoing interface is not specified, we also
- * choose a loopback interface as the outgoing interface.
- */
- if (IN6_IS_ADDR_MULTICAST(dst)) {
- struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
-
- if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
- ifp = &loif[0];
- }
-
- if (ifp) {
- ia6 = in6_ifawithscope(ifp, dst);
- if (ia6 == 0) {
- *errorp = EADDRNOTAVAIL;
- return(0);
- }
- return(&satosin6(&ia6->ia_addr)->sin6_addr);
- }
- }
-
- /*
- * If the next hop address for the packet is specified
- * by caller, use an address associated with the route
- * to the next hop.
- */
- {
- struct sockaddr_in6 *sin6_next;
- struct rtentry *rt;
-
- if (opts && opts->ip6po_nexthop) {
- sin6_next = satosin6(opts->ip6po_nexthop);
- rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
- if (rt) {
- ia6 = in6_ifawithscope(rt->rt_ifp, dst);
- if (ia6 == 0)
- ia6 = ifatoia6(rt->rt_ifa);
- }
- if (ia6 == 0) {
- *errorp = EADDRNOTAVAIL;
- return(0);
- }
- return(&satosin6(&ia6->ia_addr)->sin6_addr);
- }
- }
-
- /*
- * If route is known or can be allocated now,
- * our src addr is taken from the i/f, else punt.
- */
- if (ro) {
- if (ro->ro_rt &&
- !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
- RTFREE(ro->ro_rt);
- ro->ro_rt = (struct rtentry *)0;
- }
- if (ro->ro_rt == (struct rtentry *)0 ||
- ro->ro_rt->rt_ifp == (struct ifnet *)0) {
- /* No route yet, so try to acquire one */
- bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
- ro->ro_dst.sin6_family = AF_INET6;
- ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
- ro->ro_dst.sin6_addr = *dst;
- if (IN6_IS_ADDR_MULTICAST(dst)) {
- ro->ro_rt = rtalloc1(&((struct route *)ro)
- ->ro_dst, 0);
- } else {
- rtalloc((struct route *)ro);
- }
-
- }
-
- /*
- * in_pcbconnect() checks out IFF_LOOPBACK to skip using
- * the address. But we don't know why it does so.
- * It is necessary to ensure the scope even for lo0
- * so doesn't check out IFF_LOOPBACK.
- */
-
- if (ro->ro_rt) {
- ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
- if (ia6 == 0) /* xxx scope error ?*/
- ia6 = ifatoia6(ro->ro_rt->rt_ifa);
- }
-#if 0
- /*
- * xxx The followings are necessary? (kazu)
- * I don't think so.
- * It's for SO_DONTROUTE option in IPv4.(jinmei)
- */
- if (ia6 == 0) {
- struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
-
- sin6->sin6_addr = *dst;
-
- ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
- if (ia6 == 0)
- ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
- if (ia6 == 0)
- return(0);
- return(&satosin6(&ia6->ia_addr)->sin6_addr);
- }
-#endif /* 0 */
- if (ia6 == 0) {
- *errorp = EHOSTUNREACH; /* no route */
- return(0);
- }
- return(&satosin6(&ia6->ia_addr)->sin6_addr);
- }
-
- *errorp = EADDRNOTAVAIL;
- return(0);
-}
-
-/*
- * Default hop limit selection. The precedence is as follows:
- * 1. Hoplimit valued specified via ioctl.
- * 2. (If the outgoing interface is detected) the current
- * hop limit of the interface specified by router advertisement.
- * 3. The system default hoplimit.
-*/
-int
-in6_selecthlim(in6p, ifp)
- struct in6pcb *in6p;
- struct ifnet *ifp;
-{
- if (in6p && in6p->in6p_hops >= 0)
- return(in6p->in6p_hops);
- else if (ifp)
- return(nd_ifinfo[ifp->if_index].chlim);
- else
- return(ip6_defhlim);
-}
-
void
in6_pcbdisconnect(in6p)
struct in6pcb *in6p;
@@ -828,9 +535,7 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
u_int16_t fport = fport_arg, lport = lport_arg;
int errno;
int nmatch = 0;
- void (*notify2) __P((struct in6pcb *, int));
-
- notify2 = NULL;
+ int do_rtchange = (notify == in6_rtchange);
if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
return 0;
@@ -851,14 +556,7 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
lport = 0;
bzero((caddr_t)laddr6, sizeof(*laddr6));
- /*
- * Keep the old notify function to store a soft error
- * in each PCB.
- */
- if (cmd == PRC_HOSTDEAD && notify != in6_rtchange)
- notify2 = notify;
-
- notify = in6_rtchange;
+ do_rtchange = 1;
}
if (notify == NULL)
@@ -868,7 +566,7 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
for (in6p = head->in6p_next; in6p != head; in6p = nin6p) {
nin6p = in6p->in6p_next;
- if (notify == in6_rtchange) {
+ if (do_rtchange) {
/*
* Since a non-connected PCB might have a cached route,
* we always call in6_rtchange without matching
@@ -880,10 +578,8 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
&faddr6))
in6_rtchange(in6p, errno);
- if (notify2 == NULL)
- continue;
-
- notify = notify2;
+ if (notify == in6_rtchange)
+ continue; /* there's nothing to do any more */
}
/* at this point, we can assume that NOTIFY is not NULL. */
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
new file mode 100644
index 00000000000..8e60f5a16a5
--- /dev/null
+++ b/sys/netinet6/in6_src.c
@@ -0,0 +1,388 @@
+/* $NetBSD: in6_src.c,v 1.1 2000/06/03 14:36:36 itojun Exp $ */
+/* $KAME: in6_src.c,v 1.15 2000/05/30 10:16:24 jinmei Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
+ */
+
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/nd6.h>
+
+#include <net/net_osdep.h>
+
+#include "loop.h"
+extern struct ifnet loif[NLOOP];
+
+/*
+ * Return an IPv6 address, which is the most appropriate for given
+ * destination and user specified options.
+ * If necessary, this function lookups the routing table and return
+ * an entry to the caller for later use.
+ */
+struct in6_addr *
+in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
+ struct sockaddr_in6 *dstsock;
+ struct ip6_pktopts *opts;
+ struct ip6_moptions *mopts;
+ struct route_in6 *ro;
+ struct in6_addr *laddr;
+ int *errorp;
+{
+ struct in6_addr *dst;
+ struct in6_ifaddr *ia6 = 0;
+ struct in6_pktinfo *pi = NULL;
+
+ dst = &dstsock->sin6_addr;
+ *errorp = 0;
+
+ /*
+ * If the source address is explicitly specified by the caller,
+ * use it.
+ */
+ if (opts && (pi = opts->ip6po_pktinfo) &&
+ !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
+ return(&pi->ipi6_addr);
+
+ /*
+ * If the source address is not specified but the socket(if any)
+ * is already bound, use the bound address.
+ */
+ if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
+ return(laddr);
+
+ /*
+ * If the caller doesn't specify the source address but
+ * the outgoing interface, use an address associated with
+ * the interface.
+ */
+ if (pi && pi->ipi6_ifindex) {
+ /* XXX boundary check is assumed to be already done. */
+ ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
+ dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ /*
+ * If the destination address is a link-local unicast address or
+ * a multicast address, and if the outgoing interface is specified
+ * by the sin6_scope_id filed, use an address associated with the
+ * interface.
+ * XXX: We're now trying to define more specific semantics of
+ * sin6_scope_id field, so this part will be rewritten in
+ * the near future.
+ */
+ if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
+ dstsock->sin6_scope_id) {
+ /*
+ * I'm not sure if boundary check for scope_id is done
+ * somewhere...
+ */
+ if (dstsock->sin6_scope_id < 0 ||
+ if_index < dstsock->sin6_scope_id) {
+ *errorp = ENXIO; /* XXX: better error? */
+ return(0);
+ }
+ ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
+ dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ /*
+ * If the destination address is a multicast address and
+ * the outgoing interface for the address is specified
+ * by the caller, use an address associated with the interface.
+ * There is a sanity check here; if the destination has node-local
+ * scope, the outgoing interfacde should be a loopback address.
+ * Even if the outgoing interface is not specified, we also
+ * choose a loopback interface as the outgoing interface.
+ */
+ if (IN6_IS_ADDR_MULTICAST(dst)) {
+ struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
+
+ if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
+ ifp = &loif[0];
+ }
+
+ if (ifp) {
+ ia6 = in6_ifawithscope(ifp, dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+ }
+
+ /*
+ * If the next hop address for the packet is specified
+ * by caller, use an address associated with the route
+ * to the next hop.
+ */
+ {
+ struct sockaddr_in6 *sin6_next;
+ struct rtentry *rt;
+
+ if (opts && opts->ip6po_nexthop) {
+ sin6_next = satosin6(opts->ip6po_nexthop);
+ rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
+ if (rt) {
+ ia6 = in6_ifawithscope(rt->rt_ifp, dst);
+ if (ia6 == 0)
+ ia6 = ifatoia6(rt->rt_ifa);
+ }
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+ }
+
+ /*
+ * If route is known or can be allocated now,
+ * our src addr is taken from the i/f, else punt.
+ */
+ if (ro) {
+ if (ro->ro_rt &&
+ !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = (struct rtentry *)0;
+ }
+ if (ro->ro_rt == (struct rtentry *)0 ||
+ ro->ro_rt->rt_ifp == (struct ifnet *)0) {
+ /* No route yet, so try to acquire one */
+ bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
+ ro->ro_dst.sin6_family = AF_INET6;
+ ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
+ ro->ro_dst.sin6_addr = *dst;
+ ro->ro_dst.sin6_scope_id = dstsock->sin6_scope_id;
+ if (IN6_IS_ADDR_MULTICAST(dst)) {
+ ro->ro_rt = rtalloc1(&((struct route *)ro)
+ ->ro_dst, 0);
+ } else {
+ rtalloc((struct route *)ro);
+ }
+ }
+
+ /*
+ * in_pcbconnect() checks out IFF_LOOPBACK to skip using
+ * the address. But we don't know why it does so.
+ * It is necessary to ensure the scope even for lo0
+ * so doesn't check out IFF_LOOPBACK.
+ */
+
+ if (ro->ro_rt) {
+ ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
+ if (ia6 == 0) /* xxx scope error ?*/
+ ia6 = ifatoia6(ro->ro_rt->rt_ifa);
+ }
+#if 0
+ /*
+ * xxx The followings are necessary? (kazu)
+ * I don't think so.
+ * It's for SO_DONTROUTE option in IPv4.(jinmei)
+ */
+ if (ia6 == 0) {
+ struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
+
+ sin6->sin6_addr = *dst;
+
+ ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
+ if (ia6 == 0)
+ ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
+ if (ia6 == 0)
+ return(0);
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+#endif /* 0 */
+ if (ia6 == 0) {
+ *errorp = EHOSTUNREACH; /* no route */
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+}
+
+/*
+ * Default hop limit selection. The precedence is as follows:
+ * 1. Hoplimit value specified via ioctl.
+ * 2. (If the outgoing interface is detected) the current
+ * hop limit of the interface specified by router advertisement.
+ * 3. The system default hoplimit.
+*/
+int
+in6_selecthlim(in6p, ifp)
+ struct in6pcb *in6p;
+ struct ifnet *ifp;
+{
+ if (in6p && in6p->in6p_hops >= 0)
+ return(in6p->in6p_hops);
+ else if (ifp)
+ return(nd_ifinfo[ifp->if_index].chlim);
+ else
+ return(ip6_defhlim);
+}
+
+/*
+ * Find an empty port and set it to the specified PCB.
+ */
+int
+in6_pcbsetport(laddr, in6p)
+ struct in6_addr *laddr;
+ struct in6pcb *in6p;
+{
+ struct socket *so = in6p->in6p_socket;
+ struct in6pcb *head = in6p->in6p_head;
+ u_int16_t last_port, lport = 0;
+ int wild = 0;
+ void *t;
+ u_int16_t min, max;
+ struct proc *p = curproc; /* XXX */
+
+ /* XXX: this is redundant when called from in6_pcbbind */
+ if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
+ ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
+ (so->so_options & SO_ACCEPTCONN) == 0))
+ wild = IN6PLOOKUP_WILDCARD;
+
+ if (in6p->in6p_flags & IN6P_LOWPORT) {
+ if (p == 0 || (suser(p->p_ucred, &p->p_acflag) != 0))
+ return (EACCES);
+ min = IPV6PORT_RESERVEDMIN;
+ max = IPV6PORT_RESERVEDMAX;
+ } else {
+ min = IPV6PORT_ANONMIN;
+ max = IPV6PORT_ANONMAX;
+ }
+
+ /* value out of range */
+ if (head->in6p_lport < min)
+ head->in6p_lport = min;
+ else if (head->in6p_lport > max)
+ head->in6p_lport = min;
+ last_port = head->in6p_lport;
+ goto startover; /*to randomize*/
+ for (;;) {
+ lport = htons(head->in6p_lport);
+ if (IN6_IS_ADDR_V4MAPPED(laddr)) {
+#if 0
+ t = in_pcblookup_bind(&tcbtable,
+ (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
+ lport);
+#else
+ t = NULL;
+#endif
+ } else {
+ t = in6_pcblookup(head, &zeroin6_addr, 0, laddr,
+ lport, wild);
+ }
+ if (t == 0)
+ break;
+ startover:
+ if (head->in6p_lport >= max)
+ head->in6p_lport = min;
+ else
+ head->in6p_lport++;
+ if (head->in6p_lport == last_port)
+ return (EADDRINUSE);
+ }
+
+ in6p->in6p_lport = lport;
+ return(0); /* success */
+}
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 614c45f5cfc..43a75d268fa 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -1,5 +1,5 @@
-/* $NetBSD: ip6_forward.c,v 1.11 2000/05/19 20:09:26 itojun Exp $ */
-/* $KAME: ip6_forward.c,v 1.36 2000/05/19 19:10:06 itojun Exp $ */
+/* $NetBSD: ip6_forward.c,v 1.12 2000/06/03 14:36:36 itojun Exp $ */
+/* $KAME: ip6_forward.c,v 1.37 2000/05/28 12:17:19 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -442,12 +442,18 @@ ip6_forward(m, srcrt)
* 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)
+ * XXX: it is common to route invalid packets to loopback.
+ * (itojun)
*/
- 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));
+
+ if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0) {
+ 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));
+ }
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])];
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 692a8742f51..8daf101b153 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,5 +1,5 @@
-/* $NetBSD: ip6_output.c,v 1.21 2000/05/19 20:09:27 itojun Exp $ */
-/* $KAME: ip6_output.c,v 1.104 2000/05/19 19:10:07 itojun Exp $ */
+/* $NetBSD: ip6_output.c,v 1.22 2000/06/03 14:36:37 itojun Exp $ */
+/* $KAME: ip6_output.c,v 1.109 2000/05/31 05:03:09 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -174,8 +174,8 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
ip6 = mtod(m, struct ip6_hdr *);
#endif /* IPSEC */
-#define MAKE_EXTHDR(hp,mp) \
- { \
+#define MAKE_EXTHDR(hp, mp) \
+ do { \
if (hp) { \
struct ip6_ext *eh = (struct ip6_ext *)(hp); \
error = ip6_copyexthdr((mp), (caddr_t)(hp), \
@@ -183,8 +183,8 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
if (error) \
goto freehdrs; \
} \
- }
-
+ } while (0)
+
bzero(&exthdrs, sizeof(exthdrs));
if (opt) {
/* Hop-by-Hop options header */
@@ -322,8 +322,8 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
ip6->ip6_nxt = IPPROTO_DSTOPTS;
}
-#define MAKE_CHAIN(m,mp,p,i)\
- {\
+#define MAKE_CHAIN(m, mp, p, i)\
+ do {\
if (m) {\
if (!hdrsplit) \
panic("assumption failed: hdr not split"); \
@@ -334,7 +334,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
(mp)->m_next = (m);\
(mp) = (m);\
}\
- }
+ } while (0)
/*
* result: IPv6 hbh dest1 rthdr dest2 payload
* m will point to IPv6 header. mprev will point to the
@@ -1171,7 +1171,7 @@ ip6_insertfraghdr(m0, m, hlen, frghdrp)
;
if ((mlast->m_flags & M_EXT) == 0 &&
- M_TRAILINGSPACE(mlast) < sizeof(struct ip6_frag)) {
+ M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) {
/* use the trailing space of the last mbuf for the fragment hdr */
*frghdrp =
(struct ip6_frag *)(mtod(mlast, caddr_t) + mlast->m_len);
@@ -1214,6 +1214,7 @@ ip6_ctloutput(op, so, level, optname, mp)
case PRCO_SETOPT:
switch (optname) {
case IPV6_PKTOPTIONS:
+ /* m is freed in ip6_pcbopts */
return(ip6_pcbopts(&in6p->in6p_outputopts,
m, so));
case IPV6_HOPOPTS:
@@ -2099,11 +2100,46 @@ ip6_mloopback(ifp, m, dst)
register struct mbuf *m;
register struct sockaddr_in6 *dst;
{
- struct mbuf *copym;
+ struct mbuf *copym;
+ struct ip6_hdr *ip6;
copym = m_copy(m, 0, M_COPYALL);
- if (copym != NULL)
- (void)looutput(ifp, copym, (struct sockaddr *)dst, NULL);
+ if (copym == NULL)
+ return;
+
+ /*
+ * Make sure to deep-copy IPv6 header portion in case the data
+ * is in an mbuf cluster, so that we can safely override the IPv6
+ * header portion later.
+ */
+ if ((copym->m_flags & M_EXT) != 0 ||
+ copym->m_len < sizeof(struct ip6_hdr)) {
+ copym = m_pullup(copym, sizeof(struct ip6_hdr));
+ if (copym == NULL)
+ return;
+ }
+
+#ifdef DIAGNOSTIC
+ if (copym->m_len < sizeof(*ip6)) {
+ m_freem(copym);
+ return;
+ }
+#endif
+
+#ifndef FAKE_LOOPBACK_IF
+ if ((ifp->if_flags & IFF_LOOPBACK) == 0)
+#else
+ if (1)
+#endif
+ {
+ ip6 = mtod(copym, struct ip6_hdr *);
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
+ ip6->ip6_src.s6_addr16[1] = 0;
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
+ ip6->ip6_dst.s6_addr16[1] = 0;
+ }
+
+ (void)looutput(ifp, copym, (struct sockaddr *)dst, NULL);
}
/*