# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright (c) 2018, Joyent, Inc. # Copyright 2025 OmniOS Community Edition (OmniOSce) Association. # PROG = isns DSRC = isns_provider.d DTRACE_HEADER = $(DSRC:%.d=%.h) COBJS = main.o qry.o admintf.o dsapi.o log.o sched.o dseng.o scn.o cache.o COBJS += dump.o msgq.o server.o config.o esi.o obj.o utils.o dd.o func.o COBJS += pdu.o door.o htable.o OBJS = $(COBJS) $(DSRC:%.d=%.o) POFILE= isns.po POFILES = $(COBJS:%.o=%.po) include ../../Makefile.cmd include ../../Makefile.ctf CTF_MODE = link DATA_STORE = xml XML_DIR = xml_def ISNS_SVC = $(XML_DIR)/isns_server.xml MANIFEST = isns_server.xml ROOTMANIFESTDIR = $(ROOTSVCNETWORK) $(ROOTSVCNETWORK)/isns_server.xml : FILEMODE = 0444 CFLAGS += $(CCVERBOSE) CPPFLAGS += -I./ -I$(ROOT)/usr/include/libxml2 CPPFLAGS += -DTARGET_DATA_STORE=$(DATA_STORE) CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS CERRWARN += -Wno-char-subscripts CERRWARN += -Wno-ignored-qualifiers CERRWARN += $(CNOWARN_UNINIT) CERRWARN += -Wno-implicit-function-declaration # Hammerhead: Suppress pointer/int cast warnings in legacy isns code CERRWARN += -Wno-pointer-to-int-cast CERRWARN += -Wno-int-to-pointer-cast # not linted SMATCH=off CLOBBERFILES += $(DTRACE_HEADER) LDLIBS += -lsecdb -lsocket -lnsl -lscf -lxml2 .KEEP_STATE: all: $(PROG) # Hammerhead: Ensure DTrace header is generated before compiling any C sources $(COBJS): $(DTRACE_HEADER) $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) %.h: %.d $(DTRACE) -h -s $< -o $@ %.o: %.c $(DTRACE_HEADER) $(COMPILE.c) $< $(POST_PROCESS_O) %.o: %.d $(COBJS) $(COMPILE.d) -s $< $(COBJS) $(POST_PROCESS_O) clean: $(RM) $(OBJS) $(POFILES): $(DTRACE_HEADER) $(POFILE): $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ check: $(CHKMANIFEST) include ../../Makefile.targ install: all .WAIT $(ROOTUSRSBINPROG) $(ROOTMANIFEST) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include "isns_server.h" #include "isns_cfg.h" #include "isns_htab.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_dd.h" #include "isns_utils.h" #include "isns_mgmt.h" #include "isns_protocol.h" #include "admintf.h" extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; static isns_type_t get_lc_type( object_type obj ) { isns_type_t type; switch (obj) { case Node: type = OBJ_ISCSI; break; case DiscoveryDomain: case DiscoveryDomainMember: type = OBJ_DD; break; case DiscoveryDomainSet: case DiscoveryDomainSetMember: type = OBJ_DDS; break; default: ASSERT(0); break; } return (type); } static uint32_t get_lc_id( object_type obj ) { uint32_t id; switch (obj) { case Node: id = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); break; case DiscoveryDomain: case DiscoveryDomainMember: id = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); break; case DiscoveryDomainSet: case DiscoveryDomainSetMember: id = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID); break; default: ASSERT(0); break; } return (id); } /* * **************************************************************************** * * cb_get_node_info: callback for get_node_op * The routine process matching node and add a Node object elements * to the response doc. * * p1 - matching node object * p2 - lookup control data that was used for node look up * returns parent index(newtork entity) in look up control. * return - error code * * **************************************************************************** */ static int cb_get_node_info( void *p1, void *p2 ) { xmlNodePtr n_obj, n_node, sub_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_XML_ADDCHILD_FAILED); } n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_ADDCHILD_FAILED); } n_node = xmlNewNode(NULL, (xmlChar *)NODEOBJECT); if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_ADDCHILD_FAILED); } /* get node name, alias, type and generate xml info */ attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)]; switch (attr->value.ui) { case ISNS_CONTROL_NODE_TYPE | ISNS_INITIATOR_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)CONTROLNODEINITIATORTYPE); break; case ISNS_CONTROL_NODE_TYPE | ISNS_TARGET_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)CONTROLNODETARGETTYPE); break; case ISNS_TARGET_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)TARGETTYPE); break; case ISNS_INITIATOR_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)INITIATORTYPE); break; case ISNS_CONTROL_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)CONTROLNODETYPE); break; default: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)UNKNOWNTYPE); } if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_ALIAS_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)ALIASATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } /* * A node can have all or no SCN subsribtion. * May avoid redundant code with scsusrciption table. */ attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_SCN_BITMAP_ATTR_ID)]; if (IS_SCN_INIT_SELF_INFO_ONLY(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)SCNSUBSCRIPTION, (xmlChar *)SCNINITSELFONLY); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } if (IS_SCN_TARGET_SELF_INFO_ONLY(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)SCNSUBSCRIPTION, (xmlChar *)SCNTARGETSELFONLY); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } if (IS_SCN_MGMT_REG(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)SCNSUBSCRIPTION, (xmlChar *)SCNTARGETSELFONLY); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } if (IS_SCN_OBJ_REMOVED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)SCNSUBSCRIPTION, (xmlChar *)SCNOBJECTREMOVED); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } if (IS_SCN_OBJ_ADDED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)SCNSUBSCRIPTION, (xmlChar *)SCNOBJECTADDED); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } if (IS_SCN_OBJ_UPDATED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)SCNSUBSCRIPTION, (xmlChar *)SCNOBJECTUPDATED); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } if (IS_SCN_MEMBER_REMOVED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)SCNSUBSCRIPTION, (xmlChar *)SCNMEMBERREMOVED); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } if (IS_SCN_MEMBER_ADDED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)SCNSUBSCRIPTION, (xmlChar *)SCNMEMBERADDED); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } /* set the parent object id, i.e. the network entity object id */ lcp->id[2] = get_parent_uid(obj); /* pass back the node object element to add entity, portal info to it */ lcp->data[2].ptr = (uchar_t *)n_node; /* successful */ return (0); } /* * **************************************************************************** * * cb_get_entity_info: callback for get_node_op * The routine process matching network entity and add children elements * to a Node object for given entity. * * p1 - matching entity object * p2 - lookup control data that was used for node look up * returns parent index(newtork entity) in look up control. * return - error code * * **************************************************************************** */ static int cb_get_entity_info( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlNodePtr n_node = (xmlNodePtr)lcp->data[2].ptr; xmlNodePtr sub_node, subchild_node, subgrandchild_node; char numbuf[32]; char buff[INET6_ADDRSTRLEN + 1] = { 0 }; isns_attr_t *attr; sub_node = xmlNewChild(n_node, NULL, (xmlChar *)NETWORKENTITY, NULL); if (sub_node) { attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)]; subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)ENTITYID, (xmlChar *)attr->value.ptr); if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_ENTITY_PROTOCOL_ATTR_ID)]; (void) sprintf(numbuf, "%u", attr->value.ui); subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)ENTITYPROTOCOL, (xmlChar *)numbuf); if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_MGMT_IP_ADDR_ATTR_ID)]; if (attr->value.ip) { /* convert the ipv6 to ipv4 */ if (((int *)attr->value.ip)[0] == 0x00 && ((int *)attr->value.ip)[1] == 0x00 && ((uchar_t *)attr->value.ip)[8] == 0x00 && ((uchar_t *)attr->value.ip)[9] == 0x00 && ((uchar_t *)attr->value.ip)[10] == 0xFF && ((uchar_t *)attr->value.ip)[11] == 0xFF) { subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)MANAGEMENTIPADDR, (xmlChar *)inet_ntop(AF_INET, (void *)&(((uint32_t *)attr->value.ip)[3]), buff, sizeof (buff))); } else { subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)MANAGEMENTIPADDR, (xmlChar *)inet_ntop(AF_INET6, (void *)attr->value.ip, buff, sizeof (buff))); } if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_TIMESTAMP_ATTR_ID)]; if (attr->value.ui) { (void) sprintf(numbuf, "%u", attr->value.ui); subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)ENTITYREGTIMESTAMP, (xmlChar *)numbuf); if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_VERSION_RANGE_ATTR_ID)]; if (attr->value.ui) { subchild_node = xmlNewNode(NULL, (xmlChar *)PROTOCOLVERSIONRANGE); subchild_node = xmlAddChild(sub_node, subchild_node); if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } (void) sprintf(numbuf, "%u", (attr->value.ui >> ISNS_VER_SHIFT) & ISNS_VERSION); subgrandchild_node = xmlNewChild(subchild_node, NULL, (xmlChar *)PROTOCOLMAXVERSION, (xmlChar *)numbuf); if (subgrandchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } (void) sprintf(numbuf, "%u", attr->value.ui & ISNS_VERSION); subgrandchild_node = xmlNewChild(subchild_node, NULL, (xmlChar *)PROTOCOLMINVERSION, (xmlChar *)numbuf); if (subgrandchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_ENTITY_REG_PERIOD_ATTR_ID)]; if (attr->value.ui) { (void) sprintf(numbuf, "%u", attr->value.ui); subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)REGISTRATIONPERIOD, (xmlChar *)numbuf); if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } } else { return (ERR_XML_NEWCHILD_FAILED); } /* successful */ return (0); } /* * **************************************************************************** * * cb_get_pg_info: callback for get_node_op * The routine process matching portal group and returns ip address * and port number for further portal processing. * * p1 - matching portal group object * p2 - lookup control data that was used for portal group look up * returns portal ip address, port and group tag in look up control. * return - error code * * **************************************************************************** */ static int cb_get_pg_info( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; isns_attr_t *attr; /* get pg portal ip address and port attributes */ attr = &obj->attrs[ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)]; (void) memcpy(lcp->data[1].ip, attr->value.ip, sizeof (in6_addr_t)); attr = &obj->attrs[ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID)]; lcp->data[2].ui = attr->value.ui; attr = &obj->attrs[ATTR_INDEX_PG(ISNS_PG_TAG_ATTR_ID)]; lcp->id[2] = attr->value.ui; /* successful */ return (0); } /* * **************************************************************************** * * cb_get_portal_info: callback for get_node_op * The routine process matching portal and add portal object info to * the node object. * * p1 - matching portal object * p2 - lookup control data that was used for portal look up * return - error code * * **************************************************************************** */ static int cb_get_portal_info( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlNodePtr n_node = (xmlNodePtr)lcp->data[2].ptr; uint32_t tag = lcp->id[2]; xmlNodePtr sub_node, subchild_node, subgrandchild_node; char numbuf[32]; char buff[INET6_ADDRSTRLEN + 1] = { 0 }; isns_attr_t *attr; sub_node = xmlNewChild(n_node, NULL, (xmlChar *)PORTAL, NULL); /* get portal object attributes. */ if (sub_node) { attr = &obj->attrs[ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID)]; if (attr->value.ip) { /* convert the ipv6 to ipv4 */ if (((int *)attr->value.ip)[0] == 0x00 && ((int *)attr->value.ip)[1] == 0x00 && ((uchar_t *)attr->value.ip)[8] == 0x00 && ((uchar_t *)attr->value.ip)[9] == 0x00 && ((uchar_t *)attr->value.ip)[10] == 0xFF && ((uchar_t *)attr->value.ip)[11] == 0xFF) { subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)IPADDR, (xmlChar *)inet_ntop(AF_INET, (void *)&(((uint32_t *)attr->value.ip)[3]), buff, sizeof (buff))); } else { subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)IPADDR, (xmlChar *)inet_ntop(AF_INET6, (void *)attr->value.ip, buff, sizeof (buff))); } if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)UDPTCPPORT, NULL); if (subchild_node) { attr = &obj->attrs[ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID)]; subgrandchild_node = xmlNewChild(subchild_node, NULL, (xmlChar *)PORTTYPE, IS_PORT_UDP(attr->value.ui) ? (xmlChar *)UDPPORT : (xmlChar *)TCPPORT); if (subgrandchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } (void) sprintf(numbuf, "%u", PORT_NUMBER(attr->value.ui)); subgrandchild_node = xmlNewChild(subchild_node, NULL, (xmlChar *)PORTNUMBER, (xmlChar *)numbuf); if (subgrandchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { return (ERR_XML_NEWCHILD_FAILED); } (void) sprintf(numbuf, "%u", tag); subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)GROUPTAG, (xmlChar *)numbuf); if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } attr = &obj->attrs[ATTR_INDEX_PORTAL(ISNS_PORTAL_NAME_ATTR_ID)]; if (attr->value.ptr) { subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)SYMBOLICNAME, (xmlChar *)attr->value.ptr); if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } attr = &obj->attrs[ATTR_INDEX_PORTAL(ISNS_ESI_INTERVAL_ATTR_ID)]; if (attr->value.ui) { (void) sprintf(numbuf, "%u", attr->value.ui); subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)ESIINTERVAL, (xmlChar *)numbuf); if (subchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } attr = &obj->attrs[ATTR_INDEX_PORTAL(ISNS_ESI_PORT_ATTR_ID)]; if (attr->value.ui) { subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)ESIPORT, NULL); if (subchild_node) { subgrandchild_node = xmlNewChild(subchild_node, NULL, (xmlChar *)PORTTYPE, IS_PORT_UDP(attr->value.ui) ? (xmlChar *)UDPPORT : (xmlChar *)TCPPORT); if (subgrandchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } (void) sprintf(numbuf, "%u", PORT_NUMBER(attr->value.ui)); subgrandchild_node = xmlNewChild(subchild_node, NULL, (xmlChar *)PORTNUMBER, (xmlChar *)numbuf); if (subgrandchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { return (ERR_XML_NEWCHILD_FAILED); } } attr = &obj->attrs[ATTR_INDEX_PORTAL(ISNS_SCN_PORT_ATTR_ID)]; if (attr->value.ui) { subchild_node = xmlNewChild(sub_node, NULL, (xmlChar *)SCNPORT, NULL); if (subchild_node) { subgrandchild_node = xmlNewChild(subchild_node, NULL, (xmlChar *)PORTTYPE, IS_PORT_UDP(attr->value.ui) ? (xmlChar *)UDPPORT : (xmlChar *)TCPPORT); (void) sprintf(numbuf, "%u", PORT_NUMBER(attr->value.ui)); if (subgrandchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } subgrandchild_node = xmlNewChild(subchild_node, NULL, (xmlChar *)PORTNUMBER, (xmlChar *)numbuf); if (subgrandchild_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { return (ERR_XML_NEWCHILD_FAILED); } } } else if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } /* successful */ return (0); } /* * **************************************************************************** * * cb_get_dd_info: callback for get_dd_op * The routine process matching dd object * * p1 - matching dd object * p2 - lookup control data that was used for dd look up * return - error code * * **************************************************************************** */ static int cb_get_dd_info( void *p1, void *p2 ) { xmlNodePtr n_obj, n_node, sub_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; char numbuf[32]; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_ADDCHILD_FAILED); } n_node = xmlNewNode(NULL, (xmlChar *)DDOBJECT); if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_ADDCHILD_FAILED); } attr = &obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID)]; (void) sprintf(numbuf, "%u", attr->value.ui); n_attr = xmlSetProp(n_node, (xmlChar *)IDATTR, (xmlChar *)numbuf); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DD(ISNS_DD_FEATURES_ATTR_ID)]; if (DD_BOOTLIST_ENABLED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)BOOTLISTENABLEDELEM, (xmlChar *)XMLTRUE); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)BOOTLISTENABLEDELEM, (xmlChar *)XMLFALSE); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } /* successful */ return (0); } /* * **************************************************************************** * * cb_get_ddset_info: callback for get_ddset_op * The routine process matching dd object * * p1 - matching dds object * p2 - lookup control data that was used for dd set look up * return - error code * * **************************************************************************** */ static int cb_get_ddset_info( void *p1, void *p2 ) { xmlNodePtr n_obj, n_node, sub_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; char numbuf[32]; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = xmlNewNode(NULL, (xmlChar *)DDSETOBJECT); if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } /* get node name, alias, type and generate xml info */ attr = &obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID)]; (void) sprintf(numbuf, "%u", attr->value.ui); n_attr = xmlSetProp(n_node, (xmlChar *)IDATTR, (xmlChar *)numbuf); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID)]; if (DDS_ENABLED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)ENABLEDELEM, (xmlChar *)XMLTRUE); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)ENABLEDELEM, (xmlChar *)XMLFALSE); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } /* successful */ return (0); } /* * **************************************************************************** * * cb_enumerate_node_info: callback for enumerate_node_op * The routine is invoked for each node object. * * p1 - node object * p2 - lookup control data that was used for node look up * return - error code * * **************************************************************************** */ static int cb_enumerate_node_info( void *p1, void *p2 ) { xmlNodePtr n_obj, n_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = xmlNewNode(NULL, (xmlChar *)NODEOBJECT); if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } /* get node name, alias, type and generate xml info */ attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)]; switch (attr->value.ui) { case ISNS_CONTROL_NODE_TYPE | ISNS_INITIATOR_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)CONTROLNODEINITIATORTYPE); break; case ISNS_CONTROL_NODE_TYPE | ISNS_TARGET_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)CONTROLNODETARGETTYPE); break; case ISNS_TARGET_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)TARGETTYPE); break; case ISNS_INITIATOR_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)INITIATORTYPE); break; case ISNS_CONTROL_NODE_TYPE: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)CONTROLNODETYPE); break; default: n_attr = xmlSetProp(n_node, (xmlChar *)TYPEATTR, (xmlChar *)UNKNOWNTYPE); } if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_ALIAS_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)ALIASATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } /* successful */ return (0); } /* * **************************************************************************** * * i_enumerate_dd_dds_info: * The routine is implemnetation for enumerate dd and enumerate dds. * * p1 - dd or dd set object * p2 - lookup control data that was used for dd and dd set look up * return - error code * * **************************************************************************** */ static int i_enumerate_dd_dds_info( void *p1, void *p2, isns_type_t obj_type ) { xmlNodePtr n_obj, n_node, sub_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; char numbuf[32]; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } if (obj_type == OBJ_DD) { n_node = xmlNewNode(NULL, (xmlChar *)DDOBJECT); } else { n_node = xmlNewNode(NULL, (xmlChar *)DDSETOBJECT); } if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } if (obj_type == OBJ_DD) { /* get name, id, feaure and generate xml info */ attr = &obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID)]; (void) sprintf(numbuf, "%u", attr->value.ui); n_attr = xmlSetProp(n_node, (xmlChar *)IDATTR, (xmlChar *)numbuf); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DD(ISNS_DD_FEATURES_ATTR_ID)]; if (DD_BOOTLIST_ENABLED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)BOOTLISTENABLEDELEM, (xmlChar *)XMLTRUE); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)BOOTLISTENABLEDELEM, (xmlChar *)XMLFALSE); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } } else { /* get name, id, status and generate xml info */ attr = &obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID)]; (void) sprintf(numbuf, "%u", attr->value.ui); n_attr = xmlSetProp(n_node, (xmlChar *)IDATTR, (xmlChar *)numbuf); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID)]; if (DDS_ENABLED(attr->value.ui)) { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)ENABLEDELEM, (xmlChar *)XMLTRUE); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { sub_node = xmlNewChild(n_node, NULL, (xmlChar *)ENABLEDELEM, (xmlChar *)XMLFALSE); if (sub_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } } /* successful */ return (0); } /* * **************************************************************************** * * cb_enumerate_dd_info: callback for enumerate_dd_op * The routine is invoked for each dd object. * * p1 - dd object * p2 - lookup control data that was used for dd look up * return - error code * * **************************************************************************** */ static int cb_enumerate_dd_info( void *p1, void *p2 ) { return (i_enumerate_dd_dds_info(p1, p2, OBJ_DD)); } /* * **************************************************************************** * * cb_enumerate_ddset_info: callback for enumerate_dd_op * The routine is invoked for each dd object. * * p1 - dd object * p2 - lookup control data that was used for dd set look up * return - error code * * **************************************************************************** */ static int cb_enumerate_ddset_info( void *p1, void *p2 ) { return (i_enumerate_dd_dds_info(p1, p2, OBJ_DDS)); } /* * **************************************************************************** * * cb_getAssociated_node_info: * The routine is implemnetation for enumerate dd and enumerate dds. * * p1 - dd or dd set object * p2 - lookup control data that was used for dd and dd set look up * return - error code * * **************************************************************************** */ static int cb_getAssociated_node_info( void *p1, void *p2 ) { xmlNodePtr n_obj, n_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; uchar_t *ddname = lcp->data[2].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ASSOCIATION); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = xmlNewNode(NULL, (xmlChar *)DDOBJECTMEMBER); if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } /* get node name, alias, type and generate xml info */ attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)NODENAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } n_attr = xmlSetProp(n_node, (xmlChar *)DDNAMEATTR, (xmlChar *)ddname); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } /* successful */ return (0); } /* * **************************************************************************** * * cb_getAssociated_node_to_dd_info: * The routine is implemnetation for enumerate dd and enumerate dds. * * p1 - dd or dd set object * p2 - lookup control data that was used for dd and dd set look up * return - error code * * **************************************************************************** */ static int cb_getAssociated_node_to_dd_info( void *p1, void *p2 ) { xmlNodePtr n_obj, n_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; uchar_t *nodename = lcp->data[2].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ASSOCIATION); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = xmlNewNode(NULL, (xmlChar *)DDOBJECTMEMBER); if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } /* get node name, alias, type and generate xml info */ n_attr = xmlSetProp(n_node, (xmlChar *)NODENAMEATTR, (xmlChar *)nodename); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)DDNAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } /* successful */ return (0); } /* * **************************************************************************** * * cb_getAssociated_dd_info: * The routine is implemnetation for getting dds membership. * * p1 - dd or dd set object * p2 - lookup control data that was used for dd and dd set look up * return - error code * * **************************************************************************** */ static int cb_getAssociated_dd_info( void *p1, void *p2 ) { xmlNodePtr n_obj, n_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; uchar_t *ddsetname = lcp->data[2].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ASSOCIATION); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = xmlNewNode(NULL, (xmlChar *)DDSETOBJECTMEMBER); if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } /* get node name, alias, type and generate xml info */ attr = &obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)DDNAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } n_attr = xmlSetProp(n_node, (xmlChar *)DDSETNAMEATTR, (xmlChar *)ddsetname); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } /* successful */ return (0); } /* * **************************************************************************** * * cb_getAssociated_dd_to_ddset_info: * The routine is implemnetation for enumerate dd and enumerate dds. * * p1 - dd or dd set object * p2 - lookup control data that was used for dd and dd set look up * return - error code * * **************************************************************************** */ static int cb_getAssociated_dd_to_ddset_info( void *p1, void *p2 ) { xmlNodePtr n_obj, n_node, root; xmlAttrPtr n_attr; isns_attr_t *attr; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; xmlDocPtr doc = (xmlDocPtr)lcp->data[1].ptr; uchar_t *ddname = lcp->data[2].ptr; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ASSOCIATION); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = xmlNewNode(NULL, (xmlChar *)DDSETOBJECTMEMBER); if (n_node) { n_node = xmlAddChild(n_obj, n_node); if (n_node == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } /* get node name, alias, type and generate xml info */ n_attr = xmlSetProp(n_node, (xmlChar *)DDNAMEATTR, (xmlChar *)ddname); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } attr = &obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID)]; n_attr = xmlSetProp(n_node, (xmlChar *)DDSETNAMEATTR, (xmlChar *)attr->value.ptr); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } /* successful */ return (0); } /* * **************************************************************************** * * handle_partial_success: * * doc - response doc to fill up * ret - return code from the caller. * * **************************************************************************** */ static int handle_partial_success( xmlDocPtr doc, int ret ) { xmlNodePtr n_obj, n_node, root; char numbuf[32]; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)RESULTELEMENT); if (n_obj) { if (root->children) { n_obj = xmlAddPrevSibling(root->children, n_obj); (void) sprintf(numbuf, "%d", (ret != 0) ? PARTIAL_SUCCESS : 0); n_node = xmlNewChild(n_obj, NULL, (xmlChar *)STATUSELEMENT, (xmlChar *)numbuf); if (n_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } n_node = xmlNewChild(n_obj, NULL, (xmlChar *)MESSAGEELEMENT, (xmlChar *)result_code_to_str((ret != 0) ? PARTIAL_SUCCESS : 0)); if (n_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } (void) sprintf(numbuf, "%d", ret); n_node = xmlNewChild(n_obj, NULL, (xmlChar *)STATUSELEMENT, (xmlChar *)numbuf); if (n_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } n_node = xmlNewChild(n_obj, NULL, (xmlChar *)MESSAGEELEMENT, (xmlChar *)result_code_to_str(ret)); if (n_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } } else { return (ERR_XML_NEWNODE_FAILED); } return (0); } /* * **************************************************************************** * * handle_partial_failure: * * doc - response doc to fill up * ret - return code from the caller. * * **************************************************************************** */ static int handle_partial_failure( xmlDocPtr doc, int ret, boolean_t all_failed ) { xmlNodePtr n_obj, n_node, root; char numbuf[32]; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)RESULTELEMENT); if (n_obj) { if (root->children) { /* some or all associations failed to create */ n_obj = xmlAddPrevSibling(root->children, n_obj); /* capture last error. should come up with all failed?? */ (void) sprintf(numbuf, "%d", all_failed ? ret : PARTIAL_FAILURE); n_node = xmlNewChild(n_obj, NULL, (xmlChar *)STATUSELEMENT, (xmlChar *)numbuf); if (n_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } n_node = xmlNewChild(n_obj, NULL, (xmlChar *)MESSAGEELEMENT, (xmlChar *)result_code_to_str(all_failed ? ret : PARTIAL_FAILURE)); if (n_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } else { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } (void) sprintf(numbuf, "%d", (ret != 0) ? ret : 0); n_node = xmlNewChild(n_obj, NULL, (xmlChar *)STATUSELEMENT, (xmlChar *)numbuf); if (n_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } n_node = xmlNewChild(n_obj, NULL, (xmlChar *)MESSAGEELEMENT, (xmlChar *)result_code_to_str((ret != 0) ? ret : 0)); if (n_node == NULL) { return (ERR_XML_NEWCHILD_FAILED); } } } else { return (ERR_XML_NEWNODE_FAILED); } return (0); } /* * **************************************************************************** * * get_serverconfig_op: * The routine process server administrative setting. * * doc - response doc to fill up. * * **************************************************************************** */ int get_serverconfig_op( xmlDocPtr doc ) { extern uint64_t esi_threshold; extern uint8_t mgmt_scn; extern ctrl_node_t *control_nodes; extern pthread_mutex_t ctrl_node_mtx; extern char data_store[MAXPATHLEN]; xmlNodePtr n_obj, root; char numbuf[32]; ctrl_node_t *ctrl_node_p; int ret = 0; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } n_obj = xmlNewNode(NULL, (xmlChar *)ISNSSERVER); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_ADDCHILD_FAILED); } if (xmlNewChild(n_obj, NULL, (xmlChar *)DATASTORELOCATION, (xmlChar *)data_store) == NULL) { return (ERR_XML_NEWCHILD_FAILED); } (void) sprintf(numbuf, "%llu", esi_threshold); if (xmlNewChild(n_obj, NULL, (xmlChar *)ESIRETRYTHRESHOLD, (xmlChar *)numbuf) == NULL) { return (ERR_XML_NEWCHILD_FAILED); } if (xmlNewChild(n_obj, NULL, (xmlChar *)MANAGEMENTSCNENABLED, (mgmt_scn) ? (uchar_t *)XMLTRUE : (uchar_t *)XMLFALSE) == NULL) { return (ERR_XML_NEWCHILD_FAILED); } (void) pthread_mutex_lock(&ctrl_node_mtx); if (control_nodes == NULL) { if (xmlNewChild(n_obj, NULL, (xmlChar *)CONTROLNODENAME, (xmlChar *)NULL) == NULL) { (void) pthread_mutex_unlock(&ctrl_node_mtx); return (ERR_XML_NEWCHILD_FAILED); } } else { ctrl_node_p = control_nodes; while (ctrl_node_p != NULL) { if (xmlNewChild(n_obj, NULL, (xmlChar *)CONTROLNODENAME, (xmlChar *)ctrl_node_p->name) == NULL) { (void) pthread_mutex_unlock(&ctrl_node_mtx); return (ERR_XML_NEWCHILD_FAILED); } ctrl_node_p = ctrl_node_p->next; } } (void) pthread_mutex_unlock(&ctrl_node_mtx); return (handle_partial_success(doc, ret)); } /* * **************************************************************************** * * get_node_op: * service get operation on a given node. * * req - contains all info for a request. * doc - response doc to fill up * * **************************************************************************** */ int get_node_op( request_t *req, xmlDocPtr doc /* any additional arguments go here */ ) { int ret = 0, ret_save = 0; int i = 0; lookup_ctrl_t lc, lc2, lc3; uint32_t uid; char buff2[INET6_ADDRSTRLEN]; /* prepare lookup ctrl data for looking for the node object */ lc.curr_uid = 0; lc.type = get_lc_type(req->op_info.obj); lc.id[0] = get_lc_id(req->op_info.obj); lc.op[0] = OP_STRING; lc.op[1] = 0; lc.data[1].ptr = (uchar_t *)doc; /* xml writer descriptor */ while (i < req->count) { lc.data[0].ptr = (uchar_t *)req->req_data.data[i]; ret = cache_lookup(&lc, &uid, cb_get_node_info); if (uid == 0) { ret = ERR_MATCHING_ISCSI_NODE_NOT_FOUND; } /* generate network entity object information */ if (ret == 0 && lc.id[2] != 0) { /* * !!! there might be no entity and portal info for * !!! the node if it is not a registered node */ /* prepare lookup ctrl data for looking for entity */ SET_UID_LCP(&lc2, OBJ_ENTITY, lc.id[2]); lc2.data[1].ptr = (uchar_t *)doc; /* cb_get_node_info callback returned Node object. */ lc2.data[2].ptr = lc.data[2].ptr; ret = cache_lookup(&lc2, &uid, cb_get_entity_info); if (uid == 0) { ret = ERR_MATCHING_NETWORK_ENTITY_NOT_FOUND; } } /* generate portal information */ if (ret == 0 && lc.id[2] != 0) { /* prepare lookup ctrl data for looking for pg */ lc2.curr_uid = 0; lc2.type = OBJ_PG; lc2.id[0] = ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID); lc2.op[0] = OP_STRING; /* lc.data[0].ptr contains node name */ lc2.data[0].ptr = lc.data[0].ptr; lc2.op[1] = 0; lc2.data[1].ip = (in6_addr_t *)buff2; /* prepare lookup ctrl data for looking for portal */ lc3.curr_uid = 0; lc3.type = OBJ_PORTAL; lc3.id[0] = ATTR_INDEX_PORTAL( ISNS_PORTAL_IP_ADDR_ATTR_ID); lc3.op[0] = OP_MEMORY_IP6; lc3.id[1] = ATTR_INDEX_PORTAL( ISNS_PORTAL_PORT_ATTR_ID); lc3.op[1] = OP_INTEGER; lc3.op[2] = 0; /* cb_get_node_info callback returned Node object. */ lc3.data[2].ptr = lc.data[2].ptr; for (;;) { ret = cache_lookup(&lc2, &uid, cb_get_pg_info); if (uid != 0) { /* we found a portal group */ lc2.curr_uid = uid; /* it is a null pg if pgt is zero. */ if (lc2.id[2] != 0) { /* pass ip addr */ lc3.data[0].ip = lc2.data[1].ip; /* pass port num */ lc3.data[1].ui = lc2.data[2].ui; /* pass pgt */ lc3.id[2] = lc2.id[2]; ret = cache_lookup(&lc3, &uid, cb_get_portal_info); } } else { /* * no more portal group which is * tied to this stroage node object. */ break; } } } /* save error for this iteration */ if (ret != 0) { ret_save = ret; } ret = 0; i++; } return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * i_get_dd_dds_op: * serves get operatrion on dd or dds. * * req - contains all info for a request. * doc - response doc to fill up * obj_type - object type(either dd or dd set) * * **************************************************************************** */ static int i_get_dd_dds_op( request_t *req, xmlDocPtr doc, isns_type_t obj_type /* any additional arguments go here */ ) { result_code_t ret = 0, ret_save = 0; int i = 0; lookup_ctrl_t lc; uint32_t uid; if ((obj_type != OBJ_DD) && (obj_type != OBJ_DDS)) { return (ERR_INVALID_MGMT_REQUEST); } /* prepare lookup ctrl data for looking for the node object */ lc.curr_uid = 0; lc.type = obj_type; lc.id[0] = get_lc_id(req->op_info.obj); lc.op[0] = OP_STRING; lc.op[1] = 0; lc.data[1].ptr = (uchar_t *)doc; /* xml writer descriptor */ while (i < req->count) { if (obj_type == OBJ_DD) { lc.data[0].ptr = (uchar_t *)req->req_data.data[i]; ret = cache_lookup(&lc, &uid, cb_get_dd_info); if (uid == 0) { /* set an error and continue. */ ret = ERR_MATCHING_DD_NOT_FOUND; } } else { lc.data[0].ptr = (uchar_t *)req->req_data.data[i]; ret = cache_lookup(&lc, &uid, cb_get_ddset_info); if (uid == 0) { /* set an error and continue. */ ret = ERR_MATCHING_DDSET_NOT_FOUND; } } /* save error for this iteration */ if (ret != 0) { ret_save = ret; } ret = 0; i++; } return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * i_delete_ddmember_op: * serves delete member operatrion on dd. * * container - dd name * member - node name * * **************************************************************************** */ static int i_delete_ddmember_op( uchar_t *container, uchar_t *member ) { int ret = 0; isns_assoc_iscsi_t aiscsi; isns_obj_t *assoc; isns_attr_t *attr; int len; lookup_ctrl_t lc; uint32_t dd_id; /* prepare lookup ctrl data for looking for the dd object */ lc.curr_uid = 0; lc.type = OBJ_DD; lc.id[0] = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); lc.op[0] = OP_STRING; lc.data[0].ptr = container; lc.op[1] = 0; if ((dd_id = is_obj_there(&lc)) != 0) { aiscsi.type = OBJ_ASSOC_ISCSI; aiscsi.puid = dd_id; len = strlen((char *)member) + 1; len += 4 - (len % 4); attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI( ISNS_DD_ISCSI_NAME_ATTR_ID)]; attr->tag = ISNS_DD_ISCSI_NAME_ATTR_ID; attr->len = len; attr->value.ptr = (uchar_t *)member; attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI( ISNS_DD_ISCSI_INDEX_ATTR_ID)]; attr->tag = 0; /* clear it */ assoc = (isns_obj_t *)&aiscsi; ret = remove_dd_member(assoc); } else { ret = ERR_MATCHING_DD_NOT_FOUND; } return (ret); } /* * **************************************************************************** * * i_delete_ddsetmember_op: * serves delete member operatrion on dd set. * * container - dd set name * member - dd name * * **************************************************************************** */ static int i_delete_ddsetmember_op( uchar_t *container, uchar_t *member ) { int ret = 0; lookup_ctrl_t lc, lc2; uint32_t container_id, member_id; /* prepare lookup ctrl data for looking for the dd-set object */ lc.curr_uid = 0; lc.type = OBJ_DDS; lc.id[0] = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID); lc.op[0] = OP_STRING; lc.data[0].ptr = container; lc.op[1] = 0; /* prepare lookup ctrl data for looking for the dd object */ lc2.curr_uid = 0; lc2.type = OBJ_DD; lc2.id[0] = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); lc2.op[0] = OP_STRING; lc2.data[0].ptr = member; lc2.op[1] = 0; if ((container_id = is_obj_there(&lc)) != 0) { if ((member_id = is_obj_there(&lc2)) != 0) { ret = remove_dds_member(container_id, member_id); } else { ret = ERR_MATCHING_DD_NOT_FOUND; } } else { ret = ERR_MATCHING_DDSET_NOT_FOUND; } return (ret); } /* * **************************************************************************** * * get_dd_op: * service get operation on given dd(s). * * req - contains all info for a request. * doc - response doc to fill up * * **************************************************************************** */ int get_dd_op( request_t *req, xmlDocPtr doc /* any additional arguments go here */ ) { return (i_get_dd_dds_op(req, doc, OBJ_DD)); } /* * **************************************************************************** * * get_ddset_op: * service get operation on given dd set(s). * * req - contains all info for a request. * doc - response doc to fill up * * **************************************************************************** */ int get_ddset_op( request_t *req, xmlDocPtr doc /* any additional arguments go here */ ) { return (i_get_dd_dds_op(req, doc, OBJ_DDS)); } /* * **************************************************************************** * * enumerate_node_op: * services enumerate node op. * * req - contains enumerate request info. * doc - response doc to fill up * * **************************************************************************** */ int enumerate_node_op( xmlDocPtr doc /* any additional arguments go here */ ) { htab_t *htab = cache_get_htab(OBJ_ISCSI); uint32_t uid = 0; lookup_ctrl_t lc; int ret = 0, ret_save = 0; SET_UID_LCP(&lc, OBJ_ISCSI, 0); lc.data[1].ptr = (uchar_t *)doc; lc.data[2].ui = 0; FOR_EACH_ITEM(htab, uid, { lc.data[0].ui = uid; ret = cache_lookup(&lc, NULL, cb_enumerate_node_info); if (ret != 0) { ret_save = ret; } }); return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * enumerate_dd_op: * services enumerate discovery domain op. * * req - contains enumerate request info. * doc - response doc to fill up * * **************************************************************************** */ int enumerate_dd_op( xmlDocPtr doc /* any additional arguments go here */ ) { htab_t *htab = cache_get_htab(OBJ_DD); uint32_t uid = 0; lookup_ctrl_t lc; int ret = 0, ret_save = 0; SET_UID_LCP(&lc, OBJ_DD, 0); lc.data[1].ptr = (uchar_t *)doc; lc.data[2].ui = 0; FOR_EACH_ITEM(htab, uid, { lc.data[0].ui = uid; ret = cache_lookup(&lc, NULL, cb_enumerate_dd_info); if (ret != 0) { ret_save = ret; } }); return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * enumerate_ddset_op: * services enumerate discovery domain set op. * * req - contains enumerate request info. * doc - response doc to fill up * * **************************************************************************** */ int enumerate_ddset_op( xmlDocPtr doc /* any additional arguments go here */ ) { htab_t *htab = cache_get_htab(OBJ_DDS); uint32_t uid = 0; lookup_ctrl_t lc; int ret = 0, ret_save = 0; SET_UID_LCP(&lc, OBJ_DDS, 0); lc.data[1].ptr = (uchar_t *)doc; lc.data[2].ui = 0; FOR_EACH_ITEM(htab, uid, { lc.data[0].ui = uid; ret = cache_lookup(&lc, NULL, cb_enumerate_ddset_info); if (ret != 0) { ret_save = ret; } }); return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * getassociated_dd_to_node_op: * construct a list of node that is associated with a given Discovery * Domain. * * req - contains getAssociated request info. * doc - response doc to fill up * * **************************************************************************** */ int getAssociated_dd_to_node_op( request_t *req, xmlDocPtr doc /* any additional arguments go here */ ) { uint32_t uid = 0, n; lookup_ctrl_t lc, lc2; int i = 0, ret = 0, ret_save = 0; bmp_t *p; lc.curr_uid = 0; lc.type = OBJ_DD; lc.id[0] = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); lc.op[0] = OP_STRING; lc.op[1] = 0; SET_UID_LCP(&lc2, OBJ_ISCSI, 0); lc2.data[1].ptr = (uchar_t *)doc; while (i < req->count) { lc.data[0].ptr = (uchar_t *)req->req_data.data[i]; if ((uid = is_obj_there(&lc)) != 0) { ret = get_dd_matrix(uid, &p, &n); FOR_EACH_MEMBER(p, n, uid, { lc2.data[0].ui = uid; lc2.data[2].ptr = (uchar_t *)req->req_data.data[i]; ret = cache_lookup(&lc2, NULL, cb_getAssociated_node_info); }); free(p); } else { ret = ERR_MATCHING_DD_NOT_FOUND; } /* save error for this iteration */ if (ret != 0) { ret_save = ret; } ret = 0; i++; } return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * getassociated_node_to_dd_op: * construct a list of Discovery Doamins that is associated with a given * node. * * req - contains getAssociated request info. * doc - response doc to fill up * * **************************************************************************** */ int getAssociated_node_to_dd_op( request_t *req, xmlDocPtr doc /* any additional arguments go here */ ) { uint32_t uid = 0, dd_id; lookup_ctrl_t lc, lc2; int i = 0, ret = 0, ret_save = 0; 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.op[1] = 0; SET_UID_LCP(&lc2, OBJ_DD, 0); lc2.data[1].ptr = (uchar_t *)doc; while (i < req->count) { lc.data[0].ptr = (uchar_t *)req->req_data.data[i]; if ((uid = is_obj_there(&lc)) != 0) { if ((dd_id = get_dd_id(uid, 0)) == 0) { ret = ERR_NO_ASSOCIATED_DD_FOUND; i++; continue; } else { do { lc2.data[0].ui = dd_id; lc2.data[2].ptr = (uchar_t *)req->req_data.data[i]; ret = cache_lookup(&lc2, NULL, cb_getAssociated_node_to_dd_info); dd_id = get_dd_id(uid, dd_id); } while (dd_id != 0); }; } else { ret = ERR_MATCHING_NODE_NOT_FOUND; } /* save error for this iteration */ if (ret != 0) { ret_save = ret; } ret = 0; i++; } return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * getassociated_ddset_to_dd_op: * construct a list of Discovery Doamins that is associated with a given * Discover Domain set. * * req - contains getAssociated request info. * doc - response doc to fill up * * **************************************************************************** */ int getAssociated_ddset_to_dd_op( request_t *req, xmlDocPtr doc /* any additional arguments go here */ ) { uint32_t uid = 0, n; lookup_ctrl_t lc, lc2; int i = 0, ret = 0, ret_save = 0; bmp_t *p; lc.curr_uid = 0; lc.type = OBJ_DDS; lc.id[0] = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID); lc.op[0] = OP_STRING; lc.op[1] = 0; SET_UID_LCP(&lc2, OBJ_DD, 0); lc2.data[1].ptr = (uchar_t *)doc; while (i < req->count) { lc.data[0].ptr = (uchar_t *)req->req_data.data[i]; if ((uid = is_obj_there(&lc)) != 0) { ret = get_dds_matrix(uid, &p, &n); FOR_EACH_MEMBER(p, n, uid, { lc2.data[0].ui = uid; lc2.data[2].ptr = (uchar_t *)req->req_data.data[i]; ret = cache_lookup(&lc2, NULL, cb_getAssociated_dd_info); }); free(p); } else { ret = ERR_MATCHING_DDSET_NOT_FOUND; } /* save error for this iteration */ if (ret != 0) { ret_save = ret; } ret = 0; i++; } return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * getassociated_dd_to_ddset_op: * construct a list of Discovery Doamin sets that is associated with a * given Discovery Domain. * * req - contains getAssociated request info. * doc - response doc to fill up * * **************************************************************************** */ int getAssociated_dd_to_ddset_op( request_t *req, xmlDocPtr doc /* any additional arguments go here */ ) { uint32_t uid = 0, ddset_id; lookup_ctrl_t lc, lc2; int i = 0, ret = 0, ret_save = 0; lc.curr_uid = 0; lc.type = OBJ_DD; lc.id[0] = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); lc.op[0] = OP_STRING; lc.op[1] = 0; SET_UID_LCP(&lc2, OBJ_DDS, 0); lc2.data[1].ptr = (uchar_t *)doc; while (i < req->count) { lc.data[0].ptr = (uchar_t *)req->req_data.data[i]; if ((uid = is_obj_there(&lc)) != 0) { lc2.data[2].ui = 0; if ((ddset_id = get_dds_id(uid, 0)) == 0) { ret = ERR_NO_ASSOCIATED_DDSET_FOUND; i++; continue; } else { do { lc2.data[0].ui = ddset_id; lc2.data[2].ptr = (uchar_t *)req->req_data.data[i]; ret = cache_lookup(&lc2, NULL, cb_getAssociated_dd_to_ddset_info); ddset_id = get_dds_id(uid, ddset_id); } while (ddset_id != 0); }; } else { ret = ERR_MATCHING_DD_NOT_FOUND; } if (ret != 0) { ret_save = ret; } i++; } return (handle_partial_success(doc, ret_save)); } /* * **************************************************************************** * * delete_dd_ddset_op: * removes a list of dd or dd set. * * req - contains delete request info. * doc - response doc to fill up * obj_type - object type(either dd or dd set) * * **************************************************************************** */ int delete_dd_ddset_op( request_t *req, xmlDocPtr doc, object_type type /* any additional arguments go here */ ) { result_code_t ret = 0, ret_save = 0; isns_type_t lc_type; int i = 0, err_count = 0; lookup_ctrl_t lc; uint32_t uid; xmlNodePtr n_obj, n_node, root; xmlAttrPtr n_attr; int different_err = 0; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } lc_type = get_lc_type(type); if ((lc_type != OBJ_DD) && (lc_type != OBJ_DDS)) { return (ERR_INVALID_MGMT_REQUEST); } /* prepare lookup ctrl data for looking for the node object */ lc.curr_uid = 0; lc.type = lc_type; lc.id[0] = get_lc_id(req->op_info.obj); lc.op[0] = OP_STRING; lc.op[1] = 0; lc.data[1].ptr = (uchar_t *)doc; /* xml writer descriptor */ while (i < req->count) { lc.data[0].ptr = (uchar_t *)req->req_data.data[i]; /* lock the cache for writing */ (void) cache_lock_write(); if ((uid = is_obj_there(&lc)) != 0) { /* remove the dd/ddset */ ret = (lc_type == OBJ_DD) ? remove_dd_object(uid) : remove_dds_object(uid); /* unlock the cache and sync the data */ ret = cache_unlock_sync(ret); } else { /* unlock the cache and no need to sync data */ (void) cache_unlock_nosync(); /* set an error and continue. */ ret = (lc_type == OBJ_DD) ? ERR_MATCHING_DD_NOT_FOUND : ERR_MATCHING_DDSET_NOT_FOUND; } if (ret != 0) { /* keep track if there are different errors encountered. */ if (ret_save != 0 && ret != ret_save) { different_err++; } err_count++; n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { if ((n_obj = xmlAddChild(root, n_obj)) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = (lc_type == OBJ_DD) ? xmlNewNode(NULL, (xmlChar *)DDOBJECT) : xmlNewNode(NULL, (xmlChar *)DDSETOBJECT); if (n_node) { if ((n_node = xmlAddChild(n_obj, n_node)) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } n_attr = xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)req->req_data.data[i]); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } ret_save = ret; } i ++; } return (handle_partial_failure(doc, ret_save, (req->count == err_count && !different_err) ? B_TRUE : B_FALSE)); } /* * **************************************************************************** * * delete_ddmember_ddsetmember_op: * removes a list of dd memeber or dd seti member. * * req - contains delete request info. * doc - response doc to fill up * type - object type(either dd or dd set) * * **************************************************************************** */ int delete_ddmember_ddsetmember_op( request_t *req, xmlDocPtr doc, object_type type /* any additional arguments go here */ ) { result_code_t ret = 0, ret_save = 0; isns_type_t lc_type; int i = 0, err_count = 0; lookup_ctrl_t lc, lc2; uint32_t container_id, member_id; xmlNodePtr n_node, n_obj, root; xmlAttrPtr n_attr; int different_err = 0; int is_a_member; lc_type = get_lc_type(type); if ((lc_type != OBJ_DD) && (lc_type != OBJ_DDS)) { return (ERR_INVALID_MGMT_REQUEST); } /* prepare lookup ctrl data for looking for the node object */ lc.curr_uid = 0; lc.type = lc_type; lc.id[0] = get_lc_id(req->op_info.obj); lc.op[0] = OP_STRING; lc.op[1] = 0; lc2.curr_uid = 0; if (lc_type == OBJ_DD) { lc2.type = OBJ_ISCSI; lc2.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); } else { lc2.type = OBJ_DD; lc2.id[0] = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); } lc2.op[0] = OP_STRING; lc2.op[1] = 0; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } while (i < req->count) { lc.data[0].ptr = (uchar_t *)req->req_data.pair[i]->container; /* get the dd_id/dds_id */ (void) cache_lock_write(); container_id = is_obj_there(&lc); if (container_id != 0) { lc2.data[0].ptr = (uchar_t *)req->req_data.pair[i]->member; member_id = is_obj_there(&lc2); if (member_id != 0) { is_a_member = (container_id == ((lc_type == OBJ_DD) ? get_dd_id(member_id, container_id - 1) : get_dds_id(member_id, container_id - 1))); } if (member_id != 0 && is_a_member != 0) { /* delete the dd member */ ret = (lc_type == OBJ_DD) ? i_delete_ddmember_op( (uchar_t *)req->req_data.pair[i]->container, (uchar_t *)req->req_data.pair[i]->member) : i_delete_ddsetmember_op( (uchar_t *)req->req_data.pair[i]->container, (uchar_t *)req->req_data.pair[i]->member); /* unlock the cache and sync the data */ ret = cache_unlock_sync(ret); } else { /* unlock the cache and no need to sync */ (void) cache_unlock_nosync(); ret = ERR_NO_SUCH_ASSOCIATION; } } else { /* unlock the cache and no need to sync */ (void) cache_unlock_nosync(); ret = (lc_type == OBJ_DD) ? ERR_MATCHING_DD_NOT_FOUND : ERR_MATCHING_DDSET_NOT_FOUND; } if (ret != 0) { /* keep track if there are different errors encountered. */ if (ret_save != 0 && ret != ret_save) { different_err++; } ret_save = ret; err_count++; n_obj = xmlNewNode(NULL, (xmlChar *)ASSOCIATION); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } if (lc_type == OBJ_DD) { n_node = xmlNewNode(NULL, (xmlChar *)DDOBJECTMEMBER); n_attr = xmlSetProp(n_node, (xmlChar *)NODENAMEATTR, (xmlChar *)req->req_data.pair[i]->member); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } n_attr = xmlSetProp(n_node, (xmlChar *)DDNAMEATTR, (xmlChar *)req->req_data.pair[i]->container); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } } else { n_node = xmlNewNode(NULL, (xmlChar *)DDSETOBJECTMEMBER); n_attr = xmlSetProp(n_node, (xmlChar *)DDNAMEATTR, (xmlChar *)req->req_data.pair[i]->member); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } n_attr = xmlSetProp(n_node, (xmlChar *)DDSETNAMEATTR, (xmlChar *)req->req_data.pair[i]->container); if (n_attr == NULL) { return (ERR_XML_SETPROP_FAILED); } } if (xmlAddChild(n_obj, n_node) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } i++; } return (handle_partial_failure(doc, ret_save, (req->count == err_count && !different_err) ? B_TRUE : B_FALSE)); } /* * **************************************************************************** * * create_ddmember_ddsetmember_op: * removes a list of dd memeber or dd seti member. * * req - contains delete request info. * doc - response doc to fill up * type - object type(either dd or dd set) * * **************************************************************************** */ int create_ddmember_ddsetmember_op( request_t *req, xmlDocPtr doc, object_type type /* any additional arguments go here */ ) { result_code_t ret = 0, ret_save = 0; isns_type_t lc_type; int i = 0, err_count = 0; lookup_ctrl_t lc, lc2; uint32_t container_id, member_id; xmlNodePtr n_node, n_obj, root; isns_assoc_iscsi_t aiscsi = { 0 }; isns_assoc_dd_t add = { 0 }; isns_obj_t *assoc; isns_attr_t *attr; uint32_t len; int different_err = 0; lc_type = get_lc_type(type); if ((lc_type != OBJ_DD) && (lc_type != OBJ_DDS)) { return (ERR_INVALID_MGMT_REQUEST); } /* prepare lookup ctrl data for looking for the node object */ lc.curr_uid = 0; lc.type = lc_type; lc.id[0] = get_lc_id(req->op_info.obj); lc.op[0] = OP_STRING; lc.op[1] = 0; lc2.curr_uid = 0; if (lc_type == OBJ_DD) { lc2.type = OBJ_ISCSI; lc2.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); } else { lc2.type = OBJ_DD; lc2.id[0] = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); } lc2.op[0] = OP_STRING; lc2.op[1] = 0; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } while (i < req->count) { lc.data[0].ptr = (uchar_t *)req->req_data.pair[i]->container; /* get the dd_id/dds_id */ (void) cache_lock_write(); container_id = is_obj_there(&lc); if (container_id != 0) { (void) memset(&aiscsi, 0, sizeof (aiscsi)); if (lc_type == OBJ_DD) { aiscsi.puid = container_id; aiscsi.type = OBJ_ASSOC_ISCSI; attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI( ISNS_DD_ISCSI_NAME_ATTR_ID)]; attr->tag = ISNS_DD_ISCSI_NAME_ATTR_ID; len = xmlStrlen( (xmlChar *)req->req_data.pair[i]->member) + 1; len += 4 - (len % 4); /* on 4 bytes aligned */ attr->len = len; attr->value.ptr = (uchar_t *)req->req_data.pair[i]->member; assoc = (isns_obj_t *)&aiscsi; /* add the dd member */ ret = add_dd_member(assoc); /* unlock the cache and sync the data */ ret = cache_unlock_sync(ret); } else { lc2.data[0].ptr = (uchar_t *)req->req_data.pair[i]->member; if ((member_id = is_obj_there(&lc2)) != 0) { add.puid = container_id; add.type = OBJ_ASSOC_DD; 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 = member_id; assoc = (isns_obj_t *)&add; /* add the dd-set member */ ret = add_dds_member(assoc); /* unlock the cache and sync the data */ ret = cache_unlock_sync(ret); } else { /* unlock the cache and no need to sync */ (void) cache_unlock_nosync(); ret = ERR_MATCHING_DD_NOT_FOUND; } } } else { /* unlock the cache and no need to sync */ (void) cache_unlock_nosync(); ret = (lc_type == OBJ_DD) ? ERR_MATCHING_DD_NOT_FOUND : ERR_MATCHING_DDSET_NOT_FOUND; } if (ret != 0) { /* keep track if there are different errors encountered. */ if (ret_save != 0 && ret != ret_save) { different_err++; } err_count++; n_obj = xmlNewNode(NULL, (xmlChar *)ASSOCIATION); if (n_obj) { n_obj = xmlAddChild(root, n_obj); if (n_obj == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } if (lc_type == OBJ_DD) { n_node = xmlNewNode(NULL, (xmlChar *)DDOBJECTMEMBER); if (xmlSetProp(n_node, (xmlChar *)NODENAMEATTR, (xmlChar *)req->req_data.pair[i]->member) == NULL) { return (ERR_XML_SETPROP_FAILED); } if (xmlSetProp(n_node, (xmlChar *)DDNAMEATTR, (xmlChar *)req->req_data.pair[i]->container) == NULL) { return (ERR_XML_SETPROP_FAILED); } } else { n_node = xmlNewNode(NULL, (xmlChar *)DDSETOBJECTMEMBER); if (xmlSetProp(n_node, (xmlChar *)DDNAMEATTR, (xmlChar *)req->req_data.pair[i]->member) == NULL) { return (ERR_XML_SETPROP_FAILED); } if (xmlSetProp(n_node, (xmlChar *)DDSETNAMEATTR, (xmlChar *)req->req_data.pair[i]->container) == NULL) { return (ERR_XML_SETPROP_FAILED); } } if (xmlAddChild(n_obj, n_node) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } ret_save = ret; } i++; } return (handle_partial_failure(doc, ret_save, (req->count == err_count && !different_err) ? B_TRUE : B_FALSE)); } /* * **************************************************************************** * * rename_dd_ddset_op: * removes a list of dd memeber or dd seti member. * * req - contains delete request info. * doc - response doc to fill up * type - object type(either dd or dd set) * * **************************************************************************** */ static int rename_dd_ddset_op( request_t *req, xmlDocPtr doc, object_type type /* any additional arguments go here */ ) { result_code_t ret = 0, ret_save = 0; isns_type_t lc_type; int i = 0, err_count = 0; lookup_ctrl_t lc; uint32_t container_id; xmlNodePtr n_node, n_obj, root; uchar_t *name; uint32_t len; int different_err = 0; lc_type = get_lc_type(type); if ((lc_type != OBJ_DD) && (lc_type != OBJ_DDS)) { return (ERR_INVALID_MGMT_REQUEST); } /* prepare lookup ctrl data for looking for the node object */ SET_UID_LCP(&lc, lc_type, 0); root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } while (i < req->count) { /* id is checked to be not NULL before calling this routine. */ lc.data[0].ui = *(req->req_data.attrlist[i]->id); /* get the dd_id/dds_id */ (void) cache_lock_write(); if ((container_id = is_obj_there(&lc)) != 0) { name = (uchar_t *)req->req_data.attrlist[i]->name; /* the length of the name need to include the */ /* null terminator and be on 4 bytes aligned */ len = xmlStrlen(name) + 1; len += 4 - (len % 4); /* rename the dd/dds */ ret = (lc_type == OBJ_DD) ? update_dd_name(container_id, len, name) : update_dds_name(container_id, len, name); /* release the lock and sync the data */ ret = cache_unlock_sync(ret); } else { /* release the lock and no need to sync */ (void) cache_unlock_nosync(); ret = (lc_type == OBJ_DD) ? ERR_MATCHING_DD_NOT_FOUND : ERR_MATCHING_DDSET_NOT_FOUND; } if (ret != 0) { /* keep track if there are different errors encountered. */ if (ret_save != 0 && ret != ret_save) { different_err++; } ret_save = ret; err_count++; n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { if ((n_obj = xmlAddChild(root, n_obj)) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = (lc_type == OBJ_DD) ? xmlNewNode(NULL, (xmlChar *)DDOBJECT) : xmlNewNode(NULL, (xmlChar *)DDSETOBJECT); if (n_node) { if ((n_node = xmlAddChild(n_obj, n_node)) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } else { if (xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)req->req_data.attrlist[i]->name) == NULL) { return (ERR_XML_SETPROP_FAILED); } } } else { return (ERR_XML_NEWNODE_FAILED); } } i++; } return (handle_partial_failure(doc, ret_save, (req->count == err_count && !different_err) ? B_TRUE : B_FALSE)); } /* * **************************************************************************** * * update_dd_ddset_op: * removes a list of dd memeber or dd seti member. * * req - contains delete request info. * doc - response doc to fill up * type - object type(either dd or dd set) * * **************************************************************************** */ static int update_dd_ddset_op( request_t *req, xmlDocPtr doc, object_type type /* any additional arguments go here */ ) { result_code_t ret = 0, ret_save = 0; isns_type_t lc_type; int i = 0, err_count = 0; lookup_ctrl_t lc; uint32_t container_id; xmlNodePtr n_node, n_obj, root; int different_err = 0; lc_type = get_lc_type(type); if ((lc_type != OBJ_DD) && (lc_type != OBJ_DDS)) { return (ERR_INVALID_MGMT_REQUEST); } /* prepare lookup ctrl data for looking for the node object */ lc.curr_uid = 0; lc.type = lc_type; lc.id[0] = get_lc_id(req->op_info.obj); lc.op[0] = OP_STRING; lc.op[1] = 0; root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } while (i < req->count) { lc.data[0].ptr = req->req_data.attrlist[i]->name; /* lock the cache for writing */ (void) cache_lock_write(); if ((container_id = is_obj_there(&lc)) != 0) { ret = (lc_type == OBJ_DD) ? /* enabled is checked to be not NULL before calling. */ update_dd_features(container_id, *(req->req_data.attrlist[i]->enabled) ? 1 : 0): update_dds_status(container_id, *(req->req_data.attrlist[i]->enabled) ? 1 : 0); /* unlock the cache and sync the data */ ret = cache_unlock_sync(ret); } else { (void) cache_unlock_nosync(); ret = (lc_type == OBJ_DD) ? ERR_MATCHING_DD_NOT_FOUND : ERR_MATCHING_DDSET_NOT_FOUND; } if (ret != 0) { /* keep track if there are different errors encountered. */ if (ret_save != 0 && ret != ret_save) { different_err++; } ret_save = ret; err_count++; n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { if ((n_obj = xmlAddChild(root, n_obj)) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_NEWNODE_FAILED); } n_node = (lc_type == OBJ_DD) ? xmlNewNode(NULL, (xmlChar *)DDOBJECT) : xmlNewNode(NULL, (xmlChar *)DDSETOBJECT); if (n_node) { if ((n_node = xmlAddChild(n_obj, n_node)) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } else { if (xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)req->req_data.attrlist[i]->name) == NULL) { return (ERR_XML_SETPROP_FAILED); } } } else { return (ERR_XML_NEWNODE_FAILED); } } i++; } return (handle_partial_failure(doc, ret_save, (req->count == err_count && !different_err) ? B_TRUE : B_FALSE)); } /* * **************************************************************************** * * createModify_dd_ddset_op: * removes a list of dd memeber or dd seti member. * * req - contains delete request info. * doc - response doc to fill up * * **************************************************************************** */ static int create_dd_ddset_op( request_t *req, xmlDocPtr doc, object_type type /* any additional arguments go here */ ) { isns_obj_t *obj; result_code_t ret = 0, ret_save = 0; isns_type_t lc_type; lookup_ctrl_t lc; uint32_t uid; int i = 0, err_count = 0; xmlNodePtr n_obj, n_node, root; int different_err = 0; lc_type = get_lc_type(type); if ((lc_type != OBJ_DD) && (lc_type != OBJ_DDS)) { return (ERR_INVALID_MGMT_REQUEST); } root = xmlDocGetRootElement(doc); if (root == NULL) { return (ERR_SYNTAX_MISSING_ROOT); } lc_type = get_lc_type(type); if ((lc_type != OBJ_DD) && (lc_type != OBJ_DDS)) { return (ERR_INVALID_MGMT_REQUEST); } /* prepare lookup ctrl data for looking for the node object */ lc.curr_uid = 0; lc.type = lc_type; lc.id[0] = get_lc_id(req->op_info.obj); lc.op[0] = OP_STRING; lc.op[1] = 0; lc.data[1].ptr = (uchar_t *)doc; /* xml writer descriptor */ while (i < req->count) { lc.data[0].ptr = req->req_data.attrlist[i]->name, /* grab the write lock */ (void) cache_lock_write(); uid = is_obj_there(&lc); if (uid == 0) { ret = (lc_type == OBJ_DD) ? adm_create_dd(&obj, req->req_data.attrlist[i]->name, 0, 0) : adm_create_dds(&obj, req->req_data.attrlist[i]->name, 0, 0); if (ret == 0) { ret = register_object(obj, NULL, NULL); if (ret != 0) { free_object(obj); } /* release the lock and sync the cache and data store */ ret = cache_unlock_sync(ret); } } else { /* release the lock and no need to sync the data */ (void) cache_unlock_nosync(); ret = ERR_NAME_IN_USE; } if (ret != 0) { /* keep track if there are different errors encountered. */ if (ret_save != 0 && ret != ret_save) { different_err++; } ret_save = ret; err_count++; n_obj = xmlNewNode(NULL, (xmlChar *)ISNSOBJECT); if (n_obj) { if ((n_obj = xmlAddChild(root, n_obj)) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } } else { return (ERR_XML_ADDCHILD_FAILED); } n_node = (lc_type == OBJ_DD) ? xmlNewNode(NULL, (xmlChar *)DDOBJECT) : xmlNewNode(NULL, (xmlChar *)DDSETOBJECT); if (n_node) { if ((n_node = xmlAddChild(n_obj, n_node)) == NULL) { return (ERR_XML_ADDCHILD_FAILED); } else { if (xmlSetProp(n_node, (xmlChar *)NAMEATTR, (xmlChar *)req->req_data.attrlist[i]->name) == NULL) { return (ERR_XML_SETPROP_FAILED); } } } else { return (ERR_XML_NEWNODE_FAILED); } } i++; } return (handle_partial_failure(doc, ret_save, (req->count == err_count && !different_err) ? B_TRUE : B_FALSE)); } /* * **************************************************************************** * * createModify_dd_ddset_op: * removes a list of dd memeber or dd seti member. * * req - contains delete request info. * doc - response doc to fill up * * **************************************************************************** */ int createModify_dd_ddset_op( request_t *req, xmlDocPtr doc /* any additional arguments go here */ ) { result_code_t ret = 0; if (req->req_data.attrlist[0]->id != NULL) { ret = rename_dd_ddset_op(req, doc, req->op_info.obj); } else if (req->req_data.attrlist[0]->enabled != NULL) { ret = update_dd_ddset_op(req, doc, req->op_info.obj); } else { ret = create_dd_ddset_op(req, doc, req->op_info.obj); } return (ret); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_ADMINTF_H #define _ISNS_ADMINTF_H #include #include #include #ifdef __cplusplus extern "C" { #endif int get_serverconfig_op(xmlDocPtr); int get_node_op(request_t *, xmlDocPtr); int get_dd_op(request_t *, xmlDocPtr); int get_ddset_op(request_t *, xmlDocPtr); int enumerate_node_op(xmlDocPtr); int enumerate_dd_op(xmlDocPtr); int enumerate_ddset_op(xmlDocPtr); int getAssociated_dd_to_node_op(request_t *, xmlDocPtr); int getAssociated_node_to_dd_op(request_t *, xmlDocPtr); int getAssociated_dd_to_ddset_op(request_t *, xmlDocPtr); int getAssociated_ddset_to_dd_op(request_t *, xmlDocPtr); int delete_dd_ddset_op(request_t *, xmlDocPtr, object_type); int delete_ddmember_ddsetmember_op(request_t *, xmlDocPtr, object_type); int createModify_dd_ddset_op(request_t *, xmlDocPtr); int create_ddmember_ddsetmember_op(request_t *, xmlDocPtr, object_type); #ifdef __cplusplus } #endif #endif /* _ISNS_ADMINTF_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include "isns_server.h" #include "isns_cache.h" #include "isns_msgq.h" #include "isns_obj.h" #include "isns_htab.h" /* * external variables */ extern msg_queue_t *sys_q; #ifdef DEBUG extern int verbose_lock; #endif /* * global data */ int cache_flag = 0; /* * local variables */ static cache_t *imc; /* * local functions. */ /* * **************************************************************************** * cache_init: * create the cache data initially, including to invoke individual * functions for creating the hash tables for object storage and * discovery domain membership matrix. * * return - 0: no error; 1: otherwise. * * **************************************************************************** */ int cache_init(void) { /* * allocate global cache memory. */ imc = (cache_t *)calloc(sizeof (cache_t), 1); if (imc == NULL || obj_tab_init(imc) != 0 || dd_matrix_init(imc) != 0) { cache_destroy(); return (1); /* no memory */ } /* * initialize global cache rwlock. */ (void) rwlock_init(&imc->l, USYNC_PROCESS, NULL); /* * inintialize global cache functions. */ imc->get_hval = obj_hval; imc->get_uid = get_obj_uid; imc->set_uid = set_obj_uid; imc->timestamp = get_timestamp; imc->add_hook = add_object; imc->replace_hook = replace_object; imc->cmp = obj_cmp; imc->clone = assoc_clone; imc->ddd = update_ddd; #ifdef DEBUG imc->dump = obj_dump; #endif return (0); } /* * **************************************************************************** * cache_destroy: * destroy the cache data. * * **************************************************************************** */ void cache_destroy(void) { /* do nothing */ } /* * **************************************************************************** * cache_lock: * grab the lock on the cache data. * * mode - the read/write mode of the lock. * return - error code. * * **************************************************************************** */ int cache_lock(int mode) { int ret = 0; switch (mode) { case CACHE_WRITE: ret = rw_wrlock(&imc->l); #ifdef DEBUG if (verbose_lock) { printf("cache locked for writing.\n"); } #endif break; case CACHE_READ: ret = rw_rdlock(&imc->l); #ifdef DEBUG if (verbose_lock) { printf("cache locked for reading.\n"); } #endif break; case CACHE_TRY_READ: ret = rw_tryrdlock(&imc->l); #ifdef DEBUG if (verbose_lock) { if (ret == 0) { printf("cache locked for reading.\n"); } else { printf("cache locked for reading failed.\n"); } } #endif break; default: break; } return (ret); } /* * **************************************************************************** * cache_unlock: * release the lock on the cache data. * if the cache was locked for writing, a synchronization between * the cache and persistent data store needs to be performed. * * mode - the read/write mode which the cache data was locked for. * ec - 0: commit the cache update; otherwise retreat it. * return - error code. * * **************************************************************************** */ int cache_unlock(int mode, int ec) { if (mode != CACHE_NO_ACTION) { /* sync between cache and data store */ if (mode == CACHE_WRITE) { if (sys_q) { ec = data_sync(ec); } /* rest the cache update flag */ RESET_CACHE_UPDATED(); } ASSERT(!IS_CACHE_UPDATED()); /* unlock it */ (void) rw_unlock(&imc->l); #ifdef DEBUG if (verbose_lock) { printf("cache unlocked.\n"); } #endif } return (ec); } /* * **************************************************************************** * cache_lock_read: * grab the read lock on the cache. * * return - error code. * * **************************************************************************** */ int cache_lock_read(void) { return (cache_lock(CACHE_READ)); } /* * **************************************************************************** * cache_lock_write: * grab the write lock on the cache. * * return - error code. * * **************************************************************************** */ int cache_lock_write(void) { return (cache_lock(CACHE_WRITE)); } /* * **************************************************************************** * cache_unlock_sync: * synchronize the cache with persistent data store and * release the lock. * * ec - 0: commit the cache update; otherwise retreat it. * return - error code. * * **************************************************************************** */ int cache_unlock_sync(int ec) { return (cache_unlock(CACHE_WRITE, ec)); } /* * **************************************************************************** * cache_unlock_nosync: * release the lock, no need to sync the data between cache and * data store. * if the cache has been updated, do not call this function, call * cache_unlock_sync() with non-zero error code to indicate the * sync action. * * return - error code. * * **************************************************************************** */ int cache_unlock_nosync(void) { return (cache_unlock(CACHE_READ, 0)); } /* * **************************************************************************** * cache_get_htab: * get the hash table for individual type of object. * * type - the object type. * return - the hash table. * * **************************************************************************** */ htab_t * cache_get_htab(isns_type_t type) { if (type > 0 && type < MAX_OBJ_TYPE) { return (imc->t[type]); } return (NULL); } /* * **************************************************************************** * cache_get_matrix: * get the membership matrix for a discovery domain or a * discovery domain set. * * type - the discovery domain or discovery domain set object type. * return - the matrix. * * **************************************************************************** */ matrix_t * cache_get_matrix(isns_type_t type) { matrix_t *x = NULL; switch (type) { case OBJ_DD: x = imc->x[0]; break; case OBJ_DDS: x = imc->x[1]; break; default: break; } return (x); } /* * **************************************************************************** * cache_lookup: * invoke the hash table lookup for looking up a specific object and * perform the callback function on the object. * * lcp - the object lookup control data. * uid_p - the pointer of object UID for returning. * callback - the callback function for the object. * return - error code. * * **************************************************************************** */ int cache_lookup(lookup_ctrl_t *lcp, uint32_t *uid_p, int (*callback)(void *, void *)) { return (htab_lookup(imc->t[lcp->type], lcp, (lcp->op[0] == OP_INTEGER) ? lcp->data[0].ui : 0, uid_p, callback, 0)); } /* * **************************************************************************** * cache_lookup: * invoke the hash table lookup for looking up a specific object, * the callback function is going to change the key of the object. * * lcp - the object lookup control data. * uid_p - the pointer of object UID for returning. * callback - the callback function for the object. * return - error code. * * **************************************************************************** */ int cache_rekey(lookup_ctrl_t *lcp, uint32_t *uid_p, int (*callback)(void *, void *)) { return (htab_lookup(imc->t[lcp->type], lcp, (lcp->op[0] == OP_INTEGER) ? lcp->data[0].ui : 0, uid_p, callback, 1)); } /* * **************************************************************************** * cache_add: * invoke hash table add to add an object. * * obj - the object being added. * flag - 0: a real object; * otherwise an association object for discovery domain membership. * uid_p - the pointer of object UID for returning. * update_p - the pointer of flag (update object or newly register) * for returning. * return - error code. * * **************************************************************************** */ int cache_add(isns_obj_t *obj, int flag, uint32_t *uid_p, int *update_p) { return (htab_add(imc->t[obj->type], obj, flag, uid_p, update_p)); } /* * **************************************************************************** * cache_remove: * invoke hash table remove to remove an object. * * lcp - the lookup control data for the object being removed. * flag - 0: a real object; * otherwise an association object for discovery domain membership. * return - the removed object. * * **************************************************************************** */ isns_obj_t * cache_remove(lookup_ctrl_t *lcp, int flag) { return (htab_remove(imc->t[lcp->type], lcp, (lcp->op[0] == OP_INTEGER) ? lcp->data[0].ui : 0, flag)); } /* * **************************************************************************** * cache_dump_htab: * dump the hash table for debugging purpose. * * type - the object type. * * **************************************************************************** */ #ifdef DEBUG void cache_dump_htab(isns_type_t type) { (void) htab_dump(imc->t[type]); } #endif /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include "isns_server.h" #include "isns_log.h" #include "isns_cfg.h" /* * external variables */ extern uint64_t esi_threshold; extern uint8_t mgmt_scn; extern ctrl_node_t *control_nodes; extern pthread_mutex_t ctrl_node_mtx; extern char data_store[MAXPATHLEN]; #define DEFAULT_ESI_THRESHOLD 3 #define MAX_ESI_THRESHOLD 10 /* * load_config loads config data through SMF. * arg DATA_STORE_UPDATE indicates whether the data store location * can be updated or not. */ int load_config(boolean_t DATA_STORE_UPDATE) { int retval = -1; scf_handle_t *handle = NULL; scf_scope_t *sc = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; scf_iter_t *value_iter = NULL; ctrl_node_t *ctrl_node_p; char scf_name[MAXNAMELEN]; char *name; /* connect to the current SMF global repository */ handle = scf_handle_create(SCF_VERSION); /* allocate scf resources */ sc = scf_scope_create(handle); svc = scf_service_create(handle); pg = scf_pg_create(handle); prop = scf_property_create(handle); value = scf_value_create(handle); value_iter = scf_iter_create(handle); /* if failed to allocate resources, exit */ if (handle == NULL || sc == NULL || svc == NULL || pg == NULL || prop == NULL || value == NULL || value_iter == NULL) { isnslog(LOG_DEBUG, "load_config", "scf handles allocation failed."); goto out; } /* bind scf handle to the running svc.configd daemon */ if (scf_handle_bind(handle) == -1) { isnslog(LOG_DEBUG, "load_config", "scf binding failed."); goto out; } /* get the scope of the localhost in the current repository */ if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, sc) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting scf scope failed."); goto out; } /* get the service "network/isns_server" within the scope */ if (scf_scope_get_service(sc, ISNS_SERVER_SVC_NAME, svc) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting %s service failed.", ISNS_SERVER_SVC_NAME); goto out; } /* get the property group "config" within the given service */ if (scf_service_get_pg(svc, ISNS_SERVER_CONFIG, pg) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property group %s failed.", ISNS_SERVER_CONFIG); goto out; } /* * Now get the properties. */ if (scf_pg_get_property(pg, CONFIG_ESI_THRESHOLD, prop) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property %s failed", CONFIG_ESI_THRESHOLD); goto out; } if (scf_property_get_value(prop, value) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property value for %s failed.", CONFIG_ESI_THRESHOLD); goto out; } if (scf_value_get_count(value, &esi_threshold) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property integer value for %s failed.", CONFIG_ESI_THRESHOLD); goto out; } /* the range of ESI Threshold is [1, 10] */ if (esi_threshold < 1) { esi_threshold = DEFAULT_ESI_THRESHOLD; /* 3 */ } else if (esi_threshold > MAX_ESI_THRESHOLD) { esi_threshold = MAX_ESI_THRESHOLD; /* 10 */ } isnslog(LOG_DEBUG, "load_config", "%s set to %d", CONFIG_ESI_THRESHOLD, esi_threshold); if (scf_pg_get_property(pg, CONFIG_MGMT_SCN, prop) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting scf property %s failed.", CONFIG_MGMT_SCN); goto out; } if (scf_property_get_value(prop, value) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property value for %s failed.", CONFIG_MGMT_SCN); goto out; } if (scf_value_get_boolean(value, &mgmt_scn) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting boolean value for property %s failed", CONFIG_MGMT_SCN); goto out; } isnslog(LOG_DEBUG, "load_config", "%s set to %s", CONFIG_MGMT_SCN, mgmt_scn ? "true" : "false"); if (DATA_STORE_UPDATE) { if (scf_pg_get_property(pg, CONFIG_DATA_STORE, prop) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property %s failed", CONFIG_DATA_STORE); goto out; } if (scf_property_get_value(prop, value) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property value for %s failed", CONFIG_DATA_STORE); goto out; } data_store[0] = 0; if (scf_value_get_astring(value, data_store, MAXPATHLEN) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property string value for %s failed", CONFIG_DATA_STORE); goto out; } isnslog(LOG_DEBUG, "load_config", "%s set to %s", CONFIG_DATA_STORE, data_store); } if (scf_pg_get_property(pg, CONFIG_CONTROL_NODES, prop) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property %s failed", CONFIG_CONTROL_NODES); goto out; } if (scf_iter_property_values(value_iter, prop) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting iteration property %s failed", CONFIG_CONTROL_NODES); goto out; } /* remove any old control node first. */ (void) pthread_mutex_lock(&ctrl_node_mtx); while (control_nodes != NULL) { ctrl_node_p = control_nodes->next; free(control_nodes->name); free(control_nodes); control_nodes = ctrl_node_p; } while (scf_iter_next_value(value_iter, value) != 0) { if (scf_value_get_ustring(value, scf_name, MAXNAMELEN) == -1) { isnslog(LOG_DEBUG, "load_config", "Getting property string value for %s failed", CONFIG_CONTROL_NODES); (void) pthread_mutex_unlock(&ctrl_node_mtx); goto out; } ctrl_node_p = (ctrl_node_t *)malloc(sizeof (ctrl_node_t)); if (ctrl_node_p == NULL) { isnslog(LOG_DEBUG, "load_config", "malloc() failed."); (void) pthread_mutex_unlock(&ctrl_node_mtx); goto out; } if (strlen(scf_name) != 0) { name = (char *)malloc(strlen(scf_name) + 1); if (name == NULL) { free(ctrl_node_p); isnslog(LOG_DEBUG, "load_config", "malloc() failed."); (void) pthread_mutex_unlock(&ctrl_node_mtx); goto out; } else { (void) strcpy(name, scf_name); ctrl_node_p->name = (uchar_t *)name; ctrl_node_p->next = control_nodes; control_nodes = ctrl_node_p; } isnslog(LOG_DEBUG, "load_config", "%s set to %s", CONFIG_CONTROL_NODES, scf_name); } else { free(ctrl_node_p); } } (void) pthread_mutex_unlock(&ctrl_node_mtx); isnslog(LOG_DEBUG, "load_config", "loading server settings ok."); retval = 0; /* ok */ out: /* destroy scf pointers */ if (value != NULL) { scf_value_destroy(value); } if (value_iter != NULL) { scf_iter_destroy(value_iter); } if (prop != NULL) { scf_property_destroy(prop); } if (pg != NULL) { scf_pg_destroy(pg); } if (svc != NULL) { scf_service_destroy(svc); } if (sc != NULL) { scf_scope_destroy(sc); } if (handle != NULL) { scf_handle_destroy(handle); } return (retval); } /* * is_control_node checks the given name to see if it is a control node. */ int is_control_node( uchar_t *name ) { ctrl_node_t *p; (void) pthread_mutex_lock(&ctrl_node_mtx); p = control_nodes; while (p != NULL) { if (strcmp((char *)p->name, (char *)name) == 0) { (void) pthread_mutex_unlock(&ctrl_node_mtx); return (1); } p = p->next; } (void) pthread_mutex_unlock(&ctrl_node_mtx); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include "isns_server.h" #include "isns_msgq.h" #include "isns_htab.h" #include "isns_dd.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_pdu.h" #include "isns_dseng.h" #include "isns_scn.h" #include "isns_utils.h" /* * extern global variables */ extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; extern msg_queue_t *sys_q; extern msg_queue_t *scn_q; extern int cache_flag; /* * extern functions. */ /* * global variables */ /* * local variables */ /* * local functions. */ static matrix_t *new_matrix(uint32_t, uint32_t); static int cb_update_ds_attr( void *p1, void *p2 ) { int ec = 0; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; uint32_t tag = lcp->id[1]; uint32_t which; isns_attr_t *attr; uint32_t len; uchar_t *name; lookup_ctrl_t lc; uint32_t uid; switch (tag) { case ISNS_DD_NAME_ATTR_ID: which = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); break; case ISNS_DD_FEATURES_ATTR_ID: which = ATTR_INDEX_DD(ISNS_DD_FEATURES_ATTR_ID); break; case ISNS_DD_SET_NAME_ATTR_ID: which = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID); break; case ISNS_DD_SET_STATUS_ATTR_ID: which = ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID); break; default: ASSERT(0); break; } attr = &obj->attrs[which]; switch (tag) { case ISNS_DD_NAME_ATTR_ID: case ISNS_DD_SET_NAME_ATTR_ID: len = lcp->data[1].ui; name = lcp->data[2].ptr; lc.type = lcp->type; lc.curr_uid = 0; lc.id[0] = which; lc.op[0] = OP_STRING; lc.data[0].ptr = name; lc.op[1] = 0; /* check if the name is in use */ uid = is_obj_there(&lc); if (uid != 0) { if (uid != get_obj_uid(obj)) { ec = ERR_NAME_IN_USE; } return (ec); } if (len > attr->len) { uchar_t *tmp = (uchar_t *)malloc(len); if (tmp != NULL) { free(attr->value.ptr); attr->value.ptr = tmp; } else { /* memory exhausted */ return (ISNS_RSP_INTERNAL_ERROR); } } (void) strcpy((char *)attr->value.ptr, (char *)name); attr->len = len; break; case ISNS_DD_FEATURES_ATTR_ID: case ISNS_DD_SET_STATUS_ATTR_ID: if (attr->tag != tag || attr->value.ui != lcp->data[1].ui) { attr->tag = tag; attr->len = 4; attr->value.ui = lcp->data[1].ui; } else { return (ec); } break; } /* cache has been updated, set the flag */ SET_CACHE_UPDATED(); /* update data store */ if (sys_q != NULL) { ec = write_data(DATA_UPDATE, obj); } return (ec); } static isns_obj_t * make_member_node( const uint32_t uid, isns_attr_t *attr1 ) { isns_obj_t *obj = NULL; isns_attr_t *attr; isns_attr_t tmp; switch (attr1->tag) { case ISNS_DD_ISCSI_NAME_ATTR_ID: obj = obj_calloc(OBJ_ISCSI); attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)]; tmp.tag = ISNS_ISCSI_NAME_ATTR_ID; tmp.len = attr1->len; tmp.value.ptr = attr1->value.ptr; if (assign_attr(attr, &tmp) != 0) { free_object(obj); obj = NULL; } else if (uid != 0) { (void) set_obj_uid(obj, uid); } break; default: ASSERT(0); break; } return (obj); } static isns_obj_t * make_member_dd( const uint32_t uid ) { isns_obj_t *obj = NULL; isns_attr_t name = { 0 }; obj = obj_calloc(OBJ_DD); if (obj != NULL) { (void) set_obj_uid(obj, uid); name.tag = ISNS_DD_NAME_ATTR_ID; if (assign_attr( &obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)], &name) != 0) { free_object(obj); obj = NULL; } } return (obj); } static int get_member_info( isns_obj_t *assoc, uint32_t *m_type, uint32_t *m_id, int flag ) { int ec = 0; lookup_ctrl_t lc = { 0 }; isns_obj_t *obj; isns_attr_t *attr1, *attr2; uint32_t tmp_id = 0; int i = 0; *m_type = 0; *m_id = 0; attr1 = &assoc->attrs[ATTR_INDEX_ASSOC_ISCSI( ISNS_DD_ISCSI_INDEX_ATTR_ID)]; attr2 = &assoc->attrs[ATTR_INDEX_ASSOC_ISCSI( ISNS_DD_ISCSI_NAME_ATTR_ID)]; lc.type = OBJ_ISCSI; if (attr1->tag != 0 && attr1->value.ui != 0) { *m_id = attr1->value.ui; lc.id[i] = UID_ATTR_INDEX[OBJ_ISCSI]; lc.op[i] = OP_INTEGER; lc.data[i].ui = *m_id; i ++; } if (attr2->tag != 0) { lc.id[i] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); lc.op[i] = OP_STRING; lc.data[i].ptr = attr2->value.ptr; i ++; } else if (scn_q != NULL || sys_q != NULL) { lc.id[i] = ISNS_ISCSI_NAME_ATTR_ID; } /* a member id or member name is required */ if (i == 0) { if (flag != 0) { /* add member */ return (ISNS_RSP_INVALID_REGIS); } else { /* remove member (isnsp msg request only) */ return (0); } } ec = cache_lookup(&lc, &tmp_id, cb_clone_attrs); if (ec == 0 && tmp_id == 0) { if (flag != 0) { /* add member */ if (attr1->tag == 0 || sys_q == NULL) { /* object does not exist, create one */ obj = make_member_node(*m_id, attr2); if (obj == NULL) { ec = ISNS_RSP_INTERNAL_ERROR; } else { ec = register_assoc(obj, &tmp_id); if (ec != 0) { free_object(obj); } } } else { /* don't create it if uid is specified */ ec = ISNS_RSP_NO_SUCH_ENTRY; } } else { /* remove member */ ec = ERR_NO_SUCH_ASSOCIATION; } } if (attr1->tag == 0) { attr1->tag = ISNS_DD_ISCSI_INDEX_ATTR_ID; attr1->len = 4; attr1->value.ui = tmp_id; } else if (attr2->tag == 0) { attr2->tag = ISNS_DD_ISCSI_NAME_ATTR_ID; attr2->len = strlen((char *)lc.data[1].ptr); attr2->len += 4 - (attr2->len % 4); attr2->value.ptr = lc.data[1].ptr; } *m_type = OBJ_ISCSI; *m_id = tmp_id; return (ec); } static int get_dds_member_info( uint32_t m_id ) { int ec = 0; lookup_ctrl_t lc; isns_obj_t *obj; uint32_t tmp_id; if (m_id != 0) { SET_UID_LCP(&lc, OBJ_DD, m_id); } else { return (ISNS_RSP_INVALID_REGIS); } tmp_id = is_obj_there(&lc); if (tmp_id == 0) { /* object does not exist, create one */ obj = make_member_dd(m_id); if (obj != NULL) { ec = register_object(obj, NULL, NULL); } else { /* no memory */ ec = ISNS_RSP_INTERNAL_ERROR; } } return (ec); } static int update_matrix( matrix_t *matrix, const uchar_t op, const uint32_t puid, const uint32_t m_id, int ddd_flag ) { int ec = 0; uint32_t new_x = 0, new_y = 0; matrix_t *tmp_matrix; uint32_t i, j, k = 0; uint32_t x_info; bmp_t *bmp, *tmp_bmp; uint32_t primary = GET_PRIMARY(m_id); uint32_t second = GET_SECOND(m_id); if (primary >= matrix->x) { if (op == '-') { ec = ERR_NO_SUCH_ASSOCIATION; goto update_matrix_done; } /* enlarge the matrix on x axis */ if (primary >= matrix->x * 2) { new_x = primary + 1; } else { new_x = matrix->x * 2; } } i = 0; while (i < matrix->y) { bmp = MATRIX_X_UNIT(matrix, i); x_info = MATRIX_X_INFO(bmp); if (x_info == puid) { break; } else if (x_info == 0 && k == 0) { /* the first available slot */ k = i; } i ++; } if (i == matrix->y) { if (op == '-') { ec = ERR_NO_SUCH_ASSOCIATION; goto update_matrix_done; } else if (k == 0) { new_y = matrix->y * 2; } else { i = k; } } /* * enlarge the matrix. */ if (new_x != 0 || new_y != 0) { if (new_x == 0) { new_x = matrix->x; } if (new_y == 0) { new_y = matrix->y; } tmp_matrix = new_matrix(new_x, new_y); if (tmp_matrix != NULL) { j = 0; while (j < matrix->y) { bmp = MATRIX_X_UNIT(matrix, j); x_info = MATRIX_X_INFO(bmp); if (x_info != 0) { tmp_bmp = MATRIX_X_UNIT(tmp_matrix, j); (void) memcpy((void *)tmp_bmp, (void *)bmp, SIZEOF_X_UNIT(matrix)); } j ++; } free(matrix->m); matrix->x = tmp_matrix->x; matrix->y = tmp_matrix->y; matrix->m = tmp_matrix->m; free(tmp_matrix); } else { ec = ISNS_RSP_INTERNAL_ERROR; goto update_matrix_done; } } bmp = MATRIX_X_UNIT(matrix, i); MATRIX_X_INFO(bmp) = puid; if (op == '+') { if (TEST_MEMBERSHIP(bmp, primary, second) == 0) { SET_MEMBERSHIP(bmp, primary, second); SET_CACHE_UPDATED(); if (ddd_flag != 0) { bmp = MATRIX_X_UNIT(matrix, 0); ASSERT(MATRIX_X_INFO(bmp) == ISNS_DEFAULT_DD_ID); CLEAR_MEMBERSHIP(bmp, primary, second); } } else { ec = ERR_ALREADY_ASSOCIATED; } } else if (op == '-') { if (TEST_MEMBERSHIP(bmp, primary, second) != 0) { CLEAR_MEMBERSHIP(bmp, primary, second); SET_CACHE_UPDATED(); if (ddd_flag != 0) { i = 1; while (i < matrix->y) { bmp = MATRIX_X_UNIT(matrix, i); x_info = MATRIX_X_INFO(bmp); if (x_info != 0 && TEST_MEMBERSHIP(bmp, primary, second) != 0) { break; } i ++; } if (i == matrix->y) { bmp = MATRIX_X_UNIT(matrix, 0); ASSERT(MATRIX_X_INFO(bmp) == ISNS_DEFAULT_DD_ID); SET_MEMBERSHIP(bmp, primary, second); } } } else { ec = ERR_NO_SUCH_ASSOCIATION; } } update_matrix_done: return (ec); } /*ARGSUSED*/ static int update_dd_matrix( const uchar_t op, const uint32_t dd_id, const uint32_t m_type, const uint32_t m_id ) { matrix_t *matrix; ASSERT(m_type == OBJ_ISCSI); matrix = cache_get_matrix(OBJ_DD); return (update_matrix(matrix, op, dd_id, m_id, 1)); } static int update_dds_matrix( const uchar_t op, const uint32_t dds_id, const uint32_t m_id ) { matrix_t *dds_matrix = cache_get_matrix(OBJ_DDS); return (update_matrix(dds_matrix, op, dds_id, m_id, 0)); } static int clear_matrix( matrix_t *matrix, const uint32_t uid, bmp_t **p, uint32_t *n, int ddd_flag ) { int ec = 0; bmp_t *bmp; uint32_t x_info; int i, j; uint32_t primary; uint32_t second; if (p != NULL) { *p = NULL; *n = 0; } i = 0; while (i < matrix->y) { bmp = MATRIX_X_UNIT(matrix, i); x_info = MATRIX_X_INFO(bmp); if (x_info == uid) { if (p != NULL) { /* dup it for caller */ *n = matrix->x; *p = (bmp_t *)malloc(*n * sizeof (bmp_t)); if (*p != NULL) { (void) memcpy(*p, &bmp[MATRIX_X_HEADER], *n * sizeof (bmp_t)); } else { ec = ISNS_RSP_INTERNAL_ERROR; } } /* clean it */ (void) memset(bmp, 0, SIZEOF_X_UNIT(matrix)); break; } i ++; } if (ddd_flag != 0 && p != NULL) { bmp = MATRIX_X_UNIT(matrix, 0); ASSERT(MATRIX_X_INFO(bmp) == ISNS_DEFAULT_DD_ID); /* Test the membership for each node which is a */ /* member in the dd that is being deleted. */ FOR_EACH_MEMBER(*p, *n, i, { j = get_dd_id(i, 0); if (j == 0) { /* put it to the default dd */ primary = GET_PRIMARY(i); second = GET_SECOND(i); SET_MEMBERSHIP(bmp, primary, second); } }); } return (ec); } static int get_matrix( matrix_t *matrix, const uint32_t uid, bmp_t **p, uint32_t *n ) { int ec = 0; bmp_t *bmp; uint32_t x_info; int i; *n = 0; *p = NULL; i = 0; while (i < matrix->y) { bmp = MATRIX_X_UNIT(matrix, i); x_info = MATRIX_X_INFO(bmp); if (x_info == uid) { /* dup it for caller */ *n = matrix->x; *p = (bmp_t *)malloc(*n * sizeof (bmp_t)); if (*p != NULL) { (void) memcpy(*p, &bmp[MATRIX_X_HEADER], *n * sizeof (bmp_t)); } else { *n = 0; ec = ISNS_RSP_INTERNAL_ERROR; } break; } i ++; } return (ec); } static int clear_dd_matrix( const uint32_t dd_id, bmp_t **p, uint32_t *n ) { matrix_t *matrix = cache_get_matrix(OBJ_DD); return (clear_matrix(matrix, dd_id, p, n, 1)); } static int clear_dds_matrix( const uint32_t dds_id ) { matrix_t *matrix = cache_get_matrix(OBJ_DDS); return (clear_matrix(matrix, dds_id, NULL, NULL, 0)); } int get_dd_matrix( const uint32_t dd_id, bmp_t **p, uint32_t *n ) { matrix_t *matrix = cache_get_matrix(OBJ_DD); return (get_matrix(matrix, dd_id, p, n)); } int get_dds_matrix( const uint32_t dds_id, bmp_t **p, uint32_t *n ) { matrix_t *matrix = cache_get_matrix(OBJ_DDS); return (get_matrix(matrix, dds_id, p, n)); } /*ARGSUSED*/ static int cb_get_dds_status( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; isns_attr_t *attr = &obj->attrs[ ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID)]; return (DDS_ENABLED(attr->value.ui) ? 1 : 0); } static int get_dds_status( uint32_t dds_id ) { lookup_ctrl_t lc; if (dds_id == 0) { return (0); } SET_UID_LCP(&lc, OBJ_DDS, dds_id); return (cache_lookup(&lc, NULL, cb_get_dds_status)); } int is_dd_active( uint32_t dd_id ) { int active = 0; matrix_t *dds_matrix; uint32_t primary; uint32_t second; uint32_t x_info; bmp_t *bmp; int i; if (dd_id == 0) { return (active); } dds_matrix = cache_get_matrix(OBJ_DDS); primary = GET_PRIMARY(dd_id); second = GET_SECOND(dd_id); if (primary < dds_matrix->x) { i = 0; while (i < dds_matrix->y) { bmp = MATRIX_X_UNIT(dds_matrix, i); x_info = MATRIX_X_INFO(bmp); if (x_info != 0 && TEST_MEMBERSHIP(bmp, primary, second) != 0) { if (get_dds_status(x_info) != 0) { active = 1; break; } } i ++; } } return (active); } int get_scope( uchar_t *node_name, bmp_t **p, uint32_t *n ) { int ec = 0; lookup_ctrl_t lc; uint32_t uid; matrix_t *dd_matrix; uint32_t primary; uint32_t second; uint32_t x_info; bmp_t *bmp; int i, j; bmp_t *tmp_p; uint32_t tmp_n; bmp_t *short_p; uint32_t short_n; /* clear it */ *p = NULL; *n = 0; /* get the source object uid */ 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 = node_name; lc.op[1] = 0; uid = is_obj_there(&lc); /* no such object */ if (uid == 0) { return (ec); } dd_matrix = cache_get_matrix(OBJ_DD); primary = GET_PRIMARY(uid); second = GET_SECOND(uid); if (primary < dd_matrix->x) { i = 0; while (i < dd_matrix->y) { bmp = MATRIX_X_UNIT(dd_matrix, i); x_info = MATRIX_X_INFO(bmp); if (ec == 0 && x_info != 0 && TEST_MEMBERSHIP(bmp, primary, second) != 0) { if (is_dd_active(x_info) != 0 && (ec = get_dd_matrix(x_info, &tmp_p, &tmp_n)) == 0) { if (*p == NULL) { *p = tmp_p; *n = tmp_n; } else { if (*n >= tmp_n) { short_p = tmp_p; short_n = tmp_n; } else { short_p = *p; short_n = *n; *p = tmp_p; *n = tmp_n; } j = 0; while (j < short_n) { (*p)[j] |= short_p[j]; j ++; } free(short_p); } } } i ++; } } primary ++; if (ec == 0 && *p == NULL) { *p = (bmp_t *)calloc(primary, sizeof (bmp_t)); if (*p != NULL) { *n = primary; } else { *n = 0; ec = ISNS_RSP_INTERNAL_ERROR; } } if (*p != NULL) { (*p)[primary - 1] |= (1 << second); } return (ec); } int cb_clone_attrs( void *p1, void *p2 ) { int ec = 0; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; isns_attr_t *attr; int i = 1; while (i < MAX_LOOKUP_CTRL && lcp->op[i] != 0) { i ++; } while (ec == 0 && i < MAX_LOOKUP_CTRL && lcp->id[i] != 0) { switch (lcp->id[i]) { case ISNS_ISCSI_NAME_ATTR_ID: attr = &obj->attrs[ATTR_INDEX_ISCSI( ISNS_ISCSI_NAME_ATTR_ID)]; lcp->data[i].ptr = (uchar_t *)malloc(attr->len); if (lcp->data[i].ptr != NULL) { (void) strcpy((char *)lcp->data[i].ptr, (char *)attr->value.ptr); } else { /* memory exhausted */ ec = ISNS_RSP_INTERNAL_ERROR; } break; case ISNS_ISCSI_NODE_TYPE_ATTR_ID: attr = &obj->attrs[ATTR_INDEX_ISCSI( ISNS_ISCSI_NODE_TYPE_ATTR_ID)]; lcp->data[i].ui = attr->value.ui; break; case ISNS_PG_ISCSI_NAME_ATTR_ID: attr = &obj->attrs[ATTR_INDEX_PG( ISNS_PG_ISCSI_NAME_ATTR_ID)]; lcp->data[i].ptr = (uchar_t *)malloc(attr->len); if (lcp->data[i].ptr != NULL) { (void) strcpy((char *)lcp->data[i].ptr, (char *)attr->value.ptr); } else { /* memory exhausted */ ec = ISNS_RSP_INTERNAL_ERROR; } break; case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: attr = &obj->attrs[ATTR_INDEX_PG( ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)]; lcp->data[i].ip = (in6_addr_t *)malloc(attr->len); if (lcp->data[i].ip != NULL) { (void) memcpy(lcp->data[i].ip, attr->value.ip, attr->len); } else { /* memory exhausted */ ec = ISNS_RSP_INTERNAL_ERROR; } break; case ISNS_PG_PORTAL_PORT_ATTR_ID: attr = &obj->attrs[ATTR_INDEX_PG( ISNS_PG_PORTAL_PORT_ATTR_ID)]; lcp->data[i].ui = attr->value.ui; break; case ISNS_PORTAL_IP_ADDR_ATTR_ID: attr = &obj->attrs[ATTR_INDEX_PORTAL( ISNS_PORTAL_IP_ADDR_ATTR_ID)]; lcp->data[i].ip = (in6_addr_t *)malloc(attr->len); if (lcp->data[i].ip != NULL) { (void) memcpy(lcp->data[i].ip, attr->value.ip, attr->len); } else { /* memory exhausted */ ec = ISNS_RSP_INTERNAL_ERROR; } break; case ISNS_PORTAL_PORT_ATTR_ID: case ISNS_ESI_PORT_ATTR_ID: attr = &obj->attrs[ATTR_INDEX_PORTAL(lcp->id[i])]; if (attr->tag != 0 && attr->value.ui != 0) { lcp->data[i].ui = attr->value.ui; } else { lcp->data[i].ui = 0; } break; default: ASSERT(0); lcp->data[i].ui = 0; break; } i ++; } return (ec); } static matrix_t * new_matrix( uint32_t x, uint32_t y ) { matrix_t *matrix; matrix = (matrix_t *)malloc(sizeof (matrix_t)); if (matrix != NULL) { matrix->x = x; matrix->y = y; matrix->m = (bmp_t *)calloc(y, SIZEOF_X_UNIT(matrix)); if (matrix->m == NULL) { free(matrix); matrix = NULL; } } return (matrix); } int dd_matrix_init( struct cache *c ) { matrix_t *x; bmp_t *bmp; uint32_t primary; uint32_t second; /* * allocate an array of pointer for dd and dd-set matrix. */ c->x = (matrix_t **)calloc(2, sizeof (matrix_t *)); if (c->x == NULL) { return (1); } /* * create dd matrix. */ x = new_matrix(8, 64); if (x != NULL) { x->c = c; c->x[0] = x; } else { return (1); } /* * Mark the first array on the y axis for Default DD. */ bmp = MATRIX_X_UNIT(x, 0); MATRIX_X_INFO(bmp) = ISNS_DEFAULT_DD_ID; /* * create dd set matrix. */ x = new_matrix(2, 16); if (x != NULL) { x->c = c; c->x[1] = x; } else { return (1); } /* * Mark the first array on the y axis for Default DD-set. */ bmp = MATRIX_X_UNIT(x, 0); MATRIX_X_INFO(bmp) = ISNS_DEFAULT_DD_SET_ID; /* * Add Default DD as a member of Default DD-set. */ primary = GET_PRIMARY(ISNS_DEFAULT_DD_ID); second = GET_SECOND(ISNS_DEFAULT_DD_ID); SET_MEMBERSHIP(bmp, primary, second); return (0); } static uint32_t get_ds_id( matrix_t *matrix, uint32_t m_id, uint32_t curr_id ) { bmp_t *bmp; uint32_t primary = GET_PRIMARY(m_id); uint32_t second = GET_SECOND(m_id); uint32_t dd_id = 0; uint32_t uid; int i = 0; if (matrix->x > primary) { while (i < matrix->y) { bmp = MATRIX_X_UNIT(matrix, i); uid = MATRIX_X_INFO(bmp); if (uid > curr_id && TEST_MEMBERSHIP(bmp, primary, second) != 0) { if (dd_id == 0 || uid < dd_id) { dd_id = uid; } } i ++; } } return (dd_id); } uint32_t get_common_dd( uint32_t m_id1, uint32_t m_id2, uint32_t curr_id ) { matrix_t *matrix; bmp_t *bmp; uint32_t primary1 = GET_PRIMARY(m_id1); uint32_t second1 = GET_SECOND(m_id1); uint32_t primary2 = GET_PRIMARY(m_id2); uint32_t second2 = GET_SECOND(m_id2); uint32_t dd_id = 0; int i = 0; matrix = cache_get_matrix(OBJ_DD); if (matrix->x > primary1 && matrix->x > primary2) { while (i < matrix->y) { bmp = MATRIX_X_UNIT(matrix, i); if (MATRIX_X_INFO(bmp) > curr_id && TEST_MEMBERSHIP(bmp, primary1, second1) != 0 && TEST_MEMBERSHIP(bmp, primary2, second2) != 0) { dd_id = MATRIX_X_INFO(bmp); break; } i ++; } } return (dd_id); } uint32_t get_dd_id( uint32_t m_id, uint32_t curr_id ) { matrix_t *matrix = cache_get_matrix(OBJ_DD); return (get_ds_id(matrix, m_id, curr_id)); } uint32_t get_dds_id( uint32_t m_id, uint32_t curr_id ) { matrix_t *matrix = cache_get_matrix(OBJ_DDS); return (get_ds_id(matrix, m_id, curr_id)); } static int create_ds_object( isns_type_t type, isns_obj_t **ds_p, isns_attr_t *name_attr, isns_attr_t *uid_attr, isns_attr_t *status_attr ) { int ec = 0; isns_obj_t *obj; int id1, id2, id3; if (type == OBJ_DD) { id1 = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); id2 = ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID); id3 = ATTR_INDEX_DD(ISNS_DD_FEATURES_ATTR_ID); } else { ASSERT(type == OBJ_DDS); id1 = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID); id2 = ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID); id3 = ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID); } obj = obj_calloc(type); if (obj != NULL && (name_attr != NULL && name_attr->tag != 0 && assign_attr(&obj->attrs[id1], name_attr) == 0) && (uid_attr == NULL || uid_attr->value.ui == 0 || assign_attr(&obj->attrs[id2], uid_attr) == 0) && (status_attr == NULL || status_attr->value.ui == 0 || assign_attr(&obj->attrs[id3], status_attr) == 0)) { *ds_p = obj; } else { /* no memory */ free_object(obj); ec = ISNS_RSP_INTERNAL_ERROR; } return (ec); } int create_dd_object( isns_tlv_t *op, uint16_t op_len, isns_obj_t **dd_p ) { int ec = 0; uint8_t *value; isns_attr_t name = { 0 }; isns_attr_t dd_id = { 0 }, features = { 0 }; name.tag = ISNS_DD_NAME_ATTR_ID; while (op_len > 8 && ec == 0) { value = &op->attr_value[0]; switch (op->attr_id) { case ISNS_DD_ID_ATTR_ID: if (op->attr_len == 4) { dd_id.tag = ISNS_DD_ID_ATTR_ID; dd_id.len = 4; dd_id.value.ui = ntohl(*(uint32_t *)value); } else if (op->attr_len != 0) { ec = ISNS_RSP_MSG_FORMAT_ERROR; } break; case ISNS_DD_NAME_ATTR_ID: if (op->attr_len > 0 && op->attr_len <= 256) { name.len = op->attr_len; name.value.ptr = (uchar_t *)value; } else if (op->attr_len != 0) { ec = ISNS_RSP_MSG_FORMAT_ERROR; } break; case ISNS_DD_ISCSI_INDEX_ATTR_ID: case ISNS_DD_ISCSI_NAME_ATTR_ID: 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 (op->attr_len == 4) { features.tag = ISNS_DD_FEATURES_ATTR_ID; features.len = op->attr_len; features.value.ui = ntohl(*(uint32_t *)value); } else if (op->attr_len != 0) { ec = ISNS_RSP_MSG_FORMAT_ERROR; } break; default: ec = ISNS_RSP_INVALID_REGIS; break; } NEXT_TLV(op, op_len); } if (ec == 0) { ec = create_ds_object(OBJ_DD, dd_p, &name, &dd_id, &features); } return (ec); } int create_dds_object( isns_tlv_t *op, uint16_t op_len, isns_obj_t **dds_p ) { int ec = 0; uint8_t *value; isns_attr_t name = { 0 }; isns_attr_t dds_id = { 0 }, code = { 0 }; name.tag = ISNS_DD_SET_NAME_ATTR_ID; while (op_len > 8 && ec == 0) { value = &op->attr_value[0]; switch (op->attr_id) { case ISNS_DD_SET_ID_ATTR_ID: if (op->attr_len == 4) { dds_id.tag = ISNS_DD_ID_ATTR_ID; dds_id.len = 4; dds_id.value.ui = ntohl(*(uint32_t *)value); } else if (op->attr_len != 0) { ec = ISNS_RSP_MSG_FORMAT_ERROR; } break; case ISNS_DD_SET_NAME_ATTR_ID: if (op->attr_len > 0 && op->attr_len <= 256) { name.len = op->attr_len; name.value.ptr = (uchar_t *)value; } else if (op->attr_len != 0) { ec = ISNS_RSP_MSG_FORMAT_ERROR; } break; case ISNS_DD_SET_STATUS_ATTR_ID: if (op->attr_len == 4) { code.tag = ISNS_DD_SET_STATUS_ATTR_ID; code.len = op->attr_len; code.value.ui = ntohl(*(uint32_t *)value); } else if (op->attr_len != 0) { ec = ISNS_RSP_MSG_FORMAT_ERROR; } break; case ISNS_DD_ID_ATTR_ID: break; default: ec = ISNS_RSP_INVALID_REGIS; break; } NEXT_TLV(op, op_len); } if (ec == 0) { ec = create_ds_object(OBJ_DDS, dds_p, &name, &dds_id, &code); } return (ec); } int adm_create_dd( isns_obj_t **dd_p, uchar_t *name, uint32_t uid, uint32_t features ) { uint32_t len; isns_attr_t name_attr = { 0 }; isns_attr_t uid_attr = { 0 }; isns_attr_t features_attr = { 0 }; name_attr.tag = ISNS_DD_NAME_ATTR_ID; if (name != NULL) { /* need to include the null terminator */ /* and be on 4 bytes aligned */ len = strlen((char *)name) + 1; len += 4 - (len % 4); name_attr.len = len; name_attr.value.ptr = name; } uid_attr.tag = ISNS_DD_ID_ATTR_ID; uid_attr.len = 4; uid_attr.value.ui = uid; features_attr.tag = ISNS_DD_FEATURES_ATTR_ID; features_attr.len = 4; features_attr.value.ui = features; return (create_ds_object(OBJ_DD, dd_p, &name_attr, &uid_attr, &features_attr)); } int adm_create_dds( isns_obj_t **dds_p, uchar_t *name, uint32_t uid, uint32_t code ) { uint32_t len; isns_attr_t name_attr = { 0 }; isns_attr_t uid_attr = { 0 }; isns_attr_t code_attr = { 0 }; name_attr.tag = ISNS_DD_SET_NAME_ATTR_ID; if (name != NULL) { /* need to include the null terminator */ /* and be on 4 bytes aligned */ len = strlen((char *)name) + 1; len += 4 - (len % 4); name_attr.len = len; name_attr.value.ptr = name; } uid_attr.tag = ISNS_DD_SET_ID_ATTR_ID; uid_attr.len = 4; uid_attr.value.ui = uid; code_attr.tag = ISNS_DD_SET_STATUS_ATTR_ID; code_attr.len = 4; code_attr.value.ui = code; return (create_ds_object(OBJ_DDS, dds_p, &name_attr, &uid_attr, &code_attr)); } static int update_ds_name( isns_type_t type, uint32_t uid, uint32_t tag, uint32_t len, uchar_t *name ) { int ec = 0; lookup_ctrl_t lc; SET_UID_LCP(&lc, type, uid); lc.id[1] = tag; lc.data[1].ui = len; lc.data[2].ptr = name; ec = cache_rekey(&lc, &uid, cb_update_ds_attr); if (uid == 0) { ec = ISNS_RSP_INVALID_REGIS; } return (ec); } int update_dd_name( uint32_t uid, uint32_t len, uchar_t *name ) { /* * We do now allow changing the default DD and DD-set name. */ if (uid == ISNS_DEFAULT_DD_ID) { return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); } return (update_ds_name(OBJ_DD, uid, ISNS_DD_NAME_ATTR_ID, len, name)); } int update_dds_name( uint32_t uid, uint32_t len, uchar_t *name ) { /* * We do now allow changing the default DD and DD-set name. */ if (uid == ISNS_DEFAULT_DD_ID) { return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); } return (update_ds_name(OBJ_DDS, uid, ISNS_DD_SET_NAME_ATTR_ID, len, name)); } static int update_ds_uint32( isns_type_t type, uint32_t uid, uint32_t tag, uint32_t value ) { int ec = 0; lookup_ctrl_t lc; SET_UID_LCP(&lc, type, uid); lc.id[1] = tag; lc.data[1].ui = value; ec = cache_lookup(&lc, &uid, cb_update_ds_attr); if (uid == 0) { ec = ISNS_RSP_INVALID_REGIS; } return (ec); } int update_dd_features( uint32_t uid, uint32_t features ) { return (update_ds_uint32(OBJ_DD, uid, ISNS_DD_FEATURES_ATTR_ID, features)); } int update_dds_status( uint32_t uid, uint32_t enabled ) { return (update_ds_uint32(OBJ_DDS, uid, ISNS_DD_SET_STATUS_ATTR_ID, enabled)); } int add_dd_member( isns_obj_t *assoc ) { int ec = 0; uint32_t dd_id; uint32_t m_id, m_type; dd_id = get_parent_uid(assoc); /* * We do now allow placing any node to the default DD explicitly. */ if (dd_id == ISNS_DEFAULT_DD_ID) { return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); } ec = get_member_info(assoc, &m_type, &m_id, 1); if (ec == 0) { ec = update_dd_matrix( '+', /* add member */ dd_id, m_type, m_id); } if (ec == 0) { if (sys_q != NULL) { /* add the membership to data store */ ec = write_data(DATA_ADD, assoc); } /* trigger a management scn */ if (ec == 0 && scn_q != NULL) { (void) make_scn(ISNS_MEMBER_ADDED, assoc); } } return (ec); } int add_dds_member( isns_obj_t *assoc ) { int ec = 0; uint32_t m_id = assoc->attrs[ATTR_INDEX_ASSOC_DD( ISNS_DD_ID_ATTR_ID)].value.ui; uint32_t dds_id; dds_id = get_parent_uid(assoc); /* * We do now allow changing the membership of the default DD * and DD-set. */ if (dds_id == ISNS_DEFAULT_DD_SET_ID || m_id == ISNS_DEFAULT_DD_ID) { return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); } ec = get_dds_member_info(m_id); if (ec == 0) { ec = update_dds_matrix( '+', /* add member */ dds_id, m_id); } if (ec == 0) { if (sys_q != NULL) { /* add the membership to data store */ ec = write_data(DATA_ADD, assoc); } /* trigger a management scn */ if (ec == 0 && scn_q != NULL) { (void) make_scn(ISNS_MEMBER_ADDED, assoc); } } return (ec); } int remove_dd_member( isns_obj_t *assoc ) { int ec = 0; uint32_t dd_id; uint32_t m_type; uint32_t m_id; lookup_ctrl_t lc; dd_id = get_parent_uid(assoc); /* * We do now allow removing the member from default DD explicitly. */ if (dd_id == ISNS_DEFAULT_DD_ID) { return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); } ec = get_member_info(assoc, &m_type, &m_id, 0); if (ec == 0) { ec = update_dd_matrix( '-', /* remove member */ dd_id, m_type, m_id); if (ec == 0) { /* update data store */ if (sys_q != NULL) { /* remove it from data store */ ec = write_data( DATA_DELETE_ASSOC, assoc); } /* trigger a management scn */ if (ec == 0 && scn_q != NULL) { (void) make_scn(ISNS_MEMBER_REMOVED, assoc); } /* remove it from object container if */ /* it is not a registered object */ if (ec == 0) { SET_UID_LCP(&lc, m_type, m_id); ec = dereg_assoc(&lc); } } } return (ec); } int remove_dds_member( uint32_t dds_id, uint32_t m_id ) { int ec = 0; isns_obj_t *clone; /* * We do now allow removing the member from default DD-set. */ if (dds_id == ISNS_DEFAULT_DD_SET_ID) { return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); } if (m_id != 0) { ec = update_dds_matrix( '-', /* remove member */ dds_id, m_id); if (ec == 0) { clone = obj_calloc(OBJ_ASSOC_DD); if (clone != NULL) { (void) set_obj_uid((void *)clone, m_id); (void) set_parent_obj(clone, dds_id); } /* update data store */ if (sys_q != NULL) { if (clone != NULL) { /* remove it from data store */ ec = write_data( DATA_DELETE_ASSOC, clone); } else { ec = ISNS_RSP_INTERNAL_ERROR; } } /* trigger a management scn */ if (ec == 0 && scn_q != NULL && clone != NULL) { (void) make_scn(ISNS_MEMBER_REMOVED, clone); } free_object(clone); } } return (ec); } static int remove_member_wildchar( matrix_t *matrix, uint32_t m_id ) { int ec = 0; bmp_t *bmp; uint32_t x_info; int i; uint32_t primary = GET_PRIMARY(m_id); uint32_t second = GET_SECOND(m_id); isns_obj_t *clone; if (primary >= matrix->x) { return (ec); } i = 0; while (ec == 0 && i < matrix->y) { bmp = MATRIX_X_UNIT(matrix, i); x_info = MATRIX_X_INFO(bmp); if (x_info != 0 && TEST_MEMBERSHIP(bmp, primary, second) != 0) { /* clean the membership */ CLEAR_MEMBERSHIP(bmp, primary, second); /* update data store */ if (sys_q != NULL) { clone = obj_calloc(OBJ_ASSOC_DD); if (clone != NULL) { (void) set_obj_uid((void *)clone, m_id); (void) set_parent_obj(clone, x_info); /* remove it from data store */ ec = write_data( DATA_DELETE_ASSOC, clone); free_object(clone); } else { ec = ISNS_RSP_INTERNAL_ERROR; } } } i ++; } return (ec); } int remove_dd_object( uint32_t dd_id ) { matrix_t *dds_matrix; bmp_t *p; uint32_t n; int ec; lookup_ctrl_t lc; uint32_t uid; /* * We do now allow removing the default DD. */ if (dd_id == ISNS_DEFAULT_DD_ID) { return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); } SET_UID_LCP(&lc, OBJ_DD, dd_id); /* de-register the object at first */ ec = dereg_object(&lc, 0); /* clear it from all of dd-set */ dds_matrix = cache_get_matrix(OBJ_DDS); (void) remove_member_wildchar(dds_matrix, dd_id); /* clear its member bitmap */ (void) clear_dd_matrix(dd_id, &p, &n); /* deregister the member nodes which are not-registered node */ /* and have no longer membership in other DD(s). */ if (p != NULL) { SET_UID_LCP(&lc, OBJ_ISCSI, 0); FOR_EACH_MEMBER(p, n, uid, { lc.data[0].ui = uid; (void) dereg_assoc(&lc); }); free(p); } return (ec); } int remove_dds_object( uint32_t dds_id ) { int ec; lookup_ctrl_t lc; /* * We do now allow removing the default DD-set. */ if (dds_id == ISNS_DEFAULT_DD_SET_ID) { return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); } (void) clear_dds_matrix(dds_id); SET_UID_LCP(&lc, OBJ_DDS, dds_id); ec = dereg_object(&lc, 0); return (ec); } int update_ddd( void *p, const uchar_t op ) { isns_obj_t *obj; uint32_t uid; matrix_t *matrix; obj = (isns_obj_t *)p; if (obj->type != OBJ_ISCSI) { return (0); } matrix = cache_get_matrix(OBJ_DD); uid = get_obj_uid(obj); return (update_matrix(matrix, op, ISNS_DEFAULT_DD_ID, uid, 0)); } int verify_ddd( ) { int ec = 0; lookup_ctrl_t lc; isns_obj_t *obj; uchar_t *name; uint32_t uid; uint32_t features; uint32_t code; /* Ensure the Default DD is registered. */ uid = ISNS_DEFAULT_DD_ID; SET_UID_LCP(&lc, OBJ_DD, uid); (void) cache_lock_write(); if (is_obj_there(&lc) == 0) { name = (uchar_t *)DEFAULT_DD_NAME; features = DEFAULT_DD_FEATURES; ec = adm_create_dd(&obj, name, uid, features); if (ec == 0) { ec = register_object(obj, NULL, NULL); if (ec != 0) { free_object(obj); goto verify_done; } } else { goto verify_done; } } /* Ensure the Default DD-set is registered. */ uid = ISNS_DEFAULT_DD_SET_ID; SET_UID_LCP(&lc, OBJ_DDS, uid); if (is_obj_there(&lc) == 0) { name = (uchar_t *)DEFAULT_DD_SET_NAME; code = DEFAULT_DD_SET_STATUS; ec = adm_create_dds(&obj, name, uid, code); if (ec == 0) { ec = register_object(obj, NULL, NULL); if (ec != 0) { free_object(obj); } } } verify_done: ec = cache_unlock_sync(ec); return (ec); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2025 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "isns_server.h" #include "admintf.h" #include "isns_mgmt.h" #include "isns_utils.h" #include "isns_protocol.h" #include "isns_log.h" #include "isns_provider.h" /* door creation flag */ extern boolean_t door_created; /* macro for allocating name buffers for the request */ #define NEW_REQARGV(old, n) (xmlChar **)realloc((xmlChar *)old, \ (unsigned)(n+2) * sizeof (xmlChar *)) /* macro for allocating association pair buffers for the request */ #define NEW_REQPAIRARGV(old, n) (assoc_pair_t **)realloc((assoc_pair_t *)old, \ (unsigned)(n+2) * sizeof (assoc_pair_t *)) /* macro for allocating DD/DD set attribute list buffers for the request */ #define NEW_REQATTRLISTARGV(old, n)\ (object_attrlist_t **)realloc((object_attrlist_t *)old, \ (unsigned)(n+2) * sizeof (object_attrlist_t *)) #if LIBXML_VERSION >= 20904 #define XMLSTRING_CAST (const char *) #else #define XMLSTRING_CAST (const xmlChar *) #endif /* operation table */ static op_table_entry_t op_table[] = { {GET, get_op}, {GETASSOCIATED, getAssociated_op}, {ENUMERATE, enumerate_op}, {CREATEMODIFY, createModify_op}, {DELETE, delete_op}, {NULL, 0} }; /* object table */ static obj_table_entry_t obj_table[] = { {NODEOBJECT, Node}, {DDOBJECT, DiscoveryDomain}, {DDSETOBJECT, DiscoveryDomainSet}, {DDOBJECTMEMBER, DiscoveryDomainMember}, {DDSETOBJECTMEMBER, DiscoveryDomainSetMember}, {ISNSSERVER, ServerConfig}, {NULL, 0} }; /* * list to capture thread id and associated door return buffer * the return buffer from the previous door return is freed * when the same thread is invoked to take another request. * While the server is running one buffer is outstanding * to be freed. */ static thr_elem_t *thr_list = NULL; /* * get_op_id_from_doc -- * extracts an operation id through the given context ptr. * * ctext: context ptr for the original doc * * Returns an operation id if found or -1 otherwise. */ static int get_op_id_from_doc(xmlXPathContextPtr ctext) { xmlChar expr[ISNS_MAX_LABEL_LEN + 13]; xmlXPathObjectPtr xpath_obj = NULL; int i; for (i = 0; op_table[i].op_str != NULL; i++) { (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", op_table[i].op_str); xpath_obj = xmlXPathEvalExpression(expr, ctext); if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { isnslog(LOG_DEBUG, "get_op_id_from_doc ", "xpath obj->nodesetval->nodeNr: %d", xpath_obj->nodesetval->nodeNr); isnslog(LOG_DEBUG, "get_op_id_from_doc", "operation: %s id: %d", op_table[i].op_str, op_table[i].op_id); if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (op_table[i].op_id); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (-1); } /* * process_get_request_from_doc -- * looks for the object through the context ptr and gets the object * name. Possible object types are Node, DD, DD set and server-config. * * ctext: context ptr for the original doc to parse request info. * req: request to be filled up. * * Returns 0 if successful or an error code otherwise. */ static int process_get_request_from_doc(xmlXPathContextPtr ctext, request_t *req) { xmlChar expr[ISNS_MAX_LABEL_LEN + 13]; xmlXPathObjectPtr xpath_obj = NULL; xmlNodeSetPtr r_nodes = NULL; xmlAttrPtr attr = NULL; int i, cnt; int obj = 0; isnslog(LOG_DEBUG, "process_get_request_from_doc", "entered"); (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", ISNSOBJECT); xpath_obj = xmlXPathEvalExpression(expr, ctext); if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeTab) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab[0]->children) && (xpath_obj->nodesetval->nodeTab[0]->children->name)) { for (i = 0; obj_table[i].obj_str != NULL; i++) { /* * To handle DiscoveryDomain and DiscoveryDomainSet * searches isnsobject instead of the object directly. */ if (xmlStrncmp( xpath_obj->nodesetval->nodeTab[0]->children->name, (xmlChar *)obj_table[i].obj_str, xmlStrlen( xpath_obj->nodesetval->nodeTab[0]->children->name)) == 0) { obj = obj_table[i].obj_id; break; } } if (xpath_obj) xmlXPathFreeObject(xpath_obj); } if (obj == 0) { /* check the server config request. */ (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", ISNSSERVER); xpath_obj = xmlXPathEvalExpression(expr, ctext); if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { for (i = 0; obj_table[i].obj_str != NULL; i++) { if (strncmp(ISNSSERVER, obj_table[i].obj_str, strlen(ISNSSERVER)) == 0) { obj = obj_table[i].obj_id; break; } } } if (xpath_obj) xmlXPathFreeObject(xpath_obj); } if (obj == 0) { return (ERR_XML_VALID_OBJECT_NOT_FOUND); } req->op_info.obj = obj; if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) { ISNS_MGMT_OBJECT_TYPE(obj); } (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 12, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", obj_table[i].obj_str); xpath_obj = xmlXPathEvalExpression(expr, ctext); if (((xpath_obj == NULL) || (xpath_obj->nodesetval == NULL) || (xpath_obj->nodesetval->nodeNr <= 0) || (xpath_obj->nodesetval->nodeTab == NULL))) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_VALID_OBJECT_NOT_FOUND); } switch (obj) { /* using the same algorithm for isns object */ case Node: case DiscoveryDomain: case DiscoveryDomainSet: r_nodes = xpath_obj->nodesetval; cnt = r_nodes->nodeNr; req->count = 0; req->req_data.data = (xmlChar **) malloc(sizeof (xmlChar *)); for (i = 0; i < cnt; i++) { attr = r_nodes->nodeTab[i]->properties; for (; attr != NULL; attr = attr->next) { if (xmlStrncmp(attr->name, (xmlChar *)NAMEATTR, xmlStrlen((xmlChar *)NAMEATTR)) == 0) { req->req_data.data = NEW_REQARGV(req->req_data.data, req->count); if (req->req_data.data == (xmlChar **)NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.data[req->count] = xmlNodeGetContent(attr->children); req->req_data.data[++req->count] = NULL; } } } break; case ServerConfig: /* indication the obj type is sufficient. */ break; default: if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_OP_FAILED); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (0); } /* * process_enumerate_request_from_doc -- * looks for the object through the context ptr and sets the * request with object type. * * ctext: context ptr for the original doc to parse request info. * req: request to be filled up. * * Returns 0 if successful or an error code otherwise. */ static int process_enumerate_request_from_doc(xmlXPathContextPtr ctext, request_t *req) { xmlChar expr[ISNS_MAX_LABEL_LEN + 13]; xmlXPathObjectPtr xpath_obj = NULL; int i; int obj = 0; isnslog(LOG_DEBUG, "process_enumerate_request_from_doc", "entered"); (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", ISNSOBJECTTYPE); xpath_obj = xmlXPathEvalExpression(expr, ctext); isnslog(LOG_DEBUG, "process_enumerate_request_from_doc", "xpath obj->nodesetval->nodeNR: %d", xpath_obj->nodesetval->nodeNr); if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { for (i = 0; obj_table[i].obj_str != NULL; i++) { if (xmlStrncmp( xpath_obj->nodesetval->nodeTab[0]->children->content, (xmlChar *)obj_table[i].obj_str, xmlStrlen((xmlChar *) xpath_obj->nodesetval->nodeTab[0]->children->content)) == 0) { obj = obj_table[i].obj_id; break; } } } else { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_VALID_OBJECT_NOT_FOUND); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); if (obj == 0) { return (ERR_XML_VALID_OBJECT_NOT_FOUND); } req->op_info.obj = obj; if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) { ISNS_MGMT_OBJECT_TYPE(obj); } return (0); } /* * process_getAssociated_request_from_doc -- * first looks for association type through the contexti and then * find out the given object. That will indicate the direction of * association, containter to member or vice versa. * Lastly it extract the object name form the doc that assocation * is requested. * * ctext: context ptr for the original doc to parse request info. * req: request to be filled up. * * Returns 0 if successful or an error code otherwise. */ static int process_getAssociated_request_from_doc(xmlXPathContextPtr ctext, request_t *req) { xmlChar expr[ISNS_MAX_LABEL_LEN + 13]; xmlXPathObjectPtr xpath_obj = NULL; xmlNodeSetPtr r_nodes = NULL; xmlAttrPtr attr = NULL; int i, cnt, obj = 0; isnslog(LOG_DEBUG, "process_getAssociated_request_from_doc", "entered"); (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", ASSOCIATIONTYPE); xpath_obj = xmlXPathEvalExpression(expr, ctext); if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { for (i = 0; obj_table[i].obj_str != NULL; i++) { if (xmlStrncmp( xpath_obj->nodesetval->nodeTab[0]->children->content, (xmlChar *)obj_table[i].obj_str, xmlStrlen( xpath_obj->nodesetval->nodeTab[0]->children->content)) == 0) { obj = obj_table[i].obj_id; break; } } } if (xpath_obj) xmlXPathFreeObject(xpath_obj); if (obj == 0) { return (ERR_XML_VALID_OBJECT_NOT_FOUND); } req->op_info.obj = obj; if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) { ISNS_MGMT_OBJECT_TYPE(obj); } switch (obj) { /* using the same algorithm for isns object */ case DiscoveryDomainMember: (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", NODEOBJECT); xpath_obj = xmlXPathEvalExpression(expr, ctext); r_nodes = xpath_obj->nodesetval; if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { req->assoc_req = member_to_container; } else { if (xpath_obj) xmlXPathFreeObject(xpath_obj); (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", DDOBJECT); xpath_obj = xmlXPathEvalExpression(expr, ctext); r_nodes = xpath_obj->nodesetval; if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { req->assoc_req = container_to_member; } else { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_VALID_OBJECT_NOT_FOUND); } } break; case DiscoveryDomainSetMember: (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", DDSETOBJECT); xpath_obj = xmlXPathEvalExpression(expr, ctext); r_nodes = xpath_obj->nodesetval; if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { req->assoc_req = container_to_member; } else { if (xpath_obj) xmlXPathFreeObject(xpath_obj); (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", DDOBJECT); xpath_obj = xmlXPathEvalExpression(expr, ctext); r_nodes = xpath_obj->nodesetval; if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { req->assoc_req = member_to_container; } else { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_VALID_OBJECT_NOT_FOUND); } } break; default: if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_OP_FAILED); } /* now process the name attr */ cnt = r_nodes->nodeNr; req->count = 0; req->req_data.data = (xmlChar **) malloc(sizeof (xmlChar *)); /* for (i = cnt - 1; i >= 0; i--) { */ for (i = 0; i < cnt; i++) { attr = r_nodes->nodeTab[i]->properties; for (; attr != NULL; attr = attr->next) { if (xmlStrncmp(attr->name, (xmlChar *)NAMEATTR, xmlStrlen((xmlChar *)NAMEATTR)) == 0) { req->req_data.data = NEW_REQARGV(req->req_data.data, req->count); if (req->req_data.data == (xmlChar **)NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.data[req->count++] = xmlNodeGetContent(attr->children); req->req_data.data[req->count] = NULL; } } } if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (0); } /* * process_delete_request_from_doc -- * first looks for the object through the context ptr and sets the * request with additional data. * For DD and DD set, the name is given. * For DD and DD set membership, container and member pairs are given. * * ctext: context ptr for the original doc to parse request info. * req: request to be filled up. * * Returns 0 if successful or an error code otherwise. */ static int process_delete_request_from_doc(xmlXPathContextPtr ctext, request_t *req) { xmlChar expr[ISNS_MAX_LABEL_LEN + 13]; xmlXPathObjectPtr xpath_obj = NULL; xmlNodeSetPtr r_nodes = NULL; xmlAttrPtr attr = NULL; xmlChar *container = NULL, *member = NULL; int i, cnt; int obj = 0; isnslog(LOG_DEBUG, "process_delete_request_from_doc", "entered"); for (i = 0; obj_table[i].obj_str != NULL; i++) { (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", obj_table[i].obj_str); xpath_obj = xmlXPathEvalExpression(expr, ctext); if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { obj = obj_table[i].obj_id; break; } if (xpath_obj) xmlXPathFreeObject(xpath_obj); } if (obj == 0) { return (ERR_XML_VALID_OBJECT_NOT_FOUND); } req->op_info.obj = obj; if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) { ISNS_MGMT_OBJECT_TYPE(obj); } switch (obj) { case DiscoveryDomainMember: /* at least one object exists to get here. */ r_nodes = xpath_obj->nodesetval; cnt = r_nodes->nodeNr; req->count = 0; req->req_data.pair = (assoc_pair_t **)malloc(sizeof (assoc_pair_t *)); for (i = 0; i < cnt; i++) { attr = r_nodes->nodeTab[i]->properties; for (; attr != NULL; attr = attr->next) { if (xmlStrncmp(attr->name, (xmlChar *)DDNAMEATTR, xmlStrlen((xmlChar *)DDNAMEATTR)) == 0) { container = xmlNodeGetContent(attr->children); } if (xmlStrncmp(attr->name, (xmlChar *)NODENAMEATTR, xmlStrlen((xmlChar *)NODENAMEATTR)) == 0) { member = xmlNodeGetContent(attr->children); } } if (container != NULL && member != NULL) { req->req_data.pair = NEW_REQPAIRARGV(req->req_data.pair, req->count); if (req->req_data.pair == (assoc_pair_t **)NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.pair[req->count] = (assoc_pair_t *) malloc(sizeof (assoc_pair_t)); if (req->req_data.pair[req->count] == NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.pair[req->count]->container = container; req->req_data.pair[req->count]->member = member; req->req_data.data[++req->count] = NULL; } else { if (container != NULL) { xmlFree(container); } if (member != NULL) { xmlFree(member); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_OP_FAILED); } container = NULL; member = NULL; } if (xpath_obj) xmlXPathFreeObject(xpath_obj); break; case DiscoveryDomainSetMember: /* at least one object exists to get here. */ r_nodes = xpath_obj->nodesetval; cnt = r_nodes->nodeNr; req->count = 0; req->req_data.pair = (assoc_pair_t **)malloc(sizeof (assoc_pair_t *)); for (i = 0; i < cnt; i++) { attr = r_nodes->nodeTab[i]->properties; for (; attr != NULL; attr = attr->next) { if (xmlStrncmp(attr->name, (xmlChar *)DDSETNAMEATTR, xmlStrlen((xmlChar *)DDNAMEATTR)) == 0) { container = xmlNodeGetContent(attr->children); } if (xmlStrncmp(attr->name, (xmlChar *)DDNAMEATTR, xmlStrlen((xmlChar *)NODENAMEATTR)) == 0) { member = xmlNodeGetContent(attr->children); } } if (container != NULL && member != NULL) { req->req_data.pair = NEW_REQPAIRARGV(req->req_data.pair, req->count); if (req->req_data.pair == (assoc_pair_t **)NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.pair[req->count] = (assoc_pair_t *) malloc(sizeof (assoc_pair_t)); if (req->req_data.pair[req->count] == NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.pair[req->count]->container = container; req->req_data.pair[req->count++]->member = member; req->req_data.data[req->count] = NULL; } else { if (container != NULL) { xmlFree(container); } if (member != NULL) { xmlFree(member); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_OP_FAILED); } } if (xpath_obj) xmlXPathFreeObject(xpath_obj); break; case DiscoveryDomain: case DiscoveryDomainSet: r_nodes = xpath_obj->nodesetval; cnt = r_nodes->nodeNr; req->count = 0; req->req_data.data = (xmlChar **) malloc(sizeof (xmlChar *)); for (i = 0; i < cnt; i++) { attr = r_nodes->nodeTab[i]->properties; for (; attr != NULL; attr = attr->next) { if (xmlStrncmp(attr->name, (xmlChar *)NAMEATTR, xmlStrlen((xmlChar *)NAMEATTR)) == 0) { req->req_data.data = NEW_REQARGV(req->req_data.data, req->count); if (req->req_data.data == (xmlChar **)NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.data[req->count] = xmlNodeGetContent(attr->children); req->req_data.data[++req->count] = NULL; } } } if (xpath_obj) xmlXPathFreeObject(xpath_obj); break; default: if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_OP_FAILED); } return (0); } /* * process_createModify_request_from_doc -- * first looks for the object through the context ptr and sets the * request with additional data. * For DD and DD set, the name is given. * For DD and DD set membership, container and member pairs are given. * * ctext: context ptr for the original doc to parse request info. * req: request to be filled up. * * Returns 0 if successful or an error code otherwise. */ static int process_createModify_request_from_doc(xmlXPathContextPtr ctext, request_t *req) { xmlChar expr[ISNS_MAX_LABEL_LEN + 13]; xmlXPathObjectPtr xpath_obj = NULL; xmlNodeSetPtr r_nodes = NULL; xmlAttrPtr attr = NULL; xmlChar *container = NULL, *member = NULL, *xml_id; int i, cnt; int obj = 0; isnslog(LOG_DEBUG, "process_createModify_request_from_doc", "entered"); for (i = 0; obj_table[i].obj_str != NULL; i++) { (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", obj_table[i].obj_str); xpath_obj = xmlXPathEvalExpression(expr, ctext); if ((xpath_obj) && (xpath_obj->nodesetval) && (xpath_obj->nodesetval->nodeNr > 0) && (xpath_obj->nodesetval->nodeTab)) { obj = obj_table[i].obj_id; break; } if (xpath_obj) xmlXPathFreeObject(xpath_obj); } if (obj == 0) { return (ERR_XML_VALID_OBJECT_NOT_FOUND); } req->op_info.obj = obj; if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) { ISNS_MGMT_OBJECT_TYPE(obj); } switch (obj) { case DiscoveryDomainMember: /* at least one object exists to get here. */ r_nodes = xpath_obj->nodesetval; cnt = r_nodes->nodeNr; req->count = 0; req->req_data.pair = (assoc_pair_t **)malloc(sizeof (assoc_pair_t *)); for (i = 0; i < cnt; i++) { attr = r_nodes->nodeTab[i]->properties; for (; attr != NULL; attr = attr->next) { if (xmlStrncmp(attr->name, (xmlChar *)DDNAMEATTR, xmlStrlen((xmlChar *)DDNAMEATTR)) == 0) { container = xmlNodeGetContent(attr->children); } if (xmlStrncmp(attr->name, (xmlChar *)NODENAMEATTR, xmlStrlen((xmlChar *)NODENAMEATTR)) == 0) { member = xmlNodeGetContent(attr->children); } } if (container != NULL && member != NULL) { req->req_data.pair = NEW_REQPAIRARGV(req->req_data.pair, req->count); if (req->req_data.pair == (assoc_pair_t **)NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.pair[req->count] = (assoc_pair_t *) malloc(sizeof (assoc_pair_t)); if (req->req_data.pair[req->count] == NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.pair[req->count]->container = container; req->req_data.pair[req->count]->member = member; req->req_data.data[++req->count] = NULL; } else { if (container != NULL) { xmlFree(container); } if (member != NULL) { xmlFree(member); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_OP_FAILED); } container = member = NULL; } if (xpath_obj) xmlXPathFreeObject(xpath_obj); break; case DiscoveryDomainSetMember: /* at least one object exists to get here. */ r_nodes = xpath_obj->nodesetval; cnt = r_nodes->nodeNr; req->count = 0; req->req_data.pair = (assoc_pair_t **)malloc(sizeof (assoc_pair_t *)); for (i = 0; i < cnt; i++) { attr = r_nodes->nodeTab[i]->properties; for (; attr != NULL; attr = attr->next) { if (xmlStrncmp(attr->name, (xmlChar *)DDSETNAMEATTR, xmlStrlen((xmlChar *)DDSETNAMEATTR)) == 0) { container = xmlNodeGetContent(attr->children); } if (xmlStrncmp(attr->name, (xmlChar *)DDNAMEATTR, xmlStrlen((xmlChar *)DDNAMEATTR)) == 0) { member = xmlNodeGetContent(attr->children); } } if (container != NULL && member != NULL) { req->req_data.pair = NEW_REQPAIRARGV(req->req_data.pair, req->count); if (req->req_data.pair == (assoc_pair_t **)NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.pair[req->count] = (assoc_pair_t *) malloc(sizeof (assoc_pair_t)); if (req->req_data.pair[req->count] == NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.pair[req->count]->container = container; req->req_data.pair[req->count]->member = member; req->req_data.data[++req->count] = NULL; } else { if (container != NULL) { xmlFree(container); } if (member != NULL) { xmlFree(member); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_OP_FAILED); } container = member = NULL; } if (xpath_obj) xmlXPathFreeObject(xpath_obj); break; case DiscoveryDomain: case DiscoveryDomainSet: /* at least one object exists to get here. */ r_nodes = xpath_obj->nodesetval; cnt = r_nodes->nodeNr; req->count = 0; req->req_data.attrlist = (object_attrlist_t **)malloc(sizeof (object_attrlist_t *)); for (i = 0; i < cnt; i++) { req->req_data.attrlist = NEW_REQATTRLISTARGV(req->req_data.attrlist, req->count); if (req->req_data.attrlist == (object_attrlist_t **)NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.attrlist[req->count] = (object_attrlist_t *) malloc(sizeof (object_attrlist_t)); if (req->req_data.attrlist[req->count] == NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } req->req_data.attrlist[req->count]->name = NULL; req->req_data.attrlist[req->count]->id = NULL; req->req_data.attrlist[req->count]->enabled = NULL; attr = r_nodes->nodeTab[i]->properties; for (; attr != NULL; attr = attr->next) { if ((xmlStrncmp(attr->name, (xmlChar *)NAMEATTR, xmlStrlen((xmlChar *)NAMEATTR))) == 0) { req->req_data.attrlist[req->count]->name = xmlNodeGetContent(attr->children); } if ((xmlStrncmp(attr->name, (xmlChar *)IDATTR, xmlStrlen((xmlChar *)IDATTR))) == 0) { req->req_data.attrlist[req->count]->id = (uint32_t *)calloc(1, sizeof (uint32_t)); if (req->req_data.attrlist[req->count]->id == NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } xml_id = xmlNodeGetContent(attr->children); if (xml_id != NULL) { *(req->req_data.attrlist[req->count]->id) = atoi((const char *)xml_id); xmlFree(xml_id); } } } /* * check the enabled element. * Only one child element so check the children ptr. */ if (r_nodes->nodeTab[i]->children) { req->req_data.attrlist[req->count]->enabled = (boolean_t *)malloc(sizeof (boolean_t)); if (req->req_data.attrlist[req->count]->enabled == NULL) { if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_MALLOC_FAILED); } /* value is children of enabled. */ if (xmlStrncmp( r_nodes->nodeTab[i]->children->children->content, (xmlChar *)XMLTRUE, xmlStrlen((xmlChar *)XMLTRUE)) == 0) { *(req->req_data.attrlist[req->count]->enabled) = B_TRUE; } else { *(req->req_data.attrlist[req->count]->enabled) = B_FALSE; } } req->req_data.attrlist[++req->count] = NULL; } if (xpath_obj) xmlXPathFreeObject(xpath_obj); break; default: if (xpath_obj) xmlXPathFreeObject(xpath_obj); return (ERR_XML_OP_FAILED); } return (0); } /* * build_mgmt_request -- extracts the request info from the given XML doc. * * x_doc: ptr to the request XML doc * req: ptr to the request struct to be filled up. * * Return value: ISNS_RSP_SUCCESSFUL if successful or an error code. */ static int process_mgmt_request(xmlDocPtr x_doc, request_t *req, ucred_t *uc) { result_code_t ret; int op; xmlXPathContextPtr ctext = NULL; uid_t user; struct passwd pwds, *pwd; char buf_pwd[1024]; isnslog(LOG_DEBUG, "process_mgmt_request", "entered"); (void) memset(req, 0, sizeof (request_t)); /* get the operation first. */ ctext = xmlXPathNewContext(x_doc); if (ctext == NULL) { return (ERR_XML_FAILED_TO_SET_XPATH_CONTEXT); } isnslog(LOG_DEBUG, "process_mgmt_request", "xpath context succeeded"); op = get_op_id_from_doc(ctext); if (op == -1) { if (ctext) xmlXPathFreeContext(ctext); return (ERR_XML_VALID_OPERATION_NOT_FOUND); } user = ucred_getruid(uc); ret = getpwuid_r(user, &pwds, buf_pwd, sizeof (buf_pwd), &pwd); if (ret != 0) { if (ctext) xmlXPathFreeContext(ctext); return (ERR_DOOR_SERVER_DETECTED_INVALID_USER); } /* write operations are restricted. */ if ((op == delete_op) || (op == createModify_op)) { if (!chkauthattr(ISNS_ADMIN_WRITE_AUTH, pwd->pw_name)) { if (ctext) xmlXPathFreeContext(ctext); return (ERR_DOOR_SERVER_DETECTED_NOT_AUTHORIZED_USER); } } req->op_info.op = op; if (ISNS_MGMT_OPERATION_TYPE_ENABLED()) { ISNS_MGMT_OPERATION_TYPE(op); } switch (op) { case (get_op): ret = process_get_request_from_doc(ctext, req); break; case (getAssociated_op): ret = process_getAssociated_request_from_doc(ctext, req); break; case (enumerate_op): ret = process_enumerate_request_from_doc(ctext, req); break; case (delete_op): ret = process_delete_request_from_doc(ctext, req); break; case (createModify_op): ret = process_createModify_request_from_doc(ctext, req); break; default: ret = ERR_XML_VALID_OPERATION_NOT_FOUND; } if (ctext) xmlXPathFreeContext(ctext); return (ret); } /* * build_mgmt_response -- sets an XML doc with a root and calls a porper * routine based on the request. If the called routine constructed * the response doc with the result element, this routine fills up * response buffer with raw XML doc. * * reponse: ptr to response buffer * req: request to be processed. * size: ptr to the response doc buffer */ static int build_mgmt_response(xmlChar **response, request_t req, int *size) { int ret; xmlDocPtr doc; xmlNodePtr root; xmlXPathContextPtr ctext = NULL; xmlChar expr[ISNS_MAX_LABEL_LEN + 13]; xmlXPathObjectPtr xpath_obj = NULL; isnslog(LOG_DEBUG, "build_mgmt_response", "entered"); doc = xmlNewDoc((uchar_t *)"1.0"); root = xmlNewNode(NULL, (xmlChar *)ISNSRESPONSE); (void) xmlDocSetRootElement(doc, root); if (xmlSetProp(root, (xmlChar *)XMLNSATTR, (xmlChar *)XMLNSATTRVAL) == NULL) { return (ERR_XML_SETPROP_FAILED); } switch (req.op_info.op) { case get_op: switch (req.op_info.obj) { case Node: ret = get_node_op(&req, doc); break; case DiscoveryDomain: ret = get_dd_op(&req, doc); break; case DiscoveryDomainSet: ret = get_ddset_op(&req, doc); break; case ServerConfig: ret = get_serverconfig_op(doc); break; default: ret = ERR_INVALID_MGMT_REQUEST; } break; case enumerate_op: isnslog(LOG_DEBUG, "build_mgmt_response", "enumerate_op"); switch (req.op_info.obj) { case Node: ret = enumerate_node_op(doc); break; case DiscoveryDomain: ret = enumerate_dd_op(doc); break; case DiscoveryDomainSet: ret = enumerate_ddset_op(doc); break; default: ret = ERR_INVALID_MGMT_REQUEST; } break; case getAssociated_op: switch (req.op_info.obj) { case DiscoveryDomainMember: if (req.assoc_req == container_to_member) { ret = getAssociated_dd_to_node_op(&req, doc); } else { ret = getAssociated_node_to_dd_op(&req, doc); } break; case DiscoveryDomainSetMember: if (req.assoc_req == container_to_member) { ret = getAssociated_ddset_to_dd_op(&req, doc); } else { ret = getAssociated_dd_to_ddset_op(&req, doc); } break; default: ret = ERR_INVALID_MGMT_REQUEST; } break; case createModify_op: switch (req.op_info.obj) { case DiscoveryDomain: case DiscoveryDomainSet: ret = createModify_dd_ddset_op(&req, doc); break; case DiscoveryDomainMember: case DiscoveryDomainSetMember: ret = create_ddmember_ddsetmember_op(&req, doc, req.op_info.obj); break; default: ret = ERR_INVALID_MGMT_REQUEST; } break; case delete_op: switch (req.op_info.obj) { case DiscoveryDomainMember: case DiscoveryDomainSetMember: ret = delete_ddmember_ddsetmember_op(&req, doc, req.op_info.obj); break; case DiscoveryDomain: case DiscoveryDomainSet: ret = delete_dd_ddset_op(&req, doc, req.op_info.obj); break; default: ret = ERR_INVALID_MGMT_REQUEST; } break; default: ret = ERR_INVALID_MGMT_REQUEST; } /* * if failed check to see the doc contains the result element. * if not, the response is set with only an error code. */ if (ret != ISNS_RSP_SUCCESSFUL) { ctext = xmlXPathNewContext(doc); if (ctext != NULL) { (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13, XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", RESULT); xpath_obj = xmlXPathEvalExpression(expr, ctext); if ((xpath_obj == NULL) || (xpath_obj->nodesetval == NULL) || (xpath_obj->nodesetval->nodeNr <= 0) || (xpath_obj->nodesetval->nodeTab == NULL)) { isnslog(LOG_DEBUG, "build_mgmt_response", "returning repsonse only with error code %d\n", ret); *response = malloc(sizeof (ret)); if (*response) **response = ret; *size = sizeof (ret); } else { xmlDocDumpMemory(doc, response, size); } } else { /* can't verify the xml doc. dump return the doc anyway. */ xmlDocDumpMemory(doc, response, size); } } else { xmlDocDumpMemory(doc, response, size); } if (xpath_obj) xmlXPathFreeObject(xpath_obj); if (ctext) xmlXPathFreeContext(ctext); if (doc) xmlFreeDoc(doc); return (ret); } /* * build_result_message -- construct a response doc with the given result. * Result contains status code and message. * * reponse: ptr to response doc * code: result code * size: ptr to the response doc size */ static int build_result_message(xmlChar **response, result_code_t code, int *size) { int ret = ISNS_RSP_SUCCESSFUL; xmlDocPtr doc; xmlNodePtr root, n_obj; char numbuf[32]; isnslog(LOG_DEBUG, "build_result_response", "entered"); doc = xmlNewDoc((uchar_t *)"1.0"); root = xmlNewNode(NULL, (xmlChar *)ISNSRESPONSE); (void) xmlDocSetRootElement(doc, root); n_obj = xmlNewChild(root, NULL, (xmlChar *)RESULT, NULL); if (code == ISNS_RSP_SUCCESSFUL) { (void) sprintf(numbuf, "%d", ISNS_RSP_SUCCESSFUL); if (xmlNewChild(n_obj, NULL, (xmlChar *)STATUSELEMENT, (xmlChar *)numbuf) == NULL) { ret = ERR_XML_NEWCHILD_FAILED; } } else { (void) sprintf(numbuf, "%d", code); if (xmlNewChild(n_obj, NULL, (xmlChar *)STATUSELEMENT, (xmlChar *)numbuf) == NULL) { ret = ERR_XML_NEWCHILD_FAILED; } if (xmlNewChild(n_obj, NULL, (xmlChar *)MESSAGEELEMENT, (xmlChar *)result_code_to_str(code)) == NULL) { ret = ERR_XML_NEWCHILD_FAILED; } } xmlDocDumpMemory(doc, response, size); if (doc) xmlFreeDoc(doc); return (ret); } /* * cleanup_request -- deallocatate memory associated with the given request * structure. */ static void cleanup_request(request_t req) { int i; isnslog(LOG_DEBUG, "cleanup_request", "entered"); switch (req.op_info.op) { case (get_op): for (i = 0; i < req.count; i++) { if (req.req_data.data[i]) xmlFree(req.req_data.data[i]); } if (req.req_data.data) free(req.req_data.data); break; case (getAssociated_op): for (i = 0; i < req.count; i++) { if (req.req_data.data[i]) xmlFree(req.req_data.data[i]); } if (req.req_data.data) free(req.req_data.data); break; case (enumerate_op): break; case (delete_op): if ((req.op_info.obj == DiscoveryDomainMember) || (req.op_info.obj == DiscoveryDomainSetMember)) { for (i = 0; i < req.count; i++) { if (req.req_data.pair[i]->container) xmlFree(req.req_data.pair[i]->container); if (req.req_data.pair[i]->member) xmlFree(req.req_data.pair[i]->member); if (req.req_data.pair[i]) free(req.req_data.pair[i]); } if (req.req_data.pair) free(req.req_data.pair); } else { for (i = 0; i < req.count; i++) { if (req.req_data.data[i]) xmlFree(req.req_data.data[i]); } if (req.req_data.data) free(req.req_data.data); } break; case (createModify_op): if ((req.op_info.obj == DiscoveryDomainMember) || (req.op_info.obj == DiscoveryDomainSetMember)) { for (i = 0; i < req.count; i++) { if (req.req_data.pair[i]->container) xmlFree(req.req_data.pair[i]->container); if (req.req_data.pair[i]->member) xmlFree(req.req_data.pair[i]->member); if (req.req_data.pair[i]) free(req.req_data.pair[i]); } if (req.req_data.pair) free(req.req_data.pair); } else if ((req.op_info.obj == DiscoveryDomain) || (req.op_info.obj == DiscoveryDomainSet)) { for (i = 0; i < req.count; i++) { if (req.req_data.attrlist[i]->name) xmlFree(req.req_data.attrlist[i]->name); if (req.req_data.attrlist[i]->id) free(req.req_data.attrlist[i]->id); if (req.req_data.attrlist[i]->enabled) free(req.req_data.attrlist[i]->enabled); if (req.req_data.pair[i]) free(req.req_data.pair[i]); } if (req.req_data.attrlist) free(req.req_data.attrlist); } break; } } /* * Find a matching entry for the given thread id. */ static thr_elem_t *match_entry(pthread_t tid) { thr_elem_t *thr = thr_list; while (thr) { if (pthread_equal(thr->thr_id, tid)) { return (thr); } thr = thr->next; } return (NULL); } /* * Add an entry to the thr_list for the given thread id. */ static int add_entry(pthread_t tid, xmlChar *doc) { thr_elem_t *new_e; thr_elem_t *thr = thr_list; if ((new_e = malloc(sizeof (thr_elem_t))) == NULL) { return (ERR_MALLOC_FAILED); } new_e->thr_id = tid; new_e->doc = doc; new_e->next = NULL; if (thr_list == NULL) { thr_list = new_e; } else { while (thr->next) { thr = thr->next; } thr->next = new_e; } return (ISNS_RSP_SUCCESSFUL); } /* * door_server -- proecess the management request and send response back * the client. * * In order to handle allocation after door_return, * a global list, thr_list, is maintained to free the response buffer * from the previous invocation of the server function on the same thread. * Note: the door framework creates a thread and the same thread is used * while a new thread is created for concurrent door_calls. * * If a thread is used once the buffer will be left allocated. */ /*ARGSUSED*/ static void door_server(void *cookie, char *argp, size_t arg_size, door_desc_t *dp, uint_t n_desc) { request_t req; xmlDocPtr x_doc; xmlChar *resp_buf = NULL; int ret, size = 0; pthread_t tid; thr_elem_t *thr; ucred_t *uc = NULL; if (ISNS_MGMT_REQUEST_RECEIVED_ENABLED()) { ISNS_MGMT_REQUEST_RECEIVED(); } if (door_ucred(&uc) != 0) { isnslog(LOG_DEBUG, "door_server", "door_ucred failed. errno: %d\n", errno); ret = build_result_message(&resp_buf, ERR_DOOR_UCRED_FAILED, &size); if (ret == ISNS_RSP_SUCCESSFUL) { (void) door_return((char *)resp_buf, size + 1, NULL, 0); /* Not reached */ } else { ret = ERR_DOOR_UCRED_FAILED; (void) door_return((void *)&ret, sizeof (ret), NULL, 0); /* Not reached */ } } isnslog(LOG_DEBUG, "door_server", "entered with request:\n %s\n", argp); if ((x_doc = xmlParseMemory(argp, arg_size)) != NULL) { isnslog(LOG_DEBUG, "door_server", "ParseMemory succeeded"); if ((ret = process_mgmt_request(x_doc, &req, uc)) == 0) { ret = build_mgmt_response(&resp_buf, req, &size); } else { ret = build_result_message(&resp_buf, ret, &size); } xmlFreeDoc(x_doc); cleanup_request(req); } else { ret = build_result_message(&resp_buf, ERR_XML_PARSE_MEMORY_FAILED, &size); } /* free the ucred */ ucred_free(uc); if (resp_buf) { tid = pthread_self(); if ((thr = match_entry(tid)) == NULL) { (void) add_entry(tid, resp_buf); } else { isnslog(LOG_DEBUG, "door_server", "free the previouly returned buffer %x on this thread\n", thr->doc); xmlFree(thr->doc); isnslog(LOG_DEBUG, "door_server", "store the currently allocated buffer %x on this thread\n", resp_buf); thr->doc = resp_buf; } isnslog(LOG_DEBUG, "door_server", "exiting with response:\n %s\n", (const char *)resp_buf); if (ISNS_MGMT_REQUEST_RESPONDED_ENABLED()) { ISNS_MGMT_REQUEST_RESPONDED(); } (void) door_return((char *)resp_buf, size + 1, NULL, 0); /* Not reached */ } isnslog(LOG_DEBUG, "door_server", "exiting only with error code %d\n", ret); if (ISNS_MGMT_REQUEST_RESPONDED_ENABLED()) { ISNS_MGMT_REQUEST_RESPONDED(); } (void) door_return((void *)&ret, sizeof (ret), NULL, 0); } /* * setup_mgmt_door -- Create a door portal for management application requests * * First check to see if another daemon is already running by attempting * to send an empty request to the door. If successful it means this * daemon should exit. */ int setup_mgmt_door(msg_queue_t *sys_q) { int fd, door_id; struct stat buf; door_arg_t darg; isnslog(LOG_DEBUG, "setup_mgmt_door", "entered"); /* check if a door is already running. */ if ((fd = open(ISNS_DOOR_NAME, 0)) >= 0) { darg.data_ptr = "" "" "" "" ""; darg.data_size = xmlStrlen((xmlChar *)darg.data_ptr); darg.desc_ptr = NULL; darg.desc_num = 0; darg.rbuf = NULL; darg.rsize = 0; if (door_call(fd, &darg) == 0) { /* door already running. */ (void) close(fd); isnslog(LOG_DEBUG, "setup_mgmt_door", "management door is already runninng."); if (darg.rsize > darg.data_size) { (void) munmap(darg.rbuf, darg.rsize); } door_created = B_FALSE; return (0); } (void) close(fd); } if ((door_id = door_create(door_server, (void *)sys_q, 0)) < 0) { isnslog(LOG_DEBUG, "setup_mgmt_door", "Failed to create managment door"); exit(1); } if (stat(ISNS_DOOR_NAME, &buf) < 0) { if ((fd = creat(ISNS_DOOR_NAME, 0666)) < 0) { isnslog(LOG_DEBUG, "setup_mgmt_door", "open failed on %s errno = %d", ISNS_DOOR_NAME, errno); exit(1); } (void) close(fd); } /* make sure the file permission set to general access. */ (void) chmod(ISNS_DOOR_NAME, 0666); (void) fdetach(ISNS_DOOR_NAME); if (fattach(door_id, ISNS_DOOR_NAME) < 0) { syslog(LOG_DEBUG, "setup_mgmt_door", "fattach failed on %s errno=%d", ISNS_DOOR_NAME, errno); return (-1); } door_created = B_TRUE; return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #ifdef DEBUG #include #endif #include "isns_server.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_log.h" #ifndef TARGET_DATA_STORE #define TARGET_DATA_STORE xml #endif #define TARGET_src(TARGET) XTARGET_src(TARGET) #define XTARGET_src(TARGET) XXTARGET_src(TARGET/data.c) #define XXTARGET_src(TARGET) #TARGET #include TARGET_src(TARGET_DATA_STORE) #define TARGET_func(func) XTARGET_func(TARGET_DATA_STORE, func) #define XTARGET_func(TARGET, func) XXTARGET_func(TARGET, func) #define XXTARGET_func(TARGET, func) TARGET ## func #ifdef DEBUG static time_t total_time = 0; static clock_t total_clock = 0; extern int verbose_tc; #endif int target_init_data( ) { return (TARGET_func(_init_data)()); } int target_load_obj( void **p, isns_obj_t **objp, uchar_t *phase ) { return (TARGET_func(_load_obj)(p, objp, phase)); } int target_add_obj( const isns_obj_t *obj ) { int status; #ifdef DEBUG time_t t; clock_t c; if (verbose_tc != 0) { t = time(NULL); c = clock(); } #endif status = TARGET_func(_add_obj)(obj); #ifdef DEBUG if (verbose_tc != 0) { t = time(NULL) - t; c = clock() - c; total_time += t; total_clock += c; printf("time %d clock %.4lf -adding one object\n", t, c / (double)CLOCKS_PER_SEC); } #endif return (status); } int target_modify_obj( const isns_obj_t *obj ) { int status; #ifdef DEBUG time_t t; clock_t c; if (verbose_tc != 0) { t = time(NULL); c = clock(); } #endif status = TARGET_func(_modify_obj)(obj); #ifdef DEBUG if (verbose_tc != 0) { t = time(NULL) - t; c = clock() - c; total_time += t; total_clock += c; printf("time %d clock %.4lf -updating one object\n", t, c / (double)CLOCKS_PER_SEC); } #endif return (status); } int target_delete_obj( const isns_obj_t *obj ) { int status; #ifdef DEBUG time_t t; clock_t c; if (verbose_tc != 0) { t = time(NULL); c = clock(); } #endif status = TARGET_func(_delete_obj)(obj); #ifdef DEBUG if (verbose_tc != 0) { t = time(NULL) - t; c = clock() - c; total_time += t; total_clock += c; printf("time %d clock %.4lf -deleting one object\n", t, c / (double)CLOCKS_PER_SEC); } #endif return (status); } int target_delete_assoc( const isns_obj_t *obj ) { int status; #ifdef DEBUG time_t t; clock_t c; if (verbose_tc != 0) { t = time(NULL); c = clock(); } #endif status = TARGET_func(_delete_assoc)(obj); #ifdef DEBUG if (verbose_tc != 0) { t = time(NULL) - t; c = clock() - c; total_time += t; total_clock += c; printf("time %d clock %.4lf -deleting one membership\n", t, c / (double)CLOCKS_PER_SEC); } #endif return (status); } int target_update_commit( ) { int status; #ifdef DEBUG time_t t; clock_t c; if (verbose_tc != 0) { t = time(NULL); c = clock(); } #endif status = TARGET_func(_update_commit)(); #ifdef DEBUG if (verbose_tc != 0) { t = time(NULL) - t; c = clock() - c; total_time += t; total_clock += c; printf("time %d clock %.4lf -flushing the data\n", t, c / (double)CLOCKS_PER_SEC); printf("time %d clock %.4lf -total update\n", total_time, total_clock / (double)CLOCKS_PER_SEC); total_time = 0; total_clock = 0; } #endif return (status); } int target_update_retreat( ) { int status; #ifdef DEBUG time_t t; clock_t c; if (verbose_tc != 0) { t = time(NULL); c = clock(); } #endif status = TARGET_func(_update_retreat)(); #ifdef DEBUG if (verbose_tc != 0) { t = time(NULL) - t; c = clock() - c; total_time += t; total_clock += c; printf("time %d clock %.4lf -flushing the data\n", t, c / (double)CLOCKS_PER_SEC); printf("time %d clock %.4lf -total update\n", total_time, total_clock / (double)CLOCKS_PER_SEC); total_time = 0; total_clock = 0; } #endif return (status); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include "isns_server.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_dsapi.h" #include "isns_dseng.h" #include "isns_msgq.h" #include "isns_log.h" #include "isns_scn.h" #include "isns_esi.h" /* * extern variables */ extern const int NUM_OF_CHILD[MAX_OBJ_TYPE]; extern const int TYPE_OF_PARENT[MAX_OBJ_TYPE_FOR_SIZE]; int init_data( ) { return (target_init_data()); } int load_data( ) { int ec = 0; void *prev = NULL; isns_obj_t *obj; uint32_t uid = 0, type = 0; uint32_t puid = 0; isns_type_t ptype = 0; void const **child[MAX_CHILD_TYPE] = { NULL }; uchar_t phase; isns_attr_t *scn_bitmap; isns_attr_t *scn_name; isns_attr_t *eid_attr; /* lock the cache */ (void) cache_lock_write(); ec = target_load_obj(&prev, &obj, &phase); while (ec == 0 && obj != NULL) { scn_bitmap = NULL; switch (obj->type) { case OBJ_DD: case OBJ_DDS: ptype = obj->type; ec = register_object(obj, &puid, NULL); break; case OBJ_ENTITY: ptype = OBJ_ENTITY; ec = register_object(obj, &puid, NULL); if (ec == 0) { eid_attr = &obj->attrs[ ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)]; ec = esi_load(puid, eid_attr->value.ptr, eid_attr->len); } break; case OBJ_ISCSI: scn_bitmap = &obj->attrs[ATTR_INDEX_ISCSI( ISNS_ISCSI_SCN_BITMAP_ATTR_ID)]; scn_name = &obj->attrs[ATTR_INDEX_ISCSI( ISNS_ISCSI_NAME_ATTR_ID)]; /* FALLTHROUGH */ case OBJ_PORTAL: if (puid != 0 && TYPE_OF_PARENT[obj->type] == ptype) { (void) set_parent_obj(obj, puid); type = obj->type; ec = register_object(obj, &uid, NULL); } else { ec = ISNS_RSP_INTERNAL_ERROR; } if (ec == 0) { ec = buff_child_obj(ptype, type, (void *)uid, child); } if (ec == 0 && scn_bitmap != NULL) { /* register scn */ ec = scn_list_load( uid, scn_name->value.ptr, scn_name->len, scn_bitmap->value.ui); } break; case OBJ_PG: if (puid != 0 && TYPE_OF_PARENT[OBJ_PG] == ptype) { (void) set_parent_obj(obj, puid); ec = register_object(obj, NULL, NULL); } else { ec = ISNS_RSP_INTERNAL_ERROR; } break; case OBJ_ASSOC_ISCSI: if (puid != 0 && TYPE_OF_PARENT[OBJ_ASSOC_ISCSI] == ptype) { /* ignore adding member to default dd */ /* during loading objects from data store */ if (puid != ISNS_DEFAULT_DD_ID) { (void) set_parent_obj(obj, puid); ec = add_dd_member(obj); } } else { ec = ISNS_RSP_INTERNAL_ERROR; } free_object(obj); break; case OBJ_ASSOC_DD: if (puid != 0 && TYPE_OF_PARENT[OBJ_ASSOC_DD] == ptype) { /* ignore adding member to default dd-set */ /* and adding default dd to any dd-set */ /* during loading objects from data store */ if (puid != ISNS_DEFAULT_DD_SET_ID && get_obj_uid(obj) != ISNS_DEFAULT_DD_ID) { (void) set_parent_obj(obj, puid); ec = add_dds_member(obj); } } else { ec = ISNS_RSP_INTERNAL_ERROR; } free_object(obj); break; default: ASSERT(0); ec = ISNS_RSP_INTERNAL_ERROR; break; } if (ec == 0) { ec = target_load_obj(&prev, &obj, &phase); } if (ec == 0 && puid != 0 && NUM_OF_CHILD[ptype] > 0 && (obj == NULL || TYPE_OF_PARENT[obj->type] != ptype)) { ec = update_child_obj(ptype, puid, child, 0); } } /* unlock the cache */ (void) cache_unlock_sync(0); /* free the child buffer */ uid = 0; while (uid < MAX_CHILD_TYPE) { if (child[uid] != NULL) { free(child[uid]); } uid ++; } return (ec); } int write_data( int op, const isns_obj_t *obj ) { int ec = 0; switch (op) { case DATA_ADD: ec = target_add_obj(obj); break; case DATA_UPDATE: ec = target_modify_obj(obj); break; case DATA_DELETE: ec = target_delete_obj(obj); break; case DATA_DELETE_ASSOC: ec = target_delete_assoc(obj); break; case DATA_COMMIT: ec = target_update_commit(); break; case DATA_RETREAT: ec = target_update_retreat(); break; default: break; } return (ec); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2025 OmniOS Community Edition (OmniOSce) Association. */ /* This file is getting large unexpectly, a lex & yacc */ /* implementation is expected. */ #include #include #include #include #include #include #include #include #include #include #include #include "isns_server.h" #include "isns_htab.h" #include "isns_msgq.h" #include "isns_obj.h" #include "isns_func.h" #include "isns_dd.h" #include "isns_cache.h" #include "isns_pdu.h" #ifdef DEBUG /* * external variables */ extern const int NUM_OF_CHILD[MAX_OBJ_TYPE]; extern const int TYPE_OF_CHILD[MAX_OBJ_TYPE][MAX_CHILD_TYPE]; extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; extern const int NUM_OF_REF[MAX_OBJ_TYPE_FOR_SIZE]; extern lookup_ctrl_t *setup_ddid_lcp(lookup_ctrl_t *, uint32_t); extern lookup_ctrl_t *setup_ddsid_lcp(lookup_ctrl_t *, uint32_t); /* * global variables */ int verbose_mc = 0; int verbose_tc = 0; int verbose_lock = 0; int verbose_net = 0; int verbose_parser = 0; /* * local variables */ static void print_entity(char *, isns_obj_t *); static void print_iscsi(char *, isns_obj_t *); static void print_portal(char *, isns_obj_t *); static void print_pg(char *, isns_obj_t *); static void print_dd(char *, isns_obj_t *); static void print_dds(char *, isns_obj_t *); static void (*const print_func[MAX_OBJ_TYPE])(char *, isns_obj_t *) = { NULL, &print_entity, &print_iscsi, &print_portal, &print_pg, &print_dd, &print_dds }; static int run_cmd(char *); typedef struct { uint16_t func_id; char *fname; } isnsp_fnames_t; isnsp_fnames_t fnames[] = { { ISNS_DEV_ATTR_REG, "DevAttrReg" }, { ISNS_DEV_ATTR_QRY, "DevAttrQry" }, { ISNS_DEV_GET_NEXT, "DevGetNext" }, { ISNS_DEV_DEREG, "DevDereg" }, { ISNS_SCN_REG, "SCNReg" }, { ISNS_SCN_DEREG, "SCNDereg" }, { ISNS_DD_REG, "DDReg" }, { ISNS_DD_DEREG, "DDDereg" }, { ISNS_DDS_REG, "DDSReg" }, { ISNS_DDS_DEREG, "DDSDereg" }, { ISNS_SCN, "SCN" }, { ISNS_ESI, "ESI" }, { ISNS_HEARTBEAT, "Heartbeat" }, { ISNS_DEV_ATTR_REG_RSP, "DevAttrRegRsp" }, { ISNS_DEV_ATTR_QRY_RSP, "DevAttrQryRsp" }, { ISNS_DEV_GET_NEXT_RSP, "DevGetNextRsp" }, { ISNS_DEV_DEREG_RSP, "DevDeregRsp" }, { ISNS_SCN_REG_RSP, "SCNRegRsp" }, { ISNS_SCN_DEREG_RSP, "SCNDeregRsp" }, { ISNS_SCN_RSP, "SCNRsp" }, { ISNS_ESI_RSP, "ESIRsp" }, { 0xFFFF, "Unknown" } }; static char * get_func_name( uint16_t id ) { int i = 0; isnsp_fnames_t *fp = &fnames[i ++]; while (fp->func_id != 0xFFFF) { if (fp->func_id == id) { return (fp->fname); } fp = &fnames[i ++]; } return ("UNKNOWN"); } static char * get_tlv_tag_name( uint32_t tag ) { switch (tag) { case ISNS_DELIMITER_ATTR_ID: return ("Delimiter"); case ISNS_EID_ATTR_ID: return ("Entity Identifier"); case ISNS_ENTITY_PROTOCOL_ATTR_ID: return ("Entity Protocol"); case ISNS_ENTITY_REG_PERIOD_ATTR_ID: return ("Registration Period"); case ISNS_TIMESTAMP_ATTR_ID: return ("Timestamp"); case ISNS_PORTAL_IP_ADDR_ATTR_ID: return ("Portal IP Address"); case ISNS_PORTAL_PORT_ATTR_ID: return ("Portal TCP/UDP Port"); case ISNS_PORTAL_NAME_ATTR_ID: return ("Portal Symbolic Name"); case ISNS_ESI_INTERVAL_ATTR_ID: return ("ESI Interval"); case ISNS_ESI_PORT_ATTR_ID: return ("ESI Port"); case ISNS_SCN_PORT_ATTR_ID: return ("SCN Port"); case ISNS_PORTAL_SEC_BMP_ATTR_ID: return ("Portal Security Bitmap"); case ISNS_ISCSI_NAME_ATTR_ID: return ("iSCSI Name"); case ISNS_ISCSI_NODE_TYPE_ATTR_ID: return ("iSCSI Node Type"); case ISNS_ISCSI_ALIAS_ATTR_ID: return ("iSCSI Alias"); case ISNS_ISCSI_AUTH_METHOD_ATTR_ID: return ("iSCSI Auth Method"); case ISNS_ISCSI_SCN_BITMAP_ATTR_ID: return ("iSCSI SCN Bitmap"); case ISNS_PG_ISCSI_NAME_ATTR_ID: return ("PG iSCSI Name"); case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: return ("PG Portal IP Addr"); case ISNS_PG_PORTAL_PORT_ATTR_ID: return ("PG Portal TCP/UDP Port"); case ISNS_PG_TAG_ATTR_ID: return ("PG Tag (PGT)"); case ISNS_PG_INDEX_ATTR_ID: return ("PG Index"); case ISNS_DD_NAME_ATTR_ID: return ("DD Name"); case ISNS_DD_ID_ATTR_ID: return ("DD Index"); case ISNS_DD_ISCSI_INDEX_ATTR_ID: return ("DD ISCSI Node Index"); case ISNS_DD_ISCSI_NAME_ATTR_ID: return ("DD ISCSI Node Name"); case ISNS_DD_SET_NAME_ATTR_ID: return ("DDS Name"); case ISNS_DD_SET_ID_ATTR_ID: return ("DDS Index"); case ISNS_DD_SET_STATUS_ATTR_ID: return ("DDS Status"); default: return ("Unknown"); } } static void dump_pdu( isns_pdu_t *pdu, int flag ) { short ver, id, len, flags, xid, seq; uint8_t *payload = pdu->payload; isns_resp_t *resp; /* convert the data */ if (flag) { ver = ntohs(pdu->version); id = ntohs(pdu->func_id); len = ntohs(pdu->payload_len); flags = ntohs(pdu->flags) & 0xFFFF; xid = ntohs(pdu->xid); seq = ntohs(pdu->seq); } else { ver = pdu->version; id = pdu->func_id; len = pdu->payload_len; flags = pdu->flags & 0xFFFF; xid = pdu->xid; seq = pdu->seq; } /* print the pdu header */ printf("iSNSP Version: %d\n", ver); printf("Function ID: %s\n", get_func_name(id)); printf("PDU Length: %d\n", len); printf("Flags: %x\n", flags); printf(" %d... .... .... .... : ISNS_FLAG_CLIENT\n", ((flags & ISNS_FLAG_CLIENT) == 0) ? 0 : 1); printf(" .%d.. .... .... .... : ISNS_FLAG_SERVER\n", ((flags & ISNS_FLAG_SERVER) == 0) ? 0 : 1); printf(" ..%d. .... .... .... : ISNS_FLAG_AUTH_BLK_PRESENTED\n", ((flags & ISNS_FLAG_AUTH_BLK_PRESENTED) == 0) ? 0 : 1); printf(" ...%d .... .... .... : ISNS_FLAG_REPLACE_REG\n", ((flags & ISNS_FLAG_REPLACE_REG) == 0) ? 0 : 1); printf(" .... %d... .... .... : ISNS_FLAG_LAST_PDU\n", ((flags & ISNS_FLAG_LAST_PDU) == 0) ? 0 : 1); printf(" .... .%d.. .... .... : ISNS_FLAG_FIRST_PDU\n", ((flags & ISNS_FLAG_FIRST_PDU) == 0) ? 0 : 1); printf("Transaction ID: %d\n", xid); printf("Sequence ID: %d\n", seq); printf("Payload: ...\n"); if (id & ISNS_RSP_MASK) { resp = (isns_resp_t *)payload; printf(" ErrorCode: %d\n", ntohl(resp->status)); len -= 4; payload += 4; } /* print the payload */ while (len > 0) { isns_tlv_t *tlvp; int t, l; uint8_t *v; char *s; int i; in6_addr_t *ip; char pbuff[256] = { 0 }; tlvp = (isns_tlv_t *)payload; /* convert the data */ t = ntohl(tlvp->attr_id); l = ntohl(tlvp->attr_len); v = &(tlvp->attr_value[0]); /* print payload */ if (l > 0) { printf("%s: ", get_tlv_tag_name(t)); switch (t) { 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_DD_NAME_ATTR_ID: case ISNS_DD_SET_NAME_ATTR_ID: s = (char *)v; printf("%s\n", s); break; case ISNS_ENTITY_PROTOCOL_ATTR_ID: i = ntohl(*(uint32_t *)v); printf("%s (%d)\n", ((i == 1) ? "No Protocol" : ((i == 2) ? "iSCSI" : ((i == 3) ? "iFCP" : "Others"))), i); break; case ISNS_PORTAL_IP_ADDR_ATTR_ID: case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: ip = (in6_addr_t *)v; inet_ntop(AF_INET6, (void *)ip, pbuff, sizeof (pbuff)); printf("%s\n", pbuff); break; case ISNS_PORTAL_PORT_ATTR_ID: case ISNS_ESI_PORT_ATTR_ID: case ISNS_SCN_PORT_ATTR_ID: i = ntohl(*(uint32_t *)v); printf("%d\n", (i & 0x0000FFFF)); printf(" .... .... %d... .... : " "0=TCP\n", ((i & 0x10000) == 0) ? 0 : 1); break; case ISNS_ISCSI_NODE_TYPE_ATTR_ID: i = ntohl(*(uint32_t *)v); printf("0x%x\t", i); if (i & ISNS_CONTROL_NODE_TYPE) { printf("Control "); } if (i & ISNS_INITIATOR_NODE_TYPE) { printf("Initiator "); } if (i & ISNS_TARGET_NODE_TYPE) { printf("Target "); } printf("\n"); break; case ISNS_PG_TAG_ATTR_ID: default: i = ntohl(*(uint32_t *)v); printf("%d\n", i); break; } printf(" Attribute Tag: %s (%d)\n", get_tlv_tag_name(t), t); printf(" Attribute Length: %d\n", l); } else { printf("%s: (%d)\n", get_tlv_tag_name(t), t); } len -= (sizeof (uint32_t) * 2 + l); payload += (sizeof (uint32_t) * 2 + l); } } void dump_pdu1( isns_pdu_t *pdu ) { if (verbose_net) { printf("### PDU RECEIVED ###\n"); dump_pdu(pdu, 0); } } void dump_pdu2( isns_pdu_t *pdu ) { if (verbose_net) { printf("### PDU SENT ###\n"); dump_pdu(pdu, 1); } } void dump_db( ) { #if 0 isns_list_t *list, *lista, *listb; isns_dds_t *dds; isns_dd_t *dd; isns_iscsi2_t *iscsi2; printf("### DUMP DATABASE ###\n"); /* dump dds(s) */ list = dds_list; while (list != NULL) { dds = list->obj.dds; printf("[DDS:%d]%s(%s)\n", dds->id, dds->name, dds->status ? "enabled" : "disabled"); lista = dds->dd_list; /* dd(s) that belong to this dds */ while (lista != NULL) { dd = lista->obj.dd; printf("\t[DD:%d]%s\n", dd->id, dd->name); lista = lista->next; } list = list->next; } /* dump dd(s) */ list = dd_list; while (list != NULL) { dd = list->obj.dd; printf("[DD:%d]%s\n", dd->id, dd->name); /* dds(s) this dd belongs to */ lista = dd->dds_list; while (lista != NULL) { dds = lista->obj.dds; printf("\t[DDS:%d]%s\n", dds->id, dds->name); lista = lista->next; } /* node(s) that this dd have */ listb = dd->iscsi_list; while (listb != NULL) { iscsi2 = listb->obj.iscsi2; printf("\t[ISCSI:%d]%s\n", iscsi2->id, iscsi2->name); listb = listb->next; } list = list->next; } /* dump node(s) */ list = iscsi_list; while (list != NULL) { iscsi2 = list->obj.iscsi2; printf("[ISCSI:%d]%s\n", iscsi2->id, iscsi2->name); lista = iscsi2->dd_list; /* dd(s) that this node belongs to */ while (lista != NULL) { dd = lista->obj.dd; printf("\t[DD:%d]%s\n", dd->id, dd->name); lista = lista->next; } list = list->next; } #endif } static void test_cli_help( ) { printf("list - list all of storage node.\n"); printf("list dd [id] - list all of dd or one with member.\n"); printf("list dds [id] - list all of dd-set or one with member.\n"); printf("\n"); printf("new dd - create a dd with name.\n"); printf("new dds - create a dd-set with name.\n"); printf("new ddn - create a dd with id and name.\n"); printf("new ddsn - create a dd-set with id and name.\n"); printf("del dd - delete a dd.\n"); printf("del dds - delete a dd-set.\n"); printf("\n"); printf("add dd - add a node to dd.\n"); printf("add ddn - add a node to dd.\n"); printf("add ddsn - add a dd to dd-set.\n"); printf("remove dd - remove a node from dd.\n"); printf("remove ddn - remove a node from dd.\n"); printf("remove ddsn - remove a dd from dd-set.\n"); printf("\n"); printf("enable - enable a dd-set.\n"); printf("disable - disable a dd-set.\n"); printf("\n"); printf("file - loading command from a file.\n"); printf("pause - suspend batch until enter key is pressed.\n"); printf("help - print this help.\n"); printf("quit - stop iSNS server and quit.\n"); } enum { CMD_LIST, CMD_LISTNE, CMD_LISTP, CMD_LISTPG, CMD_LISTDD, CMD_LISTDDS, CMD_LISTDDN, CMD_LISTDDSN, CMD_NEWDD, CMD_NEWDDS, CMD_NEWDDN, CMD_NEWDDSN, CMD_DELDD, CMD_DELDDS, CMD_ENABLE, CMD_DISABLE, CMD_ADDDD, CMD_ADDDDN, CMD_ADDDDSN, CMD_REMDD, CMD_REMDDN, CMD_REMDDSN, CMD_VIEW, CMD_FILE, CMD_PAUSE, CMD_HELP, CMD_VERBOSE_MEMORY, CMD_VERBOSE_NET, CMD_VERBOSE_PARSER, CMD_VERBOSE_TIME, CMD_VERBOSE_LOCK, CMD_QUIT, CMD_NONE, CMD_INVALID }; static int getcmd( int *argc, int *argv, char *cmd ) { int j = 0; char tmp[256] = { 0 }; *argc = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_NONE); } else if (*cmd == '?') { return (CMD_HELP); } /* list, list dd, list dds, list dd 0 */ if (strncmp(cmd, "list ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LIST); } else if (*cmd == 'p') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTP); } } else if (*cmd == 'g') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTPG); } } else if (*cmd == 'e') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTNE); } } else if (strncmp(cmd, "dds ", 4) == 0) { cmd += 4; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTDDS); } j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_LISTDDSN); } } else if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTDD); } j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_LISTDDN); } } return (CMD_INVALID); } /* view 0 */ if (strncmp(cmd, "view ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_VIEW); } return (CMD_INVALID); } /* add dd name */ /* add ddn/ddsn id id */ if (strncmp(cmd, "add ", 4) == 0) { int addcmd = CMD_INVALID; cmd += 4; while (*cmd == ' ') cmd ++; if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; addcmd = CMD_ADDDD; } else if (strncmp(cmd, "ddn ", 4) == 0) { cmd += 4; addcmd = CMD_ADDDDN; } else if (strncmp(cmd, "ddsn ", 5) == 0) { cmd += 5; addcmd = CMD_ADDDDSN; } else { return (CMD_INVALID); } while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; if (j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } while (*cmd == ' ') cmd ++; if (*cmd != 0) { switch (addcmd) { case CMD_ADDDDN: case CMD_ADDDDSN: j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } break; case CMD_ADDDD: j = strlen(cmd); while (j > 0) { /* get rid of trail blank space */ if (cmd[j - 1] == ' ') { cmd[--j] = 0; } else { break; } } if (j > 0) { cmd[j] = 0; argv[(*argc)++] = (int)cmd; } else { return (CMD_INVALID); } break; } return (addcmd); } return (CMD_INVALID); } /* remove dd name */ /* remove ddn/ddsn id id */ if (strncmp(cmd, "remove ", 7) == 0) { int rmcmd = CMD_INVALID; cmd += 7; while (*cmd == ' ') cmd ++; if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; while (*cmd == ' ') cmd ++; rmcmd = CMD_REMDD; } else if (strncmp(cmd, "ddn ", 4) == 0) { cmd += 4; while (*cmd == ' ') cmd ++; rmcmd = CMD_REMDDN; } else if (strncmp(cmd, "ddsn ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; rmcmd = CMD_REMDDSN; } else { return (CMD_INVALID); } j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; if (j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } while (*cmd == ' ') cmd ++; if (*cmd != 0) { switch (rmcmd) { case CMD_REMDDN: case CMD_REMDDSN: j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } break; case CMD_REMDD: j = strlen(cmd); while (j > 0) { /* get rid of trail blank space */ if (cmd[j - 1] == ' ') { cmd[--j] = 0; } else { break; } } if (j > 0) { cmd[j] = 0; argv[(*argc)++] = (int)cmd; } else { return (CMD_INVALID); } break; } return (rmcmd); } return (CMD_INVALID); } /* new dd, new dds */ if (strncmp(cmd, "new ", 4) == 0) { int newcmd = CMD_INVALID; cmd += 4; while (*cmd == ' ') cmd ++; if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; newcmd = CMD_NEWDD; } else if (strncmp(cmd, "dds ", 4) == 0) { cmd += 4; newcmd = CMD_NEWDDS; } else if (strncmp(cmd, "ddn ", 4) == 0) { cmd += 4; newcmd = CMD_NEWDDN; } else if (strncmp(cmd, "ddsn ", 5) == 0) { cmd += 5; newcmd = CMD_NEWDDSN; } if (newcmd != CMD_INVALID) { while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (newcmd); } switch (newcmd) { case CMD_NEWDDN: case CMD_NEWDDSN: j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; if (*cmd == ' ' && j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } case CMD_NEWDD: case CMD_NEWDDS: while (*cmd == ' ') cmd ++; if (*cmd != 0) { j = strlen(cmd); } else { j = 0; } while (j > 0) { /* get rid of trail blank space */ if (cmd[j - 1] == ' ') { cmd[--j] = 0; } else { break; } } if (j > 0) { cmd[j] = 0; argv[(*argc)++] = (int)cmd; } } return (newcmd); } return (CMD_INVALID); } /* del dd, del dds, disable 0 */ if (strncmp(cmd, "del ", 4) == 0) { int delcmd = CMD_INVALID; cmd += 4; while (*cmd == ' ') cmd ++; if (strncmp(cmd, "dds ", 4) == 0) { cmd += 4; delcmd = CMD_DELDDS; } else if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; delcmd = CMD_DELDD; } if (delcmd != CMD_INVALID) { while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (delcmd); } } return (CMD_INVALID); } /* enable 0 */ if (strncmp(cmd, "enable ", 7) == 0) { cmd += 7; while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_ENABLE); } return (CMD_INVALID); } /* disable 0 */ if (strncmp(cmd, "disable ", 8) == 0) { cmd += 8; while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_DISABLE); } return (CMD_INVALID); } /* file */ if (strncmp(cmd, "file ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; if (*cmd != 0) { j = strlen(cmd); } else { j = 0; } while (j > 0) { /* get rid of trail blank space */ if (cmd[j - 1] == ' ') { cmd[--j] = 0; } else { break; } } if (j > 0) { cmd[j] = 0; argv[(*argc)++] = (int)cmd; return (CMD_FILE); } return (CMD_INVALID); } /* pause */ if (strncmp(cmd, "pause ", 6) == 0) { cmd += 6; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_PAUSE); } return (CMD_INVALID); } /* help */ if (strncmp(cmd, "help ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_HELP); } return (CMD_INVALID); } /* verbose */ if (strncmp(cmd, "verbose ", 8) == 0) { cmd += 8; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_PARSER); } else if (*cmd == 'm') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_MEMORY); } } else if (*cmd == 'n') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_NET); } } else if (*cmd == 'p') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_PARSER); } } else if (*cmd == 't') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_TIME); } } else if (*cmd == 'l') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_LOCK); } } return (CMD_INVALID); } /* quit */ if (strncmp(cmd, "quit ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_QUIT); } return (CMD_INVALID); } return (CMD_INVALID); } static void print_entity( char *ident, isns_obj_t *obj ) { uint32_t uid; uchar_t *eid; uint32_t *cuid; int i, num; eid = obj->attrs[ ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)].value.ptr; uid = get_obj_uid(obj); if (ident != NULL) { printf("%s%d\t%s\n", ident, uid, (const char *)eid); } else { printf("%d\t%s\n", uid, (const char *)eid); } i = 0; while (i < NUM_OF_CHILD[obj->type]) { cuid = get_child_n(obj, i); if (ident != NULL) { printf("%s\t%s%d:", "child", i); } else { printf("\t%s%d:", "child", i); } if (cuid != NULL) { num = *cuid ++; } else { num = 0; } while (num > 0) { printf("\t%d", *cuid ++); num --; } printf("\n"); i ++; } } static void print_iscsi( char *ident, isns_obj_t *obj ) { uchar_t *name = obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)] .value.ptr; uchar_t *alias = obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_ALIAS_ATTR_ID)] .value.ptr; uint32_t type = obj->attrs[ ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)].value.ui; uint32_t uid = get_obj_uid(obj); uint32_t puid = get_parent_uid(obj); if (!alias) { alias = (uchar_t *)"-"; } if (ident != NULL) { printf("%s%d[%d]\t%s\n", ident, uid, puid, (const char *)name); printf("%s\t%s", ident, alias); } else { printf("%d[%d]\t%s\n", uid, puid, (const char *)name); printf("\t%s", alias); } if (IS_TYPE_TARGET(type)) { printf("\tTarget"); } if (IS_TYPE_INITIATOR(type)) { printf("\tInitiator"); } if (IS_TYPE_CONTROL(type)) { printf("\tControl"); } if (IS_TYPE_UNKNOWN(type)) { printf("\t-"); } printf("\n"); } static void print_portal( char *ident, isns_obj_t *obj ) { char pbuff[256] = { 0 }; in6_addr_t *ip = obj->attrs[ ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID)].value.ip; uint32_t port = obj->attrs[ ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID)].value.ui; uint32_t uid = get_obj_uid(obj); uint32_t puid = get_parent_uid(obj); inet_ntop(AF_INET6, (void *)ip, pbuff, sizeof (pbuff)); if (ident != NULL) { printf("%s%d[%d]\t%s:%d", ident, uid, puid, pbuff, PORT_NUMBER(port)); } else { printf("%d[%d]\t%s:%d", uid, puid, pbuff, PORT_NUMBER(port)); } printf(" %s\n", IS_PORT_UDP(port) ? "UDP" : "TCP"); } static void print_pg( char *ident, isns_obj_t *obj ) { uint32_t ref; int i; char pbuff[256] = { 0 }; uchar_t *name = obj->attrs[ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID)] .value.ptr; in6_addr_t *ip = obj->attrs[ ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)].value.ip; uint32_t port = obj->attrs[ ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID)].value.ui; uint32_t tag = obj->attrs[ ATTR_INDEX_PG(ISNS_PG_TAG_ATTR_ID)].value.ui; uint32_t uid = get_obj_uid(obj); uint32_t puid = get_parent_uid(obj); inet_ntop(AF_INET6, (void *)ip, pbuff, sizeof (pbuff)); if (ident != NULL) { printf("%s%d[%d]\t[%d] %s\n", ident, uid, puid, tag, (const char *)name); printf("%s\t%s:%d", ident, pbuff, PORT_NUMBER(port)); } else { printf("%d[%d]\t[%d] %s\n", uid, puid, tag, (const char *)name); printf("\t%s:%d", pbuff, PORT_NUMBER(port)); } printf(" %s\n", IS_PORT_UDP(port) ? "UDP" : "TCP"); if (NUM_OF_REF[obj->type] > 0) { if (ident != NULL) { printf("%s\t%s:", "ref"); } else { printf("\t%s:", "ref"); } } i = 0; while (i < NUM_OF_REF[obj->type]) { ref = get_ref_n(obj, i); printf("\t%d", ref); i ++; } if (i > 0) { printf("\n"); } } static void print_dd( char *ident, isns_obj_t *obj ) { uchar_t *name = obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)] .value.ptr; uint32_t uid = obj->attrs[UID_ATTR_INDEX[OBJ_DD]].value.ui; if (ident != NULL) { printf("%s%d\t%s\n", ident, uid, (const char *)name); } else { printf("%d\t%s\n", uid, (const char *)name); } } static void print_dds( char *ident, isns_obj_t *obj ) { uchar_t *name = obj->attrs[ATTR_INDEX_DDS( ISNS_DD_SET_NAME_ATTR_ID)].value.ptr; uint32_t uid = obj->attrs[UID_ATTR_INDEX[OBJ_DDS]].value.ui; uint32_t enabled = obj->attrs[ATTR_INDEX_DDS( ISNS_DD_SET_STATUS_ATTR_ID)].value.ui; if (ident != NULL) { printf("%s%d\t%s\t\t(%s)\n", ident, uid, (const char *)name, enabled ? "enabled" : "disabled"); } else { printf("%d\t%s\t\t(%s)\n", uid, (const char *)name, enabled ? "enabled" : "disabled"); } } void print_object( char *ident, isns_obj_t *obj ) { print_func[obj->type](ident, obj); } /*ARGSUSED*/ static int cb_print_obj_n( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; print_func[obj->type](NULL, obj); return (0); } static void list_pg( ) { cache_dump_htab(OBJ_PG); } static void list_portal( ) { cache_dump_htab(OBJ_PORTAL); } static void list_node( ) { cache_dump_htab(OBJ_ISCSI); } static void list_entity( ) { cache_dump_htab(OBJ_ENTITY); } static void list_dd( ) { cache_dump_htab(OBJ_DD); } static void list_ddn( uint32_t uid ) { lookup_ctrl_t lc; bmp_t *p; uint32_t n; if (uid != 0) { setup_ddid_lcp(&lc, uid); cache_lookup(&lc, &uid, cb_print_obj_n); } if (uid != 0) { printf("--------------------------------\n"); get_dd_matrix(uid, &p, &n); SET_UID_LCP(&lc, OBJ_ISCSI, 0); FOR_EACH_MEMBER(p, n, uid, { lc.data[0].ui = uid; cache_lookup(&lc, NULL, cb_print_obj_n); }); free(p); } else { printf("no such dd.\n"); } } static void list_ddsn( uint32_t uid ) { lookup_ctrl_t lc; bmp_t *p; uint32_t n; if (uid != 0) { setup_ddsid_lcp(&lc, uid); cache_lookup(&lc, &uid, cb_print_obj_n); } if (uid != 0) { printf("--------------------------------\n"); get_dds_matrix(uid, &p, &n); SET_UID_LCP(&lc, OBJ_DD, 0); FOR_EACH_MEMBER(p, n, uid, { lc.data[0].ui = uid; cache_lookup(&lc, NULL, cb_print_obj_n); }); free(p); } else { printf("no such dd-set.\n"); } } static void list_dds( ) { cache_dump_htab(OBJ_DDS); } static void new_dd_dds( int cmd_id, int argc, int *argv ) { uint32_t buff[256]; isns_pdu_t *pdu = (isns_pdu_t *)buff; uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = 0; isns_tlv_t *tlv; int len = 0; uint32_t uid = 0; char *name; conn_arg_t conn; pdu->version = ISNSP_VERSION; /* source attribute */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID); tlv->attr_len = htonl(32); strcpy((char *)tlv->attr_value, "i am a control node."); payload += 8 + 32; payload_len += 8 + 32; /* key attributes */ /* delimiter */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID); tlv->attr_len = htonl(0); payload += 8 + 0; payload_len += 8 + 0; /* operating attributes */ switch (cmd_id) { case CMD_NEWDD: pdu->func_id = ISNS_DD_REG; if (argc == 1) { name = (char *)argv[0]; len = strlen(name) + 1; len += 4 - (len % 4); } tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_NAME_ATTR_ID); tlv->attr_len = htonl(len); if (len > 0) { strcpy((char *)tlv->attr_value, name); } payload_len += 8 + len; break; case CMD_NEWDDS: pdu->func_id = ISNS_DDS_REG; if (argc == 1) { name = (char *)argv[0]; len = strlen(name) + 1; len += 4 - (len % 4); } tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_NAME_ATTR_ID); tlv->attr_len = htonl(len); if (len > 0) { strcpy((char *)tlv->attr_value, name); } payload_len += 8 + len; break; case CMD_NEWDDN: pdu->func_id = ISNS_DD_REG; switch (argc) { case 2: name = (char *)argv[1]; len = strlen(name) + 1; len += 4 - (len % 4); /* FALLTHROUGH */ case 1: uid = argv[0]; } tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_NAME_ATTR_ID); tlv->attr_len = htonl(len); if (len > 0) { strcpy((char *)tlv->attr_value, name); } payload += 8 + len; payload_len += 8 + len; if (uid > 0) { tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_ID_ATTR_ID); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; } break; case CMD_NEWDDSN: pdu->func_id = ISNS_DDS_REG; switch (argc) { case 2: name = (char *)argv[1]; len = strlen(name) + 1; len += 4 - (len % 4); /* FALLTHROUGH */ case 1: uid = argv[0]; } tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_NAME_ATTR_ID); tlv->attr_len = htonl(len); if (len > 0) { strcpy((char *)tlv->attr_value, name); } payload_len += 8 + len; payload += 8 + len; if (uid > 0) { tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_ID_ATTR_ID); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; } break; default: break; } pdu->payload_len = payload_len; dump_pdu1(pdu); conn.in_packet.pdu = pdu; conn.out_packet.pdu = NULL; conn.out_packet.sz = 0; if (packet_split_verify(&conn) == 0) { cache_lock(conn.lock); conn.handler(&conn); conn.ec = cache_unlock(conn.lock, conn.ec); } if (conn.out_packet.pdu != NULL) { pdu_update_code(conn.out_packet.pdu, &conn.out_packet.pl, conn.ec); dump_pdu2(conn.out_packet.pdu); free(conn.out_packet.pdu); } else if (conn.ec != 0) { printf("operation failed[%d].\n", conn.ec); } } static void del_dd_dds( int cmd_id, int uid ) { uint32_t buff[256]; isns_pdu_t *pdu = (isns_pdu_t *)buff; uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = 0; isns_tlv_t *tlv; uint32_t tag; conn_arg_t conn; if (uid == 0) { return; } pdu->version = ISNSP_VERSION; if (cmd_id == CMD_DELDD) { tag = ISNS_DD_ID_ATTR_ID; pdu->func_id = ISNS_DD_DEREG; } else { tag = ISNS_DD_SET_ID_ATTR_ID; pdu->func_id = ISNS_DDS_DEREG; } /* source attribute */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID); tlv->attr_len = htonl(32); strcpy((char *)tlv->attr_value, "i am a control node."); payload_len += 8 + 32; payload += 8 + 32; /* key attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(tag); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; payload += 8 + 4; /* delimiter */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID); tlv->attr_len = htonl(0); payload_len += 8 + 0; payload += 8 + 0; /* operating attributes */ pdu->payload_len = payload_len; dump_pdu1(pdu); conn.in_packet.pdu = pdu; conn.out_packet.pdu = NULL; conn.out_packet.sz = 0; if (packet_split_verify(&conn) == 0) { cache_lock(conn.lock); conn.handler(&conn); conn.ec = cache_unlock(conn.lock, conn.ec); } if (conn.out_packet.pdu != NULL) { pdu_update_code(conn.out_packet.pdu, &conn.out_packet.pl, conn.ec); dump_pdu2(conn.out_packet.pdu); free(conn.out_packet.pdu); } else if (conn.ec != 0) { printf("operation failed[%d].\n", conn.ec); } } static void update_dds( int cmd_id, int uid ) { uint32_t buff[256]; isns_pdu_t *pdu = (isns_pdu_t *)buff; uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = 0; isns_tlv_t *tlv; conn_arg_t conn; if (uid == 0) { return; } pdu->version = ISNSP_VERSION; pdu->func_id = ISNS_DDS_REG; /* source attribute */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID); tlv->attr_len = htonl(32); strcpy((char *)tlv->attr_value, "i am a control node."); payload_len += 8 + 32; payload += 8 + 32; /* key attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_ID_ATTR_ID); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; payload += 8 + 4; /* delimiter */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID); tlv->attr_len = htonl(0); payload_len += 8 + 0; payload += 8 + 0; /* operating attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_STATUS_ATTR_ID); tlv->attr_len = htonl(4); if (cmd_id == CMD_ENABLE) { *(uint32_t *)tlv->attr_value = htonl(1); } else { *(uint32_t *)tlv->attr_value = htonl(0); } payload_len += 8 + 4; pdu->payload_len = payload_len; dump_pdu1(pdu); conn.in_packet.pdu = pdu; conn.out_packet.pdu = NULL; conn.out_packet.sz = 0; if (packet_split_verify(&conn) == 0) { cache_lock(conn.lock); conn.handler(&conn); conn.ec = cache_unlock(conn.lock, conn.ec); } if (conn.out_packet.pdu != NULL) { pdu_update_code(conn.out_packet.pdu, &conn.out_packet.pl, conn.ec); dump_pdu2(conn.out_packet.pdu); free(conn.out_packet.pdu); } else if (conn.ec != 0) { printf("operation failed[%d].\n", conn.ec); } } static void update_member( int cmd_id, int *argv ) { uint32_t buff[256]; isns_pdu_t *pdu = (isns_pdu_t *)buff; uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = 0; isns_tlv_t *tlv; uint32_t key_tag, op_tag, op_len; uint32_t uid = argv[0]; uint32_t m_id; char *m_name; conn_arg_t conn; if (uid == 0) { printf("operation failed.\n"); return; } pdu->version = ISNSP_VERSION; switch (cmd_id) { case CMD_ADDDD: case CMD_ADDDDN: pdu->func_id = ISNS_DD_REG; break; case CMD_REMDD: case CMD_REMDDN: pdu->func_id = ISNS_DD_DEREG; break; case CMD_ADDDDSN: pdu->func_id = ISNS_DDS_REG; break; case CMD_REMDDSN: pdu->func_id = ISNS_DDS_DEREG; break; } switch (cmd_id) { case CMD_ADDDD: case CMD_REMDD: key_tag = ISNS_DD_ID_ATTR_ID; op_tag = ISNS_DD_ISCSI_NAME_ATTR_ID; m_name = (char *)argv[1]; op_len = strlen(m_name); op_len += 4 - (op_len % 4); break; case CMD_ADDDDN: case CMD_REMDDN: key_tag = ISNS_DD_ID_ATTR_ID; op_tag = ISNS_DD_ISCSI_INDEX_ATTR_ID; m_id = argv[1]; op_len = 4; break; case CMD_ADDDDSN: case CMD_REMDDSN: key_tag = ISNS_DD_SET_ID_ATTR_ID; op_tag = ISNS_DD_ID_ATTR_ID; m_id = argv[1]; op_len = 4; break; } /* source attribute */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID); tlv->attr_len = htonl(32); strcpy((char *)tlv->attr_value, "i am a control node."); payload_len += 8 + 32; payload += 8 + 32; /* key attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(key_tag); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; payload += 8 + 4; /* delimiter */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID); tlv->attr_len = htonl(0); payload_len += 8 + 0; payload += 8 + 0; /* operating attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(op_tag); tlv->attr_len = htonl(op_len); switch (cmd_id) { case CMD_ADDDD: case CMD_REMDD: strcpy((char *)tlv->attr_value, m_name); break; case CMD_ADDDDN: case CMD_ADDDDSN: case CMD_REMDDN: case CMD_REMDDSN: *(uint32_t *)tlv->attr_value = htonl(m_id); break; } payload_len += 8 + op_len; pdu->payload_len = payload_len; dump_pdu1(pdu); conn.in_packet.pdu = pdu; conn.out_packet.pdu = NULL; conn.out_packet.sz = 0; if (packet_split_verify(&conn) == 0) { cache_lock(conn.lock); conn.handler(&conn); conn.ec = cache_unlock(conn.lock, conn.ec); } if (conn.out_packet.pdu != NULL) { pdu_update_code(conn.out_packet.pdu, &conn.out_packet.pl, conn.ec); dump_pdu2(conn.out_packet.pdu); free(conn.out_packet.pdu); } else if (conn.ec != 0) { printf("operation failed[%d].\n", conn.ec); } } static void cmd_file( char *file ) { char i = 0, ch, cmd[256]; FILE *f = fopen(file, "r"); if (f != NULL) { while ((ch = fgetc(f)) != 0 && ch != EOF) { if (ch == '\t') { cmd[i++] = ' '; } else if (ch != '\n') { cmd[i++] = ch; } else { cmd[i ++] = ' '; cmd[i] = 0; i = 0; printf("%s\n", cmd); if (run_cmd(cmd) != 0) { break; } } } fclose(f); } else { printf("Cannot open file %s.\n", file); } } static int run_cmd( char *cmd ) { int argc, argv[32]; int cmd_id; cmd_id = getcmd(&argc, argv, cmd); switch (cmd_id) { case CMD_LIST: list_node(); break; case CMD_LISTNE: list_entity(); break; case CMD_LISTP: list_portal(); break; case CMD_LISTPG: list_pg(); break; case CMD_LISTDD: list_dd(); break; case CMD_LISTDDS: list_dds(); break; case CMD_LISTDDN: list_ddn(argv[0]); break; case CMD_LISTDDSN: list_ddsn(argv[0]); break; case CMD_NEWDD: case CMD_NEWDDS: case CMD_NEWDDN: case CMD_NEWDDSN: new_dd_dds(cmd_id, argc, argv); break; case CMD_DELDD: case CMD_DELDDS: del_dd_dds(cmd_id, argv[0]); break; case CMD_ENABLE: case CMD_DISABLE: update_dds(cmd_id, argv[0]); break; case CMD_ADDDD: case CMD_ADDDDN: case CMD_ADDDDSN: case CMD_REMDD: case CMD_REMDDN: case CMD_REMDDSN: update_member(cmd_id, argv); break; case CMD_PAUSE: printf("Press enter to continue..."); getchar(); break; case CMD_FILE: cmd_file((char *)argv[0]); break; case CMD_HELP: test_cli_help(); break; case CMD_VERBOSE_MEMORY: verbose_mc = !verbose_mc; break; case CMD_VERBOSE_NET: verbose_net = !verbose_net; break; case CMD_VERBOSE_TIME: verbose_tc = !verbose_tc; break; case CMD_VERBOSE_LOCK: verbose_lock = !verbose_lock; break; case CMD_VERBOSE_PARSER: verbose_parser = !verbose_parser; break; case CMD_QUIT: /* clean up cli */ /* notify sys control */ shutdown_server(); return (1); case CMD_NONE: break; default: printf("invalid command\n"); break; } if (cmd_id != CMD_NONE) { printf("\n>"); } else { printf(">"); } return (0); } /*ARGSUSED*/ void *cli_test(void *arg) { char i = 0, ch, cmd[256]; printf("iSNS Server test CLI.\n"); printf("Copyright 2007 Sun Microsystems, Inc.\n"); printf("\n>"); while ((ch = getchar()) != 0 && ch != EOF) { if (ch == '\t') { cmd[i++] = ' '; } else if (ch != '\n') { cmd[i++] = ch; } else { cmd[i ++] = ' '; cmd[i] = 0; i = 0; if (run_cmd(cmd) != 0) { break; } } } return (NULL); } #endif /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include "isns_server.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_pdu.h" #include "isns_func.h" #include "isns_qry.h" #include "isns_msgq.h" #include "isns_log.h" #include "isns_sched.h" #include "isns_scn.h" #include "isns_esi.h" /* * global variables. */ /* * local variables. */ static ev_t *ev_list = NULL; static uint32_t stopwatch = 0; static pthread_mutex_t stw_mtx = PTHREAD_MUTEX_INITIALIZER; static int wakeup = 0; static pthread_mutex_t idl_mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t idl_cond = PTHREAD_COND_INITIALIZER; /* * external variables. */ extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; extern boolean_t time_to_exit; extern msg_queue_t *sys_q; extern uint64_t esi_threshold; #ifdef DEBUG extern void dump_pdu1(isns_pdu_t *); #endif /* * local functions. */ static void *esi_monitor(void *); /* * **************************************************************************** * * new_esi_portal: * Make a new portal for ESI event. * * uid - the portal object UID. * ip6 - the portal IPv6 format IP address. * port - the portal port. * esip - the ESI port. * return - the new ESI portal. * * **************************************************************************** */ static esi_portal_t * new_esi_portal( uint32_t uid, in6_addr_t *ip6, uint32_t port, uint32_t esip ) { esi_portal_t *p; p = (esi_portal_t *)malloc(sizeof (esi_portal_t)); if (p != NULL) { if (((int *)ip6)[0] == 0x00 && ((int *)ip6)[1] == 0x00 && ((uchar_t *)ip6)[8] == 0x00 && ((uchar_t *)ip6)[9] == 0x00 && ((uchar_t *)ip6)[10] == 0xFF && ((uchar_t *)ip6)[11] == 0xFF) { p->sz = sizeof (in_addr_t); p->ip4 = ((uint32_t *)ip6)[3]; } else { p->sz = sizeof (in6_addr_t); } p->ip6 = ip6; p->port = port; p->esip = esip; p->ref = uid; p->so = 0; p->next = NULL; } return (p); } /* * **************************************************************************** * * free_esi_portal: * Free a list of portal of one ESI event. * * p - the ESI portal. * * **************************************************************************** */ static void free_esi_portal( esi_portal_t *p ) { esi_portal_t *n; while (p != NULL) { n = p->next; free(p->ip6); free(p); p = n; } } /* * **************************************************************************** * * ev_new: * Make a new ESI event. * * uid - the Entity object UID. * eid - the Entity object name. * len - the length of the name. * return - the ESI event. * * **************************************************************************** */ static ev_t * ev_new( uint32_t uid, uchar_t *eid, uint32_t len ) { ev_t *ev; ev = (ev_t *)malloc(sizeof (ev_t)); if (ev != NULL) { if (pthread_mutex_init(&ev->mtx, NULL) != 0 || (ev->eid = (uchar_t *)malloc(len)) == NULL) { free(ev); return (NULL); } ev->uid = uid; (void) strcpy((char *)ev->eid, (char *)eid); ev->eid_len = len; /* initialization time */ ev->flags = EV_FLAG_INIT; } return (ev); } /* * **************************************************************************** * * cb_portal_uids: * Callback function which makes a copy of the portal child object * UIDs from a Network Entity object. * * p1 - the Network Entity object. * p2 - the lookup control data. * return - the number of portal object UIDs. * * **************************************************************************** */ static int cb_portal_uids( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; isns_attr_t *attr; uint32_t *cuidp; uint32_t num = 0; uint32_t *p = NULL; cuidp = get_child_t(obj, OBJ_PORTAL); if (cuidp != NULL) { p = (uint32_t *)malloc(*cuidp * sizeof (*p)); if (p != NULL) { num = *cuidp ++; (void) memcpy(p, cuidp, num * sizeof (*p)); lcp->data[1].ptr = (uchar_t *)p; } } attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_ENTITY_REG_PERIOD_ATTR_ID)]; if (attr->tag != 0 && attr->value.ui != 0) { lcp->data[2].ui = attr->value.ui; } else { /* just one second before the end of the world */ lcp->data[2].ui = INFINITY - 1; } return (num); } /* * **************************************************************************** * * cb_esi_portal: * Callback function which gets ESI port number and ESI interval * from a portal object. * * p1 - the Portal object. * p2 - the lookup control data. * return - the ESI interval. * * **************************************************************************** */ static int cb_esi_portal( void *p1, void *p2 ) { uint32_t intval = 0; isns_obj_t *obj; lookup_ctrl_t *lcp; in6_addr_t *ip; uint32_t esip; isns_attr_t *attr; if (cb_clone_attrs(p1, p2) == 0) { obj = (isns_obj_t *)p1; lcp = (lookup_ctrl_t *)p2; ip = lcp->data[1].ip; esip = lcp->data[2].ui; if (esip != 0) { attr = &obj->attrs[ATTR_INDEX_PORTAL( ISNS_PORTAL_PORT_ATTR_ID)]; lcp->data[0].ui = attr->value.ui; attr = &obj->attrs[ATTR_INDEX_PORTAL( ISNS_ESI_INTERVAL_ATTR_ID)]; if (attr->tag != 0 && attr->value.ui != 0) { intval = attr->value.ui; } else { intval = DEFAULT_ESI_INTVAL; } } else { free(ip); } } return ((int)intval); } /* * **************************************************************************** * * extract_esi_portal: * Extract a list of portal which have an ESI port for an Entity. * * uid - the Entity object UID. * intval - the ESI interval for returnning. * return - the list of portals. * * **************************************************************************** */ static esi_portal_t * extract_esi_portal( uint32_t uid, uint32_t *intval ) { esi_portal_t *list = NULL; esi_portal_t *p; lookup_ctrl_t lc; uint32_t num_of_portal; uint32_t *portal_uids; uint32_t intv; /* prepare for looking up entity object */ SET_UID_LCP(&lc, OBJ_ENTITY, uid); lc.data[1].ptr = NULL; lc.data[2].ui = INFINITY - 1; /* get the array of the portal uid(s) */ num_of_portal = (uint32_t)cache_lookup(&lc, NULL, cb_portal_uids); portal_uids = (uint32_t *)lc.data[1].ptr; *intval = lc.data[2].ui; /* prepare for looking up portal object(s) */ SET_UID_LCP(&lc, OBJ_PORTAL, 0); lc.id[1] = ISNS_PORTAL_IP_ADDR_ATTR_ID; lc.id[2] = ISNS_ESI_PORT_ATTR_ID; FOR_EACH_OBJS(portal_uids, num_of_portal, uid, { if (uid != 0) { lc.data[0].ui = uid; intv = cache_lookup(&lc, NULL, cb_esi_portal); if (intv != 0) { p = new_esi_portal(uid, (in6_addr_t *)lc.data[1].ip, lc.data[0].ui, lc.data[2].ui); if (p != NULL) { p->next = list; list = p; if (*intval > intv) { *intval = intv; } } } } }); /* free up the portal uid array */ free(portal_uids); return (list); } /* * **************************************************************************** * * ev_add: * Add an ESI event. * * ev - the ESI event. * init - 0: initialization time, otherwise not. * return - error code. * * **************************************************************************** */ static int ev_add( ev_t *ev, int init ) { uint32_t intval; esi_portal_t *p; double rnd; uint32_t t = 0; /* get the portal(s) which are registered for ESI monitoring */ /* and the second interval for ESI or registration expiration */ p = extract_esi_portal(ev->uid, &intval); ev->intval = intval; if (p != NULL) { ev->type = EV_ESI; ev->portal = p; /* avoid running everything at the same time */ if (init != 0) { /* generate random number within range (0, 1] */ rnd = (rand() + 1) / (double)(RAND_MAX + 1); t = (uint32_t)(intval * rnd); } } else { /* no portal is registered for ESI monitoring, make */ /* an entry for entity registration expiration */ ev->type = EV_REG_EXP; ev->portal = NULL; if (init != 0) { t = intval; } } /* schedule the event */ return (el_add(ev, t, NULL)); } /* * global functions. */ /* * **************************************************************************** * * sigalrm: * The signal handler for SIGALRM, the ESI proc uses the SIGALRM * for waking up to perform the client status inquery. * * sig - the signal. * * **************************************************************************** */ /*ARGSUSED*/ void sigalrm( int sig ) { /* wake up the idle */ (void) pthread_mutex_lock(&idl_mtx); wakeup = 1; /* wake up naturally */ (void) pthread_cond_signal(&idl_cond); (void) pthread_mutex_unlock(&idl_mtx); } /* * **************************************************************************** * * esi_load: * Load an ESI event from data store. * * uid - the Entity object UID. * eid - the Entity object name. * len - the length of the name. * return - error code. * * **************************************************************************** */ int esi_load( uint32_t uid, uchar_t *eid, uint32_t len ) { int ec = 0; /* make a new event */ ev_t *ev = ev_new(uid, eid, len); /* put the new event to the list */ if (ev != NULL) { ev->next = ev_list; ev_list = ev; } else { ec = ISNS_RSP_INTERNAL_ERROR; } return (ec); } /* * **************************************************************************** * * verify_esi_portal: * Verify ESI port and add the ESI entries after the ESI are loaded. * * return - error code. * * **************************************************************************** */ int verify_esi_portal( ) { int ec = 0; ev_t *ev; /* add each event from the list */ while (ev_list != NULL && ec == 0) { ev = ev_list; ev_list = ev->next; ev->next = NULL; ec = ev_add(ev, 1); } return (ec); } /* * **************************************************************************** * * esi_add: * Add a new ESI event when a new Entity is registered. * * uid - the Entity object UID. * eid - the Entity object name. * len - the length of the name. * return - error code. * * **************************************************************************** */ int esi_add( uint32_t uid, uchar_t *eid, uint32_t len ) { int ec = 0; /* make a new event */ ev_t *ev = ev_new(uid, eid, len); if (ev != NULL) { /* interrupt idle */ ev->flags |= EV_FLAG_WAKEUP; ec = ev_add(ev, 0); } else { ec = ISNS_RSP_INTERNAL_ERROR; } return (ec); } /* * **************************************************************************** * * esi_remove: * Remove an ESI event immediately. * * uid - the Entity object UID. * return - always successful. * * **************************************************************************** */ int esi_remove( uint32_t uid ) { (void) el_remove(uid, 0, 0); return (0); } /* * **************************************************************************** * * esi_remove_obj: * Update an ESI event when a Entity object or a Portal object is * removed from server. If the object is being removed because of * ESI failure, the ESI event will be removed with a pending time, * otherwise, the ESI will be removed immediately. * * obj - the object being removed. * pending - the pending flag. * return - always successful. * * **************************************************************************** */ int esi_remove_obj( const isns_obj_t *obj, int pending ) { uint32_t puid, uid; switch (obj->type) { case OBJ_PORTAL: puid = get_parent_uid(obj); uid = get_obj_uid(obj); break; case OBJ_ENTITY: puid = get_obj_uid(obj); uid = 0; break; default: puid = 0; break; } if (puid != 0) { (void) el_remove(puid, uid, pending); } return (0); } /* * **************************************************************************** * * get_stopwatch: * Get the stopwatch. It might need to signal the condition to * wake up the idle so the stopwatch gets updated. * * flag - wake up flag. * return - the stopwatch. * * **************************************************************************** */ uint32_t get_stopwatch( int flag ) { uint32_t t; /* not re-schedule, wake up idle */ (void) pthread_mutex_lock(&idl_mtx); if (flag != 0) { wakeup = 2; /* wake up manually */ (void) pthread_cond_signal(&idl_cond); } else { wakeup = 0; /* clear previous interruption */ } (void) pthread_mutex_unlock(&idl_mtx); /* get most current time */ (void) pthread_mutex_lock(&stw_mtx); t = stopwatch; (void) pthread_mutex_unlock(&stw_mtx); return (t); } /* * **************************************************************************** * * ev_intval: * Get the time interval of an ESI event. * * p - the ESI event. * return - the time interval. * * **************************************************************************** */ uint32_t ev_intval( void *p ) { return (((ev_t *)p)->intval); } /* * **************************************************************************** * * ev_match: * Check the ESI event maching an Entity object. * * p - the ESI event. * uid - the Entity object UID. * return - 1: match, otherwise not. * * **************************************************************************** */ int ev_match( void *p, uint32_t uid ) { if (((ev_t *)p)->uid == uid) { return (1); } else { return (0); } } /* * **************************************************************************** * * ev_remove: * Remove a portal or an ESI event. If all of ESI portal has been * removed, the ESI event will be marked as removal pending, which * will result in removing the Entity object after the pending time. * * p - the ESI event. * portal_uid - the Portal object UID. * flag - 0: the ESI is currently in use, otherwise it is scheduled. * pending - flag for the ESI removal pending. * return - 0: the ESI is physically removed, otherwise not. * * **************************************************************************** */ int ev_remove( void *p, uint32_t portal_uid, int flag, int pending ) { ev_t *ev = (ev_t *)p; esi_portal_t **pp, *portal; int has_portal = 0; int state; /* remove one portal only */ if (portal_uid != 0) { pp = &ev->portal; portal = *pp; while (portal != NULL) { /* found the match portal */ if (portal->ref == portal_uid) { /* mark it as removed */ portal->ref = 0; if (flag != 0) { /* not in use, remove it physically */ *pp = portal->next; portal->next = NULL; free_esi_portal(portal); } else { pp = &portal->next; } } else { /* one or more esi portals are available */ if (portal->ref != 0) { has_portal = 1; } pp = &portal->next; } portal = *pp; } } /* no portal available */ if (has_portal == 0) { state = (pending << 1) | flag; switch (state) { case 0x0: /* mark the event as removed */ ev->flags |= EV_FLAG_REMOVE; isnslog(LOG_DEBUG, "ev_remove", "%s [%d] is marked as removed.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid); break; case 0x1: /* physically remove the event */ ev_free(ev); break; case 0x2: case 0x3: /* mark the event as removal pending */ isnslog(LOG_DEBUG, "ev_remove", "%s [%d] is marked as removal pending.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid); ev->flags |= EV_FLAG_REM_P1; has_portal = 1; break; default: break; } } else { isnslog(LOG_DEBUG, "ev_remove", "%s [%d] removed portal %d.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid, portal_uid); } return (has_portal); } /* * **************************************************************************** * * ev_free: * Free an ESI event. * * p - the ESI event. * * **************************************************************************** */ void ev_free( void *p ) { ev_t *ev = (ev_t *)p; /* free up all of portals */ free_esi_portal(ev->portal); isnslog(LOG_DEBUG, "ev_free", "%s [%d] is physically removed.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid); free(ev->eid); /* free the event */ free(ev); } /* * **************************************************************************** * * evf_init: * Check the initial flag of an ESI event. * * p - the ESI event. * return - 0: not initial, otherwise yes. * * **************************************************************************** */ int evf_init( void *p ) { return (((ev_t *)p)->flags & EV_FLAG_INIT); } /* * **************************************************************************** * * evf_again: * Check the again flag of an ESI event. * (this flag might be eliminated and use the init flag.) * * p - the ESI event. * return - 0: not again, otherwise yes. * * **************************************************************************** */ int evf_again( void *p ) { return (((ev_t *)p)->flags & EV_FLAG_AGAIN); } /* * **************************************************************************** * * evf_wakeup: * Check the wakeup flag of an ESI event. The idle might need to * wake up before the event is scheduled. * * p - the ESI event. * return - 0: no wakeup, otherwise yes. * * **************************************************************************** */ int evf_wakeup( void *p ) { return (((ev_t *)p)->flags & EV_FLAG_WAKEUP); } /* * **************************************************************************** * * evf_rem: * Check the removal flag of an ESI event. The ESI entry might be * marked as removal. * * p - the ESI event. * return - 0: not removed, otherwise yes. * * **************************************************************************** */ int evf_rem( void *p ) { return (((ev_t *)p)->flags & EV_FLAG_REMOVE); } /* * **************************************************************************** * * evf_rem_pending: * Check the removal pending flag of an ESI event. The ESI entry * might be marked as removal pending. If it is, we will switch the * event type and change the time interval. * * p - the ESI event. * return - 0: not removal pending, otherwise yes. * * **************************************************************************** */ int evf_rem_pending( void *p ) { ev_t *ev = (ev_t *)p; if ((ev->flags & EV_FLAG_REM_P) != 0) { if (ev->type != EV_REG_EXP) { isnslog(LOG_DEBUG, "ev_rem_pending", "%s [%d] is changed to REG_EXP.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid); ev->type = EV_REG_EXP; ev->intval *= 2; /* after 2 ESI interval */ } return (1); } return (0); } /* * **************************************************************************** * * evf_zero: * Reset the event flag. * * p - the ESI event. * * **************************************************************************** */ void evf_zero( void *p ) { ev_t *ev = (ev_t *)p; /* not acutally clear it, need to set again flag */ /* and keep the removal pending flag */ ev->flags = EV_FLAG_AGAIN | (ev->flags & EV_FLAG_REM_P); } /* * **************************************************************************** * * evl_append: * Append an ESI event to the list, the list contains all of * ESI events which are being processed at present. * * p - the ESI event. * * **************************************************************************** */ void evl_append( void *p ) { ev_t *ev; ev = (ev_t *)p; ev->next = ev_list; ev_list = ev; } /* * **************************************************************************** * * evl_strip: * Strip off an ESI event from the list after the event is being * processed, it will be scheduled in the scheduler. * * p - the ESI event. * * **************************************************************************** */ void evl_strip( void *p ) { ev_t **evp = &ev_list; ev_t *ev = *evp; while (ev != NULL) { if (ev == p) { *evp = ev->next; break; } evp = &ev->next; ev = *evp; } } /* * **************************************************************************** * * evl_remove: * Remove an ESI event or a portal of an ESI event from the event list. * * id1 - the Entity object UID. * id2 - the Portal object UID. * pending - the pending flag. * return - 1: found a match event, otherwise not. * * **************************************************************************** */ int evl_remove( uint32_t id1, uint32_t id2, int pending ) { ev_t *ev = ev_list; while (ev != NULL) { /* found it */ if (ev_match(ev, id1) != 0) { /* lock the event */ (void) pthread_mutex_lock(&ev->mtx); /* mark it as removed */ (void) ev_remove(ev, id2, 0, pending); /* unlock the event */ (void) pthread_mutex_unlock(&ev->mtx); /* tell caller removal is done */ return (1); } ev = ev->next; } /* not found it */ return (0); } #define ALARM_MAX (21427200) /* * **************************************************************************** * * idle: * Idle for certain amount of time or a wakeup signal is recieved. * * t - the idle time. * return - the time that idle left. * * **************************************************************************** */ static int idle( uint32_t t ) { uint32_t t1, t2, t3 = 0; int idl_int = 0; /* hold the mutex for stopwatch update */ (void) pthread_mutex_lock(&stw_mtx); do { if (t > ALARM_MAX) { t1 = ALARM_MAX; } else { t1 = t; } /* start alarm */ (void) alarm(t1); /* hold the mutex for idle condition */ (void) pthread_mutex_lock(&idl_mtx); /* wait on condition variable to wake up idle */ while (wakeup == 0) { (void) pthread_cond_wait(&idl_cond, &idl_mtx); } if (wakeup == 2) { idl_int = 1; } /* clean wakeup flag */ wakeup = 0; /* release the mutex for idle condition */ (void) pthread_mutex_unlock(&idl_mtx); /* stop alarm */ t2 = alarm(0); /* seconds actually slept */ t3 += t1 - t2; t -= t3; } while (t > 0 && idl_int == 0); /* increate the stopwatch by the actually slept time */ stopwatch += t3; /* release the mutex after stopwatch is updated */ (void) pthread_mutex_unlock(&stw_mtx); /* return the amount of time which is not slept */ return (t); } /* * **************************************************************************** * * ev_ex: * Execute an event. To inquiry the client status or * perform registration expiration. * * ev - the event. * * **************************************************************************** */ static void ev_ex( ev_t *ev ) { pthread_t tid; switch (ev->type) { case EV_ESI: if (pthread_create(&tid, NULL, esi_monitor, (void *)ev) != 0) { isnslog(LOG_DEBUG, "ev_ex", "pthread_create() failed."); /* reschedule for next occurence */ (void) el_add(ev, 0, NULL); } else { /* increase the thread ref count */ inc_thr_count(); } break; case EV_REG_EXP: (void) queue_msg_set(sys_q, REG_EXP, (void *)ev); break; default: break; } } /* * **************************************************************************** * * esi_proc: * ESI thread entry, which: * 1: fetch an event from schedule, * 2: idle for some time, * 3: execute the event or re-schedule it, * 4: repeat from step 1 before server is being shutdown. * * arg - the thread argument. * * **************************************************************************** */ /*ARGSUSED*/ void * esi_proc( void *arg ) { uint32_t t, t1, pt; ev_t *ev; void *evp; while (time_to_exit == B_FALSE) { ev = (ev_t *)el_first(&pt); /* caculate the idle time */ if (ev != NULL) { if (pt > stopwatch) { t = pt - stopwatch; } else { t = 0; } } else { t = INFINITY; } do { /* block for a certain amount of time */ if (t > 0) { isnslog(LOG_DEBUG, "esi_proc", "idle for %d seconds.", t); t1 = idle(t); } else { t1 = 0; } if (t1 > 0) { isnslog(LOG_DEBUG, "esi_proc", "idle interrupted after idle for " "%d seconds.", t - t1); } if (time_to_exit != B_FALSE) { ev = NULL; /* force break */ } else if (ev != NULL) { if (t1 > 0) { /* not naturally waken up */ /* reschedule current event */ evp = NULL; (void) el_add(ev, pt, &evp); ev = (ev_t *)evp; t = t1; } else { /* excute */ isnslog(LOG_DEBUG, "esi_proc", "excute the cron job[%d].", ev->uid); ev_ex(ev); ev = NULL; } } } while (ev != NULL); } return (NULL); } /* * **************************************************************************** * * esi_ping: * Ping the client with the ESI retry threshold for status inquiry. * * so - the socket descriptor. * pdu - the ESI packet. * pl - the length of packet. * return - 1: status inquired, otherwise not. * * **************************************************************************** */ static int esi_ping( int so, isns_pdu_t *pdu, size_t pl ) { int try_cnt = 0; isns_pdu_t *rsp = NULL; size_t rsp_sz; int alive = 0; do { if (isns_send_pdu(so, pdu, pl) == 0) { if (isns_rcv_pdu(so, &rsp, &rsp_sz, ISNS_RCV_SHORT_TIMEOUT) > 0) { #ifdef DEBUG dump_pdu1(rsp); #endif alive = 1; break; } } else { /* retry after 1 second */ (void) sleep(1); } try_cnt ++; } while (try_cnt < esi_threshold); if (rsp != NULL) { free(rsp); } return (alive); } /* * **************************************************************************** * * esi_monitor: * Child thread for client status mornitoring. * * arg - the ESI event. * * **************************************************************************** */ static void * esi_monitor( void *arg ) { ev_t *ev = (ev_t *)arg; esi_portal_t *p; int so; isns_pdu_t *pdu = NULL; size_t sz; size_t pl; size_t half; time_t t; int feedback; /* lock the event for esi monitoring */ (void) pthread_mutex_lock(&ev->mtx); if (evf_rem(ev) != 0) { goto mon_done; } else if (evf_rem_pending(ev) != 0) { goto mon_done; } /* timestamp */ t = time(NULL); /* allocate ESI PDU */ if (pdu_reset_esi(&pdu, &pl, &sz) != 0 || pdu_add_tlv(&pdu, &pl, &sz, ISNS_TIMESTAMP_ATTR_ID, 8, (void *)&t, 1) != 0 || pdu_add_tlv(&pdu, &pl, &sz, ISNS_EID_ATTR_ID, ev->eid_len, (void *)ev->eid, 0) != 0) { /* no memory, will retry later */ goto mon_done; } /* set pdu head */ pdu->version = htons((uint16_t)ISNSP_VERSION); pdu->func_id = htons((uint16_t)ISNS_ESI); pdu->xid = htons(get_server_xid()); /* keep the current lenght of the playload */ half = pl; p = ev->portal; while (p != NULL) { if (p->ref != 0 && /* skip IPv6 portal */ p->sz != sizeof (in6_addr_t) && pdu_add_tlv(&pdu, &pl, &sz, ISNS_PORTAL_IP_ADDR_ATTR_ID, sizeof (in6_addr_t), (void *)p->ip6, 0) == 0 && pdu_add_tlv(&pdu, &pl, &sz, ISNS_PORTAL_PORT_ATTR_ID, 4, (void *)p->port, 0) == 0) { /* connect once */ so = connect_to(p->sz, p->ip4, p->ip6, p->esip); if (so != -1) { feedback = esi_ping(so, pdu, pl); (void) close(so); /* p->so = so; */ } else { /* cannot connect, portal is dead */ feedback = 0; } if (feedback == 0) { isnslog(LOG_DEBUG, "esi_monitor", "ESI ping failed."); (void) queue_msg_set(sys_q, DEAD_PORTAL, (void *)p->ref); } else { goto mon_done; } } pl = half; p = p->next; } mon_done: /* unlock the event after esi monitoring is done */ (void) pthread_mutex_unlock(&ev->mtx); /* clean up pdu */ if (pdu != NULL) { free(pdu); } /* set reschedule flags */ ev->flags |= EV_FLAG_WAKEUP; /* reschedule for next occurence */ (void) el_add(ev, 0, NULL); /* decrease the thread ref count */ dec_thr_count(); return (NULL); } /* * **************************************************************************** * * portal_dies: * Handles the dead portal that ESI detected. * * uid - the Portal object UID. * * **************************************************************************** */ void portal_dies( uint32_t uid ) { int ec = 0; lookup_ctrl_t lc; /* prepare the lookup control for deregistration */ SET_UID_LCP(&lc, OBJ_PORTAL, uid); /* lock the cache for object deregistration */ (void) cache_lock_write(); /* deregister the portal */ ec = dereg_object(&lc, 1); /* unlock cache and sync with data store */ (void) cache_unlock_sync(ec); } /* * **************************************************************************** * * portal_dies: * Handles the Entity registration expiration. * * p - the ESI event. * * **************************************************************************** */ void reg_expiring( void *p ) { int ec = 0; ev_t *ev = (ev_t *)p; lookup_ctrl_t lc; /* prepare the lookup control for deregistration */ SET_UID_LCP(&lc, OBJ_ENTITY, ev->uid); /* lock the cache for object deregistration */ (void) cache_lock_write(); if (evf_rem(ev) == 0) { /* deregister the entity */ ec = dereg_object(&lc, 0); /* unlock cache and sync with data store */ ec = cache_unlock_sync(ec); if (ec == 0) { /* successfuk, mark ev as removed */ ev->flags |= EV_FLAG_REMOVE; } else { /* failed, retry after 3 mintues */ ev->intval = 3 * 60; isnslog(LOG_DEBUG, "reg_expiring", "dereg failed, retry after 3 mintues."); } } else { /* ev is marked as removed, no need to dereg */ (void) cache_unlock_nosync(); } /* reschedule it for next occurence */ (void) el_add(ev, 0, NULL); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #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" /* * extern global variables */ #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]; /* scn message queue */ extern msg_queue_t *scn_q; /* * extern functions. */ /* * local variables */ /* * local functions. */ 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 *); /* * **************************************************************************** * * packet_get_source: * get the source attributes of the packet. * * conn - the argument of the connection. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * packet_get_key: * get the key attributes of the packet. * * conn - the argument of the connection. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * packet_get_operand: * get the operating attributes of the packet. * * conn - the argument of the connection. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * packet_split_verify: * split and verify the packet, get the apporiate locking type and * function handler for the packet. * * conn - the argument of the connection. * return - error code. * * **************************************************************************** */ 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; /* packet split & verify */ 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); } /* * **************************************************************************** * * setup_key_lcp: * setup the lookup control data for looking up the object * which the key attributes identify. * * lcp - the pointer of the lookup control data. * key - the key attributes. * key_len - the length of the key attributes. * return - the pointer of the lookup control data or * NULL if there is an error. * * **************************************************************************** */ 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; /* invalid */ ec = ISNS_RSP_MSG_FORMAT_ERROR; } return (ec); } /* * **************************************************************************** * * rsp_add_op: * add the operating attributes to the response packet. * * conn - the argument of the connection. * obj - the object which is being added as operating attributes. * return - error code. * * **************************************************************************** */ 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]; /* there is an attribute, send it back */ 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); } /* * **************************************************************************** * * rsp_add_key: * add the key attributes to the response packet. * * conn - the argument of the connection. * entity - the object which is being added as key attributes. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * rsp_add_tlv: * add one attribute with TLV format to the response packet. * * conn - the argument of the connection. * tag - the tag of the attribute. * len - the length of the attribute. * value- the value of the attribute. * pflag- the flag of the value, 0: value; 1: pointer to value * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * rsp_add_tlvs: * add attributes with TLV format to the response packet. * * conn - the argument of the connection. * tlv - the attributes with TLV format being added. * tlv_len - the length of the attributes. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * dev_attr_reg: * function which handles the isnsp DEV_ATTR_REG message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ 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; /* network entity object */ isns_type_t ptype; /* parent object type */ uint32_t puid; /* parent object UID */ void const **child[MAX_CHILD_TYPE] = { NULL }; /* children */ int ety_update, obj_update; isns_attr_t *eid_attr; isns_obj_t *obj; /* child object */ isns_type_t ctype; /* child object type */ uint32_t uid; /* child object 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) { /* validate key attributes and make lcp for */ /* the object identified by key attributes. */ ec = setup_key_lcp(&lc, key, key_len); if (ec == 0 && lc.type != 0) { lc_key = lc; /* object is not found */ if ((uid = is_obj_there(&lc)) == 0) { /* error if it is a network entity */ if (lc.type != OBJ_ENTITY) { ec = ISNS_RSP_INVALID_REGIS; } /* validate for the source attribute before */ /* update or replace the network entity object */ } 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; /* de-register the network entity if replace is true */ } else if (replace != 0) { UPDATE_LCP_UID(&lc, uid); ec = dereg_object(&lc, 0); /* generate a SCN */ if (ec == 0) { (void) queue_msg_set(scn_q, SCN_TRIGGER, NULL); } } } } if (ec != 0) { goto reg_done; } /* register the network entity object */ 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)) { /* the eid in key attribute and */ /* op attribute must be the same */ 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) { /* newly registered, reset the pointer */ ety = NULL; } /* register the reset of objects which are specified in */ /* operating attributes */ 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; /* set the parent object UID */ (void) set_parent_obj(obj, puid); /* register it */ ec = register_object(obj, &uid, &obj_update); if (ec == 0) { if (obj_update == 0 || is_obj_online(obj) == 0) { /* update the ref'd object */ (void) update_ref_obj(obj); /* add the newly registered object info */ /* to child info array of the parent object */ 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; } /* it was for updating an existing object */ free_one_object(obj); } } else { /* failed registering it */ free_one_object(obj); } } /* update the portal group object for the associations between */ /* the newly registered objects and previously registered objects */ if (ec == 0) { ec = verify_ref_obj(ptype, puid, child); } if (ec != 0) { goto reg_done; } /* update the children list of the parent object */ 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 /* for interop-ability, we cannot treat this as */ /* an error, instead, remove the network entity */ SET_UID_LCP(&lc, OBJ_ENTITY, puid); ec = dereg_object(&lc, 0); goto reg_done; #endif } if (ec != 0) { goto reg_done; } /* add esi entry */ 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); } /* * **************************************************************************** * * dev_attr_qry: * function which handles the isnsp DEV_ATTR_QRY message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int dev_attr_qry(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; 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; } /* * RFC 4171 section 5.7.5.2: * If no Operating Attributes are included in the original query, then * all Operating Attributes SHALL be returned in the response. ??? */ 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) { /* * Return the original message key. */ ec = rsp_add_tlvs(conn, key, key_len); if (ec != 0) { goto qry_done; } /* * Delimiter */ ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0); if (ec != 0) { goto qry_done; } /* * Query objects which match the Key Attributes. */ 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; } /* * Iterate thru each object identified by the message key. */ tlv = op; tlv_len = op_len; FOR_EACH_OBJS(key_uids, num_of_keys, key_uid, { /* * Iterate thru each Operating Attributes. */ 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; } /* * Iterate thru each object for the Operating * Attributes again. */ 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 { /* * Iterate thru each Operating Attributes. */ 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; } /* * Iterate thru each object for the Operating * Attributes again. */ 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); } /* * **************************************************************************** * * dev_get_next: * function which handles the isnsp DEV_GET_NEXT message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int dev_get_next(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; 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; } } /* * Get Message Key type and validate the Message Key. */ 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) { /* * Query the objects which match the Operating Attributes. */ 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 { /* * Query the objects which match the Message Key type. */ 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; } /* * Get the object which is next to the one indicated by the * Message Key. */ 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; } /* * Message Key */ if ((ec = get_qry_attrs1(uid, key_type, key, key_len, conn)) != 0) { goto get_next_done; } /* * Delimiter */ if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0)) != 0) { goto get_next_done; } /* * Operating Attributes */ 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); } /* * **************************************************************************** * * dev_dereg: * function which handles the isnsp DEV_DEREG message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int dev_dereg(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; 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); } /* * **************************************************************************** * * scn_reg: * function which handles the isnsp SCN_REG message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int scn_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; /* uchar_t *src; */ uchar_t *node_name; uint32_t nlen; uint32_t scn; isnslog(LOG_DEBUG, "scn_reg", "entered"); /* src = (uchar_t *)&source->attr_value[0]; */ 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); } /* * **************************************************************************** * * scn_dereg: * function which handles the isnsp SCN_DEREG message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * setup_ddid_lcp: * setup the lookup control data for looking up the DD object * by using the dd_id attribute. * * lcp - pointer to the lookup control data. * dd_id- the unique ID of the DD object. * return - the pointer to the lcp. * * **************************************************************************** */ #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); } /* * **************************************************************************** * * setup_ddsid_lcp: * setup the lookup control data for looking up the DD-set object * by using the dds_id attribute. * * lcp - pointer to the lookup control data. * dds_id - the unique ID of the DD-set object. * return - the pointer to the 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); } /* * **************************************************************************** * * dd_reg: * function which handles the isnsp DD_REG message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int dd_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; 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; } /* message key */ if (key != NULL && (ec = rsp_add_tlv(conn, ISNS_DD_ID_ATTR_ID, 4, (void *)dd_id, 0)) != 0) { goto dd_reg_done; } /* delimiter */ if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0)) != 0) { goto dd_reg_done; } /* A DDReg message with no Message Key SHALL result in the */ /* attempted creation of a new Discovery Domain (DD). */ 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; } } /* add the newly created dd to the response */ 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 the DD_ID is included in both the Message Key */ /* and Operating Attributes, then the DD_ID value */ /* in the Message Key MUST be the same as the DD_ID */ /* value in the Operating Attributes. */ 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: /* It is going to modify the DD Symbolic Name. */ 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) { /* zero the association object */ 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; /* clear it */ attr->value.ptr = NULL; /* clear it */ 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; /* clear it */ 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: /* It is going to modify the DD Symbolic Name. */ 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); } /* * **************************************************************************** * * dds_reg: * function which handles the isnsp DDS_REG message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int dds_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; 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; } /* message key */ if (key != NULL && (ec = rsp_add_tlv(conn, ISNS_DD_SET_ID_ATTR_ID, 4, (void *)dds_id, 0)) != 0) { goto dds_reg_done; } /* delimiter */ if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0)) != 0) { goto dds_reg_done; } /* A DDSReg message with no Message Key SHALL result in the */ /* attempted creation of a new Discovery Domain (DD). */ 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; } } /* add the newly created dd to the response */ 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 the DDS_ID is included in both the Message Key */ /* and Operating Attributes, then the DDS_ID value */ /* in the Message Key MUST be the same as the DDS_ID */ /* value in the Operating Attributes. */ 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: /* It is going to modify the DD Symbolic Name. */ 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: /* It is going to modify the DD Symbolic Name. */ 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) { /* zero the association object */ 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); } /* * **************************************************************************** * * dd_dereg: * function which handles the isnsp DD_DEREG message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int dd_dereg(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; 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: /* zero the association object */ 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; /* clear it */ attr->value.ptr = NULL; /* clear it */ 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; /* clear it */ 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); } /* * **************************************************************************** * * dds_dereg: * function which handles the isnsp DDS_DEREG message. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int dds_dereg(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; 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); } /* * **************************************************************************** * * msg_error: * function which handles any unknown isnsp messages or the * messages which are not supported. * * conn - the argument of the connection. * return - 0: the message requires response. * * **************************************************************************** */ static int msg_error(conn_arg_t *conn __unused) { return (0); } /* * **************************************************************************** * * isns_response_ec: * send the response message to the client with error code. * * so - the socket descriptor. * pdu - the received pdu. * ec - the error code which is being responsed. * return - status of the sending operation. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * isns_response: * send the response message to the client. * * conn - the argument of the connection. * return - status of the sending operation. * * **************************************************************************** */ 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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include "isns_server.h" #include "isns_cache.h" #include "isns_htab.h" #include "isns_log.h" #define UID_REUSABLE(T, X) ((T) - (X)->t >= ONE_DAY) /* * external variables. */ extern int cache_flag; /* * **************************************************************************** * avl_search: * search a node from an AVL tree. * * tab - the hash table. * uid - the object UID. * return - the node which matches the object UID. * * **************************************************************************** */ static htab_itemx_t * avl_search( const htab_t *tab, const uint32_t uid ) { htab_itemx_t *x = tab->avlt; while (x != NULL) { if (x->uid > uid) { x = x->l; } else if (x->uid < uid) { x = x->r; } else { break; } } return (x); } /* * **************************************************************************** * avl_search_next: * search a node from an AVL tree, the object UID of the node * is next to the previous object UID. * * tab - the hash table. * uid - the previous object UID. * return - the next node. * * **************************************************************************** */ static htab_itemx_t * avl_search_next( const htab_t *tab, const uint32_t uid ) { htab_itemx_t *p = NULL; htab_itemx_t *x = tab->avlt; while (x != NULL) { if (x->uid > uid) { p = x; x = x->l; } else if (x->uid <= uid) { x = x->r; } } return (p); } /* * **************************************************************************** * avl_ll: * perform LL balance rotation on an AVL tree (or the subtree). * * a - the left child. * b - the right child. * return - the new root. * * **************************************************************************** */ static htab_itemx_t * avl_ll( htab_itemx_t *a, htab_itemx_t *b ) { /* rotate right */ a->l = b->r; a->bf = 0; b->r = a; b->bf = 0; return (b); } /* * **************************************************************************** * avl_rr: * perform RR balance rotation on an AVL tree (or the subtree). * * a - the left child. * b - the right child. * return - the new root. * * **************************************************************************** */ static htab_itemx_t * avl_rr( htab_itemx_t *a, htab_itemx_t *b ) { /* rotate left */ a->r = b->l; a->bf = 0; b->l = a; b->bf = 0; return (b); } /* * **************************************************************************** * avl_lr: * perform LR balance rotation on an AVL tree (or the subtree). * * a - the left child. * b - the right child. * return - the new root. * * **************************************************************************** */ static htab_itemx_t * avl_lr( htab_itemx_t *a, htab_itemx_t *b ) { htab_itemx_t *c; c = b->r; /* rotate left and then right */ a->l = c->r; c->r = a; b->r = c->l; c->l = b; /* update balance factor */ switch (c->bf) { case -1: /* on c's right */ a->bf = 0; b->bf = 1; break; case 0: /* on c itself */ a->bf = 0; b->bf = 0; break; case 1: /* on c's left */ a->bf = -1; b->bf = 0; break; } c->bf = 0; return (c); } /* * **************************************************************************** * avl_rl: * perform RL balance rotation on an AVL tree (or the subtree). * * a - the left child. * b - the right child. * return - the new root. * * **************************************************************************** */ static htab_itemx_t * avl_rl( htab_itemx_t *a, htab_itemx_t *b ) { htab_itemx_t *c; c = b->l; /* rotate right and then left */ a->r = c->l; c->l = a; b->l = c->r; c->r = b; /* update balance factor */ switch (c->bf) { case -1: /* on c's right */ a->bf = 1; b->bf = 0; break; case 0: /* on c itself */ a->bf = 0; b->bf = 0; break; case 1: /* on c's left */ a->bf = 0; b->bf = -1; break; } c->bf = 0; return (c); } /* * **************************************************************************** * avl_insert: * insert a node into an AVL tree. * * tab - the hash table. * x - the node being added. * * **************************************************************************** */ static void avl_insert( htab_t *tab, htab_itemx_t *x ) { htab_itemx_t *f, *a, *p, *q, *b, *c; int d; /* initialize the new one */ x->bf = 0; x->l = NULL; x->r = NULL; if (tab->avlt == NULL) { tab->avlt = x; } else { /* locate the position */ f = NULL; a = tab->avlt; p = tab->avlt; q = NULL; while (p != NULL) { if (p->bf != 0) { a = p; f = q; } q = p; if (x->uid < q->uid) { p = p->l; } else { p = p->r; } } /* insert it */ if (x->uid < q->uid) { q->l = x; } else { q->r = x; } /* update the balance factor between a to x */ if (x->uid < a->uid) { p = a->l; d = 1; } else { p = a->r; d = -1; } b = p; while (p != x) { if (x->uid < p->uid) { p->bf = 1; p = p->l; } else { p->bf = -1; p = p->r; } } /* brance is not broken */ if (a->bf == 0) { a->bf = d; goto bal_done; } else if (a->bf + d == 0) { a->bf = 0; goto bal_done; } /* rotate the tree */ if (d == 1) { if (b->bf == 1) { /* LL rotate */ c = avl_ll(a, b); } else if (b->bf == -1) { /* LR rotate */ c = avl_lr(a, b); } } else { if (b->bf == -1) { /* RR rotate */ c = avl_rr(a, b); } else if (b->bf == 1) { /* RL rotate */ c = avl_rl(a, b); } } /* update the parent */ if (f == NULL) { tab->avlt = c; } else if (f->l == a) { f->l = c; } else if (f->r == a) { f->r = c; } } bal_done: if (x->uid > tab->buid) { tab->buid = x->uid; } } /* * **************************************************************************** * new_uid: * allocate new node(s) of the avl tree. * * tab - the hash table. * uid - the UID of the node. * return - the newly allocated UID node. * * **************************************************************************** */ static htab_itemx_t * new_uid( htab_t *tab, uint32_t uid ) { htab_itemx_t *x = NULL; uint32_t start, end; /* overflow happened */ if (uid == 0) { /* search for an unused one */ uid ++; while (uid != 0 && avl_search(tab, uid) != NULL) { uid ++; } if (uid == 0) { /* all are used up, sigh! */ return (NULL); } } /* check if there is a gap and the gap needs to be filled up */ if (uid > tab->buid && (tab->flags & UID_FLAGS_SEQ) != 0) { start = tab->buid + 1; } else { start = uid; } end = uid; /* make new UID(s) */ do { if (x != NULL) { x->hval = BAD_HVAL_MASK; x->t = 0; /* put it to the start of the fifo list */ x->n = tab->list; tab->list = x; if (tab->tail == NULL) { tab->tail = x; } } x = (htab_itemx_t *)malloc(sizeof (htab_itemx_t)); if (x != NULL) { x->uid = start; x->n = NULL; /* insert it to the tree */ avl_insert(tab, x); } start ++; } while (x != NULL && start <= end && start != 0); return (x); } /* * **************************************************************************** * uid_insert: * insert a new UID node to the avl tree. * * tab - the hash table. * uid_p- the pointer of the UID. * hval - the hash value of the new node. * return - 0: no UID value assigned; * 1: assigned an UID. * -1: no memory. * -2: invalid UID. * * **************************************************************************** */ static int uid_insert( htab_t *tab, uint32_t *const uid_p, const uint32_t hval ) { int assignx = 0; uint32_t uid = *uid_p; htab_itemx_t *x, *n; if (uid != 0) { /* search the existing one from the tree */ x = avl_search(tab, uid); if (x == NULL) { x = new_uid(tab, uid); } else if (!BAD_HVAL(x->hval) && x->hval != hval) { /* the item with this uid will override an */ /* existing item, we treat this as an error */ return (-2); } } else { /* assign a value */ x = tab->list; /* strip off the used ones */ while (x != NULL && !BAD_HVAL(x->hval)) { n = x->n; x->n = NULL; x = n; } if (x == NULL || UID_REUSABLE(tab->c->timestamp(), x) == 0) { /* none is available, make a new one */ tab->list = x; x = new_uid(tab, tab->buid + 1); } else { n = x->n; x->n = NULL; tab->list = n; } /* update the available list */ if (tab->list == NULL) { tab->tail = NULL; } assignx = 1; if (x != NULL) { *uid_p = x->uid; } } if (x == NULL) { return (-1); /* no memory */ } x->hval = hval; x->t = 0; /* registration initial time */ return (assignx); } /* * **************************************************************************** * enlarge_htab: * enlarge the hash table when it gets too full. * * tab - the hash table. * * **************************************************************************** */ static void enlarge_htab( htab_t *tab ) { htab_item_t **items; uint16_t logsize; uint32_t oldsz, newsz, mask; htab_item_t *item, *tmp, **itemp; uint16_t i; uint32_t j; uint32_t uid; /* enlarge the logsize by one */ logsize = tab->logsize + 1; newsz = (1 << logsize); items = (htab_item_t **)calloc( newsz * tab->chunks, sizeof (htab_item_t *)); /* re-hash all items to the new table */ if (items != NULL) { mask = newsz - 1; oldsz = (1 << tab->logsize); i = 0; while (i < tab->chunks) { j = 0; while (j < oldsz) { item = tab->items[(i * oldsz) + j]; while (item != NULL) { tmp = item->next; itemp = &items[(i * newsz) + (item->hval & mask)]; uid = tab->c->get_uid(item->p); while (*itemp != NULL && tab->c->get_uid((*itemp)->p) > uid) { itemp = &(*itemp)->next; } item->next = *itemp; *itemp = item; item = tmp; } j ++; } i ++; } free(tab->items); tab->items = items; tab->logsize = logsize; tab->mask = mask; } else { isnslog(LOG_DEBUG, "enlarge_htab", "calloc() failed."); } } /* * **************************************************************************** * htab_init: * some generic initialization for the hash table. * * **************************************************************************** */ void htab_init( ) { /* do nothing */ } /* * **************************************************************************** * htab_create: * create a new hash table. * * flags - UID_FLAGS_SEQ: the UID in the table needs to be sequential. * logsize - the hash table logsize. * chunks - the number of seperated chunks of the table. * return - the newly created hash table. * * **************************************************************************** */ htab_t * htab_create( int flags, uint16_t logsize, uint16_t chunks ) { htab_t *tab = NULL; htab_item_t **items = NULL; uint32_t count; /* do not enlarge it if the logsize reaches the maximum */ if (logsize <= MAX_LOGSIZE && chunks > 0) { tab = (htab_t *)calloc(1, sizeof (htab_t)); if (tab != NULL) { count = (1 << logsize); items = (htab_item_t **)calloc( count * chunks, sizeof (htab_item_t *)); if (items != NULL) { tab->flags = flags; tab->items = items; tab->logsize = logsize; tab->chunks = chunks; tab->mask = count - 1; tab->count = 1; /* reserve one */ tab->avlt = NULL; tab->buid = 0; tab->list = NULL; tab->tail = NULL; } else { free(tab); tab = NULL; } } } return (tab); } /* * **************************************************************************** * htab_compute_hval: * compute a hash value for the specified key. * * key - the key of the hash. * return - the hash value. * * **************************************************************************** */ uint32_t htab_compute_hval( const uchar_t *key ) { /* use classic Dan Bernstein hash alorigthm */ uint32_t hash = 5381; int c; while ((c = *key++) != 0) { hash = ((hash << 5) + hash) + c; } return (hash); } /* * **************************************************************************** * htab_add: * add an object to the hash table. * * tab - the hash table. * p - the object. * flag - 0: not an association object; otherwise association object. * uid_p- pointer of UID for returning. * update_p - pointer of update flag for returning. * return - error code. * * **************************************************************************** */ int htab_add( htab_t *tab, void *p, int flag, uint32_t *uid_p, int *update_p ) { int ec = 0; htab_item_t *items = NULL, **itemp; uint32_t chunksz; uint32_t flags = 0; uint32_t hval; uint32_t uid = 0; int i; /* compute the hash value */ hval = VALID_HVAL(tab->c->get_hval(p, 0, &flags)); /* check for duplicate */ items = tab->items[hval & tab->mask]; while (items != NULL) { if (tab->c->cmp(items->p, p, 0) == 0) { if (flag == 0) { ec = tab->c->replace_hook(items->p, p, uid_p, update_p == NULL ? 1 : 0); } if (update_p != NULL) { *update_p = 1; } items = NULL; goto add_done; } items = items->next; } /* add new object */ if (update_p != NULL) { *update_p = 0; } /* make new items for the object */ items = (htab_item_t *)calloc(tab->chunks, sizeof (htab_item_t)); if (items == NULL || tab->count == 0 || (++tab->count) == 0) { /* no memory or table is full */ ec = ISNS_RSP_INTERNAL_ERROR; goto add_done; } /* check if the table needs is too full */ chunksz = (1 << tab->logsize); if (tab->count >= (chunksz * HASH_RATIO) && tab->logsize < MAX_LOGSIZE) { enlarge_htab(tab); chunksz = (1 << tab->logsize); } /* put the UID of the object to the avl tree */ uid = tab->c->get_uid(p); switch (uid_insert(tab, &uid, hval)) { case -2: ec = ISNS_RSP_INVALID_REGIS; goto add_done; case -1: ec = ISNS_RSP_INTERNAL_ERROR; goto add_done; case 0: break; case 1: tab->c->set_uid(p, uid); break; default: break; } /* update data store before putting to hash table */ if (flag == 0) { /* not association object */ ec = tab->c->add_hook(p); } /* put the object to the table */ for (i = 0; ec == 0; ) { items[i].hval = hval; items[i].p = p; itemp = &tab->items[(i * chunksz) + (hval & tab->mask)]; while (*itemp != NULL && tab->c->get_uid((*itemp)->p) > uid) { itemp = &(*itemp)->next; } items[i].next = *itemp; *itemp = &items[i]; i ++; if (i < tab->chunks) { hval = VALID_HVAL(tab->c->get_hval(p, i, &flags)); } else { break; } } /* cache has been successfully updated */ SET_CACHE_UPDATED(); /* successfully added */ items = NULL; if (ec == 0) { /* perform the Default DD behavior */ tab->c->ddd(p, '+'); /* set the return uid */ if (uid_p != NULL) { *uid_p = uid; } } add_done: if (ec != 0 && items != NULL) { free(items); } return (ec); } /* * **************************************************************************** * htab_remove: * remove an object from the hash table. * * tab - the hash table. * p - the lookup control for the object. * uid - the UID of the object. * clone_flag - indicate if the removing is for an association object. * return - the removed object. * * **************************************************************************** */ isns_obj_t * htab_remove( htab_t *tab, void *p, uint32_t uid, int clone_flag ) { void *zhizi = NULL; void *clone = NULL; htab_item_t *items = NULL; htab_item_t *item, **itemp; htab_itemx_t *x = NULL; uint32_t chunksz; uint32_t flags; uint32_t hval; int i; /* get the object hash value */ if (uid != 0) { x = avl_search(tab, uid); if (x != NULL && !BAD_HVAL(x->hval)) { hval = x->hval; } else { goto remove_done; } } else { flags = 0 | FLAGS_CTRL_MASK; hval = VALID_HVAL(tab->c->get_hval(p, 0, &flags)); } /* search the object from the table */ flags = 0; chunksz = (1 << tab->logsize); for (i = 0; ; ) { itemp = &tab->items[(i * chunksz) + (hval & tab->mask)]; item = *itemp; while (item != NULL) { /* found it */ if (tab->c->cmp(item->p, p, 1) == 0) { /* make an association object if the object */ /* has membership in user-defined DD(s). */ if (i == 0) { if ((clone = tab->c->clone(item->p, clone_flag)) == NULL) { tab->c->ddd(item->p, '-'); tab->count --; items = item; zhizi = item->p; } } if (clone == NULL) { /* remove it */ *itemp = item->next; } else if (clone == item->p) { /* itself is an association object */ goto remove_done; } else { /* replace it with association */ zhizi = item->p; item->p = clone; } if (i == 0) { /* obj has been removed or updated */ SET_CACHE_UPDATED(); } break; } itemp = &item->next; item = *itemp; } i ++; if (zhizi != NULL && i < tab->chunks) { hval = VALID_HVAL(tab->c->get_hval( zhizi, i, &flags)); } else { break; } } /* update the node in the avl tree */ if (items != NULL) { if (x == NULL) { uid = tab->c->get_uid(zhizi); ASSERT(uid != 0); x = avl_search(tab, uid); } ASSERT(x != NULL && !BAD_HVAL(x->hval)); /* mark the uid item as invalid */ x->hval |= BAD_HVAL_MASK; /* update the timestamp */ x->t = tab->c->timestamp(); /* put it to the end of fifo list */ if (tab->list != NULL) { tab->tail->n = x; } else { tab->list = x; } tab->tail = x; } remove_done: if (items != NULL) { free(items); } return (zhizi); } /* * **************************************************************************** * htab_lookup: * lookup an object from the hash table. * * tab - the hash table. * p - the lookup control for the item. * uid - the UID of the object. * uid_p- the pointer of UID for returning. * callback - callback function if the object is found. * rekey - flag that indicates if the callback function will update * the key of the object. * return - error code. * * **************************************************************************** */ int htab_lookup( htab_t *tab, void *p, uint32_t uid, uint32_t *uid_p, int (*callback)(void *, void *), int rekey ) { uint32_t ret = 0; void *zhizi = NULL; htab_item_t *item, **itemp; htab_itemx_t *x = NULL; uint32_t chunksz; uint32_t flags = 0 | FLAGS_CTRL_MASK; uint32_t hval; int i; /* compute the hash value */ if (uid != 0) { x = avl_search(tab, uid); if (x != NULL) { hval = x->hval; } else { hval = BAD_HVAL_MASK; } } else { hval = VALID_HVAL(tab->c->get_hval(p, 0, &flags)); } /* find the object */ if (!BAD_HVAL(hval)) { i = flags & FLAGS_CHUNK_MASK; chunksz = (1 << tab->logsize); itemp = &tab->items[(i * chunksz) + (hval & tab->mask)]; item = *itemp; while (item != NULL) { if (tab->c->cmp(item->p, p, 1) == 0) { zhizi = item->p; break; } itemp = &item->next; item = *itemp; } } /* found it */ if (zhizi != NULL) { /* set the return uid */ if (uid_p != NULL) { *uid_p = tab->c->get_uid(zhizi); } /* invoke callback */ if (callback != NULL) { ret = callback(zhizi, p); } if (rekey != 0 && ret == 0) { /* Rekey works for one-chunk hash table only. */ ASSERT(tab->chunks == 1 && x != NULL); /* remove from previous slot */ *itemp = item->next; /* add it to the new slot */ flags = 0; hval = VALID_HVAL(tab->c->get_hval(zhizi, 0, &flags)); x->hval = hval; item->hval = hval; itemp = &tab->items[(hval & tab->mask)]; while (*itemp != NULL && (tab->c->get_uid((*itemp)->p) > tab->c->get_uid(zhizi))) { itemp = &(*itemp)->next; } item->next = *itemp; *itemp = item; } } else if (uid_p != NULL) { /* set the return uid to 0 */ *uid_p = 0; } return (ret); } /* * **************************************************************************** * htab_get_next: * get the next object UID from the hash table. * * tab - the hash table. * uid - the previous objet UID. * return - the next object UID. * * **************************************************************************** */ uint32_t htab_get_next( htab_t *tab, uint32_t uid ) { htab_itemx_t *x; do { /* search the next node from the avl tree */ x = avl_search_next(tab, uid); if (x != NULL) { uid = x->uid; /* validate the node */ if (!BAD_HVAL(x->hval)) { return (uid); } } } while (x != NULL); /* no more node is available */ return (0); } /* * **************************************************************************** * htab_dump: * dump all objects stored in the hash table for debug purpose. * * tab - the hash table. * * **************************************************************************** */ #ifdef DEBUG void htab_dump( htab_t *tab ) { uint32_t chunksz; htab_item_t *items; uint32_t i; chunksz = (1 << tab->logsize); for (i = 0; i < chunksz; i++) { items = tab->items[i]; while (items != NULL) { tab->c->dump(items->p); items = items->next; } } } #endif /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_CACHE_H #define _ISNS_CACHE_H #include #include #include #ifdef __cplusplus extern "C" { #endif #define CACHE_FLAG_UPDATED 0x1 #define SET_CACHE_UPDATED() (cache_flag |= CACHE_FLAG_UPDATED) #define RESET_CACHE_UPDATED() (cache_flag &= ~CACHE_FLAG_UPDATED) #define IS_CACHE_UPDATED() (cache_flag & CACHE_FLAG_UPDATED) #define CACHE_NO_ACTION (0) #define CACHE_READ (1) #define CACHE_TRY_READ (2) #define CACHE_WRITE (3) typedef struct cache { rwlock_t l; htab_t **t; matrix_t **x; uint32_t (*get_hval)(void *, uint16_t, uint32_t *); uint32_t (*get_uid)(const void *); uint32_t (*set_uid)(void *, uint32_t); uint32_t (*timestamp)(void); int (*add_hook)(void *); int (*replace_hook)(void *, void *, uint32_t *, int); int (*cmp)(void *, void *, int); void *(*clone)(void *, int); int (*ddd)(void *, const uchar_t); #ifdef DEBUG void (*dump)(void *); #endif } cache_t; int cache_init(void); void cache_destroy(void); int cache_lock(int); int cache_unlock(int, int); int cache_lock_read(void); int cache_lock_write(void); int cache_unlock_sync(int); int cache_unlock_nosync(void); htab_t *cache_get_htab(isns_type_t); matrix_t *cache_get_matrix(isns_type_t); int cache_lookup(lookup_ctrl_t *, uint32_t *, int (*)(void *, void *)); int cache_rekey(lookup_ctrl_t *, uint32_t *, int (*)(void *, void *)); int cache_add(isns_obj_t *, int, uint32_t *, int *); isns_obj_t *cache_remove(lookup_ctrl_t *, int); #ifdef DEBUG void cache_dump_htab(isns_type_t); #endif #ifdef __cplusplus } #endif #endif /* _ISNS_CACHE_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_CFG_H #define _ISNS_CFG_H #ifdef __cplusplus extern "C" { #endif /* the list of the administratively configured control nodes */ typedef struct ctrl_node { uchar_t *name; struct ctrl_node *next; } ctrl_node_t; /* function prototype */ int load_config( boolean_t ); int is_control_node(uchar_t *); #ifdef __cplusplus } #endif #endif /* _ISNS_CFG_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_DD_H #define _ISNS_DD_H #include #ifdef __cplusplus extern "C" { #endif typedef uint32_t bmp_t; /* * dd matrix */ typedef struct matrix { uint32_t x, y; /* uint32_t *z; */ /* obsoleted- map between uid & mid */ /* rwlock_t l; */ /* obsoleted */ bmp_t *m; struct cache *c; } matrix_t; #define MATRIX_X_HEADER (1) #define MATRIX_X_INFO(X) (X[0]) #define SIZEOF_X_UNIT(M) (((M)->x + MATRIX_X_HEADER) * sizeof (bmp_t)) #define MATRIX_X_UNIT(M, N) &(M)->m[(N) * ((M)->x + MATRIX_X_HEADER)] #define NUM_OF_MEMBER(M) ((M)->x * sizeof (bmp_t) * 8) #define UID2MID(M, UID) get_mid(M, UID) #define NEW_MID(M, UID) new_mid(M, UID) #define GET_PRIMARY(UID) (UID) / (sizeof (bmp_t) * 8) #define GET_SECOND(UID) (UID) % (sizeof (bmp_t) * 8) #define COMP_UID(PRI, SND) ((PRI) * sizeof (bmp_t) * 8 + (SND)) #define SET_MEMBERSHIP(BMP, PRI, SND) \ (BMP)[(PRI) + MATRIX_X_HEADER] |= (0x1 << (SND)) #define CLEAR_MEMBERSHIP(BMP, PRI, SND) \ (BMP)[(PRI) + MATRIX_X_HEADER] &= ~(0x1 << (SND)) #define TEST_MEMBERSHIP(BMP, PRI, SEC) \ ((BMP)[(PRI) + MATRIX_X_HEADER] & (0x1 << (SEC))) #define FOR_EACH_MEMBER(BMP, NUM, UID, STMT) \ {\ int i1624 = 0;\ while (i1624 < (NUM)) {\ int j1624 = 0;\ while (j1624 < 8 * sizeof ((BMP)[0])) {\ if (((BMP)[i1624] & (1 << j1624)) != 0) {\ UID = COMP_UID(i1624, j1624);\ STMT\ }\ j1624 ++;\ }\ i1624 ++;\ }\ } /* functions */ int dd_matrix_init(struct cache *); int create_dd_object(isns_tlv_t *, uint16_t, isns_obj_t **); int create_dds_object(isns_tlv_t *, uint16_t, isns_obj_t **); int adm_create_dd(isns_obj_t **, uchar_t *, uint32_t, uint32_t); int adm_create_dds(isns_obj_t **, uchar_t *, uint32_t, uint32_t); int update_dd_name(uint32_t, uint32_t, uchar_t *); int update_dds_name(uint32_t, uint32_t, uchar_t *); int update_dd_features(uint32_t, uint32_t); int update_dds_status(uint32_t, uint32_t); uint32_t get_dd_id(uint32_t, uint32_t); uint32_t get_dds_id(uint32_t, uint32_t); uint32_t get_common_dd(uint32_t, uint32_t, uint32_t); int remove_dd_object(uint32_t); int remove_dds_object(uint32_t); int add_dd_member(isns_obj_t *); int add_dds_member(isns_obj_t *); int remove_dd_member(isns_obj_t *); int remove_dds_member(uint32_t, uint32_t); int get_dd_matrix(const uint32_t, bmp_t **, uint32_t *); int get_dds_matrix(const uint32_t, bmp_t **, uint32_t *); int get_scope(uchar_t *, bmp_t **, uint32_t *); int cb_clone_attrs(void *, void *); int is_dd_active(uint32_t); int update_ddd(void *, const uchar_t); int verify_ddd(void); #ifdef __cplusplus } #endif #endif /* _ISNS_DD_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_DSAPI_H #define _ISNS_DSAPI_H #include #ifdef __cplusplus extern "C" { #endif int target_init_data(); int target_load_obj(void **, isns_obj_t **, uchar_t *); int target_add_obj(const isns_obj_t *); int target_modify_obj(const isns_obj_t *); int target_delete_obj(const isns_obj_t *); int target_delete_assoc(const isns_obj_t *); int target_update_commit(); int target_update_retreat(); #ifdef __cplusplus } #endif #endif /* _ISNS_DSAPI_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_DSENG_H #define _ISNS_DSENG_H #include #ifdef __cplusplus extern "C" { #endif int init_data(); int load_data(); int write_data(int, const isns_obj_t *); #ifdef __cplusplus } #endif #endif /* _ISNS_DSENG_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_ESI_H #define _ISNS_ESI_H #ifdef __cplusplus extern "C" { #endif typedef enum { EV_ESI = 1, EV_REG_EXP } ev_type_t; #define EV_FLAG_INIT (0x01) #define EV_FLAG_AGAIN (0x02) #define EV_FLAG_WAKEUP (0x04) #define EV_FLAG_REMOVE (0x08) #define EV_FLAG_REM_P1 (0x10) #define EV_FLAG_REM_P2 (0x20) #define EV_FLAG_REM_P3 (0x40) #define EV_FLAG_REM_P4 (0x80) #define EV_FLAG_REM_P (0xF0) typedef struct esi_portal { int sz; in_addr_t ip4; in6_addr_t *ip6; uint32_t port; uint32_t esip; uint32_t ref; int so; struct esi_portal *next; } esi_portal_t; typedef struct ev { ev_type_t type; uint32_t uid; uint32_t intval; int flags; uchar_t *eid; uint32_t eid_len; esi_portal_t *portal; pthread_mutex_t mtx; struct ev *next; } ev_t; /* function prototypes */ int esi_load(uint32_t, uchar_t *, uint32_t); int esi_add(uint32_t, uchar_t *, uint32_t); int esi_remove(uint32_t); int esi_remove_obj(const isns_obj_t *, int); int verify_esi_portal(); uint32_t get_stopwatch(int); uint32_t ev_intval(void *); int ev_match(void *, uint32_t); int ev_remove(void *, uint32_t, int, int); void ev_free(void *); int evf_init(void *); int evf_again(void *); int evf_wakeup(void *); int evf_rem(void *); int evf_rem_pending(void *); void evf_zero(void *); void evl_append(void *); void evl_strip(void *); int evl_remove(uint32_t, uint32_t, int); void *esi_proc(void *); void portal_dies(uint32_t); void reg_expiring(void *); #ifdef __cplusplus } #endif #endif /* _ISNS_ESI_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_FUNC_H #define _ISNS_FUNC_H #include #ifdef __cplusplus extern "C" { #endif typedef struct conn_arg { int so; int lock; int (*handler)(struct conn_arg *); struct { isns_pdu_t *pdu; isns_tlv_t *source; isns_tlv_t *key; size_t key_len; isns_tlv_t *op; size_t op_len; } in_packet; struct { isns_pdu_t *pdu; size_t pl; size_t sz; } out_packet; struct sockaddr_storage ss; int ec; } conn_arg_t; int packet_split_verify(conn_arg_t *); isns_pdu_t *make_dummy_rsp(isns_pdu_t *, int); int isns_response(conn_arg_t *); #ifdef __cplusplus } #endif #endif /* _ISNS_FUNC_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_HTAB_H #define _ISNS_HTAB_H #ifdef __cplusplus extern "C" { #endif #define HASH_RATIO (3) #define MAX_LOGSIZE (sizeof (uint32_t) * 8 - 1) #define HVAL_MASK (((uint32_t)1 << MAX_LOGSIZE) - 1) #define BAD_HVAL_MASK ((uint32_t)1 << MAX_LOGSIZE) #define VALID_HVAL(H) ((H) & HVAL_MASK) #define BAD_HVAL(H) (((H) & BAD_HVAL_MASK) == BAD_HVAL_MASK) #define FLAGS_CTRL_MASK (0x10000000) #define FLAGS_CHUNK_MASK (0x00001111) typedef struct htab_item { uint32_t hval; void *p; struct htab_item *next; } htab_item_t; typedef struct htab_itemx { uint32_t uid; uint32_t hval; uint32_t t; int bf; struct htab_itemx *l; struct htab_itemx *r; struct htab_itemx *n; } htab_itemx_t; typedef struct htab { int flags; struct cache *c; htab_item_t **items; uint16_t logsize; uint16_t chunks; uint32_t mask; uint32_t count; /* AVL tree of the object UIDs */ htab_itemx_t *avlt; /* the biggest UID in the tree */ uint32_t buid; /* fifo list of available UIDs */ htab_itemx_t *list; htab_itemx_t *tail; } htab_t; #define UID_FLAGS_SEQ (0x1) #define FOR_EACH_ITEM(HTAB, UID, STMT) \ {\ UID = htab_get_next(HTAB, UID);\ while (UID != 0) {\ STMT\ UID = htab_get_next(HTAB, UID);\ }\ } void htab_init(void); htab_t *htab_create(int, uint16_t, uint16_t); void htab_destroy(htab_t *); uint32_t htab_compute_hval(const uchar_t *); int htab_add(htab_t *, void *, int, uint32_t *, int *); isns_obj_t *htab_remove(htab_t *, void *, uint32_t, int); int htab_lookup(htab_t *, void *, uint32_t, uint32_t *, int (*)(void *, void *), int); uint32_t htab_get_next(htab_t *, uint32_t); #ifdef DEBUG void htab_dump(htab_t *); #endif #ifdef __cplusplus } #endif #endif /* _ISNS_HTAB_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_LOG_H #define _ISNS_LOG_H #include #ifdef __cplusplus extern "C" { #endif /* * macros for message log. */ /* * function prototype. */ void isnslog(int, const char *, char *, ...); #ifdef __cplusplus } #endif #endif /* _ISNS_LOG_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_MGMT_H #define _ISNS_MGMT_H #ifdef __cplusplus extern "C" { #endif #include #include #define ISNS_DOOR_NAME "/var/run/isns_server_door" #define ISNS_ADMIN_WRITE_AUTH "solaris.isnsmgr.write" #define ISNS_MAX_LABEL_LEN 50 #define ISNS_MAX_NAME_LEN 256 #define DOOR_DEFAULT_BUF_SIZE 4096 #define MAX_DATA_COUNT 100 /* macro */ #define XMLNCMP(x, y) (xmlStrncasecmp(xmlTextReaderConstName(x), \ (const xmlChar *)y, xmlStrlen(xmlTextReaderConstName(x)))) #define XMLNCMPVAL(x, y) (xmlStrncasecmp(xmlTextReaderConstValue(x), \ (const xmlChar *)y, xmlStrlen(xmlTextReaderConstName(x)))) /* operation element names */ #define ISNSREQUEST "isnsRequest" #define ISNSRESPONSE "isnsResponse" #define RESULT "result" #define GET "get" #define ENUMERATE "enumerate" #define GETASSOCIATED "getAssociated" #define CREATEMODIFY "createModify" #define DELETE "delete" /* object element names */ #define ISNSOBJECT "isnsObject" #define ASSOCIATION "Association" #define ISNSSERVER "isnsServer" #define NODEOBJECT "Node" #define DDOBJECT "DiscoveryDomain" #define DDSETOBJECT "DiscoveryDomainSet" #define DDOBJECTMEMBER "DiscoveryDomainMember" #define DDSETOBJECTMEMBER "DiscoveryDomainSetMember" /* iSNS NODE attribute element names - Network Entity */ #define XMLNSATTR "xmlns" #define XMLNSATTRVAL "http://www.sun.com/schema/isnsmanagement" /* iSNS NODE attribute element names - Network Entity */ #define NETWORKENTITY "Network_Entity" #define ENTITYID "Entity_ID" #define ENTITYPROTOCOL "Entity_Protocol" #define MANAGEMENTIPADDR "Management_IP_Addr" #define ENTITYREGTIMESTAMP "Entity_Reg_Timestamp" #define PROTOCOLVERSIONRANGE "Protocol_Version_Range" #define PROTOCOLMINVERSION "minVersion" #define PROTOCOLMAXVERSION "maxVersion" #define REGISTRATIONPERIOD "Registration_Period" /* iSNS NODE attribute element names - Portal element names */ #define SCNSUBSCRIPTION "SCN_Subscription" #define SCNINITSELFONLY "Initiator and Self information only" #define SCNTARGETSELFONLY "Target and Self information only" #define SCNMGMTREG "Management Registration/SCN" #define SCNOBJECTREMOVED "Object Removed" #define SCNOBJECTADDED "Object Added" #define SCNOBJECTUPDATED "Object Updated" #define SCNMEMBERREMOVED "DD/DD-Set Member Removed" #define SCNMEMBERADDED "DD/DD-Set Member Added" #define PORTAL "Portal" #define REGISTRATIONPERIOD "Registration_Period" #define IPADDR "IP_Addr" #define UDPTCPPORT "UDP_TCP_port" #define PORTTYPE "Port_Type" #define UDPPORT "UDP" #define TCPPORT "TCP" #define PORTNUMBER "Port_Number" #define GROUPTAG "Group_Tag" #define SYMBOLICNAME "Symbolic_Name" #define ESIINTERVAL "ESI_Interval" #define ESIPORT "ESI_Port" #define SCNPORT "SCN_Port" /* iSNS DD set state element */ #define ENABLEDELEM "Enabled" /* iSNS DD Boot List element */ #define BOOTLISTENABLEDELEM "BootList_Enabled" /* iSNS server config elements */ #define DATASTORELOCATION "datastoreLocation" #define ESIRETRYTHRESHOLD "esiRetryThreshold" #define DEFAULTDDDDSETENABLED "defaultDD_DDsetEnabled" #define MANAGEMENTSCNENABLED "managementSCNEnabled" #define CANCONTROLNODEMODIFYDDDDSET "canControlNodeModifyDD_DDset" #define CANINTIATORNODEMODIFYDDDDSET "canIntiatorNodeModifyDD_DDset" #define CANTARGETNODEMODIFYDDDDSET "canTargetNodeModifyDD_DDset" #define CONTROLNODENAME "controlNodeName" /* object element type names */ #define ISNSOBJECTTYPE "isnsObjectType" #define ASSOCIATIONTYPE "AssociationType" /* attribute names */ #define NAMEATTR "name" #define IDATTR "id" #define TYPEATTR "type" #define ALIASATTR "alias" #define NODENAMEATTR "NodeName" #define DDNAMEATTR "DDName" #define DDSETNAMEATTR "DDsetName" #define EMPTYSTR "" /* Node type value names */ #define INITIATORTYPE "Initiator" #define TARGETTYPE "Target" #define CONTROLNODETYPE "Control" #define CONTROLNODETARGETTYPE "Control/Target" #define CONTROLNODEINITIATORTYPE "Control/Initiator" #define UNKNOWNTYPE "Unknown" /* response related element names. */ #define RESULTELEMENT "result" #define STATUSELEMENT "status" #define MESSAGEELEMENT "message" /* response related element names. */ #define XMLTRUE "true" #define XMLFALSE "false" typedef enum { get_op = 100, enumerate_op, getAssociated_op, createModify_op, delete_op } request_op; typedef enum { member_to_container, container_to_member } association_req_t; typedef struct { char *op_str; request_op op_id; } op_table_entry_t; typedef enum { Node = 100, DiscoveryDomain, DiscoveryDomainSet, DiscoveryDomainMember, DiscoveryDomainSetMember, ServerConfig } object_type; typedef struct { char *obj_str; object_type obj_id; } obj_table_entry_t; typedef struct thr_elem { pthread_t thr_id; xmlChar *doc; struct thr_elem *next; } thr_elem_t; /* * request entry with interger and string value */ typedef struct { request_op op; object_type obj; } operation_t; typedef struct { xmlChar *container; xmlChar *member; } assoc_pair_t; typedef struct { xmlChar *name; uint32_t *id; boolean_t *enabled; } object_attrlist_t; typedef union { xmlChar **data; assoc_pair_t **pair; object_attrlist_t **attrlist; } req_data_ut; typedef struct { operation_t op_info; association_req_t assoc_req; uint_t count; req_data_ut req_data; } request_t; #ifdef __cplusplus } #endif #endif /* _ISNS_MGMT_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_MSGQ_H #define _ISNS_MSGQ_H #include #include #ifdef __cplusplus extern "C" { #endif #define TEST_CLI_STOPPED (0x0001) #define DD_SERVICE_STOPPED (0x0002) #define SCN_STOPPED (0x0004) #define ESI_STOPPED (0x0008) typedef enum msg_id { DATA_ADD = 1, DATA_UPDATE, DATA_DELETE, DATA_DELETE_ASSOC, DATA_COMMIT, DATA_RETREAT, REG_EXP, DEAD_PORTAL, SYS_QUIT_OK, SCN_ADD = 100, SCN_REMOVE, SCN_REMOVE_P, SCN_SET, SCN_TRIGGER, SCN_IGNORE, SCN_STOP, SERVER_EXIT, CONFIG_RELOAD } msg_id_t; typedef struct msg_text { struct msg_text *prev; struct msg_text *next; msg_id_t id; void *data; } msg_text_t; typedef struct msg_queue { msg_text_t *q_head; msg_text_t *q_tail; pthread_mutex_t q_mutex; sema_t q_sema; } msg_queue_t; /* function prototypes */ msg_queue_t *queue_calloc(); int queue_msg_set(msg_queue_t *, msg_id_t, void *); msg_text_t *queue_msg_get(msg_queue_t *); void queue_msg_free(msg_text_t *); #ifdef __cplusplus } #endif #endif /* _ISNS_MSGQ_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_OBJ_H #define _ISNS_OBJ_H #ifdef __cplusplus extern "C" { #endif #define ENTITY_KEY ISNS_EID_ATTR_ID #define ISCSI_KEY ISNS_ISCSI_NAME_ATTR_ID #define PORTAL_KEY1 ISNS_PORTAL_IP_ADDR_ATTR_ID #define PORTAL_KEY2 ISNS_PORTAL_PORT_ATTR_ID #define PG_KEY1 ISNS_PG_ISCSI_NAME_ATTR_ID #define PG_KEY2 ISNS_PG_PORTAL_IP_ADDR_ATTR_ID #define PG_KEY3 ISNS_PG_PORTAL_PORT_ATTR_ID #define PG_PGT ISNS_PG_TAG_ATTR_ID #define DD_KEY ISNS_DD_ID_ATTR_ID #define DDS_KEY ISNS_DD_SET_ID_ATTR_ID #define ENTITY_END ISNS_ENTITY_CERT_ATTR_ID #define ISCSI_END ISNS_ISCSI_AUTH_METHOD_ATTR_ID #define PORTAL_END ISNS_PORTAL_CERT_ATTR_ID #define PG_END ISNS_PG_NEXT_ID_ATTR_ID #define DD_END ISNS_DD_FEATURES_ATTR_ID #define DDS_END ISNS_DD_SET_STATUS_ATTR_ID #define IS_ENTITY_KEY(ID) ((ID) == ENTITY_KEY) #define IS_ISCSI_KEY(ID) ((ID) == ISCSI_KEY) #define IS_PORTAL_KEY1(ID) ((ID) == PORTAL_KEY1) #define IS_PORTAL_KEY2(ID) ((ID) == PORTAL_KEY2) #define IS_PG_KEY1(ID) ((ID) == PG_KEY1) #define IS_PG_KEY2(ID) ((ID) == PG_KEY2) #define IS_PG_KEY3(ID) ((ID) == PG_KEY3) #define IS_PG_PGT(ID) ((ID) == PG_PGT) #define IS_ENTITY_ATTR(ID) \ ((ID) > ENTITY_KEY && (ID) <= ENTITY_END) #define IS_ISCSI_ATTR(ID) \ ((ID) > ISCSI_KEY && (ID) <= ISCSI_END) #define IS_PORTAL_ATTR(ID) \ ((ID) > PORTAL_KEY2 && (ID) <= PORTAL_END) #define IS_PG_ATTR(ID) \ ((ID) > PG_KEY1 && (ID) <= PG_END) /* functions */ int obj_tab_init(struct cache *); uint32_t set_obj_uid(void *, uint32_t); int extract_attr(isns_attr_t *, const isns_tlv_t *, int); int assign_attr(isns_attr_t *, const isns_attr_t *); void free_one_object(isns_obj_t *); void free_object(isns_obj_t *); isns_obj_t *obj_calloc(int); isns_obj_t *make_default_entity(); int reg_get_entity( isns_obj_t **, isns_tlv_t **, uint16_t * ); int reg_get_obj( isns_obj_t **, isns_attr_t *, isns_tlv_t **, uint16_t * ); int reg_auth_src(isns_type_t, uint32_t, uchar_t *); int set_parent_obj(isns_obj_t *, uint32_t); int buff_child_obj(const isns_type_t, const isns_type_t, const void *, void const***); int update_child_obj(const isns_type_t, const uint32_t, void const***, int); int update_ref_obj(const isns_obj_t *); int verify_ref_obj(const isns_type_t, const uint32_t, void const***); int update_deref_obj(isns_obj_t *); uint32_t set_child_number(isns_obj_t *, int, uint16_t); int key_cmp(lookup_ctrl_t *, isns_obj_t *); int register_object(isns_obj_t *, uint32_t *, int *); int register_assoc(isns_obj_t *, uint32_t *); int dereg_assoc(lookup_ctrl_t *); int dereg_object(lookup_ctrl_t *, int); int dereg_downwards(isns_obj_t *); int data_sync(int); uint32_t obj_hval(void *, uint16_t, uint32_t *); int is_obj_equal(isns_obj_t *, isns_obj_t *); uint32_t get_obj_uid(const void *); uint32_t is_obj_there(lookup_ctrl_t *); uint32_t is_parent_there(uchar_t *); void *assoc_clone(void *, int); int obj_cmp(void *, void *, int); int add_object(void *); int replace_object(void *, void *, uint32_t *, int); #ifdef DEBUG void obj_dump(void *); uint32_t *get_child_n(isns_obj_t *, int); uint32_t get_ref_n(isns_obj_t *, int); #endif uint32_t get_ref_t(isns_obj_t *, isns_type_t); uint32_t *const get_parent_p(const isns_obj_t *); uint32_t get_parent_uid(const isns_obj_t *); uint32_t *get_child_t(isns_obj_t *, int); int is_obj_online(const isns_obj_t *); uint32_t get_timestamp(void); #ifdef __cplusplus } #endif #endif /* _ISNS_OBJ_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_PDU_H #define _ISNS_PDU_H #ifdef __cplusplus extern "C" { #endif #define ISNS_RCV_TIMEOUT 5 #define ISNS_RCV_SHORT_TIMEOUT 1 #define NEXT_TLV(OP, LEN) { \ if ((LEN) >= (8 + (OP)->attr_len)) { \ uint8_t *b1 = (uint8_t *)(OP); \ (LEN) -= (8 + (OP)->attr_len); \ b1 += (8 + (OP)->attr_len); \ (OP) = (isns_tlv_t *)b1; \ } else { \ (LEN) = 0; \ (OP) = NULL; \ } \ } size_t isns_rcv_pdu(int, isns_pdu_t **, size_t *, int); int isns_send_pdu(int, isns_pdu_t *, size_t); int pdu_reset_rsp(isns_pdu_t **, size_t *, size_t *); int pdu_reset_scn(isns_pdu_t **, size_t *, size_t *); int pdu_reset_esi(isns_pdu_t **, size_t *, size_t *); int pdu_update_code(isns_pdu_t *, size_t *, int); int pdu_add_tlv(isns_pdu_t **, size_t *, size_t *, uint32_t, uint32_t, void *, int); isns_tlv_t *pdu_get_source(isns_pdu_t *); isns_tlv_t *pdu_get_key(isns_pdu_t *, size_t *); isns_tlv_t *pdu_get_operand(isns_pdu_t *, size_t *); #ifdef __cplusplus } #endif #endif /* _ISNS_PDU_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_PROTOCOL_H #define _ISNS_PROTOCOL_H #ifdef __cplusplus extern "C" { #endif #include #include #include #define ISNSP_VERSION (0x01) #define ISNS_DEFAULT_SERVER_PORT (3205) #define ISNSP_HEADER_SIZE (12) #define ISNSP_RSP_CODE_SIZE (4) #define ISNSP_MAX_PAYLOAD_SIZE (65532) #define ISNSP_MAX_PDU_SIZE (ISNSP_HEADER_SIZE + \ ISNSP_MAX_PAYLOAD_SIZE) #define ISNS_TLV_ATTR_ID_LEN (4) #define ISNS_TLV_ATTR_LEN_LEN (4) #define MAX_ISNS_MESG_ATTR_ENTRIES (8) #define MAX_ISNS_OPER_ATTR_ENTRIES (32) /* iSNS Entity Protocol, iSNS Draft - section 6.2.2. */ #define ISNS_ENTITY_PROTOCOL_NO (1) #define ISNS_ENTITY_PROTOCOL_ISCSI (2) #define ISNS_ENTITY_PROTOCOL_FCP (3) /* iSNS Function IDs, iSNS Draft - section 4.1.3. */ #define ISNS_DEV_ATTR_REG (0x0001) #define ISNS_DEV_ATTR_QRY (0x0002) #define ISNS_DEV_GET_NEXT (0x0003) #define ISNS_DEV_DEREG (0x0004) #define ISNS_SCN_REG (0x0005) #define ISNS_SCN_DEREG (0x0006) #define ISNS_SCN_EVENT (0x0007) #define ISNS_SCN (0x0008) #define ISNS_DD_REG (0x0009) #define ISNS_DD_DEREG (0x000A) #define ISNS_DDS_REG (0x000B) #define ISNS_DDS_DEREG (0x000C) #define ISNS_ESI (0x000D) #define ISNS_HEARTBEAT (0x000E) #define ISNS_DEV_ATTR_REG_RSP (0x8001) #define ISNS_DEV_ATTR_QRY_RSP (0x8002) #define ISNS_DEV_GET_NEXT_RSP (0x8003) #define ISNS_DEV_DEREG_RSP (0x8004) #define ISNS_SCN_REG_RSP (0x8005) #define ISNS_SCN_DEREG_RSP (0x8006) #define ISNS_SCN_EVENT_RSP (0x8007) #define ISNS_SCN_RSP (0x8008) #define ISNS_DD_REG_RSP (0x8009) #define ISNS_DD_DEREG_RSP (0x800A) #define ISNS_DDS_REG_RSP (0x800B) #define ISNS_DDS_DEREG_RSP (0x800C) #define ISNS_ESI_RSP (0x800D) /* iSNS Flags, iSNS Draft - section 5.1.4. */ #define ISNS_FLAG_FIRST_PDU (0x0400) #define ISNS_FLAG_LAST_PDU (0x0800) #define ISNS_FLAG_REPLACE_REG (0x1000) #define ISNS_FLAG_AUTH_BLK_PRESENTED (0x2000) #define ISNS_FLAG_SERVER (0x4000) #define ISNS_FLAG_CLIENT (0x8000) /* iSNS Response Status, iSNS Draft - section 5.4 */ #define ISNS_RSP_SUCCESSFUL (0) #define ISNS_RSP_UNKNOWN_ERROR (1) #define ISNS_RSP_MSG_FORMAT_ERROR (2) #define ISNS_RSP_INVALID_REGIS (3) #define ISNS_RSP_INVALID_QRY (5) #define ISNS_RSP_SRC_UNKNOWN (6) #define ISNS_RSP_SRC_ABSENT (7) #define ISNS_RSP_SRC_UNAUTHORIZED (8) #define ISNS_RSP_NO_SUCH_ENTRY (9) #define ISNS_RSP_VER_NOT_SUPPORTED (10) #define ISNS_RSP_INTERNAL_ERROR (11) #define ISNS_RSP_BUSY (12) #define ISNS_RSP_OPTION_NOT_UNDERSTOOD (13) #define ISNS_RSP_INVALID_UPDATE (14) #define ISNS_RSP_MSG_NOT_SUPPORTED (15) #define ISNS_RSP_SCN_EVENT_REJECTED (16) #define ISNS_RSP_SCN_REGIS_REJECTED (17) #define ISNS_RSP_ATTR_NOT_IMPL (18) #define ISNS_RSP_ESI_NOT_AVAILABLE (21) #define ISNS_RSP_INVALID_DEREGIS (22) #define ISNS_RSP_REGIS_NOT_SUPPORTED (23) /* iSNS Attribute IDs, iSNS Draft - section 6.1. */ #define ISNS_DELIMITER_ATTR_ID (0) #define ISNS_EID_ATTR_ID (1) #define ISNS_ENTITY_PROTOCOL_ATTR_ID (2) #define ISNS_MGMT_IP_ADDR_ATTR_ID (3) #define ISNS_TIMESTAMP_ATTR_ID (4) #define ISNS_VERSION_RANGE_ATTR_ID (5) #define ISNS_ENTITY_REG_PERIOD_ATTR_ID (6) #define ISNS_ENTITY_INDEX_ATTR_ID (7) #define ISNS_ENTITY_NEXT_INDEX_ATTR_ID (8) #define ISNS_ENTITY_ISAKMP_P1_ATTR_ID (11) #define ISNS_ENTITY_CERT_ATTR_ID (12) #define ISNS_PORTAL_IP_ADDR_ATTR_ID (16) #define ISNS_PORTAL_PORT_ATTR_ID (17) #define ISNS_PORTAL_NAME_ATTR_ID (18) #define ISNS_ESI_INTERVAL_ATTR_ID (19) #define ISNS_ESI_PORT_ATTR_ID (20) #define ISNS_PORTAL_INDEX_ATTR_ID (22) #define ISNS_SCN_PORT_ATTR_ID (23) #define ISNS_PORTAL_NEXT_INDEX_ATTR_ID (24) #define ISNS_PORTAL_SEC_BMP_ATTR_ID (27) #define ISNS_PORTAL_ISAKMP_P1_ATTR_ID (28) #define ISNS_PORTAL_ISAKMP_P2_ATTR_ID (29) #define ISNS_PORTAL_CERT_ATTR_ID (31) #define ISNS_ISCSI_NAME_ATTR_ID (32) #define ISNS_ISCSI_NODE_TYPE_ATTR_ID (33) #define ISNS_ISCSI_ALIAS_ATTR_ID (34) #define ISNS_ISCSI_SCN_BITMAP_ATTR_ID (35) #define ISNS_ISCSI_NODE_INDEX_ATTR_ID (36) #define ISNS_WWNN_TOKEN_ATTR_ID (37) #define ISNS_NODE_NEXT_INDEX_ATTR_ID (38) #define ISNS_ISCSI_AUTH_METHOD_ATTR_ID (42) #define ISNS_PG_ISCSI_NAME_ATTR_ID (48) #define ISNS_PG_PORTAL_IP_ADDR_ATTR_ID (49) #define ISNS_PG_PORTAL_PORT_ATTR_ID (50) #define ISNS_PG_TAG_ATTR_ID (51) #define ISNS_PG_INDEX_ATTR_ID (52) #define ISNS_PG_NEXT_ID_ATTR_ID (53) #define ISNS_DD_SET_ID_ATTR_ID (2049) #define ISNS_DD_SET_NAME_ATTR_ID (2050) #define ISNS_DD_SET_STATUS_ATTR_ID (2051) #define ISNS_DD_ID_ATTR_ID (2065) #define ISNS_DD_NAME_ATTR_ID (2066) #define ISNS_DD_ISCSI_INDEX_ATTR_ID (2067) #define ISNS_DD_ISCSI_NAME_ATTR_ID (2068) #define ISNS_DD_FC_PORT_NAME_ATTR_ID (2069) #define ISNS_DD_PORTAL_INDEX_ATTR_ID (2070) #define ISNS_DD_PORTAL_IP_ADDR_ATTR_ID (2071) #define ISNS_DD_PORTAL_PORT_ATTR_ID (2072) #define ISNS_DD_FEATURES_ATTR_ID (2078) /* Entity Protocol, RFC 4171 - section 6.2.2. */ #define ISNS_ENTITY_NO_PROTOCOL (1) #define ISNS_ENTITY_ISCSI (2) #define ISNS_ENTITY_IFCP (3) /* Protocol Version Range, RFC 4171 - section 6.2.5. */ #define ISNS_VER_SHIFT (16) #define ISNS_VERSION (0x0000FFFF) /* Portal Port, RFC 4171 - section 6.3.2. */ #define ISNS_PORT_BITS (0x0000FFFF) /* Bits 16 - 31 */ #define ISNS_PORT_TYPE (0x00010000) /* Bit 15 */ /* Portal Security Bitmap, RFC 4171 - section 6.3.9. */ #define ISNS_TUNNEL_MODE_PREFERRED (0x0040) /* Bit 25 */ #define ISNS_TRANS_MODE_PREFERRED (0x0020) /* Bit 26 */ #define ISNS_PFS_ENABLED (0x0010) /* Bit 27 */ #define ISNS_AGGR_MODE_ENABLED (0x0008) /* Bit 28 */ #define ISNS_MAIN_MODE_ENABLED (0x0004) /* Bit 29 */ #define ISNS_IKE_IPSEC_ENABLED (0x0002) /* Bit 30 */ #define ISNS_BITMAP_VALID (0x0001) /* Bit 31 */ /* iSCSI Node Type, RFC 4171 - section 6.4.2. */ #define ISNS_TARGET_NODE_TYPE (0x0001) #define ISNS_INITIATOR_NODE_TYPE (0x0002) #define ISNS_CONTROL_NODE_TYPE (0x0004) /* iSCSI Node SCN Bitmap, RFC 4171 - section 6.4.4. */ #define ISNS_INIT_SELF_INFO_ONLY (0x0080) /* Bit 24 */ #define ISNS_TARGET_SELF_INFO_ONLY (0x0040) /* Bit 25 */ #define ISNS_MGMT_REG (0x0020) /* Bit 26 */ #define ISNS_OBJECT_REMOVED (0x0010) /* Bit 27 */ #define ISNS_OBJECT_ADDED (0x0008) /* Bit 28 */ #define ISNS_OBJECT_UPDATED (0x0004) /* Bit 29 */ #define ISNS_MEMBER_REMOVED (0x0002) /* Bit 30 */ #define ISNS_MEMBER_ADDED (0x0001) /* Bit 31 */ /* Portal Group Tag, RFC 4171 - section 6.5.4. */ #define ISNS_PG_TAG (0x0000FFFF) /* Bits 16 - 31 */ /* DDS Status, RFC 4171 - section 6.11.1.3. */ #define ISNS_DDS_STATUS (0x0001) /* Bit 31 */ /* DD Feature, RFC 4171 - section 6.11.2.9. */ #define ISNS_DD_BOOTLIST (0x0001) /* Bit 31 */ /* iSNS Defaults */ #define ISNS_DEFAULT_PGT (0x00000001) #define ISNS_DEFAULT_DD_SET_ID (1) #define ISNS_DEFAULT_DD_ID (1) /* Min/Max length of names */ #define ISNS_DDS_MAX_NAME_LEN (256) #define ISNS_DD_MAX_NAME_LEN (256) #define ISNS_ISCSI_MAX_NAME_LEN (224) #define ISNS_ISCSI_MAX_ALIAS_LEN (256) #define ISNS_ENTITY_MIN_EID_LEN (3) #define ISNS_ENTITY_MAX_EID_LEN (255) typedef struct isns_tlv { uint32_t attr_id; uint32_t attr_len; uint8_t attr_value[1]; } isns_tlv_t; typedef struct isns_packet_data { uint16_t version; uint16_t func_id; uint16_t payload_len; uint16_t flags; uint16_t xid; uint16_t seq; int num_of_tlvs; isns_tlv_t tlvs[MAX_ISNS_OPER_ATTR_ENTRIES]; } isns_packet_data_t; typedef struct isns_reg_mesg { isns_tlv_t src_attr; int num_of_mesg_attrs; isns_tlv_t *mesg_attrs[MAX_ISNS_MESG_ATTR_ENTRIES]; isns_tlv_t delimiter_attr; isns_tlv_t *operating_attrs[MAX_ISNS_OPER_ATTR_ENTRIES]; } isns_reg_mesg_t; typedef struct isns_resp_mesg { uint8_t status[4]; isns_tlv_t messages_attrs[MAX_ISNS_MESG_ATTR_ENTRIES]; isns_tlv_t delimiter_attr; isns_tlv_t operating_attrs[MAX_ISNS_OPER_ATTR_ENTRIES]; } isns_resp_mesg_t; typedef struct isns_pdu { uint16_t version; uint16_t func_id; uint16_t payload_len; uint16_t flags; uint16_t xid; uint16_t seq; uint8_t payload[1]; } isns_pdu_t; typedef struct isns_resp { uint32_t status; uint8_t data[1]; } isns_resp_t; #ifdef __cplusplus } #endif #endif /* _ISNS_PROTOCOL_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ provider isns { probe connection__accepted(uintptr_t); probe msg__received(uintptr_t); probe msg__responded(uintptr_t); probe operation__type(uintptr_t, uint32_t); probe mgmt__request__received(); probe mgmt__request__responded(); probe mgmt__operation__type(uint32_t); probe mgmt__object__type(uint32_t); }; #pragma D attributes Private/Private/ISA provider isns provider #pragma D attributes Private/Private/Unknown provider isns module #pragma D attributes Private/Private/Unknown provider isns function #pragma D attributes Private/Private/ISA provider isns name #pragma D attributes Private/Private/ISA provider isns args /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_QRY_H #define _ISNS_QRY_H #ifdef __cplusplus extern "C" { #endif #define TLV2TYPE(TLV) \ (TLV)->attr_id >= FIRST_TAG_DD ? OBJ_DD : \ (TLV)->attr_id >= FIRST_TAG_DDS ? OBJ_DDS : \ (TLV)->attr_id >= FIRST_TAG_PG ? OBJ_PG : \ (TLV)->attr_id >= FIRST_TAG_ISCSI ? OBJ_ISCSI : \ (TLV)->attr_id >= FIRST_TAG_PORTAL ? OBJ_PORTAL : \ (TLV)->attr_id >= FIRST_TAG_ENTITY ? OBJ_ENTITY : 0; #define FOR_EACH_OBJS(IDS, NUM, UID, STMT) \ {\ uint32_t i1609 = 0;\ while (i1609 < (NUM)) {\ UID = (IDS)[i1609];\ STMT\ i1609 ++;\ }\ } #define NEXT_OP(OP, OP_LEN, OP_TYPE) \ do {\ NEXT_TLV((OP), (OP_LEN));\ } while ((OP_LEN) >= 8 &&\ (OP)->attr_id >= TAG_RANGE[OP_TYPE][0] &&\ (OP)->attr_id <= TAG_RANGE[OP_TYPE][2]); #define FOR_EACH_OP(OP, OP_LEN, OP_TYPE, STMT) \ {\ while ((OP_LEN) >= 8) {\ OP_TYPE = TLV2TYPE(OP);\ STMT\ NEXT_OP((OP), (OP_LEN), (OP_TYPE));\ }\ } int validate_qry_key(isns_type_t, isns_tlv_t *, uint16_t, isns_attr_t *); int get_qry_keys(bmp_t *, uint32_t, isns_type_t *, isns_tlv_t *, uint16_t, uint32_t **, uint32_t *); int get_qry_ops(uint32_t, isns_type_t, isns_type_t, uint32_t **, uint32_t *, uint32_t *); int get_qry_ops2(uint32_t *, uint32_t, isns_type_t, uint32_t **, uint32_t *, uint32_t *); int get_qry_attrs(uint32_t, isns_type_t, isns_tlv_t *, uint16_t, conn_arg_t *); int get_qry_attrs1(uint32_t, isns_type_t, isns_tlv_t *, uint16_t, conn_arg_t *); uint32_t get_next_obj(isns_tlv_t *, uint32_t, isns_type_t, uint32_t *, uint32_t); #ifdef __cplusplus } #endif #endif /* _ISNS_QRY_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_SCHED_H #define _ISNS_SCHED_H #ifdef __cplusplus extern "C" { #endif typedef struct el_notice { uint32_t time; void *event; int isdummy; struct el_key *key; struct el_notice *pred; struct el_notice *sucd; } el_notice_t; typedef struct el_key { uint32_t time; int count; struct el_notice *notice; struct el_key *left; struct el_key *right; } el_key_t; /* function prototypes */ int el_init(); int el_add(void *, uint32_t, void **); int el_remove(uint32_t, uint32_t, int); void *el_first(uint32_t *); #ifdef __cplusplus } #endif #endif /* _ISNS_SCHED_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_SCN_H #define _ISNS_SCN_H #ifdef __cplusplus extern "C" { #endif /* raw scn data type */ typedef struct scn_raw { uint32_t event; int type; uint32_t uid; uchar_t *iscsi; uint32_t ref; uint32_t ilen; uint32_t nt; in6_addr_t *ip; uint32_t port; uint32_t dd_id; uint32_t dds_id; } scn_raw_t; /* scn context data type */ typedef struct scn_text { int flag; uint32_t ref; uint32_t uid; uchar_t *iscsi; uint32_t ilen; uint32_t nt; uint32_t dd_id; uint32_t dds_id; struct scn_text *next; } scn_text_t; /* portal data type stroed in scn registry */ typedef struct scn_portal { uint32_t uid; int sz; union { in_addr_t in; in6_addr_t *in6; } ip; uint32_t port; uint32_t ref; int so; struct scn_portal *next; } scn_portal_t; typedef struct scn_list { union { scn_text_t *text; scn_portal_t *portal; } data; struct scn_list *next; } scn_list_t; /* scn trigger uint */ typedef struct scn { uint32_t event; union { scn_raw_t *raw; scn_list_t *list; } data; struct scn *next; } scn_t; /* scn registry list */ typedef struct scn_registry { uint32_t uid; uchar_t *name; uint32_t nlen; uint32_t bitmap; union { scn_portal_t *p; scn_list_t *l; } portal; scn_t *scn; struct scn_registry *next; } scn_registry_t; /* function prototypes */ void *scn_proc(void *); int scn_list_load(uint32_t, uchar_t *, uint32_t, uint32_t); int verify_scn_portal(void); int add_scn_entry(uchar_t *, uint32_t, uint32_t); int remove_scn_entry(uchar_t *); int remove_scn_portal(uint32_t); int make_scn(uint32_t, isns_obj_t *); int connect_to(int, in_addr_t, in6_addr_t *, uint32_t); #ifdef __cplusplus } #endif #endif /* _ISNS_SCN_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_SERVER_H #define _ISNS_SERVER_H #ifdef __cplusplus extern "C" { #endif #include #include #include #ifdef DEBUG #define ASSERT(EXP) assert(EXP) #else #define ASSERT(EXP) #endif #define ISNS_RSP_MASK (0x8000) /* * definitions for SMF. */ #define ISNS_SERVER_SVC_NAME "network/isns_server" #define ISNS_SERVER_CONFIG "config" #define CONFIG_DATA_STORE "data_store_location" #define CONFIG_ESI_THRESHOLD "ESI_retry_threshold_count" #define CONFIG_MGMT_SCN "Management_SCN_Enabled" #define CONFIG_CONTROL_NODES "Authorized_Control_Nodes" #ifdef DEBUG #define OPT_DAEMONLIZE "daemonlize" #endif #define ISNS_DAEMON_SYSLOG_PP "isns" #define FIRST_TAG_ENTITY ISNS_EID_ATTR_ID #define FIRST_TAG_ISCSI ISNS_ISCSI_NAME_ATTR_ID #define FIRST_TAG_PORTAL ISNS_PORTAL_IP_ADDR_ATTR_ID #define FIRST_TAG_PG ISNS_PG_ISCSI_NAME_ATTR_ID #define FIRST_TAG_DD ISNS_DD_ID_ATTR_ID #define FIRST_TAG_DDS ISNS_DD_SET_ID_ATTR_ID #define FIRST_TAG_ASSOC_ISCSI ISNS_DD_ISCSI_INDEX_ATTR_ID #define FIRST_TAG_ASSOC_DD ISNS_DD_ID_ATTR_ID #define LAST_TAG_ENTITY ISNS_ENTITY_INDEX_ATTR_ID #define LAST_TAG_ISCSI ISNS_ISCSI_AUTH_METHOD_ATTR_ID #define LAST_TAG_PORTAL ISNS_SCN_PORT_ATTR_ID #define LAST_TAG_PG ISNS_PG_INDEX_ATTR_ID #define LAST_TAG_DD ISNS_DD_FEATURES_ATTR_ID #define LAST_TAG_DDS ISNS_DD_SET_STATUS_ATTR_ID #define LAST_TAG_ASSOC_ISCSI ISNS_DD_ISCSI_NAME_ATTR_ID #define LAST_TAG_ASSOC_DD ISNS_DD_ID_ATTR_ID #define NUM_OF_ENTITY_ATTRS \ (LAST_TAG_ENTITY - FIRST_TAG_ENTITY + 1) #define NUM_OF_ISCSI_ATTRS \ (LAST_TAG_ISCSI - FIRST_TAG_ISCSI + 1) #define NUM_OF_PORTAL_ATTRS \ (LAST_TAG_PORTAL - FIRST_TAG_PORTAL + 1) #define NUM_OF_PG_ATTRS \ (LAST_TAG_PG - FIRST_TAG_PG + 1) #define NUM_OF_DD_ATTRS \ (LAST_TAG_DD - FIRST_TAG_DD + 1) #define NUM_OF_DDS_ATTRS \ (LAST_TAG_DDS - FIRST_TAG_DDS + 1) #define NUM_OF_ASSOC_ISCSI_ATTRS \ (LAST_TAG_ASSOC_ISCSI - FIRST_TAG_ASSOC_ISCSI + 1) #define NUM_OF_ASSOC_DD_ATTRS \ (LAST_TAG_ASSOC_DD - FIRST_TAG_ASSOC_DD + 1) #define ATTR_INDEX_ENTITY(TAG) ((TAG) - FIRST_TAG_ENTITY) #define ATTR_INDEX_ISCSI(TAG) ((TAG) - FIRST_TAG_ISCSI) #define ATTR_INDEX_PORTAL(TAG) ((TAG) - FIRST_TAG_PORTAL) #define ATTR_INDEX_PG(TAG) ((TAG) - FIRST_TAG_PG) #define ATTR_INDEX_DD(TAG) ((TAG) - FIRST_TAG_DD) #define ATTR_INDEX_DDS(TAG) ((TAG) - FIRST_TAG_DDS) #define ATTR_INDEX_ASSOC_ISCSI(TAG) ((TAG) - FIRST_TAG_ASSOC_ISCSI) #define ATTR_INDEX_ASSOC_DD(TAG) ((TAG) - FIRST_TAG_ASSOC_DD) #define ATTR_INDEX(TAG, TYPE) ((TAG) - TAG_RANGE[TYPE][0]) #define ISCSI_ATTR(ISCSI, TAG) ((ISCSI)->attrs[ATTR_INDEX_ISCSI(TAG)].value) /* * isns object type. */ typedef enum isns_otype { /* * iSNS objects as they are defined in RFC 4171. */ OBJ_ENTITY = 0x1, OBJ_ISCSI, OBJ_PORTAL, OBJ_PG, OBJ_DD, OBJ_DDS, MAX_OBJ_TYPE, /* * dummy object types for future extension. */ OBJ_DUMMY1, OBJ_DUMMY2, OBJ_DUMMY3, OBJ_DUMMY4, /* * madeup object for internal implementation. */ OBJ_ASSOC_ISCSI, OBJ_ASSOC_DD, MAX_OBJ_TYPE_FOR_SIZE } isns_type_t; #define MAX_LOOKUP_CTRL (3) /* * lookup operation. */ typedef enum { OP_STRING = 1, OP_INTEGER, OP_MEMORY_IP6 } lookup_method_t; /* * lookup control data. */ typedef struct lookup_ctrl { isns_type_t type; uint32_t curr_uid; uint16_t id[MAX_LOOKUP_CTRL]; uint8_t op[MAX_LOOKUP_CTRL]; union { uchar_t *ptr; uint32_t ui; in6_addr_t *ip; } data[MAX_LOOKUP_CTRL]; } lookup_ctrl_t; #define SET_UID_LCP(LCP, TYPE, UID) {\ (LCP)->type = TYPE;\ (LCP)->curr_uid = 0;\ (LCP)->id[0] = UID_ATTR_INDEX[TYPE];\ (LCP)->op[0] = OP_INTEGER;\ (LCP)->data[0].ui = UID;\ (LCP)->op[1] = 0;\ } #define UPDATE_LCP_UID(LCP, UID) {\ (LCP)->curr_uid = 0;\ (LCP)->id[0] = UID_ATTR_INDEX[(LCP)->type];\ (LCP)->op[0] = OP_INTEGER;\ (LCP)->data[0].ui = UID;\ (LCP)->op[1] = 0;\ } /* * isns object attribute */ typedef struct isns_attr { uint32_t tag; uint32_t len; union { int32_t i; uint32_t ui; in6_addr_t *ip; uchar_t *ptr; time_t timestamp; } value; } isns_attr_t; #define MAX_KEY_ATTRS (3) /* * isns generic object. */ typedef struct isns_obj { isns_type_t type; isns_attr_t attrs[1]; } isns_obj_t; #define ISCSI_PARENT_TYPE (OBJ_ENTITY) #define PORTAL_PARENT_TYPE (OBJ_ENTITY) #define PG_PARENT_TYPE (OBJ_ENTITY) #define ASSOC_ISCSI_PARENT_TYPE (OBJ_DD) #define ASSOC_DD_PARENT_TYPE (OBJ_DDS) /* * iSNS objects. */ typedef struct isns_dds { isns_type_t type; isns_attr_t attrs[NUM_OF_DDS_ATTRS]; } isns_dds_t; typedef struct isns_assoc_dd { isns_type_t type; isns_attr_t attrs[NUM_OF_ASSOC_DD_ATTRS]; /* parent object uid */ #ifdef ASSOC_DD_PARENT_TYPE uint32_t puid; #endif } isns_assoc_dd_t; #define DDS_ENABLED(UI) ((UI) & (ISNS_DDS_STATUS)) #define ENABLE_DDS(DDS) (((DDS)->status) |= (ISNS_DDS_STATUS)) #define DISABLE_DDS(DDS) (((DDS)->status) &= ~(ISNS_DDS_STATUS)) #define DD_BOOTLIST_ENABLED(UI) ((UI) & (ISNS_DD_BOOTLIST)) typedef struct isns_dd { isns_type_t type; isns_attr_t attrs[NUM_OF_DD_ATTRS]; } isns_dd_t; typedef struct isns_assoc_iscsi { isns_type_t type; isns_attr_t attrs[NUM_OF_ASSOC_ISCSI_ATTRS]; /* parent object uid */ #ifdef ASSOC_ISCSI_PARENT_TYPE uint32_t puid; #endif } isns_assoc_iscsi_t; #define MAX_ISCSI_CHILD (0) #define MAX_PORTAL_CHILD (0) #define MAX_PG_CHILD (0) #define MAX_ENTITY_CHILD (2) #define MAX_CHILD_TYPE (2) #define PG_REF_COUNT (2) #define MAX_REF_COUNT (2) typedef struct isns_iscsi { isns_type_t type; isns_attr_t attrs[NUM_OF_ISCSI_ATTRS]; /* parent object uid */ #ifdef ISCSI_PARENT_TYPE uint32_t puid; #endif /* subordinate object uid(s) */ #if defined(MAX_ISCSI_CHILD) && (MAX_ISCSI_CHILD > 0) uint32_t *cuid[MAX_ISCSI_CHILD]; #endif } isns_iscsi_t; #define IS_ISCSI_TARGET(NODE) (((NODE)->type) & ISNS_TARGET_NODE_TYPE) #define IS_ISCSI_INITIATOR(NODE) (((NODE)->type) & ISNS_INITIATOR_NODE_TYPE) #define IS_ISCSI_CONTROL(NODE) (((NODE)->type) & ISNS_CONTROL_NODE_TYPE) #define IS_TYPE_TARGET(TYPE) ((TYPE) & ISNS_TARGET_NODE_TYPE) #define IS_TYPE_INITIATOR(TYPE) ((TYPE) & ISNS_INITIATOR_NODE_TYPE) #define IS_TYPE_CONTROL(TYPE) ((TYPE) & ISNS_CONTROL_NODE_TYPE) #define IS_TYPE_UNKNOWN(TYPE) (!IS_TYPE_TARGET(TYPE) && \ !IS_TYPE_INITIATOR(TYPE) && \ !IS_TYPE_CONTROL(TYPE)) #define IS_SCN_INIT_SELF_INFO_ONLY(UI) ((UI) & ISNS_INIT_SELF_INFO_ONLY) #define IS_SCN_TARGET_SELF_INFO_ONLY(UI) ((UI) & ISNS_TARGET_SELF_INFO_ONLY) #define IS_SCN_MGMT_REG(UI) ((UI) & ISNS_MGMT_REG) #define IS_SCN_OBJ_REMOVED(UI) ((UI) & ISNS_OBJECT_REMOVED) #define IS_SCN_OBJ_ADDED(UI) ((UI) & ISNS_OBJECT_ADDED) #define IS_SCN_OBJ_UPDATED(UI) ((UI) & ISNS_OBJECT_UPDATED) #define IS_SCN_MEMBER_REMOVED(UI) ((UI) & ISNS_MEMBER_REMOVED) #define IS_SCN_MEMBER_ADDED(UI) ((UI) & ISNS_MEMBER_ADDED) typedef struct isns_portal { isns_type_t type; isns_attr_t attrs[NUM_OF_PORTAL_ATTRS]; /* parent object uid */ #ifdef PORTAL_PARENT_TYPE uint32_t puid; #endif /* subordinate object uid(s) */ #if defined(MAX_PORTAL_CHILD) && (MAX_PORTAL_CHILD > 0) uint32_t *cuid[MAX_PORTAL_CHILD]; #endif } isns_portal_t; #define PORTAL_PORT(UI) ((UI) & ISNS_PORT_BITS) #define ESI_PORT(UI) ((UI) & ISNS_PORT_BITS) #define IS_ESI_UDP(UI) ((UI) & ISNS_PORT_TYPE) #define SCN_PORT(UI) ((UI) & ISNS_PORT_BITS) #define IS_SCN_UDP(UI) ((UI) & ISNS_PORT_TYPE) #define PORT_NUMBER(UI) ((UI) & ISNS_PORT_BITS) #define IS_PORT_UDP(UI) ((UI) & ISNS_PORT_TYPE) typedef struct isns_pg { isns_type_t type; isns_attr_t attrs[NUM_OF_PG_ATTRS]; /* parent object uid */ #ifdef PG_PARENT_TYPE uint32_t puid; #endif /* subordinate object uid(s) */ #if defined(MAX_PG_CHILD) && (MAX_PG_CHILD > 0) uint32_t *cuid[MAX_PG_CHILD]; #endif /* ref count */ #if defined(PG_REF_COUNT) && (PG_REF_COUNT > 0) uint32_t ref[PG_REF_COUNT]; #endif } isns_pg_t; #define PG_TAG(PGT) (((PGT)->tag) & ISNS_PG_TAG) typedef struct isns_entity { isns_type_t type; isns_attr_t attrs[NUM_OF_ENTITY_ATTRS]; /* parent object uid */ #ifdef ENTITY_PARENT_TYPE uint32_t puid; #endif /* subordinate object uid(s) */ #if defined(MAX_ENTITY_CHILD) && (MAX_ENTITY_CHILD > 0) uint32_t *cuid[MAX_ENTITY_CHILD]; #endif } isns_entity_t; #define PROTOCOL_MAX_VER(ENTITY) ((((ENTITY)->versions) >> \ ISNS_VER_SHIFT) && \ ISNS_VERSION) #define PROTOCOL_MIN_VER(ENTITY) (((ENTITY)->versions) & ISNS_VERSION) #define DEFAULT_EID_LEN 20 #define DEFAULT_EID_PATTERN "isns: %.6d" #define DEFAULT_DD_NAME "Default" #define DEFAULT_DD_SET_NAME "Default" #define DEFAULT_DD_FEATURES 0 #define DEFAULT_DD_SET_STATUS 0 #define MIN_ESI_INTVAL (20) /* 20 seconds */ #define DEFAULT_ESI_INTVAL (3 * 60) /* 3 mintues */ #define ONE_DAY (86400) #define INFINITY (4294967295UL) /* >136 years, max # of uint32_t */ /* * function prototype. */ void * isns_port_watcher( void * ); uint16_t get_server_xid(void); void inc_thr_count(void); void dec_thr_count(void); void shutdown_server(void); #ifdef __cplusplus } #endif #endif /* _ISNS_SERVER_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISNS_UTILS_H #define _ISNS_UTILS_H #include #ifdef __cplusplus extern "C" { #endif int setup_mgmt_door(msg_queue_t *); typedef enum { PARTIAL_SUCCESS = 100, PARTIAL_FAILURE, ERR_DOOR_ALREADY_RUNNING, ERR_DOOR_CREATE_FAILED, ERR_DOOR_MORE_SPACE, ERR_NULL_XML_MESSAGE, ERR_INVALID_MGMT_REQUEST, ERR_XML_VALID_OPERATION_NOT_FOUND, ERR_XML_VALID_OBJECT_NOT_FOUND, ERR_XML_FAIL_TO_CREATE_WRITE_BUFFER, ERR_XML_FAIL_TO_GET_WRITEPTR, ERR_XML_INIT_READER_FAILED, ERR_XML_PARSE_MEMORY_FAILED, ERR_XML_FAILED_TO_SET_XPATH_CONTEXT, ERR_XML_FAILED_TO_REGISTER_NAMESPACE, ERR_XML_NEWNODE_FAILED, ERR_XML_ADDCHILD_FAILED, ERR_XML_SETPROP_FAILED, ERR_XML_NEWCHILD_FAILED, ERR_SYNTAX_MISSING_ROOT, ERR_SYNTAX_MISSING_NAME_ATTR, ERR_MALLOC_FAILED, ERR_XML_OP_FAILED, ERR_XML_STRDUP_FAILED, ERR_DOOR_SERVER_DETECTED_INVALID_USER, ERR_DOOR_SERVER_DETECTED_NOT_AUTHORIZED_USER, ERR_MATCHING_ISCSI_NODE_NOT_FOUND, ERR_MATCHING_NETWORK_ENTITY_NOT_FOUND, ERR_NO_PORTAL_GROUP_FOUND, ERR_MATCHING_PORTAL_NOT_FOUND, ERR_MATCHING_NODE_NOT_FOUND, ERR_MATCHING_DD_NOT_FOUND, ERR_MATCHING_DDSET_NOT_FOUND, ERR_NO_ASSOCIATED_DD_FOUND, ERR_NO_ASSOCIATED_DDSET_FOUND, ERR_NO_SUCH_ASSOCIATION, ERR_ALREADY_ASSOCIATED, ERR_NAME_IN_USE, ERR_DOOR_UCRED_FAILED } result_code_t; char *result_code_to_str(int); #ifdef __cplusplus } #endif #endif /* _ISNS_UTILS_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include "isns_log.h" extern int dbg_level; #define MAX_LOG_LEN 2048 void isnslog( int level, const char *routine, char *msg, ... ) { char header[MAX_LOG_LEN+1]; char message[MAX_LOG_LEN+1]; int oldErrno = 0; va_list ap; oldErrno = errno; if (dbg_level >= level) { (void) memset(&header, 0, MAX_LOG_LEN+1); (void) memset(&message, 0, MAX_LOG_LEN+1); va_start(ap, msg); (void) snprintf(header, MAX_LOG_LEN, "%s: %s: %s", "iSNS Daemon", routine, msg); /* LINTED E_SEC_PRINTF_VAR_FMT */ (void) vsnprintf(message, MAX_LOG_LEN, header, ap); /* LINTED E_SEC_PRINTF_VAR_FMT */ syslog(LOG_DAEMON | level, message); va_end(ap); } errno = oldErrno; } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2025 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #ifdef DEBUG #include #endif #include #include #include #include "isns_server.h" #include "isns_dseng.h" #include "isns_msgq.h" #include "isns_log.h" #include "isns_cfg.h" #include "isns_utils.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_dd.h" #include "isns_scn.h" #include "isns_sched.h" #include "isns_esi.h" #include "isns_mgmt.h" /* * iSNS Server administrative settings. */ uint8_t daemonlize = 0; int dbg_level = 7; uint64_t esi_threshold; uint8_t mgmt_scn; ctrl_node_t *control_nodes = NULL; pthread_mutex_t ctrl_node_mtx = PTHREAD_MUTEX_INITIALIZER; char data_store[MAXPATHLEN]; /* semaphore for handling exit */ static sem_t isns_child_sem; static int isns_child_smf_exit_code; static pid_t isns_child_pid; #if !defined(SMF_EXIT_ERR_OTHER) #define SMF_EXIT_ERR_OTHER -1 #endif /* * Globals for singal handling. time_to_exit is set by sig_handle() * when set the main thread(daemon) and othere threads should exit. * * semaphone is used to make sure all threads that are created * by isns_port_watcher and esi. */ boolean_t time_to_exit = B_FALSE; static uint32_t thr_ref_count; static pthread_mutex_t thr_count_mtx = PTHREAD_MUTEX_INITIALIZER; #define MAX_RETRY_COUNT 10 /* for checking remaining threads before exit. */ /* * Door creation flag. */ boolean_t door_created = B_FALSE; /* * global system message queue */ msg_queue_t *sys_q = NULL; msg_queue_t *scn_q = NULL; #ifdef DEBUG extern void *cli_test(void *argv); extern int dump_db(void); #endif extern void sigalrm(int); /* * sigusr2_handler -- SIGUSR2 Handler * sigusr2 is exepected only when child is running okay. */ /* ARGSUSED */ static void sigusr2_handler( int sig ) { /* post okay status. */ isnslog(LOG_DEBUG, "sigusr2_handler", "SIGUSR@ is received. Parent is existing..."); isns_child_smf_exit_code = SMF_EXIT_OK; (void) sem_post(&isns_child_sem); } /* * sigchld_handler -- SIGCHLD Handler * sigchld is exepected only when there is an error. */ /* ARGSUSED */ static void sigchld_handler( int sig ) { int status; pid_t ret_pid; /* This is the default code. */ isns_child_smf_exit_code = SMF_EXIT_ERR_OTHER; ret_pid = waitpid(isns_child_pid, &status, WNOHANG); if (ret_pid == isns_child_pid) { if (WIFEXITED(status)) { isns_child_smf_exit_code = WEXITSTATUS(status); } } (void) sem_post(&isns_child_sem); } /* ARGSUSED */ static void sighup_handler( int sig ) { isnslog(LOG_DEBUG, "sighup_handle", "SIGHUP is received. Reloading config..."); (void) queue_msg_set(sys_q, CONFIG_RELOAD, NULL); } /* ARGSUSED */ static void sigexit_handler( int sig ) { isnslog(LOG_DEBUG, "sigexit_handler", "Signal: %d received and sending server exit.", sig); shutdown_server(); } void inc_thr_count( ) { (void) pthread_mutex_lock(&thr_count_mtx); isnslog(LOG_DEBUG, "inc_thr_count", "increase thread reference count(%d).", thr_ref_count); thr_ref_count++; (void) pthread_mutex_unlock(&thr_count_mtx); } void dec_thr_count( ) { (void) pthread_mutex_lock(&thr_count_mtx); isnslog(LOG_DEBUG, "dec_thr_count", "decrease thread reference count(%d).", thr_ref_count); thr_ref_count--; (void) pthread_mutex_unlock(&thr_count_mtx); } uint32_t get_thr_count( ) { uint32_t ref; (void) pthread_mutex_lock(&thr_count_mtx); ref = thr_ref_count; (void) pthread_mutex_unlock(&thr_count_mtx); isnslog(LOG_DEBUG, "get_thr_count", "checking thread reference count %d.", ref); return (ref); } void shutdown_server( ) { isnslog(LOG_DEBUG, "shutdown", "raise exit flag."); time_to_exit = B_TRUE; (void) queue_msg_set(sys_q, SERVER_EXIT, NULL); } int main( /* LINTED E_FUNC_ARG_UNUSED */ int argc, /* LINTED E_FUNC_ARG_UNUSED */ char *argv[] ) { int opt_i = 0; pthread_t port_tid, esi_tid, scn_tid; uint32_t thr_cnt; int i; #ifdef DEBUG time_t t; clock_t c; #endif #ifdef DEBUG if (getopt(argc, argv, "i") == 'i') { opt_i = 1; /* interactive mode */ } #endif /* set locale */ openlog(ISNS_DAEMON_SYSLOG_PP, LOG_PID | LOG_CONS, LOG_DAEMON); /* load administative settings. pick up data location. */ if (load_config(B_TRUE) != 0) { isnslog(LOG_ERR, "main", "administrative settings load error."); exit(SMF_EXIT_ERR_OTHER); } /* A signal handler is set for SIGCHLD. */ (void) signal(SIGCHLD, sigchld_handler); (void) signal(SIGUSR2, sigusr2_handler); (void) sigset(SIGALRM, sigalrm); #ifdef DEBUG printf("start daemon\n"); #endif if (opt_i == 0 || daemonlize) { isnslog(LOG_DEBUG, "main", "now forking... pid %d", getpid()); daemonlize = 1; /* daemonlize */ isns_child_pid = fork(); if (isns_child_pid < 0) { /* * cannot fork(), terminate the server. */ exit(SMF_EXIT_ERR_CONFIG); } if (isns_child_pid > 0) { /* * terminate parent. */ (void) sem_wait(&isns_child_sem); (void) sem_destroy(&isns_child_sem); isnslog(LOG_DEBUG, "main", "exiting with %d", isns_child_smf_exit_code); exit(isns_child_smf_exit_code); } /* * redirect stdout, and stderr to /dev/null. */ i = open("/dev/null", O_RDWR); (void) dup2(i, 1); (void) dup2(i, 2); } /* end of daemonlize */ #ifdef DEBUG printf("calling cache init\n"); #endif /* initialize object hash table */ if (cache_init() != 0) { isnslog(LOG_ERR, "main", "object hash table initialization error."); exit(SMF_EXIT_ERR_OTHER); } /* initialize event list */ if (el_init(10, 60, 6) != 0) { isnslog(LOG_ERR, "main", "ESI event list initialization error."); exit(SMF_EXIT_ERR_OTHER); } /* initialize iSNS database */ if (init_data() != 0) { isnslog(LOG_ERR, "main", "internal database initialization error"); exit(SMF_EXIT_ERR_OTHER); } #ifdef DEBUG printf("calling load_data\n"); t = time(NULL); c = clock(); #endif if (load_data() != 0) { isnslog(LOG_ERR, "main", "loading data store failed"); exit(SMF_EXIT_ERR_OTHER); } #ifdef DEBUG t = time(NULL) - t; c = clock() - c; printf("time %d clock %.4lf -loading data\n", t, c / (double)CLOCKS_PER_SEC); #endif #ifdef DEBUG printf("sys queue creating...\n"); #endif /* create a message queue for system control */ sys_q = queue_calloc(); if (!sys_q) { exit(SMF_EXIT_ERR_OTHER); } /* create a message queue for scn thread */ scn_q = queue_calloc(); if (!scn_q) { exit(SMF_EXIT_ERR_OTHER); } /* create scn thread */ /* Check for Default DD/DD-set existence and */ /* create them if they are not there. */ if (verify_ddd() != 0) { exit(SMF_EXIT_ERR_OTHER); } /* setup and verify the portal(s) for scn(s) */ /* after scn registry is loaded from data store. */ if (verify_scn_portal() != 0) { exit(SMF_EXIT_ERR_OTHER); } /* setup and verify the portal(s) for esi(s) */ /* after esi list is loaded from data store. */ if (verify_esi_portal() != 0) { exit(SMF_EXIT_ERR_OTHER); } #ifdef DEBUG printf("scn queue creating...\n"); #endif (void) sigset(SIGHUP, sighup_handler); (void) sigset(SIGINT, sigexit_handler); (void) sigset(SIGTERM, sigexit_handler); (void) sigset(SIGQUIT, sigexit_handler); /* create scn thread */ if (pthread_create(&scn_tid, NULL, scn_proc, NULL) != 0) { isnslog(LOG_ERR, "main", "SCN thread creating error."); exit(SMF_EXIT_ERR_OTHER); } /* setup a door for management interface */ if (setup_mgmt_door(sys_q) != 0) { exit(SMF_EXIT_ERR_OTHER); } /* create server port watcher */ if (pthread_create(&port_tid, NULL, isns_port_watcher, (void *)sys_q) != 0) { isnslog(LOG_ERR, "main", "iSNS port thread creating error."); exit(SMF_EXIT_ERR_OTHER); } /* create entity status inquiry thread */ if (pthread_create(&esi_tid, NULL, esi_proc, NULL) != 0) { isnslog(LOG_ERR, "main", "ESI thread creating error."); exit(SMF_EXIT_ERR_OTHER); } #ifdef DEBUG if (!daemonlize) { pthread_t tid; (void) pthread_create(&tid, NULL, cli_test, (void *)sys_q); } #endif if (opt_i == 0 || daemonlize) { isnslog(LOG_DEBUG, "main", "issuing SIGUSR2.. parent pid %d", getppid()); (void) kill(getppid(), SIGUSR2); } /* pause */ for (;;) { msg_text_t *msg = queue_msg_get(sys_q); switch (msg->id) { case DATA_ADD: case DATA_UPDATE: case DATA_DELETE: case DATA_DELETE_ASSOC: case DATA_COMMIT: case DATA_RETREAT: break; case REG_EXP: /* registration expiring */ reg_expiring(msg->data); break; case DEAD_PORTAL: portal_dies((uint32_t)msg->data); break; case SERVER_EXIT: /* graceful exit. */ (void) queue_msg_free(msg); isnslog(LOG_DEBUG, "main", "wake up ESI and stop it."); (void) get_stopwatch(1); isnslog(LOG_DEBUG, "main", "sending SCN stop msg."); (void) queue_msg_set(scn_q, SCN_STOP, NULL); if (door_created) { isnslog(LOG_DEBUG, "main", "closing the door."); (void) fdetach(ISNS_DOOR_NAME); } (void) pthread_join(esi_tid, NULL); isnslog(LOG_DEBUG, "main", "esi thread %d exited.", esi_tid); (void) pthread_join(port_tid, NULL); isnslog(LOG_DEBUG, "main", "port watcher thread %d exited.", port_tid); (void) pthread_join(scn_tid, NULL); isnslog(LOG_DEBUG, "main", "scn thread %d exited.", scn_tid); /* now check any remaining threads. */ i = 0; do { thr_cnt = get_thr_count(); if (thr_cnt == 0) { isnslog(LOG_DEBUG, "main", "main thread %d is done.", pthread_self()); exit(1); } else { (void) sleep(1); i++; } } while (MAX_RETRY_COUNT > i); isnslog(LOG_DEBUG, "main", "main thread %d existing ...", pthread_self()); exit(1); break; case CONFIG_RELOAD: /* load config again. don't pick data store. */ (void) load_config(B_FALSE); break; case SYS_QUIT_OK: (void) queue_msg_free(msg); exit(0); default: break; } (void) queue_msg_free(msg); } /* LINTED E_STMT_NOT_REACHED */ return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "isns_server.h" #include "isns_msgq.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_log.h" msg_queue_t * queue_calloc( ) { msg_queue_t *q; q = (msg_queue_t *)calloc(1, sizeof (msg_queue_t)); if (q) { if (sema_init(&q->q_sema, 0, USYNC_THREAD, NULL) || pthread_mutex_init(&q->q_mutex, NULL)) { free(q); q = NULL; } } return (q); } int queue_msg_set( msg_queue_t *q, msg_id_t id, void *data ) { msg_text_t *msg; msg = (msg_text_t *)calloc(1, sizeof (msg_text_t)); if (!msg) { return (1); } msg->id = id; msg->data = data; (void) pthread_mutex_lock(&q->q_mutex); if (q->q_head == NULL) { ASSERT(!q->q_tail); q->q_head = msg; q->q_tail = msg; } else { ASSERT(q->q_tail); q->q_tail->next = msg; msg->prev = q->q_tail; q->q_tail = msg; } (void) pthread_mutex_unlock(&q->q_mutex); (void) sema_post(&q->q_sema); return (0); } msg_text_t * queue_msg_get( msg_queue_t *q ) { msg_text_t *msg; while (sema_wait(&q->q_sema)) { (void) sleep(1); } (void) pthread_mutex_lock(&q->q_mutex); msg = q->q_head; ASSERT(msg); q->q_head = msg->next; if (q->q_head == NULL) { q->q_tail = NULL; } (void) pthread_mutex_unlock(&q->q_mutex); return (msg); } void queue_msg_free( msg_text_t *msg ) { free(msg); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #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" /* * external variables */ #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; /* * global data */ /* * local variables */ /* type of parent object */ const int TYPE_OF_PARENT[MAX_OBJ_TYPE_FOR_SIZE] = { 0, 0, ISCSI_PARENT_TYPE, PORTAL_PARENT_TYPE, PG_PARENT_TYPE, 0, /* OBJ_DD */ 0, /* OBJ_DDS */ 0, /* MAX_OBJ_TYPE */ 0, /* OBJ_DUMMY1 */ 0, /* OBJ_DUMMY2 */ 0, /* OBJ_DUMMY3 */ 0, /* OBJ_DUMMY4 */ ASSOC_ISCSI_PARENT_TYPE, ASSOC_DD_PARENT_TYPE }; /* number of children object type */ const int NUM_OF_CHILD[MAX_OBJ_TYPE] = { 0, MAX_ENTITY_CHILD, MAX_ISCSI_CHILD, MAX_PORTAL_CHILD, MAX_PG_CHILD, 0, 0 }; /* type of a child object */ 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 } }; /* number of attributes of certain type of object */ 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, /* MAX_OBJ_TYPE */ 0, /* OBJ_DUMMY1 */ 0, /* OBJ_DUMMY2 */ 0, /* OBJ_DUMMY3 */ 0, /* OBJ_DUMMY4 */ NUM_OF_ASSOC_ISCSI_ATTRS, NUM_OF_ASSOC_DD_ATTRS }; /* the tag of UID of each type of object */ 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, /* MAX_OBJ_TYPE */ 0, /* OBJ_DUMMY1 */ 0, /* OBJ_DUMMY2 */ 0, /* OBJ_DUMMY3 */ 0, /* OBJ_DUMMY4 */ ISNS_DD_ISCSI_INDEX_ATTR_ID, ISNS_DD_ID_ATTR_ID }; /* the index of UID of each type of object */ 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, /* MAX_OBJ_TYPE */ 0, /* OBJ_DUMMY1 */ 0, /* OBJ_DUMMY2 */ 0, /* OBJ_DUMMY3 */ 0, /* OBJ_DUMMY4 */ ATTR_INDEX_ASSOC_ISCSI(ISNS_DD_ISCSI_INDEX_ATTR_ID), ATTR_INDEX_ASSOC_DD(ISNS_DD_ID_ATTR_ID) }; /* the index of the key attributes of each type of object */ 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 } }; /* the operating methods for key attributes of each type of object */ 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 } }; /* the size of each type of object */ 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 }; /* the type of the reference object */ 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 } }; /* the operating method for match operation of the reference object */ #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 } }; /* the index of the attribute of being matched object */ 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 } }; /* the index of the attribute of matching object */ 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 } }; /* * local functions. */ 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 }; /* * **************************************************************************** * * entity_hval: * caculate the hash value of a network entity object. * * p - the pointer pointers to network entity object or * the lookup control data, both have the key attribute * of a network entity object. * chunk- which chunk of the hash table. * flags- pointer to flags. * return - the hash value. * * **************************************************************************** */ static uint32_t entity_hval( void *p, /* LINTED E_FUNC_ARG_UNUSED */ uint16_t chunk, uint32_t *flags ) { uchar_t *key; isns_obj_t *obj; lookup_ctrl_t *lcp; if ((*flags & FLAGS_CTRL_MASK) == 0) { /* p pointers to a network entity object */ obj = (isns_obj_t *)p; key = obj->attrs[ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)]. value.ptr; } else { /* p is lookup control data */ lcp = (lookup_ctrl_t *)p; key = lcp->data[0].ptr; } return (htab_compute_hval(key)); } /* * **************************************************************************** * * iscsi_hval: * caculate the hash value of an iscsi storage node object. * * p - the pointer pointers to iscsi storage node object or * the lookup control data, both have the key attribute * of an iscsi storage node object. * chunk- which chunk of the hash table. * flags- pointer to flags. * return - the hash value. * * **************************************************************************** */ static uint32_t iscsi_hval( void *p, /* LINTED E_FUNC_ARG_UNUSED */ uint16_t chunk, uint32_t *flags ) { uchar_t *key; isns_obj_t *obj; lookup_ctrl_t *lcp; if ((*flags & FLAGS_CTRL_MASK) == 0) { /* p pointers to an iscsi storage node object */ obj = (isns_obj_t *)p; key = obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)]. value.ptr; } else { /* p is lookup control data */ lcp = (lookup_ctrl_t *)p; key = lcp->data[0].ptr; } return (htab_compute_hval(key)); } /* * **************************************************************************** * * portal_hval: * caculate the hash value of a portal object. * * p - the pointer pointers to a portal object or the lookup control * data, both have the key attributes of a portal object. * chunk- which chunk of the hash table. * flags- pointer to flags. * return - the hash value. * * **************************************************************************** */ static uint32_t portal_hval( void *p, /* LINTED E_FUNC_ARG_UNUSED */ 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) { /* p pointers to a portal object */ 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 { /* p is lookup control data */ 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)); } /* * **************************************************************************** * * pg_hval: * caculate the hash value of a portal group object. * * p - the pointer pointers to a portal group object or the lookup * control data, both have the key attributes of a portal object. * chunk- which chunk of the hash table. * flags- pointer to flags. * return - the hash value. * * **************************************************************************** */ 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) { /* p is a portal group object */ obj = (isns_obj_t *)p; if (chunk == 0) { /* the first chunk */ key = obj->attrs[ATTR_INDEX_PG (ISNS_PG_ISCSI_NAME_ATTR_ID)].value.ptr; } else { /* another chunk */ 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 { /* p is a lookup control data */ lcp = (lookup_ctrl_t *)p; /* clear the chunk flags */ *flags &= ~FLAGS_CHUNK_MASK; if (lcp->op[0] == OP_STRING) { /* the first chunk */ key = lcp->data[0].ptr; } else { /* another chunk */ 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)); } /* * **************************************************************************** * * dd_hval: * caculate the hash value of a DD object. * * p - the pointer pointers to a DD object or the lookup control data, * both have the key attributes of a DD object. * chunk- which chunk of the hash table. * flags- pointer to flags. * return - the hash value. * * **************************************************************************** */ static uint32_t dd_hval( void *p, /* LINTED E_FUNC_ARG_UNUSED */ uint16_t chunk, uint32_t *flags ) { uchar_t *key; isns_obj_t *obj; lookup_ctrl_t *lcp; if ((*flags & FLAGS_CTRL_MASK) == 0) { /* p is a DD object */ obj = (isns_obj_t *)p; key = obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)]. value.ptr; } else { /* p is a lookup control data */ lcp = (lookup_ctrl_t *)p; key = lcp->data[0].ptr; } return (htab_compute_hval(key)); } /* * **************************************************************************** * * dds_hval: * caculate the hash value of a DD-set object. * * p - the pointer pointers to a DD-set object or the lookup control data, * both have the key attributes of a DD-set object. * chunk- which chunk of the hash table. * flags- pointer to flags. * return - the hash value. * * **************************************************************************** */ static uint32_t dds_hval( void *p, /* LINTED E_FUNC_ARG_UNUSED */ uint16_t chunk, uint32_t *flags ) { uchar_t *key; isns_obj_t *obj; lookup_ctrl_t *lcp; if ((*flags & FLAGS_CTRL_MASK) == 0) { /* p is a DD-set object */ obj = (isns_obj_t *)p; key = obj->attrs[ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID)]. value.ptr; } else { /* p is lookup control data */ lcp = (lookup_ctrl_t *)p; key = lcp->data[0].ptr; } return (htab_compute_hval(key)); } /* * **************************************************************************** * * obj_hval: * caculate the hash value of an object. * * p - the pointer pointers to an object or lookup control data, * both has the object type and the key attributes of an object. * chunk- which chunk of the hash table. * flags- pointer to flags. * return - the hash value. * * **************************************************************************** */ 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)); } /* * **************************************************************************** * * get_obj_uid: * get the UID of an object. * * p - the pointer pointers to an object. * return - the UID. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * set_obj_uid: * set the UID of an object. * * p - the pointer pointers to an object. * uid - the UID. * return - the 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]]; /* set the tag, len and value */ attr->tag = UID_TAG[obj->type]; attr->len = 4; attr->value.ui = uid; return (uid); } /* * **************************************************************************** * * obj_cmp: * compare between two objects or an object with a lookup control data. * * p1 - the pointer points to an object. * p2 - the pointer points to an object or a lookup control data. * flags- 0: p2 is an object; otherwise p2 is a lookup control data. * return - the comparsion result. * * **************************************************************************** */ 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); /* the object are linked with decending order by */ /* the object UID, if the object UID is greater than */ /* or equal to the current UID, it needs to compare */ /* for the next one. */ if (lcp->curr_uid != 0 && uid >= lcp->curr_uid) { return (-1); } } return (key_cmp(lcp, obj)); } /* * **************************************************************************** * * replace_object: * replace an existing object with the new one. * * p1 - the pointer points to an object being replaced. * p2 - the pointer points to a new object. * uid_p- points to uid for returning. * flag - 0: do not free the source object, otherwise free it. * return - error code. * * **************************************************************************** */ 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) { /* replace not allowed */ return (ERR_NAME_IN_USE); } online = is_obj_online(dst); /* set cache update flag */ SET_CACHE_UPDATED(); /* update parent uid */ #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 /* update all of attributes */ if (copy_attrs(dst, src) != 0) { return (ISNS_RSP_INTERNAL_ERROR); } /* free up the src object */ 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); } /* update data store */ if (sys_q != NULL) { ec = write_data(DATA_UPDATE, dst); } else { /* we should never have duplicated entry in data store */ ec = ISNS_RSP_INTERNAL_ERROR; } /* trigger a scn */ 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); } /* * **************************************************************************** * * add_object: * post function after adding a new object. * * p - object which has been added. * return - error code. * * **************************************************************************** */ int add_object( void *p ) { int ec = 0; isns_obj_t *obj = (isns_obj_t *)p; /* add the new object to data store */ if (sys_q != NULL) { ec = write_data(DATA_ADD, obj); } /* trigger a scn */ if (ec == 0 && scn_q != NULL) { (void) make_scn(ISNS_OBJECT_ADDED, obj); } return (ec); } /* * **************************************************************************** * * obj_tab_init: * initialize the object hash tables. * * c - points to the cache. * return - error code. * * **************************************************************************** */ int obj_tab_init( struct cache *c ) { htab_t *t; htab_init(); /* * allocate an array of pointer for the object hash tables. */ c->t = (struct htab **)calloc(sizeof (struct htab *), MAX_OBJ_TYPE); if (c->t == NULL) { return (1); } /* * hash table for network entity objects. */ t = htab_create(UID_FLAGS_SEQ, 8, 1); if (t != NULL) { t->c = c; c->t[OBJ_ENTITY] = t; } else { return (1); } /* * hash table for iscsi storage node objects. */ t = htab_create(UID_FLAGS_SEQ, 8, 1); if (t != NULL) { t->c = c; c->t[OBJ_ISCSI] = t; } else { return (1); } /* * hash table for portal objects. */ t = htab_create(UID_FLAGS_SEQ, 8, 1); if (t != NULL) { t->c = c; c->t[OBJ_PORTAL] = t; } else { return (1); } /* * hash table for portal group objects. */ t = htab_create(UID_FLAGS_SEQ, 8, 2); if (t != NULL) { t->c = c; c->t[OBJ_PG] = t; } else { return (1); } /* * hash table for discovery domain objects. */ t = htab_create(0, 6, 1); if (t != NULL) { t->c = c; c->t[OBJ_DD] = t; } else { return (1); } /* * hash table for discovery domain set objects. */ t = htab_create(0, 4, 1); if (t != NULL) { t->c = c; c->t[OBJ_DDS] = t; } else { return (1); } return (0); } /* * **************************************************************************** * * get_ref_np: * get the ref pointer of the portal group object. * * obj - portal group object. * return - ref pointer. * * **************************************************************************** */ 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); /* LINTED E_NOP_ELSE_STMT */ } else { ASSERT(0); } return (0); } /* * **************************************************************************** * * get_parent_p: * get the pointer of the parent object. * * obj - an object. * return - parent object pointer. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * get_child_np: * get the pointer of the UID array of the n'th child of an object. * * obj - an object. * n - the child index. * return - the pointer of the UID array. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * get_child_n: * get the UID array of the n'th child of an object. * * obj - an object. * n - the child index. * return - the UID array. * * **************************************************************************** */ #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); } /* * **************************************************************************** * * get_child_p: * get the pointer of the UID array of the child matching the type. * * base - an object. * child_type - the child object type. * return - the pointer of the UID array. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * get_child_t: * get the UID array of the child object matching the type. * * base - an object. * child_type - the child object type. * return - the UID array. * * **************************************************************************** */ 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); } } /* * **************************************************************************** * * key_cmp: * compare the object against the lookup control data. * * lcp - the lookup control data. * obj - an object. * return - comparison result. * * **************************************************************************** */ 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); } } /* * **************************************************************************** * * set_lookup_ctrl: * fill in the lookup control data for an object. * * lcp - the lookup control data. * obj - an object. * return - the lookup control data. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * assign_attr: * assign an attribute. * * attr - the attribute being assigned. * tmp - the attribute. * return - error code. * * **************************************************************************** */ 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 { /* memory exhausted */ return (1); } } /* FALLTHROUGH */ 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 { /* memory exhausted */ 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 { /* memory exhausted */ 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; } /* FALLTHROUGH */ 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; /* 20 seconds */ } break; default: ASSERT(0); /* don't assign the attribute */ break; } return (0); } /* * **************************************************************************** * * copy_attrs: * copy all of attributes from one object to another. * * dst - the destination object. * tmp - the source object. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * extract_attr: * extract an attribute from a TLV format data. * * attr - the attribute. * tlv - the TLV format data. * return - error code. * * **************************************************************************** */ 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; /* FALLTHROUGH */ 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; /* FALLTHROUGH */ 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: /* fall throught */ case ISNS_PORTAL_PORT_ATTR_ID: case ISNS_ESI_INTERVAL_ATTR_ID: case ISNS_ESI_PORT_ATTR_ID: case ISNS_SCN_PORT_ATTR_ID: /* fall throught */ case ISNS_ISCSI_NODE_TYPE_ATTR_ID: /* fall throught */ case ISNS_PG_PORTAL_PORT_ATTR_ID: /* fall throught */ case ISNS_DD_SET_ID_ATTR_ID: case ISNS_DD_SET_STATUS_ATTR_ID: /* fall throught */ case ISNS_DD_ID_ATTR_ID: if (tlv->attr_len != 4) { ec = ISNS_RSP_MSG_FORMAT_ERROR; break; } /* FALLTHROUGH */ 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: /* ignore scn bitmap attribute during object registration, */ /* it is registered by scn_reg message. */ 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; } /* FALLTHROUGH */ 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); } /* * **************************************************************************** * * copy_attr: * copy an attribute from a TLV format data. * * attr - the attribute. * tlv - the TLV format data. * return - error code. * * **************************************************************************** */ static int copy_attr( isns_attr_t *attr, const isns_tlv_t *tlv ) { int ec = 0; isns_attr_t tmp = { 0 }; /* extract the attribute first */ ec = extract_attr(&tmp, tlv, 1); /* assign the attribute */ if (ec == 0 && tmp.tag != 0) { if (assign_attr(attr, &tmp) != 0) { ec = ISNS_RSP_INTERNAL_ERROR; } } return (ec); } /* * **************************************************************************** * * get_timestamp: * get current timestamp. * * return - current timestamp. * * **************************************************************************** */ uint32_t get_timestamp( ) { uint32_t t; int flag; /* block the scheduler */ (void) pthread_mutex_lock(&el_mtx); /* get most current time */ if (sys_q != NULL) { /* need to wakeup idle */ flag = 1; } else { flag = 0; } t = get_stopwatch(flag); /* unblock it */ (void) pthread_mutex_unlock(&el_mtx); return (t); } /* * **************************************************************************** * * get_reg_period: * get the longest registration period. * * return - the longest registration period. * * **************************************************************************** */ static uint32_t get_reg_period( ) { uint32_t t; uint32_t period; /* get most current time */ t = get_timestamp(); /* just one second before the end of the world */ period = INFINITY - t - 1; return (period); } /* * **************************************************************************** * * obj_calloc: * allocate memory space for an object. * * type - the object type. * return - pointer of the object being allocated. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * make_default_entity: * generate a default network entity object. * * return - pointer of the default network entity object. * * **************************************************************************** */ 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)]; /* set default entity name */ attr->tag = ISNS_EID_ATTR_ID; attr->len = len; attr->value.ptr = (uchar_t *)eid; /* set default registration period */ 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); } /* * **************************************************************************** * * make_default_pg: * generate a default portal group object. * * iscsi - the iscsi storage node object. * portal - the portal object. * return - pointer of the default portal group object. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * reg_get_entity: * parse the Operating Attributes of the DevAttrReg message and * create the Network Entity object if it has one. * * p - the pointer of the object for returning. * op - the operating attributes. * op_len - the length of the operating attributes. * return - error code. * * **************************************************************************** */ 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; /* parse the entity object */ 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) { /* set default registration period */ 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); } /* * **************************************************************************** * * reg_get_iscsi: * parse the Operating Attributes of the DevAttrReg message and * create an iSCSI Storage Node object. * * p - the pointer of the object for returning. * pg_key1 - the pointer of iscsi storage node name for returning. * op - the operating attributes. * op_len - the length of the operating attributes. * return - error code. * * **************************************************************************** */ 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; /* keep the iscsi storage node name for */ /* parsing a pg object which is immediately */ /* followed with a PGT by the iscsi storage node */ pg_key1->tag = PG_KEY1; pg_key1->len = tmp->attr_len; pg_key1->value.ptr = (uchar_t *)&tmp->attr_value[0]; /* parse one iscsi storage node object */ obj = obj_calloc(OBJ_ISCSI); if (obj != NULL) { /* parse key & non-key attributes */ 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 { /* no memory */ ec = ISNS_RSP_INTERNAL_ERROR; } *p = obj; *op = tmp; *op_len = tmp_len; return (ec); } /* * **************************************************************************** * * reg_get_portal: * parse the Operating Attributes of the DevAttrReg message and * create a Portal object. * * p - the pointer of the object for returning. * pg_key1 - the pointer of portal ip addr for returning. * pg_key2 - the pointer of portal port for returning. * op - the operating attributes. * op_len - the length of the operating attributes. * return - error code. * * **************************************************************************** */ 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; /* keep the portal ip addr */ 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) { /* keep the portal port */ pg_key2->tag = PG_KEY3; pg_key2->len = tmp->attr_len; pg_key2->value.ui = ntohl(*(uint32_t *)&tmp->attr_value[0]); /* parse one portal object */ obj = obj_calloc(OBJ_PORTAL); if (obj != NULL) { /* copy ip addr attribute */ attr = &obj->attrs[ ATTR_INDEX_PORTAL(ip->attr_id)]; ec = copy_attr(attr, ip); /* copy port attribute */ if (ec == 0) { attr = &obj->attrs[ ATTR_INDEX_PORTAL(tmp->attr_id)]; ec = copy_attr(attr, tmp); } /* parse non-key attributes */ 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 { /* no memory */ ec = ISNS_RSP_INTERNAL_ERROR; } } else { /* ip address is not followed by port */ ec = ISNS_RSP_MSG_FORMAT_ERROR; } *p = obj; *op = tmp; *op_len = tmp_len; return (ec); } /* * **************************************************************************** * * reg_get_pg: * parse the Operating Attributes of the DevAttrReg message and * create a Portal Group object. * * p - the pointer of the object for returning. * op - the operating attributes. * op_len - the length of the operating attributes. * return - error code. * * **************************************************************************** */ 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; /* parse a complete pg object */ obj = obj_calloc(OBJ_PG); if (obj != NULL) { /* parse attributes */ 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); } /* * **************************************************************************** * * reg_get_pg1: * parse the Operating Attributes of the DevAttrReg message and * create a Portal Group object which is followed to a Portal object. * * p - the pointer of the object for returning. * pgt - the size-3 array of pointers which have the pg portal ip addr, port * and the pg tag attributes. * op - the operating attributes. * op_len - the length of the operating attributes. * return - error code. * * **************************************************************************** */ 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) { /* the pg iscsi storage node name is */ /* followed to a portal group tag */ obj = obj_calloc(OBJ_PG); if (obj != NULL) { /* copy pg iscsi storage node name */ attr = &obj->attrs[ ATTR_INDEX_PG(tmp->attr_id)]; ec = copy_attr(attr, tmp); /* copy pg ip addr, pg port & pgt */ 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 { /* no memory */ ec = ISNS_RSP_INTERNAL_ERROR; } } else { ec = ISNS_RSP_MSG_FORMAT_ERROR; } *p = obj; *op = tmp; *op_len = tmp_len; return (ec); } /* * **************************************************************************** * * reg_get_pg2: * parse the Operating Attributes of the DevAttrReg message and * create a Portal Group object which is followed to a iSCSI * Storage Node object. * * p - the pointer of the object for returning. * pgt - the size-3 array of pointers which have the pg iscsi storage * node name and the pg tag attributes. * op - the operating attributes. * op_len - the length of the operating attributes. * return - error code. * * **************************************************************************** */ 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; /* keep ip address */ ip = tmp; NEXT_TLV(tmp, tmp_len); if (tmp_len > 8 && /* expect pg portal port */ tmp->attr_id == PG_KEY3 && tmp->attr_len == 4 && /* expect pg tag */ pgt[2].tag == PG_PGT && /* expect pg iscsi storage node name only */ pgt[1].tag == 0 && pgt[0].tag == PG_KEY1) { /* the pg portal ip addr & port is followed */ /* to a pg tag and we have the iscsi storage */ /* node parsed previously */ obj = obj_calloc(OBJ_PG); if (obj != NULL) { /* copy the pg ip addr */ attr = &obj->attrs[ ATTR_INDEX_PG(ip->attr_id)]; ec = copy_attr(attr, ip); /* copy the pg port */ if (ec == 0) { attr = &obj->attrs[ ATTR_INDEX_PG(tmp->attr_id)]; ec = copy_attr(attr, tmp); } /* copy pg iscsi storage node name & pgt */ 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); } /* * **************************************************************************** * * reg_get_obj: * parse and create one object from the rest of Operating Attributes * of the DevAttrReg message, the object can be iSCSI Storage Node, * Portal or Portal Group. * * p - the pointer of the object for returning. * pgt - an attribute array with size 3, the elements are: * 0: the first pg key attribute, it is either the name of an * iscsi storage node object or the ip addr of a portal object. * 1: the second pg key attribute, i.e. the portal port. * 2: the portal group tag attribute. * op - the operating attributes. * op_len - the length of the operating attributes. * return - error code. * * **************************************************************************** */ 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) { /* pg iscsi storage node name is */ /* followed to a pgt */ ec = reg_get_pg1(p, pgt, op, op_len); } else { /* a complete pg object */ ec = reg_get_pg(p, op, op_len); pgt[0].tag = 0; pgt[1].tag = 0; pgt[2].tag = 0; } break; case PG_KEY2: /* pg portal ip addr is followed to a pgt */ ec = reg_get_pg2(p, pgt, op, op_len); break; case PG_PGT: switch (pgt[0].tag) { case 0: /* portal group tag does not follow */ /* iscsi storage node or portal object */ *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]); /* FALLTHROUGH */ 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: /* should never happen */ 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); } /* * **************************************************************************** * * reg_auth_src: * Authorize the source attribute the DevAttrReg message. * The update can only performed by the node who has the owenership. * * p - the pointer of the object for returning. * pgt - an attribute array with size 3, the elements are: * 0: the first pg key attribute, it is either the name of an * iscsi storage node object or the ip addr of a portal object. * 1: the second pg key attribute, i.e. the portal port. * 2: the portal group tag attribute. * op - the operating attributes. * op_len - the length of the operating attributes. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * is_obj_online: * determine if the object is currently registered with the server. * * obj - the object being checked. * return - 0: not registered, otherwise registered. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * assoc_clone: * clone the association object. * * p - the object being cloned. * clone_flag - 0: the object is being removed; * 1: only the association is being removed. * return - the clone object. * * **************************************************************************** */ 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; /* clone_flag dd_flag online action */ /* 0 0 0 ASSERT(0) */ /* 0 0 1 NULL */ /* 0 1 0 itself */ /* 0 1 1 clone it */ /* 1 0 0 NULL */ /* 1 0 1 itself */ /* 1 1 0 itself */ /* 1 1 1 itself */ 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); } /* * **************************************************************************** * * free_one_object: * free up one object. * * obj - the object being freed. * * **************************************************************************** */ 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; } } /* free child uids */ i = 0; while (i < NUM_OF_CHILD[obj->type]) { cuid = get_child_n(obj, i); free(cuid); i ++; } /* at last, free the object itself */ #ifdef DEBUG if (verbose_mc) { printf("object(%d) deallocated\n", obj->type); } #endif free(obj); } /* * **************************************************************************** * * free_object: * free up one object. * * obj - the object being freed. * * **************************************************************************** */ void free_object( isns_obj_t *obj ) { free_one_object(obj); } /* * **************************************************************************** * * set_parent_obj: * set the parent object UID. * * obj - the child object. * puid- the parent object UID. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * buff_child_obj: * add a child object UID to the child object array. * * obj - the parent object. * child_type - the type of the child object. * number - the number of the child object. * return - the length of the child object UID array. * * **************************************************************************** */ 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; /* get the pointer of the array which the child belongs to */ while (i < NUM_OF_CHILD[ptype]) { if (TYPE_OF_CHILD[ptype][i] == ctype) { pp = &child[i]; break; } i ++; } /* the child type is not applicable */ if (pp == NULL) { return (ec); } p = *pp; /* get an empty slot from the uid array for this child */ if (p != NULL) { num = (uint32_t)*p; i = 0; while (i < num) { if (p[++i] == NULL) { /* found it */ p[i] = c; return (ec); } } p = *pp; new_num = num + 1; } else { num = 0; new_num = 1; } /* the array is full, enlarge the child uid array */ 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); } /* * **************************************************************************** * * update_child_object: * update the child object of a network entity object. * * puid - the UID of the parent object, i.e. the network entity object. * child_type - the type of the child object. * child_uid - the uid of the child object. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * verify_ref_obj: * update the reference bit of a portal group object. * * obj - the object being ref'ed. * return - error code. * * **************************************************************************** */ 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); } /* * **************************************************************************** * * register_object: * add one object to the object container. * * obj - the object being added. * uid_p- the pointer for returning object UID. * update_p- the pointer for returning flag which indicates if the object * is newly registered or updated with an existing one. * return - error code. * * **************************************************************************** */ int register_object( isns_obj_t *obj, uint32_t *uid_p, int *update_p ) { return (cache_add(obj, 0, uid_p, update_p)); } /* * **************************************************************************** * * register_assoc: * add one association object to the object container, the association * object has only the information for discovery domain membership, i.e. * a name and UID only. * * obj - the association object being added. * uid_p- the pointer for returning object UID. * return - error code. * * **************************************************************************** */ int register_assoc( isns_obj_t *obj, uint32_t *uid_p ) { return (cache_add(obj, 1, uid_p, NULL)); } /* * **************************************************************************** * * is_obj_there: * check if the object is registered or not. * * lcp - the lookup control data. * return - the object UID. * * **************************************************************************** */ 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)); } /* * **************************************************************************** * * setup_ref_lcp: * prepare the lookup control data for looking up a portal group * object which references to a iscsi stroage node and/or a portal * object. * * lcp - the lookup control data. * iscsi- the ref'ed iscsi storage node object. * portal- the ref'ed portal object. * return - error code. * * **************************************************************************** */ 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]; /* extrace the matching attributes from iscsi storage node object */ 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 ++; } /* extrace the matching attributes from portal object */ 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; /* extrace the matching attributes from iscsi storage node object */ 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); } /* * **************************************************************************** * * setup_parent_lcp: * prepare the lookup control data for looking up parent object * with a child object. * * lcp - the lookup control data. * obj - the child object. * return - parent object UID. * * **************************************************************************** */ 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, /* LINTED E_FUNC_ARG_UNUSED */ void *p2 ) { return (get_parent_uid(p1)); } static int cb_node_child( void *p1, /* LINTED E_FUNC_ARG_UNUSED */ 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); } /* * **************************************************************************** * * cb_set_ref: * callback function which sets the reference bit to 1 according to * the type of object. * * p1 - the object. * p2 - the lcp. * return - error code. * * **************************************************************************** */ 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; /* successful */ return (0); } /* * **************************************************************************** * * cb_clear_ref: * callback function which clears the reference bit according to * the type of object. * * p1 - the object. * p2 - the lcp. * return - 1: the object is no longer ref'ed, 0: otherwise. * * **************************************************************************** */ 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) { /* copy required */ 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); } /* * **************************************************************************** * * cb_remove_child: * callback function which removes a child object UID from the * children objet UID array of the parent object. * * p1 - the object. * p2 - the lcp. * return - 1: no more such type of child object, 0: otherwise. * * **************************************************************************** */ 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; /* get the children object UID array */ cuidp = get_child_t(obj, child_type); if (cuidp != NULL) { num_of_child = *cuidp; } /* remove it */ while (num_of_child > 0) { cuid = *++cuidp; if (cuid == child_uid) { *cuidp = 0; break; } num_of_child --; } /* check if all of child object UIDs are removed */ 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; /* parent object type */ isns_type_t ct; /* child object type */ isns_type_t rt; /* ref object type */ isns_type_t et; /* peer object type */ 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 --; } /* End of while each unum */ } j --; } /* End of while each vnum */ 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 --; } /* End of while each vnum */ flag[et] = 1; } /* End of for each type of child */ 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) { /* no such ref, create a default one */ 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); } /* * **************************************************************************** * * do_dereg: * Physically remove an object along with the children objects, * the reference object and the parent object recursively. * Apporiate SCN is triggered. * * lcp - the lookup control for the object being removed. * parent_flag - 1: the object being removed is the parent object; * 0: otherwise. * child_flag - 1: the object being removed is a child object; * 0: otherwise. * pending - 1: do not remove the ESI entry immediately; * 0: remove the ESI entry without any delay. * return - error code. * * **************************************************************************** */ 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; /* remove the object from object container */ obj = cache_remove(lcp, 0); if (obj == NULL) { return (0); } /* trigger a scn */ if (scn_q != NULL) { (void) make_scn(ISNS_OBJECT_REMOVED, obj); } /* dereg children */ 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 ++; } /* clear the ref bit on the ref'd object */ 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); } /* remove it from the parent */ 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) { /* remove it from persistent data store */ if (sys_q) { ec = write_data(DATA_DELETE, obj); } /* remove esi event entry */ if (ec == 0) { (void) esi_remove_obj(obj, pending); } /* save the parent uid for caller */ if (TYPE_OF_PARENT[obj->type] != 0) { lcp->curr_uid = get_parent_uid(obj); } else { /* it's the parent itself */ lcp->curr_uid = get_obj_uid(obj); } } /* remove this portal from scn registry */ if (ec == 0 && obj->type == OBJ_PORTAL) { (void) remove_scn_portal(get_obj_uid(obj)); } /* free the object */ (void) free_object(obj); return (ec); } /* * **************************************************************************** * * dereg_assoc: * Remove one association object from object container. * * lcp - the lookup control for the object being removed. * return - error code. * * **************************************************************************** */ int dereg_assoc( lookup_ctrl_t *lcp ) { isns_obj_t *obj; obj = cache_remove(lcp, 1); /* free the object */ if (obj != NULL) { free_object(obj); } return (0); } /* * **************************************************************************** * * dereg_object: * Remove one object from object container. * * lcp - the lookup control for the object being removed. * return - error code. * * **************************************************************************** */ int dereg_object( lookup_ctrl_t *lcp, int pending ) { return (do_dereg(lcp, 0, 0, pending)); } /* * **************************************************************************** * * data_sync: * Synchronize the cache with persistent data store. * Flush the cache data to data store if the input ec is zero, * retreat the changes in cache and ignore data store update * if there is an error. * * ec - error code. * return - error code. * * **************************************************************************** */ int data_sync( int ec ) { /* cache is updated successfully, commit the data to data store */ if (IS_CACHE_UPDATED()) { if (ec == 0) { ec = write_data(DATA_COMMIT, NULL); } if (ec == 0) { /* successful, trigger the SCN */ (void) queue_msg_set(scn_q, SCN_TRIGGER, (void *)NULL); } else { shutdown_server(); } } else { /* ignore all SCNs which have been generated */ (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 }; /* * **************************************************************************** * * make_unique_name: * make a default unique name for a newly registered network entity, * discovery domain or discovery domain set object. * * len - pointer of the length of the new name for returning. * tag - which attribute of the new name is for. * return - the name being made. * * **************************************************************************** */ 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]); /* no more space, failure */ 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); /* 4-bytes aligned length */ *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 /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include "isns_server.h" #include "isns_log.h" #include "isns_pdu.h" #define ISNS_MAX_IOVEC 5 #define MAX_XID (2^16) #define MAX_RCV_RSP_COUNT 10 /* Maximum number of unmatched xid */ #define ISNS_RCV_RETRY_MAX 2 #define IPV4_RSVD_BYTES 10 /* externs */ #ifdef DEBUG extern void dump_pdu2(isns_pdu_t *); #endif /* * local functions. */ size_t isns_rcv_pdu( int fd, isns_pdu_t **pdu, size_t *pdu_size, int rcv_timeout ) { int poll_cnt; struct pollfd fds; iovec_t iovec[ISNS_MAX_IOVEC]; isns_pdu_t *tmp_pdu_hdr; ssize_t bytes_received, total_bytes_received = 0; struct msghdr msg; uint8_t *tmp_pdu_data; uint16_t payload_len = 0; /* initialize to zero */ *pdu = NULL; *pdu_size = 0; fds.fd = fd; fds.events = (POLLIN | POLLRDNORM); fds.revents = 0; /* Receive the header first */ tmp_pdu_hdr = (isns_pdu_t *)malloc(ISNSP_HEADER_SIZE); if (tmp_pdu_hdr == NULL) { return (0); } (void) memset((void *)&tmp_pdu_hdr[0], 0, ISNSP_HEADER_SIZE); (void) memset((void *)&iovec[0], 0, sizeof (iovec_t)); iovec[0].iov_base = (void *)tmp_pdu_hdr; iovec[0].iov_len = ISNSP_HEADER_SIZE; /* Initialization of the message header. */ bzero(&msg, sizeof (msg)); msg.msg_iov = &iovec[0]; /* msg.msg_flags = MSG_WAITALL, */ msg.msg_iovlen = 1; /* Poll and receive the pdu header */ poll_cnt = 0; do { int err = poll(&fds, 1, rcv_timeout * 1000); if (err <= 0) { poll_cnt ++; } else { bytes_received = recvmsg(fd, &msg, MSG_WAITALL); break; } } while (poll_cnt < ISNS_RCV_RETRY_MAX); if (poll_cnt >= ISNS_RCV_RETRY_MAX) { free(tmp_pdu_hdr); return (0); } if (bytes_received <= 0) { free(tmp_pdu_hdr); return (0); } total_bytes_received += bytes_received; payload_len = ntohs(tmp_pdu_hdr->payload_len); /* Verify the received payload len is within limit */ if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) { free(tmp_pdu_hdr); return (0); } /* Proceed to receive additional data. */ tmp_pdu_data = malloc(payload_len); if (tmp_pdu_data == NULL) { free(tmp_pdu_hdr); return (0); } (void) memset((void *)&iovec[0], 0, sizeof (iovec_t)); iovec[0].iov_base = (void *)tmp_pdu_data; iovec[0].iov_len = payload_len; /* Initialization of the message header. */ bzero(&msg, sizeof (msg)); msg.msg_iov = &iovec[0]; /* msg.msg_flags = MSG_WAITALL, */ msg.msg_iovlen = 1; /* poll and receive the pdu payload */ poll_cnt = 0; do { int err = poll(&fds, 1, rcv_timeout * 1000); if (err <= 0) { poll_cnt ++; } else { bytes_received = recvmsg(fd, &msg, MSG_WAITALL); break; } } while (poll_cnt < ISNS_RCV_RETRY_MAX); if (poll_cnt >= ISNS_RCV_RETRY_MAX) { free(tmp_pdu_data); free(tmp_pdu_hdr); return (0); } if (bytes_received <= 0) { free(tmp_pdu_data); free(tmp_pdu_hdr); return (0); } total_bytes_received += bytes_received; *pdu_size = ISNSP_HEADER_SIZE + payload_len; (*pdu) = (isns_pdu_t *)malloc(*pdu_size); if (*pdu == NULL) { *pdu_size = 0; free(tmp_pdu_data); free(tmp_pdu_hdr); return (0); } (*pdu)->version = ntohs(tmp_pdu_hdr->version); (*pdu)->func_id = ntohs(tmp_pdu_hdr->func_id); (*pdu)->payload_len = payload_len; (*pdu)->flags = ntohs(tmp_pdu_hdr->flags); (*pdu)->xid = ntohs(tmp_pdu_hdr->xid); (*pdu)->seq = ntohs(tmp_pdu_hdr->seq); (void) memcpy(&((*pdu)->payload), tmp_pdu_data, payload_len); free(tmp_pdu_data); tmp_pdu_data = NULL; free(tmp_pdu_hdr); tmp_pdu_hdr = NULL; return (total_bytes_received); } int isns_send_pdu( int fd, isns_pdu_t *pdu, size_t pl ) { uint8_t *payload; uint16_t flags; uint16_t seq; iovec_t iovec[ISNS_MAX_IOVEC]; struct msghdr msg = { 0 }; size_t send_len; ssize_t bytes_sent; /* Initialization of the message header. */ msg.msg_iov = &iovec[0]; /* msg.msg_flags = MSG_WAITALL, */ msg.msg_iovlen = 2; /* * Initialize the pdu flags. */ flags = ISNS_FLAG_SERVER; flags |= ISNS_FLAG_FIRST_PDU; /* * Initialize the pdu sequence id. */ seq = 0; iovec[0].iov_base = (void *)pdu; iovec[0].iov_len = (ISNSP_HEADER_SIZE); payload = pdu->payload; #ifdef DEBUG pdu->flags = htons(flags); pdu->seq = htons(0); pdu->payload_len = htons(pl); dump_pdu2(pdu); #endif do { /* set the payload for sending */ iovec[1].iov_base = (void *)payload; if (pl > ISNSP_MAX_PAYLOAD_SIZE) { send_len = ISNSP_MAX_PAYLOAD_SIZE; } else { send_len = pl; /* set the last pdu flag */ flags |= ISNS_FLAG_LAST_PDU; } iovec[1].iov_len = send_len; pdu->payload_len = htons(send_len); /* set the pdu flags */ pdu->flags = htons(flags); /* set the pdu sequence id */ pdu->seq = htons(seq); /* send the packet */ bytes_sent = sendmsg(fd, &msg, 0); /* get rid of the first pdu flag */ flags &= ~(ISNS_FLAG_FIRST_PDU); /* next part of payload */ payload += send_len; pl -= send_len; /* add the length of header for verification */ send_len += ISNSP_HEADER_SIZE; /* increase the sequence id by one */ seq ++; } while (bytes_sent == send_len && pl > 0); if (bytes_sent == send_len) { return (0); } else { isnslog(LOG_DEBUG, "isns_send_pdu", "sending pdu failed."); return (-1); } } #define RSP_PDU_FRAG_SZ (ISNSP_MAX_PDU_SIZE / 10) static int pdu_reset( isns_pdu_t **rsp, size_t *sz ) { int ec = 0; if (*rsp == NULL) { *rsp = (isns_pdu_t *)malloc(RSP_PDU_FRAG_SZ); if (*rsp != NULL) { *sz = RSP_PDU_FRAG_SZ; } else { ec = ISNS_RSP_INTERNAL_ERROR; } } return (ec); } int pdu_reset_rsp( isns_pdu_t **rsp, size_t *pl, size_t *sz ) { int ec = pdu_reset(rsp, sz); if (ec == 0) { /* leave space for status code */ *pl = 4; } return (ec); } int pdu_reset_scn( isns_pdu_t **pdu, size_t *pl, size_t *sz ) { int ec = pdu_reset(pdu, sz); if (ec == 0) { *pl = 0; } return (ec); } int pdu_reset_esi( isns_pdu_t **pdu, size_t *pl, size_t *sz ) { return (pdu_reset_scn(pdu, pl, sz)); } int pdu_update_code( isns_pdu_t *pdu, size_t *pl, int code ) { isns_resp_t *resp; resp = (isns_resp_t *)pdu->payload; /* reset the payload length */ if (code != ISNS_RSP_SUCCESSFUL || *pl == 0) { *pl = 4; } resp->status = htonl(code); return (0); } int pdu_add_tlv( isns_pdu_t **pdu, size_t *pl, size_t *sz, uint32_t attr_id, uint32_t attr_len, void *attr_data, int pflag ) { int ec = 0; isns_pdu_t *new_pdu; size_t new_sz; isns_tlv_t *attr_tlv; uint8_t *payload_ptr; uint32_t normalized_attr_len; uint64_t attr_tlv_len; /* The attribute length must be 4-byte aligned. Section 5.1.3. */ normalized_attr_len = (attr_len % 4) == 0 ? (attr_len) : (attr_len + (4 - (attr_len % 4))); attr_tlv_len = ISNS_TLV_ATTR_ID_LEN + ISNS_TLV_ATTR_LEN_LEN + normalized_attr_len; /* Check if we are going to exceed the maximum PDU length. */ if ((ISNSP_HEADER_SIZE + *pl + attr_tlv_len) > *sz) { new_sz = *sz + RSP_PDU_FRAG_SZ; new_pdu = (isns_pdu_t *)realloc(*pdu, new_sz); if (new_pdu != NULL) { *sz = new_sz; *pdu = new_pdu; } else { ec = ISNS_RSP_INTERNAL_ERROR; return (ec); } } attr_tlv = (isns_tlv_t *)malloc(attr_tlv_len); (void) memset((void *)attr_tlv, 0, attr_tlv_len); attr_tlv->attr_id = htonl(attr_id); switch (attr_id) { case ISNS_DELIMITER_ATTR_ID: break; case ISNS_PORTAL_IP_ADDR_ATTR_ID: case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: /* IPv6 */ ASSERT(attr_len == sizeof (in6_addr_t)); (void) memcpy(attr_tlv->attr_value, attr_data, sizeof (in6_addr_t)); break; case ISNS_EID_ATTR_ID: case ISNS_ISCSI_NAME_ATTR_ID: case ISNS_ISCSI_ALIAS_ATTR_ID: case ISNS_PG_ISCSI_NAME_ATTR_ID: (void) memcpy(attr_tlv->attr_value, (char *)attr_data, attr_len); break; default: if (attr_len == 8) { if (pflag == 0) { /* * In the iSNS protocol, there is only one * attribute ISNS_TIMESTAMP_ATTR_ID which has * 8 bytes length integer value and when the * function "pdu_add_tlv" is called for adding * the timestamp attribute, the value of * the attribute is always passed in as its * address, i.e. the pflag sets to 1. * So it is an error when we get to this code * path. */ ec = ISNS_RSP_INTERNAL_ERROR; return (ec); } else { *(uint64_t *)attr_tlv->attr_value = *(uint64_t *)attr_data; } } else if (attr_len == 4) { if (pflag == 0) { *(uint32_t *)attr_tlv->attr_value = htonl((uint32_t)attr_data); } else { *(uint32_t *)attr_tlv->attr_value = *(uint32_t *)attr_data; } } break; } attr_tlv->attr_len = htonl(normalized_attr_len); /* * Convert the network byte ordered payload length to host byte * ordered for local address calculation. */ payload_ptr = (*pdu)->payload + *pl; (void) memcpy(payload_ptr, attr_tlv, attr_tlv_len); *pl += attr_tlv_len; /* * The payload length might exceed the maximum length of a * payload that isnsp allows, we will split the payload and * set the size of each payload before they are sent. */ free(attr_tlv); attr_tlv = NULL; return (ec); } isns_tlv_t * pdu_get_source( isns_pdu_t *pdu ) { uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = pdu->payload_len; isns_tlv_t *tlv = NULL; /* response code */ if (pdu->func_id & ISNS_RSP_MASK) { if (payload_len < 4) { return (NULL); } payload += 4; payload_len -= 4; } if (payload_len > 8) { tlv = (isns_tlv_t *)payload; tlv->attr_id = ntohl(tlv->attr_id); tlv->attr_len = ntohl(tlv->attr_len); } return (tlv); } isns_tlv_t * pdu_get_key( isns_pdu_t *pdu, size_t *key_len ) { uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = pdu->payload_len; isns_tlv_t *tlv, *key; /* reset */ *key_len = 0; /* response code */ if (pdu->func_id & ISNS_RSP_MASK) { if (payload_len <= 4) { return (NULL); } payload += 4; payload_len -= 4; } /* skip the soure */ if (payload_len >= 8) { tlv = (isns_tlv_t *)payload; payload += (8 + tlv->attr_len); payload_len -= (8 + tlv->attr_len); key = (isns_tlv_t *)payload; while (payload_len >= 8) { tlv = (isns_tlv_t *)payload; tlv->attr_id = ntohl(tlv->attr_id); tlv->attr_len = ntohl(tlv->attr_len); if (tlv->attr_id == ISNS_DELIMITER_ATTR_ID) { break; } *key_len += (8 + tlv->attr_len); payload += (8 + tlv->attr_len); payload_len -= (8 + tlv->attr_len); } } if (*key_len >= 8) { return (key); } return (NULL); } isns_tlv_t * pdu_get_operand( isns_pdu_t *pdu, size_t *op_len ) { uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = pdu->payload_len; isns_tlv_t *tlv, *op = NULL; int found_op = 0; /* reset */ *op_len = 0; /* response code */ if (pdu->func_id & ISNS_RSP_MASK) { if (payload_len < 4) { return (NULL); } payload += 4; payload_len -= 4; } /* tlvs */ while (payload_len >= 8) { tlv = (isns_tlv_t *)payload; if (found_op != 0) { tlv->attr_id = ntohl(tlv->attr_id); tlv->attr_len = ntohl(tlv->attr_len); payload += (8 + tlv->attr_len); payload_len -= (8 + tlv->attr_len); } else { payload += (8 + tlv->attr_len); payload_len -= (8 + tlv->attr_len); if (tlv->attr_id == ISNS_DELIMITER_ATTR_ID) { /* found it */ op = (isns_tlv_t *)payload; *op_len = payload_len; found_op = 1; } } } if (*op_len >= 8) { return (op); } return (NULL); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include "isns_server.h" #include "isns_func.h" #include "isns_msgq.h" #include "isns_htab.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_dd.h" #include "isns_pdu.h" #include "isns_qry.h" /* * external variables */ extern const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE]; extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; extern const int NUM_OF_CHILD[MAX_OBJ_TYPE]; extern const int TYPE_OF_CHILD[MAX_OBJ_TYPE][MAX_CHILD_TYPE]; /* * global variables */ const int TAG_RANGE[MAX_OBJ_TYPE][3] = { { 0, 0 }, { ENTITY_KEY, LAST_TAG_ENTITY, ENTITY_END }, { ISCSI_KEY, LAST_TAG_ISCSI, ISCSI_END }, { PORTAL_KEY1, LAST_TAG_PORTAL, PORTAL_END }, { PG_KEY1, LAST_TAG_PG, PG_END }, { DD_KEY, LAST_TAG_DD, DD_END }, { DDS_KEY, LAST_TAG_DDS, DDS_END } }; /* * local variables */ typedef int (*qry_func_t)(lookup_ctrl_t *); /* Edge functions of each adjacent object */ static int qry_c2e(lookup_ctrl_t *); static int qry_ds2m(lookup_ctrl_t *); static int qry_slf(lookup_ctrl_t *); static int qry_e2i(lookup_ctrl_t *); static int qry_e2p(lookup_ctrl_t *); static int qry_e2g(lookup_ctrl_t *); static int qry_i2g(lookup_ctrl_t *); static int qry_i2d(lookup_ctrl_t *); static int qry_p2g(lookup_ctrl_t *); static int qry_g2i(lookup_ctrl_t *); static int qry_g2p(lookup_ctrl_t *); static int qry_d2s(lookup_ctrl_t *); /* The directed cyclic graph of query procedure. */ /* __|____e_________i_________p_________g_________d_________s____ */ /* e | qry_slf...qry_e2i...qry_e2p...qry_e2g...NULL......NULL.... */ /* i | qry_c2e...qry_slf...NULL......qry_i2g...qry_i2d...NULL.... */ /* p | qry_c2e...NULL......qry_slf...qry_p2g...NULL......NULL.... */ /* g | qry_c2e...qry_g2i...qry_g2p...qry_slf...NULL......NULL.... */ /* d | NULL......qry_ds2m..NULL......NULL......qry_slf...qry_d2s. */ /* s | NULL......NULL......NULL......NULL......qry_ds2m..qry_slf. */ /* The type of spanning tree of query graph. */ typedef struct adjvex { qry_func_t f; isns_type_t t; struct adjvex const *v; } adjvex_t; /* The solid edges in the spanning tree. */ static const adjvex_t v_slf = { &qry_slf, 0, NULL }; static const adjvex_t v_c2e = { &qry_c2e, OBJ_ENTITY, NULL }; static const adjvex_t v_e2i = { &qry_e2i, OBJ_ISCSI, NULL }; static const adjvex_t v_e2p = { &qry_e2p, OBJ_PORTAL, NULL }; static const adjvex_t v_e2g = { &qry_e2g, OBJ_PG, NULL }; static const adjvex_t v_i2g = { &qry_i2g, OBJ_PG, NULL }; static const adjvex_t v_i2d = { &qry_i2d, OBJ_DD, NULL }; static const adjvex_t v_p2g = { &qry_p2g, OBJ_PG, NULL }; static const adjvex_t v_g2i = { &qry_g2i, OBJ_ISCSI, NULL }; static const adjvex_t v_g2p = { &qry_g2p, OBJ_PORTAL, NULL }; static const adjvex_t v_d2s = { &qry_d2s, OBJ_DDS, NULL }; static const adjvex_t v_d2i = { &qry_ds2m, OBJ_ISCSI, NULL }; static const adjvex_t v_s2d = { &qry_ds2m, OBJ_DD, NULL }; /* The virtual edges in the spanning tree. */ static const adjvex_t v_i2p = { &qry_i2g, OBJ_PG, &v_g2p }; static const adjvex_t v_i2s = { &qry_i2d, OBJ_DD, &v_d2s }; static const adjvex_t v_g2d = { &qry_g2i, OBJ_ISCSI, &v_i2d }; static const adjvex_t v_g2s = { &qry_g2i, OBJ_ISCSI, &v_i2s }; static const adjvex_t v_p2i = { &qry_p2g, OBJ_PG, &v_g2i }; static const adjvex_t v_p2d = { &qry_p2g, OBJ_PG, &v_g2d }; static const adjvex_t v_p2s = { &qry_p2g, OBJ_PG, &v_g2s }; static const adjvex_t v_e2d = { &qry_e2i, OBJ_ISCSI, &v_i2d }; static const adjvex_t v_e2s = { &qry_e2i, OBJ_ISCSI, &v_i2s }; static const adjvex_t v_d2e = { &qry_ds2m, OBJ_ISCSI, &v_c2e }; static const adjvex_t v_d2p = { &qry_ds2m, OBJ_ISCSI, &v_i2p }; static const adjvex_t v_d2g = { &qry_ds2m, OBJ_ISCSI, &v_i2g }; static const adjvex_t v_s2e = { &qry_ds2m, OBJ_DD, &v_d2e }; static const adjvex_t v_s2i = { &qry_ds2m, OBJ_DD, &v_d2i }; static const adjvex_t v_s2p = { &qry_ds2m, OBJ_DD, &v_d2p }; static const adjvex_t v_s2g = { &qry_ds2m, OBJ_DD, &v_d2g }; /* the vector of query graph */ static const adjvex_t *qry_puzzle[MAX_OBJ_TYPE][MAX_OBJ_TYPE] = { { NULL }, { NULL, &v_slf, &v_e2i, &v_e2p, &v_e2g, &v_e2d, &v_e2s }, { NULL, &v_c2e, &v_slf, &v_i2p, &v_i2g, &v_i2d, &v_i2s }, { NULL, &v_c2e, &v_p2i, &v_slf, &v_p2g, &v_p2d, &v_p2s }, { NULL, &v_c2e, &v_g2i, &v_g2p, &v_slf, &v_g2d, &v_g2s }, { NULL, &v_d2e, &v_d2i, &v_d2p, &v_d2g, &v_slf, &v_d2s }, { NULL, &v_s2e, &v_s2i, &v_s2p, &v_s2g, &v_s2d, &v_slf } }; static int cb_qry_parent_uid( void *p1, /* LINTED E_FUNC_ARG_UNUSED */ void *p2 ) { uint32_t puid = get_parent_uid((isns_obj_t *)p1); return ((int)puid); } static int cb_qry_child_uids( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; isns_type_t type = lcp->data[1].ui; uint32_t *uidp = get_child_t(obj, type); uint32_t num = 0; uint32_t *p; if (uidp != NULL && *uidp > 0) { num = *uidp; p = malloc(num * sizeof (*p)); if (p != NULL) { uidp ++; (void) memcpy(p, uidp, num * sizeof (*p)); lcp->id[2] = num; lcp->data[2].ptr = (uchar_t *)p; } else { return (ISNS_RSP_INTERNAL_ERROR); } } return (0); } static int e2c( lookup_ctrl_t *lcp, isns_type_t type ) { int ec = 0; uint32_t uid = lcp->curr_uid; /* last child */ uint32_t num_of_child; uint32_t *uids; uint32_t tmp_uid = 0; /* the first times of query */ if (uid == 0) { lcp->data[1].ui = type; ec = cache_lookup(lcp, NULL, cb_qry_child_uids); } num_of_child = lcp->id[2]; uids = (uint32_t *)lcp->data[2].ptr; while (num_of_child > 0) { if (*uids > uid) { tmp_uid = *uids; break; } uids ++; num_of_child --; } uid = tmp_uid; /* no more child, clean up memory */ if (uid == 0) { lcp->data[1].ui = 0; lcp->id[2] = 0; lcp->data[2].ptr = NULL; /* free up the memory */ free(uids); } /* save it for returning and querying next uid */ lcp->curr_uid = uid; return (ec); } static int qry_c2e( lookup_ctrl_t *lcp ) { uint32_t uid; /* child object has only one parent */ if (lcp->curr_uid == 0) { uid = (uint32_t)cache_lookup(lcp, NULL, cb_qry_parent_uid); } else { uid = 0; } /* save the result for returnning */ lcp->curr_uid = uid; return (0); } static int qry_ds2m( lookup_ctrl_t *lcp ) { int ec = 0; uint32_t uid = lcp->curr_uid; /* last member */ isns_type_t type = lcp->type; uint32_t ds_id = lcp->data[0].ui; uint32_t tmp_uid; uint32_t n; bmp_t *p; /* the first times of query */ if (uid == 0) { ec = (type == OBJ_DD) ? get_dd_matrix(ds_id, &p, &n) : get_dds_matrix(ds_id, &p, &n); lcp->id[1] = n; lcp->data[1].ptr = (uchar_t *)p; } else { n = lcp->id[1]; p = (bmp_t *)lcp->data[1].ptr; } FOR_EACH_MEMBER(p, n, tmp_uid, { if (tmp_uid > uid) { lcp->curr_uid = tmp_uid; return (ec); } }); /* no more member, clean up memory */ lcp->id[1] = 0; lcp->data[1].ptr = NULL; /* free up the matrix */ free(p); lcp->curr_uid = 0; return (ec); } static int qry_slf( lookup_ctrl_t *lcp ) { uint32_t uid; if (lcp->curr_uid == 0) { uid = lcp->data[0].ui; } else { uid = 0; } lcp->curr_uid = uid; return (0); } static int qry_e2i( lookup_ctrl_t *lcp ) { return (e2c(lcp, OBJ_ISCSI)); } static int qry_e2p( lookup_ctrl_t *lcp ) { return (e2c(lcp, OBJ_PORTAL)); } static int qry_e2g( lookup_ctrl_t *lcp ) { uint32_t uid = lcp->curr_uid; /* last pg */ htab_t *htab = cache_get_htab(OBJ_PG); lookup_ctrl_t lc; uint32_t puid; SET_UID_LCP(&lc, OBJ_PG, 0); /* this is a shortcut */ FOR_EACH_ITEM(htab, uid, { lc.data[0].ui = uid; puid = (uint32_t)cache_lookup(&lc, NULL, cb_qry_parent_uid); if (puid == lcp->data[0].ui) { /* keep the current uid */ lcp->curr_uid = uid; return (0); } }); lcp->curr_uid = 0; return (0); } static int qry_i2g( lookup_ctrl_t *lcp ) { int ec = 0; uint32_t uid = lcp->curr_uid; /* last pg */ lookup_ctrl_t lc; /* the first times of query */ if (uid == 0) { lcp->id[1] = ISNS_ISCSI_NAME_ATTR_ID; ec = cache_lookup(lcp, NULL, cb_clone_attrs); } if (lcp->data[1].ptr != NULL) { /* pg lookup */ lc.curr_uid = uid; lc.type = OBJ_PG; lc.id[0] = ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID); lc.op[0] = OP_STRING; lc.data[0].ptr = lcp->data[1].ptr; lc.op[1] = 0; uid = is_obj_there(&lc); } else { uid = 0; } /* no more pg, update lcp with pg object */ if (uid == 0) { lcp->id[1] = 0; /* clean up the memory */ if (lcp->data[1].ptr != NULL) { free(lcp->data[1].ptr); /* reset it */ lcp->data[1].ptr = NULL; } } /* save it for returning and querying next pg */ lcp->curr_uid = uid; return (ec); } static int qry_i2d( lookup_ctrl_t *lcp ) { uint32_t dd_id = lcp->curr_uid; /* last dd_id */ uint32_t uid = lcp->data[0].ui; dd_id = get_dd_id(uid, dd_id); /* save it for returning and getting next dd */ lcp->curr_uid = dd_id; return (0); } static int qry_p2g( lookup_ctrl_t *lcp ) { int ec = 0; uint32_t uid = lcp->curr_uid; /* last pg */ lookup_ctrl_t lc; /* the first time of query */ if (uid == 0) { /* use 1&2 for the portal ip address & port */ lcp->id[1] = ISNS_PORTAL_IP_ADDR_ATTR_ID; lcp->id[2] = ISNS_PORTAL_PORT_ATTR_ID; ec = cache_lookup(lcp, NULL, cb_clone_attrs); } if (lcp->data[1].ip != NULL) { /* pg lookup */ lc.curr_uid = uid; lc.type = OBJ_PG; lc.id[0] = ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID); lc.op[0] = OP_MEMORY_IP6; lc.data[0].ip = lcp->data[1].ip; lc.id[1] = ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID); lc.op[1] = OP_INTEGER; lc.data[1].ui = lcp->data[2].ui; lc.op[2] = 0; uid = is_obj_there(&lc); } else { uid = 0; } /* no more pg, clean up memory */ if (uid == 0) { lcp->id[1] = 0; lcp->id[2] = 0; /* clean up the memory */ if (lcp->data[1].ip != NULL) { free(lcp->data[1].ip); /* reset it */ lcp->data[1].ip = NULL; } lcp->data[2].ui = 0; } /* save it for returning and next query */ lcp->curr_uid = uid; return (ec); } static int qry_g2i( lookup_ctrl_t *lcp ) { int ec = 0; uint32_t uid = lcp->curr_uid; /* last node */ lookup_ctrl_t lc; /* the first time of query */ if (uid == 0) { /* use slot 1 for the storage node name */ lcp->id[1] = ISNS_PG_ISCSI_NAME_ATTR_ID; ec = cache_lookup(lcp, NULL, cb_clone_attrs); if (lcp->data[1].ptr != NULL) { /* iscsi node lookup */ lc.curr_uid = uid; lc.type = OBJ_ISCSI; lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); lc.op[0] = OP_STRING; lc.data[0].ptr = lcp->data[1].ptr; lc.op[1] = 0; uid = is_obj_there(&lc); /* no longer need it, clean it up */ free(lcp->data[1].ptr); lcp->data[1].ptr = NULL; } /* no longer need it, reset it */ lcp->id[1] = 0; } else { /* one pg has maximum number of one storage node */ uid = 0; } /* save it for returning and next query */ lcp->curr_uid = uid; return (ec); } static int qry_g2p( lookup_ctrl_t *lcp ) { int ec = 0; uint32_t uid = lcp->curr_uid; /* last portal */ lookup_ctrl_t lc; /* the first times of query */ if (uid == 0) { /* use 1&2 for the portal ip addr and port */ lcp->id[1] = ISNS_PG_PORTAL_IP_ADDR_ATTR_ID; lcp->id[2] = ISNS_PG_PORTAL_PORT_ATTR_ID; ec = cache_lookup(lcp, NULL, cb_clone_attrs); if (lcp->data[1].ip != NULL) { /* portal lookup */ lc.curr_uid = uid; lc.type = OBJ_PORTAL; lc.id[0] = ATTR_INDEX_PORTAL( ISNS_PORTAL_IP_ADDR_ATTR_ID); lc.op[0] = OP_MEMORY_IP6; lc.data[0].ip = lcp->data[1].ip; lc.id[1] = ATTR_INDEX_PORTAL( ISNS_PORTAL_PORT_ATTR_ID); lc.op[1] = OP_INTEGER; lc.data[1].ui = lcp->data[2].ui; lc.op[2] = 0; uid = is_obj_there(&lc); /* no longer need it, reset it */ free(lcp->data[1].ip); lcp->data[1].ip = NULL; } /* no longer need it, reset it */ lcp->id[1] = 0; lcp->id[2] = 0; lcp->data[2].ui = 0; } else { /* one pg has maximum number of one portal */ uid = 0; } /* save it for returning and next query */ lcp->curr_uid = uid; return (ec); } static int qry_d2s( lookup_ctrl_t *lcp ) { uint32_t dds_id = lcp->curr_uid; /* last dds */ uint32_t dd_id = lcp->data[0].ui; dds_id = get_dds_id(dd_id, dds_id); /* save it for returning and for getting next dds */ lcp->curr_uid = dds_id; return (0); } int validate_qry_key( isns_type_t type, isns_tlv_t *key, uint16_t key_len, isns_attr_t *attrs ) { int ec = 0; uint32_t tag; uint32_t min_tag, max_tag; isns_attr_t *attr; min_tag = TAG_RANGE[type][0]; max_tag = TAG_RANGE[type][2]; while (key_len != 0 && ec == 0) { tag = key->attr_id; if (tag < min_tag || tag > max_tag) { ec = ISNS_RSP_MSG_FORMAT_ERROR; } else if (key->attr_len > 0 && attrs != NULL) { attr = &attrs[tag - min_tag]; /* ATTR_INDEX_xxx */ ec = extract_attr(attr, key, 0); if (ec == ISNS_RSP_INVALID_REGIS) { ec = ISNS_RSP_MSG_FORMAT_ERROR; } } NEXT_TLV(key, key_len); } return (ec); } static lookup_method_t get_op_method( uint32_t tag ) { lookup_method_t method = 0; switch (tag) { /* OP_STRING */ case ISNS_EID_ATTR_ID: 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: case ISNS_ISCSI_NAME_ATTR_ID: case ISNS_PG_ISCSI_NAME_ATTR_ID: case ISNS_ISCSI_AUTH_METHOD_ATTR_ID: method = OP_STRING; break; /* OP_MEMORY_IP6 */ case ISNS_MGMT_IP_ADDR_ATTR_ID: case ISNS_PORTAL_IP_ADDR_ATTR_ID: case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: method = OP_MEMORY_IP6; break; /* OP_INTEGER */ case ISNS_ENTITY_PROTOCOL_ATTR_ID: case ISNS_VERSION_RANGE_ATTR_ID: case ISNS_ENTITY_REG_PERIOD_ATTR_ID: case ISNS_ENTITY_INDEX_ATTR_ID: case ISNS_PORTAL_PORT_ATTR_ID: case ISNS_ESI_INTERVAL_ATTR_ID: case ISNS_ESI_PORT_ATTR_ID: case ISNS_PORTAL_INDEX_ATTR_ID: case ISNS_SCN_PORT_ATTR_ID: case ISNS_ISCSI_NODE_TYPE_ATTR_ID: case ISNS_ISCSI_SCN_BITMAP_ATTR_ID: case ISNS_ISCSI_NODE_INDEX_ATTR_ID: case ISNS_PG_PORTAL_PORT_ATTR_ID: case ISNS_PG_TAG_ATTR_ID: case ISNS_PG_INDEX_ATTR_ID: case ISNS_DD_SET_ID_ATTR_ID: case ISNS_DD_SET_STATUS_ATTR_ID: case ISNS_DD_ID_ATTR_ID: /* all other attrs */ default: method = OP_INTEGER; break; } return (method); } static int cb_attrs_match( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; isns_attr_t *attrs = (isns_attr_t *) ((lookup_ctrl_t *)p2)->data[1].ptr; lookup_ctrl_t lc; int match = 1; /* 0: not match, otherwise: match */ int i; lc.op[1] = 0; for (i = 0; match != 0 && i < NUM_OF_ATTRS[obj->type]; i++) { if (attrs->tag != 0 && attrs->len > 0) { lc.id[0] = i; lc.op[0] = get_op_method(attrs->tag); lc.data[0].ptr = attrs->value.ptr; match = key_cmp(&lc, obj) == 0 ? 1 : 0; } attrs ++; } return (match); } static int attrs_match( isns_type_t type, uint32_t uid, isns_attr_t *attrs ) { int match; /* 0: not match, otherwise: match */ lookup_ctrl_t lc; SET_UID_LCP(&lc, type, uid); lc.data[1].ptr = (uchar_t *)attrs; match = cache_lookup(&lc, NULL, cb_attrs_match); return (match); } static int insert_uid( uint32_t **pp, uint32_t *np, uint32_t *sp, uint32_t uid ) { int ec = 0; uint32_t *p = *pp; uint32_t n = *np; uint32_t s = *sp; uint32_t u; uint32_t *t; /* check for duplication */ if (n > 0 && uid <= p[n - 1]) { while (n-- > 0) { if (p[n] == uid) { return (0); } } n = *np; u = p[n - 1]; p[n - 1] = uid; uid = u; } if (s == n) { s = (s == 0) ? 8 : s * 2; t = (uint32_t *)realloc(p, s * sizeof (uint32_t)); if (t != NULL) { p = t; *pp = p; *sp = s; } else { ec = ISNS_RSP_INTERNAL_ERROR; } } if (ec == 0) { p[n ++] = uid; *np = n; } return (ec); } static int qry_and_match( uint32_t **obj_uids, uint32_t *num_of_objs, uint32_t *size, isns_type_t type, uint32_t src_uid, isns_type_t src_type, isns_attr_t *attrs ) { int ec = 0; lookup_ctrl_t lc = { 0 }; /* !!! need to be empty */ uint32_t uid; const adjvex_t *vex; /* circular list */ uint32_t *p[2], n[2], s[2]; int i, j; uint32_t *p1, n1; uint32_t *p2, n2, s2; isns_type_t t; /* initialize the circular list */ i = 0; j = 1; p[i] = *obj_uids; n[i] = *num_of_objs; s[i] = *size; p[j] = malloc(8 * sizeof (uint32_t)); p[j][0] = src_uid; n[j] = 1; s[j] = 8; /* initial object type of being queried */ t = src_type; vex = qry_puzzle[src_type][type]; do { /* shift one on the circular list */ i = (i + 1) & 1; j = (j + 1) & 1; p1 = p[i]; n1 = n[i]; p2 = p[j]; n2 = n[j]; s2 = s[j]; /* prepare lookup control */ lc.type = t; lc.id[0] = UID_ATTR_INDEX[t]; lc.op[0] = OP_INTEGER; /* result object type */ t = vex->t; FOR_EACH_OBJS(p1, n1, uid, { /* start query */ lc.data[0].ui = uid; ec = vex->f(&lc); uid = lc.curr_uid; while (ec == 0 && uid != 0) { if (attrs == NULL || attrs_match(type, uid, attrs) != 0) { ec = insert_uid(&p2, &n2, &s2, uid); } if (ec == 0) { ec = vex->f(&lc); uid = lc.curr_uid; } else { n1 = n2 = 0; /* force break */ } } }); if (ec == 0) { vex = vex->v; } else { vex = NULL; /* force break */ } /* push back */ p[j] = p2; n[j] = n2; s[j] = s2; /* reset the number of objects */ n[i] = 0; } while (vex != NULL); /* clean up the memory */ free(p1); if (ec != 0) { free(p2); p2 = NULL; n2 = 0; s2 = 0; } *obj_uids = p2; *num_of_objs = n2; *size = s2; return (ec); } int get_qry_keys( bmp_t *nodes_bmp, uint32_t num_of_nodes, isns_type_t *type, isns_tlv_t *key, uint16_t key_len, uint32_t **obj_uids, uint32_t *num_of_objs ) { int ec = 0; union { isns_obj_t o; isns_entity_t e; isns_iscsi_t i; isns_portal_t p; isns_pg_t g; isns_dd_t d; isns_dds_t s; } an_obj = { 0 }; isns_attr_t *attrs; htab_t *htab; uint32_t node_uid; uint32_t size; *obj_uids = NULL; *num_of_objs = 0; size = 0; /* get the object type identified by the key */ *type = TLV2TYPE(key); if (*type == 0) { return (ISNS_RSP_INVALID_QRY); } attrs = &an_obj.o.attrs[0]; /* validate the Message Key */ ec = validate_qry_key(*type, key, key_len, attrs); if (ec != 0) { return (ec); } if (nodes_bmp != NULL) { FOR_EACH_MEMBER(nodes_bmp, num_of_nodes, node_uid, { ec = qry_and_match( obj_uids, num_of_objs, &size, *type, node_uid, OBJ_ISCSI, attrs); if (ec != 0) { return (ec); } }); } else { node_uid = 0; htab = cache_get_htab(OBJ_ISCSI); FOR_EACH_ITEM(htab, node_uid, { ec = qry_and_match( obj_uids, num_of_objs, &size, *type, node_uid, OBJ_ISCSI, attrs); if (ec != 0) { return (ec); } }); } return (ec); } int get_qry_ops( uint32_t uid, isns_type_t src_type, isns_type_t op_type, uint32_t **op_uids, uint32_t *num_of_ops, uint32_t *size ) { int ec = 0; *num_of_ops = 0; ec = qry_and_match( op_uids, num_of_ops, size, op_type, uid, src_type, NULL); return (ec); } int get_qry_ops2( uint32_t *nodes_bmp, uint32_t num_of_nodes, isns_type_t op_type, uint32_t **op_uids, uint32_t *num_of_ops, uint32_t *size ) { int ec = 0; uint32_t node_uid; htab_t *htab; *num_of_ops = 0; if (nodes_bmp != NULL) { FOR_EACH_MEMBER(nodes_bmp, num_of_nodes, node_uid, { ec = qry_and_match( op_uids, num_of_ops, size, op_type, node_uid, OBJ_ISCSI, NULL); if (ec != 0) { return (ec); } }); } else { node_uid = 0; htab = cache_get_htab(OBJ_ISCSI); FOR_EACH_ITEM(htab, node_uid, { ec = qry_and_match( op_uids, num_of_ops, size, op_type, node_uid, OBJ_ISCSI, NULL); if (ec != 0) { return (ec); } }); } return (ec); } uint32_t get_next_obj( isns_tlv_t *tlv, uint32_t tlv_len, isns_type_t type, uint32_t *uids, uint32_t num ) { lookup_ctrl_t lc; uint32_t tag; uint8_t *value; uint32_t old = 0; uint32_t min = 0; uint32_t uid, diff; uint32_t pre_diff = 0xFFFFFFFF; lc.curr_uid = 0; lc.type = type; lc.op[1] = 0; lc.op[2] = 0; if (tlv_len > 8) { tag = tlv->attr_id; value = tlv->attr_value; switch (tag) { 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; 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; 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); 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(tlv, tlv_len); if (tlv_len > 8 && ((tag = tlv->attr_id) == ISNS_PORTAL_PORT_ATTR_ID)) { value = tlv->attr_value; lc.id[1] = ATTR_INDEX_PORTAL( ISNS_PORTAL_PORT_ATTR_ID); lc.op[1] = OP_INTEGER; lc.data[1].ui = ntohl(*(uint32_t *)value); } else { return (0); } 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); break; case ISNS_PG_INDEX_ATTR_ID: lc.id[0] = ATTR_INDEX_PG(ISNS_PG_INDEX_ATTR_ID); lc.op[0] = OP_INTEGER; lc.data[0].ui = ntohl(*(uint32_t *)value); break; default: return (0); } old = is_obj_there(&lc); if (old == 0) { return (0); } } while (num > 0) { uid = uids[-- num]; if (uid > old) { diff = uid - old; if (diff < pre_diff) { min = uid; pre_diff = diff; } } } return (min); } static int cb_qry_rsp( void *p1, void *p2 ) { int ec = 0; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; uint16_t tlv_len = lcp->id[1]; isns_tlv_t *tlv = (isns_tlv_t *)lcp->data[1].ptr; conn_arg_t *conn = (conn_arg_t *)lcp->data[2].ptr; isns_type_t type = obj->type; uint32_t min_tag = TAG_RANGE[type][0]; uint32_t mid_tag = TAG_RANGE[type][1]; uint32_t max_tag = TAG_RANGE[type][2]; isns_attr_t *attr; uint32_t tag; uint32_t id; uint32_t len; void *value; isns_pdu_t *rsp = conn->out_packet.pdu; size_t pl = conn->out_packet.pl; size_t sz = conn->out_packet.sz; do { if (tlv->attr_len == 0) { tag = tlv->attr_id; if (tag <= mid_tag) { id = ATTR_INDEX(tag, type); attr = &obj->attrs[id]; len = attr->len; value = (void *)attr->value.ptr; ec = pdu_add_tlv(&rsp, &pl, &sz, tag, len, value, 0); } } NEXT_TLV(tlv, tlv_len); } while (ec == 0 && tlv_len >= 8 && tlv->attr_id >= min_tag && tlv->attr_id <= max_tag); conn->out_packet.pdu = rsp; conn->out_packet.pl = pl; conn->out_packet.sz = sz; return (ec); } int get_qry_attrs( uint32_t uid, isns_type_t type, isns_tlv_t *tlv, uint16_t tlv_len, conn_arg_t *conn ) { int ec = 0; lookup_ctrl_t lc; SET_UID_LCP(&lc, type, uid); lc.id[1] = tlv_len; lc.data[1].ptr = (uchar_t *)tlv; lc.data[2].ptr = (uchar_t *)conn; ec = cache_lookup(&lc, NULL, cb_qry_rsp); return (ec); } int get_qry_attrs1( uint32_t uid, isns_type_t type, isns_tlv_t *tlv, uint16_t tlv_len, conn_arg_t *conn ) { isns_tlv_t *tmp = tlv; uint32_t tmp_len = tlv_len; /* clear the length of all of tlv */ while (tmp_len > 8) { tmp->attr_len = 0; NEXT_TLV(tmp, tmp_len); } return (get_qry_attrs(uid, type, tlv, tlv_len, conn)); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "isns_server.h" #include "isns_protocol.h" #include "isns_log.h" #include "isns_sched.h" #include "isns_scn.h" #include "isns_esi.h" /* * extern variables. */ /* * global variables. */ pthread_mutex_t el_mtx = PTHREAD_MUTEX_INITIALIZER; /* * local variables. */ static el_key_t **il; static int icurr = 0; static el_notice_t *curr = NULL; static uint32_t DU; static uint32_t DT; static uint32_t LB; static uint32_t NLIM; /* * external variables. */ /* * local functions. */ /* * **************************************************************************** * * il_shift: * Shift the indexed-list to the most current time. * * t - most current time. * * **************************************************************************** */ static void il_shift( uint32_t t ) { el_notice_t *fn, *n; el_key_t *fk, *k; uint32_t nt; int c; k = il[icurr]; while (k->time < t) { fk = k; fn = k->notice; /* remove the dummy key and dummy notice */ fk->left->right = fk->right; fk->right->left = fk->left; fn->pred->sucd = fn->sucd; fn->sucd->pred = fn->pred; /* find the place where the dummy goes to */ k = il[(icurr + DU - 1) % DU]; if (k->time < INFINITY - DT) { nt = k->time + DT; /* next key time */ } else { nt = INFINITY - 1; /* the last second */ } while (k->time < nt) { k = k->right; } n = k->notice->pred; c = 1; while (n->time >= nt) { c ++; n = n->pred; } n = n->sucd; /* update lower bound */ LB = fk->time; /* insert the dummy key */ fk->time = nt; fk->count = k->count - c + 1; fk->left = k->left; fk->right = k; k->left->right = fk; k->left = fk; k->count = c; /* insert the dummy notice */ fn->time = nt; fn->pred = n->pred; fn->sucd = n; n->pred->sucd = fn; n->pred = fn; /* shift the current index */ icurr = (icurr + 1) % DU; k = il[icurr]; } } /* * global functions. */ /* * **************************************************************************** * * el_init: * Initialize the element list. * * du - Number of uint in the indexed-list. * dt - Time interval of the indexed-list. * nlim - Limit number of each notice. * return - 0: successful, otherwise failed. * * **************************************************************************** */ int el_init( uint32_t du, uint32_t dt, uint32_t nlim ) { el_key_t *k, *kleft; el_notice_t *n, *npred; uint32_t t = 0; int i; if (du < 1 || dt < 1 || nlim < 1) { return (1); } DU = du; DT = dt; LB = 0; NLIM = nlim; /* * initialize the event set */ /* first dummy notice */ n = (el_notice_t *)malloc(sizeof (el_notice_t)); if (n == NULL) { return (1); } n->time = LB; n->event = NULL; n->isdummy = 1; n->pred = NULL; npred = n; /* first dummy key */ k = (el_key_t *)malloc(sizeof (el_key_t)); if (k == NULL) { return (1); } k->time = LB; k->count = 1; k->notice = n; k->left = NULL; kleft = k; n->key = k; /* index list */ il = (el_key_t **)malloc((DU + 1) * sizeof (el_key_t *)); if (il == NULL) { return (1); } /* create notice list, key list & index list */ for (i = 0; i < DU; i++) { t += DT; n = (el_notice_t *)malloc(sizeof (el_notice_t)); if (n == NULL) { return (1); } n->time = t; n->event = NULL; n->isdummy = 1; n->pred = npred; npred->sucd = n; npred = n; k = (el_key_t *)malloc(sizeof (el_key_t)); if (k == NULL) { return (1); } k->time = t; k->count = 1; k->notice = n; k->left = kleft; kleft->right = k; kleft = k; n->key = k; il[i] = k; } /* last dummy notice */ n = (el_notice_t *)malloc(sizeof (el_notice_t)); if (n == NULL) { return (1); } n->time = INFINITY; /* the end of the world */ n->event = NULL; n->isdummy = 1; n->pred = npred; n->sucd = NULL; npred->sucd = n; /* last dummy key */ k = (el_key_t *)malloc(sizeof (el_key_t)); if (k == NULL) { return (1); } k->time = INFINITY; /* the end of the world */ k->count = 1; k->notice = n; k->left = kleft; k->right = NULL; kleft->right = k; n->key = k; /* last index */ il[DU] = k; return (0); } /* * **************************************************************************** * * el_add: * Add an event to the element list with it's execution time. * It might not actually put the event to the list if the event * is the most current one for execution. * * ev - The Event. * t - The time when the event is scheduled at. * evp - Pointer of event for returning. * return - Error code. * * **************************************************************************** */ int el_add( void *ev, uint32_t t, void **evp ) { int ec = 0; uint32_t t1 = 0; int i, j; el_key_t *k; el_notice_t *n; el_key_t *y; el_notice_t *x; /* lock the event set */ (void) pthread_mutex_lock(&el_mtx); /* strip it off from the event list which is being handled */ if (evf_again(ev) != 0) { /* if it is rescheduling an event and the event */ /* was waiting for execution after idle finishes */ if (evf_rem(ev) == 0 && evp != NULL && (curr == NULL || t <= curr->time)) { /* no need to reschedule it */ *evp = ev; goto add_done; } evl_strip(ev); /* if it is marked as a removed event, do not add it */ if (evf_rem(ev) != 0) { ev_free(ev); goto add_done; } } /* get the index in the il */ if (t == 0) { t = ev_intval(ev); /* not initialization time */ if (evf_init(ev) || evf_again(ev)) { t1 = get_stopwatch(evf_wakeup(ev)); /* make il up to date */ il_shift(t1); /* avoid overflow */ if (t1 >= INFINITY - t) { /* the last second */ t1 = INFINITY - t1 - 1; } } t += t1; } i = (t - LB) / DT; if (i >= DU) { i = DU; } else { i = (i + icurr) % DU; } /* find the right key */ k = (il[i])->left; while (k->time > t) { k = k->left; } k = k->right; /* need to split */ if (k->count == NLIM) { /* insert a new key */ y = (el_key_t *)malloc(sizeof (el_key_t)); if (y == NULL) { ec = ISNS_RSP_INTERNAL_ERROR; goto add_done; } k->count = NLIM / 2; x = k->notice; for (j = 1; j <= NLIM / 2; j++) { x = x->pred; } y->time = x->time; y->count = NLIM - NLIM / 2; y->notice = x; y->right = k; y->left = k->left; k->left->right = y; k->left = y; /* update the key */ x->key = y; /* shift */ if (y->time > t) { k = y; } } /* make a new notice */ x = (el_notice_t *)malloc(sizeof (el_notice_t)); if (x == NULL) { ec = ISNS_RSP_INTERNAL_ERROR; goto add_done; } x->time = t; x->event = ev; x->isdummy = 0; x->key = NULL; /* insert it */ n = k->notice; while (n->time > t) { n = n->pred; } x->pred = n; x->sucd = n->sucd; n->sucd->pred = x; n->sucd = x; /* increase number of notice */ k->count ++; /* reset current notice and wake up idle */ if (curr == NULL || curr->time > t) { curr = x; } /* clear event flags */ evf_zero(ev); isnslog(LOG_DEBUG, "el_add", "%s [%d] is scheduled at %d.", ((ev_t *)ev)->type == EV_ESI ? "ESI" : "REG_EXP", ((ev_t *)ev)->uid, t); add_done: /* unlock the event set */ (void) pthread_mutex_unlock(&el_mtx); /* failed, free it */ if (ec != 0) { ev_free(ev); isnslog(LOG_DEBUG, "el_add", "failed, no memory."); } return (ec); } /* * **************************************************************************** * * el_remove: * Remove or update an event from the element list. If the event is * currently not in the element list, it must be in a queue which * contains all of event which are being executing at the moment. * So it seeks the event from the list prior to the element list. * * id1 - The event ID. * id2 - The second ID for the event update. * pending - Do not actually remove, mark it for removal pending. * return - Error code. * * **************************************************************************** */ int el_remove( uint32_t id1, uint32_t id2, int pending ) { el_key_t *k, *kl, *kr; el_notice_t *n, *n2; (void) pthread_mutex_lock(&el_mtx); /* search the event from the event list which is being handled */ if (evl_remove(id1, id2, pending) != 0) { (void) pthread_mutex_unlock(&el_mtx); return (0); } /* search the notice starting from current */ n = curr; while (n != NULL) { /* found the match notice */ if (!n->isdummy && ev_match(n->event, id1) != 0) { if (ev_remove(n->event, id2, 1, pending) == 0) { /* update the key of the match notice */ k = n->key; if (k != NULL && k->count == 1) { /* no more notice */ k->left->right = k->right; k->right->left = k->left; free(k); } else { if (k != NULL) { k->notice = n->pred; k->notice->key = k; k->time = k->notice->time; } n2 = n; k = n2->key; while (k == NULL) { n2 = n2->sucd; k = n2->key; } /* decrease the count by one */ k->count --; /* merge the keys */ kl = k->left; kr = k->right; if (!kl->notice->isdummy && (kl->count + k->count) <= NLIM) { /* delete the left key */ k->count += kl->count; k->left = kl->left; k->left->right = k; kl->notice->key = NULL; free(kl); } else if (!k->notice->isdummy && (kr->count + k->count) <= NLIM) { /* delete this key */ kr->count += k->count; kr->left = k->left; kr->left->right = kr; k->notice->key = NULL; free(k); } } /* delete the match notice */ n->pred->sucd = n->sucd; n->sucd->pred = n->pred; /* update current */ if (n == curr) { n2 = n->sucd; while (n2 != NULL && n2->isdummy) { n2 = n2->sucd; } curr = n2; } free(n); } break; /* exit while loop */ } n = n->sucd; } (void) pthread_mutex_unlock(&el_mtx); return (0); } /* * **************************************************************************** * * el_first: * Fetch the first event from the element list. * * t - Pointer of time of the event for returning. * return - The event. * * **************************************************************************** */ void * el_first( uint32_t *t ) { void *p = NULL; el_notice_t *n; el_key_t *k; (void) pthread_mutex_lock(&el_mtx); if (curr != NULL) { /* remove current from the event set */ curr->pred->sucd = curr->sucd; curr->sucd->pred = curr->pred; /* decrease number of notice */ n = curr; while (n->key == NULL) { n = n->sucd; } k = n->key; k->count --; /* empty not-dummy key */ if (k->count == 0) { k->left->right = k->right; k->right->left = k->left; free(k); } /* get next notice */ n = curr->sucd; while (n != NULL && n->isdummy) { n = n->sucd; } /* return the time */ *t = curr->time; /* reset current notice */ p = curr->event; free(curr); curr = n; } /* the one that is being handled by esi_proc */ if (p) { evl_append(p); } (void) pthread_mutex_unlock(&el_mtx); if (p) { isnslog(LOG_DEBUG, "el_first", "%s [%d] is fetched.", ((ev_t *)p)->type == EV_ESI ? "ESI" : "REG_EXP", ((ev_t *)p)->uid); } return (p); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include "isns_server.h" #include "isns_msgq.h" #include "isns_cache.h" #include "isns_cfg.h" #include "isns_obj.h" #include "isns_dseng.h" #include "isns_log.h" #include "isns_scn.h" #include "isns_pdu.h" /* * global variables. */ /* * local variables. */ static scn_registry_t *scn_registry = NULL; static int scn_dispatched = 0; /* * external variables. */ extern uint8_t mgmt_scn; extern msg_queue_t *sys_q; extern msg_queue_t *scn_q; extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; #ifdef DEBUG extern void dump_pdu1(isns_pdu_t *); #endif static int sf_gen(scn_raw_t *); static int sf_error(scn_raw_t *); static scn_raw_t *make_raw_entity(isns_obj_t *); static scn_raw_t *make_raw_iscsi(isns_obj_t *); static scn_raw_t *make_raw_portal(isns_obj_t *); static scn_raw_t *make_raw_assoc_iscsi(isns_obj_t *); static scn_raw_t *make_raw_assoc_dd(isns_obj_t *); static scn_raw_t *(*const make_raw[MAX_OBJ_TYPE_FOR_SIZE])(isns_obj_t *) = { NULL, &make_raw_entity, &make_raw_iscsi, &make_raw_portal, NULL, /* OBJ_PG */ NULL, /* OBJ_DD */ NULL, /* OBJ_DDS */ NULL, /* MAX_OBJ_TYPE */ NULL, /* OBJ_DUMMY1 */ NULL, /* OBJ_DUMMY2 */ NULL, /* OBJ_DUMMY3 */ NULL, /* OBJ_DUMMY4 */ &make_raw_assoc_iscsi, &make_raw_assoc_dd }; static scn_text_t *scn_gen_entity(scn_raw_t *); static scn_text_t *scn_gen_iscsi(scn_raw_t *); static scn_text_t *scn_gen_portal(scn_raw_t *); static scn_text_t *scn_gen_assoc_dd(scn_raw_t *); static scn_text_t *(*const scn_gen[MAX_OBJ_TYPE_FOR_SIZE])(scn_raw_t *) = { NULL, &scn_gen_entity, &scn_gen_iscsi, &scn_gen_portal, NULL, /* OBJ_PG */ NULL, /* OBJ_DD */ NULL, /* OBJ_DDS */ NULL, /* MAX_OBJ_TYPE */ NULL, /* OBJ_DUMMY1 */ NULL, /* OBJ_DUMMY2 */ NULL, /* OBJ_DUMMY3 */ NULL, /* OBJ_DUMMY4 */ &scn_gen_iscsi, &scn_gen_assoc_dd }; #define SCN_TEST(E, BITMAP, UID1, UID2, NT) \ (((E) & (BITMAP)) && \ (!((BITMAP) & (ISNS_INIT_SELF_INFO_ONLY | \ ISNS_TARGET_SELF_INFO_ONLY)) || \ ((UID1) == (UID2)) || \ (((BITMAP) & ISNS_INIT_SELF_INFO_ONLY) && \ ((NT) & ISNS_INITIATOR_NODE_TYPE)) || \ (((BITMAP) & ISNS_TARGET_SELF_INFO_ONLY) && \ ((NT) & ISNS_TARGET_NODE_TYPE)))) /* * local functions. */ /* * **************************************************************************** * * free_portal_1: * Free one SCN portal or decrease the reference count if the portal * is referenced by other SCN entry(s). * * p - the portal. * * **************************************************************************** */ static void free_portal_1( scn_portal_t *p ) { if (p->ref <= 1) { if (p->sz == sizeof (in6_addr_t)) { free(p->ip.in6); } free(p); } else { p->ref --; } } /* * **************************************************************************** * * free_portal: * Free the unused portals, which are extracted for new SCN entry, * after the new SCN entry is added. * * p - the portal. * * **************************************************************************** */ static void free_portal( scn_portal_t *p ) { scn_portal_t *n; while (p != NULL) { n = p->next; free_portal_1(p); p = n; } } /* * **************************************************************************** * * free_portal_list: * Free the list of portals while a SCN entry is being destroyed. * * l - the portal list. * * **************************************************************************** */ static void free_portal_list( scn_list_t *l ) { scn_list_t *n; scn_portal_t *p; while (l != NULL) { n = l->next; p = l->data.portal; free_portal_1(p); free(l); l = n; } } /* * **************************************************************************** * * free_scn_text: * Free one SCN or decrease the ref count after the SCN is emitted. * * text - the SCN. * * **************************************************************************** */ static void free_scn_text( scn_text_t *text ) { if (text->ref <= 1) { free(text->iscsi); free(text); } else { text->ref --; } } /* * **************************************************************************** * * free_scn_list: * Free the the list of SCN. * * scn - the list. * * **************************************************************************** */ static void free_scn_list( scn_t *scn ) { scn_t *next_scn; scn_list_t *list; scn_list_t *next_list; while (scn != NULL) { next_scn = scn->next; list = scn->data.list; while (list != NULL) { next_list = list->next; free_scn_text(list->data.text); free(list); list = next_list; } free(scn); scn = next_scn; } } /* * **************************************************************************** * * free_scn: * Free all of SCNs which are dispatched to every entry. * * **************************************************************************** */ static void free_scn( ) { scn_registry_t *p; p = scn_registry; while (p != NULL) { free_scn_list(p->scn); p->scn = NULL; p = p->next; } } /* * **************************************************************************** * * free_entry: * Free one SCN entry. * * e - the SCN entry. * * **************************************************************************** */ static void free_entry( scn_registry_t *e ) { free_scn_list(e->scn); free_portal_list(e->portal.l); free(e->name); free(e); } /* * **************************************************************************** * * free_raw: * Free the raw data after the SCN is generated from it. * * raw - the raw SCN data. * * **************************************************************************** */ static void free_raw( scn_raw_t *raw ) { if (raw->ref == 0) { free(raw->iscsi); } if (raw->ip != NULL) { free(raw->ip); } free(raw); } /* * **************************************************************************** * * scn_add_portal: * Add portals to the portal list of a SCN entry. * * e - the SCN entry. * p - the portals. * return - 0: successful, otherwise failed. * * **************************************************************************** */ static int scn_add_portal( scn_registry_t *e, scn_portal_t *p ) { scn_portal_t *x; scn_list_t *l, *m; scn_list_t **lp; int found_it; lp = &e->portal.l; while (p != NULL) { m = (scn_list_t *)malloc(sizeof (scn_list_t)); if (m == NULL) { return (1); } found_it = 0; e = scn_registry; while (e && !found_it) { l = e->portal.l; while (l && !found_it) { x = l->data.portal; if (x->uid == p->uid) { found_it = 1; } l = l->next; } e = e->next; } if (!found_it) { x = p; } m->data.portal = x; x->ref ++; m->next = *lp; *lp = m; p = p->next; } return (0); } /* * **************************************************************************** * * scn_remove_portal: * Remove a portal from the portal list of every SCN entry. * * uid - the portal object uid. * return - always successful (0). * * **************************************************************************** */ static int scn_remove_portal( uint32_t uid ) { scn_registry_t **ep, *e; scn_portal_t *x; scn_list_t **lp, *l; ep = &scn_registry; e = *ep; while (e != NULL) { lp = &e->portal.l; l = *lp; while (l != NULL) { x = l->data.portal; if (x->uid == uid) { /* remove it */ *lp = l->next; free_portal_1(x); free(l); } else { lp = &l->next; } l = *lp; } if (e->portal.l == NULL) { /* no portal for this entry, destroy it */ *ep = e->next; free_entry(e); } else { ep = &e->next; } e = *ep; } return (0); } /* * **************************************************************************** * * scn_list_add: * Add one SCN entry to the SCN entry list. * * e - the SCN entry. * return - always successful (0). * * **************************************************************************** */ static int scn_list_add( scn_registry_t *e ) { scn_registry_t **pp; scn_portal_t *p; p = e->portal.p; e->portal.l = NULL; pp = &scn_registry; while (*pp) { if ((*pp)->uid == e->uid) { /* replace the bitmap */ (*pp)->bitmap = e->bitmap; free_portal(p); free_entry(e); return (0); } else if ((*pp)->uid < e->uid) { break; } pp = &(*pp)->next; } (void) scn_add_portal(e, p); if (e->portal.l != NULL || sys_q == NULL) { /* insert it to the list */ e->next = *pp; *pp = e; } else { /* no portal, ignore it */ free_entry(e); } /* free the unused portal(s) */ free_portal(p); return (0); } /* * **************************************************************************** * * scn_list_remove: * Remove one SCN entry from the SCN entry list. * * uid - the SCN entry unique ID. * return - always successful (0). * * **************************************************************************** */ static int scn_list_remove( uint32_t uid ) { scn_registry_t **ep, *e; ep = &scn_registry; e = *ep; while (e) { if (e->uid == uid) { /* destroy it */ *ep = e->next; free_entry(e); break; } else if (e->uid < uid) { break; } ep = &e->next; e = *ep; } return (0); } /* * **************************************************************************** * * cb_get_scn_port: * The callback function which returns the SCN port of a portal object. * * p1 - the portal object. * p2 - the lookup control data. * return - the SCN port number. * * **************************************************************************** */ static int cb_get_scn_port( void *p1, /*ARGSUSED*/ void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; isns_attr_t *attr = &obj->attrs[ ATTR_INDEX_PORTAL(ISNS_SCN_PORT_ATTR_ID)]; int port = 0; if (attr->tag != 0 && attr->value.ui != 0) { port = (int)attr->value.ui; } return (port); } /* * **************************************************************************** * * new_scn_portal: * Make a new SCN portal. * * ref - the ref count. * uid - the portal object UID. * ip - the ip address. * port - the port number. * return - the SCN portal. * * **************************************************************************** */ static scn_portal_t * new_scn_portal( uint32_t ref, uint32_t uid, in6_addr_t *ip, uint32_t port ) { scn_portal_t *p; p = (scn_portal_t *)malloc(sizeof (scn_portal_t)); if (p != NULL) { p->uid = uid; /* convert the ipv6 to ipv4 */ if (((int *)ip)[0] == 0x00 && ((int *)ip)[1] == 0x00 && ((uchar_t *)ip)[8] == 0x00 && ((uchar_t *)ip)[9] == 0x00 && ((uchar_t *)ip)[10] == 0xFF && ((uchar_t *)ip)[11] == 0xFF) { p->sz = sizeof (in_addr_t); p->ip.in = ((uint32_t *)ip)[3]; free(ip); } else { p->sz = sizeof (in6_addr_t); p->ip.in6 = ip; } p->port = port; p->ref = ref; p->so = 0; p->next = NULL; } return (p); } /* * **************************************************************************** * * extract scn_portal: * Extract the SCN portal(s) for a storage node. * * name - the storage node name. * return - the SCN portal list. * * **************************************************************************** */ static scn_portal_t * extract_scn_portal( uchar_t *name ) { scn_portal_t *list = NULL; scn_portal_t *p; lookup_ctrl_t lc_pg, lc_p; uint32_t pg_uid, uid; in6_addr_t *ip; uint32_t port; lc_pg.type = OBJ_PG; lc_pg.curr_uid = 0; lc_pg.id[0] = ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID); lc_pg.op[0] = OP_STRING; lc_pg.data[0].ptr = name; lc_pg.op[1] = 0; lc_pg.id[1] = ISNS_PG_PORTAL_IP_ADDR_ATTR_ID; lc_pg.id[2] = ISNS_PG_PORTAL_PORT_ATTR_ID; lc_p.type = OBJ_PORTAL; lc_p.curr_uid = 0; lc_p.id[0] = ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID); lc_p.op[0] = OP_MEMORY_IP6; lc_p.id[1] = ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID); lc_p.op[1] = OP_INTEGER; lc_p.op[2] = 0; while (cache_lookup(&lc_pg, &pg_uid, cb_clone_attrs) == 0 && pg_uid != 0) { ip = lc_pg.data[1].ip; port = lc_pg.data[2].ui; if (ip != NULL) { lc_p.data[0].ip = ip; lc_p.data[1].ui = port; port = cache_lookup(&lc_p, &uid, cb_get_scn_port); if (port != 0 && uid != 0) { /* ref starts from 1 */ p = new_scn_portal(1, uid, ip, port); if (p != NULL) { p->next = list; list = p; } else { free(ip); free(p); } } else { /* portal not registered or no scn port */ free(ip); } } lc_pg.curr_uid = pg_uid; } return (list); } /* * **************************************************************************** * * cb_update_scn_bitmap: * The callback function which updates the SCN Bitmap attribute of * a storage node object. * * p1 - the storage node object. * p2 - the lookup control data. * return - error code. * * **************************************************************************** */ static int cb_update_scn_bitmap( void *p1, void *p2 ) { int ec = 0; isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; int id = ATTR_INDEX_ISCSI(ISNS_ISCSI_SCN_BITMAP_ATTR_ID); isns_attr_t *attr = &obj->attrs[id]; uint32_t bitmap = lcp->data[2].ui; if (bitmap != 0) { attr->tag = ISNS_ISCSI_SCN_BITMAP_ATTR_ID; attr->len = 4; } else if (attr->tag == 0) { return (ec); } else { attr->tag = 0; attr->len = 0; } attr->value.ui = bitmap; if (sys_q != NULL) { ec = write_data(DATA_UPDATE, obj); } return (ec); } /* * **************************************************************************** * * cb_get_node_type: * The callback function which returns the node type attribute of * a storage node object. * * p1 - the storage node object. * p2 - the lookup control data. * return - error code. * * **************************************************************************** */ static int cb_get_node_type( void *p1, /* LINTED E_FUNC_ARG_UNUSED */ void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; isns_attr_t *attr = &obj->attrs[ ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)]; int nt = (int)attr->value.ui; return (nt); } /* * **************************************************************************** * * cb_get_node_type: * The callback function which returns the storage node object UID * from a portal group object. * * p1 - the pg object. * p2 - the lookup control data. * return - the storage node object UID. * * **************************************************************************** */ static int cb_pg_node( void *p1, /* LINTED E_FUNC_ARG_UNUSED */ void *p2 ) { uint32_t ref; ref = get_ref_t(p1, OBJ_ISCSI); return ((int)ref); } /* * **************************************************************************** * * make_raw_entity: * Make raw SCN data with a Network Entity object. * * obj - the network entity object. * return - the raw SCN data. * * **************************************************************************** */ static scn_raw_t * make_raw_entity( /*ARGSUSED*/ isns_obj_t *obj ) { scn_raw_t *raw; raw = (scn_raw_t *)malloc(sizeof (scn_raw_t)); if (raw != NULL) { raw->type = obj->type; raw->uid = get_obj_uid(obj); raw->iscsi = NULL; raw->ref = 0; raw->ilen = 0; raw->nt = 0; raw->ip = NULL; raw->dd_id = 0; raw->dds_id = 0; } else { isnslog(LOG_DEBUG, "make_raw_entity", "malloc failed."); } return (raw); } /* * **************************************************************************** * * make_raw_iscsi: * Make raw SCN data with a Storage Node object. * * obj - the storage node object. * return - the raw SCN data. * * **************************************************************************** */ static scn_raw_t * make_raw_iscsi( isns_obj_t *obj ) { uint32_t uid; uint32_t nt; uchar_t *iscsi; uint32_t ilen; isns_attr_t *attr; scn_raw_t *raw; uid = get_obj_uid(obj); attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)]; nt = attr->value.ui; attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)]; raw = (scn_raw_t *)malloc(sizeof (scn_raw_t)); ilen = attr->len; iscsi = (uchar_t *)malloc(ilen); if (raw != NULL && iscsi != NULL) { /* copy the iscsi storage node name */ (void) strcpy((char *)iscsi, (char *)attr->value.ptr); raw->type = obj->type; raw->uid = uid; raw->iscsi = iscsi; raw->ref = 0; raw->ilen = ilen; raw->nt = nt; raw->ip = NULL; raw->dd_id = 0; raw->dds_id = 0; } else { free(raw); free(iscsi); raw = NULL; isnslog(LOG_DEBUG, "make_raw_iscsi", "malloc failed."); } return (raw); } /* * **************************************************************************** * * make_raw_portal: * Make raw SCN data with a Portal object. * * obj - the portal object. * return - the raw SCN data. * * **************************************************************************** */ static scn_raw_t * make_raw_portal( isns_obj_t *obj ) { isns_attr_t *attr; in6_addr_t *ip; uint32_t port; scn_raw_t *raw; raw = (scn_raw_t *)malloc(sizeof (scn_raw_t)); ip = (in6_addr_t *)malloc(sizeof (in6_addr_t)); if (raw != NULL && ip != NULL) { attr = &obj->attrs[ ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID)]; (void) memcpy(ip, attr->value.ip, sizeof (in6_addr_t)); attr = &obj->attrs[ ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID)]; port = attr->value.ui; raw->type = obj->type; raw->uid = 0; raw->iscsi = NULL; raw->ref = 0; raw->ilen = 0; raw->nt = 0; raw->ip = ip; raw->port = port; raw->dd_id = 0; raw->dds_id = 0; } else { free(ip); free(raw); raw = NULL; isnslog(LOG_DEBUG, "make_raw_portal", "malloc failed."); } return (raw); } /* * **************************************************************************** * * make_raw_assoc_iscsi: * Make raw SCN data with a Discovery Domain member association. * * obj - the member association object. * return - the raw SCN data. * * **************************************************************************** */ static scn_raw_t * make_raw_assoc_iscsi( isns_obj_t *obj ) { uint32_t uid; uint32_t dd_id; uint32_t nt; lookup_ctrl_t lc; isns_attr_t *attr; scn_raw_t *raw; uchar_t *iscsi; uint32_t ilen; uid = get_obj_uid(obj); dd_id = get_parent_uid(obj); SET_UID_LCP(&lc, OBJ_ISCSI, uid); nt = cache_lookup(&lc, NULL, cb_get_node_type); attr = &obj->attrs[ATTR_INDEX_ASSOC_ISCSI(ISNS_DD_ISCSI_NAME_ATTR_ID)]; raw = (scn_raw_t *)malloc(sizeof (scn_raw_t)); ilen = attr->len; iscsi = (uchar_t *)malloc(ilen); if (raw != NULL && iscsi != NULL) { /* copy the iscsi storage node name */ (void) strcpy((char *)iscsi, (char *)attr->value.ptr); raw->type = obj->type; raw->uid = uid; raw->iscsi = iscsi; raw->ref = 0; raw->ilen = ilen; raw->nt = nt; raw->ip = NULL; raw->dd_id = dd_id; raw->dds_id = 0; } else { free(raw); free(iscsi); raw = NULL; isnslog(LOG_DEBUG, "make_raw_assoc_iscsi", "malloc failed."); } return (raw); } /* * **************************************************************************** * * make_raw_assoc_dd: * Make raw SCN data with a Discovery Domain Set member association. * * obj - the member association object. * return - the raw SCN data. * * **************************************************************************** */ static scn_raw_t * make_raw_assoc_dd( isns_obj_t *obj ) { scn_raw_t *raw; raw = (scn_raw_t *)malloc(sizeof (scn_raw_t)); if (raw != NULL) { raw->type = obj->type; raw->uid = 0; raw->iscsi = NULL; raw->ref = 0; raw->ilen = 0; raw->nt = 0; raw->ip = NULL; raw->dd_id = get_obj_uid(obj); raw->dds_id = get_parent_uid(obj); } else { isnslog(LOG_DEBUG, "make_raw_assoc_dd", "malloc failed."); } return (raw); } /* * **************************************************************************** * * scn_gen_entity: * Generate SCN with the raw SCN data from a Network Entity object. * * raw - the raw SCN data. * return - the SCN. * * **************************************************************************** */ static scn_text_t * scn_gen_entity( /* LINTED E_FUNC_ARG_UNUSED */ scn_raw_t *raw ) { return (NULL); } /* * **************************************************************************** * * scn_gen_iscsi: * Generate SCN with the raw SCN data from a Storage Node object. * * raw - the raw SCN data. * return - the SCN. * * **************************************************************************** */ static scn_text_t * scn_gen_iscsi( scn_raw_t *raw ) { scn_text_t *text; text = (scn_text_t *)malloc(sizeof (scn_text_t)); if (text != NULL) { text->flag = 0; text->ref = 1; /* start with 1 */ text->uid = raw->uid; text->iscsi = raw->iscsi; raw->ref ++; text->ilen = raw->ilen; text->nt = raw->nt; text->dd_id = raw->dd_id; text->dds_id = raw->dds_id; text->next = NULL; } else { isnslog(LOG_DEBUG, "scn_gen_iscsi", "malloc failed."); } return (text); } /* * **************************************************************************** * * scn_gen_portal: * Generate SCN with the raw SCN data from a Portal object. * * raw - the raw SCN data. * return - the SCN. * * **************************************************************************** */ static scn_text_t * scn_gen_portal( scn_raw_t *raw ) { in6_addr_t *ip; uint32_t port; uint32_t pg_uid, uid; lookup_ctrl_t pg_lc, lc; uint32_t nt; uchar_t *name; int ilen; scn_text_t *text, *l = NULL; ip = raw->ip; port = raw->port; pg_lc.curr_uid = 0; pg_lc.type = OBJ_PG; pg_lc.id[0] = ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID); pg_lc.op[0] = OP_MEMORY_IP6; pg_lc.data[0].ip = ip; pg_lc.id[1] = ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID); pg_lc.op[1] = OP_INTEGER; pg_lc.data[1].ui = port; pg_lc.op[2] = 0; SET_UID_LCP(&lc, OBJ_ISCSI, 0); lc.id[1] = ISNS_ISCSI_NAME_ATTR_ID; lc.id[2] = ISNS_ISCSI_NODE_TYPE_ATTR_ID; lc.data[1].ptr = NULL; /* get a pg which is associated to the portal */ uid = cache_lookup(&pg_lc, &pg_uid, cb_pg_node); while (pg_uid != 0) { if (uid != 0) { lc.data[0].ui = uid; (void) cache_lookup(&lc, NULL, cb_clone_attrs); name = lc.data[1].ptr; if (name != NULL) { nt = lc.data[2].ui; text = (scn_text_t *)malloc( sizeof (scn_text_t)); if (text != NULL) { text->flag = 0; text->ref = 1; /* start with 1 */ text->uid = uid; text->iscsi = name; ilen = strlen((char *)name); ilen += 4 - (ilen % 4); text->ilen = ilen; text->nt = nt; text->dd_id = 0; text->dds_id = 0; text->next = l; l = text; } else { free(name); isnslog(LOG_DEBUG, "scn_gen_portal", "malloc failed."); } lc.data[1].ptr = NULL; } else { isnslog(LOG_WARNING, "scn_gen_portal", "cannot get node name."); } } /* get the next pg */ pg_lc.curr_uid = pg_uid; uid = cache_lookup(&pg_lc, &pg_uid, cb_pg_node); } /* update the iscsi storage node object */ raw->event = ISNS_OBJECT_UPDATED; return (l); } /* * **************************************************************************** * * scn_gen_assoc_dd: * Generate SCN with the raw SCN data from a DD membership object. * * raw - the raw SCN data. * return - the SCN. * * **************************************************************************** */ static scn_text_t * scn_gen_assoc_dd( /* LINTED E_FUNC_ARG_UNUSED */ scn_raw_t *raw ) { return (NULL); } /* * **************************************************************************** * * make_scn: * Make a SCN with an event and an object. * * event - the event. * obj - the object. * return - always successful (0). * * **************************************************************************** */ int make_scn( uint32_t event, isns_obj_t *obj ) { scn_raw_t *raw = NULL; scn_raw_t *(*f)(isns_obj_t *) = make_raw[obj->type]; if (f != NULL) { /* make raw scn data */ raw = f(obj); } if (raw != NULL) { /* trigger an scn event */ raw->event = event; (void) queue_msg_set(scn_q, SCN_SET, (void *)raw); } return (0); } /* * data structure of the SCN state transition table. */ typedef struct scn_tbl { int state; uint32_t event; isns_type_t type; int (*sf)(scn_raw_t *); int next_state; } scn_tbl_t; /* * the SCN state transition table. */ static const scn_tbl_t stbl[] = { { -1, 0, OBJ_PG, NULL, 0 }, { -1, 0, OBJ_DD, NULL, 0 }, { -1, 0, OBJ_DDS, NULL, 0 }, { 0, ISNS_OBJECT_ADDED, OBJ_ENTITY, NULL, 1 }, { 1, ISNS_OBJECT_ADDED, OBJ_ISCSI, sf_gen, 1 }, { 1, ISNS_OBJECT_ADDED, 0, NULL, 1 }, { 0, ISNS_OBJECT_UPDATED, OBJ_ENTITY, sf_gen, 2 }, { 2, ISNS_OBJECT_UPDATED, 0, NULL, 2 }, { 2, ISNS_OBJECT_ADDED, OBJ_ISCSI, sf_gen, 2 }, { 2, ISNS_OBJECT_ADDED, 0, NULL, 2 }, { 0, ISNS_OBJECT_REMOVED, OBJ_ENTITY, NULL, 3 }, { 0, ISNS_OBJECT_REMOVED, 0, sf_gen, 4 }, { 3, ISNS_OBJECT_REMOVED, OBJ_ISCSI, sf_gen, 3 }, { 3, ISNS_OBJECT_REMOVED, 0, NULL, 3 }, { 4, ISNS_OBJECT_REMOVED, 0, sf_gen, 4 }, { 0, ISNS_MEMBER_ADDED, OBJ_ASSOC_ISCSI, sf_gen, 5 }, { 5, ISNS_MEMBER_ADDED, OBJ_ASSOC_ISCSI, sf_gen, 5 }, { 0, ISNS_MEMBER_ADDED, OBJ_ASSOC_DD, sf_gen, 6 }, { 6, ISNS_MEMBER_ADDED, OBJ_ASSOC_DD, sf_gen, 6 }, { 0, ISNS_MEMBER_REMOVED, OBJ_ASSOC_ISCSI, sf_gen, 7 }, { 7, ISNS_MEMBER_REMOVED, OBJ_ASSOC_ISCSI, sf_gen, 7 }, { 0, ISNS_MEMBER_REMOVED, OBJ_ASSOC_DD, sf_gen, 8 }, { 8, ISNS_MEMBER_REMOVED, OBJ_ASSOC_DD, sf_gen, 8 }, { -1, 0, 0, sf_error, -1 } }; /* * **************************************************************************** * * scn_disp1: * Dispatch one SCN to one SCN entry. * * event - the event. * p - the SCN entry. * t - the SCN. * return - always successful (0). * * **************************************************************************** */ static int scn_disp1( uint32_t event, scn_registry_t *p, scn_text_t *t ) { scn_t *s, *r = NULL; scn_list_t *l, **lp; s = p->scn; while (s != NULL) { if (s->event == event) { l = s->data.list; do { if (l->data.text->uid == t->uid) { /* duplicated */ return (0); } lp = &l->next; l = *lp; } while (l != NULL); break; } r = s; s = s->next; } l = (scn_list_t *)malloc(sizeof (scn_list_t)); if (l != NULL) { if (s == NULL) { s = (scn_t *)malloc(sizeof (scn_t)); if (s != NULL) { s->event = event; s->next = NULL; if (r != NULL) { r->next = s; } else { p->scn = s; } lp = &s->data.list; } else { free(l); isnslog(LOG_DEBUG, "scn_disp1", "malloc scn failed.\n"); return (0); } } t->ref ++; l->data.text = t; l->next = NULL; *lp = l; } else { isnslog(LOG_DEBUG, "scn_disp1", "malloc list failed.\n"); } return (0); } /* * **************************************************************************** * * scn_disp1: * Dispatch one SCN to every SCN entry and update the dispatch status. * * event - the event. * text - the SCN. * return - always successful (0). * * **************************************************************************** */ static int scn_disp( uint32_t event, scn_text_t *text ) { scn_registry_t *registry, *p; uint32_t dd_id = 0; scn_text_t *t; uint32_t e; registry = scn_registry; t = text; while (t != NULL) { e = event; if (t->flag == 0) { if (e & ISNS_MEMBER_ADDED) { e |= ISNS_OBJECT_ADDED; } else if (e & ISNS_MEMBER_REMOVED) { e |= ISNS_OBJECT_REMOVED; } } p = registry; while (p != NULL) { if (SCN_TEST(e, p->bitmap, p->uid, t->uid, t->nt)) { if (p->bitmap & ISNS_MGMT_REG) { /* management scn are not bound */ /* by discovery domain service. */ dd_id = 1; } else { dd_id = 0; /* lock the cache for reading */ (void) cache_lock_read(); /* verify common dd */ do { dd_id = get_common_dd( p->uid, t->uid, dd_id); } while (dd_id > 0 && is_dd_active(dd_id) == 0); /* unlock the cache */ (void) cache_unlock_nosync(); } if (dd_id != 0) { (void) scn_disp1(e, p, t); } } p = p->next; } t = t->next; } while (text != NULL) { t = text->next; /* clean up the scn text(s) which nobody cares about. */ free_scn_text(text); text = t; } if (dd_id != 0) { /* scn(s) are dispatched. */ scn_dispatched = 1; } return (0); } /* * **************************************************************************** * * sf_gen: * State transition function which generates and dispatches SCN(s). * * raw - the raw SCN data. * return - always successful (0). * * **************************************************************************** */ static int sf_gen( scn_raw_t *raw ) { uint32_t event; scn_text_t *(*gen)(scn_raw_t *); scn_text_t *text = NULL; gen = scn_gen[raw->type]; if (gen != NULL) { text = gen(raw); } event = raw->event; if (text != NULL) { (void) scn_disp(event, text); } return (0); } /* * **************************************************************************** * * sf_error: * State transition function for an error state. It free any SCN(s) * which have been generated and dispatched previously. * * raw - the raw SCN data. * return - always successful (0). * * **************************************************************************** */ static int sf_error( /* LINTED E_FUNC_ARG_UNUSED */ scn_raw_t *raw ) { free_scn(); return (0); } /* * **************************************************************************** * * scn_transition: * Performs the state transition when a SCN event occurs. * * state - the previous state. * raw - the raw SCN data. * return - the next state. * * **************************************************************************** */ static int scn_transition( int state, scn_raw_t *raw ) { uint32_t event = raw->event; isns_type_t type = raw->type; int new_state = state; const scn_tbl_t *tbl; tbl = &stbl[0]; for (;;) { if ((tbl->state == -1 || tbl->state == state) && (tbl->event == 0 || tbl->event == event) && (tbl->type == 0 || tbl->type == type)) { if (tbl->next_state != 0) { new_state = tbl->next_state; } if (tbl->sf != NULL) { tbl->sf(raw); } break; } tbl ++; } if (new_state == -1) { isnslog(LOG_DEBUG, "scn_transition", "prev state: %d new event: 0x%x new object: %d.\n", state, event, type); new_state = 0; } state = new_state; return (state); } /* * **************************************************************************** * * connect_to: * Create socket connection with peer network portal. * * sz - the size of the ip addr. * in - the ipv4 address. * in6 - the ipv6 address. * port2- the port info. * return - the socket descriptor. * * **************************************************************************** */ int connect_to( int sz, in_addr_t in, /* LINTED E_FUNC_ARG_UNUSED */ in6_addr_t *in6, uint32_t port2 ) { int so = -1; union { struct sockaddr sin; struct sockaddr_in in; struct sockaddr_in6 in6; } ca = { 0 }; int tcp; uint16_t port; tcp = (port2 & 0x10000) == 0 ? 1 : 0; port = (uint16_t)(port2 & 0xFFFF); if (sz == sizeof (in_addr_t)) { if (tcp != 0) { so = socket(AF_INET, SOCK_STREAM, 0); if (so != -1) { ca.in.sin_family = AF_INET; ca.in.sin_port = htons(port); ca.in.sin_addr.s_addr = in; if (connect(so, &ca.sin, sizeof (ca.in)) != 0) { isnslog(LOG_DEBUG, "connect_to", "connect() failed %%m."); (void) close(so); so = -1; } } else { isnslog(LOG_DEBUG, "connect_to", "socket() failed %%m."); } } else { /* FIXME: UDP support */ isnslog(LOG_DEBUG, "connect_to", "No UDP support."); } } else { /* FIXME: IPv6 support */ isnslog(LOG_DEBUG, "connect_to", "No IPv6 support."); } return (so); } /* * **************************************************************************** * * emit_scn: * Emit the SCN to any portal of the peer storage node. * * list - the list of portal. * pdu - the SCN packet. * pl - the SCN packet payload length. * return - always successful (0). * * **************************************************************************** */ static int emit_scn( scn_list_t *list, isns_pdu_t *pdu, size_t pl ) { int so = 0; scn_list_t *l; scn_portal_t *p; isns_pdu_t *rsp = NULL; size_t rsp_sz; pdu->version = htons((uint16_t)ISNSP_VERSION); pdu->func_id = htons((uint16_t)ISNS_SCN); pdu->xid = htons(get_server_xid()); l = list; while (l != NULL) { p = l->data.portal; so = connect_to(p->sz, p->ip.in, p->ip.in6, p->port); if (so != -1) { if (isns_send_pdu(so, pdu, pl) == 0) { /* This may help Solaris iSCSI Initiator */ /* not to panic frequently. */ (void) isns_rcv_pdu(so, &rsp, &rsp_sz, ISNS_RCV_SHORT_TIMEOUT); } else { isnslog(LOG_DEBUG, "emit_scn", "sending packet failed."); } (void) close(so); /* p->so = so; */ break; } l = l->next; } if (rsp != NULL) { #ifdef DEBUG dump_pdu1(rsp); #endif free(rsp); } return (0); } /* * **************************************************************************** * * scn_trigger1: * Trigger one SCN for one SCN entry. * * t - the time that SCN is being triggered. * p - the SCN entry. * return - always successful (0). * * **************************************************************************** */ static int scn_trigger1( time_t t, scn_registry_t *p ) { int ec; isns_pdu_t *pdu = NULL; size_t sz; size_t pl; scn_t *s; scn_list_t *l; scn_text_t *x; union { uint32_t i32; uint64_t i64; } u; #ifdef DEBUG char buff[1024] = { 0 }; char *logbuff = buff; #endif ec = pdu_reset_scn(&pdu, &pl, &sz); if (pdu == NULL) { goto scn_done; } /* add destination attribute */ ec = pdu_add_tlv(&pdu, &pl, &sz, ISNS_ISCSI_NAME_ATTR_ID, p->nlen, (void *)p->name, 0); if (ec != 0) { goto scn_done; } #ifdef DEBUG sprintf(logbuff, "==>%s ", p->name); logbuff += strlen(logbuff); #endif /* add timestamp */ u.i64 = BE_64((uint64_t)t); ec = pdu_add_tlv(&pdu, &pl, &sz, ISNS_TIMESTAMP_ATTR_ID, 8, (void *)&u.i64, 1); s = p->scn; while (s != NULL && ec == 0) { u.i32 = htonl(s->event); ec = pdu_add_tlv(&pdu, &pl, &sz, ISNS_ISCSI_SCN_BITMAP_ATTR_ID, 4, (void *)&u.i32, 1); #ifdef DEBUG sprintf(logbuff, "EVENT [%d] ", s->event); logbuff += strlen(logbuff); #endif l = s->data.list; while (l != NULL && ec == 0) { x = l->data.text; if (x->flag == 0) { ec = pdu_add_tlv(&pdu, &pl, &sz, ISNS_ISCSI_NAME_ATTR_ID, x->ilen, (void *)x->iscsi, 0); #ifdef DEBUG sprintf(logbuff, "FROM [%s] ", x->iscsi); logbuff += strlen(logbuff); #endif if (ec == 0 && (p->bitmap & (ISNS_MEMBER_ADDED | ISNS_MEMBER_REMOVED))) { /* management SCN */ u.i32 = htonl(x->dd_id); ec = pdu_add_tlv(&pdu, &pl, &sz, ISNS_DD_ID_ATTR_ID, 4, (void *)&u.i32, 1); #ifdef DEBUG sprintf(logbuff, "IN DD [%d] ", x->dd_id); logbuff += strlen(logbuff); #endif } } else { /* add(remove) dd to(from) dd-set */ u.i32 = htonl(x->dd_id); ec = pdu_add_tlv(&pdu, &pl, &sz, ISNS_DD_ID_ATTR_ID, 4, (void *)&u.i32, 1); u.i32 = htonl(x->dds_id); if (ec == 0) { ec = pdu_add_tlv(&pdu, &pl, &sz, ISNS_DD_ID_ATTR_ID, 4, (void *)&u.i32, 1); } #ifdef DEBUG sprintf(logbuff, "FROM [%d] ", x->dd_id); logbuff += strlen(logbuff); sprintf(logbuff, "IN [%d] ", x->dds_id); logbuff += strlen(logbuff); #endif } l = l->next; } s = s->next; } scn_done: if (ec == 0) { #ifdef DEBUG isnslog(LOG_DEBUG, "scn_trigger1", buff); #endif ec = emit_scn(p->portal.l, pdu, pl); } else { isnslog(LOG_DEBUG, "scn_trigger1", " failed.\n"); } free(pdu); return (0); } /* * **************************************************************************** * * scn_trigger: * Trigger one SCN for every SCN entry. * * return - always successful (0). * * **************************************************************************** */ static int scn_trigger( ) { time_t t; scn_registry_t *p; t = time(NULL); p = scn_registry; while (p != NULL) { if (p->scn != NULL) { (void) scn_trigger1(t, p); } p = p->next; } return (0); } /* * global functions. */ /* * **************************************************************************** * * scn_list_load: * Load one SCN entry and add it to the SCN entry list. * * uid - the Storage Node object UID. * node - the Storage Node name. * nlen - the length of the name. * bitmap - the SCN bitmap. * return - error code. * * **************************************************************************** */ int scn_list_load( uint32_t uid, uchar_t *node, uint32_t nlen, uint32_t bitmap ) { int ec = 0; scn_registry_t *list; uchar_t *name; list = (scn_registry_t *)malloc(sizeof (scn_registry_t)); name = (uchar_t *)malloc(nlen); if (list != NULL && name != NULL) { list->uid = uid; (void) strcpy((char *)name, (char *)node); list->name = name; list->nlen = nlen; list->bitmap = bitmap; list->portal.l = NULL; list->scn = NULL; list->next = NULL; ASSERT(scn_q == NULL); (void) scn_list_add(list); } else { free(list); free(name); ec = ISNS_RSP_INTERNAL_ERROR; } return (ec); } /* * **************************************************************************** * * verify_scn_portal: * Extract and verify portals for every SCN entry(s) after they are * loaded from data store, for those which do not have a SCN portal, * remove it from the SCN entry list. * * return - 1: error occurs, otherwise 0. * * **************************************************************************** */ int verify_scn_portal( ) { scn_registry_t **pp, *e; scn_portal_t *p; pp = &scn_registry; while (*pp != NULL) { e = *pp; p = extract_scn_portal(e->name); if (p != NULL) { if (scn_add_portal(e, p) != 0) { return (1); } } if (e->portal.l != NULL) { pp = &e->next; } else { /* remove this entry */ *pp = e->next; free_entry(e); } /* free the unused portal(s) */ free_portal(p); } return (0); } /* * **************************************************************************** * * add_scn_entry: * Add a SCN entry. * * node - the Storage Node name. * nlen - the length of the name. * bitmap - the SCN bitmap. * return - error code. * * **************************************************************************** */ int add_scn_entry( uchar_t *node, uint32_t nlen, uint32_t bitmap ) { int ec = 0; uint32_t mgmt; scn_portal_t *p; lookup_ctrl_t lc; uint32_t uid; scn_registry_t *e; uchar_t *name; mgmt = bitmap & ( ISNS_MGMT_REG | ISNS_MEMBER_REMOVED | ISNS_MEMBER_ADDED); if ((mgmt > 0 && (mgmt_scn == 0 || mgmt < ISNS_MGMT_REG || is_control_node(node) == 0)) || (p = extract_scn_portal(node)) == NULL) { return (ISNS_RSP_SCN_REGIS_REJECTED); } e = (scn_registry_t *)malloc(sizeof (scn_registry_t)); name = (uchar_t *)malloc(nlen); if (e != NULL && name != NULL) { lc.type = OBJ_ISCSI; lc.curr_uid = 0; lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); lc.data[0].ptr = node; lc.op[0] = OP_STRING; lc.op[1] = 0; lc.data[2].ui = bitmap; ec = cache_lookup(&lc, &uid, cb_update_scn_bitmap); if (uid == 0) { ec = ISNS_RSP_SCN_REGIS_REJECTED; } if (ec == 0) { e->uid = uid; (void) strcpy((char *)name, (char *)node); e->name = name; e->nlen = nlen; e->bitmap = bitmap; e->portal.p = p; e->scn = NULL; e->next = NULL; (void) queue_msg_set(scn_q, SCN_ADD, (void *)e); } } else { ec = ISNS_RSP_INTERNAL_ERROR; } if (ec != 0) { free(e); free(name); free_portal(p); } return (ec); } /* * **************************************************************************** * * remove_scn_entry: * Remove a SCN entry. * * node - the Storage Node name. * return - error code. * * **************************************************************************** */ int remove_scn_entry( uchar_t *node ) { int ec = 0; lookup_ctrl_t lc; uint32_t uid; lc.type = OBJ_ISCSI; lc.curr_uid = 0; lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); lc.data[0].ptr = node; lc.op[0] = OP_STRING; lc.op[1] = 0; lc.data[2].ui = 0; ec = cache_lookup(&lc, &uid, cb_update_scn_bitmap); if (ec == 0 && uid != 0) { (void) queue_msg_set(scn_q, SCN_REMOVE, (void *)uid); } return (ec); } /* * **************************************************************************** * * remove_scn_portal: * Remove a portal from every SCN entry. * * uid - the Portal object UID. * return - alrays successful (0). * * **************************************************************************** */ int remove_scn_portal( uint32_t uid ) { (void) queue_msg_set(scn_q, SCN_REMOVE_P, (void *)uid); return (0); } /* * **************************************************************************** * * scn_proc: * The entry point of the SCN thread. It listens on the SCN message * queue and process every SCN related stuff. * * arg - nothing. * return - NULL. * * **************************************************************************** */ void * scn_proc( /* LINTED E_FUNC_ARG_UNUSED */ void *arg ) { int state = 0; scn_raw_t *raw; msg_text_t *msg; for (;;) { msg = queue_msg_get(scn_q); switch (msg->id) { case SCN_ADD: (void) scn_list_add((scn_registry_t *)msg->data); break; case SCN_REMOVE: (void) scn_list_remove((uint32_t)msg->data); break; case SCN_REMOVE_P: (void) scn_remove_portal((uint32_t)msg->data); break; case SCN_SET: raw = (scn_raw_t *)msg->data; state = scn_transition(state, raw); /* free the raw data */ free_raw(raw); break; case SCN_TRIGGER: if (scn_dispatched != 0) { (void) scn_trigger(); } /* FALLTHROUGH */ case SCN_IGNORE: /* clean the scn(s) */ free_scn(); /* reset the state */ state = 0; /* reset the scn_dispatched flag */ scn_dispatched = 0; break; case SCN_STOP: queue_msg_free(msg); return (NULL); default: break; } queue_msg_free(msg); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #include #endif #include "isns_server.h" #include "isns_cache.h" #include "isns_pdu.h" #include "isns_msgq.h" #include "isns_func.h" #include "isns_log.h" #include "isns_provider.h" /* external functions */ #ifdef DEBUG extern void dump_pdu1(isns_pdu_t *); extern int verbose_tc; #endif extern boolean_t time_to_exit; void * isns_connection( void *arg ) { int status = 0; conn_arg_t *conn; isns_pdu_t *pdu, *combined_pdu, *new_combined_pdu; uint8_t *payload_ptr; size_t pdu_sz; conn = (conn_arg_t *)arg; conn->out_packet.pdu = NULL; conn->out_packet.sz = 0; combined_pdu = NULL; pdu = NULL; while (status == 0 && time_to_exit == B_FALSE && isns_rcv_pdu(conn->so, &pdu, &pdu_sz, ISNS_RCV_TIMEOUT) > 0) { uint16_t flags = pdu->flags; if (ISNS_MSG_RECEIVED_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_MSG_RECEIVED((uintptr_t)buf); } if ((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) { if (combined_pdu != NULL || pdu->seq != 0) { goto conn_done; } combined_pdu = pdu; pdu = NULL; } else { if (combined_pdu == NULL || combined_pdu->func_id != pdu->func_id || combined_pdu->xid != pdu->xid || (combined_pdu->seq + 1) != pdu->seq) { /* expect the first pdu, the same tranx id */ /* and the next sequence id */ goto conn_done; } new_combined_pdu = (isns_pdu_t *)malloc( ISNSP_HEADER_SIZE + combined_pdu->payload_len + pdu->payload_len); if (new_combined_pdu == NULL) { goto conn_done; } (void) memcpy((void *)new_combined_pdu, (void *)combined_pdu, ISNSP_HEADER_SIZE + combined_pdu->payload_len); payload_ptr = new_combined_pdu->payload + combined_pdu->payload_len; (void) memcpy((void *)payload_ptr, (void *)pdu->payload, pdu->payload_len); new_combined_pdu->seq = pdu->seq; free(combined_pdu); combined_pdu = new_combined_pdu; free(pdu); pdu = NULL; } if ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU) { #ifdef DEBUG time_t t; clock_t c; dump_pdu1(combined_pdu); if (verbose_tc != 0) { t = time(NULL); c = clock(); } #endif conn->in_packet.pdu = combined_pdu; conn->out_packet.pl = 0; conn->ec = 0; if (packet_split_verify(conn) == 0) { (void) cache_lock(conn->lock); status = conn->handler(conn); conn->ec = cache_unlock(conn->lock, conn->ec); } switch (status) { case -1: /* error */ break; case 0: status = isns_response(conn); isnslog(LOG_DEBUG, "isns_connection", "Response status: %d.", status); if (ISNS_MSG_RESPONDED_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_MSG_RESPONDED((uintptr_t)buf); } break; default: /* no need to send response message */ status = 0; break; } #ifdef DEBUG if (verbose_tc != 0) { t = time(NULL) - t; c = clock() - c; printf("time %d clock %.4lf -msg response\n", t, c / (double)CLOCKS_PER_SEC); } #endif free(combined_pdu); combined_pdu = NULL; } } conn_done: if (pdu != NULL) { free(pdu); } if (combined_pdu != NULL) { free(combined_pdu); } (void) close(conn->so); (void) free(conn->out_packet.pdu); (void) free(conn); /* decrease the thread ref count */ dec_thr_count(); return (NULL); } /* the iSNS server port watcher */ void * isns_port_watcher( /* LINTED E_FUNC_ARG_UNUSED */ void *arg ) { int s, f; int opt = 1; struct sockaddr_in sin; struct sockaddr_in *sinp; struct sockaddr_storage *ssp; socklen_t sslen; char buf[INET6_ADDRSTRLEN]; pthread_t tid; struct pollfd fds; int poll_ret; conn_arg_t *conn; if ((s = socket(AF_INET, SOCK_STREAM, 0)) != -1) { /* IPv4 */ isnslog(LOG_DEBUG, "isns_port_watcher", "IPv4 socket created."); (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof (opt)); sin.sin_family = AF_INET; sin.sin_port = htons(ISNS_DEFAULT_SERVER_PORT); sin.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { isnslog(LOG_DEBUG, "isns_port_watcher", "binding on server port failed: %%m"); goto watch_failed; } isnslog(LOG_DEBUG, "isns_port_watcher", "successful binding on server port."); } else { isnslog(LOG_DEBUG, "isns_port_watcher", "cannot create socket: %%m."); goto watch_failed; } if (listen(s, 5) < 0) { isnslog(LOG_DEBUG, "isns_port_watcher", "listening on server port failed: %%m."); goto watch_failed; } isnslog(LOG_DEBUG, "isns_port_watcher", "listening on server port ok."); fds.fd = s; fds.events = (POLLIN | POLLRDNORM); fds.revents = 0; /* waiting for connections */ for (;;) { if (time_to_exit) { return (NULL); } poll_ret = poll(&fds, 1, 1000); if (poll_ret <= 0) { continue; } /* allocate a connection argument */ conn = (conn_arg_t *)malloc(sizeof (conn_arg_t)); if (conn == NULL) { isnslog(LOG_DEBUG, "isns_port_watcher", "malloc() failed."); goto watch_failed; } ssp = &conn->ss; sslen = sizeof (conn->ss); f = accept(s, (struct sockaddr *)ssp, &sslen); if (f < 0) { isnslog(LOG_DEBUG, "isns_port_watcher", "accepting connection failed: %%m."); goto watch_failed; } 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)); } isnslog(LOG_DEBUG, "isns_port_watcher", "connection from %s:%d.", buf, sinp->sin_port); if (ISNS_CONNECTION_ACCEPTED_ENABLED()) { ISNS_CONNECTION_ACCEPTED((uintptr_t)buf); } conn->so = f; /* create an isns connection */ if (pthread_create(&tid, NULL, isns_connection, (void *)conn) != 0) { (void) close(f); (void) free(conn); isnslog(LOG_DEBUG, "isns_port_watcher", "pthread_create() failed."); } else { /* increase the thread ref count */ inc_thr_count(); } } watch_failed: shutdown_server(); return (NULL); } static uint16_t xid = 0; static pthread_mutex_t xid_mtx = PTHREAD_MUTEX_INITIALIZER; uint16_t get_server_xid( ) { uint16_t tmp; (void) pthread_mutex_lock(&xid_mtx); tmp = ++ xid; (void) pthread_mutex_unlock(&xid_mtx); return (tmp); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "isns_utils.h" #include "isns_protocol.h" char * result_code_to_str(int code) { switch (code) { case ISNS_RSP_SUCCESSFUL: return ((char *)gettext("Successful Operation")); case ISNS_RSP_UNKNOWN_ERROR: return ((char *)gettext("Unknown Error")); case ISNS_RSP_MSG_FORMAT_ERROR: return ((char *)gettext("Message Format Error")); case ISNS_RSP_INVALID_REGIS: return ((char *)gettext("Invalid Registration")); case ISNS_RSP_INVALID_QRY: return ((char *)gettext("Invalid Query")); case ISNS_RSP_SRC_UNKNOWN: return ((char *)gettext("Source Unknown")); case ISNS_RSP_SRC_ABSENT: return ((char *)gettext("Source Absent")); case ISNS_RSP_SRC_UNAUTHORIZED: return ((char *)gettext("Source Unauthorized")); case ISNS_RSP_NO_SUCH_ENTRY: return ((char *)gettext("No Such Entry")); case ISNS_RSP_VER_NOT_SUPPORTED: return ((char *)gettext("Version Not Supported")); case ISNS_RSP_INTERNAL_ERROR: return ((char *)gettext("Internal Error")); case ISNS_RSP_BUSY: return ((char *)gettext("Busy")); case ISNS_RSP_OPTION_NOT_UNDERSTOOD: return ((char *)gettext("Option Not Understood")); case ISNS_RSP_INVALID_UPDATE: return ((char *)gettext("Invalid Update")); case ISNS_RSP_MSG_NOT_SUPPORTED: return ((char *)gettext("Message Not Supported")); case ISNS_RSP_SCN_EVENT_REJECTED: return ((char *)gettext("SCN Event Rejected")); case ISNS_RSP_SCN_REGIS_REJECTED: return ((char *)gettext("SCN Registration Rejected")); case ISNS_RSP_ATTR_NOT_IMPL: return ((char *)gettext("Attribute Not Implemented")); case ISNS_RSP_ESI_NOT_AVAILABLE: return ((char *)gettext("ESI Not Available")); case ISNS_RSP_INVALID_DEREGIS: return ((char *)gettext("Invalid Deregistration")); case ISNS_RSP_REGIS_NOT_SUPPORTED: return ((char *)gettext("Registration Not Supported")); case PARTIAL_SUCCESS: return ((char *)gettext("Partial_success")); case PARTIAL_FAILURE: return ((char *)gettext("Partial failure")); case ERR_DOOR_ALREADY_RUNNING: return ((char *)gettext("iSNS managemnet door is already " "running")); case ERR_DOOR_CREATE_FAILED: return ((char *)gettext("Failed to create iSNS managemnet " "door")); case ERR_DOOR_MORE_SPACE: return ((char *)gettext("More space needed to return the " "response")); case ERR_INVALID_MGMT_REQUEST: return ((char *)gettext("Invalid managmenet request")); case ERR_NULL_XML_MESSAGE: return ((char *)gettext("Null XML request")); case ERR_XML_VALID_OPERATION_NOT_FOUND: return ((char *)gettext("XML Doc error: no valid operation " "found")); case ERR_XML_VALID_OBJECT_NOT_FOUND: return ((char *)gettext("XML Doc error: no valid object " "found")); case ERR_XML_FAIL_TO_CREATE_WRITE_BUFFER: return ((char *)gettext("failed to create XML witer buffer.")); case ERR_XML_FAIL_TO_GET_WRITEPTR: return ((char *)gettext("failed to get XML writer pointer.")); case ERR_XML_INIT_READER_FAILED: return ((char *)gettext("failed to initialize XML reader.")); case ERR_XML_PARSE_MEMORY_FAILED: return ((char *)gettext("failed to parse XML doc in memory.")); case ERR_XML_FAILED_TO_SET_XPATH_CONTEXT: return ((char *)gettext("failed to get XPATH context.")); case ERR_XML_FAILED_TO_REGISTER_NAMESPACE: return ((char *)gettext("failed to register name space.")); case ERR_SYNTAX_MISSING_ROOT: return ((char *)gettext("XML Syntax error: " "isnsRequest root element missing")); case ERR_SYNTAX_MISSING_NAME_ATTR: return ((char *)gettext("XML Syntax error: missing a required " " name attribute")); case ERR_XML_OP_FAILED: return ((char *)gettext("XML operation failed.")); case ERR_XML_STRDUP_FAILED: return ((char *)gettext("XML strndup operation failed.")); case ERR_MALLOC_FAILED: return ((char *)gettext("malloc failed.")); case ERR_DOOR_SERVER_DETECTED_INVALID_USER: return ((char *)gettext("Door server detected invalid user.")); case ERR_DOOR_SERVER_DETECTED_NOT_AUTHORIZED_USER: return ((char *)gettext("Door server detected unauthorized " "user.")); case ERR_MATCHING_ISCSI_NODE_NOT_FOUND: return ((char *)gettext("Matching iSCSI Node not found.")); case ERR_MATCHING_NETWORK_ENTITY_NOT_FOUND: return ((char *)gettext("Network Entity not found.")); case ERR_NO_PORTAL_GROUP_FOUND: return ((char *)gettext("No Portal Group not found.")); case ERR_MATCHING_PORTAL_NOT_FOUND: return ((char *)gettext("Matching Portal not found.")); case ERR_MATCHING_DD_NOT_FOUND: return ((char *)gettext("Matching Discovery Domain not " "found.")); case ERR_MATCHING_DDSET_NOT_FOUND: return ((char *)gettext("Matching Discovery Domain Set " "not found.")); case ERR_NO_ASSOCIATED_DD_FOUND: return ((char *)gettext("No associated Discovery Domain " "found.")); case ERR_NO_ASSOCIATED_DDSET_FOUND: return ((char *)gettext("No associated Discovery Domain Set " "found.")); case ERR_NO_SUCH_ASSOCIATION: return ((char *)gettext("No such association.")); case ERR_ALREADY_ASSOCIATED: return ((char *)gettext("Member is already created.")); case ERR_NAME_IN_USE: return ((char *)gettext("Name is already in use.")); case ERR_DOOR_UCRED_FAILED: return ((char *)gettext("Failed to acquire user credentials " "of management door caller")); default: return ((char *)gettext("Unknown error code")); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2025 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "isns_server.h" #include "isns_obj.h" #include "isns_log.h" #if LIBXML_VERSION >= 20904 #define XMLSTRING_CAST (const char *) #else #define XMLSTRING_CAST (const xmlChar *) #endif /* * external variables */ extern const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE]; extern const int TYPE_OF_PARENT[MAX_OBJ_TYPE_FOR_SIZE]; extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; extern char data_store[MAXPATHLEN]; /* * local variables */ static xmlDocPtr xml_doc = NULL; static char *xml_file = NULL; static char *xml_tmp_file = NULL; static char *xml_bak_file = NULL; static const int OBJ_DTD_ORDER[MAX_OBJ_TYPE_FOR_SIZE] = { 0, 1, /* OBJ_ENTITY */ 2, /* OBJ_ISCSI */ 3, /* OBJ_PORTAL */ 4, /* OBJ_PG */ 5, /* OBJ_DD */ 6, /* OBJ_DDS */ 0, /* MAX_OBJ_TYPE */ 0, /* OBJ_DUMMY1 */ 0, /* OBJ_DUMMY2 */ 0, /* OBJ_DUMMY3 */ 0, /* OBJ_DUMMY4 */ 12, /* OBJ_ASSOC_ISCSI */ 14, /* OBJ_ASSOC_DD */ }; #define DEF_XML_ROOT(ISNS_DATA, VENDOR, SMI, VERSION, ONE_DOT_O) \ (xmlChar *)ISNS_DATA, \ (xmlChar *)VENDOR, \ (xmlChar *)SMI, \ (xmlChar *)VERSION, \ (xmlChar *)ONE_DOT_O static const xmlChar *xml_root[] = { #include "data.def" }; #define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) (xmlChar *)TAG, static const xmlChar* xmlTag[] = { #include "data.def" }; #define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) TYPE, static const char *xmlType[] = { #include "data.def" }; #define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) ARG1, static const int xmlArg1[] = { #include "data.def" }; #define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) ARG2, static const int xmlArg2[] = { #include "data.def" }; #define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) TYPE, static const unsigned char xmlPropType[] = { #include "data.def" }; #define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) (xmlChar *)NAME, static const xmlChar *xmlPropName[] = { #include "data.def" }; #define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) TAG, static const int xmlPropTag[] = { #include "data.def" }; #define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) ID, static const int xmlPropID[] = { #include "data.def" }; #define ARRAY_LENGTH(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0])) /* * **************************************************************************** * * get_index_by_name: * find the index in the global tables for the name of an attribute. * * name - the name of an attribute. * return - index or -1 for error. * * **************************************************************************** */ static int get_index_by_name( const xmlChar *name ) { int i; for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) { if (xmlStrEqual(xmlTag[i], name)) { return (i); } } return (-1); } /* * **************************************************************************** * * get_index_by_otype: * find the index in the global tables for the type of an object. * * name - the type of an object. * return - index or -1 for error. * * **************************************************************************** */ static int get_index_by_otype( int otype ) { int i; for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) { if (xmlArg1[i] == otype && xmlType[i][0] == 'o') { return (i); } } return (-1); } /* * **************************************************************************** * * get_index_by_tag: * find the index in the global tables for the tag of an attribute. * * name - the tag of an attribute. * return - index or -1 for error. * * **************************************************************************** */ static int get_index_by_tag( int tag ) { int i; for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) { if (xmlArg1[i] == tag && xmlType[i][0] != 'o' && xmlType[i][0] != 'a') { return (i); } } return (-1); } /* * **************************************************************************** * * get_xml_doc: * open the xml file and assign the global xml doc if the xml file * is not opened, set the doc pointer with the opened xml file for * returnning. * * docp - the doc pointer for returning. * return - error code. * * **************************************************************************** */ static int get_xml_doc( xmlDocPtr *docp ) { int ec = 0; if (xml_doc == NULL) { /* validate the xml file */ /* open the xml file */ xml_doc = xmlReadFile(xml_file, NULL, XML_PARSE_NOBLANKS); } *docp = xml_doc; if (xml_doc == NULL) { ec = ISNS_RSP_INTERNAL_ERROR; } return (ec); } /* * **************************************************************************** * * close_xml_doc: * close the global xml doc and ignore any changes that has been * made in it. * * **************************************************************************** */ static void close_xml_doc( ) { if (xml_doc) { /* just close it */ xmlFreeDoc(xml_doc); xml_doc = NULL; } } /* * **************************************************************************** * * convert_xml2attr: * convert a xml data to a TLV format isns attribute. * * tag - the tag of attribute. * type - the data type of the xml data. * value - the xml data. * attr - TLV format attribute for returning. * return - error code. * * **************************************************************************** */ static int convert_xml2attr( const int tag, const unsigned char type, xmlChar *value, isns_attr_t *attr ) { uint32_t len; int ec = 0; attr->tag = tag; switch (type) { case 'u': /* 4-bytes non-negative integer */ attr->len = 4; attr->value.ui = atoi((const char *)value); break; case 's': /* literal string */ len = strlen((char *)value); len += 4 - (len % 4); attr->len = len; attr->value.ptr = (uchar_t *)malloc(attr->len); if (attr->value.ptr != NULL) { (void) strcpy((char *)attr->value.ptr, (char *)value); } else { ec = ISNS_RSP_INTERNAL_ERROR; } break; case 'p': /* IPv6 block data */ attr->len = sizeof (in6_addr_t); attr->value.ip = (in6_addr_t *)malloc(attr->len); if (attr->value.ip != NULL) { (void) inet_pton(AF_INET6, (char *)value, attr->value.ip); } else { ec = ISNS_RSP_INTERNAL_ERROR; } break; default: break; } return (ec); } /* * **************************************************************************** * * convert_attr2xml: * convert a TLV format isns attribute to xml node format. * * node - the xml node where the new node is being added to. * attr - the TLV format attribute. * name - the name of the attribute in xml node. * type - the data type of the attribute. * elm_flag - 0: adding a xml attlist. * 1: adding a xml child node. * 2: adding a previous sibling node. * 3: adding a xml content node. * 4: adding a xml attribute. * return - xml node. * * **************************************************************************** */ static xmlNodePtr convert_attr2xml( xmlNodePtr node, const isns_attr_t *attr, const xmlChar *name, const char type, const int elm_flag ) { xmlChar buff[INET6_ADDRSTRLEN + 1] = { 0 }; xmlChar *value = NULL; xmlNodePtr child = NULL; switch (type) { case 'u': /* 4-bytes non-negative integer */ if (xmlStrPrintf(buff, sizeof (buff), XMLSTRING_CAST "%u", attr->value.ui) > 0) { value = (xmlChar *)&buff; } break; case 's': /* literal string */ value = (xmlChar *)attr->value.ptr; break; case 'p': /* IPv6 block data */ value = (xmlChar *)inet_ntop(AF_INET6, (char *)attr->value.ip, (char *)buff, sizeof (buff)); break; default: break; } if (!value) { return (NULL); } switch (elm_flag) { case 0: /* attlist */ if (xmlSetProp(node, name, value)) { child = node; } break; case 1: /* child element */ child = xmlNewChild(node, NULL, name, value); break; case 2: /* prev sibling element */ child = xmlNewNode(NULL, name); if (child != NULL && xmlAddPrevSibling(node, child) == NULL) { xmlFreeNode(child); node = NULL; } else { node = child; } /* FALLTHROUGH */ case 3: /* set content */ if (node) { xmlNodeSetContent(node, value); } child = node; break; case 4: /* new attr value */ if (xmlSetProp(node, name, value)) { child = node; } break; default: ASSERT(0); break; } return (child); } /* * **************************************************************************** * * parse_xml_prop: * parse the properties of a xml node and convert them to the attributes * of an isns object, these xml properties are the UID attribute and * key attributes of the isns object. * * node - the xml node that contains the properties. * obj - the isns object. * i - the index of the attribute in the global tables. * return - error code. * * **************************************************************************** */ static int parse_xml_prop( xmlNodePtr node, isns_obj_t *obj, int i ) { int ec = 0; const char *props = &xmlType[i][1]; const xmlChar *prop_name; xmlChar *prop_value; unsigned char prop_type; int prop_tag; int prop_id; char prop; int j; j = 0; prop = props[j ++]; while (ec == 0 && prop >= 'a' && prop <= 'z') { prop -= 'a'; prop_id = xmlPropID[prop]; prop_tag = xmlPropTag[prop]; prop_name = xmlPropName[prop]; prop_type = xmlPropType[prop]; prop_value = xmlGetProp(node, prop_name); if (prop_value) { ec = convert_xml2attr( prop_tag, prop_type, prop_value, &(obj->attrs[prop_id])); xmlFree(prop_value); } prop = props[j ++]; } return (ec); } /* * **************************************************************************** * * parse_xml_attr: * parse a xml node and convert it to one isns object attribute. * this attribute is the non-key attribute of the isns object. * * node - the xml node. * obj - the isns object. * i - the index of the attribute in the global tables. * return - error code. * * **************************************************************************** */ static int parse_xml_attr( xmlNodePtr node, isns_obj_t *obj, int i ) { int ec = 0; const unsigned char attr_type = xmlType[i][0]; const int attr_tag = xmlArg1[i]; const int attr_id = xmlArg2[i]; xmlChar *attr_value; attr_value = xmlNodeGetContent(node); if (attr_value) { ec = convert_xml2attr( attr_tag, attr_type, attr_value, &(obj->attrs[attr_id])); xmlFree(attr_value); } return (ec); } /* * **************************************************************************** * * parse_xml_obj: * parse one isns object from the xml doc. * * nodep - the pointer of the xml node for parsing. * objp - the pointer of isns object for returning. * return - error code. * * **************************************************************************** */ static int parse_xml_obj( xmlNodePtr *nodep, isns_obj_t **objp ) { int ec = 0; int i, j; xmlNodePtr node = *nodep; xmlNodePtr children; isns_obj_t *obj = *objp; while (node && ec == 0) { if (node->type == XML_ELEMENT_NODE) { children = node->children; i = get_index_by_name(node->name); ASSERT(i >= 0); j = xmlType[i][0]; if (j == 'o' && obj == NULL) { obj = obj_calloc(xmlArg1[i]); if (obj == NULL) { ec = ISNS_RSP_INTERNAL_ERROR; break; } if ((ec = parse_xml_prop(node, obj, i)) == 0 && (children == NULL || (ec = parse_xml_obj(&children, &obj)) == 0)) { if (children != NULL && children != node->children) { *nodep = children; } *objp = obj; } else { free_object(obj); } break; /* LINTED E_NOP_IF_STMT */ } else if (j == 'o') { } else if (j != 0) { ASSERT(obj); if (children != NULL) { ec = parse_xml_attr(children, obj, i); *nodep = children; } else { /* assign a default value */ *nodep = node; } } else { /* unknown xml node */ break; } /* LINTED E_NOP_ELSE_STMT */ } else { /* carry return or blank spaces, skip it */ } node = node->next; } return (ec); } /* * **************************************************************************** * * locate_xml_node: * locate the xml node from xml doc by matching the object UID. * * doc - the xml doc. * otype - the matching object type. * match_uid - the matching object UID. * node - the pointer of matched xml node for returning. * context - the xml context for matching process. * result - the xml result for matching process. * return - error code. * * **************************************************************************** */ static int locate_xml_node( xmlDocPtr doc, int otype, int match_uid, xmlNodePtr *node, xmlXPathContextPtr *context, xmlXPathObjectPtr *result ) { int ec = 0; xmlNodeSetPtr nodeset; xmlNodePtr curr; xmlChar expr[32] = { (xmlChar)'/', (xmlChar)'/', 0 }; char prop; const xmlChar *prop_name; xmlChar *prop_value; int uid; int i, j; *node = NULL; i = get_index_by_otype(otype); ASSERT(i >= 0); *context = xmlXPathNewContext(doc); if (*context && xmlStrPrintf(&expr[2], 30, XMLSTRING_CAST "%s", xmlTag[i]) != -1) { *result = xmlXPathEvalExpression(expr, *context); if (*result) { prop = xmlArg2[i] - 'a'; prop_name = xmlPropName[prop]; ASSERT(xmlPropType[prop] == 'u'); nodeset = (*result)->nodesetval; for (j = 0; nodeset && (j < nodeset->nodeNr); j++) { curr = nodeset->nodeTab[j]; prop_value = xmlGetProp(curr, prop_name); if (prop_value) { uid = atoi((const char *)prop_value); xmlFree(prop_value); if (uid == match_uid) { /* found it */ *node = curr; return (ec); } } } } else { ec = ISNS_RSP_INTERNAL_ERROR; } } else { ec = ISNS_RSP_INTERNAL_ERROR; } if (*result) { xmlXPathFreeObject(*result); *result = NULL; } if (*context) { xmlXPathFreeContext(*context); *context = NULL; } return (ec); } /* * **************************************************************************** * * make_xml_node: * generate a xml node for presenting an isns object. * * obj - an isns object. * return - the xml node. * * **************************************************************************** */ static xmlNodePtr make_xml_node( const isns_obj_t *obj ) { const isns_attr_t *attr; xmlNodePtr node; const char *props; char prop; const xmlChar *name; unsigned char type; int prop_id; int i, j; i = get_index_by_otype(obj->type); ASSERT(i >= 0); node = xmlNewNode(NULL, xmlTag[i]); if (!node) { return (NULL); } /* generate xml attributes of the node */ props = &xmlType[i][1]; prop = *(props ++); while (prop >= 'a' && prop <= 'z') { prop -= 'a'; prop_id = xmlPropID[prop]; name = xmlPropName[prop]; type = xmlPropType[prop]; attr = &obj->attrs[prop_id]; if (!convert_attr2xml(node, attr, name, type, 0)) { xmlFreeNode(node); return (NULL); } /* attr->tag = 0; */ prop = *(props ++); } /* generate sub elements for isns attributes of the object */ i = 0; while (i < NUM_OF_ATTRS[obj->type]) { attr = &obj->attrs[i ++]; j = get_index_by_tag(attr->tag); if (j >= 0) { name = xmlTag[j]; type = xmlType[j][0]; if (!convert_attr2xml(node, attr, name, type, 1)) { xmlFreeNode(node); return (NULL); } } } return (node); } /* * **************************************************************************** * * xml_init_data: * initialization of the xml data store. * * return - error code. * * **************************************************************************** */ static int xml_init_data( ) { #define XML_PATH "/etc/isns" #define XML_FILE_NAME "/isnsdata.xml" #define XML_DOT_TMP ".tmp" #define XML_DOT_BAK ".bak" int fd; xmlDocPtr doc; xmlNodePtr root; int len; char *xml_path, *p = NULL; char *cwd = NULL; int has_bak = 0; /* cannot reset the xml file when server is running */ if (xml_file != NULL) { return (1); } /* set the data store file name along with the backup */ /* file name and temporary file name */ len = strlen(data_store); if (len > 0) { xml_file = data_store; p = strdup(xml_file); xml_bak_file = (char *)malloc(len + 5); xml_tmp_file = (char *)malloc(len + 5); if (p != NULL && xml_bak_file != NULL && xml_tmp_file != NULL) { xml_path = dirname(p); (void) strcpy(xml_bak_file, xml_file); (void) strcat(xml_bak_file, XML_DOT_BAK); (void) strcpy(xml_tmp_file, xml_file); (void) strcat(xml_tmp_file, XML_DOT_TMP); } else { return (1); } } else { xml_path = XML_PATH; xml_file = XML_PATH XML_FILE_NAME; xml_bak_file = XML_PATH XML_FILE_NAME XML_DOT_BAK; xml_tmp_file = XML_PATH XML_FILE_NAME XML_DOT_TMP; } /* save current working directory */ cwd = getcwd(NULL, MAXPATHLEN); if (cwd == NULL) { return (1); } /* check access permission on data store directory */ if (chdir(xml_path) != 0) { if (errno == ENOENT) { if (mkdir(xml_path, S_IRWXU) != 0 || chdir(xml_path) != 0) { return (1); } } else { return (1); } } /* go back to original working directory */ (void) chdir(cwd); free(cwd); free(p); /* remove the tmp file if it exists */ if (access(xml_tmp_file, F_OK) == 0) { (void) remove(xml_tmp_file); } /* test if we can write the bak file */ fd = open(xml_bak_file, O_RDWR); if (fd == -1) { fd = open(xml_bak_file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { return (1); } else { (void) close(fd); (void) remove(xml_bak_file); } } else { has_bak = 1; (void) close(fd); } /* Test if we have the data store file, create an empty */ /* data store if we do not have the data store file and */ /* the backup data store. */ fd = open(xml_file, O_RDWR); if (fd == -1) { if (has_bak == 0) { doc = xmlNewDoc(BAD_CAST "1.0"); root = xmlNewNode(NULL, xml_root[0]); if (doc != NULL && root != NULL && xmlSetProp(root, xml_root[1], xml_root[2]) != NULL && xmlSetProp(root, xml_root[3], xml_root[4]) != NULL) { (void) xmlDocSetRootElement(doc, root); if (xmlSaveFormatFile(xml_file, doc, 1) == -1) { xmlFreeDoc(doc); return (-1); } xmlFreeDoc(doc); } else { if (doc != NULL) { xmlFreeDoc(doc); } if (root != NULL) { xmlFreeNode(root); } return (1); } } else { isnslog(LOG_WARNING, "get_xml_doc", "initializing with backup data"); if (rename(xml_bak_file, xml_file) != 0) { return (1); } } } else { (void) close(fd); } return (0); } /* * **************************************************************************** * * xml_load_obj: * load an isns object from the xml data store. * * p - the pointer of current xml node. * objp - the pointer of the object for returning. * level - the direction of xml parsing for returning. * return - error code. * * **************************************************************************** */ static int xml_load_obj( void **p, isns_obj_t **objp, uchar_t *level ) { xmlDocPtr doc = NULL; xmlNodePtr node = (xmlNodePtr)*p; int ec = 0; *objp = NULL; if (node == NULL) { *level = '^'; ec = get_xml_doc(&doc); if (doc == NULL) { return (ec); } node = xmlDocGetRootElement(doc); if (node != NULL) { node = node->children; } } else if (node->children != NULL) { *level = '>'; node = node->children; } else if (node->next != NULL) { *level = 'v'; node = node->next; } else { *level = 'v'; while (node != NULL && node->next == NULL) { if (node->type == XML_ELEMENT_NODE) { *level = '<'; } node = node->parent; } if (node != NULL) { node = node->next; } } /* there is a node, parse it */ if (node) { ec = parse_xml_obj(&node, objp); *p = (void *)node; } if (ec == 0 && *objp != NULL) { ec = update_deref_obj(*objp); if (ec != 0) { free_object(*objp); *objp = NULL; } } /* no object available, close the xml doc */ if (*objp == NULL) { (void) close_xml_doc(); } return (ec); } /* * **************************************************************************** * * xml_add_obj: * add an isns object to the xml data store. * * obj - the object being added. * return - error code. * * **************************************************************************** */ static int xml_add_obj( const isns_obj_t *obj ) { int ec = 0; xmlDocPtr doc; xmlXPathContextPtr context = NULL; xmlXPathObjectPtr result = NULL; xmlNodePtr node, prev; xmlNodePtr candidate; uint32_t puid, parent_type; int i; /* get the xml doc */ ec = get_xml_doc(&doc); if (doc == NULL) { goto add_done; } /* create the candidate node */ candidate = make_xml_node(obj); if (candidate == NULL) { ec = ISNS_RSP_INTERNAL_ERROR; goto add_done; } /* locate the position */ parent_type = TYPE_OF_PARENT[obj->type]; if (parent_type > 0) { puid = get_parent_uid(obj); ec = locate_xml_node(doc, parent_type, puid, &node, &context, &result); } else { node = xmlDocGetRootElement(doc); } /* cannot locate the point for inserting the node */ if (node == NULL) { xmlFreeNode(candidate); ec = ISNS_RSP_INTERNAL_ERROR; goto add_done; } /* add it with the apporiate child order */ if (node->children) { node = node->children; while (node) { if (node->type == XML_ELEMENT_NODE) { i = get_index_by_name(node->name); ASSERT(i >= 0); if (xmlType[i][0] == 'o' && OBJ_DTD_ORDER[xmlArg1[i]] >= OBJ_DTD_ORDER[obj->type]) { break; } } prev = node; node = node->next; } if (node == NULL) { node = xmlAddNextSibling(prev, candidate); } else { node = xmlAddPrevSibling(node, candidate); } } else { node = xmlAddChild(node, candidate); } if (node == NULL) { /* Failed, free the candidate node. */ xmlFreeNode(candidate); ec = ISNS_RSP_INTERNAL_ERROR; } add_done: if (result) { xmlXPathFreeObject(result); } if (context) { xmlXPathFreeContext(context); } return (ec); } /* * **************************************************************************** * * xml_modify_obj: * modify an isns object in the xml data store. * * obj - the new object. * return - error code. * * **************************************************************************** */ static int xml_modify_obj( const isns_obj_t *obj ) { int ec = 0; xmlDocPtr doc; xmlXPathContextPtr context = NULL; xmlXPathObjectPtr result = NULL; xmlNodePtr node, child; const char *props; char prop; int prop_id; int prop_tag; const xmlChar *name; unsigned char type; const isns_attr_t *attr; int i, j, k; int make_child; /* get the doc pointer */ ec = get_xml_doc(&doc); if (doc == NULL) { return (ec); } /* locate the node for the object */ i = get_index_by_otype(obj->type); ASSERT(i >= 0); prop = xmlArg2[i] - 'a'; prop_id = xmlPropID[prop]; attr = &obj->attrs[prop_id]; ec = locate_xml_node(doc, obj->type, attr->value.ui, &node, &context, &result); /* modify it */ if (node != NULL) { props = &xmlType[i][1]; prop = *(props ++); while (prop >= 'a' && prop <= 'z') { prop -= 'a'; prop_id = xmlPropID[prop]; prop_tag = xmlPropTag[prop]; attr = &obj->attrs[prop_id]; /* no need to update the key attributes, skip it. */ /* btw, dd and dd-set names are non-key attributes. */ if (prop_tag == ISNS_DD_NAME_ATTR_ID || prop_tag == ISNS_DD_SET_NAME_ATTR_ID) { name = xmlPropName[prop]; type = xmlPropType[prop]; if (!convert_attr2xml(node, attr, name, type, 4)) { ec = ISNS_RSP_INTERNAL_ERROR; goto modify_done; } } /* attr->tag = 0; */ prop = *(props ++); } /* set the child */ child = node->children; if (child == NULL) { make_child = 1; } else { make_child = 0; } for (i = 0; i < NUM_OF_ATTRS[obj->type]; i++) { attr = &obj->attrs[i]; j = get_index_by_tag(attr->tag); if (j < 0) { continue; } name = xmlTag[j]; type = xmlType[j][0]; if (make_child == 1) { /* make a child node */ if (!convert_attr2xml(node, attr, name, type, 1)) { ec = ISNS_RSP_INTERNAL_ERROR; goto modify_done; } continue; } while (child) { if (child->type == XML_ELEMENT_NODE) { k = get_index_by_name(child->name); ASSERT(k >= 0); if (xmlType[k][0] == 'o' || xmlType[k][0] == 'a' || xmlArg1[k] > attr->tag) { if (!convert_attr2xml(child, attr, name, type, 2)) { /* internal error */ ec = 11; goto modify_done; } break; } else if (xmlArg1[k] == attr->tag) { /* replace content */ if (!convert_attr2xml(child, attr, name, type, 3)) { /* internal error */ ec = 11; goto modify_done; } break; } } child = child->next; } if (child == NULL) { /* make a child node */ if (!convert_attr2xml(node, attr, name, type, 1)) { ec = ISNS_RSP_INTERNAL_ERROR; goto modify_done; } } } } else { /* This case is for registering a node which has */ /* membership in one or more non-default DD(s). */ ec = xml_add_obj(obj); } modify_done: if (result) { xmlXPathFreeObject(result); } if (context) { xmlXPathFreeContext(context); } return (ec); } /* * **************************************************************************** * * xml_delete_obj: * delete an isns object from the xml data store. * * obj - the object being deleted. * return - error code. * * **************************************************************************** */ static int xml_delete_obj( const isns_obj_t *obj ) { int ec = 0; xmlDocPtr doc; xmlXPathContextPtr context = NULL; xmlXPathObjectPtr result = NULL; xmlNodePtr node; isns_type_t otype; uint32_t uid; /* get the xml doc */ ec = get_xml_doc(&doc); if (doc == NULL) { return (ec); } otype = obj->type; #ifdef WRITE_DATA_ASYNC /* it is a thin clone */ uid = obj->attrs[0].value.ui; #else uid = get_obj_uid(obj); #endif /* locate the object */ ec = locate_xml_node(doc, otype, uid, &node, &context, &result); /* destroy it */ if (node) { xmlUnlinkNode(node); xmlFreeNode(node); } if (result) { xmlXPathFreeObject(result); } if (context) { xmlXPathFreeContext(context); } return (ec); } /* * **************************************************************************** * * xml_delete_assoc: * delete a DD or DD-set membership from the xml data store. * * assoc - the membership being deleted. * return - error code. * * **************************************************************************** */ static int xml_delete_assoc( const isns_obj_t *assoc ) { int ec = 0; xmlDocPtr doc; xmlXPathContextPtr context = NULL; xmlXPathObjectPtr result = NULL; xmlNodePtr node; uint32_t puid, parent_type; uint32_t uid, match_uid; char prop; const xmlChar *prop_name; xmlChar *prop_value; int i; /* get the xml doc */ ec = get_xml_doc(&doc); if (doc == NULL) { return (ec); } /* get the container object UID */ parent_type = TYPE_OF_PARENT[assoc->type]; ASSERT(parent_type != 0); puid = get_parent_uid(assoc); ASSERT(puid != 0); /* get the member object UID */ i = get_index_by_otype(assoc->type); prop = xmlArg2[i] - 'a'; prop_name = xmlPropName[prop]; match_uid = assoc->attrs[UID_ATTR_INDEX[assoc->type]].value.ui; /* locate the container object */ ec = locate_xml_node(doc, parent_type, puid, &node, &context, &result); /* get the membership nodes */ if (node != NULL) { node = node->children; } /* get the matching membership node */ while (node) { if (node->type == XML_ELEMENT_NODE) { i = get_index_by_name(node->name); ASSERT(i >= 0); if (xmlType[i][0] == 'o' && xmlArg1[i] == assoc->type) { prop_value = xmlGetProp(node, prop_name); if (prop_value) { uid = atoi((const char *)prop_value); xmlFree(prop_value); if (uid == match_uid) { break; } } } } node = node->next; } /* destroy it */ if (node) { xmlUnlinkNode(node); xmlFreeNode(node); } if (result) { xmlXPathFreeObject(result); } if (context) { xmlXPathFreeContext(context); } return (ec); } /* * **************************************************************************** * * xml_update_commit: * backup the current written file and commit all updates from * the xml doc to the written file. * * return - error code. * * **************************************************************************** */ static int xml_update_commit( ) { int ec = 0; if (xml_doc) { /* write to tmp file */ if (xmlSaveFormatFile(xml_tmp_file, xml_doc, 1) == -1 || /* backup the current file */ rename(xml_file, xml_bak_file) != 0 || /* rename the tmp file to the current file */ rename(xml_tmp_file, xml_file) != 0) { /* failed saving file */ ec = ISNS_RSP_INTERNAL_ERROR; } /* close the xml_doc */ xmlFreeDoc(xml_doc); xml_doc = NULL; } return (ec); } /* * **************************************************************************** * * xml_update_retreat: * ignore all of updates in the xml doc. * * return - 0: always successful. * * **************************************************************************** */ static int xml_update_retreat( ) { if (xml_doc) { /* close the xml_doc */ xmlFreeDoc(xml_doc); xml_doc = NULL; } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef DEF_XML_ROOT #define DEF_XML_ROOT(ISNS_DATA, VENDOR, SMI, VERSION, ONE_DOT_O) #endif #ifndef DEF_XML_DATA #define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) #endif #ifndef DEF_XML_PROP #define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) #endif /* * The root element. */ DEF_XML_ROOT("isns_data", "vendor", "Sun Microsystems, Inc.", "version", "1.0") /* * iSNS objects. */ DEF_XML_DATA("pg", "oabcd", OBJ_PG, 'a') DEF_XML_DATA("portal", "oefg", OBJ_PORTAL, 'e') DEF_XML_DATA("iscsi", "ohi", OBJ_ISCSI, 'h') DEF_XML_DATA("entity", "ojk", OBJ_ENTITY, 'j') DEF_XML_DATA("dd", "olm", OBJ_DD, 'l') DEF_XML_DATA("dds", "ono", OBJ_DDS, 'n') DEF_XML_DATA("assoc_iscsi", "opq", OBJ_ASSOC_ISCSI, 'p') DEF_XML_DATA("assoc_dd", "or", OBJ_ASSOC_DD, 'r') /* * UID attributes and key attributes of iSNS objects. */ DEF_XML_PROP('a', 'u', "uid", ISNS_PG_INDEX_ATTR_ID, ATTR_INDEX_PG(ISNS_PG_INDEX_ATTR_ID)) DEF_XML_PROP('b', 's', "pg_iscsi", ISNS_PG_ISCSI_NAME_ATTR_ID, ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID)) DEF_XML_PROP('c', 'p', "pg_ip", ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)) DEF_XML_PROP('d', 'u', "pg_port", ISNS_PG_PORTAL_PORT_ATTR_ID, ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID)) DEF_XML_PROP('e', 'u', "uid", ISNS_PORTAL_INDEX_ATTR_ID, ATTR_INDEX_PORTAL(ISNS_PORTAL_INDEX_ATTR_ID)) DEF_XML_PROP('f', 'p', "ip", ISNS_PORTAL_IP_ADDR_ATTR_ID, ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID)) DEF_XML_PROP('g', 'u', "port", ISNS_PORTAL_PORT_ATTR_ID, ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID)) DEF_XML_PROP('h', 'u', "uid", ISNS_ISCSI_NODE_INDEX_ATTR_ID, ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_INDEX_ATTR_ID)) DEF_XML_PROP('i', 's', "name", ISNS_ISCSI_NAME_ATTR_ID, ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)) DEF_XML_PROP('j', 'u', "uid", ISNS_ENTITY_INDEX_ATTR_ID, ATTR_INDEX_ENTITY(ISNS_ENTITY_INDEX_ATTR_ID)) DEF_XML_PROP('k', 's', "eid", ISNS_EID_ATTR_ID, ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)) DEF_XML_PROP('l', 'u', "uid", ISNS_DD_ID_ATTR_ID, ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID)) DEF_XML_PROP('m', 's', "name", ISNS_DD_NAME_ATTR_ID, ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)) DEF_XML_PROP('n', 'u', "uid", ISNS_DD_SET_ID_ATTR_ID, ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID)) DEF_XML_PROP('o', 's', "name", ISNS_DD_SET_NAME_ATTR_ID, ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID)) DEF_XML_PROP('p', 'u', "iscsi_uid", ISNS_DD_ISCSI_INDEX_ATTR_ID, ATTR_INDEX_ASSOC_ISCSI(ISNS_DD_ISCSI_INDEX_ATTR_ID)) DEF_XML_PROP('q', 's', "iscsi_name", ISNS_DD_ISCSI_NAME_ATTR_ID, ATTR_INDEX_ASSOC_ISCSI(ISNS_DD_ISCSI_NAME_ATTR_ID)) DEF_XML_PROP('r', 'u', "dd_uid", ISNS_DD_ID_ATTR_ID, ATTR_INDEX_ASSOC_DD(ISNS_DD_ID_ATTR_ID)) /* * Attributes for Portal Group object. */ DEF_XML_DATA("pgt", "u", ISNS_PG_TAG_ATTR_ID, ATTR_INDEX_PG(ISNS_PG_TAG_ATTR_ID)) /* * Attributes for Portal object. */ DEF_XML_DATA("name", "s", ISNS_PORTAL_NAME_ATTR_ID, ATTR_INDEX_PORTAL(ISNS_PORTAL_NAME_ATTR_ID)) DEF_XML_DATA("esi_int", "u", ISNS_ESI_INTERVAL_ATTR_ID, ATTR_INDEX_PORTAL(ISNS_ESI_INTERVAL_ATTR_ID)) DEF_XML_DATA("esi", "u", ISNS_ESI_PORT_ATTR_ID, ATTR_INDEX_PORTAL(ISNS_ESI_PORT_ATTR_ID)) DEF_XML_DATA("scn", "u", ISNS_SCN_PORT_ATTR_ID, ATTR_INDEX_PORTAL(ISNS_SCN_PORT_ATTR_ID)) /* * Attributes for Storage Node object. */ DEF_XML_DATA("type", "u", ISNS_ISCSI_NODE_TYPE_ATTR_ID, ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)) DEF_XML_DATA("alias", "s", ISNS_ISCSI_ALIAS_ATTR_ID, ATTR_INDEX_ISCSI(ISNS_ISCSI_ALIAS_ATTR_ID)) DEF_XML_DATA("scn_bmp", "u", ISNS_ISCSI_SCN_BITMAP_ATTR_ID, ATTR_INDEX_ISCSI(ISNS_ISCSI_SCN_BITMAP_ATTR_ID)) DEF_XML_DATA("auth", "s", ISNS_ISCSI_AUTH_METHOD_ATTR_ID, ATTR_INDEX_ISCSI(ISNS_ISCSI_AUTH_METHOD_ATTR_ID)) /* * Attributes for Network Entity object. */ DEF_XML_DATA("protocol", "u", ISNS_ENTITY_PROTOCOL_ATTR_ID, ATTR_INDEX_ENTITY(ISNS_ENTITY_PROTOCOL_ATTR_ID)) DEF_XML_DATA("period", "u", ISNS_ENTITY_REG_PERIOD_ATTR_ID, ATTR_INDEX_ENTITY(ISNS_ENTITY_REG_PERIOD_ATTR_ID)) /* * Attributes for Discovery Domain object. */ /* * Attributes for Discovery Domain Set object. */ DEF_XML_DATA("status", "u", ISNS_DD_SET_STATUS_ATTR_ID, ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID)) #undef DEF_XML_ROOT #undef DEF_XML_DATA #undef DEF_XML_PROP