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:
itojun 2000-06-03 14:36:32 +00:00
parent 07af740946
commit 9d853e8a4f
5 changed files with 463 additions and 336 deletions

View File

@ -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

View File

@ -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. */

388
sys/netinet6/in6_src.c Normal file
View File

@ -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 */
}

View File

@ -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])];

View File

@ -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);
}
/*