Blame SOURCES/0039-iscsiadm-Add-support-to-set-CHAP-entry-using-host-ch.patch

786c6d
From 062718a9579a10ea7c87e46162f80e3f57e80b67 Mon Sep 17 00:00:00 2001
786c6d
From: Adheer Chandravanshi <adheer.chandravanshi@qlogic.com>
786c6d
Date: Tue, 17 Sep 2013 08:07:32 -0400
786c6d
Subject: [PATCH] iscsiadm: Add support to set CHAP entry using host chap mode
786c6d
786c6d
Provide support to add and update CHAP entry using chap submode of
786c6d
iscsiadm host mode.
786c6d
Both, new and update, iscsiadm operations perform the same function.
786c6d
Currently only one entry can be added or updated at a time.
786c6d
786c6d
Signed-off-by: Adheer Chandravanshi <adheer.chandravanshi@qlogic.com>
786c6d
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
786c6d
---
786c6d
 include/iscsi_if.h |  19 ++++-
786c6d
 usr/host.c         | 110 ++++++++++++++++++++++++++++
786c6d
 usr/host.h         |   1 +
786c6d
 usr/idbm.c         |   8 ++-
786c6d
 usr/idbm.h         |   1 +
786c6d
 usr/iscsi_ipc.h    |   3 +
786c6d
 usr/iscsiadm.c     | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++---
786c6d
 usr/netlink.c      |  25 +++++++
786c6d
 8 files changed, 360 insertions(+), 14 deletions(-)
