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.
This commit is contained in:
parent
07af740946
commit
9d853e8a4f
|
@ -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
|
||||
|
|
|
@ -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? */
|
||||
}
|
||||
|
@ -290,78 +290,6 @@ in6_pcbbind(in6p, nam)
|
|||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
}
|
|
@ -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])];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue