git: 6378393308bc - main - Add an internal libiscsiutil library.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 22 Dec 2021 18:43:35 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=6378393308bc6bd81fb871dacf6b03cf1a390d8b

commit 6378393308bc6bd81fb871dacf6b03cf1a390d8b
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2021-12-22 18:35:46 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2021-12-22 18:43:11 +0000

    Add an internal libiscsiutil library.
    
    Move some of the code duplicated between ctld(8) and iscsid(8) into a
    libiscsiutil library.
    
    Sharing the low-level PDU code did require having a
    'struct connection' base class with a method table to permit separate
    initiator vs target behavior (e.g. in handling proxy PDUs).
    
    Reviewed by:    mav, emaste
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D33544
---
 lib/Makefile                               |   1 +
 lib/libiscsiutil/Makefile                  |  10 +
 {usr.sbin/ctld => lib/libiscsiutil}/chap.c |   6 +-
 lib/libiscsiutil/connection.c              |  53 ++++
 {usr.sbin/ctld => lib/libiscsiutil}/keys.c |   6 +-
 lib/libiscsiutil/libiscsiutil.h            | 148 ++++++++++
 {usr.sbin/ctld => lib/libiscsiutil}/log.c  |   6 +-
 {usr.sbin/ctld => lib/libiscsiutil}/pdu.c  |  96 ++-----
 lib/libiscsiutil/utils.c                   |  44 +++
 rescue/rescue/Makefile                     |   3 +
 share/mk/bsd.libnames.mk                   |   1 +
 share/mk/src.libnames.mk                   |   4 +
 usr.sbin/ctld/Makefile                     |   7 +-
 usr.sbin/ctld/ctld.c                       |  86 ++++--
 usr.sbin/ctld/ctld.h                       | 102 +------
 usr.sbin/ctld/discovery.c                  |   8 +-
 usr.sbin/ctld/kernel.c                     |  27 +-
 usr.sbin/ctld/login.c                      |  51 ++--
 usr.sbin/iscsid/Makefile                   |   5 +-
 usr.sbin/iscsid/chap.c                     | 423 -----------------------------
 usr.sbin/iscsid/discovery.c                |  14 +-
 usr.sbin/iscsid/iscsid.c                   | 173 ++++++++----
 usr.sbin/iscsid/iscsid.h                   |  97 +------
 usr.sbin/iscsid/keys.c                     | 199 --------------
 usr.sbin/iscsid/log.c                      | 202 --------------
 usr.sbin/iscsid/login.c                    |  74 ++---
 usr.sbin/iscsid/pdu.c                      | 309 ---------------------
 27 files changed, 583 insertions(+), 1572 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index bd28b974c673..43c345daf356 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -63,6 +63,7 @@ SUBDIR=	${SUBDIR_BOOTSTRAP} \
 	libgeom \
 	libifconfig \
 	libipsec \
+	libiscsiutil \
 	libjail \
 	libkiconv \
 	libkvm \
diff --git a/lib/libiscsiutil/Makefile b/lib/libiscsiutil/Makefile
new file mode 100644
index 000000000000..9ec625970eae
--- /dev/null
+++ b/lib/libiscsiutil/Makefile
@@ -0,0 +1,10 @@
+LIB=		iscsiutil
+INTERNALLIB=
+PACKAGE=	iscsi
+
+INCS=		libiscsiutil.h
+
+SRCS=		chap.c connection.c keys.c log.c pdu.c utils.c
+CFLAGS+=	-I${SRCTOP}/sys/dev/iscsi
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/ctld/chap.c b/lib/libiscsiutil/chap.c
similarity index 99%
rename from usr.sbin/ctld/chap.c
rename to lib/libiscsiutil/chap.c
index 7b57b7080c97..b33fef220106 100644
--- a/usr.sbin/ctld/chap.c
+++ b/lib/libiscsiutil/chap.c
@@ -26,12 +26,8 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
@@ -39,7 +35,7 @@ __FBSDID("$FreeBSD$");
 #include <resolv.h>
 #include <md5.h>
 
