xref: /linux/fs/smb/client/smb2maperror.c (revision d874ca0522389405e26bc2ba38b59c9849c52cc1)
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 
cmp_smb2_status(const void * _key,const void * _pivot)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 
smb2_get_err_map(__u32 smb2_status)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
map_smb2_to_linux_error(char * buf,bool log_err)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 
smb2_init_maperror(void)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 /* Previous prototype for eliminating the build warning. */
116 const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status);
117 
smb2_get_err_map_test(__u32 smb2_status)118 const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status)
119 {
120 	return smb2_get_err_map(smb2_status);
121 }
122 EXPORT_SYMBOL_FOR_SMB_TEST(smb2_get_err_map_test);
123 
124 const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table;
125 EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_table_test);
126 
127 unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table);
128 EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_num);
129 #endif
130