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