-#include "ctld.h"
+#include "libiscsiutil.h"
 
 static void
 chap_compute_md5(const char id, const char *secret,
diff --git a/lib/libiscsiutil/connection.c b/lib/libiscsiutil/connection.c
new file mode 100644
index 000000000000..7dc50574644c
--- /dev/null
+++ b/lib/libiscsiutil/connection.c
@@ -0,0 +1,53 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2012 The FreeBSD Foundation
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "libiscsiutil.h"
+
+void
+connection_init(struct connection *conn, const struct connection_ops *ops,
+	bool use_proxy)
+{
+	memset(conn, 0, sizeof(*conn));
+	conn->conn_ops = ops;
+	conn->conn_use_proxy = use_proxy;
+
+	/*
+	 * Default values, from RFC 3720, section 12.
+	 */
+	conn->conn_header_digest = CONN_DIGEST_NONE;
+	conn->conn_data_digest = CONN_DIGEST_NONE;
+	conn->conn_immediate_data = true;
+	conn->conn_max_recv_data_segment_length = 8192;
+	conn->conn_max_send_data_segment_length = 8192;
+	conn->conn_max_burst_length = 262144;
+	conn->conn_first_burst_length = 65536;
+}
diff --git a/usr.sbin/ctld/keys.c b/lib/libiscsiutil/keys.c
similarity index 98%
rename from usr.sbin/ctld/keys.c
rename to lib/libiscsiutil/keys.c
index f28e333bcd81..8011b0a25329 100644
--- a/usr.sbin/ctld/keys.c
+++ b/lib/libiscsiutil/keys.c
@@ -26,18 +26,14 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "ctld.h"
+#include "libiscsiutil.h"
 
 struct keys *
 keys_new(void)
diff --git a/lib/libiscsiutil/libiscsiutil.h b/lib/libiscsiutil/libiscsiutil.h
new file mode 100644
index 000000000000..79c79872b2e6
--- /dev/null
+++ b/lib/libiscsiutil/libiscsiutil.h
@@ -0,0 +1,148 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2012 The FreeBSD Foundation
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __LIBISCSIUTIL_H__
+#define	__LIBISCSIUTIL_H__
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+struct connection_ops;
+
+#define	CONN_DIGEST_NONE		0
+#define	CONN_DIGEST_CRC32C		1
+
+struct connection {
+	const struct connection_ops *conn_ops;
+	int		conn_socket;
+	uint8_t		conn_isid[6];
+	uint16_t	conn_tsih;
+	uint32_t	conn_cmdsn;
+	uint32_t	conn_statsn;
+	int		conn_header_digest;
+	int		conn_data_digest;
+	bool		conn_immediate_data;
+	bool		conn_use_proxy;
+	int		conn_max_recv_data_segment_length;
+	int		conn_max_send_data_segment_length;
+	int		conn_max_burst_length;
+	int		conn_first_burst_length;
+};
+
+struct pdu {
+	struct connection *pdu_connection;
+	struct iscsi_bhs *pdu_bhs;
+	char		*pdu_data;
+	size_t		pdu_data_len;
+};
+
+struct connection_ops {
+	bool		(*timed_out)(void);
+	void		(*pdu_receive_proxy)(struct pdu *);
+	void		(*pdu_send_proxy)(struct pdu *);
+	void		(*fail)(const struct connection *, const char *);
+};
+
+#define	KEYS_MAX		1024
+
+struct keys {
+	char		*keys_names[KEYS_MAX];
+	char		*keys_values[KEYS_MAX];
+	char		*keys_data;
+	size_t		keys_data_len;
+};
+
+#define	CHAP_CHALLENGE_LEN	1024
+#define	CHAP_DIGEST_LEN		16 /* Equal to MD5 digest size. */
+
+struct chap {
+	unsigned char	chap_id;
+	char		chap_challenge[CHAP_CHALLENGE_LEN];
+	char		chap_response[CHAP_DIGEST_LEN];
+};
+
+struct rchap {
+	char		*rchap_secret;
+	unsigned char	rchap_id;
+	void		*rchap_challenge;
+	size_t		rchap_challenge_len;
+};
+
+struct chap		*chap_new(void);
+char			*chap_get_id(const struct chap *chap);
+char			*chap_get_challenge(const struct chap *chap);
+int			chap_receive(struct chap *chap, const char *response);
+int			chap_authenticate(struct chap *chap,
+			    const char *secret);
+void			chap_delete(struct chap *chap);
+
+struct rchap		*rchap_new(const char *secret);
+int			rchap_receive(struct rchap *rchap,
+			    const char *id, const char *challenge);
+char			*rchap_get_response(struct rchap *rchap);
+void			rchap_delete(struct rchap *rchap);
+
+struct keys		*keys_new(void);
+void			keys_delete(struct keys *key);
+void			keys_load(struct keys *keys, const struct pdu *pdu);
+void			keys_save(struct keys *keys, struct pdu *pdu);
+const char		*keys_find(struct keys *keys, const char *name);
+void			keys_add(struct keys *keys,
+			    const char *name, const char *value);
+void			keys_add_int(struct keys *keys,
+			    const char *name, int value);
+
+struct pdu		*pdu_new(struct connection *ic);
+struct pdu		*pdu_new_response(struct pdu *request);
+int			pdu_ahs_length(const struct pdu *pdu);
+int			pdu_data_segment_length(const struct pdu *pdu);
+void			pdu_set_data_segment_length(struct pdu *pdu,
+			    uint32_t len);
+void			pdu_receive(struct pdu *request);
+void			pdu_send(struct pdu *response);
+void			pdu_delete(struct pdu *ip);
+
+void			connection_init(struct connection *conn,
+			    const struct connection_ops *ops, bool use_proxy);
+
+void			log_init(int level);
+void			log_set_peer_name(const char *name);
+void			log_set_peer_addr(const char *addr);
+void			log_err(int, const char *, ...)
+			    __dead2 __printflike(2, 3);
+void			log_errx(int, const char *, ...)
+			    __dead2 __printflike(2, 3);
+void			log_warn(const char *, ...) __printflike(1, 2);
+void			log_warnx(const char *, ...) __printflike(1, 2);
+void			log_debugx(const char *, ...) __printflike(1, 2);
+
+char			*checked_strdup(const char *);
+
+#endif /* !__LIBISCSIUTIL_H__ */
diff --git a/usr.sbin/ctld/log.c b/lib/libiscsiutil/log.c
similarity index 98%
rename from usr.sbin/ctld/log.c
rename to lib/libiscsiutil/log.c
index 94e014293a61..7d7a13bb11f2 100644
--- a/usr.sbin/ctld/log.c
+++ b/lib/libiscsiutil/log.c
@@ -26,12 +26,8 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -40,7 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <syslog.h>
 #include <vis.h>
 
-#include "ctld.h"
+#include "libiscsiutil.h"
 
 static int log_level = 0;
 static char *peer_name = NULL;
diff --git a/usr.sbin/ctld/pdu.c b/lib/libiscsiutil/pdu.c
similarity index 77%
rename from usr.sbin/ctld/pdu.c
rename to lib/libiscsiutil/pdu.c
index 04691556b997..ed5ee5b71766 100644
--- a/usr.sbin/ctld/pdu.c
+++ b/lib/libiscsiutil/pdu.c
@@ -35,26 +35,22 @@ __FBSDID("$FreeBSD$");
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <assert.h>
+#include <errno.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
-#include "ctld.h"
-#include "iscsi_proto.h"
+#include <iscsi_proto.h>
+#include "libiscsiutil.h"
 
-#ifdef ICL_KERNEL_PROXY
-#include <sys/ioctl.h>
-#endif
-
-extern bool proxy_mode;
-
-static int
+int
 pdu_ahs_length(const struct pdu *pdu)
 {
 
 	return (pdu->pdu_bhs->bhs_total_ahs_len * 4);
 }
 
-static int
+int
 pdu_data_segment_length(const struct pdu *pdu)
 {
 	uint32_t len = 0;
@@ -68,7 +64,7 @@ pdu_data_segment_length(const struct pdu *pdu)
 	return (len);
 }
 
-static void
+void
 pdu_set_data_segment_length(struct pdu *pdu, uint32_t len)
 {
 
@@ -102,40 +98,6 @@ pdu_new_response(struct pdu *request)
 	return (pdu_new(request->pdu_connection));
 }
 
-#ifdef ICL_KERNEL_PROXY
-
-static void
-pdu_receive_proxy(struct pdu *pdu)
-{
-	struct connection *conn;
-	size_t len;
-
-	assert(proxy_mode);
-	conn = pdu->pdu_connection;
-
-	kernel_receive(pdu);
-
-	len = pdu_ahs_length(pdu);
-	if (len > 0)
-		log_errx(1, "protocol error: non-empty AHS");
-
-	len = pdu_data_segment_length(pdu);
-	assert(len <= (size_t)conn->conn_max_recv_data_segment_length);
-	pdu->pdu_data_len = len;
-}
-
-static void
-pdu_send_proxy(struct pdu *pdu)
-{
-
-	assert(proxy_mode);
-
-	pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
-	kernel_send(pdu);
-}
-
-#endif /* ICL_KERNEL_PROXY */
-
 static size_t
 pdu_padding(const struct pdu *pdu)
 {
@@ -147,18 +109,24 @@ pdu_padding(const struct pdu *pdu)
 }
 
 static void
-pdu_read(int fd, char *data, size_t len)
+pdu_read(const struct connection *conn, char *data, size_t len)
 {
 	ssize_t ret;
 
 	while (len > 0) {
-		ret = read(fd, data, len);
+		ret = read(conn->conn_socket, data, len);
 		if (ret < 0) {
-			if (timed_out())
+			if (conn->conn_ops->timed_out()) {
+				conn->conn_ops->fail(conn,
+				    "Login Phase timeout");
 				log_errx(1, "exiting due to timeout");
+			}
+			conn->conn_ops->fail(conn, strerror(errno));
 			log_err(1, "read");
-		} else if (ret == 0)
+		} else if (ret == 0) {
+			conn->conn_ops->fail(conn, "connection lost");
 			log_errx(1, "read: connection lost");
+		}
 		len -= ret;
 		data += ret;
 	}
@@ -171,16 +139,11 @@ pdu_receive(struct pdu *pdu)
 	size_t len, padding;
 	char dummy[4];
 
-#ifdef ICL_KERNEL_PROXY
-	if (proxy_mode)
-		return (pdu_receive_proxy(pdu));
-#endif
-
-	assert(proxy_mode == false);
 	conn = pdu->pdu_connection;
+	if (conn->conn_use_proxy)
+		return (conn->conn_ops->pdu_receive_proxy(pdu));
 
-	pdu_read(conn->conn_socket, (char *)pdu->pdu_bhs,
-	    sizeof(*pdu->pdu_bhs));
+	pdu_read(conn, (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs));
 
 	len = pdu_ahs_length(pdu);
 	if (len > 0)
@@ -199,13 +162,12 @@ pdu_receive(struct pdu *pdu)
 		if (pdu->pdu_data == NULL)
 			log_err(1, "malloc");
 
-		pdu_read(conn->conn_socket, (char *)pdu->pdu_data,
-		    pdu->pdu_data_len);
+		pdu_read(conn, (char *)pdu->pdu_data, pdu->pdu_data_len);
 
 		padding = pdu_padding(pdu);
 		if (padding != 0) {
 			assert(padding < sizeof(dummy));
-			pdu_read(conn->conn_socket, (char *)dummy, padding);
+			pdu_read(conn, (char *)dummy, padding);
 		}
 	}
 }