786c6d
786c6d
diff --git a/include/iscsi_if.h b/include/iscsi_if.h
786c6d
index 01d38e7..0284662 100644
786c6d
--- a/include/iscsi_if.h
786c6d
+++ b/include/iscsi_if.h
786c6d
@@ -74,8 +74,9 @@ enum iscsi_uevent_e {
786c6d
 	ISCSI_UEVENT_LOGIN_FLASHNODE	= UEVENT_BASE + 28,
786c6d
 	ISCSI_UEVENT_LOGOUT_FLASHNODE	= UEVENT_BASE + 29,
786c6d
 	ISCSI_UEVENT_LOGOUT_FLASHNODE_SID	= UEVENT_BASE + 30,
786c6d
+	ISCSI_UEVENT_SET_CHAP		= UEVENT_BASE + 31,
786c6d
 
786c6d
-	ISCSI_UEVENT_MAX		= ISCSI_UEVENT_LOGOUT_FLASHNODE_SID,
786c6d
+	ISCSI_UEVENT_MAX		= ISCSI_UEVENT_SET_CHAP,
786c6d
 
786c6d
 	/* up events */
786c6d
 	ISCSI_KEVENT_RECV_PDU		= KEVENT_BASE + 1,
786c6d
@@ -318,8 +319,16 @@ enum iscsi_param_type {
786c6d
 	ISCSI_HOST_PARAM,	/* iscsi_host_param */
786c6d
 	ISCSI_NET_PARAM,	/* iscsi_net_param */
786c6d
 	ISCSI_FLASHNODE_PARAM,	/* iscsi_flashnode_param */
786c6d
+	ISCSI_CHAP_PARAM,	/* iscsi_chap_param */
786c6d
 };
786c6d
 
786c6d
+/* structure for minimalist usecase */
786c6d
+struct iscsi_param_info {
786c6d
+	uint32_t len;		/* Actual length of the param value */
786c6d
+	uint16_t param;		/* iscsi param */
786c6d
+	uint8_t value[0];	/* length sized value follows */
786c6d
+} __attribute__((__packed__));
786c6d
+
786c6d
 struct iscsi_iface_param_info {
786c6d
 	uint32_t iface_num;	/* iface number, 0 - n */
786c6d
 	uint32_t len;		/* Actual length of the param */
786c6d
@@ -748,6 +757,14 @@ enum chap_type_e {
786c6d
 	CHAP_TYPE_IN,
786c6d
 };
786c6d
 
786c6d
+enum iscsi_chap_param {
786c6d
+	ISCSI_CHAP_PARAM_INDEX,
786c6d
+	ISCSI_CHAP_PARAM_CHAP_TYPE,
786c6d
+	ISCSI_CHAP_PARAM_USERNAME,
786c6d
+	ISCSI_CHAP_PARAM_PASSWORD,
786c6d
+	ISCSI_CHAP_PARAM_PASSWORD_LEN
786c6d
+};
786c6d
+
786c6d
 #define ISCSI_CHAP_AUTH_NAME_MAX_LEN	256
786c6d
 #define ISCSI_CHAP_AUTH_SECRET_MAX_LEN	256
786c6d
 struct iscsi_chap_rec {
786c6d
diff --git a/usr/host.c b/usr/host.c
786c6d
index 1fcb350..f2052d3 100644
786c6d
--- a/usr/host.c
786c6d
+++ b/usr/host.c
786c6d
@@ -34,6 +34,7 @@
786c6d
 #include "initiator.h"
786c6d
 #include "iface.h"
786c6d
 #include "iscsi_err.h"
786c6d
+#include "iscsi_netlink.h"
786c6d
 
786c6d
 static int match_host_to_session(void *data, struct session_info *info)
786c6d
 {
786c6d
@@ -314,3 +315,112 @@ int host_info_print(int info_level, uint32_t host_no)
786c6d
 	}
786c6d
 	return 0;
786c6d
 }
786c6d
+
786c6d
+static int chap_fill_param_uint(struct iovec *iov, int param,
786c6d
+				uint32_t param_val, int param_len)
786c6d
+{
786c6d
+	struct iscsi_param_info *param_info;
786c6d
+	struct nlattr *attr;
786c6d
+	int len;
786c6d
+	uint8_t val8 = 0;
786c6d
+	uint16_t val16 = 0;
786c6d
+	uint32_t val32 = 0;
786c6d
+	char *val = NULL;
786c6d
+
786c6d
+	len = sizeof(struct iscsi_param_info) + param_len;
786c6d
+	iov->iov_base = iscsi_nla_alloc(param, len);
786c6d
+	if (!iov->iov_base)
786c6d
+		return 1;
786c6d
+
786c6d
+	attr = iov->iov_base;
786c6d
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
786c6d
+
786c6d
+	param_info = (struct iscsi_param_info *)ISCSI_NLA_DATA(attr);
786c6d
+	param_info->param = param;
786c6d
+	param_info->len = param_len;
786c6d
+
786c6d
+	switch (param_len) {
786c6d
+	case 1:
786c6d
+		val8 = (uint8_t)param_val;
786c6d
+		val = (char *)&val;;
786c6d
+		break;
786c6d
+
786c6d
+	case 2:
786c6d
+		val16 = (uint16_t)param_val;
786c6d
+		val = (char *)&val16;
786c6d
+		break;
786c6d
+
786c6d
+	case 4:
786c6d
+		val32 = (uint32_t)param_val;
786c6d
+		val = (char *)&val32;
786c6d
+		break;
786c6d
+
786c6d
+	default:
786c6d
+		goto free;
786c6d
+	}
786c6d
+	memcpy(param_info->value, val, param_len);
786c6d
+
786c6d
+	return 0;
786c6d
+
786c6d
+free:
786c6d
+	free(iov->iov_base);
786c6d
+	iov->iov_base = NULL;
786c6d
+	iov->iov_len = 0;
786c6d
+	return 1;
786c6d
+}
786c6d
+
786c6d
+static int chap_fill_param_str(struct iovec *iov, int param, char *param_val,
786c6d
+			       int param_len)
786c6d
+{
786c6d
+	struct iscsi_param_info *param_info;
786c6d
+	struct nlattr *attr;
786c6d
+	int len;
786c6d
+
786c6d
+	len = sizeof(struct iscsi_param_info) + param_len;
786c6d
+	iov->iov_base = iscsi_nla_alloc(param, len);
786c6d
+	if (!iov->iov_base)
786c6d
+		return 1;
786c6d
+
786c6d
+	attr = iov->iov_base;
786c6d
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
786c6d
+
786c6d
+	param_info = (struct iscsi_param_info *)ISCSI_NLA_DATA(attr);
786c6d
+	param_info->param = param;
786c6d
+	param_info->len = param_len;
786c6d
+	memcpy(param_info->value, param_val, param_len);
786c6d
+	return 0;
786c6d
+}
786c6d
+
786c6d
+int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs)
786c6d
+{
786c6d
+	struct iovec *iov = NULL;
786c6d
+	int count = 0;
786c6d
+
786c6d
+	/* start at 2, because 0 is for nlmsghdr and 1 for event */
786c6d
+	iov = iovs + 2;
786c6d
+
786c6d
+	if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_INDEX,
786c6d
+				  crec->chap_tbl_idx,
786c6d
+				  sizeof(crec->chap_tbl_idx)))
786c6d
+		count++;
786c6d
+
786c6d
+	if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_CHAP_TYPE,
786c6d
+				  crec->chap_type, sizeof(crec->chap_type)))
786c6d
+		count++;
786c6d
+
786c6d
+	if (!chap_fill_param_str(&iov[count], ISCSI_CHAP_PARAM_USERNAME,
786c6d
+				 crec->username, strlen(crec->username)))
786c6d
+		count++;
786c6d
+
786c6d
+	if (!chap_fill_param_str(&iov[count], ISCSI_CHAP_PARAM_PASSWORD,
786c6d
+				 (char *)crec->password,
786c6d
+				 strlen((char *)crec->password)))
786c6d
+		count++;
786c6d
+
786c6d
+	if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_PASSWORD_LEN,
786c6d
+				  crec->password_length,
786c6d
+				  sizeof(crec->password_length)))
786c6d
+		count++;
786c6d
+
786c6d
+	return count;
786c6d
+}
786c6d
diff --git a/usr/host.h b/usr/host.h
786c6d
index 52e5b9e..149aa0d 100644
786c6d
--- a/usr/host.h
786c6d
+++ b/usr/host.h
786c6d
@@ -17,5 +17,6 @@ struct host_info {
786c6d
 };
