Author: bz
Date: Sat Mar 12 21:46:37 2011
New Revision: 219579
URL: http://svn.freebsd.org/changeset/base/219579

Log:
  Merge the two identical implementations for local port selections from
  in_pcbbind_setup() and in6_pcbsetport() in a single in_pcb_lport().
  
  MFC after:    2 weeks

Modified:
  head/sys/netinet/in_pcb.c
  head/sys/netinet/in_pcb.h
  head/sys/netinet6/in6_src.c

Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c   Sat Mar 12 21:13:08 2011        (r219578)
+++ head/sys/netinet/in_pcb.c   Sat Mar 12 21:46:37 2011        (r219579)
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 
 #include "opt_ddb.h"
 #include "opt_ipsec.h"
+#include "opt_inet.h"
 #include "opt_inet6.h"
 
 #include <sys/param.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 */
 
 
@@ -312,6 +314,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 = V_ipport_hifirstauto;   /* sysctl */
+               last  = V_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 = V_ipport_lowfirstauto;  /* 1023 */
+               last  = V_ipport_lowlastauto;   /* 600 */
+               lastport = &pcbinfo->ipi_lastlow;
+       } else {
+               first = V_ipport_firstauto;     /* sysctl */
+               last  = V_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 (V_ipport_randomized &&
+               (!V_ipport_stoprandom || pcbinfo == &V_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 != &V_udbinfo)
+               V_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
@@ -326,14 +446,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
@@ -458,72 +576,10 @@ in_pcbbind_setup(struct inpcb *inp, stru
        if (*lportp != 0)
                lport = *lportp;
        if (lport == 0) {
-               u_short first, last, aux;
-               int count;
-
-               if (inp->inp_flags & INP_HIGHPORT) {
-                       first = V_ipport_hifirstauto;   /* sysctl */
-                       last  = V_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 = V_ipport_lowfirstauto;  /* 1023 */
-                       last  = V_ipport_lowlastauto;   /* 600 */
-                       lastport = &pcbinfo->ipi_lastlow;
-               } else {
-                       first = V_ipport_firstauto;     /* sysctl */
-                       last  = V_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 (V_ipport_randomized &&
-                       (!V_ipport_stoprandom || pcbinfo == &V_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 != &V_udbinfo)
-                       V_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;
-               }
-
-               if (dorandom)
-                       *lastport = first +
-                                   (arc4random() % (last - first));
-
-               count = last - first;
+               error = in_pcb_lport(inp, &laddr, &lport, cred, wild);
+               if (error != 0)
+                       return (error);
 
-               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));
        }
        *laddrp = laddr.s_addr;
        *lportp = lport;

Modified: head/sys/netinet/in_pcb.h
==============================================================================
--- head/sys/netinet/in_pcb.h   Sat Mar 12 21:13:08 2011        (r219578)
+++ head/sys/netinet/in_pcb.h   Sat Mar 12 21:46:37 2011        (r219579)
@@ -491,6 +491,8 @@ void        in_pcbinfo_init(struct inpcbinfo *,
 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: head/sys/netinet6/in6_src.c
==============================================================================
--- head/sys/netinet6/in6_src.c Sat Mar 12 21:13:08 2011        (r219578)
+++ head/sys/netinet6/in6_src.c Sat Mar 12 21:46:37 2011        (r219579)
@@ -850,9 +850,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);
@@ -868,71 +870,9 @@ in6_pcbsetport(struct in6_addr *laddr, s
 
        inp->inp_flags |= INP_ANONPORT;
 
-       if (inp->inp_flags & INP_HIGHPORT) {
-               first = V_ipport_hifirstauto;   /* sysctl */
-               last  = V_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 = V_ipport_lowfirstauto;  /* 1023 */
-               last  = V_ipport_lowlastauto;   /* 600 */
-               lastport = &pcbinfo->ipi_lastlow;
-       } else {
-               first = V_ipport_firstauto;     /* sysctl */
-               last  = V_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 (V_ipport_randomized &&
-           (!V_ipport_stoprandom || pcbinfo == &V_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 != &V_udbinfo)
-               V_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) {
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to