@@ -213,18 +175,16 @@ pdu_receive(struct pdu *pdu)
 void
 pdu_send(struct pdu *pdu)
 {
+	struct connection *conn;
 	ssize_t ret, total_len;
 	size_t padding;
 	uint32_t zero = 0;
 	struct iovec iov[3];
 	int iovcnt;
 
-#ifdef ICL_KERNEL_PROXY
-	if (proxy_mode)
-		return (pdu_send_proxy(pdu));
-#endif
-
-	assert(proxy_mode == false);
+	conn = pdu->pdu_connection;
+	if (conn->conn_use_proxy)
+		return (conn->conn_ops->pdu_send_proxy(pdu));
 
 	pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
 	iov[0].iov_base = pdu->pdu_bhs;
@@ -248,9 +208,9 @@ pdu_send(struct pdu *pdu)
 		}
 	}
 
-	ret = writev(pdu->pdu_connection->conn_socket, iov, iovcnt);
+	ret = writev(conn->conn_socket, iov, iovcnt);
 	if (ret < 0) {
-		if (timed_out())
+		if (conn->conn_ops->timed_out())
 			log_errx(1, "exiting due to timeout");
 		log_err(1, "writev");
 	}
diff --git a/lib/libiscsiutil/utils.c b/lib/libiscsiutil/utils.c
new file mode 100644
index 000000000000..1e04490c477c
--- /dev/null
+++ b/lib/libiscsiutil/utils.c
@@ -0,0 +1,44 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2012 The FreeBSD Foundation
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "libiscsiutil.h"
+
+char *
+checked_strdup(const char *s)
+{
+	char *c;
+
+	c = strdup(s);
+	if (c == NULL)
+		log_err(1, "strdup");
+	return (c);
+}
diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile
index 90aaea3cb709..783b5bbd7721 100644
--- a/rescue/rescue/Makefile
+++ b/rescue/rescue/Makefile
@@ -236,6 +236,9 @@ CRUNCH_LIBS+= -lm
 .if ${MK_ISCSI} != "no"
 CRUNCH_PROGS_usr.bin+=	iscsictl
 CRUNCH_PROGS_usr.sbin+=	iscsid
