summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/iscsi_err.h2
-rw-r--r--include/iscsi_if.h32
-rw-r--r--usr/host.h3
-rw-r--r--usr/idbm.c34
-rw-r--r--usr/idbm.h3
-rw-r--r--usr/idbm_fields.h10
-rw-r--r--usr/iscsi_err.c1
-rw-r--r--usr/iscsi_ipc.h7
-rw-r--r--usr/iscsiadm.c165
-rw-r--r--usr/netlink.c80
10 files changed, 333 insertions, 4 deletions
diff --git a/include/iscsi_err.h b/include/iscsi_err.h
index e038f1c..aabea4e 100644
--- a/include/iscsi_err.h
+++ b/include/iscsi_err.h
@@ -60,6 +60,8 @@ enum {
ISCSI_ERR_ISNS_REG_FAILED = 26,
/* operation not supported */
ISCSI_ERR_OP_NOT_SUPP = 27,
+ /* device or resource in use */
+ ISCSI_ERR_BUSY = 28,
/* Always last. Indicates end of error code space */
ISCSI_MAX_ERR_VAL,
diff --git a/include/iscsi_if.h b/include/iscsi_if.h
index 26182aa..ce9ba15 100644
--- a/include/iscsi_if.h
+++ b/include/iscsi_if.h
@@ -66,8 +66,10 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_PATH_UPDATE = UEVENT_BASE + 20,
ISCSI_UEVENT_SET_IFACE_PARAMS = UEVENT_BASE + 21,
ISCSI_UEVENT_PING = UEVENT_BASE + 22,
+ ISCSI_UEVENT_GET_CHAP = UEVENT_BASE + 23,
+ ISCSI_UEVENT_DELETE_CHAP = UEVENT_BASE + 24,
- ISCSI_UEVENT_MAX = ISCSI_UEVENT_PING,
+ ISCSI_UEVENT_MAX = ISCSI_UEVENT_DELETE_CHAP,
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
@@ -205,6 +207,18 @@ struct iscsi_uevent {
uint32_t pid; /* unique ping id associated
with each ping request */
} iscsi_ping;
+ struct msg_get_chap {
+ uint32_t host_no;
+ uint32_t num_entries; /* number of CHAP entries
+ * on request, number of
+ * valid CHAP entries on
+ * response */
+ uint16_t chap_tbl_idx;
+ } get_chap;
+ struct msg_delete_chap {
+ uint32_t host_no;
+ uint16_t chap_tbl_idx;
+ } delete_chap;
} u;
union {
/* messages k -> u */
@@ -583,4 +597,20 @@ struct iscsi_stats {
__attribute__ ((aligned (sizeof(uint64_t))));
};
+enum chap_type_e {
+ CHAP_TYPE_OUT,
+ CHAP_TYPE_IN,
+};
+
+#define ISCSI_CHAP_AUTH_NAME_MAX_LEN 256
+#define ISCSI_CHAP_AUTH_SECRET_MAX_LEN 256
+
+struct iscsi_chap_rec {
+ uint16_t chap_tbl_idx;
+ enum chap_type_e chap_type;
+ char username[ISCSI_CHAP_AUTH_NAME_MAX_LEN];
+ uint8_t password[ISCSI_CHAP_AUTH_SECRET_MAX_LEN];
+ uint8_t password_length;
+};
+
#endif
diff --git a/usr/host.h b/usr/host.h
index a38efc9..894ab91 100644
--- a/usr/host.h
+++ b/usr/host.h
@@ -5,6 +5,9 @@
#include "types.h"
#include "config.h"
+#define MAX_CHAP_BUF_SZ 4096
+#define REQ_CHAP_BUF_SZ (MAX_CHAP_BUF_SZ + sizeof(struct iscsi_uevent))
+
struct host_info {
struct iface_rec iface;
uint32_t host_no;
diff --git a/usr/idbm.c b/usr/idbm.c
index 7ebd3d5..3f53115 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -445,6 +445,30 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
__recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1);
}
+static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
+{
+ int num = 0;
+
+ __recinfo_uint16(HOST_AUTH_INDEX, ri, r, chap_tbl_idx, IDBM_SHOW,
+ num, 1);
+
+ if (r->chap_type == CHAP_TYPE_OUT) {
+ __recinfo_str(HOST_AUTH_USERNAME, ri, r, username, IDBM_SHOW,
+ num, 0);
+ __recinfo_str(HOST_AUTH_PASSWORD, ri, r, password, IDBM_MASKED,
+ num, 1);
+ __recinfo_int(HOST_AUTH_PASSWORD_LEN, ri, r, password_length,
+ IDBM_HIDE, num, 1);
+ } else {
+ __recinfo_str(HOST_AUTH_USERNAME_IN, ri, r, username, IDBM_SHOW,
+ num, 0);
+ __recinfo_str(HOST_AUTH_PASSWORD_IN, ri, r, password,
+ IDBM_MASKED, num, 1);
+ __recinfo_int(HOST_AUTH_PASSWORD_IN_LEN, ri, r, password_length,
+ IDBM_HIDE, num, 1);
+ }
+}
+
recinfo_t *idbm_recinfo_alloc(int max_keys)
{
recinfo_t *info;
@@ -475,6 +499,9 @@ void idbm_print(int type, void *rec, int show, FILE *f)
case IDBM_PRINT_TYPE_IFACE:
idbm_recinfo_iface((struct iface_rec *)rec, info);
break;
+ case IDBM_PRINT_TYPE_HOST_CHAP:
+ idbm_recinfo_host_chap((struct iscsi_chap_rec *)rec, info);
+ break;
}
fprintf(f, "%s\n", ISCSI_BEGIN_REC);
@@ -845,6 +872,13 @@ int idbm_print_iface_info(void *data, struct iface_rec *iface)
return 0;
}
+int idbm_print_host_chap_info(struct iscsi_chap_rec *chap)
+{
+ /* User only calls this to print chap so always print */
+ idbm_print(IDBM_PRINT_TYPE_HOST_CHAP, chap, 1, stdout);
+ return 0;
+}
+
int idbm_print_node_flat(void *data, node_rec_t *rec)
{
if (strchr(rec->conn[0].address, '.'))
diff --git a/usr/idbm.h b/usr/idbm.h
index ced224d..0f8767a 100644
--- a/usr/idbm.h
+++ b/usr/idbm.h
@@ -162,6 +162,7 @@ enum {
IDBM_PRINT_TYPE_DISCOVERY,
IDBM_PRINT_TYPE_NODE,
IDBM_PRINT_TYPE_IFACE,
+ IDBM_PRINT_TYPE_HOST_CHAP,
};
extern void idbm_print(int type, void *rec, int show, FILE *f);
@@ -174,4 +175,6 @@ extern struct node_rec *idbm_create_rec(char *targetname, int tpgt,
extern struct node_rec *
idbm_create_rec_from_boot_context(struct boot_context *context);
+extern int idbm_print_host_chap_info(struct iscsi_chap_rec *chap);
+
#endif /* IDBM_H */
diff --git a/usr/idbm_fields.h b/usr/idbm_fields.h
index 269d87c..358d014 100644
--- a/usr/idbm_fields.h
+++ b/usr/idbm_fields.h
@@ -116,4 +116,14 @@
#define DISC_ISNS_ADDR "discovery.sendtargets.address"
#define DISC_ISNS_PORT "discovery.sendtargets.port"
+/* host auth fields */
+#define HOST_AUTH_INDEX "host.auth.tbl_idx"
+#define HOST_AUTH_METHOD "host.auth.authmethod"
+#define HOST_AUTH_USERNAME "host.auth.username"
+#define HOST_AUTH_PASSWORD "host.auth.password"
+#define HOST_AUTH_PASSWORD_LEN "host.auth.password_length"
+#define HOST_AUTH_USERNAME_IN "host.auth.username_in"
+#define HOST_AUTH_PASSWORD_IN "host.auth.password_in"
+#define HOST_AUTH_PASSWORD_IN_LEN "host.auth.password_in_length"
+
#endif
diff --git a/usr/iscsi_err.c b/usr/iscsi_err.c
index 4936e45..4fe1c53 100644
--- a/usr/iscsi_err.c
+++ b/usr/iscsi_err.c
@@ -50,6 +50,7 @@ static char *iscsi_err_msgs[] = {
/* 25 */ "iSNS query failed",
/* 26 */ "iSNS registration failed",
/* 27 */ "operation not supported",
+ /* 28 */ "device or resource in use",
};
char *iscsi_err_to_str(int err)
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
index a00135f..08cf6f9 100644
--- a/usr/iscsi_ipc.h
+++ b/usr/iscsi_ipc.h
@@ -138,6 +138,13 @@ struct iscsi_ipc {
int (*exec_ping) (uint64_t transport_handle, uint32_t host_no,
struct sockaddr *addr, uint32_t iface_num,
uint32_t iface_type, uint32_t size);
+
+ int (*get_chap) (uint64_t transport_handle, uint32_t host_no,
+ uint16_t chap_tbl_idx, uint32_t num_entries,
+ char *chap_buf, uint32_t *valid_chap_entries);
+
+ int (*delete_chap) (uint64_t transport_handle, uint32_t host_no,
+ uint16_t chap_tbl_idx);
};
#endif /* ISCSI_IPC_H */
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index 7ff8728..85b6774 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -67,6 +67,7 @@ enum iscsiadm_mode {
MODE_IFACE,
MODE_FW,
MODE_PING,
+ MODE_CHAP
};
enum iscsiadm_op {
@@ -191,6 +192,8 @@ str_to_submode(char *str)
if (!strcmp("ping", str))
sub_mode = MODE_PING;
+ else if (!strcmp("chap", str))
+ sub_mode = MODE_CHAP;
else
sub_mode = -1;
@@ -1297,6 +1300,146 @@ free_buf:
return ISCSI_SUCCESS;
}
+static int get_host_chap_info(uint32_t host_no)
+{
+ struct iscsi_transport *t = NULL;
+ struct iscsi_chap_rec *crec = NULL;
+ char *req_buf = NULL;
+ uint32_t valid_chap_entries;
+ uint32_t num_entries;
+ uint16_t chap_tbl_idx = 0;
+ int rc = 0;
+ int fd, i = 0;
+
+ t = iscsi_sysfs_get_transport_by_hba(host_no);
+ if (!t) {
+ log_error("Could not match hostno %d to "
+ "transport.", host_no);
+ rc = ISCSI_ERR_TRANS_NOT_FOUND;
+ goto exit_chap_info;
+ }
+
+ num_entries = MAX_CHAP_BUF_SZ / sizeof(*crec);
+
+ req_buf = calloc(1, REQ_CHAP_BUF_SZ);
+ if (!req_buf) {
+ log_error("Could not allocate memory for CHAP request.");
+ rc = ISCSI_ERR_NOMEM;
+ goto exit_chap_info;
+ }
+
+ fd = ipc->ctldev_open();
+ if (fd < 0) {
+ rc = ISCSI_ERR_INTERNAL;
+ log_error("Netlink open failed.");
+ goto exit_chap_info;
+ }
+
+get_chap:
+ memset(req_buf, 0, REQ_CHAP_BUF_SZ);
+
+ rc = ipc->get_chap(t->handle, host_no, chap_tbl_idx, num_entries,
+ req_buf, &valid_chap_entries);
+ if (rc < 0) {
+ log_error("get_chap_info failed. errno=%d", errno);
+ rc = ISCSI_ERR;
+ goto exit_chap_info;
+ }
+
+ log_info("Valid CHAP Entries = %d\n", valid_chap_entries);
+
+ crec = (struct iscsi_chap_rec *) (req_buf +
+ sizeof(struct iscsi_uevent));
+
+ if (valid_chap_entries)
+ chap_tbl_idx =
+ (crec + (valid_chap_entries - 1))->chap_tbl_idx + 1;
+
+ /* print chap info */
+ for (i = 0; i < valid_chap_entries; i++) {
+ idbm_print_host_chap_info(crec);
+ crec++;
+ }
+
+ if (valid_chap_entries != num_entries)
+ goto exit_chap_info;
+ else
+ goto get_chap;
+
+ ipc->ctldev_close();
+
+exit_chap_info:
+ if (req_buf)
+ free(req_buf);
+
+ return rc;
+}
+
+static int delete_host_chap_info(uint32_t host_no, char *value)
+{
+ struct iscsi_transport *t = NULL;
+ int fd, rc = 0;
+ uint16_t chap_tbl_idx;
+
+ if (!value) {
+ log_error("CHAP deletion requires --value=table_index.");
+ return ISCSI_ERR_INVAL;
+ }
+
+ chap_tbl_idx = (uint16_t)atoi(value);
+
+ t = iscsi_sysfs_get_transport_by_hba(host_no);
+ if (!t) {
+ log_error("Could not match hostno %d to "
+ "transport.", host_no);
+ rc = ISCSI_ERR_TRANS_NOT_FOUND;
+ goto exit_delete_chap;
+ }
+
+ fd = ipc->ctldev_open();
+ if (fd < 0) {
+ log_error("Netlink open failed.");
+ rc = ISCSI_ERR_INTERNAL;
+ goto exit_delete_chap;
+ }
+
+ log_info("Deleteing CHAP index: %d\n", chap_tbl_idx);
+ rc = ipc->delete_chap(t->handle, host_no, chap_tbl_idx);
+ if (rc < 0) {
+ log_error("CHAP Delete failed.");
+ if (rc == -EBUSY) {
+ rc = ISCSI_ERR_BUSY;
+ log_error("CHAP index %d is in use.", chap_tbl_idx);
+ } else
+ rc = ISCSI_ERR;
+ }
+
+ ipc->ctldev_close();
+
+exit_delete_chap:
+ return rc;
+}
+
+static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
+ char *value)
+{
+ int rc = ISCSI_ERR_INVAL;
+
+ switch (op) {
+ case OP_SHOW:
+ rc = get_host_chap_info(host_no);
+ break;
+ case OP_DELETE:
+ rc = delete_host_chap_info(host_no, value);
+ break;
+ default:
+ log_error("Invalid operation.");
+ break;
+ }
+
+ return rc;
+}
+
/* TODO: merge iter helpers and clean them up, so we can use them here */
static int exec_iface_op(int op, int do_show, int info_level,
struct iface_rec *iface, uint32_t host_no,
@@ -2393,14 +2536,30 @@ main(int argc, char **argv)
switch (mode) {
case MODE_HOST:
- if ((rc = verify_mode_params(argc, argv, "HdmP", 0))) {
+ if ((rc = verify_mode_params(argc, argv, "CHdmPov", 0))) {
log_error("host mode: option '-%c' is not "
"allowed/supported", rc);
rc = ISCSI_ERR_INVAL;
goto out;
}
-
- rc = host_info_print(info_level, host_no);
+ if (sub_mode != -1) {
+ switch (sub_mode) {
+ case MODE_CHAP:
+ if (!op || !host_no) {
+ log_error("CHAP mode requires host "
+ "no and valid operation");
+ rc = ISCSI_ERR_INVAL;
+ break;
+ }
+ rc = exec_host_chap_op(op, info_level, host_no,
+ value);
+ break;
+ default:
+ log_error("Invalid Sub Mode");
+ break;
+ }
+ } else
+ rc = host_info_print(info_level, host_no);
break;
case MODE_IFACE:
iface_setup_host_bindings();
diff --git a/usr/netlink.c b/usr/netlink.c
index f680b31..2556f1f 100644
--- a/usr/netlink.c
+++ b/usr/netlink.c
@@ -336,6 +336,9 @@ __kipc_call(struct iovec *iovp, int count)
} else if (ev->type == ISCSI_UEVENT_GET_STATS) {
/* kget_stats() will read */
return 0;
+ } else if (ev->type == ISCSI_UEVENT_GET_CHAP) {
+ /* kget_chap() will read */
+ return 0;
} else {
if ((rc = nlpayload_read(ctrl_fd, (void*)ev,
sizeof(*ev), 0)) < 0) {
@@ -1180,6 +1183,75 @@ close_nl:
return rc;
}
+static int kget_chap(uint64_t transport_handle, uint32_t host_no,
+ uint16_t chap_tbl_idx, uint32_t num_entries,
+ char *chap_buf, uint32_t *valid_chap_entries)
+{
+ int rc = 0;
+ int ev_size;
+ struct iscsi_uevent ev;
+ struct iovec iov[2];
+ char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
+ struct nlmsghdr *nlh;
+
+ memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+ ev.type = ISCSI_UEVENT_GET_CHAP;
+ ev.transport_handle = transport_handle;
+ ev.u.get_chap.host_no = host_no;
+ ev.u.get_chap.chap_tbl_idx = chap_tbl_idx;
+ ev.u.get_chap.num_entries = num_entries;
+
+ iov[1].iov_base = &ev;
+ iov[1].iov_len = sizeof(ev);
+ rc = __kipc_call(iov, 2);
+ if (rc < 0)
+ return rc;
+
+ if ((rc = nl_read(ctrl_fd, nlm_ev,
+ NLMSG_SPACE(sizeof(struct iscsi_uevent)),
+ MSG_PEEK)) < 0) {
+ log_error("can not read nlm_ev, error %d", rc);
+ return rc;
+ }
+
+ nlh = (struct nlmsghdr *)nlm_ev;
+ ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+
+ if ((rc = nlpayload_read(ctrl_fd, (void *)chap_buf, ev_size, 0)) < 0) {
+ log_error("can not read from NL socket, error %d", rc);
+ return rc;
+ }
+
+ *valid_chap_entries = ev.u.get_chap.num_entries;
+
+ return rc;
+}
+
+static int kdelete_chap(uint64_t transport_handle, uint32_t host_no,
+ uint16_t chap_tbl_idx)
+{
+ int rc = 0;
+ struct iscsi_uevent ev;
+ struct iovec iov[2];
+
+ memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+ ev.type = ISCSI_UEVENT_DELETE_CHAP;
+ ev.transport_handle = transport_handle;
+ ev.u.delete_chap.host_no = host_no;
+ ev.u.delete_chap.chap_tbl_idx = chap_tbl_idx;
+
+ iov[1].iov_base = &ev;
+ iov[1].iov_len = sizeof(ev);
+
+ rc = __kipc_call(iov, 2);
+ if (rc < 0)
+ return rc;
+
+ return rc;
+}
+
static void drop_data(struct nlmsghdr *nlh)
{
int ev_size;
@@ -1216,11 +1288,17 @@ static int ctldev_handle(void)
/* old kernels sent ISCSI_UEVENT_CREATE_SESSION on creation */
case ISCSI_UEVENT_CREATE_SESSION:
drop_data(nlh);
+ if (!ipc_ev_clbk)
+ return 0;
+
if (ipc_ev_clbk->create_session)
ipc_ev_clbk->create_session(ev->r.c_session_ret.host_no,
ev->r.c_session_ret.sid);
return 0;
case ISCSI_KEVENT_DESTROY_SESSION:
+ if (!ipc_ev_clbk)
+ return 0;
+
drop_data(nlh);
if (ipc_ev_clbk->destroy_session)
ipc_ev_clbk->destroy_session(ev->r.d_session.host_no,
@@ -1464,6 +1542,8 @@ struct iscsi_ipc nl_ipc = {
.set_net_config = kset_net_config,
.recv_conn_state = krecv_conn_state,
.exec_ping = kexec_ping,
+ .get_chap = kget_chap,
+ .delete_chap = kdelete_chap,
};
struct iscsi_ipc *ipc = &nl_ipc;