Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Jun 2013 15:30:02 GMT
From:      Mikolaj Golub <trociny@FreeBSD.org>
To:        freebsd-net@FreeBSD.org
Subject:   Re: kern/179901: [netinet] [patch] Multicast SO_REUSEADDR handled incorrectly
Message-ID:  <201306251530.r5PFU2fR095198@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/179901; it has been noted by GNATS.

From: Mikolaj Golub <trociny@FreeBSD.org>
To: Michael Gmelin <freebsd@grem.de>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/179901: [netinet] [patch] Multicast SO_REUSEADDR handled
 incorrectly
Date: Tue, 25 Jun 2013 18:24:55 +0300

 --tThc/1wpZn/ma/RB
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 On Tue, Jun 25, 2013 at 01:39:38PM +0200, Michael Gmelin wrote:
 
 > Yes, but it seems like your patch is fixing the not all places in
 > in6_pcb.c, I think you should modify the code at line 246 as well:
 > 
 >                         } else if (t && (reuseport == 0 ||
 >                             (t->inp_flags2 & INP_REUSEPORT) == 0)) {
 >                                 return (EADDRINUSE);
 >                         }
 > 
 > so it says
 >                         } else if (t &&
 >                             (reuseport & inp_so_options(t)) == 0) {
 > 		
 
 Good catch! I missed this because I was preparing the patch using
 r227207 as a reference, but this had been missed there too (fixed
 later in r233272 by glebius).
 
 > Once 1) has been resolved I can test on a machine running 9.1-RELEASE
 > later (the patch is small enough to apply it manually). I will run the
 > "unit test" code from multicast.c I sent earlier and add IPv6 test
 > cases to it as well.
 
 The updated patch is attached. Thanks.
 
 -- 
 Mikolaj Golub
 
 --tThc/1wpZn/ma/RB
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="pr179901.2.patch"
 
 Index: sys/netinet/in_pcb.c
 ===================================================================
 --- sys/netinet/in_pcb.c	(revision 251760)
 +++ sys/netinet/in_pcb.c	(working copy)
 @@ -467,6 +467,23 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *la
  
  	return (0);
  }
 +
 +/*
 + * Return cached socket options.
 + */
 +int
 +inp_so_options(const struct inpcb *inp)
 +{
 +   int so_options;
 +
 +   so_options = 0;
 +
 +   if ((inp->inp_flags2 & INP_REUSEPORT) != 0)
 +	   so_options |= SO_REUSEPORT;
 +   if ((inp->inp_flags2 & INP_REUSEADDR) != 0)
 +	   so_options |= SO_REUSEADDR;
 +   return (so_options);
 +}
  #endif /* INET || INET6 */
  
  #ifdef INET
 @@ -595,8 +612,7 @@ in_pcbbind_setup(struct inpcb *inp, struct sockadd
  				if (tw == NULL ||
  				    (reuseport & tw->tw_so_options) == 0)
  					return (EADDRINUSE);
 -			} else if (t && (reuseport == 0 ||
 -			    (t->inp_flags2 & INP_REUSEPORT) == 0)) {
 +			} else if (t && (reuseport & inp_so_options(t)) == 0) {
  #ifdef INET6
  				if (ntohl(sin->sin_addr.s_addr) !=
  				    INADDR_ANY ||
 Index: sys/netinet/in_pcb.h
 ===================================================================
 --- sys/netinet/in_pcb.h	(revision 251760)
 +++ sys/netinet/in_pcb.h	(working copy)
 @@ -442,6 +442,7 @@ struct tcpcb *
  	inp_inpcbtotcpcb(struct inpcb *inp);
  void 	inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
  		uint32_t *faddr, uint16_t *fp);
 +int	inp_so_options(const struct inpcb *inp);
  
  #endif /* _KERNEL */
  
 @@ -543,6 +544,7 @@ void 	inp_4tuple_get(struct inpcb *inp, uint32_t *
  #define	INP_PCBGROUPWILD	0x00000004 /* in pcbgroup wildcard list */
  #define	INP_REUSEPORT		0x00000008 /* SO_REUSEPORT option is set */
  #define	INP_FREED		0x00000010 /* inp itself is not valid */
 +#define	INP_REUSEADDR		0x00000020 /* SO_REUSEADDR option is set */
  
  /*
   * Flags passed to in_pcblookup*() functions.
 Index: sys/netinet/ip_output.c
 ===================================================================
 --- sys/netinet/ip_output.c	(revision 251760)
 +++ sys/netinet/ip_output.c	(working copy)
 @@ -900,13 +900,10 @@ ip_ctloutput(struct socket *so, struct sockopt *so
  			switch (sopt->sopt_name) {
  			case SO_REUSEADDR:
  				INP_WLOCK(inp);
 -				if (IN_MULTICAST(ntohl(inp->inp_laddr.s_addr))) {
 -					if ((so->so_options &
 -					    (SO_REUSEADDR | SO_REUSEPORT)) != 0)
 -						inp->inp_flags2 |= INP_REUSEPORT;
 -					else
 -						inp->inp_flags2 &= ~INP_REUSEPORT;
 -				}
 +				if ((so->so_options & SO_REUSEADDR) != 0)
 +					inp->inp_flags2 |= INP_REUSEADDR;
 +				else
 +					inp->inp_flags2 &= ~INP_REUSEADDR;
  				INP_WUNLOCK(inp);
  				error = 0;
  				break;
 Index: sys/netinet6/in6_pcb.c
 ===================================================================
 --- sys/netinet6/in6_pcb.c	(revision 251760)
 +++ sys/netinet6/in6_pcb.c	(working copy)
 @@ -243,8 +243,7 @@ in6_pcbbind(register struct inpcb *inp, struct soc
  				if (tw == NULL ||
  				    (reuseport & tw->tw_so_options) == 0)
  					return (EADDRINUSE);
 -			} else if (t && (reuseport == 0 ||
 -			    (t->inp_flags2 & INP_REUSEPORT) == 0)) {
 +			} else if (t && (reuseport & inp_so_options(t)) == 0) {
  				return (EADDRINUSE);
  			}
  #ifdef INET
 @@ -265,8 +264,8 @@ in6_pcbbind(register struct inpcb *inp, struct soc
  					     INP_IPV6PROTO) ==
  					     (t->inp_vflag & INP_IPV6PROTO))))
  						return (EADDRINUSE);
 -				} else if (t && (reuseport == 0 ||
 -				    (t->inp_flags2 & INP_REUSEPORT) == 0) &&
 +				} else if (t &&
 +				    (reuseport & inp_so_options(t)) == 0 &&
  				    (ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
  				    (t->inp_vflag & INP_IPV6PROTO) != 0))
  					return (EADDRINUSE);
 Index: sys/netinet6/ip6_output.c
 ===================================================================
 --- sys/netinet6/ip6_output.c	(revision 251760)
 +++ sys/netinet6/ip6_output.c	(working copy)
 @@ -1477,13 +1477,10 @@ ip6_ctloutput(struct socket *so, struct sockopt *s
  			switch (sopt->sopt_name) {
  			case SO_REUSEADDR:
  				INP_WLOCK(in6p);
 -				if (IN_MULTICAST(ntohl(in6p->inp_laddr.s_addr))) {
 -					if ((so->so_options &
 -					    (SO_REUSEADDR | SO_REUSEPORT)) != 0)
 -						in6p->inp_flags2 |= INP_REUSEPORT;
 -					else
 -						in6p->inp_flags2 &= ~INP_REUSEPORT;
 -				}
 +				if ((so->so_options & SO_REUSEADDR) != 0)
 +					in6p->inp_flags2 |= INP_REUSEADDR;
 +				else
 +					in6p->inp_flags2 &= ~INP_REUSEADDR;
  				INP_WUNLOCK(in6p);
  				error = 0;
  				break;
 
 --tThc/1wpZn/ma/RB--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201306251530.r5PFU2fR095198>