+
+CRUNCH_LIBS+=		${OBJTOP}/lib/libiscsiutil/libiscsiutil.a
+CRUNCH_BUILDOPTS+=	CRUNCH_CFLAGS+=-I${OBJTOP}/lib/libiscsiutil
 .endif
 
 .include <bsd.crunchgen.mk>
diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk
index f71664bf5858..45710b203ddc 100644
--- a/share/mk/bsd.libnames.mk
+++ b/share/mk/bsd.libnames.mk
@@ -83,6 +83,7 @@ LIBIBVERBS?=	${LIBDESTDIR}${LIBDIR_BASE}/libibverbs.a
 LIBICP?=	${LIBDESTDIR}${LIBDIR_BASE}/libicp.a
 LIBIPSEC?=	${LIBDESTDIR}${LIBDIR_BASE}/libipsec.a
 LIBIPT?=	${LIBDESTDIR}${LIBDIR_BASE}/libipt.a
+LIBISCSIUTIL?=	${LIBDESTDIR}${LIBDIR_BASE}/libiscsiutil.a
 LIBJAIL?=	${LIBDESTDIR}${LIBDIR_BASE}/libjail.a
 LIBKADM5CLNT?=	${LIBDESTDIR}${LIBDIR_BASE}/libkadm5clnt.a
 LIBKADM5SRV?=	${LIBDESTDIR}${LIBDIR_BASE}/libkadm5srv.a
diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk
index 385e8616a82d..cf6c41887791 100644
--- a/share/mk/src.libnames.mk
+++ b/share/mk/src.libnames.mk
@@ -44,6 +44,7 @@ _INTERNALLIBS=	\
 		fifolog \
 		ifconfig \
 		ipf \
+		iscsiutil \
 		lpr \
 		lua \
 		lutok \
@@ -556,6 +557,9 @@ LIBIFCONFIG?=	${LIBIFCONFIGDIR}/libifconfig${PIE_SUFFIX}.a
 LIBIPFDIR=	${_LIB_OBJTOP}/sbin/ipf/libipf
 LIBIPF?=	${LIBIPFDIR}/libipf${PIE_SUFFIX}.a
 
+LIBISCSIUTILDIR=	${_LIB_OBJTOP}/lib/libiscsiutil
+LIBISCSIUTIL?=	${LIBISCSIUTILDIR}/libiscsiutil${PIE_SUFFIX}.a
+
 LIBTELNETDIR=	${_LIB_OBJTOP}/lib/libtelnet
 LIBTELNET?=	${LIBTELNETDIR}/libtelnet${PIE_SUFFIX}.a
 
diff --git a/usr.sbin/ctld/Makefile b/usr.sbin/ctld/Makefile
index ec207f024ab1..5f80ba026204 100644
--- a/usr.sbin/ctld/Makefile
+++ b/usr.sbin/ctld/Makefile
@@ -7,16 +7,17 @@ CFLAGS+=-I${SRCTOP}/contrib/libucl/include
 
 PACKAGE=	iscsi
 PROG=		ctld
