summaryrefslogtreecommitdiff
path: root/fs/smb/client/smb2maperror.c
blob: cd036365201fbcb6010abac6864fe9ec83e61e77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// SPDX-License-Identifier: LGPL-2.1
/*
 *
 *   Functions which do error mapping of SMB2 status codes to POSIX errors
 *
 *   Copyright (C) International Business Machines  Corp., 2009
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 */
#include <linux/errno.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "smb2proto.h"
#include "smb2glob.h"
#include "../common/smb2status.h"
#include "trace.h"

struct status_to_posix_error {
	__u32 smb2_status;
	int posix_error;
	char *status_string;
};

static const struct status_to_posix_error smb2_error_map_table[] = {
/*
 * Automatically generated by the `gen_smb2_mapping` script,
 * sorted by NT status code (cpu-endian, ascending)
 */
#include "smb2_mapping_table.c"
};

static __always_inline int cmp_smb2_status(const void *_key, const void *_pivot)
{
	__u32 key = *(__u32 *)_key;
	const struct status_to_posix_error *pivot = _pivot;

	if (key < pivot->smb2_status)
		return -1;
	if (key > pivot->smb2_status)
		return 1;
	return 0;
}

static const struct status_to_posix_error *smb2_get_err_map(__u32 smb2_status)
{
	const struct status_to_posix_error *err_map;

	err_map = __inline_bsearch(&smb2_status, smb2_error_map_table,
				   ARRAY_SIZE(smb2_error_map_table),
				   sizeof(struct status_to_posix_error),
				   cmp_smb2_status);
	return err_map;
}

int
map_smb2_to_linux_error(char *buf, bool log_err)
{
	struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
	int rc = -EIO;
	__le32 smb2err = shdr->Status;
	const struct status_to_posix_error *err_map;

	if (smb2err == 0) {
		trace_smb3_cmd_done(le32_to_cpu(shdr->Id.SyncId.TreeId),
			      le64_to_cpu(shdr->SessionId),
			      le16_to_cpu(shdr->Command),
			      le64_to_cpu(shdr->MessageId));
		return 0;
	}

	log_err = (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
		   (smb2err != STATUS_END_OF_FILE)) ||
		  (cifsFYI & CIFS_RC);

	err_map = smb2_get_err_map(le32_to_cpu(smb2err));
	if (!err_map)
		goto out;

	rc = err_map->posix_error;
	if (log_err)
		pr_notice("Status code returned 0x%08x %s\n",
			  err_map->smb2_status, err_map->status_string);

out:
	/* on error mapping not found  - return EIO */

	cifs_dbg(FYI, "Mapping SMB2 status code 0x%08x to POSIX err %d\n",
		 le32_to_cpu(smb2err), rc);

	trace_smb3_cmd_err(le32_to_cpu(shdr->Id.SyncId.TreeId),
			   le64_to_cpu(shdr->SessionId),
			   le16_to_cpu(shdr->Command),
			   le64_to_cpu(shdr->MessageId),
			   le32_to_cpu(smb2err), rc);
	if (rc == -EIO)
		smb_EIO1(smb_eio_trace_smb2_received_error, le32_to_cpu(smb2err));
	return rc;
}

int __init smb2_init_maperror(void)
{
	unsigned int i;

	/* Check whether the array is sorted in ascending order */
	for (i = 1; i < ARRAY_SIZE(smb2_error_map_table); i++) {
		if (smb2_error_map_table[i].smb2_status >=
		    smb2_error_map_table[i - 1].smb2_status)
			continue;

		pr_err("smb2_error_map_table array order is incorrect\n");
		return -EINVAL;
	}

	return 0;
}

#define SMB_CLIENT_KUNIT_AVAILABLE \
	((IS_MODULE(CONFIG_CIFS) && IS_ENABLED(CONFIG_KUNIT)) || \
	 (IS_BUILTIN(CONFIG_CIFS) && IS_BUILTIN(CONFIG_KUNIT)))

#if SMB_CLIENT_KUNIT_AVAILABLE && IS_ENABLED(CONFIG_SMB_KUNIT_TESTS)
#include "smb2maperror_test.c"
#endif /* CONFIG_SMB_KUNIT_TESTS */