diff --git a/lib/Makefile b/lib/Makefile --- a/lib/Makefile +++ b/lib/Makefile @@ -63,6 +63,7 @@ libgeom \ libifconfig \ libipsec \ + libiscsiutil \ libjail \ libkiconv \ libkvm \ diff --git a/lib/libiscsiutil/Makefile b/lib/libiscsiutil/Makefile new file mode 100644 --- /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 diff --git a/usr.sbin/ctld/chap.c b/lib/libiscsiutil/chap.c rename from usr.sbin/ctld/chap.c rename to lib/libiscsiutil/chap.c --- 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 -__FBSDID("$FreeBSD$"); - #include #include #include @@ -39,7 +35,7 @@ #include #include -#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 --- /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 + +#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 rename from usr.sbin/ctld/keys.c rename to lib/libiscsiutil/keys.c --- 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 -__FBSDID("$FreeBSD$"); - #include #include #include #include -#include "ctld.h" +#include "libiscsiutil.h" struct keys * keys_new(void) diff --git a/usr.sbin/iscsid/iscsid.h b/lib/libiscsiutil/libiscsiutil.h copy from usr.sbin/iscsid/iscsid.h copy to lib/libiscsiutil/libiscsiutil.h --- a/usr.sbin/iscsid/iscsid.h +++ b/lib/libiscsiutil/libiscsiutil.h @@ -26,62 +26,57 @@ * 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. - * - * $FreeBSD$ */ -#ifndef ISCSID_H -#define ISCSID_H +#ifndef __LIBISCSIUTIL_H__ +#define __LIBISCSIUTIL_H__ +#include #include -#include - -#include -#define DEFAULT_PIDFILE "/var/run/iscsid.pid" +struct connection_ops; #define CONN_DIGEST_NONE 0 #define CONN_DIGEST_CRC32C 1 -#define CONN_MUTUAL_CHALLENGE_LEN 1024 -#define SOCKBUF_SIZE 1048576 - struct connection { - int conn_iscsi_fd; - int conn_socket; - unsigned int conn_session_id; - struct iscsi_session_conf conn_conf; - struct iscsi_session_limits conn_limits; - char conn_target_alias[ISCSI_ADDR_LEN]; - uint8_t conn_isid[6]; - uint16_t conn_tsih; - uint32_t conn_statsn; - int conn_protocol_level; - int conn_header_digest; - int conn_data_digest; - bool conn_initial_r2t; - bool conn_immediate_data; - 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 chap *conn_mutual_chap; + 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 *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; + char *keys_names[KEYS_MAX]; + char *keys_values[KEYS_MAX]; + char *keys_data; + size_t keys_data_len; }; #define CHAP_CHALLENGE_LEN 1024 @@ -126,13 +121,16 @@ 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 login(struct connection *ic); - -void discovery(struct connection *ic); +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); @@ -146,7 +144,5 @@ void log_debugx(const char *, ...) __printflike(1, 2); char *checked_strdup(const char *); -bool timed_out(void); -void fail(const struct connection *, const char *); -#endif /* !ISCSID_H */ +#endif /* !__LIBISCSIUTIL_H__ */ diff --git a/usr.sbin/ctld/log.c b/lib/libiscsiutil/log.c rename from usr.sbin/ctld/log.c rename to lib/libiscsiutil/log.c --- 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 -__FBSDID("$FreeBSD$"); - #include #include #include @@ -40,7 +36,7 @@ #include #include -#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 rename from usr.sbin/ctld/pdu.c rename to lib/libiscsiutil/pdu.c --- a/usr.sbin/ctld/pdu.c +++ b/lib/libiscsiutil/pdu.c @@ -35,26 +35,22 @@ #include #include #include +#include #include +#include #include -#include "ctld.h" -#include "iscsi_proto.h" +#include +#include "libiscsiutil.h" -#ifdef ICL_KERNEL_PROXY -#include -#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 @@ return (len); } -static void +void pdu_set_data_segment_length(struct pdu *pdu, uint32_t len) { @@ -102,40 +98,6 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ } } - 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 --- /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 + +#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 --- a/rescue/rescue/Makefile +++ b/rescue/rescue/Makefile @@ -236,6 +236,9 @@ .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 diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk --- a/share/mk/bsd.libnames.mk +++ b/share/mk/bsd.libnames.mk @@ -83,6 +83,7 @@ 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 --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -44,6 +44,7 @@ fifolog \ ifconfig \ ipf \ + iscsiutil \ lpr \ lua \ lutok \ @@ -556,6 +557,9 @@ 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 --- a/usr.sbin/ctld/Makefile +++ b/usr.sbin/ctld/Makefile @@ -7,16 +7,17 @@ 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.h b/usr.sbin/ctld/ctld.h --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -39,6 +39,7 @@ #endif #include #include +#include #include #define DEFAULT_CONFIG_PATH "/etc/ctl.conf" @@ -229,83 +230,25 @@ #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 @@ 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_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/ctld.c b/usr.sbin/ctld/ctld.c --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -54,6 +54,13 @@ #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 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 @@ 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 @@ 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 @@ return (cumulated_error); } -bool +static bool timed_out(void) { @@ -2407,7 +2443,7 @@ 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/discovery.c b/usr.sbin/ctld/discovery.c --- a/usr.sbin/ctld/discovery.c +++ b/usr.sbin/ctld/discovery.c @@ -211,7 +211,7 @@ } static bool -discovery_target_filtered_out(const struct connection *conn, +discovery_target_filtered_out(const struct ctld_connection *conn, const struct port *port) { const struct auth_group *ag; @@ -274,7 +274,7 @@ } void -discovery(struct connection *conn) +discovery(struct ctld_connection *conn) { struct pdu *request, *response; struct keys *request_keys, *response_keys; @@ -285,7 +285,7 @@ pg = conn->conn_portal->p_portal_group; log_debugx("beginning discovery session; waiting for Text PDU"); - request = text_receive(conn); + request = text_receive(&conn->conn); request_keys = keys_new(); keys_load(request_keys, request); @@ -326,7 +326,7 @@ keys_delete(request_keys); log_debugx("done sending targets; waiting for Logout PDU"); - request = logout_receive(conn); + request = logout_receive(&conn->conn); response = logout_new_response(request); pdu_send(response); diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c --- a/usr.sbin/ctld/kernel.c +++ b/usr.sbin/ctld/kernel.c @@ -893,7 +893,7 @@ } void -kernel_handoff(struct connection *conn) +kernel_handoff(struct ctld_connection *conn) { struct ctl_iscsi req; @@ -919,27 +919,28 @@ } #ifdef ICL_KERNEL_PROXY if (proxy_mode) - req.data.handoff.connection_id = conn->conn_socket; + req.data.handoff.connection_id = conn->conn.conn_socket; else - req.data.handoff.socket = conn->conn_socket; + req.data.handoff.socket = conn->conn.conn_socket; #else - req.data.handoff.socket = conn->conn_socket; + req.data.handoff.socket = conn->conn.conn_socket; #endif req.data.handoff.portal_group_tag = conn->conn_portal->p_portal_group->pg_tag; - if (conn->conn_header_digest == CONN_DIGEST_CRC32C) + if (conn->conn.conn_header_digest == CONN_DIGEST_CRC32C) req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; - if (conn->conn_data_digest == CONN_DIGEST_CRC32C) + if (conn->conn.conn_data_digest == CONN_DIGEST_CRC32C) req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; - req.data.handoff.cmdsn = conn->conn_cmdsn; - req.data.handoff.statsn = conn->conn_statsn; + req.data.handoff.cmdsn = conn->conn.conn_cmdsn; + req.data.handoff.statsn = conn->conn.conn_statsn; req.data.handoff.max_recv_data_segment_length = - conn->conn_max_recv_data_segment_length; + conn->conn.conn_max_recv_data_segment_length; req.data.handoff.max_send_data_segment_length = - conn->conn_max_send_data_segment_length; - req.data.handoff.max_burst_length = conn->conn_max_burst_length; - req.data.handoff.first_burst_length = conn->conn_first_burst_length; - req.data.handoff.immediate_data = conn->conn_immediate_data; + conn->conn.conn_max_send_data_segment_length; + req.data.handoff.max_burst_length = conn->conn.conn_max_burst_length; + req.data.handoff.first_burst_length = + conn->conn.conn_first_burst_length; + req.data.handoff.immediate_data = conn->conn.conn_immediate_data; if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { log_err(1, "error issuing CTL_ISCSI ioctl; " diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c --- a/usr.sbin/ctld/login.c +++ b/usr.sbin/ctld/login.c @@ -401,7 +401,7 @@ } static void -login_chap(struct connection *conn, struct auth_group *ag) +login_chap(struct ctld_connection *conn, struct auth_group *ag) { const struct auth *auth; struct chap *chap; @@ -411,7 +411,7 @@ * Receive CHAP_A PDU. */ log_debugx("beginning CHAP authentication; waiting for CHAP_A"); - request = login_receive_chap_a(conn); + request = login_receive_chap_a(&conn->conn); /* * Generate the challenge. @@ -430,7 +430,7 @@ * Receive CHAP_N/CHAP_R PDU and authenticate. */ log_debugx("waiting for CHAP_N/CHAP_R"); - request = login_receive_chap_r(conn, ag, chap, &auth); + request = login_receive_chap_r(&conn->conn, ag, chap, &auth); /* * Yay, authentication succeeded! @@ -453,9 +453,9 @@ { int which; size_t tmp; - struct connection *conn; + struct ctld_connection *conn; - conn = request->pdu_connection; + conn = (struct ctld_connection *)request->pdu_connection; if (strcmp(name, "InitiatorName") == 0) { if (!skipped_security) @@ -487,7 +487,7 @@ case 1: log_debugx("initiator prefers CRC32C " "for header digest; we'll use it"); - conn->conn_header_digest = CONN_DIGEST_CRC32C; + conn->conn.conn_header_digest = CONN_DIGEST_CRC32C; keys_add(response_keys, name, "CRC32C"); break; case 2: @@ -513,7 +513,7 @@ case 1: log_debugx("initiator prefers CRC32C " "for data digest; we'll use it"); - conn->conn_data_digest = CONN_DIGEST_CRC32C; + conn->conn.conn_data_digest = CONN_DIGEST_CRC32C; keys_add(response_keys, name, "CRC32C"); break; case 2: @@ -537,10 +537,10 @@ keys_add(response_keys, name, "Irrelevant"); } else { if (strcmp(value, "Yes") == 0) { - conn->conn_immediate_data = true; + conn->conn.conn_immediate_data = true; keys_add(response_keys, name, "Yes"); } else { - conn->conn_immediate_data = false; + conn->conn.conn_immediate_data = false; keys_add(response_keys, name, "No"); } } @@ -564,7 +564,7 @@ conn->conn_max_send_data_segment_limit); tmp = conn->conn_max_send_data_segment_limit; } - conn->conn_max_send_data_segment_length = tmp; + conn->conn.conn_max_send_data_segment_length = tmp; } else if (strcmp(name, "MaxBurstLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) { @@ -576,7 +576,7 @@ tmp, conn->conn_max_burst_limit); tmp = conn->conn_max_burst_limit; } - conn->conn_max_burst_length = tmp; + conn->conn.conn_max_burst_length = tmp; keys_add_int(response_keys, name, tmp); } else if (strcmp(name, "FirstBurstLength") == 0) { tmp = strtoul(value, NULL, 10); @@ -589,7 +589,7 @@ tmp, conn->conn_first_burst_limit); tmp = conn->conn_first_burst_limit; } - conn->conn_first_burst_length = tmp; + conn->conn.conn_first_burst_length = tmp; keys_add_int(response_keys, name, tmp); } else if (strcmp(name, "DefaultTime2Wait") == 0) { keys_add(response_keys, name, value); @@ -642,7 +642,7 @@ } static bool -login_portal_redirect(struct connection *conn, struct pdu *request) +login_portal_redirect(struct ctld_connection *conn, struct pdu *request) { const struct portal_group *pg; @@ -658,7 +658,7 @@ } static bool -login_target_redirect(struct connection *conn, struct pdu *request) +login_target_redirect(struct ctld_connection *conn, struct pdu *request) { const char *target_address; @@ -679,7 +679,7 @@ } static void -login_negotiate(struct connection *conn, struct pdu *request) +login_negotiate(struct ctld_connection *conn, struct pdu *request) { struct pdu *response; struct iscsi_bhs_login_response *bhslr2; @@ -721,8 +721,8 @@ * sender and receiver operation, and we must obey defaults. */ if (conn->conn_max_send_data_segment_limit < - conn->conn_max_send_data_segment_length) { - conn->conn_max_send_data_segment_length = + conn->conn.conn_max_send_data_segment_length) { + conn->conn.conn_max_send_data_segment_length = conn->conn_max_send_data_segment_limit; } } else { @@ -735,7 +735,7 @@ if (request == NULL) { log_debugx("beginning operational parameter negotiation; " "waiting for Login PDU"); - request = login_receive(conn, false); + request = login_receive(&conn->conn, false); skipped_security = false; } else skipped_security = true; @@ -788,14 +788,15 @@ * with illegal values here. */ if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL && - conn->conn_first_burst_length > conn->conn_max_burst_length) { + conn->conn.conn_first_burst_length > + conn->conn.conn_max_burst_length) { log_errx(1, "initiator sent FirstBurstLength > MaxBurstLength"); } - conn->conn_max_recv_data_segment_length = + conn->conn.conn_max_recv_data_segment_length = conn->conn_max_recv_data_segment_limit; keys_add_int(response_keys, "MaxRecvDataSegmentLength", - conn->conn_max_recv_data_segment_length); + conn->conn.conn_max_recv_data_segment_length); log_debugx("operational parameter negotiation done; " "transitioning to Full Feature Phase"); @@ -809,13 +810,13 @@ } static void -login_wait_transition(struct connection *conn) +login_wait_transition(struct ctld_connection *conn) { struct pdu *request, *response; struct iscsi_bhs_login_request *bhslr; log_debugx("waiting for state transition request"); - request = login_receive(conn, false); + request = login_receive(&conn->conn, false); bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs; if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) == 0) { login_send_error(request, 0x02, 0x00); @@ -833,7 +834,7 @@ } void -login(struct connection *conn) +login(struct ctld_connection *conn) { struct pdu *request, *response; struct iscsi_bhs_login_request *bhslr; @@ -850,7 +851,7 @@ * is required, or call appropriate authentication code. */ log_debugx("beginning Login Phase; waiting for Login PDU"); - request = login_receive(conn, true); + request = login_receive(&conn->conn, true); bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs; if (bhslr->bhslr_tsih != 0) { login_send_error(request, 0x02, 0x0a); diff --git a/usr.sbin/iscsid/Makefile b/usr.sbin/iscsid/Makefile --- a/usr.sbin/iscsid/Makefile +++ b/usr.sbin/iscsid/Makefile @@ -2,13 +2,14 @@ PACKAGE= iscsi PROG= iscsid -SRCS= chap.c discovery.c iscsid.c keys.c log.c login.c pdu.c +SRCS= discovery.c iscsid.c login.c CFLAGS+= -I${.CURDIR} CFLAGS+= -I${SRCTOP}/sys/cam CFLAGS+= -I${SRCTOP}/sys/dev/iscsi +CFLAGS+= -I${SRCTOP}/lib/libiscsiutil CFLAGS+= -DICL_KERNEL_PROXY MAN= iscsid.8 -LIBADD= md util +LIBADD= iscsiutil md util .include diff --git a/usr.sbin/iscsid/chap.c b/usr.sbin/iscsid/chap.c deleted file mode 100644 --- a/usr.sbin/iscsid/chap.c +++ /dev/null @@ -1,423 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2014 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include - -#include "iscsid.h" - -static void -chap_compute_md5(const char id, const char *secret, - const void *challenge, size_t challenge_len, void *response, - size_t response_len) -{ - MD5_CTX ctx; - - assert(response_len == CHAP_DIGEST_LEN); - - MD5Init(&ctx); - MD5Update(&ctx, &id, sizeof(id)); - MD5Update(&ctx, secret, strlen(secret)); - MD5Update(&ctx, challenge, challenge_len); - MD5Final(response, &ctx); -} - -static int -chap_hex2int(const char hex) -{ - switch (hex) { - case '0': - return (0x00); - case '1': - return (0x01); - case '2': - return (0x02); - case '3': - return (0x03); - case '4': - return (0x04); - case '5': - return (0x05); - case '6': - return (0x06); - case '7': - return (0x07); - case '8': - return (0x08); - case '9': - return (0x09); - case 'a': - case 'A': - return (0x0a); - case 'b': - case 'B': - return (0x0b); - case 'c': - case 'C': - return (0x0c); - case 'd': - case 'D': - return (0x0d); - case 'e': - case 'E': - return (0x0e); - case 'f': - case 'F': - return (0x0f); - default: - return (-1); - } -} - -static int -chap_b642bin(const char *b64, void **binp, size_t *bin_lenp) -{ - char *bin; - int b64_len, bin_len; - - b64_len = strlen(b64); - bin_len = (b64_len + 3) / 4 * 3; - bin = calloc(bin_len, 1); - if (bin == NULL) - log_err(1, "calloc"); - - bin_len = b64_pton(b64, bin, bin_len); - if (bin_len < 0) { - log_warnx("malformed base64 variable"); - free(bin); - return (-1); - } - *binp = bin; - *bin_lenp = bin_len; - return (0); -} - -/* - * XXX: Review this _carefully_. - */ -static int -chap_hex2bin(const char *hex, void **binp, size_t *bin_lenp) -{ - int i, hex_len, nibble; - bool lo = true; /* As opposed to 'hi'. */ - char *bin; - size_t bin_off, bin_len; - - if (strncasecmp(hex, "0b", strlen("0b")) == 0) - return (chap_b642bin(hex + 2, binp, bin_lenp)); - - if (strncasecmp(hex, "0x", strlen("0x")) != 0) { - log_warnx("malformed variable, should start with \"0x\"" - " or \"0b\""); - return (-1); - } - - hex += strlen("0x"); - hex_len = strlen(hex); - if (hex_len < 1) { - log_warnx("malformed variable; doesn't contain anything " - "but \"0x\""); - return (-1); - } - - bin_len = hex_len / 2 + hex_len % 2; - bin = calloc(bin_len, 1); - if (bin == NULL) - log_err(1, "calloc"); - - bin_off = bin_len - 1; - for (i = hex_len - 1; i >= 0; i--) { - nibble = chap_hex2int(hex[i]); - if (nibble < 0) { - log_warnx("malformed variable, invalid char \"%c\"", - hex[i]); - free(bin); - return (-1); - } - - assert(bin_off < bin_len); - if (lo) { - bin[bin_off] = nibble; - lo = false; - } else { - bin[bin_off] |= nibble << 4; - bin_off--; - lo = true; - } - } - - *binp = bin; - *bin_lenp = bin_len; - return (0); -} - -#ifdef USE_BASE64 -static char * -chap_bin2hex(const char *bin, size_t bin_len) -{ - unsigned char *b64, *tmp; - size_t b64_len; - - b64_len = (bin_len + 2) / 3 * 4 + 3; /* +2 for "0b", +1 for '\0'. */ - b64 = malloc(b64_len); - if (b64 == NULL) - log_err(1, "malloc"); - - tmp = b64; - tmp += sprintf(tmp, "0b"); - b64_ntop(bin, bin_len, tmp, b64_len - 2); - - return (b64); -} -#else -static char * -chap_bin2hex(const char *bin, size_t bin_len) -{ - unsigned char *hex, *tmp, ch; - size_t hex_len; - size_t i; - - hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */ - hex = malloc(hex_len); - if (hex == NULL) - log_err(1, "malloc"); - - tmp = hex; - tmp += sprintf(tmp, "0x"); - for (i = 0; i < bin_len; i++) { - ch = bin[i]; - tmp += sprintf(tmp, "%02x", ch); - } - - return (hex); -} -#endif /* !USE_BASE64 */ - -struct chap * -chap_new(void) -{ - struct chap *chap; - - chap = calloc(1, sizeof(*chap)); - if (chap == NULL) - log_err(1, "calloc"); - - /* - * Generate the challenge. - */ - arc4random_buf(chap->chap_challenge, sizeof(chap->chap_challenge)); - arc4random_buf(&chap->chap_id, sizeof(chap->chap_id)); - - return (chap); -} - -char * -chap_get_id(const struct chap *chap) -{ - char *chap_i; - int ret; - - ret = asprintf(&chap_i, "%d", chap->chap_id); - if (ret < 0) - log_err(1, "asprintf"); - - return (chap_i); -} - -char * -chap_get_challenge(const struct chap *chap) -{ - char *chap_c; - - chap_c = chap_bin2hex(chap->chap_challenge, - sizeof(chap->chap_challenge)); - - return (chap_c); -} - -static int -chap_receive_bin(struct chap *chap, void *response, size_t response_len) -{ - - if (response_len != sizeof(chap->chap_response)) { - log_debugx("got CHAP response with invalid length; " - "got %zd, should be %zd", - response_len, sizeof(chap->chap_response)); - return (1); - } - - memcpy(chap->chap_response, response, response_len); - return (0); -} - -int -chap_receive(struct chap *chap, const char *response) -{ - void *response_bin; - size_t response_bin_len; - int error; - - error = chap_hex2bin(response, &response_bin, &response_bin_len); - if (error != 0) { - log_debugx("got incorrectly encoded CHAP response \"%s\"", - response); - return (1); - } - - error = chap_receive_bin(chap, response_bin, response_bin_len); - free(response_bin); - - return (error); -} - -int -chap_authenticate(struct chap *chap, const char *secret) -{ - char expected_response[CHAP_DIGEST_LEN]; - - chap_compute_md5(chap->chap_id, secret, - chap->chap_challenge, sizeof(chap->chap_challenge), - expected_response, sizeof(expected_response)); - - if (memcmp(chap->chap_response, - expected_response, sizeof(expected_response)) != 0) { - return (-1); - } - - return (0); -} - -void -chap_delete(struct chap *chap) -{ - - free(chap); -} - -struct rchap * -rchap_new(const char *secret) -{ - struct rchap *rchap; - - rchap = calloc(1, sizeof(*rchap)); - if (rchap == NULL) - log_err(1, "calloc"); - - rchap->rchap_secret = checked_strdup(secret); - - return (rchap); -} - -static void -rchap_receive_bin(struct rchap *rchap, const unsigned char id, - const void *challenge, size_t challenge_len) -{ - - rchap->rchap_id = id; - rchap->rchap_challenge = calloc(challenge_len, 1); - if (rchap->rchap_challenge == NULL) - log_err(1, "calloc"); - memcpy(rchap->rchap_challenge, challenge, challenge_len); - rchap->rchap_challenge_len = challenge_len; -} - -int -rchap_receive(struct rchap *rchap, const char *id, const char *challenge) -{ - unsigned char id_bin; - void *challenge_bin; - size_t challenge_bin_len; - - int error; - - id_bin = strtoul(id, NULL, 10); - - error = chap_hex2bin(challenge, &challenge_bin, &challenge_bin_len); - if (error != 0) { - log_debugx("got incorrectly encoded CHAP challenge \"%s\"", - challenge); - return (1); - } - - rchap_receive_bin(rchap, id_bin, challenge_bin, challenge_bin_len); - free(challenge_bin); - - return (0); -} - -static void -rchap_get_response_bin(struct rchap *rchap, - void **responsep, size_t *response_lenp) -{ - void *response_bin; - size_t response_bin_len = CHAP_DIGEST_LEN; - - response_bin = calloc(response_bin_len, 1); - if (response_bin == NULL) - log_err(1, "calloc"); - - chap_compute_md5(rchap->rchap_id, rchap->rchap_secret, - rchap->rchap_challenge, rchap->rchap_challenge_len, - response_bin, response_bin_len); - - *responsep = response_bin; - *response_lenp = response_bin_len; -} - -char * -rchap_get_response(struct rchap *rchap) -{ - void *response; - size_t response_len; - char *chap_r; - - rchap_get_response_bin(rchap, &response, &response_len); - chap_r = chap_bin2hex(response, response_len); - free(response); - - return (chap_r); -} - -void -rchap_delete(struct rchap *rchap) -{ - - free(rchap->rchap_secret); - free(rchap->rchap_challenge); - free(rchap); -} diff --git a/usr.sbin/iscsid/discovery.c b/usr.sbin/iscsid/discovery.c --- a/usr.sbin/iscsid/discovery.c +++ b/usr.sbin/iscsid/discovery.c @@ -138,7 +138,7 @@ } static void -kernel_add(const struct connection *conn, const char *target) +kernel_add(const struct iscsid_connection *conn, const char *target) { struct iscsi_session_add isa; int error; @@ -154,7 +154,7 @@ } static void -kernel_remove(const struct connection *conn) +kernel_remove(const struct iscsid_connection *conn) { struct iscsi_session_remove isr; int error; @@ -167,14 +167,14 @@ } void -discovery(struct connection *conn) +discovery(struct iscsid_connection *conn) { struct pdu *request, *response; struct keys *request_keys, *response_keys; int i; log_debugx("beginning discovery session"); - request = text_new_request(conn); + request = text_new_request(&conn->conn); request_keys = keys_new(); keys_add(request_keys, "SendTargets", "All"); keys_save(request_keys, request); @@ -185,7 +185,7 @@ request = NULL; log_debugx("waiting for Text Response"); - response = text_receive(conn); + response = text_receive(&conn->conn); response_keys = keys_new(); keys_load(response_keys, response); for (i = 0; i < KEYS_MAX; i++) { @@ -220,13 +220,13 @@ #endif log_debugx("discovery done; logging out"); - request = logout_new_request(conn); + request = logout_new_request(&conn->conn); pdu_send(request); pdu_delete(request); request = NULL; log_debugx("waiting for Logout Response"); - response = logout_receive(conn); + response = logout_receive(&conn->conn); pdu_delete(response); log_debugx("discovery session done"); diff --git a/usr.sbin/iscsid/iscsid.h b/usr.sbin/iscsid/iscsid.h --- a/usr.sbin/iscsid/iscsid.h +++ b/usr.sbin/iscsid/iscsid.h @@ -37,116 +37,29 @@ #include #include +#include #define DEFAULT_PIDFILE "/var/run/iscsid.pid" -#define CONN_DIGEST_NONE 0 -#define CONN_DIGEST_CRC32C 1 - #define CONN_MUTUAL_CHALLENGE_LEN 1024 #define SOCKBUF_SIZE 1048576 -struct connection { +struct iscsid_connection { + struct connection conn; int conn_iscsi_fd; - int conn_socket; unsigned int conn_session_id; struct iscsi_session_conf conn_conf; struct iscsi_session_limits conn_limits; char conn_target_alias[ISCSI_ADDR_LEN]; - uint8_t conn_isid[6]; - uint16_t conn_tsih; - uint32_t conn_statsn; int conn_protocol_level; - int conn_header_digest; - int conn_data_digest; bool conn_initial_r2t; - bool conn_immediate_data; - 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 chap *conn_mutual_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); - -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); -void pdu_receive(struct pdu *request); -void pdu_send(struct pdu *response); -void pdu_delete(struct pdu *ip); - -void login(struct connection *ic); - -void discovery(struct connection *ic); +void login(struct iscsid_connection *ic); -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); +void discovery(struct iscsid_connection *ic); -char *checked_strdup(const char *); -bool timed_out(void); void fail(const struct connection *, const char *); #endif /* !ISCSID_H */ diff --git a/usr.sbin/iscsid/iscsid.c b/usr.sbin/iscsid/iscsid.c --- a/usr.sbin/iscsid/iscsid.c +++ b/usr.sbin/iscsid/iscsid.c @@ -57,10 +57,25 @@ #include "iscsid.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 volatile bool sigalrm_received = false; static int nchildren = 0; +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 = fail, +}; + static void usage(void) { @@ -69,17 +84,67 @@ exit(1); } -char * -checked_strdup(const char *s) +#ifdef ICL_KERNEL_PROXY + +static void +pdu_receive_proxy(struct pdu *pdu) +{ + struct iscsid_connection *conn; + struct iscsi_daemon_receive idr; + size_t len; + int error; + + conn = (struct iscsid_connection *)pdu->pdu_connection; + assert(conn->conn_conf.isc_iser != 0); + + pdu->pdu_data = malloc(conn->conn.conn_max_recv_data_segment_length); + if (pdu->pdu_data == NULL) + log_err(1, "malloc"); + + memset(&idr, 0, sizeof(idr)); + idr.idr_session_id = conn->conn_session_id; + idr.idr_bhs = pdu->pdu_bhs; + idr.idr_data_segment_len = conn->conn.conn_max_recv_data_segment_length; + idr.idr_data_segment = pdu->pdu_data; + + error = ioctl(conn->conn_iscsi_fd, ISCSIDRECEIVE, &idr); + if (error != 0) + log_err(1, "ISCSIDRECEIVE"); + + 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.conn_max_recv_data_segment_length); + pdu->pdu_data_len = len; +} + +static void +pdu_send_proxy(struct pdu *pdu) { - char *c; + struct iscsid_connection *conn; + struct iscsi_daemon_send ids; + int error; + + conn = (struct iscsid_connection *)pdu->pdu_connection; + assert(conn->conn_conf.isc_iser != 0); - c = strdup(s); - if (c == NULL) - log_err(1, "strdup"); - return (c); + pdu_set_data_segment_length(pdu, pdu->pdu_data_len); + + memset(&ids, 0, sizeof(ids)); + ids.ids_session_id = conn->conn_session_id; + ids.ids_bhs = pdu->pdu_bhs; + ids.ids_data_segment_len = pdu->pdu_data_len; + ids.ids_data_segment = pdu->pdu_data; + + error = ioctl(conn->conn_iscsi_fd, ISCSIDSEND, &ids); + if (error != 0) + log_err(1, "ISCSIDSEND"); } +#endif /* ICL_KERNEL_PROXY */ + static void resolve_addr(const struct connection *conn, const char *address, struct addrinfo **ai, bool initiator_side) @@ -154,10 +219,10 @@ free(addr); } -static struct connection * +static struct iscsid_connection * connection_new(int iscsi_fd, const struct iscsi_daemon_request *request) { - struct connection *conn; + struct iscsid_connection *conn; struct iscsi_session_limits *isl; struct addrinfo *from_ai, *to_ai; const char *from_addr, *to_addr; @@ -170,24 +235,17 @@ if (conn == NULL) log_err(1, "calloc"); - /* - * Default values, from RFC 3720, section 12. - */ + connection_init(&conn->conn, &conn_ops, + request->idr_conf.isc_iser != 0); conn->conn_protocol_level = 0; - conn->conn_header_digest = CONN_DIGEST_NONE; - conn->conn_data_digest = CONN_DIGEST_NONE; conn->conn_initial_r2t = true; - 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; conn->conn_iscsi_fd = iscsi_fd; conn->conn_session_id = request->idr_session_id; memcpy(&conn->conn_conf, &request->idr_conf, sizeof(conn->conn_conf)); - memcpy(&conn->conn_isid, &request->idr_isid, sizeof(conn->conn_isid)); - conn->conn_tsih = request->idr_tsih; + memcpy(&conn->conn.conn_isid, &request->idr_isid, + sizeof(conn->conn.conn_isid)); + conn->conn.conn_tsih = request->idr_tsih; /* * Read the driver limits and provide reasonable defaults for the ones @@ -215,9 +273,9 @@ * We can't do it for other limits, since they may affect both * sender and receiver operation, and we must obey defaults. */ - if (conn->conn_max_send_data_segment_length > + if (conn->conn.conn_max_send_data_segment_length > isl->isl_max_send_data_segment_length) { - conn->conn_max_send_data_segment_length = + conn->conn.conn_max_send_data_segment_length = isl->isl_max_send_data_segment_length; } @@ -225,11 +283,11 @@ to_addr = conn->conn_conf.isc_target_addr; if (from_addr[0] != '\0') - resolve_addr(conn, from_addr, &from_ai, true); + resolve_addr(&conn->conn, from_addr, &from_ai, true); else from_ai = NULL; - resolve_addr(conn, to_addr, &to_ai, false); + resolve_addr(&conn->conn, to_addr, &to_ai, false); #ifdef ICL_KERNEL_PROXY if (conn->conn_conf.isc_iser) { @@ -250,7 +308,7 @@ log_debugx("connecting to %s using ICL kernel proxy", to_addr); error = ioctl(iscsi_fd, ISCSIDCONNECT, &idc); if (error != 0) { - fail(conn, strerror(errno)); + fail(&conn->conn, strerror(errno)); log_err(1, "failed to connect to %s " "using ICL kernel proxy: ISCSIDCONNECT", to_addr); } @@ -264,33 +322,33 @@ #endif /* ICL_KERNEL_PROXY */ if (conn->conn_conf.isc_iser) { - fail(conn, "iSER not supported"); + fail(&conn->conn, "iSER not supported"); log_errx(1, "iscsid(8) compiled without ICL_KERNEL_PROXY " "does not support iSER"); } - conn->conn_socket = socket(to_ai->ai_family, to_ai->ai_socktype, + conn->conn.conn_socket = socket(to_ai->ai_family, to_ai->ai_socktype, to_ai->ai_protocol); - if (conn->conn_socket < 0) { - fail(conn, strerror(errno)); + if (conn->conn.conn_socket < 0) { + fail(&conn->conn, strerror(errno)); log_err(1, "failed to create socket for %s", from_addr); } optval = SOCKBUF_SIZE; - if (setsockopt(conn->conn_socket, SOL_SOCKET, SO_RCVBUF, + if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)) == -1) log_warn("setsockopt(SO_RCVBUF) failed"); optval = SOCKBUF_SIZE; - if (setsockopt(conn->conn_socket, SOL_SOCKET, SO_SNDBUF, + if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) == -1) log_warn("setsockopt(SO_SNDBUF) failed"); optval = 1; - if (setsockopt(conn->conn_socket, SOL_SOCKET, SO_NO_DDP, + if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_NO_DDP, &optval, sizeof(optval)) == -1) log_warn("setsockopt(SO_NO_DDP) failed"); if (conn->conn_conf.isc_dscp != -1) { int tos = conn->conn_conf.isc_dscp << 2; if (to_ai->ai_family == AF_INET) { - if (setsockopt(conn->conn_socket, + if (setsockopt(conn->conn.conn_socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) log_warn("setsockopt(IP_TOS) " @@ -298,7 +356,7 @@ from_addr); } else if (to_ai->ai_family == AF_INET6) { - if (setsockopt(conn->conn_socket, + if (setsockopt(conn->conn.conn_socket, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)) == -1) log_warn("setsockopt(IPV6_TCLASS) " @@ -309,7 +367,7 @@ if (conn->conn_conf.isc_pcp != -1) { int pcp = conn->conn_conf.isc_pcp; if (to_ai->ai_family == AF_INET) { - if (setsockopt(conn->conn_socket, + if (setsockopt(conn->conn.conn_socket, IPPROTO_IP, IP_VLAN_PCP, &pcp, sizeof(pcp)) == -1) log_warn("setsockopt(IP_VLAN_PCP) " @@ -317,7 +375,7 @@ from_addr); } else if (to_ai->ai_family == AF_INET6) { - if (setsockopt(conn->conn_socket, + if (setsockopt(conn->conn.conn_socket, IPPROTO_IPV6, IPV6_VLAN_PCP, &pcp, sizeof(pcp)) == -1) log_warn("setsockopt(IPV6_VLAN_PCP) " @@ -326,17 +384,18 @@ } } if (from_ai != NULL) { - error = bind(conn->conn_socket, from_ai->ai_addr, + error = bind(conn->conn.conn_socket, from_ai->ai_addr, from_ai->ai_addrlen); if (error != 0) { - fail(conn, strerror(errno)); + fail(&conn->conn, strerror(errno)); log_err(1, "failed to bind to %s", from_addr); } } log_debugx("connecting to %s", to_addr); - error = connect(conn->conn_socket, to_ai->ai_addr, to_ai->ai_addrlen); + error = connect(conn->conn.conn_socket, to_ai->ai_addr, + to_ai->ai_addrlen); if (error != 0) { - fail(conn, strerror(errno)); + fail(&conn->conn, strerror(errno)); log_err(1, "failed to connect to %s", to_addr); } @@ -348,7 +407,7 @@ } static void -handoff(struct connection *conn) +handoff(struct iscsid_connection *conn) { struct iscsi_daemon_handoff idh; int error; @@ -357,22 +416,22 @@ memset(&idh, 0, sizeof(idh)); idh.idh_session_id = conn->conn_session_id; - idh.idh_socket = conn->conn_socket; + idh.idh_socket = conn->conn.conn_socket; strlcpy(idh.idh_target_alias, conn->conn_target_alias, sizeof(idh.idh_target_alias)); - idh.idh_tsih = conn->conn_tsih; - idh.idh_statsn = conn->conn_statsn; + idh.idh_tsih = conn->conn.conn_tsih; + idh.idh_statsn = conn->conn.conn_statsn; idh.idh_protocol_level = conn->conn_protocol_level; - idh.idh_header_digest = conn->conn_header_digest; - idh.idh_data_digest = conn->conn_data_digest; + idh.idh_header_digest = conn->conn.conn_header_digest; + idh.idh_data_digest = conn->conn.conn_data_digest; idh.idh_initial_r2t = conn->conn_initial_r2t; - idh.idh_immediate_data = conn->conn_immediate_data; + idh.idh_immediate_data = conn->conn.conn_immediate_data; idh.idh_max_recv_data_segment_length = - conn->conn_max_recv_data_segment_length; + conn->conn.conn_max_recv_data_segment_length; idh.idh_max_send_data_segment_length = - conn->conn_max_send_data_segment_length; - idh.idh_max_burst_length = conn->conn_max_burst_length; - idh.idh_first_burst_length = conn->conn_first_burst_length; + conn->conn.conn_max_send_data_segment_length; + idh.idh_max_burst_length = conn->conn.conn_max_burst_length; + idh.idh_first_burst_length = conn->conn.conn_first_burst_length; error = ioctl(conn->conn_iscsi_fd, ISCSIDHANDOFF, &idh); if (error != 0) @@ -380,11 +439,13 @@ } void -fail(const struct connection *conn, const char *reason) +fail(const struct connection *base_conn, const char *reason) { + const struct iscsid_connection *conn; struct iscsi_daemon_fail idf; int error, saved_errno; + conn = (const struct iscsid_connection *)base_conn; saved_errno = errno; memset(&idf, 0, sizeof(idf)); @@ -402,7 +463,7 @@ * XXX: I CANT INTO LATIN */ static void -capsicate(struct connection *conn) +capsicate(struct iscsid_connection *conn) { cap_rights_t rights; #ifdef ICL_KERNEL_PROXY @@ -429,7 +490,7 @@ log_warnx("Capsicum capability mode not supported"); } -bool +static bool timed_out(void) { @@ -519,7 +580,7 @@ static void handle_request(int iscsi_fd, const struct iscsi_daemon_request *request, int timeout) { - struct connection *conn; + struct iscsid_connection *conn; log_set_peer_addr(request->idr_conf.isc_target_addr); if (request->idr_conf.isc_target[0] != '\0') { diff --git a/usr.sbin/iscsid/keys.c b/usr.sbin/iscsid/keys.c deleted file mode 100644 --- a/usr.sbin/iscsid/keys.c +++ /dev/null @@ -1,199 +0,0 @@ -/*- - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include "iscsid.h" - -struct keys * -keys_new(void) -{ - struct keys *keys; - - keys = calloc(1, sizeof(*keys)); - if (keys == NULL) - log_err(1, "calloc"); - - return (keys); -} - -void -keys_delete(struct keys *keys) -{ - - free(keys->keys_data); - free(keys); -} - -void -keys_load(struct keys *keys, const struct pdu *pdu) -{ - int i; - char *pair; - size_t pair_len; - - if (pdu->pdu_data_len == 0) - return; - - if (pdu->pdu_data[pdu->pdu_data_len - 1] != '\0') - log_errx(1, "protocol error: key not NULL-terminated\n"); - - assert(keys->keys_data == NULL); - keys->keys_data_len = pdu->pdu_data_len; - keys->keys_data = malloc(keys->keys_data_len); - if (keys->keys_data == NULL) - log_err(1, "malloc"); - memcpy(keys->keys_data, pdu->pdu_data, keys->keys_data_len); - - /* - * XXX: Review this carefully. - */ - pair = keys->keys_data; - for (i = 0;; i++) { - if (i >= KEYS_MAX) - log_errx(1, "too many keys received"); - - pair_len = strlen(pair); - - keys->keys_values[i] = pair; - keys->keys_names[i] = strsep(&keys->keys_values[i], "="); - if (keys->keys_names[i] == NULL || keys->keys_values[i] == NULL) - log_errx(1, "malformed keys"); - log_debugx("key received: \"%s=%s\"", - keys->keys_names[i], keys->keys_values[i]); - - pair += pair_len + 1; /* +1 to skip the terminating '\0'. */ - if (pair == keys->keys_data + keys->keys_data_len) - break; - assert(pair < keys->keys_data + keys->keys_data_len); - } -} - -void -keys_save(struct keys *keys, struct pdu *pdu) -{ - char *data; - size_t len; - int i; - - /* - * XXX: Not particularly efficient. - */ - len = 0; - for (i = 0; i < KEYS_MAX; i++) { - if (keys->keys_names[i] == NULL) - break; - /* - * +1 for '=', +1 for '\0'. - */ - len += strlen(keys->keys_names[i]) + - strlen(keys->keys_values[i]) + 2; - } - - if (len == 0) - return; - - data = malloc(len); - if (data == NULL) - log_err(1, "malloc"); - - pdu->pdu_data = data; - pdu->pdu_data_len = len; - - for (i = 0; i < KEYS_MAX; i++) { - if (keys->keys_names[i] == NULL) - break; - data += sprintf(data, "%s=%s", - keys->keys_names[i], keys->keys_values[i]); - data += 1; /* for '\0'. */ - } -} - -const char * -keys_find(struct keys *keys, const char *name) -{ - int i; - - /* - * Note that we don't handle duplicated key names here, - * as they are not supposed to happen in requests, and if they do, - * it's an initiator error. - */ - for (i = 0; i < KEYS_MAX; i++) { - if (keys->keys_names[i] == NULL) - return (NULL); - if (strcmp(keys->keys_names[i], name) == 0) - return (keys->keys_values[i]); - } - return (NULL); -} - -void -keys_add(struct keys *keys, const char *name, const char *value) -{ - int i; - - log_debugx("key to send: \"%s=%s\"", name, value); - - /* - * Note that we don't check for duplicates here, as they are perfectly - * fine in responses, e.g. the "TargetName" keys in discovery sesion - * response. - */ - for (i = 0; i < KEYS_MAX; i++) { - if (keys->keys_names[i] == NULL) { - keys->keys_names[i] = checked_strdup(name); - keys->keys_values[i] = checked_strdup(value); - return; - } - } - log_errx(1, "too many keys"); -} - -void -keys_add_int(struct keys *keys, const char *name, int value) -{ - char *str; - int ret; - - ret = asprintf(&str, "%d", value); - if (ret <= 0) - log_err(1, "asprintf"); - - keys_add(keys, name, str); - free(str); -} diff --git a/usr.sbin/iscsid/log.c b/usr.sbin/iscsid/log.c deleted file mode 100644 --- a/usr.sbin/iscsid/log.c +++ /dev/null @@ -1,202 +0,0 @@ -/*- - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include "iscsid.h" - -static int log_level = 0; -static char *peer_name = NULL; -static char *peer_addr = NULL; - -#define MSGBUF_LEN 1024 - -void -log_init(int level) -{ - - log_level = level; - openlog(getprogname(), LOG_NDELAY | LOG_PID, LOG_DAEMON); -} - -void -log_set_peer_name(const char *name) -{ - - /* - * XXX: Turn it into assertion? - */ - if (peer_name != NULL) - log_errx(1, "%s called twice", __func__); - if (peer_addr == NULL) - log_errx(1, "%s called before log_set_peer_addr", __func__); - - peer_name = checked_strdup(name); -} - -void -log_set_peer_addr(const char *addr) -{ - - /* - * XXX: Turn it into assertion? - */ - if (peer_addr != NULL) - log_errx(1, "%s called twice", __func__); - - peer_addr = checked_strdup(addr); -} - -static void -log_common(int priority, int log_errno, const char *fmt, va_list ap) -{ - static char msgbuf[MSGBUF_LEN]; - static char msgbuf_strvised[MSGBUF_LEN * 4 + 1]; - char *errstr; - int ret; - - ret = vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); - if (ret < 0) { - fprintf(stderr, "%s: snprintf failed", getprogname()); - syslog(LOG_CRIT, "snprintf failed"); - exit(1); - } - - ret = strnvis(msgbuf_strvised, sizeof(msgbuf_strvised), msgbuf, VIS_NL); - if (ret < 0) { - fprintf(stderr, "%s: strnvis failed", getprogname()); - syslog(LOG_CRIT, "strnvis failed"); - exit(1); - } - - if (log_errno == -1) { - if (peer_name != NULL) { - fprintf(stderr, "%s: %s (%s): %s\n", getprogname(), - peer_addr, peer_name, msgbuf_strvised); - syslog(priority, "%s (%s): %s", - peer_addr, peer_name, msgbuf_strvised); - } else if (peer_addr != NULL) { - fprintf(stderr, "%s: %s: %s\n", getprogname(), - peer_addr, msgbuf_strvised); - syslog(priority, "%s: %s", - peer_addr, msgbuf_strvised); - } else { - fprintf(stderr, "%s: %s\n", getprogname(), msgbuf_strvised); - syslog(priority, "%s", msgbuf_strvised); - } - - } else { - errstr = strerror(log_errno); - - if (peer_name != NULL) { - fprintf(stderr, "%s: %s (%s): %s: %s\n", getprogname(), - peer_addr, peer_name, msgbuf_strvised, errstr); - syslog(priority, "%s (%s): %s: %s", - peer_addr, peer_name, msgbuf_strvised, errstr); - } else if (peer_addr != NULL) { - fprintf(stderr, "%s: %s: %s: %s\n", getprogname(), - peer_addr, msgbuf_strvised, errstr); - syslog(priority, "%s: %s: %s", - peer_addr, msgbuf_strvised, errstr); - } else { - fprintf(stderr, "%s: %s: %s\n", getprogname(), - msgbuf_strvised, errstr); - syslog(priority, "%s: %s", - msgbuf_strvised, errstr); - } - } -} - -void -log_err(int eval, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - log_common(LOG_CRIT, errno, fmt, ap); - va_end(ap); - - exit(eval); -} - -void -log_errx(int eval, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - log_common(LOG_CRIT, -1, fmt, ap); - va_end(ap); - - exit(eval); -} - -void -log_warn(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - log_common(LOG_WARNING, errno, fmt, ap); - va_end(ap); -} - -void -log_warnx(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - log_common(LOG_WARNING, -1, fmt, ap); - va_end(ap); -} - -void -log_debugx(const char *fmt, ...) -{ - va_list ap; - - if (log_level == 0) - return; - - va_start(ap, fmt); - log_common(LOG_DEBUG, -1, fmt, ap); - va_end(ap); -} diff --git a/usr.sbin/iscsid/login.c b/usr.sbin/iscsid/login.c --- a/usr.sbin/iscsid/login.c +++ b/usr.sbin/iscsid/login.c @@ -160,7 +160,7 @@ } static void -kernel_modify(const struct connection *conn, const char *target_address) +kernel_modify(const struct iscsid_connection *conn, const char *target_address) { struct iscsi_session_modify ism; int error; @@ -188,7 +188,7 @@ * as described in draft. */ static void -login_handle_redirection(struct connection *conn, struct pdu *response) +login_handle_redirection(struct iscsid_connection *conn, struct pdu *response) { struct iscsi_bhs_login_response *bhslr; struct keys *response_keys; @@ -241,7 +241,8 @@ log_errx(1, "received Login PDU with unsupported " "Version-active 0x%x", bhslr->bhslr_version_active); if (bhslr->bhslr_status_class == 1) { - login_handle_redirection(conn, response); + login_handle_redirection((struct iscsid_connection *)conn, + response); log_debugx("redirection handled; exiting"); exit(0); } @@ -328,7 +329,7 @@ } static void -login_negotiate_key(struct connection *conn, const char *name, +login_negotiate_key(struct iscsid_connection *conn, const char *name, const char *value) { struct iscsi_session_limits *isl; @@ -351,7 +352,7 @@ case 1: log_debugx("target prefers CRC32C " "for header digest; we'll use it"); - conn->conn_header_digest = CONN_DIGEST_CRC32C; + conn->conn.conn_header_digest = CONN_DIGEST_CRC32C; break; case 2: log_debugx("target prefers not to do " @@ -368,7 +369,7 @@ case 1: log_debugx("target prefers CRC32C " "for data digest; we'll use it"); - conn->conn_data_digest = CONN_DIGEST_CRC32C; + conn->conn.conn_data_digest = CONN_DIGEST_CRC32C; break; case 2: log_debugx("target prefers not to do " @@ -388,9 +389,9 @@ conn->conn_initial_r2t = false; } else if (strcmp(name, "ImmediateData") == 0) { if (strcmp(value, "Yes") == 0) - conn->conn_immediate_data = true; + conn->conn.conn_immediate_data = true; else - conn->conn_immediate_data = false; + conn->conn.conn_immediate_data = false; } else if (strcmp(name, "MaxRecvDataSegmentLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) @@ -402,7 +403,7 @@ isl->isl_max_send_data_segment_length); tmp = isl->isl_max_send_data_segment_length; } - conn->conn_max_send_data_segment_length = tmp; + conn->conn.conn_max_send_data_segment_length = tmp; } else if (strcmp(name, "MaxBurstLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) @@ -412,7 +413,7 @@ "from %d to %d", tmp, isl->isl_max_burst_length); tmp = isl->isl_max_burst_length; } - conn->conn_max_burst_length = tmp; + conn->conn.conn_max_burst_length = tmp; } else if (strcmp(name, "FirstBurstLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) @@ -422,7 +423,7 @@ "from %d to %d", tmp, isl->isl_first_burst_length); tmp = isl->isl_first_burst_length; } - conn->conn_first_burst_length = tmp; + conn->conn.conn_first_burst_length = tmp; } else if (strcmp(name, "DefaultTime2Wait") == 0) { /* Ignore */ } else if (strcmp(name, "DefaultTime2Retain") == 0) { @@ -455,7 +456,7 @@ isl->isl_max_recv_data_segment_length); tmp = isl->isl_max_recv_data_segment_length; } - conn->conn_max_recv_data_segment_length = tmp; + conn->conn.conn_max_recv_data_segment_length = tmp; } else if (strcmp(name, "TargetPortalGroupTag") == 0) { /* Ignore */ } else if (strcmp(name, "TargetRecvDataSegmentLength") == 0) { @@ -470,14 +471,14 @@ isl->isl_max_send_data_segment_length); tmp = isl->isl_max_send_data_segment_length; } - conn->conn_max_send_data_segment_length = tmp; + conn->conn.conn_max_send_data_segment_length = tmp; } else { log_debugx("unknown key \"%s\"; ignoring", name); } } static void -login_negotiate(struct connection *conn) +login_negotiate(struct iscsid_connection *conn) { struct pdu *request, *response; struct keys *request_keys, *response_keys; @@ -486,7 +487,8 @@ struct iscsi_session_limits *isl; log_debugx("beginning operational parameter negotiation"); - request = login_new_request(conn, BHSLR_STAGE_OPERATIONAL_NEGOTIATION); + request = login_new_request(&conn->conn, + BHSLR_STAGE_OPERATIONAL_NEGOTIATION); request_keys = keys_new(); isl = &conn->conn_limits; @@ -535,7 +537,7 @@ isl->isl_max_recv_data_segment_length); } - conn->conn_max_recv_data_segment_length = + conn->conn.conn_max_recv_data_segment_length = isl->isl_max_recv_data_segment_length; keys_add(request_keys, "DefaultTime2Wait", "0"); @@ -548,7 +550,7 @@ pdu_delete(request); request = NULL; - response = login_receive(conn); + response = login_receive(&conn->conn); response_keys = keys_new(); keys_load(response_keys, response); for (i = 0; i < KEYS_MAX; i++) { @@ -579,12 +581,12 @@ pdu_delete(response); - request = login_new_request(conn, + request = login_new_request(&conn->conn, BHSLR_STAGE_OPERATIONAL_NEGOTIATION); pdu_send(request); pdu_delete(request); - response = login_receive(conn); + response = login_receive(&conn->conn); } if (login_nsg(response) != BHSLR_STAGE_FULL_FEATURE_PHASE) @@ -614,7 +616,7 @@ static void login_send_chap_r(struct pdu *response) { - struct connection *conn; + struct iscsid_connection *conn; struct pdu *request; struct keys *request_keys, *response_keys; struct rchap *rchap; @@ -631,7 +633,7 @@ * CHAP challenge; our CHAP response goes into 'request'. */ - conn = response->pdu_connection; + conn = (struct iscsid_connection *)response->pdu_connection; response_keys = keys_new(); keys_load(response_keys, response); @@ -665,7 +667,8 @@ keys_delete(response_keys); - request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); + request = login_new_request(&conn->conn, + BHSLR_STAGE_SECURITY_NEGOTIATION); request_keys = keys_new(); keys_add(request_keys, "CHAP_N", conn->conn_conf.isc_user); keys_add(request_keys, "CHAP_R", chap_r); @@ -699,12 +702,12 @@ static void login_verify_mutual(const struct pdu *response) { - struct connection *conn; + struct iscsid_connection *conn; struct keys *response_keys; const char *chap_n, *chap_r; int error; - conn = response->pdu_connection; + conn = (struct iscsid_connection *)response->pdu_connection; response_keys = keys_new(); keys_load(response_keys, response); @@ -721,14 +724,14 @@ log_errx(1, "received CHAP Response PDU with invalid CHAP_R"); if (strcmp(chap_n, conn->conn_conf.isc_mutual_user) != 0) { - fail(conn, "Mutual CHAP failed"); + fail(&conn->conn, "Mutual CHAP failed"); log_errx(1, "mutual CHAP authentication failed: wrong user"); } error = chap_authenticate(conn->conn_mutual_chap, conn->conn_conf.isc_mutual_secret); if (error != 0) { - fail(conn, "Mutual CHAP failed"); + fail(&conn->conn, "Mutual CHAP failed"); log_errx(1, "mutual CHAP authentication failed: wrong secret"); } @@ -740,15 +743,15 @@ } static void -login_chap(struct connection *conn) +login_chap(struct iscsid_connection *conn) { struct pdu *response; log_debugx("beginning CHAP authentication; sending CHAP_A"); - login_send_chap_a(conn); + login_send_chap_a(&conn->conn); log_debugx("waiting for CHAP_A/CHAP_C/CHAP_I"); - response = login_receive(conn); + response = login_receive(&conn->conn); log_debugx("sending CHAP_N/CHAP_R"); login_send_chap_r(response); @@ -759,7 +762,7 @@ */ log_debugx("waiting for CHAP result"); - response = login_receive(conn); + response = login_receive(&conn->conn); if (conn->conn_conf.isc_mutual_user[0] != '\0') login_verify_mutual(response); pdu_delete(response); @@ -768,7 +771,7 @@ } void -login(struct connection *conn) +login(struct iscsid_connection *conn) { struct pdu *request, *response; struct keys *request_keys, *response_keys; @@ -777,7 +780,8 @@ int i; log_debugx("beginning Login phase; sending Login PDU"); - request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); + request = login_new_request(&conn->conn, + BHSLR_STAGE_SECURITY_NEGOTIATION); request_keys = keys_new(); if (conn->conn_conf.isc_mutual_user[0] != '\0') { keys_add(request_keys, "AuthMethod", "CHAP"); @@ -817,7 +821,7 @@ pdu_send(request); pdu_delete(request); - response = login_receive(conn); + response = login_receive(&conn->conn); response_keys = keys_new(); keys_load(response_keys, response); @@ -875,14 +879,14 @@ } if (strcmp(auth_method, "CHAP") != 0) { - fail(conn, "Unsupported AuthMethod"); + fail(&conn->conn, "Unsupported AuthMethod"); log_errx(1, "received response " "with unsupported AuthMethod \"%s\"", auth_method); } if (conn->conn_conf.isc_user[0] == '\0' || conn->conn_conf.isc_secret[0] == '\0') { - fail(conn, "Authentication required"); + fail(&conn->conn, "Authentication required"); log_errx(1, "target requests CHAP authentication, but we don't " "have user and secret"); } diff --git a/usr.sbin/iscsid/pdu.c b/usr.sbin/iscsid/pdu.c deleted file mode 100644 --- a/usr.sbin/iscsid/pdu.c +++ /dev/null @@ -1,309 +0,0 @@ -/*- - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include "iscsid.h" -#include "iscsi_proto.h" - -#ifdef ICL_KERNEL_PROXY -#include -#endif - -static int -pdu_ahs_length(const struct pdu *pdu) -{ - - return (pdu->pdu_bhs->bhs_total_ahs_len * 4); -} - -static int -pdu_data_segment_length(const struct pdu *pdu) -{ - uint32_t len = 0; - - len += pdu->pdu_bhs->bhs_data_segment_len[0]; - len <<= 8; - len += pdu->pdu_bhs->bhs_data_segment_len[1]; - len <<= 8; - len += pdu->pdu_bhs->bhs_data_segment_len[2]; - - return (len); -} - -static void -pdu_set_data_segment_length(struct pdu *pdu, uint32_t len) -{ - - pdu->pdu_bhs->bhs_data_segment_len[2] = len; - pdu->pdu_bhs->bhs_data_segment_len[1] = len >> 8; - pdu->pdu_bhs->bhs_data_segment_len[0] = len >> 16; -} - -struct pdu * -pdu_new(struct connection *conn) -{ - struct pdu *pdu; - - pdu = calloc(1, sizeof(*pdu)); - if (pdu == NULL) - log_err(1, "calloc"); - - pdu->pdu_bhs = calloc(1, sizeof(*pdu->pdu_bhs)); - if (pdu->pdu_bhs == NULL) - log_err(1, "calloc"); - - pdu->pdu_connection = conn; - - return (pdu); -} - -struct pdu * -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; - struct iscsi_daemon_receive *idr; - size_t len; - int error; - - conn = pdu->pdu_connection; - assert(conn->conn_conf.isc_iser != 0); - - pdu->pdu_data = malloc(conn->conn_max_recv_data_segment_length); - if (pdu->pdu_data == NULL) - log_err(1, "malloc"); - - idr = calloc(1, sizeof(*idr)); - if (idr == NULL) - log_err(1, "calloc"); - - idr->idr_session_id = conn->conn_session_id; - idr->idr_bhs = pdu->pdu_bhs; - idr->idr_data_segment_len = conn->conn_max_recv_data_segment_length; - idr->idr_data_segment = pdu->pdu_data; - - error = ioctl(conn->conn_iscsi_fd, ISCSIDRECEIVE, idr); - if (error != 0) - log_err(1, "ISCSIDRECEIVE"); - - 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; - - free(idr); -} - -static void -pdu_send_proxy(struct pdu *pdu) -{ - struct connection *conn; - struct iscsi_daemon_send *ids; - int error; - - conn = pdu->pdu_connection; - assert(conn->conn_conf.isc_iser != 0); - - pdu_set_data_segment_length(pdu, pdu->pdu_data_len); - - ids = calloc(1, sizeof(*ids)); - if (ids == NULL) - log_err(1, "calloc"); - - ids->ids_session_id = conn->conn_session_id; - ids->ids_bhs = pdu->pdu_bhs; - ids->ids_data_segment_len = pdu->pdu_data_len; - ids->ids_data_segment = pdu->pdu_data; - - error = ioctl(conn->conn_iscsi_fd, ISCSIDSEND, ids); - if (error != 0) - log_err(1, "ISCSIDSEND"); - - free(ids); -} - -#endif /* ICL_KERNEL_PROXY */ - -static size_t -pdu_padding(const struct pdu *pdu) -{ - - if ((pdu->pdu_data_len % 4) != 0) - return (4 - (pdu->pdu_data_len % 4)); - - return (0); -} - -static void -pdu_read(const struct connection *conn, char *data, size_t len) -{ - ssize_t ret; - - while (len > 0) { - ret = read(conn->conn_socket, data, len); - if (ret < 0) { - if (timed_out()) { - fail(conn, "Login Phase timeout"); - log_errx(1, "exiting due to timeout"); - } - fail(conn, strerror(errno)); - log_err(1, "read"); - } else if (ret == 0) { - fail(conn, "connection lost"); - log_errx(1, "read: connection lost"); - } - len -= ret; - data += ret; - } -} - -void -pdu_receive(struct pdu *pdu) -{ - struct connection *conn; - size_t len, padding; - char dummy[4]; - - conn = pdu->pdu_connection; -#ifdef ICL_KERNEL_PROXY - if (conn->conn_conf.isc_iser != 0) - return (pdu_receive_proxy(pdu)); -#endif - assert(conn->conn_conf.isc_iser == 0); - - pdu_read(conn, (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs)); - - len = pdu_ahs_length(pdu); - if (len > 0) - log_errx(1, "protocol error: non-empty AHS"); - - len = pdu_data_segment_length(pdu); - if (len > 0) { - if (len > (size_t)conn->conn_max_recv_data_segment_length) { - log_errx(1, "protocol error: received PDU " - "with DataSegmentLength exceeding %d", - conn->conn_max_recv_data_segment_length); - } - - pdu->pdu_data_len = len; - pdu->pdu_data = malloc(len); - if (pdu->pdu_data == NULL) - log_err(1, "malloc"); - - 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, (char *)dummy, padding); - } - } -} - -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; - - conn = pdu->pdu_connection; -#ifdef ICL_KERNEL_PROXY - if (conn->conn_conf.isc_iser != 0) - return (pdu_send_proxy(pdu)); -#endif - - assert(conn->conn_conf.isc_iser == 0); - - pdu_set_data_segment_length(pdu, pdu->pdu_data_len); - iov[0].iov_base = pdu->pdu_bhs; - iov[0].iov_len = sizeof(*pdu->pdu_bhs); - total_len = iov[0].iov_len; - iovcnt = 1; - - if (pdu->pdu_data_len > 0) { - iov[1].iov_base = pdu->pdu_data; - iov[1].iov_len = pdu->pdu_data_len; - total_len += iov[1].iov_len; - iovcnt = 2; - - padding = pdu_padding(pdu); - if (padding > 0) { - assert(padding < sizeof(zero)); - iov[2].iov_base = &zero; - iov[2].iov_len = padding; - total_len += iov[2].iov_len; - iovcnt = 3; - } - } - - ret = writev(conn->conn_socket, iov, iovcnt); - if (ret < 0) { - if (timed_out()) - log_errx(1, "exiting due to timeout"); - log_err(1, "writev"); - } - if (ret != total_len) - log_errx(1, "short write"); -} - -void -pdu_delete(struct pdu *pdu) -{ - - free(pdu->pdu_data); - free(pdu->pdu_bhs); - free(pdu); -}