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