-SRCS=		chap.c ctld.c discovery.c isns.c kernel.c keys.c log.c
-SRCS+=		login.c parse.y pdu.c token.l y.tab.h uclparse.c
+SRCS=		ctld.c discovery.c isns.c kernel.c
+SRCS+=		login.c parse.y token.l y.tab.h uclparse.c
 CFLAGS+=	-I${.CURDIR}
 CFLAGS+=	-I${SRCTOP}/sys
 CFLAGS+=	-I${SRCTOP}/sys/cam/ctl
 CFLAGS+=	-I${SRCTOP}/sys/dev/iscsi
+CFLAGS+=	-I${SRCTOP}/lib/libiscsiutil
 #CFLAGS+=	-DICL_KERNEL_PROXY
 MAN=		ctld.8 ctl.conf.5
 
-LIBADD=		bsdxml md sbuf util ucl m nv
+LIBADD=		bsdxml iscsiutil md sbuf util ucl m nv
 
 YFLAGS+=	-v
 CLEANFILES=	y.tab.c y.tab.h y.output
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index c37181ff00d0..3f4bca632512 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -54,6 +54,13 @@ __FBSDID("$FreeBSD$");
 #include "ctld.h"
 #include "isns.h"
 
+static bool	timed_out(void);
+#ifdef ICL_KERNEL_PROXY
+static void	pdu_receive_proxy(struct pdu *pdu);
+static void	pdu_send_proxy(struct pdu *pdu);
+#endif /* ICL_KERNEL_PROXY */
+static void	pdu_fail(const struct connection *conn, const char *reason);
+
 bool proxy_mode = false;
 
 static volatile bool sighup_received = false;
@@ -63,6 +70,15 @@ static volatile bool sigalrm_received = false;
 static int nchildren = 0;
 static uint16_t last_portal_group_tag = 0xff;
 
+static struct connection_ops conn_ops = {
+	.timed_out = timed_out,
+#ifdef ICL_KERNEL_PROXY
+	.pdu_receive_proxy = pdu_receive_proxy,
+	.pdu_send_proxy = pdu_send_proxy,
+#endif
+	.fail = pdu_fail,
+};
+
 static void
 usage(void)
 {
@@ -72,17 +88,6 @@ usage(void)
 	exit(1);
 }
 
-char *
-checked_strdup(const char *s)
-{
-	char *c;
-
-	c = strdup(s);
-	if (c == NULL)
-		log_err(1, "strdup");
-	return (c);
-}
-
 struct conf *
 conf_new(void)
 {
@@ -1632,29 +1637,60 @@ option_set(struct option *o, const char *value)
 	o->o_value = checked_strdup(value);
 }
 
