// SPDX-License-Identifier: LGPL-2.1 /* * * Functions which do error mapping of SMB2 status codes to POSIX errors * * Copyright (C) International Business Machines Corp., 2009 * Author(s): Steve French (sfrench@us.ibm.com) * */ #include #include "cifsproto.h" #include "cifs_debug.h" #include "smb2proto.h" #include "smb2glob.h" #include "../common/smb2status.h" #include "trace.h" static const struct status_to_posix_error smb2_error_map_table[] = { /* * Automatically generated by the `gen_smb2_mapping` script, * sorted by NT status code (cpu-endian, ascending) */ #include "smb2_mapping_table.c" }; static __always_inline int cmp_smb2_status(const void *_key, const void *_pivot) { __u32 key = *(__u32 *)_key; const struct status_to_posix_error *pivot = _pivot; if (key < pivot->smb2_status) return -1; if (key > pivot->smb2_status) return 1; return 0; } static const struct status_to_posix_error *smb2_get_err_map(__u32 smb2_status) { const struct status_to_posix_error *err_map; err_map = __inline_bsearch(&smb2_status, smb2_error_map_table, ARRAY_SIZE(smb2_error_map_table), sizeof(struct status_to_posix_error), cmp_smb2_status); return err_map; } int map_smb2_to_linux_error(char *buf, bool log_err) { struct smb2_hdr *shdr = (struct smb2_hdr *)buf; int rc = -EIO; __le32 smb2err = shdr->Status; const struct status_to_posix_error *err_map; if (smb2err == 0) { trace_smb3_cmd_done(le32_to_cpu(shdr->Id.SyncId.TreeId), le64_to_cpu(shdr->SessionId), le16_to_cpu(shdr->Command), le64_to_cpu(shdr->MessageId)); return 0; } log_err = (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) && (smb2err != STATUS_END_OF_FILE)) || (cifsFYI & CIFS_RC); err_map = smb2_get_err_map(le32_to_cpu(smb2err)); if (!err_map) goto out; rc = err_map->posix_error; if (log_err) pr_notice("Status code returned 0x%08x %s\n", err_map->smb2_status, err_map->status_string); out: /* on error mapping not found - return EIO */ cifs_dbg(FYI, "Mapping SMB2 status code 0x%08x to POSIX err %d\n", le32_to_cpu(smb2err), rc); trace_smb3_cmd_err(le32_to_cpu(shdr->Id.SyncId.TreeId), le64_to_cpu(shdr->SessionId), le16_to_cpu(shdr->Command), le64_to_cpu(shdr->MessageId), le32_to_cpu(smb2err), rc); if (rc == -EIO) smb_EIO1(smb_eio_trace_smb2_received_error, le32_to_cpu(smb2err)); return rc; } int __init smb2_init_maperror(void) { unsigned int i; /* Check whether the array is sorted in ascending order */ for (i = 1; i < ARRAY_SIZE(smb2_error_map_table); i++) { if (smb2_error_map_table[i].smb2_status >= smb2_error_map_table[i - 1].smb2_status) continue; pr_err("smb2_error_map_table array order is incorrect\n"); return -EINVAL; } return 0; } #if IS_ENABLED(CONFIG_SMB_KUNIT_TESTS) #define EXPORT_SYMBOL_FOR_SMB_TEST(sym) \ EXPORT_SYMBOL_FOR_MODULES(sym, "smb2maperror_test") /* Previous prototype for eliminating the build warning. */ const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status); const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status) { return smb2_get_err_map(smb2_status); } EXPORT_SYMBOL_FOR_SMB_TEST(smb2_get_err_map_test); const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table; EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_table_test); unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table); EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_num); #endif