diff options
author | Steve French <stfrench@microsoft.com> | 2023-05-22 04:46:30 +0300 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2023-05-25 00:29:21 +0300 |
commit | 38c8a9a52082579090e34c033d439ed2cd1a462d (patch) | |
tree | ca6c3bf5b2b912f32735c1aa0a045cd21a47a205 /fs/cifs/cifs_swn.c | |
parent | cb8b02fd6343228966324528adf920bfb8b8e681 (diff) | |
download | linux-38c8a9a52082579090e34c033d439ed2cd1a462d.tar.xz |
smb: move client and server files to common directory fs/smb
Move CIFS/SMB3 related client and server files (cifs.ko and ksmbd.ko
and helper modules) to new fs/smb subdirectory:
fs/cifs --> fs/smb/client
fs/ksmbd --> fs/smb/server
fs/smbfs_common --> fs/smb/common
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/cifs_swn.c')
-rw-r--r-- | fs/cifs/cifs_swn.c | 674 |
1 files changed, 0 insertions, 674 deletions
diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c deleted file mode 100644 index 7233c6a7e6d7..000000000000 --- a/fs/cifs/cifs_swn.c +++ /dev/null @@ -1,674 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Witness Service client for CIFS - * - * Copyright (c) 2020 Samuel Cabrero <scabrero@suse.de> - */ - -#include <linux/kref.h> -#include <net/genetlink.h> -#include <uapi/linux/cifs/cifs_netlink.h> - -#include "cifs_swn.h" -#include "cifsglob.h" -#include "cifsproto.h" -#include "fscache.h" -#include "cifs_debug.h" -#include "netlink.h" - -static DEFINE_IDR(cifs_swnreg_idr); -static DEFINE_MUTEX(cifs_swnreg_idr_mutex); - -struct cifs_swn_reg { - int id; - struct kref ref_count; - - const char *net_name; - const char *share_name; - bool net_name_notify; - bool share_name_notify; - bool ip_notify; - - struct cifs_tcon *tcon; -}; - -static int cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb) -{ - int ret; - - ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH); - if (ret < 0) - return ret; - - return 0; -} - -static int cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb) -{ - int ret; - - if (tcon->ses->user_name != NULL) { - ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name); - if (ret < 0) - return ret; - } - - if (tcon->ses->password != NULL) { - ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password); - if (ret < 0) - return ret; - } - - if (tcon->ses->domainName != NULL) { - ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName); - if (ret < 0) - return ret; - } - - return 0; -} - -/* - * Sends a register message to the userspace daemon based on the registration. - * The authentication information to connect to the witness service is bundled - * into the message. - */ -static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) -{ - struct sk_buff *skb; - struct genlmsghdr *hdr; - enum securityEnum authtype; - struct sockaddr_storage *addr; - int ret; - - skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (skb == NULL) { - ret = -ENOMEM; - goto fail; - } - - hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER); - if (hdr == NULL) { - ret = -ENOMEM; - goto nlmsg_fail; - } - - ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); - if (ret < 0) - goto nlmsg_fail; - - ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); - if (ret < 0) - goto nlmsg_fail; - - ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); - if (ret < 0) - goto nlmsg_fail; - - /* - * If there is an address stored use it instead of the server address, because we are - * in the process of reconnecting to it after a share has been moved or we have been - * told to switch to it (client move message). In these cases we unregister from the - * server address and register to the new address when we receive the notification. - */ - if (swnreg->tcon->ses->server->use_swn_dstaddr) - addr = &swnreg->tcon->ses->server->swn_dstaddr; - else - addr = &swnreg->tcon->ses->server->dstaddr; - - ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr); - if (ret < 0) - goto nlmsg_fail; - - if (swnreg->net_name_notify) { - ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); - if (ret < 0) - goto nlmsg_fail; - } - - if (swnreg->share_name_notify) { - ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); - if (ret < 0) - goto nlmsg_fail; - } - - if (swnreg->ip_notify) { - ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); - if (ret < 0) - goto nlmsg_fail; - } - - authtype = cifs_select_sectype(swnreg->tcon->ses->server, swnreg->tcon->ses->sectype); - switch (authtype) { - case Kerberos: - ret = cifs_swn_auth_info_krb(swnreg->tcon, skb); - if (ret < 0) { - cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret); - goto nlmsg_fail; - } - break; - case NTLMv2: - case RawNTLMSSP: - ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb); - if (ret < 0) { - cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret); - goto nlmsg_fail; - } - break; - default: - cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype); - ret = -EINVAL; - goto nlmsg_fail; - } - - genlmsg_end(skb, hdr); - genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); - - cifs_dbg(FYI, "%s: Message to register for network name %s with id %d sent\n", __func__, - swnreg->net_name, swnreg->id); - - return 0; - -nlmsg_fail: - genlmsg_cancel(skb, hdr); - nlmsg_free(skb); -fail: - return ret; -} - -/* - * Sends an uregister message to the userspace daemon based on the registration - */ -static int cifs_swn_send_unregister_message(struct cifs_swn_reg *swnreg) -{ - struct sk_buff *skb; - struct genlmsghdr *hdr; - int ret; - - skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (skb == NULL) - return -ENOMEM; - - hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER); - if (hdr == NULL) { - ret = -ENOMEM; - goto nlmsg_fail; - } - - ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); - if (ret < 0) - goto nlmsg_fail; - - ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); - if (ret < 0) - goto nlmsg_fail; - - ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); - if (ret < 0) - goto nlmsg_fail; - - ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), - &swnreg->tcon->ses->server->dstaddr); - if (ret < 0) - goto nlmsg_fail; - - if (swnreg->net_name_notify) { - ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); - if (ret < 0) - goto nlmsg_fail; - } - - if (swnreg->share_name_notify) { - ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); - if (ret < 0) - goto nlmsg_fail; - } - - if (swnreg->ip_notify) { - ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); - if (ret < 0) - goto nlmsg_fail; - } - - genlmsg_end(skb, hdr); - genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); - - cifs_dbg(FYI, "%s: Message to unregister for network name %s with id %d sent\n", __func__, - swnreg->net_name, swnreg->id); - - return 0; - -nlmsg_fail: - genlmsg_cancel(skb, hdr); - nlmsg_free(skb); - return ret; -} - -/* - * Try to find a matching registration for the tcon's server name and share name. - * Calls to this function must be protected by cifs_swnreg_idr_mutex. - * TODO Try to avoid memory allocations - */ -static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) -{ - struct cifs_swn_reg *swnreg; - int id; - const char *share_name; - const char *net_name; - - net_name = extract_hostname(tcon->tree_name); - if (IS_ERR(net_name)) { - int ret; - - ret = PTR_ERR(net_name); - cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n", - __func__, tcon->tree_name, ret); - return ERR_PTR(-EINVAL); - } - - share_name = extract_sharename(tcon->tree_name); - if (IS_ERR(share_name)) { - int ret; - - ret = PTR_ERR(share_name); - cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n", - __func__, tcon->tree_name, ret); - kfree(net_name); - return ERR_PTR(-EINVAL); - } - - idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { - if (strcasecmp(swnreg->net_name, net_name) != 0 - || strcasecmp(swnreg->share_name, share_name) != 0) { - continue; - } - - cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name, - swnreg->share_name); - - kfree(net_name); - kfree(share_name); - - return swnreg; - } - - kfree(net_name); - kfree(share_name); - - return ERR_PTR(-EEXIST); -} - -/* - * Get a registration for the tcon's server and share name, allocating a new one if it does not - * exists - */ -static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon) -{ - struct cifs_swn_reg *reg = NULL; - int ret; - - mutex_lock(&cifs_swnreg_idr_mutex); - - /* Check if we are already registered for this network and share names */ - reg = cifs_find_swn_reg(tcon); - if (!IS_ERR(reg)) { - kref_get(®->ref_count); - mutex_unlock(&cifs_swnreg_idr_mutex); - return reg; - } else if (PTR_ERR(reg) != -EEXIST) { - mutex_unlock(&cifs_swnreg_idr_mutex); - return reg; - } - - reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC); - if (reg == NULL) { - mutex_unlock(&cifs_swnreg_idr_mutex); - return ERR_PTR(-ENOMEM); - } - - kref_init(®->ref_count); - - reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_ATOMIC); - if (reg->id < 0) { - cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__); - ret = reg->id; - goto fail; - } - - reg->net_name = extract_hostname(tcon->tree_name); - if (IS_ERR(reg->net_name)) { - ret = PTR_ERR(reg->net_name); - cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret); - goto fail_idr; - } - - reg->share_name = extract_sharename(tcon->tree_name); - if (IS_ERR(reg->share_name)) { - ret = PTR_ERR(reg->share_name); - cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret); - goto fail_net_name; - } - - reg->net_name_notify = true; - reg->share_name_notify = true; - reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT); - - reg->tcon = tcon; - - mutex_unlock(&cifs_swnreg_idr_mutex); - - return reg; - -fail_net_name: - kfree(reg->net_name); -fail_idr: - idr_remove(&cifs_swnreg_idr, reg->id); -fail: - kfree(reg); - mutex_unlock(&cifs_swnreg_idr_mutex); - return ERR_PTR(ret); -} - -static void cifs_swn_reg_release(struct kref *ref) -{ - struct cifs_swn_reg *swnreg = container_of(ref, struct cifs_swn_reg, ref_count); - int ret; - - ret = cifs_swn_send_unregister_message(swnreg); - if (ret < 0) - cifs_dbg(VFS, "%s: Failed to send unregister message: %d\n", __func__, ret); - - idr_remove(&cifs_swnreg_idr, swnreg->id); - kfree(swnreg->net_name); - kfree(swnreg->share_name); - kfree(swnreg); -} - -static void cifs_put_swn_reg(struct cifs_swn_reg *swnreg) -{ - mutex_lock(&cifs_swnreg_idr_mutex); - kref_put(&swnreg->ref_count, cifs_swn_reg_release); - mutex_unlock(&cifs_swnreg_idr_mutex); -} - -static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const char *name, int state) -{ - switch (state) { - case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE: - cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name); - cifs_signal_cifsd_for_reconnect(swnreg->tcon->ses->server, true); - break; - case CIFS_SWN_RESOURCE_STATE_AVAILABLE: - cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name); - cifs_signal_cifsd_for_reconnect(swnreg->tcon->ses->server, true); - break; - case CIFS_SWN_RESOURCE_STATE_UNKNOWN: - cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name); - break; - } - return 0; -} - -static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2) -{ - if (addr1->ss_family != addr2->ss_family) - return false; - - if (addr1->ss_family == AF_INET) { - return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr, - &((const struct sockaddr_in *)addr2)->sin_addr, - sizeof(struct in_addr)) == 0); - } - - if (addr1->ss_family == AF_INET6) { - return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr, - &((const struct sockaddr_in6 *)addr2)->sin6_addr, - sizeof(struct in6_addr)) == 0); - } - - return false; -} - -static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new, - const struct sockaddr_storage *old, - struct sockaddr_storage *dst) -{ - __be16 port = cpu_to_be16(CIFS_PORT); - - if (old->ss_family == AF_INET) { - struct sockaddr_in *ipv4 = (struct sockaddr_in *)old; - - port = ipv4->sin_port; - } else if (old->ss_family == AF_INET6) { - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old; - - port = ipv6->sin6_port; - } - - if (new->ss_family == AF_INET) { - struct sockaddr_in *ipv4 = (struct sockaddr_in *)new; - - ipv4->sin_port = port; - } else if (new->ss_family == AF_INET6) { - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new; - - ipv6->sin6_port = port; - } - - *dst = *new; - - return 0; -} - -static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr) -{ - int ret = 0; - - /* Store the reconnect address */ - cifs_server_lock(tcon->ses->server); - if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) - goto unlock; - - ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr, - &tcon->ses->server->swn_dstaddr); - if (ret < 0) { - cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret); - goto unlock; - } - tcon->ses->server->use_swn_dstaddr = true; - - /* - * Unregister to stop receiving notifications for the old IP address. - */ - ret = cifs_swn_unregister(tcon); - if (ret < 0) { - cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", - __func__, ret); - goto unlock; - } - - /* - * And register to receive notifications for the new IP address now that we have - * stored the new address. - */ - ret = cifs_swn_register(tcon); - if (ret < 0) { - cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n", - __func__, ret); - goto unlock; - } - - cifs_signal_cifsd_for_reconnect(tcon->ses->server, false); - -unlock: - cifs_server_unlock(tcon->ses->server); - - return ret; -} - -static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr) -{ - struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr; - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr; - - if (addr->ss_family == AF_INET) - cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr); - else if (addr->ss_family == AF_INET6) - cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr); - - return cifs_swn_reconnect(swnreg->tcon, addr); -} - -int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) -{ - struct cifs_swn_reg *swnreg; - char name[256]; - int type; - - if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) { - int swnreg_id; - - swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]); - mutex_lock(&cifs_swnreg_idr_mutex); - swnreg = idr_find(&cifs_swnreg_idr, swnreg_id); - mutex_unlock(&cifs_swnreg_idr_mutex); - if (swnreg == NULL) { - cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id); - return -EINVAL; - } - } else { - cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__); - return -EINVAL; - } - - if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) { - type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]); - } else { - cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__); - return -EINVAL; - } - - switch (type) { - case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: { - int state; - - if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) { - nla_strscpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME], - sizeof(name)); - } else { - cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__); - return -EINVAL; - } - if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) { - state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]); - } else { - cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__); - return -EINVAL; - } - return cifs_swn_resource_state_changed(swnreg, name, state); - } - case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: { - struct sockaddr_storage addr; - - if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) { - nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr)); - } else { - cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__); - return -EINVAL; - } - return cifs_swn_client_move(swnreg, &addr); - } - default: - cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type); - break; - } - - return 0; -} - -int cifs_swn_register(struct cifs_tcon *tcon) -{ - struct cifs_swn_reg *swnreg; - int ret; - - swnreg = cifs_get_swn_reg(tcon); - if (IS_ERR(swnreg)) - return PTR_ERR(swnreg); - - ret = cifs_swn_send_register_message(swnreg); - if (ret < 0) { - cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret); - /* Do not put the swnreg or return error, the echo task will retry */ - } - - return 0; -} - -int cifs_swn_unregister(struct cifs_tcon *tcon) -{ - struct cifs_swn_reg *swnreg; - - mutex_lock(&cifs_swnreg_idr_mutex); - - swnreg = cifs_find_swn_reg(tcon); - if (IS_ERR(swnreg)) { - mutex_unlock(&cifs_swnreg_idr_mutex); - return PTR_ERR(swnreg); - } - - mutex_unlock(&cifs_swnreg_idr_mutex); - - cifs_put_swn_reg(swnreg); - - return 0; -} - -void cifs_swn_dump(struct seq_file *m) -{ - struct cifs_swn_reg *swnreg; - struct sockaddr_in *sa; - struct sockaddr_in6 *sa6; - int id; - - seq_puts(m, "Witness registrations:"); - - mutex_lock(&cifs_swnreg_idr_mutex); - idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { - seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ", - id, kref_read(&swnreg->ref_count), - swnreg->net_name, swnreg->net_name_notify ? "(y)" : "(n)", - swnreg->share_name, swnreg->share_name_notify ? "(y)" : "(n)"); - switch (swnreg->tcon->ses->server->dstaddr.ss_family) { - case AF_INET: - sa = (struct sockaddr_in *) &swnreg->tcon->ses->server->dstaddr; - seq_printf(m, "%pI4", &sa->sin_addr.s_addr); - break; - case AF_INET6: - sa6 = (struct sockaddr_in6 *) &swnreg->tcon->ses->server->dstaddr; - seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr); - if (sa6->sin6_scope_id) - seq_printf(m, "%%%u", sa6->sin6_scope_id); - break; - default: - seq_puts(m, "(unknown)"); - } - seq_printf(m, "%s", swnreg->ip_notify ? "(y)" : "(n)"); - } - mutex_unlock(&cifs_swnreg_idr_mutex); - seq_puts(m, "\n"); -} - -void cifs_swn_check(void) -{ - struct cifs_swn_reg *swnreg; - int id; - int ret; - - mutex_lock(&cifs_swnreg_idr_mutex); - idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { - ret = cifs_swn_send_register_message(swnreg); - if (ret < 0) - cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret); - } - mutex_unlock(&cifs_swnreg_idr_mutex); -} |