Skip to content

Commit c13abc6

Browse files
committed
mi: be pedantic with response message format
This change adds a few tests to check against invalid response data received by the NVMe-MI device, and some tests to simulate these conditions. Because we're checking more of the response fields, we need a bit more support for constructing default responses in the mi and mi-mctp tests, so add that too. Signed-off-by: Jeremy Kerr <[email protected]>
1 parent 275cb31 commit c13abc6

3 files changed

Lines changed: 132 additions & 6 deletions

File tree

src/nvme/mi.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,33 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
192192
}
193193
}
194194

195+
/* basic response checks */
196+
if (resp->hdr_len < sizeof(struct nvme_mi_msg_hdr)) {
197+
nvme_msg(ep->root, LOG_DEBUG,
198+
"Bad response header len: %zd\n", resp->hdr_len);
199+
return -EIO;
200+
}
201+
202+
if (resp->hdr->type != NVME_MI_MSGTYPE_NVME) {
203+
nvme_msg(ep->root, LOG_DEBUG,
204+
"Invalid message type 0x%02x\n", resp->hdr->type);
205+
return -EPROTO;
206+
}
207+
208+
if (!(resp->hdr->nmp & (NVME_MI_ROR_RSP << 7))) {
209+
nvme_msg(ep->root, LOG_DEBUG,
210+
"ROR value in response indicates a request\n");
211+
return -EIO;
212+
}
213+
214+
if ((resp->hdr->nmp & 0x1) != (req->hdr->nmp & 0x1)) {
215+
nvme_msg(ep->root, LOG_WARNING,
216+
"Command slot mismatch: req %d, resp %d\n",
217+
req->hdr->nmp & 0x1,
218+
resp->hdr->nmp & 0x1);
219+
return -EIO;
220+
}
221+
195222
return 0;
196223
}
197224

test/mi-mctp.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,18 @@ ssize_t __wrap_sendmsg(int sd, const struct msghdr *hdr, int flags)
112112

113113
test_peer.rx_buf_len = pos;
114114

115-
if (test_peer.rx_fn)
115+
116+
if (test_peer.rx_fn) {
116117
test_peer.rx_res = test_peer.rx_fn(&test_peer,
117118
test_peer.rx_buf,
118119
test_peer.rx_buf_len);
120+
} else {
121+
/* set up a few default response fields; caller may have
122+
* initialised the rest of the response */
123+
test_peer.tx_buf[0] = NVME_MI_MSGTYPE_NVME;
124+
test_peer.tx_buf[1] = test_peer.rx_buf[1] | (NVME_MI_ROR_RSP << 7);
125+
test_set_tx_mic(&test_peer);
126+
}
119127

120128
errno = test_peer.rx_errno;
121129

@@ -191,9 +199,8 @@ static void test_read_mi_data(nvme_mi_ep_t ep, struct test_peer *peer)
191199
struct nvme_mi_read_nvm_ss_info ss_info;
192200
int rc;
193201

194-
/* empty response data, but with correct MIC */
202+
/* empty response data */
195203
peer->tx_buf_len = 8 + 32;
196-
test_set_tx_mic(peer);
197204

198205
rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info);
199206
assert(rc == 0);