786c6d
 
786c6d
 extern int host_info_print(int info_level, uint32_t host_no);
786c6d
+extern int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs);
786c6d
 
786c6d
 #endif
786c6d
diff --git a/usr/idbm.c b/usr/idbm.c
786c6d
index 1e4f8c8..6b6f57c 100644
786c6d
--- a/usr/idbm.c
786c6d
+++ b/usr/idbm.c
786c6d
@@ -456,7 +456,7 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
786c6d
 	__recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1);
786c6d
 }
786c6d
 
786c6d
-static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
786c6d
+void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
786c6d
 {
786c6d
 	int num = 0;
786c6d
 
786c6d
@@ -465,14 +465,14 @@ static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
786c6d
 
786c6d
 	if (r->chap_type == CHAP_TYPE_OUT) {
786c6d
 		__recinfo_str(HOST_AUTH_USERNAME, ri, r, username, IDBM_SHOW,
786c6d
-			      num, 0);
786c6d
+			      num, 1);
786c6d
 		__recinfo_str(HOST_AUTH_PASSWORD, ri, r, password, IDBM_MASKED,
786c6d
 			      num, 1);
786c6d
 		__recinfo_int(HOST_AUTH_PASSWORD_LEN, ri, r, password_length,
786c6d
 			      IDBM_HIDE, num, 1);
786c6d
 	} else {
786c6d
 		__recinfo_str(HOST_AUTH_USERNAME_IN, ri, r, username, IDBM_SHOW,
786c6d
-			      num, 0);
786c6d
+			      num, 1);
786c6d
 		__recinfo_str(HOST_AUTH_PASSWORD_IN, ri, r, password,
786c6d
 			      IDBM_MASKED, num, 1);
786c6d
 		__recinfo_int(HOST_AUTH_PASSWORD_IN_LEN, ri, r, password_length,
786c6d
@@ -852,6 +852,8 @@ updated:
786c6d
 	check_password_param(discovery.sendtargets.auth.password_in);
786c6d
 	check_password_param(discovery.slp.auth.password);
786c6d
 	check_password_param(discovery.slp.auth.password_in);
786c6d
+	check_password_param(host.auth.password);
786c6d
+	check_password_param(host.auth.password_in);
786c6d
 
786c6d
 	return 0;
786c6d
 }
