| // 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 "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) |
| /* 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_GPL(smb2_get_err_map_test); |
| |
| const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table; |
| EXPORT_SYMBOL_GPL(smb2_error_map_table_test); |
| |
| unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table); |
| EXPORT_SYMBOL_GPL(smb2_error_map_num); |
| #endif |