|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iSCSI Netlink/Linux Interface
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
|
|
Packit |
eace71 |
* Copyright (C) 2006 Mike Christie
|
|
Packit |
eace71 |
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
|
Packit |
eace71 |
* maintained by open-iscsi@googlegroups.com
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
eace71 |
* it under the terms of the GNU General Public License as published
|
|
Packit |
eace71 |
* by the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
eace71 |
* (at your option) any later version.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
eace71 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
eace71 |
* General Public License for more details.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* See the file COPYING included with this distribution for more details.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <stdint.h>
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <time.h>
|
|
Packit |
eace71 |
#include <inttypes.h>
|
|
Packit |
eace71 |
#include <asm/types.h>
|
|
Packit |
eace71 |
#include <sys/socket.h>
|
|
Packit |
eace71 |
#include <sys/types.h>
|
|
Packit |
eace71 |
#include <sys/poll.h>
|
|
Packit |
eace71 |
#include <linux/netlink.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "types.h"
|
|
Packit |
eace71 |
#include "iscsi_if.h"
|
|
Packit |
eace71 |
#include "log.h"
|
|
Packit |
eace71 |
#include "iscsi_ipc.h"
|
|
Packit |
eace71 |
#include "initiator.h"
|
|
Packit |
eace71 |
#include "iscsi_sysfs.h"
|
|
Packit |
eace71 |
#include "transport.h"
|
|
Packit |
eace71 |
#include "iscsi_netlink.h"
|
|
Packit |
eace71 |
#include "iscsi_err.h"
|
|
Packit |
eace71 |
#include "iscsi_timer.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int ctrl_fd;
|
|
Packit |
eace71 |
static struct sockaddr_nl src_addr, dest_addr;
|
|
Packit |
eace71 |
static void *xmitbuf = NULL;
|
|
Packit |
eace71 |
static int xmitlen = 0;
|
|
Packit |
eace71 |
static void *recvbuf = NULL;
|
|
Packit |
eace71 |
static int recvlen = 0;
|
|
Packit |
eace71 |
static void *nlm_sendbuf;
|
|
Packit |
eace71 |
static void *nlm_recvbuf;
|
|
Packit |
eace71 |
static void *pdu_sendbuf;
|
|
Packit |
eace71 |
static void *setparam_buf;
|
|
Packit |
eace71 |
static struct iscsi_ipc_ev_clbk *ipc_ev_clbk;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int ctldev_handle(void);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define NLM_BUF_DEFAULT_MAX (NLMSG_SPACE(ISCSI_DEF_MAX_RECV_SEG_LEN + \
|
|
Packit |
eace71 |
sizeof(struct iscsi_uevent) + \
|
|
Packit |
eace71 |
sizeof(struct iscsi_hdr)))
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define PDU_SENDBUF_DEFAULT_MAX (ISCSI_DEF_MAX_RECV_SEG_LEN + \
|
|
Packit |
eace71 |
sizeof(struct iscsi_uevent) + \
|
|
Packit |
eace71 |
sizeof(struct iscsi_hdr))
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define NLM_SETPARAM_DEFAULT_MAX (NI_MAXHOST + 1 + sizeof(struct iscsi_uevent))
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_ping_event {
|
|
Packit |
eace71 |
uint32_t host_no;
|
|
Packit |
eace71 |
uint32_t pid;
|
|
Packit |
eace71 |
int32_t status;
|
|
Packit |
eace71 |
int active;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_ping_event ping_event;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct nlattr *iscsi_nla_alloc(uint16_t type, uint16_t len)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct nlattr *attr;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
attr = calloc(1, ISCSI_NLA_TOTAL_LEN(len));
|
|
Packit |
eace71 |
if (!attr)
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
attr->nla_len = ISCSI_NLA_LEN(len);
|
|
Packit |
eace71 |
attr->nla_type = type;
|
|
Packit |
eace71 |
return attr;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kread(char *data, int count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
log_debug(7, "in %s %u %u %p %p", __FUNCTION__, recvlen, count,
|
|
Packit |
eace71 |
data, recvbuf);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memcpy(data, recvbuf + recvlen, count);
|
|
Packit |
eace71 |
recvlen += count;
|
|
Packit |
eace71 |
return count;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
nl_read(int ctrl_fd, char *data, int size, int flags)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iovec iov;
|
|
Packit |
eace71 |
struct msghdr msg;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov.iov_base = data;
|
|
Packit |
eace71 |
iov.iov_len = size;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&msg, 0, sizeof(msg));
|
|
Packit |
eace71 |
msg.msg_name= (void*)&src_addr;
|
|
Packit |
eace71 |
msg.msg_namelen = sizeof(src_addr);
|
|
Packit |
eace71 |
msg.msg_iov = &iov;
|
|
Packit |
eace71 |
msg.msg_iovlen = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = recvmsg(ctrl_fd, &msg, flags);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
nlpayload_read(int ctrl_fd, char *data, int count, int flags)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iovec iov;
|
|
Packit |
eace71 |
struct msghdr msg;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov.iov_base = nlm_recvbuf;
|
|
Packit |
eace71 |
iov.iov_len = NLMSG_SPACE(count);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (iov.iov_len > NLM_BUF_DEFAULT_MAX) {
|
|
Packit |
eace71 |
log_error("Cannot read %lu bytes. nlm_recvbuf too small.",
|
|
Packit |
eace71 |
iov.iov_len);
|
|
Packit |
eace71 |
return -1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
memset(iov.iov_base, 0, iov.iov_len);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&msg, 0, sizeof(msg));
|
|
Packit |
eace71 |
msg.msg_name= (void*)&src_addr;
|
|
Packit |
eace71 |
msg.msg_namelen = sizeof(src_addr);
|
|
Packit |
eace71 |
msg.msg_iov = &iov;
|
|
Packit |
eace71 |
msg.msg_iovlen = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Netlink recvmsg call path:
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* - transport api callback
|
|
Packit |
eace71 |
* - iscsi_control_conn_error (should succeed)
|
|
Packit |
eace71 |
* - iscsi_unicast_skb (must succeed)
|
|
Packit |
eace71 |
* - netlink_unicast (must succeed)
|
|
Packit |
eace71 |
* - netlink_data_ready (must succeed)
|
|
Packit |
eace71 |
* - netlink_sendskb (must succeed)
|
|
Packit |
eace71 |
* - netlink_recvmsg (must succeed)
|
|
Packit |
eace71 |
* - sock_recvmsg (must succeed)
|
|
Packit |
eace71 |
* - sys_recvmsg (must succeed)
|
|
Packit |
eace71 |
* - sys_socketcall (must succeed)
|
|
Packit |
eace71 |
* - syscall_call (must succeed)
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Note1: "must succeed" means succeed unless bug in daemon.
|
|
Packit |
eace71 |
* It also means - no sleep and memory allocation on
|
|
Packit |
eace71 |
* the path.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Note2: "should succeed" means will succeed in most of cases
|
|
Packit |
eace71 |
* because of mempool preallocation.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* FIXME: if "Note2" than interface should generate iSCSI error
|
|
Packit |
eace71 |
* level 0 on its own. Interface must always succeed on this.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
rc = recvmsg(ctrl_fd, &msg, flags);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (data)
|
|
Packit |
eace71 |
memcpy(data, NLMSG_DATA(iov.iov_base), count);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kwritev(enum iscsi_uevent_e type, struct iovec *iovp, int count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int i, rc;
|
|
Packit |
eace71 |
struct nlmsghdr *nlh;
|
|
Packit |
eace71 |
struct msghdr msg;
|
|
Packit |
eace71 |
int datalen = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < count; i++) {
|
|
Packit |
eace71 |
datalen += iovp[i].iov_len;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (xmitbuf && type != ISCSI_UEVENT_SEND_PDU) {
|
|
Packit |
eace71 |
for (i = 0; i < count; i++) {
|
|
Packit |
eace71 |
memcpy(xmitbuf + xmitlen,
|
|
Packit |
eace71 |
iovp[i].iov_base, iovp[i].iov_len);
|
|
Packit |
eace71 |
xmitlen += iovp[i].iov_len;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return datalen;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nlh = nlm_sendbuf;
|
|
Packit |
eace71 |
memset(nlh, 0, NLMSG_SPACE(0));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
datalen = 0;
|
|
Packit |
eace71 |
for (i = 1; i < count; i++)
|
|
Packit |
eace71 |
datalen += iovp[i].iov_len;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nlh->nlmsg_len = datalen + sizeof(*nlh);
|
|
Packit |
eace71 |
nlh->nlmsg_pid = getpid();
|
|
Packit |
eace71 |
nlh->nlmsg_flags = 0;
|
|
Packit |
eace71 |
nlh->nlmsg_type = type;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iovp[0].iov_base = (void *)nlh;
|
|
Packit |
eace71 |
iovp[0].iov_len = sizeof(*nlh);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&msg, 0, sizeof(msg));
|
|
Packit |
eace71 |
msg.msg_name= (void*)&dest_addr;
|
|
Packit |
eace71 |
msg.msg_namelen = sizeof(dest_addr);
|
|
Packit |
eace71 |
msg.msg_iov = iovp;
|
|
Packit |
eace71 |
msg.msg_iovlen = count;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
do {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Netlink down call path:
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* - transport api call
|
|
Packit |
eace71 |
* - iscsi_if_recv_msg (must succeed)
|
|
Packit |
eace71 |
* - iscsi_if_rx (must succeed)
|
|
Packit |
eace71 |
* - netlink_data_ready (must succeed)
|
|
Packit |
eace71 |
* - netlink_sendskb (must succeed)
|
|
Packit |
eace71 |
* - netlink_sendmsg (alloc_skb() might fail)
|
|
Packit |
eace71 |
* - sock_sendmsg (must succeed)
|
|
Packit |
eace71 |
* - sys_sendmsg (must succeed)
|
|
Packit |
eace71 |
* - sys_socketcall (must succeed)
|
|
Packit |
eace71 |
* - syscall_call (must succeed)
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Note1: "must succeed" means succeed unless bug in daemon.
|
|
Packit |
eace71 |
* It also means - no sleep and memory allocation on
|
|
Packit |
eace71 |
* the path.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Note2: netlink_sendmsg() might fail because of OOM. Since
|
|
Packit |
eace71 |
* we are in user-space, we will sleep until we succeed.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = sendmsg(ctrl_fd, &msg, 0);
|
|
Packit |
eace71 |
if (rc == -ENOMEM) {
|
|
Packit |
eace71 |
log_debug(1, "sendmsg: alloc_skb() failed");
|
|
Packit |
eace71 |
sleep(1);
|
|
Packit |
eace71 |
} else if (rc < 0) {
|
|
Packit |
eace71 |
log_error("sendmsg: bug? ctrl_fd %d", ctrl_fd);
|
|
Packit |
eace71 |
exit(rc);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} while (rc < 0);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* __kipc_call() should never block. Therefore
|
|
Packit |
eace71 |
* Netlink's xmit logic is serialized. This means we do not allocate on
|
|
Packit |
eace71 |
* xmit path. Instead we reuse nlm_sendbuf buffer.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Transport must assure non-blocking operations for:
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* - session_create()
|
|
Packit |
eace71 |
* - conn_create()
|
|
Packit |
eace71 |
* - conn_bind()
|
|
Packit |
eace71 |
* _ set_param()
|
|
Packit |
eace71 |
* - conn_start()
|
|
Packit |
eace71 |
* - conn_stop()
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Its OK to block for cleanup for short period of time in operatations for:
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* - conn_destroy()
|
|
Packit |
eace71 |
* - session_destroy()
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* FIXME: interface needs to be extended to allow longer blocking on
|
|
Packit |
eace71 |
* cleanup. (Dima)
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
__kipc_call(struct iovec *iovp, int count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc, iferr;
|
|
Packit |
eace71 |
struct iscsi_uevent *ev = iovp[1].iov_base;
|
|
Packit |
eace71 |
enum iscsi_uevent_e type = ev->type;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = kwritev(type, iovp, count);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
do {
|
|
Packit |
eace71 |
if ((rc = nlpayload_read(ctrl_fd, (void*)ev,
|
|
Packit |
eace71 |
sizeof(*ev), MSG_PEEK)) < 0) {
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (ev->type != type) {
|
|
Packit |
eace71 |
log_debug(1, "expecting event %d, got %d, handling...",
|
|
Packit |
eace71 |
type, ev->type);
|
|
Packit |
eace71 |
if (ev->type == ISCSI_KEVENT_IF_ERROR) {
|
|
Packit |
eace71 |
if ((rc = nlpayload_read(ctrl_fd, (void*)ev,
|
|
Packit |
eace71 |
sizeof(*ev), 0)) < 0) {
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iferror is u32, but the kernel returns
|
|
Packit |
eace71 |
* negative errno values for errors.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
iferr = ev->iferror;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (iferr == -ENOSYS)
|
|
Packit |
eace71 |
/* not fatal so let caller handle log */
|
|
Packit |
eace71 |
log_debug(1, "Received iferror %d: %s.",
|
|
Packit |
eace71 |
iferr, strerror(-iferr));
|
|
Packit |
eace71 |
else if (iferr < 0)
|
|
Packit |
eace71 |
log_error("Received iferror %d: %s.",
|
|
Packit |
eace71 |
iferr, strerror(-iferr));
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
log_error("Received iferror %d.",
|
|
Packit |
eace71 |
iferr);
|
|
Packit |
eace71 |
return ev->iferror;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* receive and queue async. event which as of
|
|
Packit |
eace71 |
* today could be:
|
|
Packit |
eace71 |
* - CONN_ERROR
|
|
Packit |
eace71 |
* - RECV_PDU
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
ctldev_handle();
|
|
Packit |
eace71 |
} else if (ev->type == ISCSI_UEVENT_GET_STATS) {
|
|
Packit |
eace71 |
/* kget_stats() will read */
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
} else if (ev->type == ISCSI_UEVENT_GET_CHAP) {
|
|
Packit |
eace71 |
/* kget_chap() will read */
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
} else if (ev->type == ISCSI_UEVENT_GET_HOST_STATS) {
|
|
Packit |
eace71 |
/* kget_host_stats() will read */
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
if ((rc = nlpayload_read(ctrl_fd, (void*)ev,
|
|
Packit |
eace71 |
sizeof(*ev), 0)) < 0) {
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} while (ev->type != type);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc, addrlen;
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
|
|
Packit |
eace71 |
ev = (struct iscsi_uevent *)setparam_buf;
|
|
Packit |
eace71 |
ev->type = ISCSI_UEVENT_TGT_DSCVR;
|
|
Packit |
eace71 |
ev->transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev->u.tgt_dscvr.type = ISCSI_TGT_DSCVR_SEND_TARGETS;
|
|
Packit |
eace71 |
ev->u.tgt_dscvr.host_no = host_no;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (addr->sa_family == PF_INET)
|
|
Packit |
eace71 |
addrlen = sizeof(struct sockaddr_in);
|
|
Packit |
eace71 |
else if (addr->sa_family == PF_INET6)
|
|
Packit |
eace71 |
addrlen = sizeof(struct sockaddr_in6);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
log_error("%s unknown addr family %d",
|
|
Packit |
eace71 |
__FUNCTION__, addr->sa_family);
|
|
Packit |
eace71 |
return -EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
memcpy(setparam_buf + sizeof(*ev), addr, addrlen);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(*ev) + addrlen;
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0) {
|
|
Packit |
eace71 |
log_error("sendtargets failed rc%d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kcreate_session(uint64_t transport_handle, uint64_t ep_handle,
|
|
Packit |
eace71 |
uint32_t initial_cmdsn, uint16_t cmds_max, uint16_t qdepth,
|
|
Packit |
eace71 |
uint32_t *out_sid, uint32_t *hostno)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ep_handle == 0) {
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_CREATE_SESSION;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.c_session.initial_cmdsn = initial_cmdsn;
|
|
Packit |
eace71 |
ev.u.c_session.cmds_max = cmds_max;
|
|
Packit |
eace71 |
ev.u.c_session.queue_depth = qdepth;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_CREATE_BOUND_SESSION;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.c_bound_session.initial_cmdsn = initial_cmdsn;
|
|
Packit |
eace71 |
ev.u.c_bound_session.cmds_max = cmds_max;
|
|
Packit |
eace71 |
ev.u.c_bound_session.queue_depth = qdepth;
|
|
Packit |
eace71 |
ev.u.c_bound_session.ep_handle = ep_handle;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*hostno = ev.r.c_session_ret.host_no;
|
|
Packit |
eace71 |
*out_sid = ev.r.c_session_ret.sid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kdestroy_session(uint64_t transport_handle, uint32_t sid)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_DESTROY_SESSION;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.d_session.sid = sid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kunbind_session(uint64_t transport_handle, uint32_t sid)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_UNBIND_SESSION;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.d_session.sid = sid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kcreate_conn(uint64_t transport_handle, uint32_t sid,
|
|
Packit |
eace71 |
uint32_t cid, uint32_t *out_cid)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_CREATE_CONN;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.c_conn.cid = cid;
|
|
Packit |
eace71 |
ev.u.c_conn.sid = sid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0) {
|
|
Packit |
eace71 |
log_debug(7, "returned %d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((int)ev.r.c_conn_ret.cid == -1)
|
|
Packit |
eace71 |
return -EIO;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*out_cid = ev.r.c_conn_ret.cid;
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kdestroy_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_DESTROY_CONN;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.d_conn.sid = sid;
|
|
Packit |
eace71 |
ev.u.d_conn.cid = cid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kbind_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid,
|
|
Packit |
eace71 |
uint64_t transport_eph, int is_leading, int *retcode)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_BIND_CONN;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.b_conn.sid = sid;
|
|
Packit |
eace71 |
ev.u.b_conn.cid = cid;
|
|
Packit |
eace71 |
ev.u.b_conn.transport_eph = transport_eph;
|
|
Packit |
eace71 |
ev.u.b_conn.is_leading = is_leading;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*retcode = ev.r.retcode;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
ksend_pdu_begin(uint64_t transport_handle, uint32_t sid, uint32_t cid,
|
|
Packit |
eace71 |
int hdr_size, int data_size)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
int total_xmitlen = sizeof(*ev) + hdr_size + data_size;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (xmitbuf) {
|
|
Packit |
eace71 |
log_error("send's begin state machine bug?");
|
|
Packit |
eace71 |
exit(-EIO);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (total_xmitlen > PDU_SENDBUF_DEFAULT_MAX) {
|
|
Packit |
eace71 |
log_error("BUG: Cannot send %d bytes.", total_xmitlen);
|
|
Packit |
eace71 |
exit(-EINVAL);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
xmitbuf = pdu_sendbuf;
|
|
Packit |
eace71 |
memset(xmitbuf, 0, total_xmitlen);
|
|
Packit |
eace71 |
xmitlen = sizeof(*ev);
|
|
Packit |
eace71 |
ev = xmitbuf;
|
|
Packit |
eace71 |
memset(ev, 0, sizeof(*ev));
|
|
Packit |
eace71 |
ev->type = ISCSI_UEVENT_SEND_PDU;
|
|
Packit |
eace71 |
ev->transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev->u.send_pdu.sid = sid;
|
|
Packit |
eace71 |
ev->u.send_pdu.cid = cid;
|
|
Packit |
eace71 |
ev->u.send_pdu.hdr_size = hdr_size;
|
|
Packit |
eace71 |
ev->u.send_pdu.data_size = data_size;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(3, "send PDU began for hdr %d bytes and data %d bytes",
|
|
Packit |
eace71 |
hdr_size, data_size);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
ksend_pdu_end(uint64_t transport_handle, uint32_t sid, uint32_t cid,
|
|
Packit |
eace71 |
int *retcode)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!xmitbuf) {
|
|
Packit |
eace71 |
log_error("send's end state machine bug?");
|
|
Packit |
eace71 |
exit(-EIO);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
ev = xmitbuf;
|
|
Packit |
eace71 |
if (ev->u.send_pdu.sid != sid || ev->u.send_pdu.cid != cid) {
|
|
Packit |
eace71 |
log_error("send's end state machine corruption?");
|
|
Packit |
eace71 |
exit(-EIO);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = xmitbuf;
|
|
Packit |
eace71 |
iov[1].iov_len = xmitlen;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
goto err;
|
|
Packit |
eace71 |
if (ev->r.retcode) {
|
|
Packit |
eace71 |
*retcode = ev->r.retcode;
|
|
Packit |
eace71 |
goto err;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (ev->type != ISCSI_UEVENT_SEND_PDU) {
|
|
Packit |
eace71 |
log_error("bad event: bug on send_pdu_end?");
|
|
Packit |
eace71 |
exit(-EIO);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(3, "send PDU finished for conn %d:%d",
|
|
Packit |
eace71 |
sid, cid);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
xmitbuf = NULL;
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
err:
|
|
Packit |
eace71 |
xmitbuf = NULL;
|
|
Packit |
eace71 |
xmitlen = 0;
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kset_host_param(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
enum iscsi_host_param param, void *value, int type)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
char *param_str;
|
|
Packit |
eace71 |
int rc, len;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
|
|
Packit |
eace71 |
ev = (struct iscsi_uevent *)setparam_buf;
|
|
Packit |
eace71 |
ev->type = ISCSI_UEVENT_SET_HOST_PARAM;
|
|
Packit |
eace71 |
ev->transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev->u.set_host_param.host_no = host_no;
|
|
Packit |
eace71 |
ev->u.set_host_param.param = param;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
param_str = setparam_buf + sizeof(*ev);
|
|
Packit |
eace71 |
switch (type) {
|
|
Packit |
eace71 |
case ISCSI_INT:
|
|
Packit |
eace71 |
sprintf(param_str, "%d", *((int *)value));
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_STRING:
|
|
Packit |
eace71 |
if (!strlen(value))
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
sprintf(param_str, "%s", (char *)value);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
log_error("invalid type %d", type);
|
|
Packit |
eace71 |
return -EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
ev->u.set_host_param.len = len = strlen(param_str) + 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(*ev) + len;
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kset_param(uint64_t transport_handle, uint32_t sid, uint32_t cid,
|
|
Packit |
eace71 |
enum iscsi_param param, void *value, int type)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
char *param_str;
|
|
Packit |
eace71 |
int rc, len;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
|
|
Packit |
eace71 |
ev = (struct iscsi_uevent *)setparam_buf;
|
|
Packit |
eace71 |
ev->type = ISCSI_UEVENT_SET_PARAM;
|
|
Packit |
eace71 |
ev->transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev->u.set_param.sid = sid;
|
|
Packit |
eace71 |
ev->u.set_param.cid = cid;
|
|
Packit |
eace71 |
ev->u.set_param.param = param;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
param_str = setparam_buf + sizeof(*ev);
|
|
Packit |
eace71 |
switch (type) {
|
|
Packit |
eace71 |
case ISCSI_INT:
|
|
Packit |
eace71 |
sprintf(param_str, "%d", *((int *)value));
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_UINT:
|
|
Packit |
eace71 |
sprintf(param_str, "%u", *((unsigned int *)value));
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_STRING:
|
|
Packit |
eace71 |
if (!strlen(value))
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
sprintf(param_str, "%s", (char *)value);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
log_error("invalid type %d", type);
|
|
Packit |
eace71 |
return -EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
ev->u.set_param.len = len = strlen(param_str) + 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(*ev) + len;
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kstop_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, int flag)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_STOP_CONN;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.stop_conn.sid = sid;
|
|
Packit |
eace71 |
ev.u.stop_conn.cid = cid;
|
|
Packit |
eace71 |
ev.u.stop_conn.flag = flag;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kstart_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid,
|
|
Packit |
eace71 |
int *retcode)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_START_CONN;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.start_conn.sid = sid;
|
|
Packit |
eace71 |
ev.u.start_conn.cid = cid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*retcode = ev.r.retcode;
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
krecv_pdu_begin(struct iscsi_conn *conn)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (recvbuf) {
|
|
Packit |
eace71 |
log_error("recv's begin state machine bug?");
|
|
Packit |
eace71 |
return -EIO;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!conn->recv_context) {
|
|
Packit |
eace71 |
rc = ipc->ctldev_handle();
|
|
Packit |
eace71 |
if (rc == -ENXIO)
|
|
Packit |
eace71 |
/* event for some other conn */
|
|
Packit |
eace71 |
return -EAGAIN;
|
|
Packit |
eace71 |
else if (rc < 0)
|
|
Packit |
eace71 |
/* fatal handling error or conn error */
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Session create/destroy event for another conn
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!conn->recv_context)
|
|
Packit |
eace71 |
return -EAGAIN;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
recvbuf = conn->recv_context->data + sizeof(struct iscsi_uevent);
|
|
Packit |
eace71 |
recvlen = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(3, "recv PDU began, pdu handle %p", recvbuf);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
krecv_pdu_end(struct iscsi_conn *conn)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!recvbuf) {
|
|
Packit |
eace71 |
log_error("recv's end state machine bug?");
|
|
Packit |
eace71 |
return -EIO;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(3, "recv PDU finished for pdu handle 0x%p",
|
|
Packit |
eace71 |
recvbuf);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ipc_ev_clbk->put_ev_context(conn->recv_context);
|
|
Packit |
eace71 |
conn->recv_context = NULL;
|
|
Packit |
eace71 |
recvbuf = NULL;
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc, addrlen;
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
struct sockaddr *dst_addr = (struct sockaddr *)&conn->saddr;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
|
|
Packit |
eace71 |
ev = (struct iscsi_uevent *)setparam_buf;
|
|
Packit |
eace71 |
ev->transport_handle = conn->session->t->handle;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (conn->bind_ep) {
|
|
Packit |
eace71 |
ev->type = ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST;
|
|
Packit |
eace71 |
ev->u.ep_connect_through_host.non_blocking = non_blocking;
|
|
Packit |
eace71 |
ev->u.ep_connect_through_host.host_no = conn->session->hostno;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
ev->type = ISCSI_UEVENT_TRANSPORT_EP_CONNECT;
|
|
Packit |
eace71 |
ev->u.ep_connect.non_blocking = non_blocking;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (dst_addr->sa_family == PF_INET)
|
|
Packit |
eace71 |
addrlen = sizeof(struct sockaddr_in);
|
|
Packit |
eace71 |
else if (dst_addr->sa_family == PF_INET6)
|
|
Packit |
eace71 |
addrlen = sizeof(struct sockaddr_in6);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
log_error("%s unknown addr family %d",
|
|
Packit |
eace71 |
__FUNCTION__, dst_addr->sa_family);
|
|
Packit |
eace71 |
return -EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
memcpy(setparam_buf + sizeof(*ev), dst_addr, addrlen);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(*ev) + addrlen;
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!ev->r.ep_connect_ret.handle)
|
|
Packit |
eace71 |
return -EIO;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
conn->transport_ep_handle = ev->r.ep_connect_ret.handle;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(6, "%s got handle %llx",
|
|
Packit |
eace71 |
__FUNCTION__, (unsigned long long)conn->transport_ep_handle);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
ktransport_ep_poll(iscsi_conn_t *conn, int timeout_ms)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_TRANSPORT_EP_POLL;
|
|
Packit |
eace71 |
ev.transport_handle = conn->session->t->handle;
|
|
Packit |
eace71 |
ev.u.ep_poll.ep_handle = conn->transport_ep_handle;
|
|
Packit |
eace71 |
ev.u.ep_poll.timeout_ms = timeout_ms;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return ev.r.retcode;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void
|
|
Packit |
eace71 |
ktransport_ep_disconnect(iscsi_conn_t *conn)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (conn->transport_ep_handle == -1)
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT;
|
|
Packit |
eace71 |
ev.transport_handle = conn->session->t->handle;
|
|
Packit |
eace71 |
ev.u.ep_disconnect.ep_handle = conn->transport_ep_handle;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0) {
|
|
Packit |
eace71 |
log_error("connection %d:%d transport disconnect failed for "
|
|
Packit |
eace71 |
"ep %" PRIu64 " with error %d.", conn->session->id,
|
|
Packit |
eace71 |
conn->id, conn->transport_ep_handle, rc);
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
conn->transport_ep_handle = -1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid,
|
|
Packit |
eace71 |
char *statsbuf, int statsbuf_max)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
int ev_size;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
|
|
Packit |
eace71 |
struct nlmsghdr *nlh;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_GET_STATS;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.get_stats.sid = sid;
|
|
Packit |
eace71 |
ev.u.get_stats.cid = cid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rc = nl_read(ctrl_fd, nlm_ev,
|
|
Packit |
eace71 |
NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) {
|
|
Packit |
eace71 |
log_error("can not read nlm_ev, error %d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
nlh = (struct nlmsghdr *)nlm_ev;
|
|
Packit |
eace71 |
ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(6, "message real length is %d bytes", nlh->nlmsg_len);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ev_size > statsbuf_max) {
|
|
Packit |
eace71 |
log_error("destanation buffer for statistics is "
|
|
Packit |
eace71 |
"not big enough to fit %d bytes", statsbuf_max);
|
|
Packit |
eace71 |
ev_size = statsbuf_max;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rc = nlpayload_read(ctrl_fd, (void*)statsbuf, ev_size, 0)) < 0) {
|
|
Packit |
eace71 |
log_error("can not read from NL socket, error %d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kset_net_config(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
struct iovec *iovs, uint32_t param_count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
int rc, ev_len;
|
|
Packit |
eace71 |
struct iovec *iov = iovs + 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(8, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev_len = sizeof(ev);
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_SET_IFACE_PARAMS;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.set_iface_params.host_no = host_no;
|
|
Packit |
eace71 |
/* first two iovs for nlmsg hdr and ev */
|
|
Packit |
eace71 |
ev.u.set_iface_params.count = param_count - 2;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov->iov_base = &ev;
|
|
Packit |
eace71 |
iov->iov_len = ev_len;
|
|
Packit |
eace71 |
rc = __kipc_call(iovs, param_count);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int krecv_conn_state(struct iscsi_conn *conn, uint32_t *state)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = ipc->ctldev_handle();
|
|
Packit |
eace71 |
if (rc == -ENXIO) {
|
|
Packit |
eace71 |
/* event for some other conn */
|
|
Packit |
eace71 |
rc = -EAGAIN;
|
|
Packit |
eace71 |
goto exit;
|
|
Packit |
eace71 |
} else if (rc < 0)
|
|
Packit |
eace71 |
/* fatal handling error or conn error */
|
|
Packit |
eace71 |
goto exit;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* unexpected event without a receive context */
|
|
Packit |
eace71 |
if (!conn->recv_context)
|
|
Packit |
eace71 |
return -EAGAIN;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*state = *(enum iscsi_conn_state *)conn->recv_context->data;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ipc_ev_clbk->put_ev_context(conn->recv_context);
|
|
Packit |
eace71 |
conn->recv_context = NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
exit:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
ksend_ping(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr,
|
|
Packit |
eace71 |
uint32_t iface_num, uint32_t iface_type, uint32_t pid, uint32_t size)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc, addrlen;
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(8, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
|
|
Packit |
eace71 |
ev = (struct iscsi_uevent *)setparam_buf;
|
|
Packit |
eace71 |
ev->type = ISCSI_UEVENT_PING;
|
|
Packit |
eace71 |
ev->transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev->u.iscsi_ping.host_no = host_no;
|
|
Packit |
eace71 |
ev->u.iscsi_ping.iface_num = iface_num;
|
|
Packit |
eace71 |
ev->u.iscsi_ping.iface_type = iface_type;
|
|
Packit |
eace71 |
ev->u.iscsi_ping.payload_size = size;
|
|
Packit |
eace71 |
ev->u.iscsi_ping.pid = pid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (addr->sa_family == PF_INET)
|
|
Packit |
eace71 |
addrlen = sizeof(struct sockaddr_in);
|
|
Packit |
eace71 |
else if (addr->sa_family == PF_INET6)
|
|
Packit |
eace71 |
addrlen = sizeof(struct sockaddr_in6);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
log_error("%s unknown addr family %d",
|
|
Packit |
eace71 |
__FUNCTION__, addr->sa_family);
|
|
Packit |
eace71 |
return -EINVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
memcpy(setparam_buf + sizeof(*ev), addr, addrlen);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(*ev) + addrlen;
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int kexec_ping(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
struct sockaddr *addr, uint32_t iface_num,
|
|
Packit |
eace71 |
uint32_t iface_type, uint32_t size, uint32_t *status)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct pollfd pfd;
|
|
Packit |
eace71 |
struct timeval ping_timer;
|
|
Packit |
eace71 |
int timeout, fd, rc;
|
|
Packit |
eace71 |
uint32_t pid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*status = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fd = ipc->ctldev_open();
|
|
Packit |
eace71 |
if (fd < 0) {
|
|
Packit |
eace71 |
log_error("Could not open netlink socket.");
|
|
Packit |
eace71 |
return ISCSI_ERR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* prepare to poll */
|
|
Packit |
eace71 |
memset(&pfd, 0, sizeof(pfd));
|
|
Packit |
eace71 |
pfd.fd = fd;
|
|
Packit |
eace71 |
pfd.events = POLLIN | POLLPRI;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* get unique ping id */
|
|
Packit |
eace71 |
pid = rand();
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = ksend_ping(transport_handle, host_no, addr, iface_num,
|
|
Packit |
eace71 |
iface_type, pid, size);
|
|
Packit |
eace71 |
if (rc != 0) {
|
|
Packit |
eace71 |
switch (rc) {
|
|
Packit |
eace71 |
case -ENOSYS:
|
|
Packit |
eace71 |
rc = ISCSI_ERR_OP_NOT_SUPP;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case -EINVAL:
|
|
Packit |
eace71 |
rc = ISCSI_ERR_INVAL;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
rc = ISCSI_ERR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
goto close_nl;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ping_event.host_no = -1;
|
|
Packit |
eace71 |
ping_event.pid = -1;
|
|
Packit |
eace71 |
ping_event.status = -1;
|
|
Packit |
eace71 |
ping_event.active = -1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iscsi_timer_set(&ping_timer, 30);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
timeout = iscsi_timer_msecs_until(&ping_timer);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (1) {
|
|
Packit |
eace71 |
pfd.revents = 0;
|
|
Packit |
eace71 |
rc = poll(&pfd, 1, timeout);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (iscsi_timer_expired(&ping_timer)) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_TRANS_TIMEOUT;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc > 0) {
|
|
Packit |
eace71 |
if (pfd.revents & (POLLIN | POLLPRI)) {
|
|
Packit |
eace71 |
timeout = iscsi_timer_msecs_until(&ping_timer);
|
|
Packit |
eace71 |
rc = ipc->ctldev_handle();
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ping_event.active != 1)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (pid != ping_event.pid)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
*status = ping_event.status;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (pfd.revents & POLLHUP) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_TRANS;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (pfd.revents & POLLNVAL) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_INTERNAL;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (pfd.revents & POLLERR) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_INTERNAL;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else if (rc < 0) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_INTERNAL;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
close_nl:
|
|
Packit |
eace71 |
ipc->ctldev_close();
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int kget_chap(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
uint16_t chap_tbl_idx, uint32_t num_entries,
|
|
Packit |
eace71 |
char *chap_buf, uint32_t *valid_chap_entries)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
int ev_size;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
|
|
Packit |
eace71 |
struct nlmsghdr *nlh;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_GET_CHAP;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.get_chap.host_no = host_no;
|
|
Packit |
eace71 |
ev.u.get_chap.chap_tbl_idx = chap_tbl_idx;
|
|
Packit |
eace71 |
ev.u.get_chap.num_entries = num_entries;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rc = nl_read(ctrl_fd, nlm_ev,
|
|
Packit |
eace71 |
NLMSG_SPACE(sizeof(struct iscsi_uevent)),
|
|
Packit |
eace71 |
MSG_PEEK)) < 0) {
|
|
Packit |
eace71 |
log_error("can not read nlm_ev, error %d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nlh = (struct nlmsghdr *)nlm_ev;
|
|
Packit |
eace71 |
ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rc = nlpayload_read(ctrl_fd, (void *)chap_buf, ev_size, 0)) < 0) {
|
|
Packit |
eace71 |
log_error("can not read from NL socket, error %d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*valid_chap_entries = ev.u.get_chap.num_entries;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int kset_chap(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
struct iovec *iovs, uint32_t param_count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec *iov = iovs + 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(8, "in %s", __func__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_SET_CHAP;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.set_path.host_no = host_no;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov->iov_base = &ev;
|
|
Packit |
eace71 |
iov->iov_len = sizeof(ev);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = __kipc_call(iovs, param_count);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int kdelete_chap(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
uint16_t chap_tbl_idx)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_DELETE_CHAP;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.delete_chap.host_no = host_no;
|
|
Packit |
eace71 |
ev.u.delete_chap.chap_tbl_idx = chap_tbl_idx;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kset_flashnode_params(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
uint32_t flashnode_idx, struct iovec *iovs,
|
|
Packit |
eace71 |
uint32_t param_count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
int rc, ev_len;
|
|
Packit |
eace71 |
struct iovec *iov = iovs + 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(8, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev_len = sizeof(ev);
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_SET_FLASHNODE_PARAMS;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.set_flashnode.host_no = host_no;
|
|
Packit |
eace71 |
ev.u.set_flashnode.flashnode_idx = flashnode_idx;
|
|
Packit |
eace71 |
/* first two iovs for nlmsg hdr and ev */
|
|
Packit |
eace71 |
ev.u.set_flashnode.count = param_count - 2;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov->iov_base = &ev;
|
|
Packit |
eace71 |
iov->iov_len = ev_len;
|
|
Packit |
eace71 |
rc = __kipc_call(iovs, param_count);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
knew_flashnode(uint64_t transport_handle, uint32_t host_no, void *value,
|
|
Packit |
eace71 |
uint32_t *flashnode_idx)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
char *param_str;
|
|
Packit |
eace71 |
int rc, len;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
|
|
Packit |
eace71 |
ev = (struct iscsi_uevent *)setparam_buf;
|
|
Packit |
eace71 |
ev->type = ISCSI_UEVENT_NEW_FLASHNODE;
|
|
Packit |
eace71 |
ev->transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev->u.new_flashnode.host_no = host_no;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
param_str = setparam_buf + sizeof(*ev);
|
|
Packit |
eace71 |
if (!strlen(value))
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
sprintf(param_str, "%s", (char *)value);
|
|
Packit |
eace71 |
len = strlen(param_str) + 1;
|
|
Packit |
eace71 |
ev->u.new_flashnode.len = len;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(*ev) + len;
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*flashnode_idx = ev->r.new_flashnode_ret.flashnode_idx;
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
kdel_flashnode(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
uint32_t flashnode_idx)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_DEL_FLASHNODE;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.del_flashnode.host_no = host_no;
|
|
Packit |
eace71 |
ev.u.del_flashnode.flashnode_idx = flashnode_idx;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
klogin_flashnode(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
uint32_t flashnode_idx)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_LOGIN_FLASHNODE;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.login_flashnode.host_no = host_no;
|
|
Packit |
eace71 |
ev.u.login_flashnode.flashnode_idx = flashnode_idx;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
klogout_flashnode(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
uint32_t flashnode_idx)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_LOGOUT_FLASHNODE;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.logout_flashnode.host_no = host_no;
|
|
Packit |
eace71 |
ev.u.logout_flashnode.flashnode_idx = flashnode_idx;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
klogout_flashnode_sid(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
uint32_t sid)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_LOGOUT_FLASHNODE_SID;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.logout_flashnode_sid.host_no = host_no;
|
|
Packit |
eace71 |
ev.u.logout_flashnode_sid.sid = sid;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int kget_host_stats(uint64_t transport_handle, uint32_t host_no,
|
|
Packit |
eace71 |
char *host_stats)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
int ev_size;
|
|
Packit |
eace71 |
struct iscsi_uevent ev;
|
|
Packit |
eace71 |
struct iovec iov[2];
|
|
Packit |
eace71 |
char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
|
|
Packit |
eace71 |
struct nlmsghdr *nlh;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev.type = ISCSI_UEVENT_GET_HOST_STATS;
|
|
Packit |
eace71 |
ev.transport_handle = transport_handle;
|
|
Packit |
eace71 |
ev.u.get_host_stats.host_no = host_no;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
iov[1].iov_base = &ev;
|
|
Packit |
eace71 |
iov[1].iov_len = sizeof(ev);
|
|
Packit |
eace71 |
rc = __kipc_call(iov, 2);
|
|
Packit |
eace71 |
if (rc < 0)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rc = nl_read(ctrl_fd, nlm_ev,
|
|
Packit |
eace71 |
NLMSG_SPACE(sizeof(struct iscsi_uevent)),
|
|
Packit |
eace71 |
MSG_PEEK)) < 0) {
|
|
Packit |
eace71 |
log_error("can not read nlm_ev, error %d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nlh = (struct nlmsghdr *)nlm_ev;
|
|
Packit |
eace71 |
ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rc = nlpayload_read(ctrl_fd, (void *)host_stats,
|
|
Packit |
eace71 |
ev_size, 0)) < 0) {
|
|
Packit |
eace71 |
log_error("can not read from NL socket, error %d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void drop_data(struct nlmsghdr *nlh)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int ev_size;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
|
|
Packit |
eace71 |
nlpayload_read(ctrl_fd, NULL, ev_size, 0);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int ctldev_handle(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc, ev_size;
|
|
Packit |
eace71 |
struct iscsi_uevent *ev;
|
|
Packit |
eace71 |
iscsi_session_t *session = NULL;
|
|
Packit |
eace71 |
iscsi_conn_t *conn = NULL;
|
|
Packit |
eace71 |
char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
|
|
Packit |
eace71 |
struct nlmsghdr *nlh;
|
|
Packit |
eace71 |
struct iscsi_ev_context *ev_context;
|
|
Packit |
eace71 |
uint32_t sid = 0, cid = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rc = nl_read(ctrl_fd, nlm_ev,
|
|
Packit |
eace71 |
NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) {
|
|
Packit |
eace71 |
log_error("can not read nlm_ev, error %d", rc);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
nlh = (struct nlmsghdr *)nlm_ev;
|
|
Packit |
eace71 |
ev = (struct iscsi_uevent *)NLMSG_DATA(nlm_ev);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "%s got event type %u", __FUNCTION__, ev->type);
|
|
Packit |
eace71 |
/* drivers like qla4xxx can be inserted after iscsid is started */
|
|
Packit |
eace71 |
switch (ev->type) {
|
|
Packit |
eace71 |
case ISCSI_KEVENT_CREATE_SESSION:
|
|
Packit |
eace71 |
/* old kernels sent ISCSI_UEVENT_CREATE_SESSION on creation */
|
|
Packit |
eace71 |
case ISCSI_UEVENT_CREATE_SESSION:
|
|
Packit |
eace71 |
drop_data(nlh);
|
|
Packit |
eace71 |
if (!ipc_ev_clbk)
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ipc_ev_clbk->create_session)
|
|
Packit |
eace71 |
ipc_ev_clbk->create_session(ev->r.c_session_ret.host_no,
|
|
Packit |
eace71 |
ev->r.c_session_ret.sid);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_DESTROY_SESSION:
|
|
Packit |
eace71 |
drop_data(nlh);
|
|
Packit |
eace71 |
if (!ipc_ev_clbk)
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ipc_ev_clbk->destroy_session)
|
|
Packit |
eace71 |
ipc_ev_clbk->destroy_session(ev->r.d_session.host_no,
|
|
Packit |
eace71 |
ev->r.d_session.sid);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_RECV_PDU:
|
|
Packit |
eace71 |
sid = ev->r.recv_req.sid;
|
|
Packit |
eace71 |
cid = ev->r.recv_req.cid;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_CONN_ERROR:
|
|
Packit |
eace71 |
sid = ev->r.connerror.sid;
|
|
Packit |
eace71 |
cid = ev->r.connerror.cid;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_CONN_LOGIN_STATE:
|
|
Packit |
eace71 |
sid = ev->r.conn_login.sid;
|
|
Packit |
eace71 |
cid = ev->r.conn_login.cid;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_UNBIND_SESSION:
|
|
Packit |
eace71 |
sid = ev->r.unbind_session.sid;
|
|
Packit |
eace71 |
/* session wide event so cid is 0 */
|
|
Packit |
eace71 |
cid = 0;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_HOST_EVENT:
|
|
Packit |
eace71 |
switch (ev->r.host_event.code) {
|
|
Packit |
eace71 |
case ISCSI_EVENT_LINKUP:
|
|
Packit |
eace71 |
log_warning("Host%u: Link Up.",
|
|
Packit |
eace71 |
ev->r.host_event.host_no);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_EVENT_LINKDOWN:
|
|
Packit |
eace71 |
log_warning("Host%u: Link Down.",
|
|
Packit |
eace71 |
ev->r.host_event.host_no);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
log_debug(7, "Host%u: Unknown host event: %u.",
|
|
Packit |
eace71 |
ev->r.host_event.host_no,
|
|
Packit |
eace71 |
ev->r.host_event.code);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
drop_data(nlh);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_PING_COMP:
|
|
Packit |
eace71 |
ping_event.host_no = ev->r.ping_comp.host_no;
|
|
Packit |
eace71 |
ping_event.pid = ev->r.ping_comp.pid;
|
|
Packit |
eace71 |
ping_event.status = ev->r.ping_comp.status;
|
|
Packit |
eace71 |
ping_event.active = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
drop_data(nlh);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
if ((ev->type > ISCSI_UEVENT_MAX && ev->type < KEVENT_BASE) ||
|
|
Packit |
eace71 |
(ev->type > ISCSI_KEVENT_MAX))
|
|
Packit |
eace71 |
log_error("Unknown kernel event %d. You may want to "
|
|
Packit |
eace71 |
" upgrade your iscsi tools.", ev->type);
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* If another app is using the interface we might
|
|
Packit |
eace71 |
* see their
|
|
Packit |
eace71 |
* stuff. Just drop it.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
log_debug(7, "Got unknown event %d. Dropping.",
|
|
Packit |
eace71 |
ev->type);
|
|
Packit |
eace71 |
drop_data(nlh);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* verify connection */
|
|
Packit |
eace71 |
session = session_find_by_sid(sid);
|
|
Packit |
eace71 |
if (!session) {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* this can happen normally when other apps are using the
|
|
Packit |
eace71 |
* nl interface.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
log_debug(1, "Could not verify connection %d:%d. Dropping "
|
|
Packit |
eace71 |
"event.", sid, cid);
|
|
Packit |
eace71 |
drop_data(nlh);
|
|
Packit |
eace71 |
return -ENXIO;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
conn = &session->conn[0];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ev_context = ipc_ev_clbk->get_ev_context(conn, ev_size);
|
|
Packit |
eace71 |
if (!ev_context) {
|
|
Packit |
eace71 |
log_error("Can not allocate memory for receive context.");
|
|
Packit |
eace71 |
drop_data(nlh);
|
|
Packit |
eace71 |
return -ENOMEM;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(6, "message real length is %d bytes, recv_handle %p",
|
|
Packit |
eace71 |
nlh->nlmsg_len, ev_context->data);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((rc = nlpayload_read(ctrl_fd, ev_context->data,
|
|
Packit |
eace71 |
ev_size, 0)) < 0) {
|
|
Packit |
eace71 |
ipc_ev_clbk->put_ev_context(ev_context);
|
|
Packit |
eace71 |
log_error("can not read from NL socket, error %d", rc);
|
|
Packit |
eace71 |
/* retry later */
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* we sched these events because the handlers could call back
|
|
Packit |
eace71 |
* into ctldev_handle
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
switch (ev->type) {
|
|
Packit |
eace71 |
case ISCSI_KEVENT_RECV_PDU:
|
|
Packit |
eace71 |
rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
|
|
Packit |
eace71 |
EV_CONN_RECV_PDU);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_CONN_ERROR:
|
|
Packit |
eace71 |
memcpy(ev_context->data, &ev->r.connerror.error,
|
|
Packit |
eace71 |
sizeof(ev->r.connerror.error));
|
|
Packit |
eace71 |
rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
|
|
Packit |
eace71 |
EV_CONN_ERROR);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_CONN_LOGIN_STATE:
|
|
Packit |
eace71 |
memcpy(ev_context->data, &ev->r.conn_login.state,
|
|
Packit |
eace71 |
sizeof(ev->r.conn_login.state));
|
|
Packit |
eace71 |
rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
|
|
Packit |
eace71 |
EV_CONN_LOGIN);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case ISCSI_KEVENT_UNBIND_SESSION:
|
|
Packit |
eace71 |
rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
|
|
Packit |
eace71 |
EV_CONN_STOP);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
ipc_ev_clbk->put_ev_context(ev_context);
|
|
Packit |
eace71 |
log_error("unknown kernel event %d", ev->type);
|
|
Packit |
eace71 |
return -EEXIST;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
ipc_ev_clbk->put_ev_context(ev_context);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
ctldev_open(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nlm_sendbuf = calloc(1, NLM_BUF_DEFAULT_MAX);
|
|
Packit |
eace71 |
if (!nlm_sendbuf) {
|
|
Packit |
eace71 |
log_error("can not allocate nlm_sendbuf");
|
|
Packit |
eace71 |
return -1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nlm_recvbuf = calloc(1, NLM_BUF_DEFAULT_MAX);
|
|
Packit |
eace71 |
if (!nlm_recvbuf) {
|
|
Packit |
eace71 |
log_error("can not allocate nlm_recvbuf");
|
|
Packit |
eace71 |
goto free_nlm_sendbuf;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pdu_sendbuf = calloc(1, PDU_SENDBUF_DEFAULT_MAX);
|
|
Packit |
eace71 |
if (!pdu_sendbuf) {
|
|
Packit |
eace71 |
log_error("can not allocate nlm_sendbuf");
|
|
Packit |
eace71 |
goto free_nlm_recvbuf;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
setparam_buf = calloc(1, NLM_SETPARAM_DEFAULT_MAX);
|
|
Packit |
eace71 |
if (!setparam_buf) {
|
|
Packit |
eace71 |
log_error("can not allocate setparam_buf");
|
|
Packit |
eace71 |
goto free_pdu_sendbuf;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ctrl_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ISCSI);
|
|
Packit |
eace71 |
if (ctrl_fd < 0) {
|
|
Packit |
eace71 |
log_error("can not create NETLINK_ISCSI socket [%s]",
|
|
Packit |
eace71 |
strerror(errno));
|
|
Packit |
eace71 |
goto free_setparam_buf;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&src_addr, 0, sizeof(src_addr));
|
|
Packit |
eace71 |
src_addr.nl_family = AF_NETLINK;
|
|
Packit |
eace71 |
src_addr.nl_pid = getpid();
|
|
Packit |
eace71 |
src_addr.nl_groups = 1;
|
|
Packit |
eace71 |
if (bind(ctrl_fd, (struct sockaddr *)&src_addr, sizeof(src_addr))) {
|
|
Packit |
eace71 |
log_error("can not bind NETLINK_ISCSI socket [%s]",
|
|
Packit |
eace71 |
strerror(errno));
|
|
Packit |
eace71 |
goto close_socket;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&dest_addr, 0, sizeof(dest_addr));
|
|
Packit |
eace71 |
dest_addr.nl_family = AF_NETLINK;
|
|
Packit |
eace71 |
dest_addr.nl_pid = 0; /* kernel */
|
|
Packit |
eace71 |
dest_addr.nl_groups = 0; /* unicast */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(7, "created NETLINK_ISCSI socket...");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return ctrl_fd;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
close_socket:
|
|
Packit |
eace71 |
close(ctrl_fd);
|
|
Packit |
eace71 |
free_setparam_buf:
|
|
Packit |
eace71 |
free(setparam_buf);
|
|
Packit |
eace71 |
free_pdu_sendbuf:
|
|
Packit |
eace71 |
free(pdu_sendbuf);
|
|
Packit |
eace71 |
free_nlm_recvbuf:
|
|
Packit |
eace71 |
free(nlm_recvbuf);
|
|
Packit |
eace71 |
free_nlm_sendbuf:
|
|
Packit |
eace71 |
free(nlm_sendbuf);
|
|
Packit |
eace71 |
return -1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
ctldev_close(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
log_debug(7, "in %s", __FUNCTION__);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ctrl_fd >= 0)
|
|
Packit |
eace71 |
close(ctrl_fd);
|
|
Packit |
eace71 |
free(setparam_buf);
|
|
Packit |
eace71 |
free(pdu_sendbuf);
|
|
Packit |
eace71 |
free(nlm_recvbuf);
|
|
Packit |
eace71 |
free(nlm_sendbuf);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_ipc nl_ipc = {
|
|
Packit |
eace71 |
.name = "Open-iSCSI Kernel IPC/NETLINK v.1",
|
|
Packit |
eace71 |
.ctldev_bufmax = NLM_BUF_DEFAULT_MAX,
|
|
Packit |
eace71 |
.ctldev_open = ctldev_open,
|
|
Packit |
eace71 |
.ctldev_close = ctldev_close,
|
|
Packit |
eace71 |
.ctldev_handle = ctldev_handle,
|
|
Packit |
eace71 |
.sendtargets = ksendtargets,
|
|
Packit |
eace71 |
.create_session = kcreate_session,
|
|
Packit |
eace71 |
.destroy_session = kdestroy_session,
|
|
Packit |
eace71 |
.unbind_session = kunbind_session,
|
|
Packit |
eace71 |
.create_conn = kcreate_conn,
|
|
Packit |
eace71 |
.destroy_conn = kdestroy_conn,
|
|
Packit |
eace71 |
.bind_conn = kbind_conn,
|
|
Packit |
eace71 |
.set_param = kset_param,
|
|
Packit |
eace71 |
.set_host_param = kset_host_param,
|
|
Packit |
eace71 |
.get_param = NULL,
|
|
Packit |
eace71 |
.start_conn = kstart_conn,
|
|
Packit |
eace71 |
.stop_conn = kstop_conn,
|
|
Packit |
eace71 |
.get_stats = kget_stats,
|
|
Packit |
eace71 |
.writev = kwritev,
|
|
Packit |
eace71 |
.send_pdu_begin = ksend_pdu_begin,
|
|
Packit |
eace71 |
.send_pdu_end = ksend_pdu_end,
|
|
Packit |
eace71 |
.read = kread,
|
|
Packit |
eace71 |
.recv_pdu_begin = krecv_pdu_begin,
|
|
Packit |
eace71 |
.recv_pdu_end = krecv_pdu_end,
|
|
Packit |
eace71 |
.set_net_config = kset_net_config,
|
|
Packit |
eace71 |
.recv_conn_state = krecv_conn_state,
|
|
Packit |
eace71 |
.exec_ping = kexec_ping,
|
|
Packit |
eace71 |
.get_chap = kget_chap,
|
|
Packit |
eace71 |
.set_chap = kset_chap,
|
|
Packit |
eace71 |
.delete_chap = kdelete_chap,
|
|
Packit |
eace71 |
.set_flash_node_params = kset_flashnode_params,
|
|
Packit |
eace71 |
.new_flash_node = knew_flashnode,
|
|
Packit |
eace71 |
.del_flash_node = kdel_flashnode,
|
|
Packit |
eace71 |
.login_flash_node = klogin_flashnode,
|
|
Packit |
eace71 |
.logout_flash_node = klogout_flashnode,
|
|
Packit |
eace71 |
.logout_flash_node_sid = klogout_flashnode_sid,
|
|
Packit |
eace71 |
.get_host_stats = kget_host_stats,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
struct iscsi_ipc *ipc = &nl_ipc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void ipc_register_ev_callback(struct iscsi_ipc_ev_clbk *ev_clbk)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
ipc_ev_clbk = ev_clbk;
|
|
Packit |
eace71 |
}
|