786c6d
diff --git a/usr/idbm.h b/usr/idbm.h
786c6d
index 5e4038d..b9020fe 100644
786c6d
--- a/usr/idbm.h
786c6d
+++ b/usr/idbm.h
786c6d
@@ -185,6 +185,7 @@ extern struct node_rec *
786c6d
 idbm_create_rec_from_boot_context(struct boot_context *context);
786c6d
 
786c6d
 extern int idbm_print_host_chap_info(struct iscsi_chap_rec *chap);
786c6d
+extern void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri);
786c6d
 
786c6d
 extern int idbm_print_flashnode_info(struct flashnode_rec *target);
786c6d
 extern void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri);
786c6d
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
786c6d
index b6665cb..a32da1c 100644
786c6d
--- a/usr/iscsi_ipc.h
786c6d
+++ b/usr/iscsi_ipc.h
786c6d
@@ -143,6 +143,9 @@ struct iscsi_ipc {
786c6d
 			 uint16_t chap_tbl_idx, uint32_t num_entries,
786c6d
 			 char *chap_buf, uint32_t *valid_chap_entries);
786c6d
 
786c6d
+	int (*set_chap) (uint64_t transport_handle, uint32_t host_no,
786c6d
+			 struct iovec *iovs, uint32_t param_count);
786c6d
+
786c6d
 	int (*delete_chap) (uint64_t transport_handle, uint32_t host_no,
786c6d
 			    uint16_t chap_tbl_idx);
786c6d
 	int (*set_flash_node_params) (uint64_t transport_handle,
786c6d
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
786c6d
index beabdf0..045259b 100644
786c6d
--- a/usr/iscsiadm.c
786c6d
+++ b/usr/iscsiadm.c
786c6d
@@ -115,7 +115,7 @@ static struct option const long_options[] =
786c6d
 	{"packetsize", required_argument, NULL, 'b'},
786c6d
 	{"count", required_argument, NULL, 'c'},
786c6d
 	{"interval", required_argument, NULL, 'i'},
786c6d
-	{"index", optional_argument, NULL, 'x'},
786c6d
+	{"index", required_argument, NULL, 'x'},
786c6d
 	{"portal_type", optional_argument, NULL, 'A'},
786c6d
 	{NULL, 0, NULL, 0},
786c6d
 };
786c6d
@@ -1426,11 +1426,193 @@ exit_chap_info:
786c6d
 	return rc;
786c6d
 }
786c6d
 
