1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022-2024 Chelsio Communications, Inc. 5 * Written by: John Baldwin <jhb@FreeBSD.org> 6 */ 7 8 #ifndef __NVMF_TCP_H__ 9 #define __NVMF_TCP_H__ 10 11 #ifndef _KERNEL 12 #define MPASS assert 13 #endif 14 15 #define NVME_SGL_TYPE_ICD \ 16 NVME_SGL_TYPE(NVME_SGL_TYPE_DATA_BLOCK, NVME_SGL_SUBTYPE_OFFSET) 17 18 #define NVME_SGL_TYPE_COMMAND_BUFFER \ 19 NVME_SGL_TYPE(NVME_SGL_TYPE_TRANSPORT_DATA_BLOCK, \ 20 NVME_SGL_SUBTYPE_TRANSPORT) 21 22 /* 23 * Validate common fields in a received PDU header. If an error is 24 * detected that requires an immediate disconnect, ECONNRESET is 25 * returned. If an error is detected that should be reported, EBADMSG 26 * is returned and *fes and *fei are set to the values to be used in a 27 * termination request PDU. If no error is detected, 0 is returned 28 * and *data_lenp is set to the length of any included data. 29 * 30 * Section number references refer to NVM Express over Fabrics 31 * Revision 1.1 dated October 22, 2019. 32 */ 33 static __inline int 34 nvmf_tcp_validate_pdu_header(const struct nvme_tcp_common_pdu_hdr *ch, 35 bool controller, bool header_digests, bool data_digests, uint8_t rxpda, 36 uint32_t *data_lenp, uint16_t *fes, uint32_t *fei) 37 { 38 uint32_t data_len, plen; 39 u_int expected_hlen, full_hlen; 40 uint8_t digest_flags, valid_flags; 41 42 plen = le32toh(ch->plen); 43 full_hlen = ch->hlen; 44 if ((ch->flags & NVME_TCP_CH_FLAGS_HDGSTF) != 0) 45 full_hlen += sizeof(uint32_t); 46 if (plen == full_hlen) 47 data_len = 0; 48 else 49 data_len = plen - ch->pdo; 50 51 /* 52 * Errors must be reported for the lowest incorrect field 53 * first, so validate fields in order. 54 */ 55 56 /* Validate pdu_type. */ 57 58 /* Controllers only receive PDUs with a PDU direction of 0. */ 59 if (controller != ((ch->pdu_type & 0x01) == 0)) { 60 printf("NVMe/TCP: Invalid PDU type %u\n", ch->pdu_type); 61 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 62 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, pdu_type); 63 return (EBADMSG); 64 } 65 66 switch (ch->pdu_type) { 67 case NVME_TCP_PDU_TYPE_IC_REQ: 68 case NVME_TCP_PDU_TYPE_IC_RESP: 69 /* Shouldn't get these for an established connection. */ 70 printf("NVMe/TCP: Received Initialize Connection PDU\n"); 71 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 72 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, pdu_type); 73 return (EBADMSG); 74 case NVME_TCP_PDU_TYPE_H2C_TERM_REQ: 75 case NVME_TCP_PDU_TYPE_C2H_TERM_REQ: 76 /* 77 * 7.4.7 Termination requests with invalid PDU lengths 78 * result in an immediate connection termination 79 * without reporting an error. 80 */ 81 if (plen < sizeof(struct nvme_tcp_term_req_hdr) || 82 plen > NVME_TCP_TERM_REQ_PDU_MAX_SIZE) { 83 printf("NVMe/TCP: Received invalid termination request\n"); 84 return (ECONNRESET); 85 } 86 break; 87 case NVME_TCP_PDU_TYPE_CAPSULE_CMD: 88 case NVME_TCP_PDU_TYPE_CAPSULE_RESP: 89 case NVME_TCP_PDU_TYPE_H2C_DATA: 90 case NVME_TCP_PDU_TYPE_C2H_DATA: 91 case NVME_TCP_PDU_TYPE_R2T: 92 break; 93 default: 94 printf("NVMe/TCP: Invalid PDU type %u\n", ch->pdu_type); 95 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 96 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, pdu_type); 97 return (EBADMSG); 98 } 99 100 /* Validate flags. */ 101 switch (ch->pdu_type) { 102 default: 103 __assert_unreachable(); 104 break; 105 case NVME_TCP_PDU_TYPE_H2C_TERM_REQ: 106 case NVME_TCP_PDU_TYPE_C2H_TERM_REQ: 107 valid_flags = 0; 108 break; 109 case NVME_TCP_PDU_TYPE_CAPSULE_CMD: 110 valid_flags = NVME_TCP_CH_FLAGS_HDGSTF | 111 NVME_TCP_CH_FLAGS_DDGSTF; 112 break; 113 case NVME_TCP_PDU_TYPE_CAPSULE_RESP: 114 case NVME_TCP_PDU_TYPE_R2T: 115 valid_flags = NVME_TCP_CH_FLAGS_HDGSTF; 116 break; 117 case NVME_TCP_PDU_TYPE_H2C_DATA: 118 valid_flags = NVME_TCP_CH_FLAGS_HDGSTF | 119 NVME_TCP_CH_FLAGS_DDGSTF | NVME_TCP_H2C_DATA_FLAGS_LAST_PDU; 120 break; 121 case NVME_TCP_PDU_TYPE_C2H_DATA: 122 valid_flags = NVME_TCP_CH_FLAGS_HDGSTF | 123 NVME_TCP_CH_FLAGS_DDGSTF | NVME_TCP_C2H_DATA_FLAGS_LAST_PDU | 124 NVME_TCP_C2H_DATA_FLAGS_SUCCESS; 125 break; 126 } 127 if ((ch->flags & ~valid_flags) != 0) { 128 printf("NVMe/TCP: Invalid PDU header flags %#x\n", ch->flags); 129 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 130 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, flags); 131 return (EBADMSG); 132 } 133 134 /* 135 * Verify that digests are present iff enabled. Note that the 136 * data digest will not be present if there is no data 137 * payload. 138 */ 139 digest_flags = 0; 140 if (header_digests) 141 digest_flags |= NVME_TCP_CH_FLAGS_HDGSTF; 142 if (data_digests && data_len != 0) 143 digest_flags |= NVME_TCP_CH_FLAGS_DDGSTF; 144 if ((digest_flags & valid_flags) != 145 (ch->flags & (NVME_TCP_CH_FLAGS_HDGSTF | 146 NVME_TCP_CH_FLAGS_DDGSTF))) { 147 printf("NVMe/TCP: Invalid PDU header flags %#x\n", ch->flags); 148 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 149 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, flags); 150 return (EBADMSG); 151 } 152 153 /* 7.4.5.2: SUCCESS in C2H requires LAST_PDU */ 154 if (ch->pdu_type == NVME_TCP_PDU_TYPE_C2H_DATA && 155 (ch->flags & (NVME_TCP_C2H_DATA_FLAGS_LAST_PDU | 156 NVME_TCP_C2H_DATA_FLAGS_SUCCESS)) == 157 NVME_TCP_C2H_DATA_FLAGS_SUCCESS) { 158 printf("NVMe/TCP: Invalid PDU header flags %#x\n", ch->flags); 159 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 160 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, flags); 161 return (EBADMSG); 162 } 163 164 /* Validate hlen. */ 165 switch (ch->pdu_type) { 166 default: 167 __assert_unreachable(); 168 break; 169 case NVME_TCP_PDU_TYPE_H2C_TERM_REQ: 170 case NVME_TCP_PDU_TYPE_C2H_TERM_REQ: 171 expected_hlen = sizeof(struct nvme_tcp_term_req_hdr); 172 break; 173 case NVME_TCP_PDU_TYPE_CAPSULE_CMD: 174 expected_hlen = sizeof(struct nvme_tcp_cmd); 175 break; 176 case NVME_TCP_PDU_TYPE_CAPSULE_RESP: 177 expected_hlen = sizeof(struct nvme_tcp_rsp); 178 break; 179 case NVME_TCP_PDU_TYPE_H2C_DATA: 180 expected_hlen = sizeof(struct nvme_tcp_h2c_data_hdr); 181 break; 182 case NVME_TCP_PDU_TYPE_C2H_DATA: 183 expected_hlen = sizeof(struct nvme_tcp_c2h_data_hdr); 184 break; 185 case NVME_TCP_PDU_TYPE_R2T: 186 expected_hlen = sizeof(struct nvme_tcp_r2t_hdr); 187 break; 188 } 189 if (ch->hlen != expected_hlen) { 190 printf("NVMe/TCP: Invalid PDU header length %u\n", ch->hlen); 191 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 192 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, hlen); 193 return (EBADMSG); 194 } 195 196 /* Validate pdo. */ 197 switch (ch->pdu_type) { 198 default: 199 __assert_unreachable(); 200 break; 201 case NVME_TCP_PDU_TYPE_H2C_TERM_REQ: 202 case NVME_TCP_PDU_TYPE_C2H_TERM_REQ: 203 case NVME_TCP_PDU_TYPE_CAPSULE_RESP: 204 case NVME_TCP_PDU_TYPE_R2T: 205 if (ch->pdo != 0) { 206 printf("NVMe/TCP: Invalid PDU data offset %u\n", 207 ch->pdo); 208 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 209 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, pdo); 210 return (EBADMSG); 211 } 212 break; 213 case NVME_TCP_PDU_TYPE_CAPSULE_CMD: 214 case NVME_TCP_PDU_TYPE_H2C_DATA: 215 case NVME_TCP_PDU_TYPE_C2H_DATA: 216 /* Permit PDO of 0 if there is no data. */ 217 if (data_len == 0 && ch->pdo == 0) 218 break; 219 220 if (ch->pdo < full_hlen || ch->pdo > plen || 221 ch->pdo % rxpda != 0) { 222 printf("NVMe/TCP: Invalid PDU data offset %u\n", 223 ch->pdo); 224 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 225 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, pdo); 226 return (EBADMSG); 227 } 228 break; 229 } 230 231 /* Validate plen. */ 232 if (plen < ch->hlen) { 233 printf("NVMe/TCP: Invalid PDU length %u\n", plen); 234 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 235 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, plen); 236 return (EBADMSG); 237 } 238 239 switch (ch->pdu_type) { 240 default: 241 __assert_unreachable(); 242 break; 243 case NVME_TCP_PDU_TYPE_H2C_TERM_REQ: 244 case NVME_TCP_PDU_TYPE_C2H_TERM_REQ: 245 /* Checked above. */ 246 MPASS(plen <= NVME_TCP_TERM_REQ_PDU_MAX_SIZE); 247 break; 248 case NVME_TCP_PDU_TYPE_CAPSULE_CMD: 249 case NVME_TCP_PDU_TYPE_H2C_DATA: 250 case NVME_TCP_PDU_TYPE_C2H_DATA: 251 if ((ch->flags & NVME_TCP_CH_FLAGS_DDGSTF) != 0 && 252 data_len <= sizeof(uint32_t)) { 253 printf("NVMe/TCP: PDU %u too short for digest\n", 254 ch->pdu_type); 255 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 256 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, plen); 257 return (EBADMSG); 258 } 259 break; 260 case NVME_TCP_PDU_TYPE_R2T: 261 case NVME_TCP_PDU_TYPE_CAPSULE_RESP: 262 if (data_len != 0) { 263 printf("NVMe/TCP: PDU %u with data length %u\n", 264 ch->pdu_type, data_len); 265 *fes = NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD; 266 *fei = offsetof(struct nvme_tcp_common_pdu_hdr, plen); 267 return (EBADMSG); 268 } 269 break; 270 } 271 272 if ((ch->flags & NVME_TCP_CH_FLAGS_DDGSTF) != 0) 273 data_len -= sizeof(uint32_t); 274 275 *data_lenp = data_len; 276 return (0); 277 } 278 279 #endif /* !__NVMF_TCP_H__ */ 280