xref: /linux/fs/smb/client/smb2maperror.c (revision 480afcb19b61385dfe64840d87c355293a5fa698)
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