786c6d
+static int fill_host_chap_rec(struct list_head *params,
786c6d
+			      struct iscsi_chap_rec *crec, recinfo_t *cinfo,
786c6d
+			      uint16_t chap_tbl_idx, int type, int *param_count)
786c6d
+{
786c6d
+	struct user_param *param;
786c6d
+	int rc = 0;
786c6d
+
786c6d
+	crec->chap_tbl_idx = chap_tbl_idx;
786c6d
+	crec->chap_type = type;
786c6d
+
786c6d
+	idbm_recinfo_host_chap(crec, cinfo);
786c6d
+
786c6d
+	list_for_each_entry(param, params, list) {
786c6d
+		rc = idbm_rec_update_param(cinfo, param->name, param->value, 0);
786c6d
+		if (rc)
786c6d
+			break;
786c6d
+	}
786c6d
+
786c6d
+	if (!rc)
786c6d
+		*param_count += 3; /* index, type and password_length */
786c6d
+
786c6d
+	return rc;
786c6d
+}
786c6d
+
786c6d
+static int verify_host_chap_params(struct list_head *params, int *type,
786c6d
+				   int *param_count)
786c6d
+{
786c6d
+	struct user_param *param;
786c6d
+	int username = -1;
786c6d
+	int password = -1;
786c6d
+	int rc = 0;
786c6d
+
786c6d
+	list_for_each_entry(param, params, list) {
786c6d
+		*param_count += 1;
786c6d
+
786c6d
+		if (!strcmp(param->name, HOST_AUTH_USERNAME))
786c6d
+			username = CHAP_TYPE_OUT;
786c6d
+		else if (!strcmp(param->name, HOST_AUTH_PASSWORD))
786c6d
+			password = CHAP_TYPE_OUT;
786c6d
+		else if (!strcmp(param->name, HOST_AUTH_USERNAME_IN))
786c6d
+			username = CHAP_TYPE_IN;
786c6d
+		else if (!strcmp(param->name, HOST_AUTH_PASSWORD_IN))
786c6d
+			password = CHAP_TYPE_IN;
786c6d
+		else
786c6d
+			continue;
786c6d
+	}
786c6d
+
786c6d
+	if ((username == CHAP_TYPE_OUT) && (password == CHAP_TYPE_OUT)) {
786c6d
+		if (type)
786c6d
+			*type = CHAP_TYPE_OUT;
786c6d
+
786c6d
+		rc = ISCSI_SUCCESS;
786c6d
+	} else if ((username == CHAP_TYPE_IN) && (password == CHAP_TYPE_IN)) {
786c6d
+		if (type)
786c6d
+			*type = CHAP_TYPE_IN;
786c6d
+
786c6d
+		rc = ISCSI_SUCCESS;
786c6d
+	} else {
786c6d
+		rc = ISCSI_ERR;
786c6d
+	}
786c6d
+
786c6d
+	return rc;
786c6d
+}
786c6d
+
786c6d
+static int set_host_chap_info(uint32_t host_no, uint64_t chap_index,
786c6d
+			      struct list_head *params)
786c6d
+{
786c6d
+	struct iscsi_transport *t = NULL;
786c6d
+	struct iscsi_chap_rec crec;
786c6d
+	recinfo_t *chap_info = NULL;
786c6d
+	struct iovec *iovs = NULL;
786c6d
+	struct iovec *iov = NULL;
786c6d
+	int type;
786c6d
+	int param_count;
786c6d
+	int param_used;
786c6d
+	int rc = 0;
786c6d
+	int fd, i = 0;
786c6d
+
786c6d
+	if (list_empty(params)) {
786c6d
+		log_error("Chap username/password not provided.");
786c6d
+		goto exit_set_chap;
786c6d
+	}
786c6d
+
786c6d
+	chap_info = idbm_recinfo_alloc(MAX_KEYS);
786c6d
+	if (!chap_info) {
786c6d
+		log_error("Out of Memory.");
786c6d
+		rc = ISCSI_ERR_NOMEM;
786c6d
+		goto exit_set_chap;
786c6d
+	}
786c6d
+
786c6d
+	t = iscsi_sysfs_get_transport_by_hba(host_no);
786c6d
+	if (!t) {
786c6d
+		log_error("Could not match hostno %d to transport.", host_no);
786c6d
+		rc = ISCSI_ERR_TRANS_NOT_FOUND;
786c6d
+		goto free_info_rec;
786c6d
+	}
786c6d
+
786c6d
+	rc = verify_host_chap_params(params, &type, &param_count);
786c6d
+	if (rc) {
786c6d
+		log_error("Invalid username/password pair passed. Unable to determine the type of chap entry");
786c6d
+		rc = ISCSI_ERR_INVAL;
786c6d
+		goto free_info_rec;
786c6d
+	}
786c6d
+
786c6d
+	if (param_count > 2) {
786c6d
+		log_error("Only one pair of username/password can be passed.");
786c6d
+		rc = ISCSI_ERR;
786c6d
+		goto free_info_rec;
786c6d
+	}
786c6d
+
786c6d
+	memset(&crec, 0, sizeof(crec));
786c6d
+	rc = fill_host_chap_rec(params, &crec, chap_info, chap_index, type,
786c6d
+				&param_count);
786c6d
+	if (rc) {
786c6d
+		log_error("Unable to fill CHAP record");
786c6d
+		goto free_info_rec;
786c6d
+	}
786c6d
+
786c6d
+	/* +2 for event and nlmsghdr */
786c6d
+	param_count += 2;
786c6d
+	iovs = calloc((param_count * sizeof(struct iovec)),
786c6d
+		       sizeof(char));
786c6d
+	if (!iovs) {
786c6d
+		log_error("Out of Memory.");
786c6d
+		rc = ISCSI_ERR_NOMEM;
786c6d
+		goto free_info_rec;
786c6d
+	}
786c6d
+
786c6d
+	/* param_used gives actual number of iovecs used for chap */
786c6d
+	param_used = chap_build_config(&crec, iovs);
786c6d
+	if (!param_used) {
786c6d
+		log_error("Build chap config failed.");
786c6d
+		rc = ISCSI_ERR;
786c6d
+		goto free_iovec;
786c6d
+	}
786c6d
+
786c6d
+	fd = ipc->ctldev_open();
786c6d
+	if (fd < 0) {
786c6d
+		rc = ISCSI_ERR_INTERNAL;
786c6d
+		log_error("Netlink open failed.");
786c6d
+		goto free_iovec;
786c6d
+	}
786c6d
+
786c6d
+	rc = ipc->set_chap(t->handle, host_no, iovs, param_count);
786c6d
+	if (rc < 0) {
786c6d
+		log_error("CHAP setting failed");
786c6d
+		if (rc == -EBUSY) {
786c6d
+			rc = ISCSI_ERR_BUSY;
786c6d
+			log_error("CHAP index %d is in use.",
786c6d
+				  crec.chap_tbl_idx);
786c6d
+		} else {
786c6d
+			rc = ISCSI_ERR;
786c6d
+		}
786c6d
+
786c6d
+		goto exit_set_chap;
786c6d
+	}
786c6d
+
786c6d
+	ipc->ctldev_close();
786c6d
+
786c6d
+free_iovec:
786c6d
+	/* start at 2, because 0 is for nlmsghdr and 1 for event */
786c6d
+	iov = iovs + 2;
786c6d
+	for (i = 0; i < param_used; i++, iov++) {
786c6d
+		if (iov->iov_base)
786c6d
+			free(iov->iov_base);
786c6d
+	}
786c6d
+
786c6d
+	free(iovs);
786c6d
+
786c6d
+free_info_rec:
786c6d
+	if (chap_info)
786c6d
+		free(chap_info);
786c6d
+
786c6d
+exit_set_chap:
786c6d
+	return rc;
786c6d
+}
786c6d
+
786c6d
 static int delete_host_chap_info(uint32_t host_no, uint16_t chap_tbl_idx)
