Date: Tue, 19 Apr 2011 07:45:55 +0000 (UTC) From: "Bjoern A. Zeeb" <bz@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r220817 - in stable/7/sys: netinet netinet6 Message-ID: <201104190745.p3J7jt8S098737@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: bz Date: Tue Apr 19 07:45:54 2011 New Revision: 220817 URL: http://svn.freebsd.org/changeset/base/220817 Log: MFC r219579: Merge the two (logically) identical implementations for local port selections from in_pcbbind_setup() and in6_pcbsetport() in a single in_pcb_lport(). Modified: stable/7/sys/netinet/in_pcb.c stable/7/sys/netinet/in_pcb.h stable/7/sys/netinet6/in6_src.c Directory Properties: stable/7/sys/ (props changed) stable/7/sys/cddl/contrib/opensolaris/ (props changed) stable/7/sys/contrib/dev/acpica/ (props changed) stable/7/sys/contrib/pf/ (props changed) Modified: stable/7/sys/netinet/in_pcb.c ============================================================================== --- stable/7/sys/netinet/in_pcb.c Tue Apr 19 07:44:12 2011 (r220816) +++ stable/7/sys/netinet/in_pcb.c Tue Apr 19 07:45:54 2011 (r220817) @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_ipsec.h" +#include "opt_inet.h" #include "opt_inet6.h" #include "opt_mac.h" @@ -73,6 +74,7 @@ __FBSDID("$FreeBSD$"); #ifdef INET6 #include <netinet/ip6.h> #include <netinet6/ip6_var.h> +#include <netinet6/in6_pcb.h> #endif /* INET6 */ @@ -257,6 +259,124 @@ in_pcbbind(struct inpcb *inp, struct soc return (0); } +#if defined(INET) || defined(INET6) +int +in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp, + struct ucred *cred, int wild) +{ + struct inpcbinfo *pcbinfo; + struct inpcb *tmpinp; + unsigned short *lastport; + int count, dorandom, error; + u_short aux, first, last, lport; +#ifdef INET + struct in_addr laddr; +#endif + + pcbinfo = inp->inp_pcbinfo; + + /* + * Because no actual state changes occur here, a global write lock on + * the pcbinfo isn't required. + */ + INP_INFO_LOCK_ASSERT(pcbinfo); + INP_LOCK_ASSERT(inp); + + if (inp->inp_flags & INP_HIGHPORT) { + first = ipport_hifirstauto; /* sysctl */ + last = ipport_hilastauto; + lastport = &pcbinfo->ipi_lasthi; + } else if (inp->inp_flags & INP_LOWPORT) { + error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0); + if (error) + return (error); + first = ipport_lowfirstauto; /* 1023 */ + last = ipport_lowlastauto; /* 600 */ + lastport = &pcbinfo->ipi_lastlow; + } else { + first = ipport_firstauto; /* sysctl */ + last = ipport_lastauto; + lastport = &pcbinfo->ipi_lastport; + } + /* + * For UDP, use random port allocation as long as the user + * allows it. For TCP (and as of yet unknown) connections, + * use random port allocation only if the user allows it AND + * ipport_tick() allows it. + */ + if (ipport_randomized && + (!ipport_stoprandom || pcbinfo == &udbinfo)) + dorandom = 1; + else + dorandom = 0; + /* + * It makes no sense to do random port allocation if + * we have the only port available. + */ + if (first == last) + dorandom = 0; + /* Make sure to not include UDP packets in the count. */ + if (pcbinfo != &udbinfo) + ipport_tcpallocs++; + /* + * Instead of having two loops further down counting up or down + * make sure that first is always <= last and go with only one + * code path implementing all logic. + */ + if (first > last) { + aux = first; + first = last; + last = aux; + } + +#ifdef INET + /* Make the compiler happy. */ + laddr.s_addr = 0; + if ((inp->inp_vflag & INP_IPV4) != 0) { + KASSERT(laddrp != NULL, ("%s: laddrp NULL for v4 inp %p", + __func__, inp)); + laddr = *laddrp; + } +#endif + lport = *lportp; + + if (dorandom) + *lastport = first + (arc4random() % (last - first)); + + count = last - first; + + do { + if (count-- < 0) /* completely used? */ + return (EADDRNOTAVAIL); + ++*lastport; + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV6) != 0) + tmpinp = in6_pcblookup_local(pcbinfo, + &inp->in6p_laddr, lport, wild, cred); +#endif +#if defined(INET) && defined(INET6) + else +#endif +#ifdef INET + tmpinp = in_pcblookup_local(pcbinfo, laddr, + lport, wild, cred); +#endif + } while (tmpinp != NULL); + +#ifdef INET + if ((inp->inp_vflag & INP_IPV4) != 0) + laddrp->s_addr = laddr.s_addr; +#endif + *lportp = lport; + + return (0); +} +#endif /* INET || INET6 */ + /* * Set up a bind operation on a PCB, performing port allocation * as required, but do not actually modify the PCB. Callers can @@ -271,14 +391,12 @@ in_pcbbind_setup(struct inpcb *inp, stru u_short *lportp, struct ucred *cred) { struct socket *so = inp->inp_socket; - unsigned short *lastport; struct sockaddr_in *sin; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; struct in_addr laddr; u_short lport = 0; int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); int error; - int dorandom; /* * Because no actual state changes occur here, a global write lock on @@ -397,91 +515,9 @@ in_pcbbind_setup(struct inpcb *inp, stru if (*lportp != 0) lport = *lportp; if (lport == 0) { - u_short first, last; - int count; - - if (inp->inp_flags & INP_HIGHPORT) { - first = ipport_hifirstauto; /* sysctl */ - last = ipport_hilastauto; - lastport = &pcbinfo->ipi_lasthi; - } else if (inp->inp_flags & INP_LOWPORT) { - error = priv_check_cred(cred, - PRIV_NETINET_RESERVEDPORT, 0); - if (error) - return error; - first = ipport_lowfirstauto; /* 1023 */ - last = ipport_lowlastauto; /* 600 */ - lastport = &pcbinfo->ipi_lastlow; - } else { - first = ipport_firstauto; /* sysctl */ - last = ipport_lastauto; - lastport = &pcbinfo->ipi_lastport; - } - /* - * For UDP, use random port allocation as long as the user - * allows it. For TCP (and as of yet unknown) connections, - * use random port allocation only if the user allows it AND - * ipport_tick() allows it. - */ - if (ipport_randomized && - (!ipport_stoprandom || pcbinfo == &udbinfo)) - dorandom = 1; - else - dorandom = 0; - /* - * It makes no sense to do random port allocation if - * we have the only port available. - */ - if (first == last) - dorandom = 0; - /* Make sure to not include UDP packets in the count. */ - if (pcbinfo != &udbinfo) - ipport_tcpallocs++; - /* - * Instead of having two loops further down counting up or down - * make sure that first is always <= last and go with only one - * code path implementing all logic. - * - * We split the two cases (up and down) so that the direction - * is not being tested on each round of the loop. - */ - if (first > last) { - /* - * counting down - */ - if (dorandom) - *lastport = first - - (arc4random() % (first - last)); - count = first - last; - - do { - if (count-- < 0) /* completely used? */ - return (EADDRNOTAVAIL); - --*lastport; - if (*lastport > first || *lastport < last) - *lastport = first; - lport = htons(*lastport); - } while (in_pcblookup_local(pcbinfo, laddr, lport, - wild, cred)); - } else { - /* - * counting up - */ - if (dorandom) - *lastport = first + - (arc4random() % (last - first)); - count = last - first; - - do { - if (count-- < 0) /* completely used? */ - return (EADDRNOTAVAIL); - ++*lastport; - if (*lastport < first || *lastport > last) - *lastport = first; - lport = htons(*lastport); - } while (in_pcblookup_local(pcbinfo, laddr, lport, - wild, cred)); - } + error = in_pcb_lport(inp, &laddr, &lport, cred, wild); + if (error != 0) + return (error); } *laddrp = laddr.s_addr; *lportp = lport; Modified: stable/7/sys/netinet/in_pcb.h ============================================================================== --- stable/7/sys/netinet/in_pcb.h Tue Apr 19 07:44:12 2011 (r220816) +++ stable/7/sys/netinet/in_pcb.h Tue Apr 19 07:45:54 2011 (r220817) @@ -496,6 +496,8 @@ extern struct callout ipport_tick_callou void in_pcbpurgeif0(struct inpcbinfo *, struct ifnet *); int in_pcballoc(struct socket *, struct inpcbinfo *); int in_pcbbind(struct inpcb *, struct sockaddr *, struct ucred *); +int in_pcb_lport(struct inpcb *, struct in_addr *, u_short *, + struct ucred *, int); int in_pcbbind_setup(struct inpcb *, struct sockaddr *, in_addr_t *, u_short *, struct ucred *); int in_pcbconnect(struct inpcb *, struct sockaddr *, struct ucred *); Modified: stable/7/sys/netinet6/in6_src.c ============================================================================== --- stable/7/sys/netinet6/in6_src.c Tue Apr 19 07:44:12 2011 (r220816) +++ stable/7/sys/netinet6/in6_src.c Tue Apr 19 07:45:54 2011 (r220817) @@ -783,9 +783,11 @@ int in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred) { struct socket *so = inp->inp_socket; - u_int16_t lport = 0, first, last, *lastport; - int count, error, wild = 0, dorandom; + u_int16_t lport = 0; + int error, wild = 0; +#ifdef INVARIANTS struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; +#endif INP_INFO_WLOCK_ASSERT(pcbinfo); INP_WLOCK_ASSERT(inp); @@ -801,71 +803,9 @@ in6_pcbsetport(struct in6_addr *laddr, s inp->inp_flags |= INP_ANONPORT; - if (inp->inp_flags & INP_HIGHPORT) { - first = ipport_hifirstauto; /* sysctl */ - last = ipport_hilastauto; - lastport = &pcbinfo->ipi_lasthi; - } else if (inp->inp_flags & INP_LOWPORT) { - error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0); - if (error) - return error; - first = ipport_lowfirstauto; /* 1023 */ - last = ipport_lowlastauto; /* 600 */ - lastport = &pcbinfo->ipi_lastlow; - } else { - first = ipport_firstauto; /* sysctl */ - last = ipport_lastauto; - lastport = &pcbinfo->ipi_lastport; - } - - /* - * For UDP, use random port allocation as long as the user - * allows it. For TCP (and as of yet unknown) connections, - * use random port allocation only if the user allows it AND - * ipport_tick() allows it. - */ - if (ipport_randomized && - (!ipport_stoprandom || pcbinfo == &udbinfo)) - dorandom = 1; - else - dorandom = 0; - /* - * It makes no sense to do random port allocation if - * we have the only port available. - */ - if (first == last) - dorandom = 0; - /* Make sure to not include UDP packets in the count. */ - if (pcbinfo != &udbinfo) - ipport_tcpallocs++; - - /* - * Instead of having two loops further down counting up or down - * make sure that first is always <= last and go with only one - * code path implementing all logic. - */ - if (first > last) { - u_int16_t aux; - - aux = first; - first = last; - last = aux; - } - - if (dorandom) - *lastport = first + (arc4random() % (last - first)); - - count = last - first; - - do { - if (count-- < 0) /* completely used? */ - return (EADDRNOTAVAIL); - ++*lastport; - if (*lastport < first || *lastport > last) - *lastport = first; - lport = htons(*lastport); - } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, - lport, wild, cred)); + error = in_pcb_lport(inp, NULL, &lport, cred, wild); + if (error != 0) + return (error); inp->inp_lport = lport; if (in_pcbinshash(inp) != 0) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201104190745.p3J7jt8S098737>