-static struct connection *
+#ifdef ICL_KERNEL_PROXY
+
+static void
+pdu_receive_proxy(struct pdu *pdu)
+{
+	struct connection *conn;
+	size_t len;
+
+	assert(proxy_mode);
+	conn = pdu->pdu_connection;
+
+	kernel_receive(pdu);
+
+	len = pdu_ahs_length(pdu);
+	if (len > 0)
+		log_errx(1, "protocol error: non-empty AHS");
+
+	len = pdu_data_segment_length(pdu);
+	assert(len <= (size_t)conn->conn_max_recv_data_segment_length);
+	pdu->pdu_data_len = len;
+}
+
+static void
+pdu_send_proxy(struct pdu *pdu)
+{
+
+	assert(proxy_mode);
+
+	pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
+	kernel_send(pdu);
+}
+
+#endif /* ICL_KERNEL_PROXY */
+
+static void
+pdu_fail(const struct connection *conn __unused, const char *reason __unused)
+{
+}
+
+static struct ctld_connection *
 connection_new(struct portal *portal, int fd, const char *host,
     const struct sockaddr *client_sa)
 {
-	struct connection *conn;
+	struct ctld_connection *conn;
 
 	conn = calloc(1, sizeof(*conn));
 	if (conn == NULL)
 		log_err(1, "calloc");
+	connection_init(&conn->conn, &conn_ops, proxy_mode);
+	conn->conn.conn_socket = fd;
 	conn->conn_portal = portal;
-	conn->conn_socket = fd;
 	conn->conn_initiator_addr = checked_strdup(host);
 	memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len);
 
-	/*
-	 * Default values, from RFC 3720, section 12.
-	 */
-	conn->conn_max_recv_data_segment_length = 8192;
-	conn->conn_max_send_data_segment_length = 8192;
-	conn->conn_max_burst_length = 262144;
-	conn->conn_first_burst_length = 65536;
-	conn->conn_immediate_data = true;
-
 	return (conn);
 }
 
@@ -2296,7 +2332,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 	return (cumulated_error);
 }
 