786c6d
 {
786c6d
 	struct iscsi_transport *t = NULL;
786c6d
 	int fd, rc = 0;
786c6d
 
786c6d
+	if (chap_tbl_idx > MAX_CHAP_ENTRIES) {
786c6d
+		log_error("Invalid chap table index.");
786c6d
+		goto exit_delete_chap;
786c6d
+	}
786c6d
+
786c6d
 	t = iscsi_sysfs_get_transport_by_hba(host_no);
786c6d
 	if (!t) {
786c6d
 		log_error("Could not match hostno %d to "
786c6d
@@ -1464,19 +1646,18 @@ exit_delete_chap:
786c6d
 }
786c6d
 
786c6d
 static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
786c6d
-			     uint64_t chap_index)
786c6d
+			     uint64_t chap_index, struct list_head *params)
786c6d
 {
786c6d
 	int rc = ISCSI_ERR_INVAL;
786c6d
 
786c6d
-	if (op != OP_SHOW && (chap_index > (uint64_t)MAX_CHAP_ENTRIES)) {
786c6d
-		log_error("Invalid chap table index.");
786c6d
-		goto exit_chap_op;
786c6d
-	}
786c6d
-
786c6d
 	switch (op) {
786c6d
 	case OP_SHOW:
786c6d
 		rc = get_host_chap_info(host_no);
786c6d
 		break;
786c6d
+	case OP_NEW:
786c6d
+	case OP_UPDATE:
786c6d
+		rc = set_host_chap_info(host_no, chap_index, params);
786c6d
+		break;
786c6d
 	case OP_DELETE:
786c6d
 		rc = delete_host_chap_info(host_no, chap_index);
786c6d
 		break;
786c6d
@@ -1485,7 +1666,6 @@ static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
786c6d
 		break;
786c6d
 	}
786c6d
 
786c6d
-exit_chap_op:
786c6d
 	return rc;
786c6d
 }