test/mi.c

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ static int test_transport_submit(struct nvme_mi_ep *ep,
4141

4242
assert(tpd->magic == test_transport_magic);
4343

44-
/* start from a zeroed response */
44+
/* start from a minimal response: zeroed data, nmp to match request */
4545
memset(resp->hdr, 0, resp->hdr_len);
4646
memset(resp->data, 0, resp->data_len);
47+
resp->hdr->type = NVME_MI_MSGTYPE_NVME;
48+
resp->hdr->nmp = req->hdr->nmp | (NVME_MI_ROR_RSP << 7);
4749

4850
if (tpd->submit_cb)
4951
return tpd->submit_cb(ep, req, resp, tpd->submit_cb_data);
@@ -417,8 +419,6 @@ static int test_admin_id_cb(struct nvme_mi_ep *ep,
417419

418420
/* create valid (but somewhat empty) response */
419421
hdr = (__u8 *)resp->hdr;
420-
memset(resp->hdr, 0, resp->hdr_len);
421-
memset(resp->data, 0, resp->data_len);
422422
hdr[4] = 0x00; /* status: success */
423423

424424
test_transport_resp_calc_mic(resp);
@@ -555,6 +555,94 @@ static void test_admin_invalid_formats(nvme_mi_ep_t ep)
555555
assert(rc != 0);
556556
}
557557

558+
/* test: header length too small */
559+
static int test_resp_hdr_small_cb(struct nvme_mi_ep *ep,
560+
struct nvme_mi_req *req,
561+
struct nvme_mi_resp *resp,
562+
void *data)
563+
{
564+
resp->hdr_len = 2;
565+
test_transport_resp_calc_mic(resp);
566+
return 0;
567+
}
568+
569+
static void test_resp_hdr_small(nvme_mi_ep_t ep)
570+
{
571+
struct nvme_mi_read_nvm_ss_info ss_info;
572+
int rc;
573+
574+
test_set_transport_callback(ep, test_resp_hdr_small_cb, NULL);
575+
576+
rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info);
577+
assert(rc != 0);
578+
}
579+
580+
/* test: respond with a request message */
581+
static int test_resp_req_cb(struct nvme_mi_ep *ep,
582+
struct nvme_mi_req *req,
583+
struct nvme_mi_resp *resp,
584+
void *data)
585+
{
586+
resp->hdr->nmp &= ~(NVME_MI_ROR_RSP << 7);
587+
test_transport_resp_calc_mic(resp);
588+
return 0;
589+
}
590+
591+
static void test_resp_req(nvme_mi_ep_t ep)
592+
{
593+
struct nvme_mi_read_nvm_ss_info ss_info;
594+
int rc;
595+
596+
test_set_transport_callback(ep, test_resp_req_cb, NULL);
597+
598+
rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info);
599+
assert(rc != 0);
600+
}
601+
602+
/* test: invalid MCTP type in response */
603+
static int test_resp_invalid_type_cb(struct nvme_mi_ep *ep,
604+
struct nvme_mi_req *req,
605+
struct nvme_mi_resp *resp,
606+
void *data)
607+
{
608+
resp->hdr->type = 0x3;
609+
test_transport_resp_calc_mic(resp);
610+
return 0;
611+
}
612+
613+
static void test_resp_invalid_type(nvme_mi_ep_t ep)
614+
{
615+
struct nvme_mi_read_nvm_ss_info ss_info;
616+
int rc;
617+
618+
test_set_transport_callback(ep, test_resp_invalid_type_cb, NULL);
619+
620+
rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info);
621+
assert(rc != 0);
622+
}
623+
624+
/* test: response with mis-matching command slot */
625+
static int test_resp_csi_cb(struct nvme_mi_ep *ep,
626+
struct nvme_mi_req *req,
627+
struct nvme_mi_resp *resp,
628+
void *data)
629+
{
630+
resp->hdr->nmp ^= 0x1;
631+
test_transport_resp_calc_mic(resp);
632+
return 0;
633+
}
634+
635+
static void test_resp_csi(nvme_mi_ep_t ep)
636+
{
637+
struct nvme_mi_read_nvm_ss_info ss_info;
638+
int rc;
639+
640+
test_set_transport_callback(ep, test_resp_csi_cb, NULL);
641+
642+
rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info);
643+
assert(rc != 0);
644+
}
645+
558646
#define DEFINE_TEST(name) { #name, test_ ## name }
559647
struct test {
560648
const char *name;
@@ -570,6 +658,10 @@ struct test {
570658
DEFINE_TEST(admin_id),
571659
DEFINE_TEST(admin_err_resp),
572660
DEFINE_TEST(admin_invalid_formats),
661+
DEFINE_TEST(resp_req),
662+
DEFINE_TEST(resp_hdr_small),
663+
DEFINE_TEST(resp_invalid_type),
664+
DEFINE_TEST(resp_csi),
573665
};
574666

575667
static void run_test(struct test *test, FILE *logfd, nvme_mi_ep_t ep)

0 commit comments

Comments
 (0)