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