-bool
+static bool
 timed_out(void)
 {
 
@@ -2407,7 +2443,7 @@ static void
 handle_connection(struct portal *portal, int fd,
     const struct sockaddr *client_sa, bool dont_fork)
 {
-	struct connection *conn;
+	struct ctld_connection *conn;
 	int error;
 	pid_t pid;
 	char host[NI_MAXHOST + 1];
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index 4ff8f0e638ac..293f5378592f 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -39,6 +39,7 @@
 #endif
 #include <sys/socket.h>
 #include <stdbool.h>
+#include <libiscsiutil.h>
 #include <libutil.h>
 
 #define	DEFAULT_CONFIG_PATH		"/etc/ctl.conf"
@@ -229,83 +230,25 @@ struct conf {
 #define	CONN_SESSION_TYPE_DISCOVERY	1
 #define	CONN_SESSION_TYPE_NORMAL	2
 
-#define	CONN_DIGEST_NONE		0
-#define	CONN_DIGEST_CRC32C		1
-
-struct connection {
+struct ctld_connection {
+	struct connection	conn;
 	struct portal		*conn_portal;
 	struct port		*conn_port;
 	struct target		*conn_target;
-	int			conn_socket;
 	int			conn_session_type;
 	char			*conn_initiator_name;
 	char			*conn_initiator_addr;
 	char			*conn_initiator_alias;
 	uint8_t			conn_initiator_isid[6];
 	struct sockaddr_storage	conn_initiator_sa;
-	uint32_t		conn_cmdsn;
-	uint32_t		conn_statsn;
 	int			conn_max_recv_data_segment_limit;
 	int			conn_max_send_data_segment_limit;
 	int			conn_max_burst_limit;
 	int			conn_first_burst_limit;
-	int			conn_max_recv_data_segment_length;
-	int			conn_max_send_data_segment_length;
-	int			conn_max_burst_length;
-	int			conn_first_burst_length;
-	int			conn_immediate_data;
-	int			conn_header_digest;
-	int			conn_data_digest;
 	const char		*conn_user;
 	struct chap		*conn_chap;
 };
 
-struct pdu {
-	struct connection	*pdu_connection;
-	struct iscsi_bhs	*pdu_bhs;
-	char			*pdu_data;
-	size_t			pdu_data_len;
-};
-
-#define	KEYS_MAX	1024
-
-struct keys {
-	char		*keys_names[KEYS_MAX];
-	char		*keys_values[KEYS_MAX];
-	char		*keys_data;
-	size_t		keys_data_len;
-};
-
-#define	CHAP_CHALLENGE_LEN	1024
-#define	CHAP_DIGEST_LEN		16 /* Equal to MD5 digest size. */
-
-struct chap {
-	unsigned char	chap_id;
-	char		chap_challenge[CHAP_CHALLENGE_LEN];
-	char		chap_response[CHAP_DIGEST_LEN];
-};
-
-struct rchap {
-	char		*rchap_secret;
-	unsigned char	rchap_id;
-	void		*rchap_challenge;
-	size_t		rchap_challenge_len;
-};
-
-struct chap		*chap_new(void);
-char			*chap_get_id(const struct chap *chap);
-char			*chap_get_challenge(const struct chap *chap);
-int			chap_receive(struct chap *chap, const char *response);
-int			chap_authenticate(struct chap *chap,
-			    const char *secret);
-void			chap_delete(struct chap *chap);
-
-struct rchap		*rchap_new(const char *secret);
-int			rchap_receive(struct rchap *rchap,
-			    const char *id, const char *challenge);
-char			*rchap_get_response(struct rchap *rchap);
-void			rchap_delete(struct rchap *rchap);
-
 int			parse_conf(struct conf *conf, const char *path);
 int			uclparse_conf(struct conf *conf, const char *path);
 
@@ -412,7 +355,7 @@ void			kernel_init(void);
 int			kernel_lun_add(struct lun *lun);
 int			kernel_lun_modify(struct lun *lun);
 int			kernel_lun_remove(struct lun *lun);
-void			kernel_handoff(struct connection *conn);
+void			kernel_handoff(struct ctld_connection *conn);
 void			kernel_limits(const char *offload,
 			    int *max_recv_data_segment_length,
 			    int *max_send_data_segment_length,
@@ -433,40 +376,11 @@ void			kernel_send(struct pdu *pdu);
 void			kernel_receive(struct pdu *pdu);
 #endif
 
-struct keys		*keys_new(void);
-void			keys_delete(struct keys *keys);
-void			keys_load(struct keys *keys, const struct pdu *pdu);
-void			keys_save(struct keys *keys, struct pdu *pdu);
-const char		*keys_find(struct keys *keys, const char *name);
-void			keys_add(struct keys *keys,
-			    const char *name, const char *value);
-void			keys_add_int(struct keys *keys,
-			    const char *name, int value);
-
-struct pdu		*pdu_new(struct connection *conn);
-struct pdu		*pdu_new_response(struct pdu *request);
-void			pdu_delete(struct pdu *pdu);
-void			pdu_receive(struct pdu *request);
-void			pdu_send(struct pdu *response);
-
-void			login(struct connection *conn);
-
-void			discovery(struct connection *conn);
-
-void			log_init(int level);
-void			log_set_peer_name(const char *name);
-void			log_set_peer_addr(const char *addr);
-void			log_err(int, const char *, ...)
-			    __dead2 __printflike(2, 3);
-void			log_errx(int, const char *, ...)
-			    __dead2 __printflike(2, 3);
-void			log_warn(const char *, ...) __printflike(1, 2);
-void			log_warnx(const char *, ...) __printflike(1, 2);
-void			log_debugx(const char *, ...) __printflike(1, 2);
-
-char			*checked_strdup(const char *);
+void			login(struct ctld_connection *conn);
+
+void			discovery(struct ctld_connection *conn);
+
 bool			valid_iscsi_name(const char *name);
 void			set_timeout(int timeout, int fatal);
-bool			timed_out(void);
 
 #endif /* !CTLD_H */
diff --git a/usr.sbin/ctld/discovery.c b/usr.sbin/ctld/discovery.c
*** 2321 LINES SKIPPED ***