int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
 int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
                         struct sctp_sock *);
+int sctp_bind_addr_conflict(struct sctp_bind_addr *, const union sctp_addr *,
+                        struct sctp_sock *, struct sctp_sock *);
 int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
                         const union sctp_addr *addr);
 union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr  *bp,
 
        return match;
 }
 
+/* Does the address 'addr' conflict with any addresses in
+ * the bp.
+ */
+int sctp_bind_addr_conflict(struct sctp_bind_addr *bp,
+                           const union sctp_addr *addr,
+                           struct sctp_sock *bp_sp,
+                           struct sctp_sock *addr_sp)
+{
+       struct sctp_sockaddr_entry *laddr;
+       int conflict = 0;
+       struct sctp_sock *sp;
+
+       /* Pick the IPv6 socket as the basis of comparison
+        * since it's usually a superset of the IPv4.
+        * If there is no IPv6 socket, then default to bind_addr.
+        */
+       if (sctp_opt2sk(bp_sp)->sk_family == AF_INET6)
+               sp = bp_sp;
+       else if (sctp_opt2sk(addr_sp)->sk_family == AF_INET6)
+               sp = addr_sp;
+       else
+               sp = bp_sp;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+               if (!laddr->valid)
+                       continue;
+
+               conflict = sp->pf->cmp_addr(&laddr->a, addr, sp);
+               if (conflict)
+                       break;
+       }
+       rcu_read_unlock();
+
+       return conflict;
+}
+
 /* Get the state of the entry in the bind_addr_list */
 int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
                         const union sctp_addr *addr)
 
                return 1;
        /* v4-mapped-v6 addresses */
        case AF_INET:
-               if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped)
+               if (!__ipv6_only_sock(sctp_opt2sk(sp)))
                        return 1;
        default:
                return 0;
 
        if (!af1 || !af2)
                return 0;
+
+       /* If the socket is IPv6 only, v4 addrs will not match */
+       if (__ipv6_only_sock(sctp_opt2sk(opt)) && af1 != af2)
+               return 0;
+
        /* Today, wildcard AF_INET/AF_INET6. */
        if (sctp_is_any(addr1) || sctp_is_any(addr2))
                return 1;
                                return 0;
                        }
                        dev_put(dev);
+               } else if (type == IPV6_ADDR_MAPPED) {
+                       if (!opt->v4mapped)
+                               return 0;
                }
+
                af = opt->pf->af;
        }
        return af->available(addr, opt);
 static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
                                      __be16 *types)
 {
-       types[0] = SCTP_PARAM_IPV4_ADDRESS;
-       types[1] = SCTP_PARAM_IPV6_ADDRESS;
-       return 2;
+       types[0] = SCTP_PARAM_IPV6_ADDRESS;
+       if (!opt || !ipv6_only_sock(sctp_opt2sk(opt))) {
+               types[1] = SCTP_PARAM_IPV4_ADDRESS;
+               return 2;
+       }
+       return 1;
 }
 
 static const struct proto_ops inet6_seqpacket_ops = {
 
                              struct sctp_sock *sp,
                              const struct sk_buff *skb)
 {
+       /* IPv4 addresses not allowed */
+       if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
+               return 0;
+
        /* Is this a non-unicast address or a unusable SCTP address? */
        if (IS_IPV4_UNUSABLE_ADDRESS(addr->v4.sin_addr.s_addr))
                return 0;
           !sysctl_ip_nonlocal_bind)
                return 0;
 
+       if (ipv6_only_sock(sctp_opt2sk(sp)))
+               return 0;
+
        return 1;
 }
 
 
        case SCTP_PARAM_IPV6_ADDRESS:
                if (PF_INET6 != asoc->base.sk->sk_family)
                        break;
-               /* Fall through. */
+               goto do_addr_param;
+
        case SCTP_PARAM_IPV4_ADDRESS:
+               /* v4 addresses are not allowed on v6-only socket */
+               if (ipv6_only_sock(asoc->base.sk))
+                       break;
+do_addr_param:
                af = sctp_get_af_specific(param_type2af(param.p->type));
                af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);
                scope = sctp_scope(peer_addr);
 
        if (len < sizeof (struct sockaddr))
                return NULL;
 
-       /* Does this PF support this AF? */
-       if (!opt->pf->af_supported(addr->sa.sa_family, opt))
-               return NULL;
+       /* V4 mapped address are really of AF_INET family */
+       if (addr->sa.sa_family == AF_INET6 &&
+           ipv6_addr_v4mapped(&addr->v6.sin6_addr)) {
+               if (!opt->pf->af_supported(AF_INET, opt))
+                       return NULL;
+       } else {
+               /* Does this PF support this AF? */
+               if (!opt->pf->af_supported(addr->sa.sa_family, opt))
+                       return NULL;
+       }
 
        /* If we get this far, af is valid. */
        af = sctp_get_af_specific(addr->sa.sa_family);
                                    (AF_INET6 == addr->a.sa.sa_family))
                                        continue;
 
+                               if ((PF_INET6 == sk->sk_family) &&
+                                   inet_v6_ipv6only(sk) &&
+                                   (AF_INET == addr->a.sa.sa_family))
+                                       continue;
+
                                cnt++;
                        }
                        rcu_read_unlock();
                if ((PF_INET == sk->sk_family) &&
                    (AF_INET6 == addr->a.sa.sa_family))
                        continue;
+               if ((PF_INET6 == sk->sk_family) &&
+                   inet_v6_ipv6only(sk) &&
+                   (AF_INET == addr->a.sa.sa_family))
+                       continue;
                memcpy(&temp, &addr->a, sizeof(temp));
                if (!temp.v4.sin_port)
                        temp.v4.sin_port = htons(port);
                if ((PF_INET == sk->sk_family) &&
                    (AF_INET6 == addr->a.sa.sa_family))
                        continue;
+               if ((PF_INET6 == sk->sk_family) &&
+                   inet_v6_ipv6only(sk) &&
+                   (AF_INET == addr->a.sa.sa_family))
+                       continue;
                memcpy(&temp, &addr->a, sizeof(temp));
                if (!temp.v4.sin_port)
                        temp.v4.sin_port = htons(port);
                            sk2->sk_state != SCTP_SS_LISTENING)
                                continue;
 
-                       if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
-                                                sctp_sk(sk))) {
+                       if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr,
+                                                sctp_sk(sk2), sctp_sk(sk))) {
                                ret = (long)sk2;
                                goto fail_unlock;
                        }