| // 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 <linux/errno.h> | |
| #include <kunit/visibility.h> | |
| #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) | |
| const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status) | |
| { | |
| return smb2_get_err_map(smb2_status); | |
| } | |
| EXPORT_SYMBOL_IF_KUNIT(smb2_get_err_map_test); | |
| const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table; | |
| EXPORT_SYMBOL_IF_KUNIT(smb2_error_map_table_test); | |
| unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table); | |
| EXPORT_SYMBOL_IF_KUNIT(smb2_error_map_num); | |
| #endif |