extern void cifs_wake_up_task(struct mid_q_entry *mid);
 extern int cifs_handle_standard(struct TCP_Server_Info *server,
                                struct mid_q_entry *mid);
+extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
 extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 extern int cifs_call_async(struct TCP_Server_Info *server,
                        struct smb_rqst *rqst,
        return dfs_cache_find(xid, ses, nls_codepage, remap, old_path,
                              referral, NULL);
 }
+
+int match_target_ip(struct TCP_Server_Info *server,
+                   const char *share, size_t share_len,
+                   bool *result);
 #endif
 
 static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
 
                                 struct cifs_tcon *tcon)
 {
        int rc;
+       struct TCP_Server_Info *server = tcon->ses->server;
        struct dfs_cache_tgt_list tl;
        struct dfs_cache_tgt_iterator *it = NULL;
        char *tree;
        if (!tree)
                return -ENOMEM;
 
-       if (tcon->ipc) {
-               scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
-                         tcon->ses->server->hostname);
-               rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
-               goto out;
-       }
-
        if (!tcon->dfs_path) {
-               rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
+               if (tcon->ipc) {
+                       scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
+                                 server->hostname);
+                       rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
+               } else {
+                       rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
+               }
                goto out;
        }
 
        if (rc)
                goto out;
 
-       extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
-                            &tcp_host_len);
+       extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
 
        for (it = dfs_cache_get_tgt_iterator(&tl); it;
             it = dfs_cache_get_next_tgt(&tl, it)) {
                const char *share, *prefix;
                size_t share_len, prefix_len;
+               bool target_match;
 
                rc = dfs_cache_get_tgt_share(it, &share, &share_len, &prefix,
                                             &prefix_len);
 
                if (dfs_host_len != tcp_host_len
                    || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
-                       cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
+                       cifs_dbg(FYI, "%s: %.*s doesn't match %.*s",
                                 __func__,
                                 (int)dfs_host_len, dfs_host,
                                 (int)tcp_host_len, tcp_host);
-                       continue;
-               }
 
-               scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len, share);
+                       rc = match_target_ip(server, dfs_host, dfs_host_len,
+                                            &target_match);
+                       if (rc) {
+                               cifs_dbg(VFS, "%s: failed to match target ip: %d\n",
+                                        __func__, rc);
+                               break;
+                       }
+
+                       if (!target_match) {
+                               cifs_dbg(FYI, "%s: skipping target\n", __func__);
+                               continue;
+                       }
+               }
 
-               rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
-               if (!rc) {
-                       rc = update_super_prepath(tcon, prefix, prefix_len);
-                       break;
+               if (tcon->ipc) {
+                       scnprintf(tree, MAX_TREE_SIZE, "\\\\%.*s\\IPC$",
+                                 (int)share_len, share);
+                       rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
+               } else {
+                       scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len,
+                                 share);
+                       rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
+                       if (!rc) {
+                               rc = update_super_prepath(tcon, prefix,
+                                                         prefix_len);
+                               break;
+                       }
                }
                if (rc == -EREMOTE)
                        break;
 
  * specified, or if srcaddr is specified and
  * matches the IP address of the rhs argument.
  */
-static bool
-srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
+bool
+cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs)
 {
        switch (srcaddr->sa_family) {
        case AF_UNSPEC:
                return false; /* don't expect to be here */
        }
 
-       if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr))
+       if (!cifs_match_ipaddr(srcaddr, (struct sockaddr *)&server->srcaddr))
                return false;
 
        return true;
 
 #include "cifs_unicode.h"
 #include "smb2pdu.h"
 #include "cifsfs.h"
+#ifdef CONFIG_CIFS_DFS_UPCALL
+#include "dns_resolve.h"
+#endif
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
 }
 
 #ifdef CONFIG_CIFS_DFS_UPCALL
+int match_target_ip(struct TCP_Server_Info *server,
+                   const char *share, size_t share_len,
+                   bool *result)
+{
+       int rc;
+       char *target, *tip = NULL;
+       struct sockaddr tipaddr;
+
+       *result = false;
+
+       target = kzalloc(share_len + 3, GFP_KERNEL);
+       if (!target) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       scnprintf(target, share_len + 3, "\\\\%.*s", (int)share_len, share);
+
+       cifs_dbg(FYI, "%s: target name: %s\n", __func__, target + 2);
+
+       rc = dns_resolve_server_name_to_ip(target, &tip);
+       if (rc < 0)
+               goto out;
+
+       cifs_dbg(FYI, "%s: target ip: %s\n", __func__, tip);
+
+       if (!cifs_convert_address(&tipaddr, tip, strlen(tip))) {
+               cifs_dbg(VFS, "%s: failed to convert target ip address\n",
+                        __func__);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       *result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr,
+                                   &tipaddr);
+       cifs_dbg(FYI, "%s: ip addresses match: %u\n", __func__, *result);
+       rc = 0;
+
+out:
+       kfree(target);
+       kfree(tip);
+
+       return rc;
+}
+
 static void tcon_super_cb(struct super_block *sb, void *arg)
 {
        struct super_cb_data *sd = arg;
 
                            struct cifs_tcon *tcon)
 {
        int rc;
+       struct TCP_Server_Info *server = tcon->ses->server;
        struct dfs_cache_tgt_list tl;
        struct dfs_cache_tgt_iterator *it = NULL;
        char *tree;
        if (!tree)
                return -ENOMEM;
 
-       if (tcon->ipc) {
-               scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
-                         tcon->ses->server->hostname);
-               rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
-               goto out;
-       }
-
        if (!tcon->dfs_path) {
-               rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc);
+               if (tcon->ipc) {
+                       scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
+                                 server->hostname);
+                       rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
+               } else {
+                       rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon,
+                                      nlsc);
+               }
                goto out;
        }
 
        if (rc)
                goto out;
 
-       extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
-                            &tcp_host_len);
+       extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
 
        for (it = dfs_cache_get_tgt_iterator(&tl); it;
             it = dfs_cache_get_next_tgt(&tl, it)) {
                const char *share, *prefix;
                size_t share_len, prefix_len;
+               bool target_match;
 
                rc = dfs_cache_get_tgt_share(it, &share, &share_len, &prefix,
                                             &prefix_len);
 
                if (dfs_host_len != tcp_host_len
                    || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
-                       cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
+                       cifs_dbg(FYI, "%s: %.*s doesn't match %.*s",
                                 __func__,
                                 (int)dfs_host_len, dfs_host,
                                 (int)tcp_host_len, tcp_host);
-                       continue;
-               }
 
-               scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len, share);
+                       rc = match_target_ip(server, dfs_host, dfs_host_len,
+                                            &target_match);
+                       if (rc) {
+                               cifs_dbg(VFS, "%s: failed to match target ip: %d\n",
+                                        __func__, rc);
+                               break;
+                       }
 
-               rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
-               if (!rc) {
-                       rc = update_super_prepath(tcon, prefix, prefix_len);
-                       break;
+                       if (!target_match) {
+                               cifs_dbg(FYI, "%s: skipping target\n", __func__);
+                               continue;
+                       }
+               }
+
+               if (tcon->ipc) {
+                       scnprintf(tree, MAX_TREE_SIZE, "\\\\%.*s\\IPC$",
+                                 (int)share_len, share);
+                       rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
+               } else {
+                       scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len,
+                                 share);
+                       rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
+                       if (!rc) {
+                               rc = update_super_prepath(tcon, prefix,
+                                                         prefix_len);
+                               break;
+                       }
                }
                if (rc == -EREMOTE)
                        break;