xref: /spdk/lib/nvmf/auth.c (revision 9b8579e4af16f0826736c09db858e0737f7556c5)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2024 Intel Corporation
3  */
4 
5 #include "spdk/log.h"
6 #include "spdk/stdinc.h"
7 #include "spdk/string.h"
8 #include "spdk/thread.h"
9 
10 #include "nvmf_internal.h"
11 
12 #define NVMF_AUTH_DEFAULT_KATO_US (120ull * 1000 * 1000)
13 
14 #define AUTH_ERRLOG(q, fmt, ...) \
15 	SPDK_ERRLOG("[%s:%s:%u] " fmt, (q)->ctrlr->subsys->subnqn, (q)->ctrlr->hostnqn, \
16 		    (q)->qid, ## __VA_ARGS__)
17 #define AUTH_DEBUGLOG(q, fmt, ...) \
18 	SPDK_DEBUGLOG(nvmf_auth, "[%s:%s:%u] " fmt, \
19 		      (q)->ctrlr->subsys->subnqn, (q)->ctrlr->hostnqn, (q)->qid, ## __VA_ARGS__)
20 
21 enum nvmf_qpair_auth_state {
22 	NVMF_QPAIR_AUTH_NEGOTIATE,
23 	NVMF_QPAIR_AUTH_ERROR,
24 };
25 
26 struct spdk_nvmf_qpair_auth {
27 	enum nvmf_qpair_auth_state	state;
28 	struct spdk_poller		*poller;
29 };
30 
31 static void
32 nvmf_auth_request_complete(struct spdk_nvmf_request *req, int sct, int sc, int dnr)
33 {
34 	struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl;
35 
36 	response->status.sct = sct;
37 	response->status.sc = sc;
38 	response->status.dnr = dnr;
39 
40 	spdk_nvmf_request_complete(req);
41 }
42 
43 __attribute__((unused)) static const char *
44 nvmf_auth_get_state_name(enum nvmf_qpair_auth_state state)
45 {
46 	static const char *state_names[] = {
47 		[NVMF_QPAIR_AUTH_NEGOTIATE] = "negotiate",
48 		[NVMF_QPAIR_AUTH_ERROR] = "error",
49 	};
50 
51 	return state_names[state];
52 }
53 
54 static void
55 nvmf_auth_set_state(struct spdk_nvmf_qpair *qpair, enum nvmf_qpair_auth_state state)
56 {
57 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
58 
59 	if (auth->state == state) {
60 		return;
61 	}
62 
63 	AUTH_DEBUGLOG(qpair, "auth state: %s\n", nvmf_auth_get_state_name(state));
64 	auth->state = state;
65 }
66 
67 static void
68 nvmf_auth_disconnect_qpair(struct spdk_nvmf_qpair *qpair)
69 {
70 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_ERROR);
71 	spdk_nvmf_qpair_disconnect(qpair);
72 }
73 
74 static int
75 nvmf_auth_timeout_poller(void *ctx)
76 {
77 	struct spdk_nvmf_qpair *qpair = ctx;
78 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
79 
80 	AUTH_ERRLOG(qpair, "authentication timed out\n");
81 
82 	spdk_poller_unregister(&auth->poller);
83 	nvmf_auth_disconnect_qpair(qpair);
84 
85 	return SPDK_POLLER_BUSY;
86 }
87 
88 static int
89 nvmf_auth_rearm_poller(struct spdk_nvmf_qpair *qpair)
90 {
91 	struct spdk_nvmf_ctrlr *ctrlr = qpair->ctrlr;
92 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
93 	uint64_t timeout;
94 
95 	timeout = ctrlr->feat.keep_alive_timer.bits.kato > 0 ?
96 		  ctrlr->feat.keep_alive_timer.bits.kato * 1000 :
97 		  NVMF_AUTH_DEFAULT_KATO_US;
98 
99 	spdk_poller_unregister(&auth->poller);
100 	auth->poller = SPDK_POLLER_REGISTER(nvmf_auth_timeout_poller, qpair, timeout);
101 	if (auth->poller == NULL) {
102 		return -ENOMEM;
103 	}
104 
105 	return 0;
106 }
107 
108 static int
109 nvmf_auth_check_command(struct spdk_nvmf_request *req, uint8_t secp,
110 			uint8_t spsp0, uint8_t spsp1, uint32_t len)
111 {
112 	struct spdk_nvmf_qpair *qpair = req->qpair;
113 
114 	if (secp != SPDK_NVMF_AUTH_SECP_NVME) {
115 		AUTH_ERRLOG(qpair, "invalid secp=%u\n", secp);
116 		return -EINVAL;
117 	}
118 	if (spsp0 != 1 || spsp1 != 1) {
119 		AUTH_ERRLOG(qpair, "invalid spsp0=%u, spsp1=%u\n", spsp0, spsp1);
120 		return -EINVAL;
121 	}
122 	if (len != req->length) {
123 		AUTH_ERRLOG(qpair, "invalid length: %"PRIu32" != %"PRIu32"\n", len, req->length);
124 		return -EINVAL;
125 	}
126 
127 	return 0;
128 }
129 
130 static void
131 nvmf_auth_send_exec(struct spdk_nvmf_request *req)
132 {
133 	struct spdk_nvmf_fabric_auth_send_cmd *cmd = &req->cmd->auth_send_cmd;
134 	int rc;
135 
136 	rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->tl);
137 	if (rc != 0) {
138 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
139 					   SPDK_NVME_SC_INVALID_FIELD, 1);
140 		return;
141 	}
142 
143 	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
144 				   SPDK_NVME_SC_INVALID_OPCODE, 1);
145 }
146 
147 static void
148 nvmf_auth_recv_exec(struct spdk_nvmf_request *req)
149 {
150 	struct spdk_nvmf_fabric_auth_recv_cmd *cmd = &req->cmd->auth_recv_cmd;
151 	int rc;
152 
153 	rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->al);
154 	if (rc != 0) {
155 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
156 					   SPDK_NVME_SC_INVALID_FIELD, 1);
157 		return;
158 	}
159 
160 	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
161 				   SPDK_NVME_SC_INVALID_OPCODE, 1);
162 }
163 
164 int
165 nvmf_auth_request_exec(struct spdk_nvmf_request *req)
166 {
167 	struct spdk_nvmf_qpair *qpair = req->qpair;
168 	union nvmf_h2c_msg *cmd = req->cmd;
169 
170 	/* We don't support reauthentication */
171 	if (qpair->state != SPDK_NVMF_QPAIR_AUTHENTICATING) {
172 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
173 					   SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR, 0);
174 		return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS;
175 	}
176 
177 	assert(cmd->nvmf_cmd.opcode == SPDK_NVME_OPC_FABRIC);
178 	switch (cmd->nvmf_cmd.fctype) {
179 	case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND:
180 		nvmf_auth_send_exec(req);
181 		break;
182 	case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV:
183 		nvmf_auth_recv_exec(req);
184 		break;
185 	default:
186 		assert(0 && "invalid fctype");
187 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
188 					   SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 0);
189 		break;
190 	}
191 
192 	return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS;
193 }
194 
195 int
196 nvmf_qpair_auth_init(struct spdk_nvmf_qpair *qpair)
197 {
198 	struct spdk_nvmf_qpair_auth *auth;
199 	int rc;
200 
201 	assert(qpair->auth == NULL);
202 	auth = calloc(1, sizeof(*qpair->auth));
203 	if (auth == NULL) {
204 		return -ENOMEM;
205 	}
206 
207 	qpair->auth = auth;
208 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_NEGOTIATE);
209 
210 	rc = nvmf_auth_rearm_poller(qpair);
211 	if (rc != 0) {
212 		AUTH_ERRLOG(qpair, "failed to arm timeout poller: %s\n", spdk_strerror(-rc));
213 		nvmf_qpair_auth_destroy(qpair);
214 		return rc;
215 	}
216 
217 	return 0;
218 }
219 
220 void
221 nvmf_qpair_auth_destroy(struct spdk_nvmf_qpair *qpair)
222 {
223 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
224 
225 	if (auth != NULL) {
226 		spdk_poller_unregister(&auth->poller);
227 		free(qpair->auth);
228 		qpair->auth = NULL;
229 	}
230 }
231 
232 bool
233 nvmf_auth_is_supported(void)
234 {
235 	return true;
236 }
237 SPDK_LOG_REGISTER_COMPONENT(nvmf_auth)
238