On 02/06/14(Mon) 15:45, Martin Pieuchot wrote:
> This diff is similar to the one that has been committed to handle the
> SOCK_RAW binding.  I'd like to stop using in_iawithaddr() *and*
> in_broadcast().  Since these functions are just doing an iteration on
> all the addresses present in the RB-tree (or equivalent), let's use
> ifa_ifwithaddr() instead.
> 
> This diff should not introduce any behavior change concerning SOCK_DGRAM
> and binding to multicast addresses.

As pointed out by jca@ this diff breaks on loopback.  This is because
the loopback IPv4 addresses are abusing the dstaddr field to be able to
create a route to their address.  Hopefully this hack can be removed
once the local route diff is in, but in the meantime let's use the less
intuitive but equivalent idiom:

        sin->sin_addr.s_addr != ia->ia_addr.s_addr

Update diff below, is this one ok?

Index: netinet/in_pcb.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.155
diff -u -p -r1.155 in_pcb.c
--- netinet/in_pcb.c    7 May 2014 08:26:38 -0000       1.155
+++ netinet/in_pcb.c    3 Jun 2014 07:12:53 -0000
@@ -261,14 +261,22 @@ in_pcbbind(struct inpcb *inp, struct mbu
                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
                        sin->sin_port = 0;              /* yech... */
-                       if (!(so->so_options & SO_BINDANY) &&
-                           in_iawithaddr(sin->sin_addr,
-                           inp->inp_rtableid) == NULL)
+                       if (!((so->so_options & SO_BINDANY) ||
+                           (sin->sin_addr.s_addr == INADDR_BROADCAST &&
+                            so->so_type == SOCK_DGRAM))) {
+                               struct in_ifaddr *ia;
+
+                               ia = ifatoia(ifa_ifwithaddr(sintosa(sin),
+                                   inp->inp_rtableid));
+                               if (ia == NULL)
+                                        return (EADDRNOTAVAIL);
+
                                /* SOCK_RAW does not use in_pcbbind() */
-                               if (!(so->so_type == SOCK_DGRAM &&
-                                   in_broadcast(sin->sin_addr, NULL,
-                                   inp->inp_rtableid)))
-                                       return (EADDRNOTAVAIL);
+                               if (so->so_type != SOCK_DGRAM &&
+                                   sin->sin_addr.s_addr !=
+                                   ia->ia_addr.sin_addr.s_addr)
+                                        return (EADDRNOTAVAIL);
+                       }
                }
                if (lport) {
                        struct inpcb *t;

Reply via email to