Print this page
4596 Callers of ip_srcid_find_id() need to be more careful

@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
  */
 /* Copyright (c) 1990 Mentat Inc. */
 
 #include <sys/types.h>
 #include <sys/stream.h>

@@ -766,13 +767,17 @@
                 flowinfo = sin6->sin6_flowinfo;
                 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
                         scopeid = sin6->sin6_scope_id;
                 srcid = sin6->__sin6_src_id;
                 if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
-                        ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
-                            connp->conn_netstack);
+                        /* Due to check above, we know sin6_addr is v6-only. */
+                        if (!ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
+                            B_FALSE, connp->conn_netstack)) {
+                                /* Mismatch - v6src would be v4mapped. */
+                                return (EADDRNOTAVAIL);
                 }
+                }
                 break;
         }
 
         /*
          * If there is a different thread using conn_ixa then we get a new

@@ -3335,11 +3340,10 @@
         in6_addr_t      v6src;
         in6_addr_t      v6dst;
         in6_addr_t      v6nexthop;
         in_port_t       dstport;
         uint32_t        flowinfo;
-        uint_t          srcid;
         int             is_absreq_failure = 0;
         conn_opt_arg_t  coas, *coa;
 
         ASSERT(tudr_mp != NULL || msg != NULL);
 

@@ -3438,10 +3442,13 @@
                 dstport = sin->sin_port;
                 flowinfo = 0;
                 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
                 ixa->ixa_flags |= IXAF_IS_IPV4;
         } else if (sin6 != NULL) {
+                boolean_t v4mapped;
+                uint_t srcid;
+
                 v6dst = sin6->sin6_addr;
                 dstport = sin6->sin6_port;
                 flowinfo = sin6->sin6_flowinfo;
                 srcid = sin6->__sin6_src_id;
                 if (IN6_IS_ADDR_LINKSCOPE(&v6dst) && sin6->sin6_scope_id != 0) {

@@ -3448,18 +3455,24 @@
                         ixa->ixa_scopeid = sin6->sin6_scope_id;
                         ixa->ixa_flags |= IXAF_SCOPEID_SET;
                 } else {
                         ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
                 }
-                if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
-                        ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
-                            connp->conn_netstack);
-                }
-                if (IN6_IS_ADDR_V4MAPPED(&v6dst))
+                v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst);
+                if (v4mapped)
                         ixa->ixa_flags |= IXAF_IS_IPV4;
                 else
                         ixa->ixa_flags &= ~IXAF_IS_IPV4;
+                if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
+                        if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
+                            v4mapped, connp->conn_netstack)) {
+                                /* Mismatched v4mapped/v6 specified by srcid. */
+                                mutex_exit(&connp->conn_lock);
+                                error = EADDRNOTAVAIL;
+                                goto failed;    /* Does freemsg() and mib. */
+                        }
+                }
         } else {
                 /* Connected case */
                 v6dst = connp->conn_faddr_v6;
                 flowinfo = connp->conn_flowinfo;
         }

@@ -4417,18 +4430,17 @@
         v6src = connp->conn_saddr_v6;
         if (sin != NULL) {
                 IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &v6dst);
                 dstport = sin->sin_port;
                 flowinfo = 0;
+                /* Don't bother with ip_srcid_find_id(), but indicate anyway. */
                 srcid = 0;
                 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
-                if (srcid != 0 && V4_PART_OF_V6(&v6src) == INADDR_ANY) {
-                        ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
-                            connp->conn_netstack);
-                }
                 ixa->ixa_flags |= IXAF_IS_IPV4;
         } else {
+                boolean_t v4mapped;
+
                 v6dst = sin6->sin6_addr;
                 dstport = sin6->sin6_port;
                 flowinfo = sin6->sin6_flowinfo;
                 srcid = sin6->__sin6_src_id;
                 if (IN6_IS_ADDR_LINKSCOPE(&v6dst) && sin6->sin6_scope_id != 0) {

@@ -4435,19 +4447,25 @@
                         ixa->ixa_scopeid = sin6->sin6_scope_id;
                         ixa->ixa_flags |= IXAF_SCOPEID_SET;
                 } else {
                         ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
                 }
-                if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
-                        ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
-                            connp->conn_netstack);
-                }
-                if (IN6_IS_ADDR_V4MAPPED(&v6dst))
+                v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst);
+                if (v4mapped)
                         ixa->ixa_flags |= IXAF_IS_IPV4;
                 else
                         ixa->ixa_flags &= ~IXAF_IS_IPV4;
+                if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
+                        if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
+                            v4mapped, connp->conn_netstack)) {
+                                /* Mismatched v4mapped/v6 specified by srcid. */
+                                mutex_exit(&connp->conn_lock);
+                                error = EADDRNOTAVAIL;
+                                goto ud_error;
         }
+                }
+        }
         /* Handle IP_PKTINFO/IPV6_PKTINFO setting source address. */
         if (connp->conn_xmit_ipp.ipp_fields & IPPF_ADDR) {
                 ip_pkt_t *ipp = &connp->conn_xmit_ipp;
 
                 if (ixa->ixa_flags & IXAF_IS_IPV4) {