diff options
| author | itojun <itojun@NetBSD.org> | 2000-06-03 14:36:32 +0000 |
|---|---|---|
| committer | itojun <itojun@NetBSD.org> | 2000-06-03 14:36:32 +0000 |
| commit | 9d853e8a4f8fa3e53db092f9f7fc62a6a4574ac3 (patch) | |
| tree | c03059b4646054eb9b2ab87f0734c6e36bd16261 /sys | |
| parent | 07af7409462461d6bff49e5cfb04cda71d10c94e (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/files | 3 | ||||
| -rw-r--r-- | sys/netinet6/in6_pcb.c | 326 | ||||
| -rw-r--r-- | sys/netinet6/in6_src.c | 388 | ||||
| -rw-r--r-- | sys/netinet6/ip6_forward.c | 20 | ||||
| -rw-r--r-- | sys/netinet6/ip6_output.c | 62 |
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); } /* |
