diff options
author | Hannes Reinecke <hare@suse.de> | 2023-03-10 08:44:45 +0100 |
---|---|---|
committer | Hannes Reinecke <hare@suse.de> | 2023-03-29 15:54:52 +0200 |
commit | 1a0c660776b337cb29d94ee8de050f21c9fd0df8 (patch) | |
tree | 6fbe2dbaa0f561bc9388da57e3fecfcff9420d7d | |
parent | 6f832c87e83768f104444dbfc3945a8ee2e24b65 (diff) | |
download | scsi-devel-1a0c660776b337cb29d94ee8de050f21c9fd0df8.tar.gz |
nvmet-tcp: control messages for recvmsg()
kTLS requires control messages for recvmsg() to relay any out-of-band
TLS messages (eg TLS alerts) to the caller.
Signed-off-by: Hannes Reinecke <hare@suse.de>
-rw-r--r-- | drivers/nvme/target/tcp.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 5daf161384713e..75017fd5da9fe1 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -12,6 +12,7 @@ #include <net/sock.h> #include <net/tcp.h> #ifdef CONFIG_NVME_TLS +#include <net/tls.h> #include <net/handshake.h> #include <linux/nvme-keyring.h> #endif @@ -92,6 +93,7 @@ struct nvmet_tcp_cmd { u32 pdu_len; u32 pdu_recv; int sg_idx; + char recv_cbuf[CMSG_LEN(sizeof(char))]; struct msghdr recv_msg; struct bio_vec *iov; u32 flags; @@ -1086,7 +1088,18 @@ static int nvmet_tcp_try_recv_pdu(struct nvmet_tcp_queue *queue) struct nvme_tcp_hdr *hdr = &queue->pdu.cmd.hdr; int len; struct kvec iov; +#ifdef CONFIG_NVME_TLS + char cbuf[CMSG_LEN(sizeof(char))] = {}; + unsigned char ctype; + struct cmsghdr *cmsg; + struct msghdr msg = { + .msg_control = cbuf, + .msg_controllen = sizeof(cbuf), + .msg_flags = MSG_DONTWAIT + }; +#else struct msghdr msg = { .msg_flags = MSG_DONTWAIT }; +#endif recv: iov.iov_base = (void *)&queue->pdu + queue->offset; @@ -1095,6 +1108,19 @@ recv: iov.iov_len, msg.msg_flags); if (unlikely(len < 0)) return len; +#ifdef CONFIG_NVME_TLS + cmsg = (struct cmsghdr *)cbuf; + if (CMSG_OK(&msg, cmsg) && + cmsg->cmsg_level == SOL_TLS && + cmsg->cmsg_type == TLS_GET_RECORD_TYPE) { + ctype = *((unsigned char *)CMSG_DATA(cmsg)); + if (ctype != TLS_RECORD_TYPE_DATA) { + pr_err("queue %d unhandled TLS record %d\n", + queue->idx, ctype); + return -ENOTCONN; + } + } +#endif queue->offset += len; queue->left -= len; @@ -1150,10 +1176,27 @@ static int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue) int ret; while (msg_data_left(&cmd->recv_msg)) { +#ifdef CONFIG_NVME_TLS + struct cmsghdr *cmsg; + unsigned char ctype; +#endif ret = sock_recvmsg(cmd->queue->sock, &cmd->recv_msg, cmd->recv_msg.msg_flags); if (ret <= 0) return ret; +#ifdef CONFIG_NVME_TLS + cmsg = (struct cmsghdr *)cmd->recv_cbuf; + if (CMSG_OK(&cmd->recv_msg, cmsg) && + cmsg->cmsg_level == SOL_TLS && + cmsg->cmsg_type == TLS_GET_RECORD_TYPE) { + ctype = *((unsigned char *)CMSG_DATA(cmsg)); + if (ctype != TLS_RECORD_TYPE_DATA) { + pr_err("queue %d unhandled TLS record %d\n", + queue->idx, ctype); + return -ENOTCONN; + } + } +#endif cmd->pdu_recv += ret; cmd->rbytes_done += ret; @@ -1175,7 +1218,18 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) { struct nvmet_tcp_cmd *cmd = queue->cmd; int ret; +#ifdef CONFIG_NVME_TLS + char cbuf[CMSG_LEN(sizeof(char))] = {}; + unsigned char ctype; + struct cmsghdr *cmsg; + struct msghdr msg = { + .msg_control = cbuf, + .msg_controllen = sizeof(cbuf), + .msg_flags = MSG_DONTWAIT + }; +#else struct msghdr msg = { .msg_flags = MSG_DONTWAIT }; +#endif struct kvec iov = { .iov_base = (void *)&cmd->recv_ddgst + queue->offset, .iov_len = queue->left @@ -1185,6 +1239,19 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) iov.iov_len, msg.msg_flags); if (unlikely(ret < 0)) return ret; +#ifdef CONFIG_NVME_TLS + cmsg = (struct cmsghdr *)cbuf; + if (CMSG_OK(&msg, cmsg) && + cmsg->cmsg_level == SOL_TLS && + cmsg->cmsg_type == TLS_GET_RECORD_TYPE) { + ctype = *((unsigned char *)CMSG_DATA(cmsg)); + if (ctype != TLS_RECORD_TYPE_DATA) { + pr_err("queue %d unhandled TLS record %d\n", + queue->idx, ctype); + return -ENOTCONN; + } + } +#endif queue->offset += ret; queue->left -= ret; @@ -1354,6 +1421,10 @@ static int nvmet_tcp_alloc_cmd(struct nvmet_tcp_queue *queue, if (!c->r2t_pdu) goto out_free_data; +#ifdef CONFIG_NVME_TLS + c->recv_msg.msg_control = c->recv_cbuf; + c->recv_msg.msg_controllen = sizeof(c->recv_cbuf); +#endif c->recv_msg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; list_add_tail(&c->entry, &queue->free_list); |