#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "isns_server.h"
#include "isns_msgq.h"
#include "isns_func.h"
#include "isns_cache.h"
#include "isns_obj.h"
#include "isns_dd.h"
#include "isns_pdu.h"
#include "isns_qry.h"
#include "isns_scn.h"
#include "isns_utils.h"
#include "isns_cfg.h"
#include "isns_esi.h"
#include "isns_provider.h"
#include "isns_log.h"
#ifdef DEBUG
extern int verbose_mc;
extern int verbose_tc;
#endif
extern const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE];
extern const int NUM_OF_CHILD[MAX_OBJ_TYPE];
extern const int TYPE_OF_PARENT[MAX_OBJ_TYPE_FOR_SIZE];
extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
extern const int TAG_RANGE[MAX_OBJ_TYPE][3];
extern msg_queue_t *scn_q;
static int dev_attr_reg(conn_arg_t *);
static int dev_attr_qry(conn_arg_t *);
static int dev_get_next(conn_arg_t *);
static int dev_dereg(conn_arg_t *);
static int scn_reg(conn_arg_t *);
static int scn_dereg(conn_arg_t *);
static int dd_reg(conn_arg_t *);
static int dd_dereg(conn_arg_t *);
static int dds_reg(conn_arg_t *);
static int dds_dereg(conn_arg_t *);
static int msg_error(conn_arg_t *);
static int
packet_get_source(conn_arg_t *conn)
{
int ec = 0;
isns_pdu_t *pdu = conn->in_packet.pdu;
isns_tlv_t *source = pdu_get_source(pdu);
if (source == NULL) {
ec = ISNS_RSP_SRC_ABSENT;
} else if (source->attr_id != ISNS_ISCSI_NAME_ATTR_ID ||
source->attr_len == 0) {
ec = ISNS_RSP_SRC_UNKNOWN;
}
if (ec == 0) {
conn->in_packet.source = source;
}
return (ec);
}
static int
packet_get_key(conn_arg_t *conn)
{
int ec = 0;
isns_pdu_t *pdu = conn->in_packet.pdu;
isns_tlv_t *key;
size_t key_len;
key = pdu_get_key(pdu, &key_len);
conn->in_packet.key = key;
conn->in_packet.key_len = key_len;
return (ec);
}
static int
packet_get_operand(conn_arg_t *conn)
{
int ec = 0;
isns_pdu_t *pdu = conn->in_packet.pdu;
isns_tlv_t *op;
size_t op_len;
op = pdu_get_operand(pdu, &op_len);
conn->in_packet.op = op;
conn->in_packet.op_len = op_len;
return (ec);
}
int
packet_split_verify(conn_arg_t *conn)
{
int ec = 0;
isns_pdu_t *pdu = conn->in_packet.pdu;
int (*handler)(conn_arg_t *) = msg_error;
int lock = CACHE_NO_ACTION;
if (pdu->version != ISNSP_VERSION) {
ec = ISNS_RSP_VER_NOT_SUPPORTED;
} else {
switch (pdu->func_id) {
case ISNS_DEV_ATTR_REG:
lock = CACHE_WRITE;
handler = dev_attr_reg;
break;
case ISNS_DEV_ATTR_QRY:
lock = CACHE_READ;
handler = dev_attr_qry;
break;
case ISNS_DEV_GET_NEXT:
lock = CACHE_READ;
handler = dev_get_next;
break;
case ISNS_DEV_DEREG:
lock = CACHE_WRITE;
handler = dev_dereg;
break;
case ISNS_SCN_REG:
if (scn_q != NULL) {
lock = CACHE_WRITE;
handler = scn_reg;
} else {
ec = ISNS_RSP_SCN_REGIS_REJECTED;
}
break;
case ISNS_SCN_DEREG:
if (scn_q != NULL) {
lock = CACHE_WRITE;
handler = scn_dereg;
} else {
ec = ISNS_RSP_SCN_REGIS_REJECTED;
}
break;
case ISNS_SCN_EVENT:
ec = ISNS_RSP_MSG_NOT_SUPPORTED;
break;
case ISNS_DD_REG:
lock = CACHE_WRITE;
handler = dd_reg;
break;
case ISNS_DD_DEREG:
lock = CACHE_WRITE;
handler = dd_dereg;
break;
case ISNS_DDS_REG:
lock = CACHE_WRITE;
handler = dds_reg;
break;
case ISNS_DDS_DEREG:
lock = CACHE_WRITE;
handler = dds_dereg;
break;
default:
ec = ISNS_RSP_MSG_NOT_SUPPORTED;
break;
}
}
if (ISNS_OPERATION_TYPE_ENABLED()) {
char buf[INET6_ADDRSTRLEN];
struct sockaddr_storage *ssp = &conn->ss;
struct sockaddr_in *sinp = (struct sockaddr_in *)ssp;
if (ssp->ss_family == AF_INET) {
(void) inet_ntop(AF_INET, (void *)&(sinp->sin_addr),
buf, sizeof (buf));
} else {
(void) inet_ntop(AF_INET6, (void *)&(sinp->sin_addr),
buf, sizeof (buf));
}
ISNS_OPERATION_TYPE((uintptr_t)buf, pdu->func_id);
}
conn->lock = lock;
conn->handler = handler;
if (ec == 0) {
ec = packet_get_source(conn);
if (ec == 0) {
ec = packet_get_key(conn);
if (ec == 0) {
ec = packet_get_operand(conn);
}
}
}
conn->ec = ec;
return (ec);
}
static int
setup_key_lcp(lookup_ctrl_t *lcp, isns_tlv_t *key, uint16_t key_len)
{
int ec = 0;
uint8_t *value = &key->attr_value[0];
lcp->curr_uid = 0;
lcp->op[0] = 0;
switch (key->attr_id) {
case ISNS_EID_ATTR_ID:
if (key->attr_len >= 4) {
lcp->type = OBJ_ENTITY;
lcp->id[0] = ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID);
lcp->op[0] = OP_STRING;
lcp->data[0].ptr = (uchar_t *)value;
lcp->op[1] = 0;
}
break;
case ISNS_ISCSI_NAME_ATTR_ID:
if (key->attr_len >= 4) {
lcp->type = OBJ_ISCSI;
lcp->id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
lcp->op[0] = OP_STRING;
lcp->data[0].ptr = (uchar_t *)value;
lcp->op[1] = 0;
} else {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
break;
case ISNS_PORTAL_IP_ADDR_ATTR_ID:
if (key->attr_len == sizeof (in6_addr_t)) {
lcp->id[0] = ATTR_INDEX_PORTAL(
ISNS_PORTAL_IP_ADDR_ATTR_ID);
lcp->op[0] = OP_MEMORY_IP6;
lcp->data[0].ip = (in6_addr_t *)value;
NEXT_TLV(key, key_len);
if (key_len <= 8 ||
key->attr_len != 4 ||
key->attr_id != ISNS_PORTAL_PORT_ATTR_ID) {
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
lcp->type = OBJ_PORTAL;
value = &key->attr_value[0];
lcp->id[1] = ATTR_INDEX_PORTAL(
ISNS_PORTAL_PORT_ATTR_ID);
lcp->op[1] = OP_INTEGER;
lcp->data[1].ui = ntohl(*(uint32_t *)value);
lcp->op[2] = 0;
} else {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
break;
case ISNS_PG_ISCSI_NAME_ATTR_ID:
if (key->attr_len < 4) {
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
lcp->id[0] = ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID);
lcp->op[0] = OP_STRING;
lcp->data[0].ptr = (uchar_t *)value;
NEXT_TLV(key, key_len);
if (key_len <= 8 ||
key->attr_len != sizeof (in6_addr_t) ||
key->attr_id != ISNS_PG_PORTAL_IP_ADDR_ATTR_ID) {
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
value = &key->attr_value[0];
lcp->id[1] = ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID);
lcp->op[1] = OP_MEMORY_IP6;
lcp->data[1].ip = (in6_addr_t *)value;
NEXT_TLV(key, key_len);
if (key_len <= 8 ||
key->attr_len != 4 ||
key->attr_id != ISNS_PG_PORTAL_PORT_ATTR_ID) {
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
value = &key->attr_value[0];
lcp->id[2] = ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID);
lcp->op[2] = OP_INTEGER;
lcp->data[2].ui = ntohl(*(uint32_t *)value);
lcp->type = OBJ_PG;
break;
default:
lcp->type = 0;
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
return (ec);
}
static int
rsp_add_op(conn_arg_t *conn, isns_obj_t *obj)
{
int ec = 0;
isns_attr_t *attr;
int i;
isns_pdu_t *rsp = conn->out_packet.pdu;
size_t pl = conn->out_packet.pl;
size_t sz = conn->out_packet.sz;
i = 0;
while (i < NUM_OF_ATTRS[obj->type] &&
ec == 0) {
attr = &obj->attrs[i];
if (attr->tag != 0) {
ec = pdu_add_tlv(&rsp, &pl, &sz,
attr->tag, attr->len,
(void *)attr->value.ptr, 0);
}
i ++;
}
conn->out_packet.pdu = rsp;
conn->out_packet.pl = pl;
conn->out_packet.sz = sz;
return (ec);
}
static int
rsp_add_key(conn_arg_t *conn, isns_obj_t *entity)
{
int ec = 0;
isns_tlv_t *key = conn->in_packet.key;
size_t key_len = conn->in_packet.key_len;
uint32_t tag = ISNS_EID_ATTR_ID;
isns_attr_t *attr = &entity->attrs[ATTR_INDEX_ENTITY(tag)];
uint32_t len = attr->len;
isns_pdu_t *rsp = conn->out_packet.pdu;
size_t pl = conn->out_packet.pl;
size_t sz = conn->out_packet.sz;
if (key_len == 0) {
ec = pdu_add_tlv(&rsp, &pl, &sz,
tag, len, (void *)attr->value.ptr, 0);
} else {
while (key_len >= 8 &&
ec == 0) {
if (key->attr_id == ISNS_EID_ATTR_ID) {
ec = pdu_add_tlv(&rsp, &pl, &sz,
tag, len,
(void *)attr->value.ptr, 0);
} else {
ec = pdu_add_tlv(&rsp, &pl, &sz,
key->attr_id, key->attr_len,
(void *)key->attr_value, 1);
}
NEXT_TLV(key, key_len);
}
}
if (ec == 0) {
ec = pdu_add_tlv(&rsp, &pl, &sz,
ISNS_DELIMITER_ATTR_ID, 0, NULL, 0);
}
conn->out_packet.pdu = rsp;
conn->out_packet.pl = pl;
conn->out_packet.sz = sz;
if (ec == 0) {
ec = rsp_add_op(conn, entity);
}
return (ec);
}
static int
rsp_add_tlv(conn_arg_t *conn, uint32_t tag, uint32_t len, void *value,
int pflag)
{
int ec = 0;
isns_pdu_t *rsp = conn->out_packet.pdu;
size_t pl = conn->out_packet.pl;
size_t sz = conn->out_packet.sz;
ec = pdu_add_tlv(&rsp, &pl, &sz, tag, len, value, pflag);
conn->out_packet.pdu = rsp;
conn->out_packet.pl = pl;
conn->out_packet.sz = sz;
return (ec);
}
static int
rsp_add_tlvs(conn_arg_t *conn, isns_tlv_t *tlv, uint32_t tlv_len)
{
int ec = 0;
uint32_t tag;
uint32_t len;
void *value;
while (tlv_len >= 8 &&
ec == 0) {
tag = tlv->attr_id;
len = tlv->attr_len;
value = (void *)tlv->attr_value;
ec = rsp_add_tlv(conn, tag, len, value, 1);
NEXT_TLV(tlv, tlv_len);
}
return (ec);
}
static int
dev_attr_reg(conn_arg_t *conn)
{
int ec = 0;
isns_pdu_t *pdu = conn->in_packet.pdu;
isns_tlv_t *source = conn->in_packet.source;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
boolean_t replace =
((pdu->flags & ISNS_FLAG_REPLACE_REG) == ISNS_FLAG_REPLACE_REG);
lookup_ctrl_t lc, lc_key;
uchar_t *iscsi_name;
int ctrl;
isns_obj_t *ety = NULL;
isns_type_t ptype;
uint32_t puid;
void const **child[MAX_CHILD_TYPE] = { NULL };
int ety_update, obj_update;
isns_attr_t *eid_attr;
isns_obj_t *obj;
isns_type_t ctype;
uint32_t uid;
isns_attr_t pgt[3] = { 0 };
void const **vpp = NULL;
int i = 0;
isnslog(LOG_DEBUG, "dev_attr_reg", "entered (replace: %d)", replace);
ec = pdu_reset_rsp(&conn->out_packet.pdu,
&conn->out_packet.pl,
&conn->out_packet.sz);
if (ec != 0) {
goto reg_done;
}
iscsi_name = (uchar_t *)&source->attr_value[0];
ctrl = is_control_node(iscsi_name);
lc_key.type = 0;
if (key != NULL) {
ec = setup_key_lcp(&lc, key, key_len);
if (ec == 0 && lc.type != 0) {
lc_key = lc;
if ((uid = is_obj_there(&lc)) == 0) {
if (lc.type != OBJ_ENTITY) {
ec = ISNS_RSP_INVALID_REGIS;
}
} else if (ctrl == 0 &&
#ifndef SKIP_SRC_AUTH
reg_auth_src(lc.type, uid, iscsi_name) == 0) {
#else
0) {
#endif
ec = ISNS_RSP_SRC_UNAUTHORIZED;
} else if (replace != 0) {
UPDATE_LCP_UID(&lc, uid);
ec = dereg_object(&lc, 0);
if (ec == 0) {
(void) queue_msg_set(scn_q,
SCN_TRIGGER, NULL);
}
}
}
}
if (ec != 0) {
goto reg_done;
}
ec = reg_get_entity(&ety, &op, &op_len);
if (ec != 0) {
goto reg_done;
}
if (ety == NULL && lc_key.type != OBJ_ENTITY) {
ety = make_default_entity();
} else if (ety == NULL ||
(lc_key.type == OBJ_ENTITY &&
key_cmp(&lc_key, ety) != 0)) {
ec = ISNS_RSP_INVALID_REGIS;
goto reg_done;
}
if (ety == NULL || rsp_add_key(conn, ety) != 0) {
ec = ISNS_RSP_INTERNAL_ERROR;
} else {
eid_attr = &ety->attrs[ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)];
ec = register_object(ety, &puid, &ety_update);
ptype = OBJ_ENTITY;
}
if (ec == 0 && ety_update == 0) {
ety = NULL;
}
while (ec == 0 &&
(ec = reg_get_obj(&obj, &pgt[0], &op, &op_len)) == 0 &&
obj != NULL &&
(ec = rsp_add_op(conn, obj)) == 0) {
ctype = obj->type;
(void) set_parent_obj(obj, puid);
ec = register_object(obj, &uid, &obj_update);
if (ec == 0) {
if (obj_update == 0 ||
is_obj_online(obj) == 0) {
(void) update_ref_obj(obj);
ec = buff_child_obj(ptype, ctype, obj, child);
} else {
if (ctrl == 0 &&
#ifndef SKIP_SRC_AUTH
puid != get_parent_uid(obj)) {
#else
0) {
#endif
ec = ISNS_RSP_SRC_UNAUTHORIZED;
}
free_one_object(obj);
}
} else {
free_one_object(obj);
}
}
if (ec == 0) {
ec = verify_ref_obj(ptype, puid, child);
}
if (ec != 0) {
goto reg_done;
}
while (i < MAX_CHILD_TYPE) {
vpp = child[i];
if (vpp != NULL) {
break;
}
i ++;
}
if (vpp != NULL) {
ec = update_child_obj(ptype, puid, child, 1);
} else {
#ifndef SKIP_SRC_AUTH
ec = ISNS_RSP_INVALID_REGIS;
#else
SET_UID_LCP(&lc, OBJ_ENTITY, puid);
ec = dereg_object(&lc, 0);
goto reg_done;
#endif
}
if (ec != 0) {
goto reg_done;
}
if (ety_update != 0) {
(void) esi_remove(puid);
}
ec = esi_add(puid, eid_attr->value.ptr, eid_attr->len);
reg_done:
conn->ec = ec;
free_one_object(ety);
uid = 0;
while (uid < MAX_CHILD_TYPE) {
if (child[uid] != NULL) {
free(child[uid]);
}
uid ++;
}
if (ec != 0) {
isnslog(LOG_DEBUG, "dev_attr_reg", "error code: %d", ec);
}
return (0);
}
static int
dev_attr_qry(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *source = conn->in_packet.source;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
uchar_t *iscsi_name;
bmp_t *nodes_bmp = NULL;
uint32_t num_of_nodes;
uint32_t *key_uids = NULL;
uint32_t num_of_keys;
isns_type_t key_type;
uint32_t key_uid;
uint32_t op_uid;
uint32_t size_of_ops;
uint32_t num_of_ops;
uint32_t *op_uids = NULL;
isns_type_t op_type;
isns_tlv_t *tlv;
uint16_t tlv_len;
isnslog(LOG_DEBUG, "dev_attr_qry", "entered");
ec = pdu_reset_rsp(&conn->out_packet.pdu,
&conn->out_packet.pl,
&conn->out_packet.sz);
if (ec != 0) {
goto qry_done;
}
if (op_len == 0) {
goto qry_done;
}
iscsi_name = (uchar_t *)&source->attr_value[0];
if (is_control_node(iscsi_name) == 0) {
ec = get_scope(iscsi_name, &nodes_bmp, &num_of_nodes);
if (ec != 0 || nodes_bmp == NULL) {
goto qry_done;
}
}
size_of_ops = 0;
if (key != NULL) {
ec = rsp_add_tlvs(conn, key, key_len);
if (ec != 0) {
goto qry_done;
}
ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0);
if (ec != 0) {
goto qry_done;
}
ec = get_qry_keys(nodes_bmp, num_of_nodes, &key_type,
key, key_len, &key_uids, &num_of_keys);
if (ec != 0 || key_uids == NULL) {
goto qry_done;
}
tlv = op;
tlv_len = op_len;
FOR_EACH_OBJS(key_uids, num_of_keys, key_uid, {
op = tlv;
op_len = tlv_len;
FOR_EACH_OP(op, op_len, op_type, {
if (op_type == 0) {
ec = ISNS_RSP_INVALID_QRY;
goto qry_done;
}
ec = get_qry_ops(key_uid, key_type,
op_type, &op_uids,
&num_of_ops, &size_of_ops);
if (ec != 0) {
goto qry_done;
}
FOR_EACH_OBJS(op_uids, num_of_ops, op_uid, {
ec = get_qry_attrs(op_uid, op_type,
op, op_len, conn);
if (ec != 0) {
goto qry_done;
}
});
});
});
} else {
FOR_EACH_OP(op, op_len, op_type, {
ec = get_qry_ops2(nodes_bmp, num_of_nodes,
op_type, &op_uids,
&num_of_ops, &size_of_ops);
if (ec != 0) {
goto qry_done;
}
FOR_EACH_OBJS(op_uids, num_of_ops, op_uid, {
ec = get_qry_attrs(op_uid, op_type,
op, op_len, conn);
if (ec != 0) {
goto qry_done;
}
});
});
}
qry_done:
conn->ec = ec;
if (ec != 0) {
isnslog(LOG_DEBUG, "dev_attr_qry", "error code: %d", ec);
}
free(nodes_bmp);
free(key_uids);
free(op_uids);
return (0);
}
static int
dev_get_next(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *source = conn->in_packet.source;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
uchar_t *iscsi_name;
bmp_t *nodes_bmp = NULL;
uint32_t num_of_nodes;
isns_type_t key_type;
isns_type_t op_type;
uint32_t size_of_obj;
uint32_t num_of_obj;
uint32_t *obj_uids = NULL;
uint32_t uid;
isnslog(LOG_DEBUG, "dev_get_next", "entered");
ec = pdu_reset_rsp(&conn->out_packet.pdu,
&conn->out_packet.pl,
&conn->out_packet.sz);
if (ec != 0) {
goto get_next_done;
}
iscsi_name = (uchar_t *)&source->attr_value[0];
if (is_control_node(iscsi_name) == 0) {
ec = get_scope(iscsi_name, &nodes_bmp, &num_of_nodes);
if (nodes_bmp == NULL) {
ec = ISNS_RSP_NO_SUCH_ENTRY;
}
if (ec != 0) {
goto get_next_done;
}
}
key_type = TLV2TYPE(key);
if (key_type == 0) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
goto get_next_done;
}
ec = validate_qry_key(key_type, key, key_len, NULL);
if (ec != 0) {
goto get_next_done;
}
size_of_obj = 0;
if (op != NULL) {
ec = get_qry_keys(nodes_bmp, num_of_nodes, &op_type,
op, op_len, &obj_uids, &num_of_obj);
if (op_type != key_type) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
} else {
ec = get_qry_ops2(nodes_bmp, num_of_nodes,
key_type, &obj_uids, &num_of_obj, &size_of_obj);
}
if (ec != 0) {
goto get_next_done;
}
uid = get_next_obj(key, key_len, key_type, obj_uids, num_of_obj);
if (uid == 0) {
ec = ISNS_RSP_NO_SUCH_ENTRY;
goto get_next_done;
}
if ((ec = get_qry_attrs1(uid, key_type, key, key_len, conn)) != 0) {
goto get_next_done;
}
if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0)) != 0) {
goto get_next_done;
}
if (op != NULL) {
ec = get_qry_attrs(uid, op_type, op, op_len, conn);
}
get_next_done:
conn->ec = ec;
if (ec != 0 && ec != ISNS_RSP_NO_SUCH_ENTRY) {
isnslog(LOG_DEBUG, "dev_get_next", "error code: %d", ec);
}
free(nodes_bmp);
free(obj_uids);
return (0);
}
static int
dev_dereg(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *source = conn->in_packet.source;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
uchar_t *iscsi_name;
int ctrl;
uint32_t puid;
lookup_ctrl_t lc;
uint8_t *value;
isnslog(LOG_DEBUG, "dev_dereg", "entered");
iscsi_name = (uchar_t *)&source->attr_value[0];
ctrl = is_control_node(iscsi_name);
if (ctrl == 0) {
puid = is_parent_there(iscsi_name);
}
while (op_len > 8 && ec == 0) {
lc.curr_uid = 0;
value = &op->attr_value[0];
switch (op->attr_id) {
case ISNS_EID_ATTR_ID:
lc.id[0] = ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID);
lc.op[0] = OP_STRING;
lc.data[0].ptr = (uchar_t *)value;
lc.op[1] = 0;
lc.type = OBJ_ENTITY;
break;
case ISNS_ISCSI_NAME_ATTR_ID:
lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
lc.op[0] = OP_STRING;
lc.data[0].ptr = (uchar_t *)value;
lc.op[1] = 0;
lc.type = OBJ_ISCSI;
break;
case ISNS_ISCSI_NODE_INDEX_ATTR_ID:
lc.id[0] = ATTR_INDEX_ISCSI(
ISNS_ISCSI_NODE_INDEX_ATTR_ID);
lc.op[0] = OP_INTEGER;
lc.data[0].ui = ntohl(*(uint32_t *)value);
lc.op[1] = 0;
lc.type = OBJ_ISCSI;
break;
case ISNS_PORTAL_IP_ADDR_ATTR_ID:
lc.id[0] = ATTR_INDEX_PORTAL(
ISNS_PORTAL_IP_ADDR_ATTR_ID);
lc.op[0] = OP_MEMORY_IP6;
lc.data[0].ip = (in6_addr_t *)value;
NEXT_TLV(op, op_len);
if (op_len > 8 &&
op->attr_id == ISNS_PORTAL_PORT_ATTR_ID) {
value = &op->attr_value[0];
lc.id[1] = ATTR_INDEX_PORTAL(
ISNS_PORTAL_PORT_ATTR_ID);
lc.op[1] = OP_INTEGER;
lc.data[1].ui = ntohl(*(uint32_t *)value);
lc.op[2] = 0;
lc.type = OBJ_PORTAL;
} else {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
break;
case ISNS_PORTAL_INDEX_ATTR_ID:
lc.id[0] = ATTR_INDEX_PORTAL(
ISNS_PORTAL_INDEX_ATTR_ID);
lc.op[0] = OP_INTEGER;
lc.data[0].ui = ntohl(*(uint32_t *)value);
lc.op[1] = 0;
lc.type = OBJ_PORTAL;
break;
default:
ec = ISNS_RSP_MSG_FORMAT_ERROR;
break;
}
if (ec == 0 &&
(ec = dereg_object(&lc, 0)) == 0) {
if (ctrl == 0 &&
#ifndef SKIP_SRC_AUTH
lc.curr_uid != 0 &&
puid != lc.curr_uid) {
#else
0) {
#endif
ec = ISNS_RSP_SRC_UNAUTHORIZED;
} else {
NEXT_TLV(op, op_len);
}
}
}
conn->ec = ec;
if (ec != 0) {
isnslog(LOG_DEBUG, "dev_dereg", "error code: %d", ec);
}
return (0);
}
static int
scn_reg(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
uchar_t *node_name;
uint32_t nlen;
uint32_t scn;
isnslog(LOG_DEBUG, "scn_reg", "entered");
if (op == NULL ||
op->attr_id != ISNS_ISCSI_SCN_BITMAP_ATTR_ID ||
op_len != 12 ||
key == NULL ||
key->attr_id != ISNS_ISCSI_NAME_ATTR_ID ||
key_len != 8 + key->attr_len) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
goto scn_reg_done;
}
node_name = (uchar_t *)&key->attr_value[0];
nlen = key->attr_len;
scn = ntohl(*(uint32_t *)&op->attr_value[0]);
ec = add_scn_entry(node_name, nlen, scn);
scn_reg_done:
conn->ec = ec;
if (ec != 0) {
isnslog(LOG_DEBUG, "scn_reg", "error code: %d", ec);
}
return (0);
}
static int
scn_dereg(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
uchar_t *node_name;
isnslog(LOG_DEBUG, "scn_dereg", "entered");
if (key != NULL &&
key->attr_len != 0 &&
key_len == 8 + key->attr_len &&
key->attr_id == ISNS_ISCSI_NAME_ATTR_ID) {
node_name = (uchar_t *)&key->attr_value[0];
ec = remove_scn_entry(node_name);
} else {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
conn->ec = ec;
if (ec != 0) {
isnslog(LOG_DEBUG, "scn_dereg", "error code: %d", ec);
}
return (0);
}
#ifndef DEBUG
static
#endif
lookup_ctrl_t *
setup_ddid_lcp(lookup_ctrl_t *lcp, uint32_t dd_id)
{
lcp->curr_uid = 0;
lcp->type = OBJ_DD;
lcp->id[0] = ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID);
lcp->op[0] = OP_INTEGER;
lcp->data[0].ui = dd_id;
lcp->op[1] = 0;
return (lcp);
}
#ifndef DEBUG
static
#endif
lookup_ctrl_t *
setup_ddsid_lcp(lookup_ctrl_t *lcp, uint32_t dds_id)
{
lcp->curr_uid = 0;
lcp->type = OBJ_DDS;
lcp->id[0] = ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID);
lcp->op[0] = OP_INTEGER;
lcp->data[0].ui = dds_id;
lcp->op[1] = 0;
return (lcp);
}
static int
dd_reg(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *source = conn->in_packet.source;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
uint32_t dd_id = 0;
uint8_t *value;
isns_obj_t *dd = NULL;
uchar_t *iscsi_name;
lookup_ctrl_t lc;
isns_assoc_iscsi_t aiscsi;
isns_obj_t *assoc;
isns_attr_t *attr;
uint32_t features;
isnslog(LOG_DEBUG, "dd_reg", "entered");
iscsi_name = (uchar_t *)&source->attr_value[0];
if (is_control_node(iscsi_name) == 0) {
ec = ISNS_RSP_SRC_UNAUTHORIZED;
goto dd_reg_done;
}
ec = pdu_reset_rsp(&conn->out_packet.pdu,
&conn->out_packet.pl,
&conn->out_packet.sz);
if (ec != 0) {
goto dd_reg_done;
}
if (op == NULL ||
(key != NULL &&
(key_len != 12 ||
key->attr_id != ISNS_DD_ID_ATTR_ID ||
key->attr_len != 4 ||
(dd_id = ntohl(*(uint32_t *)&key->attr_value[0])) == 0 ||
is_obj_there(setup_ddid_lcp(&lc, dd_id)) == 0))) {
ec = ISNS_RSP_INVALID_REGIS;
goto dd_reg_done;
}
if (key != NULL &&
(ec = rsp_add_tlv(conn, ISNS_DD_ID_ATTR_ID, 4,
(void *)dd_id, 0)) != 0) {
goto dd_reg_done;
}
if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0,
NULL, 0)) != 0) {
goto dd_reg_done;
}
if (dd_id == 0) {
ec = create_dd_object(op, op_len, &dd);
if (ec == 0) {
ec = register_object(dd, &dd_id, NULL);
if (ec == ERR_NAME_IN_USE) {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec != 0) {
free_object(dd);
goto dd_reg_done;
}
} else {
goto dd_reg_done;
}
}
if (dd != NULL) {
ec = rsp_add_op(conn, dd);
}
aiscsi.type = OBJ_ASSOC_ISCSI;
aiscsi.puid = dd_id;
while (op_len > 8 && ec == 0) {
value = &op->attr_value[0];
switch (op->attr_id) {
case ISNS_DD_ID_ATTR_ID:
if (dd == NULL) {
if (op->attr_len != 4 ||
dd_id != ntohl(*(uint32_t *)value)) {
ec = ISNS_RSP_INVALID_REGIS;
} else {
ec = rsp_add_tlv(conn,
ISNS_DD_ID_ATTR_ID, 4,
(void *)dd_id, 0);
}
}
break;
case ISNS_DD_NAME_ATTR_ID:
if (dd == NULL) {
if (op->attr_len > 0 && op->attr_len <= 256) {
ec = update_dd_name(
dd_id,
op->attr_len,
(uchar_t *)value);
if (ec == ERR_NAME_IN_USE) {
ec = ISNS_RSP_INVALID_REGIS;
}
} else {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec == 0) {
ec = rsp_add_tlv(conn,
ISNS_DD_NAME_ATTR_ID,
op->attr_len, (void *)value, 1);
}
}
break;
case ISNS_DD_ISCSI_INDEX_ATTR_ID:
if (op->attr_len == 4) {
attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
ISNS_DD_ISCSI_INDEX_ATTR_ID)];
attr->tag = ISNS_DD_ISCSI_INDEX_ATTR_ID;
attr->len = 4;
attr->value.ui = ntohl(*(uint32_t *)value);
attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
ISNS_DD_ISCSI_NAME_ATTR_ID)];
attr->tag = 0;
attr->value.ptr = NULL;
assoc = (isns_obj_t *)&aiscsi;
if ((ec = add_dd_member(assoc)) ==
ERR_ALREADY_ASSOCIATED) {
ec = 0;
}
if (attr->value.ptr != NULL) {
free(attr->value.ptr);
}
} else {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec == 0) {
ec = rsp_add_tlv(conn,
ISNS_DD_ISCSI_INDEX_ATTR_ID,
4, (void *)attr->value.ui, 0);
}
break;
case ISNS_DD_ISCSI_NAME_ATTR_ID:
if (op->attr_len > 0 && op->attr_len <= 224) {
attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
ISNS_DD_ISCSI_NAME_ATTR_ID)];
attr->tag = ISNS_DD_ISCSI_NAME_ATTR_ID;
attr->len = op->attr_len;
attr->value.ptr = (uchar_t *)value;
attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
ISNS_DD_ISCSI_INDEX_ATTR_ID)];
attr->tag = 0;
assoc = (isns_obj_t *)&aiscsi;
if ((ec = add_dd_member(assoc)) ==
ERR_ALREADY_ASSOCIATED) {
ec = 0;
}
} else {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec == 0) {
ec = rsp_add_tlv(conn,
ISNS_DD_ISCSI_NAME_ATTR_ID,
op->attr_len, (void *)value, 1);
}
break;
case ISNS_DD_FC_PORT_NAME_ATTR_ID:
case ISNS_DD_PORTAL_INDEX_ATTR_ID:
case ISNS_DD_PORTAL_IP_ADDR_ATTR_ID:
case ISNS_DD_PORTAL_PORT_ATTR_ID:
ec = ISNS_RSP_REGIS_NOT_SUPPORTED;
break;
case ISNS_DD_FEATURES_ATTR_ID:
if (dd == NULL) {
if (op->attr_len == 4) {
features = ntohl(*(uint32_t *)value);
ec = update_dd_features(
dd_id, features);
} else {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec == 0) {
ec = rsp_add_tlv(conn,
ISNS_DD_FEATURES_ATTR_ID,
4, (void *)features, 0);
}
}
break;
default:
ec = ISNS_RSP_INVALID_REGIS;
break;
}
NEXT_TLV(op, op_len);
}
dd_reg_done:
conn->ec = ec;
if (ec != 0) {
isnslog(LOG_DEBUG, "dd_reg", "error code: %d", ec);
}
return (0);
}
static int
dds_reg(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *source = conn->in_packet.source;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
uint32_t dds_id = 0;
uint8_t *value;
isns_obj_t *dds = NULL;
uchar_t *iscsi_name;
lookup_ctrl_t lc;
isns_assoc_dd_t add;
isns_obj_t *assoc;
isns_attr_t *attr;
uint32_t code;
isnslog(LOG_DEBUG, "dds_reg", "entered");
iscsi_name = (uchar_t *)&source->attr_value[0];
if (is_control_node(iscsi_name) == 0) {
ec = ISNS_RSP_SRC_UNAUTHORIZED;
goto dds_reg_done;
}
ec = pdu_reset_rsp(&conn->out_packet.pdu,
&conn->out_packet.pl,
&conn->out_packet.sz);
if (ec != 0) {
goto dds_reg_done;
}
if (op == NULL ||
(key != NULL &&
(key_len != 12 ||
key->attr_id != ISNS_DD_SET_ID_ATTR_ID ||
key->attr_len != 4 ||
(dds_id = ntohl(*(uint32_t *)&key->attr_value[0])) == 0 ||
is_obj_there(setup_ddsid_lcp(&lc, dds_id)) == 0))) {
ec = ISNS_RSP_INVALID_REGIS;
goto dds_reg_done;
}
if (key != NULL &&
(ec = rsp_add_tlv(conn, ISNS_DD_SET_ID_ATTR_ID, 4,
(void *)dds_id, 0)) != 0) {
goto dds_reg_done;
}
if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0,
NULL, 0)) != 0) {
goto dds_reg_done;
}
if (dds_id == 0) {
ec = create_dds_object(op, op_len, &dds);
if (ec == 0) {
ec = register_object(dds, &dds_id, NULL);
if (ec == ERR_NAME_IN_USE) {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec != 0) {
free_object(dds);
goto dds_reg_done;
}
} else {
goto dds_reg_done;
}
}
if (dds != NULL) {
ec = rsp_add_op(conn, dds);
}
add.type = OBJ_ASSOC_DD;
add.puid = dds_id;
while (op_len > 8 && ec == 0) {
value = &op->attr_value[0];
switch (op->attr_id) {
case ISNS_DD_SET_ID_ATTR_ID:
if (dds == NULL) {
if (op->attr_len != 4 ||
dds_id != ntohl(*(uint32_t *)value)) {
ec = ISNS_RSP_INVALID_REGIS;
} else {
ec = rsp_add_tlv(conn,
ISNS_DD_SET_ID_ATTR_ID,
4, (void *)dds_id, 0);
}
}
break;
case ISNS_DD_SET_NAME_ATTR_ID:
if (dds == NULL) {
if (op->attr_len > 0 && op->attr_len <= 256) {
ec = update_dds_name(
dds_id,
op->attr_len,
(uchar_t *)value);
if (ec == ERR_NAME_IN_USE) {
ec = ISNS_RSP_INVALID_REGIS;
}
} else {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec == 0) {
ec = rsp_add_tlv(conn,
ISNS_DD_SET_NAME_ATTR_ID,
op->attr_len, (void *)value, 1);
}
}
break;
case ISNS_DD_SET_STATUS_ATTR_ID:
if (dds == NULL) {
if (op->attr_len == 4) {
code = ntohl(*(uint32_t *)value);
ec = update_dds_status(
dds_id, code);
} else {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec == 0) {
ec = rsp_add_tlv(conn,
ISNS_DD_SET_STATUS_ATTR_ID,
4, (void *)code, 0);
}
}
break;
case ISNS_DD_ID_ATTR_ID:
if (op->attr_len == 4) {
attr = &add.attrs[ATTR_INDEX_ASSOC_DD(
ISNS_DD_ID_ATTR_ID)];
attr->tag = ISNS_DD_ID_ATTR_ID;
attr->len = 4;
attr->value.ui = ntohl(*(uint32_t *)value);
assoc = (isns_obj_t *)&add;
if ((ec = add_dds_member(assoc)) ==
ERR_ALREADY_ASSOCIATED) {
ec = 0;
}
} else {
ec = ISNS_RSP_INVALID_REGIS;
}
if (ec == 0) {
ec = rsp_add_tlv(conn,
ISNS_DD_ID_ATTR_ID, 4,
(void *)attr->value.ui, 0);
}
break;
default:
ec = ISNS_RSP_INVALID_REGIS;
break;
}
NEXT_TLV(op, op_len);
}
dds_reg_done:
conn->ec = ec;
if (ec != 0) {
isnslog(LOG_DEBUG, "dds_reg", "error code: %d", ec);
}
return (0);
}
static int
dd_dereg(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *source = conn->in_packet.source;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
uint32_t dd_id;
uint8_t *value;
uchar_t *iscsi_name;
isns_assoc_iscsi_t aiscsi;
isns_obj_t *assoc;
isns_attr_t *attr;
isnslog(LOG_DEBUG, "dd_dereg", "entered");
iscsi_name = (uchar_t *)&source->attr_value[0];
if (is_control_node(iscsi_name) == 0) {
ec = ISNS_RSP_SRC_UNAUTHORIZED;
goto dd_dereg_done;
}
if (key == NULL ||
key_len != 12 ||
key->attr_id != ISNS_DD_ID_ATTR_ID ||
(dd_id = ntohl(*(uint32_t *)&key->attr_value[0])) == 0) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
goto dd_dereg_done;
}
if (op == NULL) {
ec = remove_dd_object(dd_id);
} else {
aiscsi.type = OBJ_ASSOC_ISCSI;
aiscsi.puid = dd_id;
while (op_len > 8 && ec == 0) {
value = &op->attr_value[0];
switch (op->attr_id) {
case ISNS_DD_ISCSI_INDEX_ATTR_ID:
attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
ISNS_DD_ISCSI_INDEX_ATTR_ID)];
attr->tag = ISNS_DD_ISCSI_INDEX_ATTR_ID;
attr->len = 4;
attr->value.ui = ntohl(*(uint32_t *)value);
attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
ISNS_DD_ISCSI_NAME_ATTR_ID)];
attr->tag = 0;
attr->value.ptr = NULL;
assoc = (isns_obj_t *)&aiscsi;
if ((ec = remove_dd_member(assoc)) ==
ERR_NO_SUCH_ASSOCIATION) {
ec = 0;
}
if (attr->value.ptr != NULL) {
free(attr->value.ptr);
}
break;
case ISNS_DD_ISCSI_NAME_ATTR_ID:
attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
ISNS_DD_ISCSI_NAME_ATTR_ID)];
attr->tag = ISNS_DD_ISCSI_NAME_ATTR_ID;
attr->len = op->attr_len;
attr->value.ptr = (uchar_t *)value;
attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
ISNS_DD_ISCSI_INDEX_ATTR_ID)];
attr->tag = 0;
assoc = (isns_obj_t *)&aiscsi;
if ((ec = remove_dd_member(assoc)) ==
ERR_NO_SUCH_ASSOCIATION) {
ec = 0;
}
break;
case ISNS_DD_FC_PORT_NAME_ATTR_ID:
case ISNS_DD_PORTAL_INDEX_ATTR_ID:
case ISNS_DD_PORTAL_IP_ADDR_ATTR_ID:
case ISNS_DD_PORTAL_PORT_ATTR_ID:
ec = ISNS_RSP_REGIS_NOT_SUPPORTED;
break;
default:
ec = ISNS_RSP_MSG_FORMAT_ERROR;
break;
}
NEXT_TLV(op, op_len);
}
}
dd_dereg_done:
conn->ec = ec;
if (ec != 0) {
isnslog(LOG_DEBUG, "dd_dereg", "error code: %d", ec);
}
return (0);
}
static int
dds_dereg(conn_arg_t *conn)
{
int ec = 0;
isns_tlv_t *source = conn->in_packet.source;
isns_tlv_t *key = conn->in_packet.key;
uint16_t key_len = conn->in_packet.key_len;
isns_tlv_t *op = conn->in_packet.op;
uint16_t op_len = conn->in_packet.op_len;
uint32_t dds_id;
uint32_t uid;
uint8_t *value;
uchar_t *iscsi_name;
isnslog(LOG_DEBUG, "dds_dereg", "entered");
iscsi_name = (uchar_t *)&source->attr_value[0];
if (is_control_node(iscsi_name) == 0) {
ec = ISNS_RSP_SRC_UNAUTHORIZED;
goto dds_dereg_done;
}
if (key == NULL ||
key_len != 12 ||
key->attr_id != ISNS_DD_SET_ID_ATTR_ID ||
(dds_id = ntohl(*(uint32_t *)&key->attr_value[0])) == 0) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
goto dds_dereg_done;
}
if (op == NULL) {
ec = remove_dds_object(dds_id);
} else {
while (op_len > 8 && ec == 0) {
value = &op->attr_value[0];
if (op->attr_id == ISNS_DD_ID_ATTR_ID) {
uid = ntohl(*(uint32_t *)value);
if ((ec = remove_dds_member(dds_id, uid)) ==
ERR_NO_SUCH_ASSOCIATION) {
ec = 0;
}
} else {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
NEXT_TLV(op, op_len);
}
}
dds_dereg_done:
conn->ec = ec;
if (ec != 0) {
isnslog(LOG_DEBUG, "dds_dereg", "error code: %d", ec);
}
return (0);
}
static int
msg_error(conn_arg_t *conn __unused)
{
return (0);
}
static int
isns_response_ec(int so, isns_pdu_t *pdu, int ec)
{
int status;
uint8_t buff[sizeof (isns_pdu_t) + 8];
isns_pdu_t *rsp = (isns_pdu_t *)&buff;
isns_resp_t *resp = (isns_resp_t *)rsp->payload;
size_t pl = 4;
rsp->version = htons((uint16_t)ISNSP_VERSION);
rsp->func_id = htons(pdu->func_id | ISNS_RSP_MASK);
rsp->xid = htons(pdu->xid);
resp->status = htonl(ec);
status = isns_send_pdu(so, rsp, pl);
return (status);
}
int
isns_response(conn_arg_t *conn)
{
int status;
int so = conn->so;
int ec = conn->ec;
isns_pdu_t *pdu = conn->in_packet.pdu;
isns_pdu_t *rsp = conn->out_packet.pdu;
size_t pl = conn->out_packet.pl;
if (rsp != NULL) {
rsp->version = htons((uint16_t)ISNSP_VERSION);
rsp->func_id = htons(pdu->func_id | ISNS_RSP_MASK);
rsp->xid = htons(pdu->xid);
(void) pdu_update_code(rsp, &pl, ec);
status = isns_send_pdu(so, rsp, pl);
} else {
status = isns_response_ec(so, pdu, ec);
}
return (status);
}