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