diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2000-06-18 17:27:06 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2000-06-18 17:27:06 +0000 |
commit | 3871913bac8264db93680acf112ca99686da194c (patch) | |
tree | e96d8f1428a5d9396e16b8b3e713f97bfd8453d9 | |
parent | a959a3722979774302ecb8b649beae09a818a51e (diff) |
use in6_recoverscope
-rw-r--r-- | sys/netinet6/in6_pcb.c | 290 |
1 files changed, 167 insertions, 123 deletions
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index ba6e7fb3834..2df325de5e0 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,33 @@ -/* $OpenBSD: in6_pcb.c,v 1.15 2000/06/13 10:12:01 itojun Exp $ */ +/* $OpenBSD: in6_pcb.c,v 1.16 2000/06/18 17:27:05 itojun 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-nrl-95 @@ -264,112 +293,123 @@ in6_pcbbind(inp, nam) } } - if (lport == 0) { - /* This code block was derived from OpenBSD */ - uint16_t first, last, old = 0; - int count; - int loopcount = 0; - struct in_addr fa, la; - u_int16_t *lastport; - - lastport = &inp->inp_table->inpt_lastport; - - if (inp->inp_flags & INP_IPV6_MAPPED) { - la.s_addr = inp->inp_laddr6.s6_addr32[3]; - fa.s_addr = 0; - wild &= ~INPLOOKUP_IPV6; - }; - - if (inp->inp_flags & INP_HIGHPORT) { - first = ipport_hifirstauto; /* sysctl */ - last = ipport_hilastauto; - } else if (inp->inp_flags & INP_LOWPORT) { - if ((error = suser(p->p_ucred, &p->p_acflag))) - return (EACCES); - - first = IPPORT_RESERVED-1; /* 1023 */ - last = 600; /* not IPPORT_RESERVED/2 */ - } else { - first = ipport_firstauto; /* sysctl */ - last = ipport_lastauto; - } + if (lport == 0) { + error = in6_pcbsetport(&inp->inp_laddr6, inp); + if (error != 0) + return error; + } else + inp->inp_lport = lport; - /* - * Simple check to ensure all ports are not used up causing - * a deadlock here. - * - * We split the two cases (up and down) so that the direction - * is not being tested on each round of the loop. - */ + in_pcbrehash(inp); -portloop: - if (first > last) { - /* - * counting down - */ - if (loopcount == 0) { /* only do this once. */ - old = first; - first -= (arc4random() % (first - last)); - } - count = first - last; - *lastport = first; /* restart each time */ - - do { - if (count-- <= 0) { /* completely used? */ - if (loopcount == 0) { - last = old; - loopcount++; - goto portloop; - } - return (EADDRNOTAVAIL); + return 0; +} + +int +in6_pcbsetport(laddr, inp) + struct in6_addr *laddr; + struct inpcb *inp; +{ + struct socket *so = inp->inp_socket; + struct inpcbtable *table = inp->inp_table; + u_int16_t first, last, old = 0; + u_int16_t *lastport = &inp->inp_table->inpt_lastport; + u_int16_t lport = 0; + int count; + int loopcount = 0; + int wild = INPLOOKUP_IPV6; + struct proc *p = curproc; /* XXX */ + int error; + + /* XXX we no longer support IPv4 mapped address, so no tweaks here */ + + if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && + ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || + (so->so_options & SO_ACCEPTCONN) == 0)) + wild |= INPLOOKUP_WILDCARD; + + if (inp->inp_flags & INP_HIGHPORT) { + first = ipport_hifirstauto; /* sysctl */ + last = ipport_hilastauto; + } else if (inp->inp_flags & INP_LOWPORT) { + if ((error = suser(p->p_ucred, &p->p_acflag))) + return (EACCES); + first = IPPORT_RESERVED-1; /* 1023 */ + last = 600; /* not IPPORT_RESERVED/2 */ + } else { + first = ipport_firstauto; /* sysctl */ + last = ipport_lastauto; } - --*lastport; - if (*lastport > first || *lastport < last) - *lastport = first; - lport = htons(*lastport); - } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) || - ((wild & INPLOOKUP_IPV6) ? - in_pcblookup(head, (struct in_addr *)&zeroin6_addr, 0, - (struct in_addr *)&inp->inp_laddr6, lport, wild) : - in_pcblookup(head, (struct in_addr *)&fa, 0, - (struct in_addr *)&la, lport, wild))); - } else { - /* - * counting up - */ - if (loopcount == 0) { /* only do this once. */ - old = first; - first += (arc4random() % (last - first)); - } - count = last - first; - *lastport = first; /* restart each time */ - - do { - if (count-- <= 0) { /* completely used? */ - if (loopcount == 0) { - first = old; - loopcount++; - goto portloop; - } - return (EADDRNOTAVAIL); + + /* + * Simple check to ensure all ports are not used up causing + * a deadlock here. + * + * We split the two cases (up and down) so that the direction + * is not being tested on each round of the loop. + */ + +portloop: + if (first > last) { + /* + * counting down + */ + if (loopcount == 0) { /* only do this once. */ + old = first; + first -= (arc4random() % (first - last)); + } + count = first - last; + *lastport = first; /* restart each time */ + + do { + if (count-- <= 0) { /* completely used? */ + if (loopcount == 0) { + last = old; + loopcount++; + goto portloop; + } + return (EADDRNOTAVAIL); + } + --*lastport; + if (*lastport > first || *lastport < last) + *lastport = first; + lport = htons(*lastport); + } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) || + in_pcblookup(table, &zeroin6_addr, 0, + &inp->inp_laddr6, lport, wild)); + } else { + /* + * counting up + */ + if (loopcount == 0) { /* only do this once. */ + old = first; + first += (arc4random() % (last - first)); + } + count = last - first; + *lastport = first; /* restart each time */ + + do { + if (count-- <= 0) { /* completely used? */ + if (loopcount == 0) { + first = old; + loopcount++; + goto portloop; + } + return (EADDRNOTAVAIL); + } + ++*lastport; + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) || + in_pcblookup(table, &zeroin6_addr, 0, + &inp->inp_laddr6, lport, wild)); } - ++*lastport; - if (*lastport < first || *lastport > last) - *lastport = first; - lport = htons(*lastport); - } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) || - ((wild & INPLOOKUP_IPV6) ? - in_pcblookup(head, (struct in_addr *)&zeroin6_addr, 0, - (struct in_addr *)&inp->inp_laddr6, lport, wild) : - in_pcblookup(head, (struct in_addr *)&fa, 0, - (struct in_addr *)&la, lport, wild))); - } - } - inp->inp_lport = lport; + inp->inp_lport = lport; + in_pcbrehash(inp); - /* XXX hash */ - return 0; + return 0; } /*---------------------------------------------------------------------- @@ -421,7 +461,7 @@ in6_pcbconnect(inp, nam) /* KAME hack: embed scopeid */ if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0) - return EINVAL; + return EINVAL; /* this must be cleared for ifa_ifwithaddr() */ sin6->sin6_scope_id = 0; @@ -541,12 +581,13 @@ in6_pcbnotify(head, dst, fport_arg, la, lport_arg, cmd, notify) /* * Redirects go to all references to the destination, - * and use in6_rtchange to invalidate the route cache. - * Dead host indications: also use in6_rtchange to invalidate + * and use in_rtchange to invalidate the route cache. + * Dead host indications: also use in_rtchange to invalidate * the cache, and deliver the error to all the sockets. * Otherwise, if we have knowledge of the local port and address, * deliver only to that socket. */ + if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { fport = 0; @@ -561,44 +602,43 @@ in6_pcbnotify(head, dst, fport_arg, la, lport_arg, cmd, notify) inp != (struct inpcb *)&head->inpt_queue; inp = ninp) { ninp = inp->inp_queue.cqe_next; + #ifdef INET6 - if (!(inp->inp_flags & INP_IPV6)) - continue; + if ((inp->inp_flags & INP_IPV6) == 0) + continue; #endif - if (do_rtchange) - { - /* - * Since a non-connected PCB might have a cached route, - * we always call in_rtchange without matching - * the PCB to the src/dst pair. - * - * XXX: we assume in_rtchange does not free the PCB. - */ - if (IN6_ARE_ADDR_EQUAL(&inp->inp_route6.ro_dst.sin6_addr, faddr)) + + if (do_rtchange) { + /* + * Since a non-connected PCB might have a cached route, + * we always call in_rtchange without matching + * the PCB to the src/dst pair. + * + * XXX: we assume in_rtchange does not free the PCB. + */ + if (IN6_ARE_ADDR_EQUAL(&inp->inp_route6.ro_dst.sin6_addr, faddr)) { { in_rtchange(inp, errno); } if (notify == in_rtchange) - { - continue; /* there's nothing to do any more */ - } + continue; /* there's nothing to do any more */ } + } + if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) || !inp->inp_socket || (lport && inp->inp_lport != lport) || (!IN6_IS_ADDR_UNSPECIFIED(&laddr) && !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &laddr)) || (fport && inp->inp_fport != fport)) { + inp = inp->inp_queue.cqe_next; continue; } - nmatch++; if (notify) - { - (*notify)(inp, errno); - } + (*notify)(inp, errno); } return 0; } @@ -623,6 +663,9 @@ in6_setsockaddr(inp, nam) sin6->sin6_len = sizeof(struct sockaddr_in6); sin6->sin6_port = inp->inp_lport; sin6->sin6_addr = inp->inp_laddr6; + /* KAME hack: recover scopeid */ + (void)in6_recoverscope(sin6, &inp->inp_laddr6, NULL); + return 0; } @@ -647,5 +690,6 @@ in6_setpeeraddr(inp, nam) sin6->sin6_port = inp->inp_fport; sin6->sin6_addr = inp->inp_faddr6; sin6->sin6_flowinfo = inp->inp_fflowinfo; + return 0; } |