786c6d
 
786c6d
@@ -2816,7 +2996,7 @@ main(int argc, char **argv)
786c6d
 	struct iface_rec *iface = NULL, *tmp;
786c6d
 	struct node_rec *rec = NULL;
786c6d
 	uint64_t host_no =  (uint64_t)MAX_HOST_NO + 1;
786c6d
-	uint64_t index = (uint64_t)MAX_FLASHNODE_IDX + 1;
786c6d
+	uint64_t index = ULLONG_MAX;
786c6d
 	struct user_param *param;
786c6d
 	struct list_head params;
786c6d
 
786c6d
@@ -3038,8 +3218,12 @@ main(int argc, char **argv)
786c6d
 					rc = ISCSI_ERR_INVAL;
786c6d
 					break;
786c6d
 				}
786c6d
+
786c6d
+				if (index == ULLONG_MAX)
786c6d
+					index = (uint64_t)MAX_CHAP_ENTRIES + 1;
786c6d
+
786c6d
 				rc = exec_host_chap_op(op, info_level, host_no,
786c6d
-						       index);
786c6d
+						       index, &params);
786c6d
 				break;
786c6d
 			case MODE_FLASHNODE:
786c6d
 				if (host_no > MAX_HOST_NO) {
786c6d
@@ -3048,6 +3232,9 @@ main(int argc, char **argv)
786c6d
 					break;
786c6d
 				}
786c6d
 
786c6d
+				if (index == ULLONG_MAX)
786c6d
+					index = (uint64_t)MAX_FLASHNODE_IDX + 1;
786c6d
+
786c6d
 				rc = exec_flashnode_op(op, info_level, host_no,
786c6d
 						       index, portal_type,
786c6d
 						       &params);
786c6d
diff --git a/usr/netlink.c b/usr/netlink.c
786c6d
index c07fe3c..151b56d 100644
786c6d
--- a/usr/netlink.c
786c6d
+++ b/usr/netlink.c
786c6d
@@ -1228,6 +1228,30 @@ static int kget_chap(uint64_t transport_handle, uint32_t host_no,
786c6d
 	return rc;
786c6d
 }
786c6d
 
786c6d
+static int kset_chap(uint64_t transport_handle, uint32_t host_no,
786c6d
+			struct iovec *iovs, uint32_t param_count)
786c6d
+{
786c6d
+	int rc, ev_len;
786c6d
+	struct iscsi_uevent ev;
786c6d
+	struct iovec *iov = iovs + 1;
786c6d
+
786c6d
+	log_debug(8, "in %s", __func__);
786c6d
+
786c6d
+	ev_len = sizeof(ev);
786c6d
+	ev.type = ISCSI_UEVENT_SET_CHAP;
786c6d
+	ev.transport_handle = transport_handle;
786c6d
+	ev.u.set_path.host_no = host_no;
786c6d
+
786c6d
+	iov->iov_base = &ev;
786c6d
+	iov->iov_len = sizeof(ev);
786c6d
+
786c6d
+	rc = __kipc_call(iovs, param_count);
786c6d
+	if (rc < 0)
786c6d
+		return rc;
786c6d
+
786c6d
+	return 0;
786c6d
+}
786c6d
+
786c6d
 static int kdelete_chap(uint64_t transport_handle, uint32_t host_no,
786c6d
 			uint16_t chap_tbl_idx)
786c6d
 {
786c6d
@@ -1705,6 +1729,7 @@ struct iscsi_ipc nl_ipc = {
786c6d
 	.recv_conn_state        = krecv_conn_state,
786c6d
 	.exec_ping		= kexec_ping,
786c6d
 	.get_chap		= kget_chap,
786c6d
+	.set_chap		= kset_chap,
786c6d
 	.delete_chap		= kdelete_chap,
786c6d
 	.set_flash_node_params	= kset_flashnode_params,
786c6d
 	.new_flash_node		= knew_flashnode,
786c6d
-- 
786c6d
1.8.3.1
786c6d