Skip site navigation (1)Skip section navigation (2)
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>