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 2013 Nexenta Systems, Inc.  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>

@@ -2712,10 +2713,12 @@
                 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;
+
                 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) {

@@ -2722,18 +2725,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)) {
+                                /* Mismatch - 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;
                 dstport = connp->conn_fport;
                 flowinfo = connp->conn_flowinfo;

@@ -3720,18 +3729,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) {

@@ -3738,19 +3746,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) {

@@ -5524,10 +5538,11 @@
         ip_xmit_attr_t  *ixa;
         ip_xmit_attr_t  *oldixa;
         uint_t          scopeid = 0;
         uint_t          srcid = 0;
         in6_addr_t      v6src = connp->conn_saddr_v6;
+        boolean_t       v4mapped;
 
         udp = connp->conn_udp;
         us = udp->udp_us;
 
         /*

@@ -5552,15 +5567,19 @@
         case sizeof (sin6_t):
                 sin6 = (sin6_t *)sa;
                 v6dst = sin6->sin6_addr;
                 dstport = sin6->sin6_port;
                 srcid = sin6->__sin6_src_id;
+                v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst);
                 if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
-                        ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
-                            connp->conn_netstack);
+                        if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp),
+                            v4mapped, connp->conn_netstack)) {
+                                /* Mismatch v4mapped/v6 specified by srcid. */
+                                return (EADDRNOTAVAIL);
                 }
-                if (IN6_IS_ADDR_V4MAPPED(&v6dst)) {
+                }
+                if (v4mapped) {
                         if (connp->conn_ipv6_v6only)
                                 return (EADDRNOTAVAIL);
 
                         /*
                          * Destination adress is mapped IPv6 address.