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.
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 2 Jun 2014 13:37:59 -0000
@@ -261,14 +261,19 @@ 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));
/* 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 (ia == NULL || (sin->sin_addr.s_addr ==
+ ia->ia_broadaddr.sin_addr.s_addr &&
+ so->so_type != SOCK_DGRAM))
+ return (EADDRNOTAVAIL);
+ }
}
if (lport) {
struct inpcb *t;