#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.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_htab.h"
#include "isns_cache.h"
#include "isns_pdu.h"
#include "isns_obj.h"
#include "isns_dd.h"
#include "isns_func.h"
#include "isns_dseng.h"
#include "isns_log.h"
#include "isns_scn.h"
#include "isns_utils.h"
#include "isns_esi.h"
#ifdef DEBUG
extern int verbose_mc;
extern void print_object(char *, isns_obj_t *);
#endif
extern msg_queue_t *sys_q;
extern msg_queue_t *scn_q;
extern pthread_mutex_t el_mtx;
extern int cache_flag;
const int TYPE_OF_PARENT[MAX_OBJ_TYPE_FOR_SIZE] = {
0,
0,
ISCSI_PARENT_TYPE,
PORTAL_PARENT_TYPE,
PG_PARENT_TYPE,
0,
0,
0,
0,
0,
0,
0,
ASSOC_ISCSI_PARENT_TYPE,
ASSOC_DD_PARENT_TYPE
};
const int NUM_OF_CHILD[MAX_OBJ_TYPE] = {
0,
MAX_ENTITY_CHILD,
MAX_ISCSI_CHILD,
MAX_PORTAL_CHILD,
MAX_PG_CHILD,
0,
0
};
const int TYPE_OF_CHILD[MAX_OBJ_TYPE][MAX_CHILD_TYPE] = {
{ 0, 0 },
{ OBJ_ISCSI, OBJ_PORTAL },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
};
const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE] = {
0,
NUM_OF_ENTITY_ATTRS,
NUM_OF_ISCSI_ATTRS,
NUM_OF_PORTAL_ATTRS,
NUM_OF_PG_ATTRS,
NUM_OF_DD_ATTRS,
NUM_OF_DDS_ATTRS,
0,
0,
0,
0,
0,
NUM_OF_ASSOC_ISCSI_ATTRS,
NUM_OF_ASSOC_DD_ATTRS
};
static const int UID_TAG[MAX_OBJ_TYPE_FOR_SIZE] = {
0,
ISNS_ENTITY_INDEX_ATTR_ID,
ISNS_ISCSI_NODE_INDEX_ATTR_ID,
ISNS_PORTAL_INDEX_ATTR_ID,
ISNS_PG_INDEX_ATTR_ID,
ISNS_DD_ID_ATTR_ID,
ISNS_DD_SET_ID_ATTR_ID,
0,
0,
0,
0,
0,
ISNS_DD_ISCSI_INDEX_ATTR_ID,
ISNS_DD_ID_ATTR_ID
};
const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE] = {
0,
ATTR_INDEX_ENTITY(ISNS_ENTITY_INDEX_ATTR_ID),
ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_INDEX_ATTR_ID),
ATTR_INDEX_PORTAL(ISNS_PORTAL_INDEX_ATTR_ID),
ATTR_INDEX_PG(ISNS_PG_INDEX_ATTR_ID),
ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID),
ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID),
0,
0,
0,
0,
0,
ATTR_INDEX_ASSOC_ISCSI(ISNS_DD_ISCSI_INDEX_ATTR_ID),
ATTR_INDEX_ASSOC_DD(ISNS_DD_ID_ATTR_ID)
};
static const int KEY_ATTR_INDEX[MAX_OBJ_TYPE][MAX_KEY_ATTRS] = {
{ 0 },
{ ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID), 0 },
{ ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID),
0 },
{ ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID),
ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID),
0 },
{ ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID),
ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID),
ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID) },
{ ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID), 0 },
{ ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID), 0 }
};
static const int KEY_ATTR_OP[MAX_OBJ_TYPE][MAX_KEY_ATTRS] = {
{ 0 },
{ OP_STRING, 0 },
{ OP_STRING, 0 },
{ OP_MEMORY_IP6, OP_INTEGER, 0 },
{ OP_STRING, OP_MEMORY_IP6, OP_INTEGER },
{ OP_STRING, 0 },
{ OP_STRING, 0 }
};
static const int SIZEOF_OBJ[MAX_OBJ_TYPE_FOR_SIZE] = {
0,
sizeof (isns_entity_t),
sizeof (isns_iscsi_t),
sizeof (isns_portal_t),
sizeof (isns_pg_t),
sizeof (isns_dd_t),
sizeof (isns_dds_t),
0,
0,
0,
0,
0,
sizeof (isns_assoc_iscsi_t),
sizeof (isns_assoc_dd_t)
};
#ifdef DEBUG
const int NUM_OF_REF[MAX_OBJ_TYPE_FOR_SIZE] = {
#else
static const int NUM_OF_REF[MAX_OBJ_TYPE_FOR_SIZE] = {
#endif
0,
0,
0,
0,
PG_REF_COUNT,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
static const int TYPE_OF_REF[MAX_OBJ_TYPE][MAX_REF_COUNT + 1] = {
{ 0 },
{ 0 },
{ OBJ_PG, OBJ_PORTAL, 0 },
{ OBJ_PG, OBJ_ISCSI, 0 },
{ 0, OBJ_ISCSI, OBJ_PORTAL },
{ 0 },
{ 0 }
};
#define MAX_REF_MATCH (2)
static const int REF_MATCH_OPS[MAX_OBJ_TYPE][MAX_REF_MATCH] = {
{ 0, 0 },
{ 0, 0 },
{ OP_STRING, 0 },
{ OP_MEMORY_IP6, OP_INTEGER },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
};
static const int REF_MATCH_ID1[MAX_OBJ_TYPE][MAX_REF_MATCH] = {
{ 0, 0 },
{ 0, 0 },
{ ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID), 0 },
{ ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID),
ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID) },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
};
static const int REF_MATCH_ID2[MAX_OBJ_TYPE][MAX_REF_MATCH] = {
{ 0, 0 },
{ 0, 0 },
{ ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID), 0 },
{ ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID),
ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID) },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
};
static uint32_t get_reg_period();
static char *make_unique_name(int *, uint32_t);
static lookup_ctrl_t *set_lookup_ctrl(lookup_ctrl_t *, isns_obj_t *);
static int setup_ref_lcp(lookup_ctrl_t *,
const isns_obj_t *, const isns_obj_t *);
static int setup_deref_lcp(lookup_ctrl_t *,
const isns_obj_t *, isns_type_t);
static int cb_get_parent(void *, void *);
static int cb_node_child(void *, void *);
static int cb_set_ref(void *, void *);
static int cb_clear_ref(void *, void *);
static int cb_add_child(void *, void *);
static int cb_remove_child(void *, void *);
static int cb_verify_ref(void *, void *);
static int cb_ref_new2old(void *, void *);
static int cb_new_ref(void *, void *);
static int ref_new2old(
lookup_ctrl_t *, isns_type_t, uint32_t, const isns_obj_t *);
static int ref_new2new(
lookup_ctrl_t *, const isns_obj_t *, const isns_obj_t *);
static int new_ref(const isns_obj_t *, const isns_obj_t *);
static uint32_t setup_parent_lcp(lookup_ctrl_t *, isns_obj_t *);
static int set_obj_offline(isns_obj_t *);
static int copy_attrs(isns_obj_t *, const isns_obj_t *);
static isns_obj_t *make_default_pg(const isns_obj_t *, const isns_obj_t *);
static isns_obj_t *(*const make_ref[MAX_OBJ_TYPE])
(const isns_obj_t *, const isns_obj_t *) = {
NULL,
NULL,
&make_default_pg,
&make_default_pg,
NULL,
NULL,
NULL
};
static uint32_t entity_hval(void *, uint16_t, uint32_t *);
static uint32_t iscsi_hval(void *, uint16_t, uint32_t *);
static uint32_t portal_hval(void *, uint16_t, uint32_t *);
static uint32_t pg_hval(void *, uint16_t, uint32_t *);
static uint32_t dd_hval(void *, uint16_t, uint32_t *);
static uint32_t dds_hval(void *, uint16_t, uint32_t *);
static uint32_t (*const hval_func[MAX_OBJ_TYPE])
(void *, uint16_t, uint32_t *) = {
NULL,
&entity_hval,
&iscsi_hval,
&portal_hval,
&pg_hval,
&dd_hval,
&dds_hval
};
static uint32_t
entity_hval(
void *p,
uint16_t chunk,
uint32_t *flags
)
{
uchar_t *key;
isns_obj_t *obj;
lookup_ctrl_t *lcp;
if ((*flags & FLAGS_CTRL_MASK) == 0) {
obj = (isns_obj_t *)p;
key = obj->attrs[ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)].
value.ptr;
} else {
lcp = (lookup_ctrl_t *)p;
key = lcp->data[0].ptr;
}
return (htab_compute_hval(key));
}
static uint32_t
iscsi_hval(
void *p,
uint16_t chunk,
uint32_t *flags
)
{
uchar_t *key;
isns_obj_t *obj;
lookup_ctrl_t *lcp;
if ((*flags & FLAGS_CTRL_MASK) == 0) {
obj = (isns_obj_t *)p;
key = obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)].
value.ptr;
} else {
lcp = (lookup_ctrl_t *)p;
key = lcp->data[0].ptr;
}
return (htab_compute_hval(key));
}
static uint32_t
portal_hval(
void *p,
uint16_t chunk,
uint32_t *flags
)
{
char buff[INET6_ADDRSTRLEN + 8] = { 0 };
char buff2[8] = { 0 };
uchar_t *key;
isns_obj_t *obj;
lookup_ctrl_t *lcp;
in6_addr_t *ip;
uint32_t port;
if ((*flags & FLAGS_CTRL_MASK) == 0) {
obj = (isns_obj_t *)p;
ip = obj->attrs[ATTR_INDEX_PORTAL
(ISNS_PORTAL_IP_ADDR_ATTR_ID)].value.ip;
port = obj->attrs[ATTR_INDEX_PORTAL
(ISNS_PORTAL_PORT_ATTR_ID)].value.ui;
} else {
lcp = (lookup_ctrl_t *)p;
ip = lcp->data[0].ip;
port = lcp->data[1].ui;
}
key = (uchar_t *)inet_ntop(AF_INET6, (void *)ip,
buff, sizeof (buff));
(void) snprintf(buff2, sizeof (buff2), "%d", port);
(void) strcat((char *)key, buff2);
return (htab_compute_hval(key));
}
static uint32_t
pg_hval(
void *p,
uint16_t chunk,
uint32_t *flags
)
{
char buff[INET6_ADDRSTRLEN + 8] = { 0 };
char buff2[8] = { 0 };
uchar_t *key = NULL;
isns_obj_t *obj;
lookup_ctrl_t *lcp;
in6_addr_t *ip = NULL;
uint32_t port;
if ((*flags & FLAGS_CTRL_MASK) == 0) {
obj = (isns_obj_t *)p;
if (chunk == 0) {
key = obj->attrs[ATTR_INDEX_PG
(ISNS_PG_ISCSI_NAME_ATTR_ID)].value.ptr;
} else {
ip = obj->attrs[ATTR_INDEX_PG
(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)].value.ip;
port = obj->attrs[ATTR_INDEX_PG
(ISNS_PG_PORTAL_PORT_ATTR_ID)].value.ui;
}
} else {
lcp = (lookup_ctrl_t *)p;
*flags &= ~FLAGS_CHUNK_MASK;
if (lcp->op[0] == OP_STRING) {
key = lcp->data[0].ptr;
} else {
ip = lcp->data[0].ip;
port = lcp->data[1].ui;
*flags |= 1;
}
}
if (key == NULL) {
key = (uchar_t *)inet_ntop(AF_INET6, (void *)ip,
buff, sizeof (buff));
(void) snprintf(buff2, sizeof (buff2), "%d", port);
(void) strcat((char *)key, buff2);
}
return (htab_compute_hval(key));
}
static uint32_t
dd_hval(
void *p,
uint16_t chunk,
uint32_t *flags
)
{
uchar_t *key;
isns_obj_t *obj;
lookup_ctrl_t *lcp;
if ((*flags & FLAGS_CTRL_MASK) == 0) {
obj = (isns_obj_t *)p;
key = obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)].
value.ptr;
} else {
lcp = (lookup_ctrl_t *)p;
key = lcp->data[0].ptr;
}
return (htab_compute_hval(key));
}
static uint32_t
dds_hval(
void *p,
uint16_t chunk,
uint32_t *flags
)
{
uchar_t *key;
isns_obj_t *obj;
lookup_ctrl_t *lcp;
if ((*flags & FLAGS_CTRL_MASK) == 0) {
obj = (isns_obj_t *)p;
key = obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID)].
value.ptr;
} else {
lcp = (lookup_ctrl_t *)p;
key = lcp->data[0].ptr;
}
return (htab_compute_hval(key));
}
uint32_t
obj_hval(
void *p,
uint16_t chunk,
uint32_t *flags
)
{
isns_type_t type = ((isns_obj_t *)p)->type;
return (hval_func[type](p, chunk, flags));
}
uint32_t
get_obj_uid(
const void *p
)
{
isns_obj_t *obj = (isns_obj_t *)p;
isns_attr_t *attr = &obj->attrs[UID_ATTR_INDEX[obj->type]];
uint32_t uid = attr->value.ui;
return (uid);
}
uint32_t
set_obj_uid(
void *p,
uint32_t uid
)
{
isns_obj_t *obj = (isns_obj_t *)p;
isns_attr_t *attr = &obj->attrs[UID_ATTR_INDEX[obj->type]];
attr->tag = UID_TAG[obj->type];
attr->len = 4;
attr->value.ui = uid;
return (uid);
}
int
obj_cmp(
void *p1,
void *p2,
int flags
)
{
isns_obj_t *obj = (isns_obj_t *)p1;
lookup_ctrl_t buff = { 0 };
lookup_ctrl_t *lcp;
uint32_t uid;
if (flags == 0) {
lcp = set_lookup_ctrl(&buff, (isns_obj_t *)p2);
} else {
lcp = (lookup_ctrl_t *)p2;
uid = get_obj_uid(obj);
if (lcp->curr_uid != 0 && uid >= lcp->curr_uid) {
return (-1);
}
}
return (key_cmp(lcp, obj));
}
int
replace_object(
void *p1,
void *p2,
uint32_t *uid_p,
int flag
)
{
int ec = 0;
#ifndef SKIP_SRC_AUTH
uint32_t *pp_dst, *pp_src, swap;
#endif
int online;
isns_obj_t *dst = (isns_obj_t *)p1;
isns_obj_t *src = (isns_obj_t *)p2;
if (src->type == OBJ_DD || src->type == OBJ_DDS) {
return (ERR_NAME_IN_USE);
}
online = is_obj_online(dst);
SET_CACHE_UPDATED();
#ifndef SKIP_SRC_AUTH
pp_dst = get_parent_p(dst);
if (pp_dst != NULL) {
pp_src = get_parent_p(src);
swap = *pp_dst;
*pp_dst = *pp_src;
if (swap != 0) {
*pp_src = swap;
}
}
#endif
if (copy_attrs(dst, src) != 0) {
return (ISNS_RSP_INTERNAL_ERROR);
}
if (flag != 0) {
(void) free_object(src);
} else if (online == 0) {
(void) set_obj_uid(src, get_obj_uid(dst));
(void) set_obj_offline(src);
}
if (sys_q != NULL) {
ec = write_data(DATA_UPDATE, dst);
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
if (ec == 0) {
if (scn_q != NULL) {
(void) make_scn((online == 0) ?
ISNS_OBJECT_ADDED :
ISNS_OBJECT_UPDATED,
dst);
}
if (uid_p != NULL) {
*uid_p = get_obj_uid(dst);
}
}
return (ec);
}
int
add_object(
void *p
)
{
int ec = 0;
isns_obj_t *obj = (isns_obj_t *)p;
if (sys_q != NULL) {
ec = write_data(DATA_ADD, obj);
}
if (ec == 0 && scn_q != NULL) {
(void) make_scn(ISNS_OBJECT_ADDED, obj);
}
return (ec);
}
int
obj_tab_init(
struct cache *c
)
{
htab_t *t;
htab_init();
c->t = (struct htab **)calloc(sizeof (struct htab *), MAX_OBJ_TYPE);
if (c->t == NULL) {
return (1);
}
t = htab_create(UID_FLAGS_SEQ, 8, 1);
if (t != NULL) {
t->c = c;
c->t[OBJ_ENTITY] = t;
} else {
return (1);
}
t = htab_create(UID_FLAGS_SEQ, 8, 1);
if (t != NULL) {
t->c = c;
c->t[OBJ_ISCSI] = t;
} else {
return (1);
}
t = htab_create(UID_FLAGS_SEQ, 8, 1);
if (t != NULL) {
t->c = c;
c->t[OBJ_PORTAL] = t;
} else {
return (1);
}
t = htab_create(UID_FLAGS_SEQ, 8, 2);
if (t != NULL) {
t->c = c;
c->t[OBJ_PG] = t;
} else {
return (1);
}
t = htab_create(0, 6, 1);
if (t != NULL) {
t->c = c;
c->t[OBJ_DD] = t;
} else {
return (1);
}
t = htab_create(0, 4, 1);
if (t != NULL) {
t->c = c;
c->t[OBJ_DDS] = t;
} else {
return (1);
}
return (0);
}
static uint32_t *
get_ref_np(
isns_obj_t *obj,
int n
)
{
uint32_t *refp =
obj->type == OBJ_PG ? &((isns_pg_t *)obj)->ref[n] : NULL;
return (refp);
}
#ifdef DEBUG
uint32_t
#else
static uint32_t
#endif
get_ref_n(
isns_obj_t *obj,
int n
)
{
return (*get_ref_np(obj, n));
}
static uint32_t *
get_ref_p(
isns_obj_t *obj,
isns_type_t rt
)
{
isns_type_t t = obj->type;
int i = 0;
while (i < NUM_OF_REF[t]) {
if (rt == TYPE_OF_REF[t][i + 1]) {
return (get_ref_np(obj, i));
}
i ++;
}
return (NULL);
}
uint32_t
get_ref_t(
isns_obj_t *obj,
isns_type_t type
)
{
uint32_t *refp = get_ref_p(obj, type);
if (refp != NULL) {
return (*refp);
} else {
ASSERT(0);
}
return (0);
}
uint32_t *const
get_parent_p(
const isns_obj_t *obj
)
{
uint32_t *pp;
switch (obj->type) {
case OBJ_ISCSI:
pp = &((isns_iscsi_t *)obj)->puid;
break;
case OBJ_PORTAL:
pp = &((isns_portal_t *)obj)->puid;
break;
case OBJ_PG:
pp = &((isns_pg_t *)obj)->puid;
break;
case OBJ_ASSOC_ISCSI:
pp = &((isns_assoc_iscsi_t *)obj)->puid;
break;
case OBJ_ASSOC_DD:
pp = &((isns_assoc_dd_t *)obj)->puid;
break;
default:
pp = NULL;
break;
}
return (pp);
}
uint32_t
get_parent_uid(
const isns_obj_t *obj
)
{
uint32_t *pp = get_parent_p(obj);
if (pp != NULL) {
return (*pp);
}
return (0);
}
static uint32_t **
get_child_np(
isns_obj_t *obj,
int n
)
{
uint32_t **pp =
obj->type == OBJ_ENTITY ? &((isns_entity_t *)obj)->cuid[n] : NULL;
return (pp);
}
#ifdef DEBUG
uint32_t *
#else
static uint32_t *
#endif
get_child_n(
isns_obj_t *obj,
int n
)
{
uint32_t **pp = get_child_np(obj, n);
if (pp != NULL) {
return (*pp);
}
ASSERT(0);
return (NULL);
}
static uint32_t **
get_child_p(
isns_obj_t *base,
int child_type
)
{
uint32_t **pp = NULL;
int i = 0;
while (i < NUM_OF_CHILD[base->type]) {
if (child_type == TYPE_OF_CHILD[base->type][i]) {
pp = get_child_np(base, i);
break;
}
i ++;
}
return (pp);
}
uint32_t *
get_child_t(
isns_obj_t *base,
int child_type
)
{
uint32_t **pp = get_child_p(base, child_type);
if (pp != NULL) {
return (*pp);
} else {
return (NULL);
}
}
int
key_cmp(
lookup_ctrl_t *lcp,
isns_obj_t *obj
)
{
int i = 0;
int match = 1;
while (i < MAX_LOOKUP_CTRL && lcp->op[i] > 0 && match) {
isns_attr_t *attr = &obj->attrs[lcp->id[i]];
switch (lcp->op[i]) {
case OP_STRING:
match = (strcmp((const char *)lcp->data[i].ptr,
(const char *)attr->value.ptr) == 0);
break;
case OP_INTEGER:
match = (lcp->data[i].ui == attr->value.ui);
break;
case OP_MEMORY_IP6:
match = !memcmp((void *)lcp->data[i].ip,
(void *)attr->value.ip,
sizeof (in6_addr_t));
break;
default:
ASSERT(0);
match = 0;
break;
}
i ++;
}
if (i && match) {
return (0);
} else {
return (1);
}
}
static lookup_ctrl_t *
set_lookup_ctrl(
lookup_ctrl_t *lcp,
isns_obj_t *obj
)
{
isns_type_t type = obj->type;
uint32_t id, op;
int i = 0;
lcp->type = type;
while (i < MAX_KEY_ATTRS) {
op = KEY_ATTR_OP[type][i];
if (op != 0) {
id = KEY_ATTR_INDEX[type][i];
lcp->id[i] = id;
lcp->op[i] = op;
lcp->data[i].ui = obj->attrs[id].value.ui;
} else {
break;
}
i ++;
}
return (lcp);
}
int
assign_attr(
isns_attr_t *attr,
const isns_attr_t *tmp
)
{
uint32_t t;
switch (tmp->tag) {
case ISNS_EID_ATTR_ID:
case ISNS_DD_SET_NAME_ATTR_ID:
case ISNS_DD_NAME_ATTR_ID:
if (tmp->len == 0 && attr->len == 0) {
int len;
char *name = make_unique_name(&len, tmp->tag);
if (name != NULL) {
attr->value.ptr = (uchar_t *)name;
attr->tag = tmp->tag;
attr->len = len;
} else {
return (1);
}
}
case ISNS_PORTAL_NAME_ATTR_ID:
case ISNS_ISCSI_NAME_ATTR_ID:
case ISNS_ISCSI_ALIAS_ATTR_ID:
case ISNS_ISCSI_AUTH_METHOD_ATTR_ID:
case ISNS_PG_ISCSI_NAME_ATTR_ID:
case ISNS_DD_ISCSI_NAME_ATTR_ID:
if (tmp->len == 0) {
return (0);
} else if (tmp->len >= attr->len) {
attr->value.ptr = realloc(
attr->value.ptr, tmp->len + 1);
}
if (attr->value.ptr != NULL) {
(void) strncpy((char *)attr->value.ptr,
(char *)tmp->value.ptr, tmp->len);
attr->value.ptr[tmp->len] = 0;
attr->tag = tmp->tag;
attr->len = tmp->len;
} else {
return (1);
}
break;
case ISNS_MGMT_IP_ADDR_ATTR_ID:
case ISNS_PORTAL_IP_ADDR_ATTR_ID:
case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
if (attr->value.ip == NULL) {
attr->value.ip = (in6_addr_t *)calloc(1, tmp->len);
}
if (attr->value.ip != NULL) {
(void) memcpy((void *)attr->value.ip,
(void *)tmp->value.ip, tmp->len);
attr->tag = tmp->tag;
attr->len = tmp->len;
} else {
return (1);
}
break;
case ISNS_ENTITY_INDEX_ATTR_ID:
case ISNS_PORTAL_INDEX_ATTR_ID:
case ISNS_ISCSI_NODE_INDEX_ATTR_ID:
case ISNS_PG_INDEX_ATTR_ID:
case ISNS_DD_SET_ID_ATTR_ID:
case ISNS_DD_ID_ATTR_ID:
if (attr->value.ui != 0) {
break;
}
case ISNS_ENTITY_PROTOCOL_ATTR_ID:
case ISNS_VERSION_RANGE_ATTR_ID:
case ISNS_PORTAL_PORT_ATTR_ID:
case ISNS_ESI_PORT_ATTR_ID:
case ISNS_SCN_PORT_ATTR_ID:
case ISNS_ISCSI_NODE_TYPE_ATTR_ID:
case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
case ISNS_PG_PORTAL_PORT_ATTR_ID:
case ISNS_PG_TAG_ATTR_ID:
case ISNS_DD_SET_STATUS_ATTR_ID:
case ISNS_DD_ISCSI_INDEX_ATTR_ID:
attr->tag = tmp->tag;
attr->len = tmp->len;
attr->value.ui = tmp->value.ui;
break;
case ISNS_ENTITY_REG_PERIOD_ATTR_ID:
attr->tag = tmp->tag;
attr->len = tmp->len;
attr->value.ui = tmp->value.ui;
t = get_reg_period();
if (attr->value.ui > t) {
attr->value.ui = t;
} else if (attr->value.ui < ONE_DAY) {
attr->value.ui = ONE_DAY;
}
break;
case ISNS_ESI_INTERVAL_ATTR_ID:
attr->tag = tmp->tag;
attr->len = tmp->len;
attr->value.ui = tmp->value.ui;
if (attr->value.ui > ONE_DAY) {
attr->value.ui = ONE_DAY;
} else if (attr->value.ui < MIN_ESI_INTVAL) {
attr->value.ui = MIN_ESI_INTVAL;
}
break;
default:
ASSERT(0);
break;
}
return (0);
}
static int
copy_attrs(
isns_obj_t *dst,
const isns_obj_t *src
)
{
int i = 0;
int n = NUM_OF_ATTRS[dst->type];
isns_attr_t *dst_attr;
const isns_attr_t *src_attr;
while (i < n) {
src_attr = &(src->attrs[i]);
if (src_attr->tag != 0) {
dst_attr = &(dst->attrs[i]);
if (assign_attr(dst_attr, src_attr) != 0) {
return (1);
}
}
i ++;
}
return (0);
}
int
extract_attr(
isns_attr_t *attr,
const isns_tlv_t *tlv,
int flag
)
{
int ec = 0;
uint32_t min_len = 4, max_len = 224;
switch (tlv->attr_id) {
case ISNS_EID_ATTR_ID:
min_len = 0;
case ISNS_PORTAL_NAME_ATTR_ID:
case ISNS_ISCSI_ALIAS_ATTR_ID:
case ISNS_DD_SET_NAME_ATTR_ID:
case ISNS_DD_NAME_ATTR_ID:
max_len = 256;
case ISNS_ISCSI_NAME_ATTR_ID:
case ISNS_PG_ISCSI_NAME_ATTR_ID:
if (tlv->attr_len < min_len || tlv->attr_len > max_len) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
} else {
attr->tag = tlv->attr_id;
attr->len = tlv->attr_len;
attr->value.ptr = (uchar_t *)&(tlv->attr_value[0]);
}
break;
case ISNS_ISCSI_AUTH_METHOD_ATTR_ID:
attr->tag = tlv->attr_id;
attr->len = tlv->attr_len;
attr->value.ptr = (uchar_t *)&(tlv->attr_value[0]);
break;
case ISNS_MGMT_IP_ADDR_ATTR_ID:
case ISNS_PORTAL_IP_ADDR_ATTR_ID:
case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
if (tlv->attr_len != 16) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
} else {
attr->tag = tlv->attr_id;
attr->len = tlv->attr_len;
attr->value.ip = (void *)&(tlv->attr_value[0]);
}
break;
case ISNS_ENTITY_PROTOCOL_ATTR_ID:
case ISNS_VERSION_RANGE_ATTR_ID:
case ISNS_ENTITY_REG_PERIOD_ATTR_ID:
case ISNS_PORTAL_PORT_ATTR_ID:
case ISNS_ESI_INTERVAL_ATTR_ID:
case ISNS_ESI_PORT_ATTR_ID:
case ISNS_SCN_PORT_ATTR_ID:
case ISNS_ISCSI_NODE_TYPE_ATTR_ID:
case ISNS_PG_PORTAL_PORT_ATTR_ID:
case ISNS_DD_SET_ID_ATTR_ID:
case ISNS_DD_SET_STATUS_ATTR_ID:
case ISNS_DD_ID_ATTR_ID:
if (tlv->attr_len != 4) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
break;
}
case ISNS_PG_TAG_ATTR_ID:
attr->tag = tlv->attr_id;
attr->len = tlv->attr_len;
if (tlv->attr_len == 4) {
attr->value.ui = ntohl(*(uint32_t *)
&(tlv->attr_value[0]));
} else {
attr->value.ui = 0;
}
break;
case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
case ISNS_ENTITY_ISAKMP_P1_ATTR_ID:
case ISNS_ENTITY_CERT_ATTR_ID:
case ISNS_PORTAL_SEC_BMP_ATTR_ID:
case ISNS_PORTAL_ISAKMP_P1_ATTR_ID:
case ISNS_PORTAL_ISAKMP_P2_ATTR_ID:
case ISNS_PORTAL_CERT_ATTR_ID:
break;
case ISNS_PORTAL_INDEX_ATTR_ID:
case ISNS_ISCSI_NODE_INDEX_ATTR_ID:
case ISNS_PG_INDEX_ATTR_ID:
if (flag == 0) {
if (tlv->attr_len != 4) {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
} else {
attr->tag = tlv->attr_id;
attr->len = tlv->attr_len;
attr->value.ui = ntohl(*(uint32_t *)
&(tlv->attr_value[0]));
}
break;
}
case ISNS_ENTITY_INDEX_ATTR_ID:
case ISNS_TIMESTAMP_ATTR_ID:
default:
if (flag == 0) {
ec = ISNS_RSP_INVALID_QRY;
} else {
ec = ISNS_RSP_INVALID_REGIS;
}
break;
}
return (ec);
}
static int
copy_attr(
isns_attr_t *attr,
const isns_tlv_t *tlv
)
{
int ec = 0;
isns_attr_t tmp = { 0 };
ec = extract_attr(&tmp, tlv, 1);
if (ec == 0 && tmp.tag != 0) {
if (assign_attr(attr, &tmp) != 0) {
ec = ISNS_RSP_INTERNAL_ERROR;
}
}
return (ec);
}
uint32_t
get_timestamp(
)
{
uint32_t t;
int flag;
(void) pthread_mutex_lock(&el_mtx);
if (sys_q != NULL) {
flag = 1;
} else {
flag = 0;
}
t = get_stopwatch(flag);
(void) pthread_mutex_unlock(&el_mtx);
return (t);
}
static uint32_t
get_reg_period(
)
{
uint32_t t;
uint32_t period;
t = get_timestamp();
period = INFINITY - t - 1;
return (period);
}
isns_obj_t *
obj_calloc(
int type
)
{
isns_obj_t *obj = NULL;
obj = (isns_obj_t *)calloc(1, SIZEOF_OBJ[type]);
if (obj != NULL) {
obj->type = type;
#ifdef DEBUG
if (verbose_mc) {
printf("object(%d) allocated\n", type);
}
#endif
}
return (obj);
}
isns_obj_t *
make_default_entity(
)
{
uint32_t t;
isns_obj_t *obj = obj_calloc(OBJ_ENTITY);
isns_attr_t *attr;
if (obj != NULL) {
int len;
char *eid = make_unique_name(&len, ISNS_EID_ATTR_ID);
if (!eid) {
free(obj);
return (NULL);
}
attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)];
attr->tag = ISNS_EID_ATTR_ID;
attr->len = len;
attr->value.ptr = (uchar_t *)eid;
attr = &obj->attrs[
ATTR_INDEX_ENTITY(ISNS_ENTITY_REG_PERIOD_ATTR_ID)];
if (attr->tag == 0) {
attr->tag = ISNS_ENTITY_REG_PERIOD_ATTR_ID;
attr->len = 4;
t = get_reg_period();
attr->value.ui = t;
}
}
return (obj);
}
static isns_obj_t *
make_default_pg(
const isns_obj_t *p1,
const isns_obj_t *p2
)
{
const isns_obj_t *iscsi, *portal;
const isns_attr_t *name, *addr, *port;
isns_obj_t *pg;
uchar_t *pg_name;
in6_addr_t *pg_addr;
isns_attr_t *attr;
uint32_t *refp;
if (p1->type == OBJ_ISCSI) {
iscsi = p1;
portal = p2;
} else {
iscsi = p2;
portal = p1;
}
name = &iscsi->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)];
addr = &portal->attrs[ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID)];
port = &portal->attrs[ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID)];
pg = obj_calloc(OBJ_PG);
pg_name = (uchar_t *)malloc(name->len);
pg_addr = (in6_addr_t *)malloc(addr->len);
if (pg != NULL && pg_name != NULL && pg_addr != NULL) {
(void) strcpy((char *)pg_name, (char *)name->value.ptr);
attr = &pg->attrs[ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID)];
attr->tag = ISNS_PG_ISCSI_NAME_ATTR_ID;
attr->len = name->len;
attr->value.ptr = pg_name;
(void) memcpy((void *)pg_addr,
(void *)addr->value.ip, addr->len);
attr = &pg->attrs[ATTR_INDEX_PG(
ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)];
attr->tag = ISNS_PG_PORTAL_IP_ADDR_ATTR_ID;
attr->len = addr->len;
attr->value.ip = pg_addr;
attr = &pg->attrs[ATTR_INDEX_PG(
ISNS_PG_PORTAL_PORT_ATTR_ID)];
attr->tag = ISNS_PG_PORTAL_PORT_ATTR_ID;
attr->len = port->len;
attr->value.ui = port->value.ui;
attr = &pg->attrs[ATTR_INDEX_PG(
ISNS_PG_TAG_ATTR_ID)];
attr->tag = ISNS_PG_TAG_ATTR_ID;
attr->len = 4;
attr->value.ui = ISNS_DEFAULT_PGT;
refp = get_ref_p(pg, OBJ_ISCSI);
*refp = get_obj_uid(iscsi);
refp = get_ref_p(pg, OBJ_PORTAL);
*refp = get_obj_uid(portal);
(void) set_parent_obj(pg, get_parent_uid(iscsi));
} else {
free(pg);
free(pg_name);
free(pg_addr);
pg = NULL;
}
return (pg);
}
int
reg_get_entity(
isns_obj_t **p,
isns_tlv_t **op,
uint16_t *op_len
)
{
int ec = 0;
isns_tlv_t *tmp;
uint16_t tmp_len;
isns_attr_t *attr;
isns_obj_t *entity = NULL;
tmp = *op;
tmp_len = *op_len;
if (tmp_len >= 8 && IS_ENTITY_KEY(tmp->attr_id)) {
entity = obj_calloc(OBJ_ENTITY);
if (entity != NULL) {
do {
attr = &entity->attrs[
ATTR_INDEX_ENTITY(tmp->attr_id)];
ec = copy_attr(attr, tmp);
NEXT_TLV(tmp, tmp_len);
} while (ec == 0 &&
tmp_len >= 8 &&
IS_ENTITY_ATTR(tmp->attr_id));
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
if (ec == 0) {
attr = &entity->attrs[
ATTR_INDEX_ENTITY(ISNS_ENTITY_REG_PERIOD_ATTR_ID)];
if (attr->tag == 0) {
attr->tag = ISNS_ENTITY_REG_PERIOD_ATTR_ID;
attr->len = 4;
attr->value.ui = get_reg_period();
}
} else if (entity != NULL) {
free(entity);
entity = NULL;
}
}
*p = entity;
*op = tmp;
*op_len = tmp_len;
return (ec);
}
static int
reg_get_iscsi(
isns_obj_t **p,
isns_attr_t *pg_key1,
isns_tlv_t **op,
uint16_t *op_len
)
{
int ec = 0;
isns_tlv_t *tmp;
uint16_t tmp_len;
isns_attr_t *attr;
isns_obj_t *obj = NULL;
tmp = *op;
tmp_len = *op_len;
pg_key1->tag = PG_KEY1;
pg_key1->len = tmp->attr_len;
pg_key1->value.ptr = (uchar_t *)&tmp->attr_value[0];
obj = obj_calloc(OBJ_ISCSI);
if (obj != NULL) {
do {
attr = &obj->attrs[
ATTR_INDEX_ISCSI(tmp->attr_id)];
ec = copy_attr(attr, tmp);
NEXT_TLV(tmp, tmp_len);
} while (ec == 0 &&
tmp_len >= 8 &&
IS_ISCSI_ATTR(tmp->attr_id));
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
*p = obj;
*op = tmp;
*op_len = tmp_len;
return (ec);
}
static int
reg_get_portal(
isns_obj_t **p,
isns_attr_t *pg_key1,
isns_attr_t *pg_key2,
isns_tlv_t **op,
uint16_t *op_len
)
{
int ec = 0;
isns_tlv_t *tmp;
uint16_t tmp_len;
isns_attr_t *attr;
isns_obj_t *obj = NULL;
isns_tlv_t *ip;
tmp = *op;
tmp_len = *op_len;
pg_key1->tag = PG_KEY2;
pg_key1->len = tmp->attr_len;
pg_key1->value.ip = (void *)&tmp->attr_value[0];
ip = tmp;
NEXT_TLV(tmp, tmp_len);
if (tmp_len > 8 &&
tmp->attr_id == PORTAL_KEY2 &&
tmp->attr_len == 4) {
pg_key2->tag = PG_KEY3;
pg_key2->len = tmp->attr_len;
pg_key2->value.ui = ntohl(*(uint32_t *)&tmp->attr_value[0]);
obj = obj_calloc(OBJ_PORTAL);
if (obj != NULL) {
attr = &obj->attrs[
ATTR_INDEX_PORTAL(ip->attr_id)];
ec = copy_attr(attr, ip);
if (ec == 0) {
attr = &obj->attrs[
ATTR_INDEX_PORTAL(tmp->attr_id)];
ec = copy_attr(attr, tmp);
}
NEXT_TLV(tmp, tmp_len);
while (ec == 0 &&
tmp_len >= 8 &&
IS_PORTAL_ATTR(tmp->attr_id)) {
attr = &obj->attrs[
ATTR_INDEX_PORTAL(
tmp->attr_id)];
ec = copy_attr(attr, tmp);
NEXT_TLV(tmp, tmp_len);
}
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
} else {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
*p = obj;
*op = tmp;
*op_len = tmp_len;
return (ec);
}
static int
reg_get_pg(
isns_obj_t **p,
isns_tlv_t **op,
uint16_t *op_len
)
{
int ec = 0;
isns_tlv_t *tmp;
uint16_t tmp_len;
isns_attr_t *attr;
isns_obj_t *obj = NULL;
tmp = *op;
tmp_len = *op_len;
obj = obj_calloc(OBJ_PG);
if (obj != NULL) {
do {
attr = &obj->attrs[
ATTR_INDEX_PG(tmp->attr_id)];
ec = copy_attr(attr, tmp);
NEXT_TLV(tmp, tmp_len);
} while (ec == 0 &&
tmp_len >= 8 &&
IS_PG_ATTR(tmp->attr_id));
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
*p = obj;
*op = tmp;
*op_len = tmp_len;
return (ec);
}
static int
reg_get_pg1(
isns_obj_t **p,
isns_attr_t const *pgt,
isns_tlv_t **op,
uint16_t *op_len
)
{
int ec = 0;
isns_tlv_t *tmp;
uint16_t tmp_len;
isns_attr_t *attr;
isns_obj_t *obj = NULL;
int i = 0;
tmp = *op;
tmp_len = *op_len;
if (pgt[0].tag == PG_KEY2 &&
pgt[1].tag == PG_KEY3) {
obj = obj_calloc(OBJ_PG);
if (obj != NULL) {
attr = &obj->attrs[
ATTR_INDEX_PG(tmp->attr_id)];
ec = copy_attr(attr, tmp);
while (ec == 0 && i < 3) {
attr = &obj->attrs[
ATTR_INDEX_PG(pgt[i].tag)];
ec = assign_attr(attr, &pgt[i]);
i ++;
}
NEXT_TLV(tmp, tmp_len);
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
} else {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
*p = obj;
*op = tmp;
*op_len = tmp_len;
return (ec);
}
static int
reg_get_pg2(
isns_obj_t **p,
isns_attr_t const *pgt,
isns_tlv_t **op,
uint16_t *op_len
)
{
int ec = 0;
isns_tlv_t *tmp;
uint16_t tmp_len;
isns_attr_t *attr;
isns_obj_t *obj = NULL;
int i = 0;
isns_tlv_t *ip;
tmp = *op;
tmp_len = *op_len;
ip = tmp;
NEXT_TLV(tmp, tmp_len);
if (tmp_len > 8 &&
tmp->attr_id == PG_KEY3 &&
tmp->attr_len == 4 &&
pgt[2].tag == PG_PGT &&
pgt[1].tag == 0 &&
pgt[0].tag == PG_KEY1) {
obj = obj_calloc(OBJ_PG);
if (obj != NULL) {
attr = &obj->attrs[
ATTR_INDEX_PG(ip->attr_id)];
ec = copy_attr(attr, ip);
if (ec == 0) {
attr = &obj->attrs[
ATTR_INDEX_PG(tmp->attr_id)];
ec = copy_attr(attr, tmp);
}
while (ec == 0 && i < 3) {
attr = &obj->attrs[
ATTR_INDEX_PG(pgt[i].tag)];
ec = assign_attr(attr, &pgt[i]);
i += 2;
}
NEXT_TLV(tmp, tmp_len);
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
} else {
ec = ISNS_RSP_MSG_FORMAT_ERROR;
}
*p = obj;
*op = tmp;
*op_len = tmp_len;
return (ec);
}
int
reg_get_obj(
isns_obj_t **p,
isns_attr_t *pgt,
isns_tlv_t **op,
uint16_t *op_len
)
{
int ec = 0;
int derefd = 0;
uint32_t pg_tag;
if (*op_len == 0) {
*p = NULL;
return (0);
}
switch ((*op)->attr_id) {
case ISCSI_KEY:
ec = reg_get_iscsi(p, &pgt[0], op, op_len);
pgt[1].tag = 0;
pgt[2].tag = 0;
break;
case PORTAL_KEY1:
ec = reg_get_portal(p, &pgt[0], &pgt[1], op, op_len);
pgt[2].tag = 0;
break;
case PG_KEY1:
if (pgt[2].tag == PG_PGT) {
ec = reg_get_pg1(p, pgt, op, op_len);
} else {
ec = reg_get_pg(p, op, op_len);
pgt[0].tag = 0;
pgt[1].tag = 0;
pgt[2].tag = 0;
}
break;
case PG_KEY2:
ec = reg_get_pg2(p, pgt, op, op_len);
break;
case PG_PGT:
switch (pgt[0].tag) {
case 0:
*p = NULL;
ec = ISNS_RSP_MSG_FORMAT_ERROR;
break;
case PG_KEY1:
case PG_KEY2:
pgt[2].tag = PG_PGT;
pgt[2].len = (*op)->attr_len;
pg_tag = 0;
switch ((*op)->attr_len) {
case 4:
pg_tag = ntohl(*(uint32_t *)
&(*op)->attr_value[0]);
case 0:
pgt[2].value.ui = pg_tag;
break;
default:
*p = NULL;
ec = ISNS_RSP_MSG_FORMAT_ERROR;
break;
}
if (ec == 0) {
derefd = 1;
NEXT_TLV(*op, *op_len);
ec = reg_get_obj(p, pgt, op, op_len);
}
break;
default:
ASSERT(0);
*p = NULL;
ec = ISNS_RSP_INTERNAL_ERROR;
break;
}
break;
default:
*p = NULL;
ec = ISNS_RSP_MSG_FORMAT_ERROR;
break;
}
if (ec == 0 && derefd == 0) {
ec = update_deref_obj(*p);
}
if (ec != 0 && *p != NULL) {
free_one_object(*p);
*p = NULL;
}
return (ec);
}
int
reg_auth_src(
isns_type_t type,
uint32_t uid,
uchar_t *src
)
{
lookup_ctrl_t lc;
uint32_t puid;
puid = is_parent_there(src);
if (TYPE_OF_PARENT[type] != 0) {
SET_UID_LCP(&lc, type, uid);
uid = cache_lookup(&lc, NULL, cb_get_parent);
type = TYPE_OF_PARENT[type];
}
if (uid != 0 && puid == 0) {
SET_UID_LCP(&lc, type, uid);
uid = cache_lookup(&lc, NULL, cb_node_child);
}
if (puid != uid) {
return (0);
}
return (1);
}
int
is_obj_online(
const isns_obj_t *obj
)
{
int online = 1;
switch (obj->type) {
case OBJ_ISCSI:
online = obj->attrs[ATTR_INDEX_ISCSI(
ISNS_ISCSI_NODE_TYPE_ATTR_ID)].value.ui == 0 ? 0 : 1;
break;
default:
break;
}
return (online);
}
static int
set_obj_offline(
isns_obj_t *obj
)
{
switch (obj->type) {
case OBJ_ISCSI:
obj->attrs[ATTR_INDEX_ISCSI(
ISNS_ISCSI_NODE_TYPE_ATTR_ID)].value.ui = 0;
break;
default:
break;
}
return (0);
}
void *
assoc_clone(
void *p,
int clone_flag
)
{
isns_type_t type;
isns_obj_t *clone;
const isns_attr_t *src_attr;
isns_attr_t *dst_attr;
uint32_t id, op;
int i = 0;
const isns_obj_t *obj;
uint32_t dd_flag;
int online;
int state;
obj = (isns_obj_t *)p;
if (obj->type != OBJ_ISCSI) {
return (NULL);
}
dd_flag = (get_dd_id(get_obj_uid(obj), ISNS_DEFAULT_DD_ID) == 0) ?
0 : 1;
online = is_obj_online(obj);
state = (clone_flag << 2) | (dd_flag << 1) | online;
switch (state) {
case 0:
ASSERT(0);
case 1:
case 4:
return (NULL);
case 2:
case 5:
case 6:
case 7:
return (p);
case 3:
default:
break;
}
type = obj->type;
clone = obj_calloc(type);
if (clone != NULL) {
id = UID_ATTR_INDEX[type];
src_attr = &(obj->attrs[id]);
dst_attr = &(clone->attrs[id]);
if (assign_attr(dst_attr, src_attr) != 0) {
free_one_object(clone);
return (NULL);
}
while (i < MAX_KEY_ATTRS) {
op = KEY_ATTR_OP[type][i];
if (op != 0) {
id = KEY_ATTR_INDEX[type][i];
src_attr = &(obj->attrs[id]);
dst_attr = &(clone->attrs[id]);
if (assign_attr(dst_attr, src_attr) != 0) {
free_one_object(clone);
return (NULL);
}
} else {
break;
}
i ++;
}
}
return ((void *)clone);
}
void
free_one_object(
isns_obj_t *obj
)
{
int i;
uint32_t *cuid;
if (obj == NULL) {
return;
}
for (i = 0; i < NUM_OF_ATTRS[obj->type]; i++) {
isns_attr_t *attr = &obj->attrs[i];
switch (attr->tag) {
case ISNS_EID_ATTR_ID:
case ISNS_ISCSI_NAME_ATTR_ID:
case ISNS_ISCSI_ALIAS_ATTR_ID:
case ISNS_ISCSI_AUTH_METHOD_ATTR_ID:
case ISNS_PG_ISCSI_NAME_ATTR_ID:
case ISNS_PORTAL_IP_ADDR_ATTR_ID:
case ISNS_PORTAL_NAME_ATTR_ID:
case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
case ISNS_DD_SET_NAME_ATTR_ID:
case ISNS_DD_NAME_ATTR_ID:
case ISNS_DD_ISCSI_NAME_ATTR_ID:
case ISNS_DD_FC_PORT_NAME_ATTR_ID:
case ISNS_DD_PORTAL_IP_ADDR_ATTR_ID:
#ifdef DEBUG
if (verbose_mc) {
printf("memory(%d) deallocated\n",
attr->len);
}
#endif
free(attr->value.ptr);
attr->value.ptr = NULL;
break;
default:
break;
}
}
i = 0;
while (i < NUM_OF_CHILD[obj->type]) {
cuid = get_child_n(obj, i);
free(cuid);
i ++;
}
#ifdef DEBUG
if (verbose_mc) {
printf("object(%d) deallocated\n", obj->type);
}
#endif
free(obj);
}
void
free_object(
isns_obj_t *obj
)
{
free_one_object(obj);
}
int
set_parent_obj(
isns_obj_t *obj,
uint32_t puid
)
{
uint32_t *const p = get_parent_p(obj);
if (p != NULL) {
*p = puid;
}
return (0);
}
int
buff_child_obj(
const isns_type_t ptype,
const isns_type_t ctype,
const void *c,
void const ***child
)
{
int ec = 0;
int i = 0;
void const ***pp, **p;
uint32_t num, new_num;
pp = NULL;
while (i < NUM_OF_CHILD[ptype]) {
if (TYPE_OF_CHILD[ptype][i] == ctype) {
pp = &child[i];
break;
}
i ++;
}
if (pp == NULL) {
return (ec);
}
p = *pp;
if (p != NULL) {
num = (uint32_t)*p;
i = 0;
while (i < num) {
if (p[++i] == NULL) {
p[i] = c;
return (ec);
}
}
p = *pp;
new_num = num + 1;
} else {
num = 0;
new_num = 1;
}
p = (void const **)realloc(p, (new_num + 1) * sizeof (void *));
if (p != NULL) {
*pp = p;
*p = (void *)new_num;
p[new_num] = c;
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
return (ec);
}
int
update_child_obj(
const isns_type_t ptype,
const uint32_t puid,
void const ***child,
int child_flag
)
{
int ec = 0;
lookup_ctrl_t lc;
SET_UID_LCP(&lc, ptype, puid);
lc.data[1].ptr = (uchar_t *)child;
lc.data[2].ui = child_flag;
ec = cache_lookup(&lc, NULL, cb_add_child);
return (ec);
}
int
update_ref_obj(
const isns_obj_t *obj
)
{
uint32_t uid;
lookup_ctrl_t lc;
isns_type_t t;
t = obj->type;
if (TYPE_OF_REF[t][0] != 0) {
(void) setup_ref_lcp(&lc, obj, NULL);
lc.id[2] = t;
lc.data[2].ui = get_obj_uid(obj);
uid = 0;
do {
lc.curr_uid = uid;
(void) cache_lookup(&lc, &uid, cb_set_ref);
} while (uid != 0);
}
return (0);
}
int
verify_ref_obj(
const isns_type_t ptype,
const uint32_t puid,
void const ***child
)
{
int ec = 0;
lookup_ctrl_t lc;
SET_UID_LCP(&lc, ptype, puid);
lc.data[1].ptr = (uchar_t *)child;
ec = cache_lookup(&lc, NULL, cb_verify_ref);
return (ec);
}
int
update_deref_obj(
isns_obj_t *obj
)
{
int ec = 0;
isns_type_t t, rt;
lookup_ctrl_t lc;
int i, ref_count;
uint32_t uid, *refp;
t = obj->type;
i = ref_count = 0;
while (i < NUM_OF_REF[t]) {
rt = TYPE_OF_REF[t][i + 1];
(void) setup_deref_lcp(&lc, obj, rt);
uid = is_obj_there(&lc);
if (uid != 0) {
refp = get_ref_p(obj, lc.type);
*refp = uid;
ref_count ++;
}
i ++;
}
if (i > 0 && ref_count == 0) {
ec = ISNS_RSP_INVALID_REGIS;
}
return (ec);
}
int
register_object(
isns_obj_t *obj,
uint32_t *uid_p,
int *update_p
)
{
return (cache_add(obj, 0, uid_p, update_p));
}
int
register_assoc(
isns_obj_t *obj,
uint32_t *uid_p
)
{
return (cache_add(obj, 1, uid_p, NULL));
}
uint32_t
is_obj_there(
lookup_ctrl_t *lcp
)
{
uint32_t uid;
(void) cache_lookup(lcp, &uid, NULL);
return (uid);
}
uint32_t
is_parent_there(
uchar_t *src
)
{
lookup_ctrl_t lc;
lc.curr_uid = 0;
lc.type = OBJ_ISCSI;
lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
lc.op[0] = OP_STRING;
lc.data[0].ptr = src;
lc.op[1] = 0;
return (cache_lookup(&lc, NULL, cb_get_parent));
}
static int
setup_ref_lcp(
lookup_ctrl_t *lcp,
const isns_obj_t *iscsi,
const isns_obj_t *portal
)
{
int i = 0, j = 0;
lcp->curr_uid = 0;
lcp->type = TYPE_OF_REF[iscsi->type][0];
while (iscsi != NULL &&
i < MAX_REF_MATCH &&
REF_MATCH_OPS[iscsi->type][i] > 0) {
lcp->id[i] = REF_MATCH_ID2[iscsi->type][i];
lcp->op[i] = REF_MATCH_OPS[iscsi->type][i];
lcp->data[i].ptr = iscsi->attrs[
REF_MATCH_ID1[iscsi->type][i]].value.ptr;
i ++;
}
while (portal != NULL &&
i < MAX_LOOKUP_CTRL &&
j < MAX_REF_MATCH &&
REF_MATCH_OPS[portal->type][j] > 0) {
lcp->id[i] = REF_MATCH_ID2[portal->type][j];
lcp->op[i] = REF_MATCH_OPS[portal->type][j];
lcp->data[i].ptr = portal->attrs[
REF_MATCH_ID1[portal->type][j]].value.ptr;
j ++;
i ++;
}
if (i < MAX_LOOKUP_CTRL) {
lcp->op[i] = 0;
}
return (0);
}
static int
setup_deref_lcp(
lookup_ctrl_t *lcp,
const isns_obj_t *pg,
isns_type_t t
)
{
int i = 0;
lcp->curr_uid = 0;
lcp->type = t;
while (i < MAX_REF_MATCH &&
REF_MATCH_OPS[t][i] > 0) {
lcp->id[i] = REF_MATCH_ID1[t][i];
lcp->op[i] = REF_MATCH_OPS[t][i];
lcp->data[i].ptr = pg->attrs[
REF_MATCH_ID2[t][i]].value.ptr;
i ++;
}
if (i < MAX_LOOKUP_CTRL) {
lcp->op[i] = 0;
}
return (0);
}
static uint32_t
setup_parent_lcp(
lookup_ctrl_t *lcp,
isns_obj_t *obj
)
{
isns_type_t ptype;
uint32_t puid;
puid = get_parent_uid(obj);
if (puid != 0) {
ptype = TYPE_OF_PARENT[obj->type];
SET_UID_LCP(lcp, ptype, puid);
lcp->data[1].ui = obj->type;
lcp->data[2].ui = get_obj_uid(obj);
}
return (puid);
}
static int
cb_get_parent(
void *p1,
void *p2
)
{
return (get_parent_uid(p1));
}
static int
cb_node_child(
void *p1,
void *p2
)
{
isns_obj_t *obj = (isns_obj_t *)p1;
uint32_t num, uid;
uint32_t *cuid = get_child_t(obj, OBJ_ISCSI);
if (cuid != NULL) {
num = *cuid;
} else {
num = 0;
}
while (num > 0) {
uid = *++cuid;
if (uid != 0) {
return (uid);
}
num --;
}
return (0);
}
static int
cb_set_ref(
void *p1,
void *p2
)
{
isns_obj_t *obj = (isns_obj_t *)p1;
lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
isns_type_t t;
uint32_t u;
uint32_t *refp;
t = lcp->id[2];
u = lcp->data[2].ui;
refp = get_ref_p(obj, t);
*refp = u;
return (0);
}
static int
cb_clear_ref(
void *p1,
void *p2
)
{
isns_obj_t *obj = (isns_obj_t *)p1;
lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
isns_type_t t;
uint32_t *refp;
int i = 0;
uint32_t ref;
t = lcp->data[2].ui;
refp = get_ref_p(obj, t);
*refp = 0;
while (i < NUM_OF_REF[obj->type]) {
ref = get_ref_n(obj, i);
if (ref != 0) {
return (0);
}
i ++;
}
return (1);
}
static int
cb_add_child(
void *p1,
void *p2
)
{
isns_obj_t *obj = (isns_obj_t *)p1;
lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
const void ***child;
const void **vpp;
uint32_t vnum;
int child_flag;
uint32_t **upp, *up;
uint32_t num;
isns_obj_t *o;
int i = 0;
child = (const void ***)lcp->data[1].ptr;
child_flag = lcp->data[2].ui;
while (i < NUM_OF_CHILD[obj->type]) {
vpp = child[i];
if (vpp != NULL &&
(vnum = (uint32_t)*vpp) > 0 &&
*(vpp + 1) != NULL) {
upp = get_child_np(obj, i);
if (*upp == NULL) {
if (child_flag == 0 &&
sizeof (typeof (**upp)) ==
sizeof (typeof (**child))) {
*upp = (uint32_t *)vpp;
vpp = NULL;
child[i] = NULL;
}
num = vnum;
} else {
num = **upp + vnum;
}
if (vpp != NULL) {
up = (uint32_t *)realloc(*upp,
(num + 1) * sizeof (uint32_t));
if (up == NULL) {
return (ISNS_RSP_INTERNAL_ERROR);
}
*upp = up;
*up = num;
up += num;
vpp += vnum;
while (vnum > 0) {
if (*vpp == NULL) {
*up = 0;
} else if (child_flag == 0) {
*up = (uint32_t)*vpp;
*vpp = NULL;
} else {
o = (isns_obj_t *)*vpp;
*up = get_obj_uid(o);
if (is_obj_online(o) == 0) {
free_object(o);
}
*vpp = NULL;
}
up --;
vpp --;
vnum --;
}
}
}
i ++;
}
return (0);
}
static int
cb_remove_child(
void *p1,
void *p2
)
{
isns_obj_t *obj = (isns_obj_t *)p1;
lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
uint32_t child_type = lcp->data[1].ui;
uint32_t child_uid = lcp->data[2].ui;
uint32_t *cuidp, cuid, num_of_child = 0;
int i;
cuidp = get_child_t(obj, child_type);
if (cuidp != NULL) {
num_of_child = *cuidp;
}
while (num_of_child > 0) {
cuid = *++cuidp;
if (cuid == child_uid) {
*cuidp = 0;
break;
}
num_of_child --;
}
i = 0;
while (i < NUM_OF_CHILD[obj->type]) {
cuidp = get_child_n(obj, i);
if (cuidp != NULL) {
num_of_child = *cuidp;
while (num_of_child > 0) {
cuid = *++cuidp;
if (cuid != 0) {
return (0);
}
num_of_child --;
}
}
i ++;
}
return (1);
}
static int
cb_verify_ref(
void *p1,
void *p2
)
{
int ec = 0;
isns_obj_t *parent = (isns_obj_t *)p1;
lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
const void ***child;
const void **vpp;
const void *vp;
uint32_t vnum;
const void **evpp;
const void *evp;
uint32_t evnum;
isns_type_t pt;
isns_type_t ct;
isns_type_t rt;
isns_type_t et;
uint32_t *up;
uint32_t u;
uint32_t unum;
lookup_ctrl_t lc;
uint8_t flag[MAX_OBJ_TYPE + 1] = { 0 };
int i, j, k;
pt = parent->type;
child = (const void ***)lcp->data[1].ptr;
for (i = 0; i < NUM_OF_CHILD[pt]; i++) {
ct = TYPE_OF_CHILD[pt][i];
rt = TYPE_OF_REF[ct][0];
if (rt == 0) {
continue;
}
et = TYPE_OF_REF[ct][1];
vpp = child[i];
if (vpp != NULL) {
vnum = (uint32_t)*vpp;
up = get_child_t(parent, et);
if (up != NULL) {
unum = *up;
} else {
unum = 0;
}
} else {
vnum = 0;
}
j = vnum;
while (j > 0) {
vp = vpp[j];
if (vp != NULL) {
(void) setup_ref_lcp(&lc, vp, NULL);
k = unum;
while (k > 0) {
u = up[k];
if (u != 0) {
ec = ref_new2old(
&lc, et, u, vp);
if (ec != 0) {
return (ec);
}
}
k --;
}
}
j --;
}
if (flag[ct] != 0) {
continue;
}
evnum = 0;
j = 0;
while (j < NUM_OF_CHILD[pt]) {
if (TYPE_OF_CHILD[pt][j] == et) {
evpp = child[j];
if (evpp != NULL) {
evnum = (uint32_t)*evpp;
}
break;
}
j ++;
}
j = vnum;
while (j > 0) {
vp = vpp[j];
k = evnum;
while (k > 0) {
evp = evpp[k];
if (vp != NULL && evp != NULL) {
(void) setup_ref_lcp(&lc, vp, evp);
ec = ref_new2new(&lc, vp, evp);
if (ec != 0) {
return (ec);
}
}
k --;
}
j --;
}
flag[et] = 1;
}
return (ec);
}
static int
cb_ref_new2old(
void *p1,
void *p2
)
{
isns_obj_t *obj = (isns_obj_t *)p1;
lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
isns_type_t et;
uint32_t uu;
uint32_t ref;
int match;
et = lcp->id[2];
uu = lcp->data[2].ui;
ref = get_ref_t(obj, et);
if (ref == uu) {
match = 1;
} else {
match = 0;
}
return (match);
}
static int
cb_new_ref(
void *p1,
void *p2
)
{
int ec = 0;
lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
isns_obj_t *a = (isns_obj_t *)p1;
isns_obj_t *b = (isns_obj_t *)lcp->data[2].ptr;
ec = new_ref(a, b);
return (ec);
}
static int
ref_new2old(
lookup_ctrl_t *lcp,
isns_type_t et,
uint32_t uu,
const isns_obj_t *vp
)
{
int ec = 0;
int match;
uint32_t uid;
lookup_ctrl_t lc;
lcp->id[2] = et;
lcp->data[2].ui = uu;
uid = 0;
do {
lcp->curr_uid = uid;
match = cache_lookup(lcp, &uid, cb_ref_new2old);
} while (match == 0 && uid != 0);
if (match == 0) {
SET_UID_LCP(&lc, et, uu);
lc.data[2].ptr = (uchar_t *)vp;
ec = cache_lookup(&lc, NULL, cb_new_ref);
}
return (ec);
}
static int
ref_new2new(
lookup_ctrl_t *lcp,
const isns_obj_t *p1,
const isns_obj_t *p2
)
{
int ec = 0;
if (is_obj_there(lcp) != 0) {
return (0);
}
ec = new_ref(p1, p2);
return (ec);
}
static int
new_ref(
const isns_obj_t *p1,
const isns_obj_t *p2
)
{
int ec = 0;
isns_obj_t *obj;
obj = make_ref[p1->type](p1, p2);
if (obj != NULL) {
ec = register_object(obj, NULL, NULL);
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
return (ec);
}
static int
do_dereg(
lookup_ctrl_t *lcp,
int parent_flag,
int child_flag,
int pending
)
{
int ec = 0;
isns_obj_t *obj;
uint32_t *cuidp, num;
isns_type_t type;
uint32_t uid;
int i;
obj = cache_remove(lcp, 0);
if (obj == NULL) {
return (0);
}
if (scn_q != NULL) {
(void) make_scn(ISNS_OBJECT_REMOVED, obj);
}
i = 0;
while (ec == 0 && !parent_flag &&
i < NUM_OF_CHILD[obj->type]) {
type = TYPE_OF_CHILD[obj->type][i];
cuidp = get_child_n(obj, i);
if (cuidp != NULL) {
num = *cuidp;
} else {
num = 0;
}
while (ec == 0 && num > 0) {
uid = cuidp[num];
if (uid != 0) {
SET_UID_LCP(lcp, type, uid);
ec = do_dereg(lcp,
parent_flag,
1,
pending);
}
num --;
}
i ++;
}
if (ec == 0 && TYPE_OF_REF[obj->type][0] > 0) {
uid = 0;
do {
(void) setup_ref_lcp(lcp, obj, NULL);
lcp->curr_uid = uid;
lcp->data[2].ui = obj->type;
if (cache_lookup(lcp, &uid, cb_clear_ref) != 0) {
UPDATE_LCP_UID(lcp, uid);
ec = do_dereg(lcp,
parent_flag,
child_flag,
pending);
}
} while (uid != 0);
}
if (ec == 0 && !child_flag &&
TYPE_OF_PARENT[obj->type] > 0 &&
(uid = setup_parent_lcp(lcp, obj)) != 0) {
if (cache_lookup(lcp, NULL, cb_remove_child) != 0) {
UPDATE_LCP_UID(lcp, uid);
ec = do_dereg(lcp,
1,
child_flag,
0);
}
}
if (ec == 0 && !child_flag) {
if (sys_q) {
ec = write_data(DATA_DELETE, obj);
}
if (ec == 0) {
(void) esi_remove_obj(obj, pending);
}
if (TYPE_OF_PARENT[obj->type] != 0) {
lcp->curr_uid = get_parent_uid(obj);
} else {
lcp->curr_uid = get_obj_uid(obj);
}
}
if (ec == 0 &&
obj->type == OBJ_PORTAL) {
(void) remove_scn_portal(get_obj_uid(obj));
}
(void) free_object(obj);
return (ec);
}
int
dereg_assoc(
lookup_ctrl_t *lcp
)
{
isns_obj_t *obj;
obj = cache_remove(lcp, 1);
if (obj != NULL) {
free_object(obj);
}
return (0);
}
int
dereg_object(
lookup_ctrl_t *lcp,
int pending
)
{
return (do_dereg(lcp, 0, 0, pending));
}
int
data_sync(
int ec
)
{
if (IS_CACHE_UPDATED()) {
if (ec == 0) {
ec = write_data(DATA_COMMIT, NULL);
}
if (ec == 0) {
(void) queue_msg_set(scn_q, SCN_TRIGGER, (void *)NULL);
} else {
shutdown_server();
}
} else {
(void) queue_msg_set(scn_q, SCN_IGNORE, (void *)NULL);
(void) write_data(DATA_RETREAT, NULL);
}
return (ec);
}
static pthread_mutex_t name_mtx[3] = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER
};
static const char *name_pattern[3] = {
"ENTITY_ID_%d",
"DD_%d",
"DD-Set_%d"
};
static uint32_t name_count[3] = {
0,
0,
0
};
static char *
make_unique_name(
int *len,
uint32_t tag
)
{
int i;
int count;
char name[32] = { 0 };
char *p;
lookup_ctrl_t lc;
lc.curr_uid = 0;
switch (tag) {
case ISNS_EID_ATTR_ID:
i = 0;
lc.type = OBJ_ENTITY;
lc.id[0] = ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID);
break;
case ISNS_DD_NAME_ATTR_ID:
i = 1;
lc.type = OBJ_DD;
lc.id[0] = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID);
break;
case ISNS_DD_SET_NAME_ATTR_ID:
i = 2;
lc.type = OBJ_DDS;
lc.id[0] = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID);
break;
default:
ASSERT(0);
break;
}
lc.op[0] = OP_STRING;
lc.op[1] = 0;
do {
(void) pthread_mutex_lock(&name_mtx[i]);
count = ++ name_count[i];
(void) pthread_mutex_unlock(&name_mtx[i]);
if (count == 0) {
return (NULL);
}
(void) sprintf(name, name_pattern[i], count);
lc.data[0].ptr = (uchar_t *)name;
} while (is_obj_there(&lc) != 0);
*len = strlen(name);
*len = *len + (4 - *len % 4);
p = (char *)malloc(*len);
if (p != NULL) {
(void) strcpy(p, name);
}
return (p);
}
#ifdef DEBUG
void
obj_dump(
void *p
)
{
print_object(NULL, (isns_obj_t *)p);
}
#endif