1 // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * 4 * Functions which do error mapping of SMB2 status codes to POSIX errors 5 * 6 * Copyright (C) International Business Machines Corp., 2009 7 * Author(s): Steve French (sfrench@us.ibm.com) 8 * 9 */ 10 #include <linux/errno.h> 11 #include "cifsproto.h" 12 #include "cifs_debug.h" 13 #include "smb2proto.h" 14 #include "smb2glob.h" 15 #include "../common/smb2status.h" 16 #include "trace.h" 17 18 static const struct status_to_posix_error smb2_error_map_table[] = { 19 /* 20 * Automatically generated by the `gen_smb2_mapping` script, 21 * sorted by NT status code (cpu-endian, ascending) 22 */ 23 #include "smb2_mapping_table.c" 24 }; 25 26 static __always_inline int cmp_smb2_status(const void *_key, const void *_pivot) 27 { 28 __u32 key = *(__u32 *)_key; 29 const struct status_to_posix_error *pivot = _pivot; 30 31 if (key < pivot->smb2_status) 32 return -1; 33 if (key > pivot->smb2_status) 34 return 1; 35 return 0; 36 } 37 38 static const struct status_to_posix_error *smb2_get_err_map(__u32 smb2_status) 39 { 40 const struct status_to_posix_error *err_map; 41 42 err_map = __inline_bsearch(&smb2_status, smb2_error_map_table, 43 ARRAY_SIZE(smb2_error_map_table), 44 sizeof(struct status_to_posix_error), 45 cmp_smb2_status); 46 return err_map; 47 } 48 49 int 50 map_smb2_to_linux_error(char *buf, bool log_err) 51 { 52 struct smb2_hdr *shdr = (struct smb2_hdr *)buf; 53 int rc = -EIO; 54 __le32 smb2err = shdr->Status; 55 const struct status_to_posix_error *err_map; 56 57 if (smb2err == 0) { 58 trace_smb3_cmd_done(le32_to_cpu(shdr->Id.SyncId.TreeId), 59 le64_to_cpu(shdr->SessionId), 60 le16_to_cpu(shdr->Command), 61 le64_to_cpu(shdr->MessageId)); 62 return 0; 63 } 64 65 log_err = (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) && 66 (smb2err != STATUS_END_OF_FILE)) || 67 (cifsFYI & CIFS_RC); 68 69 err_map = smb2_get_err_map(le32_to_cpu(smb2err)); 70 if (!err_map) 71 goto out; 72 73 rc = err_map->posix_error; 74 if (log_err) 75 pr_notice("Status code returned 0x%08x %s\n", 76 err_map->smb2_status, err_map->status_string); 77 78 out: 79 /* on error mapping not found - return EIO */ 80 81 cifs_dbg(FYI, "Mapping SMB2 status code 0x%08x to POSIX err %d\n", 82 le32_to_cpu(smb2err), rc); 83 84 trace_smb3_cmd_err(le32_to_cpu(shdr->Id.SyncId.TreeId), 85 le64_to_cpu(shdr->SessionId), 86 le16_to_cpu(shdr->Command), 87 le64_to_cpu(shdr->MessageId), 88 le32_to_cpu(smb2err), rc); 89 if (rc == -EIO) 90 smb_EIO1(smb_eio_trace_smb2_received_error, le32_to_cpu(smb2err)); 91 return rc; 92 } 93 94 int __init smb2_init_maperror(void) 95 { 96 unsigned int i; 97 98 /* Check whether the array is sorted in ascending order */ 99 for (i = 1; i < ARRAY_SIZE(smb2_error_map_table); i++) { 100 if (smb2_error_map_table[i].smb2_status >= 101 smb2_error_map_table[i - 1].smb2_status) 102 continue; 103 104 pr_err("smb2_error_map_table array order is incorrect\n"); 105 return -EINVAL; 106 } 107 108 return 0; 109 } 110 111 #if IS_ENABLED(CONFIG_SMB_KUNIT_TESTS) 112 #define EXPORT_SYMBOL_FOR_SMB_TEST(sym) \ 113 EXPORT_SYMBOL_FOR_MODULES(sym, "smb2maperror_test") 114 115 const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status) 116 { 117 return smb2_get_err_map(smb2_status); 118 } 119 EXPORT_SYMBOL_FOR_SMB_TEST(smb2_get_err_map_test); 120 121 const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table; 122 EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_table_test); 123 124 unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table); 125 EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_num); 126 #endif 127