sctp: try harder to figure out address family when checking wildcards

sctp_is_any() function that is used to check for wildcard addresses
only looks at the address itself to determine the address family.
This function is used in the API to check the address passed in from
the user.  If the user simply zerroes out the sockaddr_storage and
pass that in, we'll end up failing.  So, let's try harder to determine
the address family by also checking the socket if it's possible.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index f62bc24..6d5944a 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -457,7 +457,7 @@
 {
 	int error = 0;
 
-	if (sctp_is_any(addr)) {
+	if (sctp_is_any(NULL, addr)) {
 		error = sctp_copy_local_addr_list(dest, scope, gfp, flags);
 	} else if (sctp_in_scope(addr, scope)) {
 		/* Now that the address is in scope, check to see if
@@ -477,11 +477,21 @@
 }
 
 /* Is this a wildcard address?  */
-int sctp_is_any(const union sctp_addr *addr)
+int sctp_is_any(struct sock *sk, const union sctp_addr *addr)
 {
-	struct sctp_af *af = sctp_get_af_specific(addr->sa.sa_family);
+	unsigned short fam = 0;
+	struct sctp_af *af;
+
+	/* Try to get the right address family */
+	if (addr->sa.sa_family != AF_UNSPEC)
+		fam = addr->sa.sa_family;
+	else if (sk)
+		fam = sk->sk_family;
+
+	af = sctp_get_af_specific(fam);
 	if (!af)
 		return 0;
+
 	return af->is_any(addr);
 }
 
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 47f91af..c78da3c 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -837,6 +837,7 @@
 			       struct sctp_sock *opt)
 {
 	struct sctp_af *af1, *af2;
+	struct sock *sk = sctp_opt2sk(opt);
 
 	af1 = sctp_get_af_specific(addr1->sa.sa_family);
 	af2 = sctp_get_af_specific(addr2->sa.sa_family);
@@ -845,11 +846,11 @@
 		return 0;
 
 	/* If the socket is IPv6 only, v4 addrs will not match */
-	if (__ipv6_only_sock(sctp_opt2sk(opt)) && af1 != af2)
+	if (__ipv6_only_sock(sk) && af1 != af2)
 		return 0;
 
 	/* Today, wildcard AF_INET/AF_INET6. */
-	if (sctp_is_any(addr1) || sctp_is_any(addr2))
+	if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
 		return 1;
 
 	if (addr1->sa.sa_family != addr2->sa.sa_family)
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 5ffb9de..a1b9045 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2309,7 +2309,7 @@
 	/* If an address other than INADDR_ANY is specified, and
 	 * no transport is found, then the request is invalid.
 	 */
-	if (!sctp_is_any(( union sctp_addr *)&params.spp_address)) {
+	if (!sctp_is_any(sk, ( union sctp_addr *)&params.spp_address)) {
 		trans = sctp_addr_id2transport(sk, &params.spp_address,
 					       params.spp_assoc_id);
 		if (!trans)
@@ -4062,7 +4062,7 @@
 	/* If an address other than INADDR_ANY is specified, and
 	 * no transport is found, then the request is invalid.
 	 */
-	if (!sctp_is_any(( union sctp_addr *)&params.spp_address)) {
+	if (!sctp_is_any(sk, ( union sctp_addr *)&params.spp_address)) {
 		trans = sctp_addr_id2transport(sk, &params.spp_address,
 					       params.spp_assoc_id);
 		if (!trans) {
@@ -4414,7 +4414,7 @@
 	if (sctp_list_single_entry(&bp->address_list)) {
 		addr = list_entry(bp->address_list.next,
 				  struct sctp_sockaddr_entry, list);
-		if (sctp_is_any(&addr->a)) {
+		if (sctp_is_any(sk, &addr->a)) {
 			rcu_read_lock();
 			list_for_each_entry_rcu(addr,
 						&sctp_local_addr_list, list) {
@@ -4602,7 +4602,7 @@
 	if (sctp_list_single_entry(&bp->address_list)) {
 		addr = list_entry(bp->address_list.next,
 				  struct sctp_sockaddr_entry, list);
-		if (sctp_is_any(&addr->a)) {
+		if (sctp_is_any(sk, &addr->a)) {
 			cnt = sctp_copy_laddrs_old(sk, bp->port,
 						   getaddrs.addr_num,
 						   addrs, &bytes_copied);
@@ -4695,7 +4695,7 @@
 	if (sctp_list_single_entry(&bp->address_list)) {
 		addr = list_entry(bp->address_list.next,
 				  struct sctp_sockaddr_entry, list);
-		if (sctp_is_any(&addr->a)) {
+		if (sctp_is_any(sk, &addr->a)) {
 			cnt = sctp_copy_laddrs(sk, bp->port, addrs,
 						space_left, &bytes_copied);
 			if (cnt < 0) {