diff options
author | Peter Dunlap <Peter.Dunlap@Sun.COM> | 2008-10-30 15:49:07 -0600 |
---|---|---|
committer | Peter Dunlap <Peter.Dunlap@Sun.COM> | 2008-10-30 15:49:07 -0600 |
commit | a6d42e7d71324c5193c3b94d57d96ba2925d52e1 (patch) | |
tree | b99a1d06464c8dcb9ae0462623f708a380a27d2c /usr/src/lib/libiscsit/common | |
parent | 2d6aa547f868d751d00f1f2e70171d9dc9317af1 (diff) | |
download | illumos-joyent-a6d42e7d71324c5193c3b94d57d96ba2925d52e1.tar.gz |
PSARC 2008/587 iSCSI Port Provider for COMSTAR
6702584 Need iSCSI port provider for COMSTAR
Diffstat (limited to 'usr/src/lib/libiscsit/common')
-rw-r--r-- | usr/src/lib/libiscsit/common/libiscsit.c | 1889 | ||||
-rw-r--r-- | usr/src/lib/libiscsit/common/libiscsit.h | 747 | ||||
-rw-r--r-- | usr/src/lib/libiscsit/common/llib-liscsit | 30 | ||||
-rw-r--r-- | usr/src/lib/libiscsit/common/mapfile-vers | 79 |
4 files changed, 2745 insertions, 0 deletions
diff --git a/usr/src/lib/libiscsit/common/libiscsit.c b/usr/src/lib/libiscsit/common/libiscsit.c new file mode 100644 index 0000000000..a9b2edeae4 --- /dev/null +++ b/usr/src/lib/libiscsit/common/libiscsit.c @@ -0,0 +1,1889 @@ +/* + * 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 <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <fcntl.h> +#include <uuid/uuid.h> +#include <errno.h> +#include <unistd.h> +#include <strings.h> +#include <libintl.h> + +#include <libstmf.h> +#include <libiscsit.h> +#include <sys/iscsit/iscsit_common.h> +#include <sys/iscsi_protocol.h> +#include <sys/iscsit/isns_protocol.h> + +/* From iscsitgtd */ +#define TARGET_NAME_VERS 2 + +/* this should be defined someplace central... */ +#define ISCSI_NAME_LEN_MAX 223 + +/* max length of a base64 encoded secret */ +#define MAX_BASE64_LEN 341 + +/* Default RADIUS server port */ +#define DEFAULT_RADIUS_PORT 1812 + +/* + * The kernel reserves target portal group tag value 1 as the default. + */ +#define ISCSIT_DEFAULT_TPGT 1 +#define MAXTAG 0xffff + +/* helper for property list validation */ +#define PROPERR(lst, key, value) { \ + if (lst) { \ + (void) nvlist_add_string(lst, key, value); \ + } \ +} + +/* helper function declarations */ +static int +it_iqn_generate(char *iqn_buf, int iqn_buf_len, char *opt_iqn_suffix); + +static int +it_val_pass(char *name, char *val, nvlist_t *e); + +/* consider making validate funcs public */ +static int +it_validate_configprops(nvlist_t *nvl, nvlist_t *errs); + +static int +it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs); + +static int +it_validate_iniprops(nvlist_t *nvl, nvlist_t *errs); + +/* + * Function: it_config_load() + * + * Allocate and create an it_config_t structure representing the + * current iSCSI configuration. This structure is compiled using + * the 'provider' data returned by stmfGetProviderData(). If there + * is no provider data associated with iscsit, the it_config_t + * structure will be set to a default configuration. + * + * Parameters: + * cfg A C representation of the current iSCSI configuration + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter + */ +int +it_config_load(it_config_t **cfg) +{ + int ret = 0; + nvlist_t *cfg_nv = NULL; + it_config_t *newcfg = NULL; + uint64_t stmf_token = 0; + + if (!cfg) { + return (EINVAL); + } + + *cfg = NULL; + + ret = stmfGetProviderDataProt(ISCSIT_MODNAME, &cfg_nv, + STMF_PORT_PROVIDER_TYPE, &stmf_token); + + if ((ret == STMF_STATUS_SUCCESS) || + (ret == STMF_ERROR_NOT_FOUND)) { + /* + * If not initialized yet, return empty it_config_t + * Else, convert nvlist to struct + */ + ret = it_nv_to_config(cfg_nv, &newcfg); + } + + if (ret == 0) { + newcfg->stmf_token = stmf_token; + *cfg = newcfg; + } + + return (ret); +} + +/* + * Function: it_config_commit() + * + * Informs the iscsit service that the configuration has changed and + * commits the new configuration to persistent store by calling + * stmfSetProviderData. This function can be called multiple times + * during a configuration sequence if necessary. + * + * Parameters: + * cfg A C representation of the current iSCSI configuration + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid it_config_t structure + * TBD ioctl() failed + * TBD could not save config to STMF + */ +int +it_config_commit(it_config_t *cfg) +{ + int ret; + nvlist_t *cfgnv = NULL; + char *packednv = NULL; + int iscsit_fd = -1; + size_t pnv_size; + iscsit_ioc_set_config_t iop; + it_tgt_t *tgtp; + + if (!cfg) { + return (EINVAL); + } + + iscsit_fd = open(ISCSIT_NODE, O_RDWR|O_EXCL); + if (iscsit_fd == -1) { + ret = errno; + return (ret); + } + + ret = it_config_to_nv(cfg, &cfgnv); + if (ret == 0) { + ret = nvlist_size(cfgnv, &pnv_size, NV_ENCODE_NATIVE); + } + + if (ret == 0) { + packednv = malloc(pnv_size); + if (!packednv) { + ret = ENOMEM; + } else { + ret = nvlist_pack(cfgnv, &packednv, &pnv_size, + NV_ENCODE_NATIVE, 0); + } + } + + /* + * Send the changes to the kernel first, for now. Kernel + * will be the final sanity check before config is saved + * persistently. + * + * XXX - this leaves open the simultaneous-change hole + * that STMF was trying to solve, but is a better sanity + * check. Final decision on save order/config generation + * number TBD. + */ + if (ret == 0) { + iop.set_cfg_vers = ISCSIT_API_VERS0; + iop.set_cfg_pnvlist = packednv; + iop.set_cfg_pnvlist_len = pnv_size; + if ((ioctl(iscsit_fd, ISCSIT_IOC_SET_CONFIG, &iop)) != 0) { + ret = errno; + } + } + + /* + * Before saving the config persistently, remove any + * PROP_OLD_TARGET_NAME entries. This is only interesting to + * the active service. + */ + if (ret == 0) { + tgtp = cfg->config_tgt_list; + for (; tgtp != NULL; tgtp = tgtp->tgt_next) { + if (!tgtp->tgt_properties) { + continue; + } + if (nvlist_exists(tgtp->tgt_properties, + PROP_OLD_TARGET_NAME)) { + (void) nvlist_remove_all(tgtp->tgt_properties, + PROP_OLD_TARGET_NAME); + } + } + } + + /* + * stmfGetProviderDataProt() checks to ensure + * that the config data hasn't changed since we fetched it. + * + * The kernel now has a version we need to save persistently. + * CLI will 'do the right thing' and warn the user if it + * gets STMF_ERROR_PROV_DATA_STALE. We'll try once to revert + * the kernel to the persistently saved data, but ultimately, + * it's up to the administrator to validate things are as they + * want them to be. + */ + if (ret == 0) { + ret = stmfSetProviderDataProt(ISCSIT_MODNAME, cfgnv, + STMF_PORT_PROVIDER_TYPE, &(cfg->stmf_token)); + + if (ret == STMF_STATUS_SUCCESS) { + ret = 0; + } else if (ret == STMF_ERROR_NOMEM) { + ret = ENOMEM; + } else if (ret == STMF_ERROR_PROV_DATA_STALE) { + int st; + it_config_t *rcfg = NULL; + + st = it_config_load(&rcfg); + if (st == 0) { + (void) it_config_commit(rcfg); + it_config_free(rcfg); + } + } + } + + (void) close(iscsit_fd); + + if (packednv) { + free(packednv); + } + + if (cfgnv) { + nvlist_free(cfgnv); + } + + return (ret); +} + +/* + * Function: it_config_setprop() + * + * Validate the provided property list and set the global properties + * for iSCSI Target. If errlist is not NULL, returns detailed + * errors for each property that failed. The format for errorlist + * is key = property, value = error string. + * + * Parameters: + * + * cfg The current iSCSI configuration obtained from + * it_config_load() + * proplist nvlist_t containing properties for this target. + * errlist (optional) nvlist_t of errors encountered when + * validating the properties. + * + * Return Values: + * 0 Success + * EINVAL Invalid property + * + */ +int +it_config_setprop(it_config_t *cfg, nvlist_t *proplist, nvlist_t **errlist) +{ + int ret; + it_portal_t *isns = NULL; + it_portal_t *pnext = NULL; + it_portal_t *newisnslist = NULL; + char **arr; + uint32_t count; + uint32_t newcount; + nvlist_t *cprops = NULL; + char *val = NULL; + + if (!cfg || !proplist) { + return (EINVAL); + } + + if (errlist) { + (void) nvlist_alloc(errlist, 0, 0); + } + + /* + * copy the existing properties, merge, then validate + * the merged properties before committing them. + */ + if (cfg->config_global_properties) { + ret = nvlist_dup(cfg->config_global_properties, &cprops, 0); + } else { + ret = nvlist_alloc(&cprops, NV_UNIQUE_NAME, 0); + } + + /* base64 encode the radius secret, if it's changed */ + val = NULL; + (void) nvlist_lookup_string(proplist, PROP_RADIUS_SECRET, &val); + if (val) { + char bsecret[MAX_BASE64_LEN]; + + ret = it_val_pass(PROP_RADIUS_SECRET, val, *errlist); + + if (ret == 0) { + (void) memset(bsecret, 0, MAX_BASE64_LEN); + + ret = iscsi_binary_to_base64_str((uint8_t *)val, + strlen(val), bsecret, MAX_BASE64_LEN); + + if (ret == 0) { + /* replace the value in the nvlist */ + ret = nvlist_add_string(proplist, + PROP_RADIUS_SECRET, bsecret); + } + } + } + + if (ret == 0) { + ret = nvlist_merge(cprops, proplist, 0); + } + + /* see if we need to remove the radius server setting */ + val = NULL; + (void) nvlist_lookup_string(cprops, PROP_RADIUS_SERVER, &val); + if (val && (strcasecmp(val, "none") == 0)) { + (void) nvlist_remove_all(cprops, PROP_RADIUS_SERVER); + } + + /* and/or remove the alias */ + val = NULL; + (void) nvlist_lookup_string(cprops, PROP_ALIAS, &val); + if (val && (strcasecmp(val, "none") == 0)) { + (void) nvlist_remove_all(cprops, PROP_ALIAS); + } + + if (ret == 0) { + ret = it_validate_configprops(cprops, *errlist); + } + + if (ret != 0) { + if (cprops) { + nvlist_free(cprops); + } + return (ret); + } + + /* + * Update iSNS server list, if exists in provided property list. + */ + ret = nvlist_lookup_string_array(proplist, PROP_ISNS_SERVER, + &arr, &count); + + if (ret == 0) { + /* special case: if "none", remove all defined */ + if (strcasecmp(arr[0], "none") != 0) { + ret = it_array_to_portallist(arr, count, + ISNS_DEFAULT_SERVER_PORT, &newisnslist, &newcount); + } else { + newisnslist = NULL; + newcount = 0; + (void) nvlist_remove_all(cprops, PROP_ISNS_SERVER); + } + + if (ret == 0) { + isns = cfg->config_isns_svr_list; + while (isns) { + pnext = isns->next; + free(isns); + isns = pnext; + } + + cfg->config_isns_svr_list = newisnslist; + cfg->config_isns_svr_count = newcount; + + /* + * Replace the array in the nvlist to ensure + * duplicates are properly removed & port numbers + * are added. + */ + if (newcount > 0) { + int i = 0; + char **newarray; + + newarray = malloc(sizeof (char *) * newcount); + if (newarray == NULL) { + ret = ENOMEM; + } else { + for (isns = newisnslist; isns != NULL; + isns = isns->next) { + (void) sockaddr_to_str( + &(isns->portal_addr), + &(newarray[i++])); + } + (void) nvlist_add_string_array(cprops, + PROP_ISNS_SERVER, newarray, + newcount); + + for (i = 0; i < newcount; i++) { + if (newarray[i]) { + free(newarray[i]); + } + } + free(newarray); + } + } + } + } else if (ret == ENOENT) { + /* not an error */ + ret = 0; + } + + if (ret == 0) { + /* replace the global properties list */ + nvlist_free(cfg->config_global_properties); + cfg->config_global_properties = cprops; + } else { + if (cprops) { + nvlist_free(cprops); + } + } + + return (ret); +} + +/* + * Function: it_config_free() + * + * Free any resources associated with the it_config_t structure. + * + * Parameters: + * cfg A C representation of the current iSCSI configuration + */ +void +it_config_free(it_config_t *cfg) +{ + it_config_free_cmn(cfg); +} + +/* + * Function: it_tgt_create() + * + * Allocate and create an it_tgt_t structure representing a new iSCSI + * target node. If tgt_name is NULL, then a unique target node name will + * be generated automatically. Otherwise, the value of tgt_name will be + * used as the target node name. The new it_tgt_t structure is added to + * the target list (cfg_tgt_list) in the configuration structure, and the + * new target will not be instantiated until the modified configuration + * is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to an iSCSI target structure + * tgt_name The target node name for the target to be created. + * The name must be in either IQN or EUI format. If + * this value is NULL, a node name will be generated + * automatically in IQN format. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocated resources + * EINVAL Invalid parameter + * EFAULT Invalid iSCSI name specified + */ +int +it_tgt_create(it_config_t *cfg, it_tgt_t **tgt, char *tgt_name) +{ + int ret = 0; + it_tgt_t *ptr; + it_tgt_t *cfgtgt; + char *namep = tgt_name; + char buf[ISCSI_NAME_LEN_MAX + 1]; + + if (!cfg || !tgt) { + return (EINVAL); + } + + if (!namep) { + /* generate a name */ + + ret = it_iqn_generate(buf, sizeof (buf), NULL); + if (ret != 0) { + return (ret); + } + namep = buf; + } else { + /* validate the passed-in name */ + if (!validate_iscsi_name(namep)) { + return (EFAULT); + } + } + + /* make sure this name isn't already on the list */ + cfgtgt = cfg->config_tgt_list; + while (cfgtgt != NULL) { + if (strcmp(namep, cfgtgt->tgt_name) == 0) { + return (EEXIST); + } + cfgtgt = cfgtgt->tgt_next; + } + + ptr = calloc(1, sizeof (it_tgt_t)); + if (ptr == NULL) { + return (ENOMEM); + } + + (void) strlcpy(ptr->tgt_name, namep, sizeof (ptr->tgt_name)); + ptr->tgt_generation = 1; + ptr->tgt_next = cfg->config_tgt_list; + cfg->config_tgt_list = ptr; + cfg->config_tgt_count++; + + *tgt = ptr; + + return (0); +} + +/* + * Function: it_tgt_setprop() + * + * Validate the provided property list and set the properties for + * the specified target. If errlist is not NULL, returns detailed + * errors for each property that failed. The format for errorlist + * is key = property, value = error string. + * + * Parameters: + * + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to an iSCSI target structure + * proplist nvlist_t containing properties for this target. + * errlist (optional) nvlist_t of errors encountered when + * validating the properties. + * + * Return Values: + * 0 Success + * EINVAL Invalid property + * + */ +int +it_tgt_setprop(it_config_t *cfg, it_tgt_t *tgt, nvlist_t *proplist, + nvlist_t **errlist) +{ + int ret; + nvlist_t *tprops = NULL; + char *val = NULL; + + if (!cfg || !tgt || !proplist) { + return (EINVAL); + } + + if (errlist) { + (void) nvlist_alloc(errlist, 0, 0); + } + + /* + * copy the existing properties, merge, then validate + * the merged properties before committing them. + */ + if (tgt->tgt_properties) { + ret = nvlist_dup(tgt->tgt_properties, &tprops, 0); + } else { + ret = nvlist_alloc(&tprops, NV_UNIQUE_NAME, 0); + } + + if (ret == 0) { + ret = nvlist_merge(tprops, proplist, 0); + } + + /* unset chap username or alias if requested */ + val = NULL; + (void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_USER, &val); + if (val && (strcasecmp(val, "none") == 0)) { + (void) nvlist_remove_all(tprops, PROP_TARGET_CHAP_USER); + } + + val = NULL; + (void) nvlist_lookup_string(proplist, PROP_ALIAS, &val); + if (val && (strcasecmp(val, "none") == 0)) { + (void) nvlist_remove_all(tprops, PROP_ALIAS); + } + + /* base64 encode the CHAP secret, if it's changed */ + val = NULL; + (void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_SECRET, &val); + if (val) { + char bsecret[MAX_BASE64_LEN]; + + ret = it_val_pass(PROP_TARGET_CHAP_SECRET, val, *errlist); + + if (ret == 0) { + (void) memset(bsecret, 0, MAX_BASE64_LEN); + + ret = iscsi_binary_to_base64_str((uint8_t *)val, + strlen(val), bsecret, MAX_BASE64_LEN); + + if (ret == 0) { + /* replace the value in the nvlist */ + ret = nvlist_add_string(tprops, + PROP_TARGET_CHAP_SECRET, bsecret); + } + } + } + + if (ret == 0) { + ret = it_validate_tgtprops(tprops, *errlist); + } + + if (ret != 0) { + if (tprops) { + nvlist_free(tprops); + } + return (ret); + } + + if (tgt->tgt_properties) { + nvlist_free(tgt->tgt_properties); + } + tgt->tgt_properties = tprops; + + return (0); +} + + +/* + * Function: it_tgt_delete() + * + * Delete target represented by 'tgt', where 'tgt' is an existing + * it_tgt_structure within the configuration 'cfg'. The target removal + * will not take effect until the modified configuration is committed + * by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to an iSCSI target structure + * + * force Set the target to offline before removing it from + * the config. If not specified, the operation will + * fail if the target is determined to be online. + * Return Values: + * 0 Success + * EBUSY Target is online + */ +int +it_tgt_delete(it_config_t *cfg, it_tgt_t *tgt, boolean_t force) +{ + int ret; + it_tgt_t *ptgt; + it_tgt_t *prev = NULL; + stmfDevid devid; + stmfTargetProperties props; + + if (!cfg || !tgt) { + return (0); + } + + ptgt = cfg->config_tgt_list; + while (ptgt != NULL) { + if (strcmp(tgt->tgt_name, ptgt->tgt_name) == 0) { + break; + } + prev = ptgt; + ptgt = ptgt->tgt_next; + } + + if (!ptgt) { + return (0); + } + + /* + * check to see if this target is offline. If it is not, + * and the 'force' flag is TRUE, tell STMF to offline it + * before removing from the configuration. + */ + ret = stmfDevidFromIscsiName(ptgt->tgt_name, &devid); + if (ret != STMF_STATUS_SUCCESS) { + /* can't happen? */ + return (EINVAL); + } + + ret = stmfGetTargetProperties(&devid, &props); + if (ret == STMF_STATUS_SUCCESS) { + /* + * only other return is STMF_ERROR_NOT_FOUND, which + * means we don't have to offline it. + */ + if (props.status == STMF_TARGET_PORT_ONLINE) { + if (!force) { + return (EBUSY); + } + ret = stmfOfflineTarget(&devid); + if (ret != 0) { + return (EBUSY); + } + } + } + + if (prev) { + prev->tgt_next = ptgt->tgt_next; + } else { + /* first one on the list */ + cfg->config_tgt_list = ptgt->tgt_next; + } + + ptgt->tgt_next = NULL; /* Only free this target */ + + cfg->config_tgt_count--; + it_tgt_free(ptgt); + + return (0); +} + +/* + * Function: it_tgt_free() + * + * Frees an it_tgt_t structure. If tgt_next is not NULL, frees + * all structures in the list. + */ +void +it_tgt_free(it_tgt_t *tgt) +{ + it_tgt_free_cmn(tgt); +} + +/* + * Function: it_tpgt_create() + * + * Allocate and create an it_tpgt_t structure representing a new iSCSI + * target portal group tag. The new it_tpgt_t structure is added to the + * target tpgt list (tgt_tpgt_list) in the it_tgt_t structure. The new + * target portal group tag will not be instantiated until the modified + * configuration is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to the iSCSI target structure associated + * with the target portal group tag + * tpgt Pointer to a target portal group tag structure + * tpg_name The name of the TPG to be associated with this TPGT + * tpgt_tag 16-bit numerical identifier for this TPGT. If + * tpgt_tag is '0', this function will choose the + * tag number. If tpgt_tag is >0, and the requested + * tag is determined to be in use, another value + * will be chosen. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter + * EEXIST Specified tag name is already used. + * E2BIG No available tag numbers + */ +int +it_tpgt_create(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t **tpgt, + char *tpg_name, uint16_t tpgt_tag) +{ + it_tpgt_t *ptr = NULL; + it_tpgt_t *cfgt; + char tagid_used[MAXTAG + 1]; + uint16_t tagid = ISCSIT_DEFAULT_TPGT; + + if (!cfg || !tgt || !tpgt || !tpg_name) { + return (EINVAL); + } + + (void) memset(&(tagid_used[0]), 0, sizeof (tagid_used)); + + /* + * Make sure this name and/or tag isn't already on the list + * At the same time, capture all tag ids in use for this target + * + * About tag numbering -- since tag numbers are used by + * the iSCSI protocol, we should be careful about reusing + * them too quickly. Start with a value greater than the + * highest one currently defined. If current == MAXTAG, + * just find an unused tag. + */ + cfgt = tgt->tgt_tpgt_list; + while (cfgt != NULL) { + tagid_used[cfgt->tpgt_tag] = 1; + + if (strcmp(tpg_name, cfgt->tpgt_tpg_name) == 0) { + return (EEXIST); + } + + if (cfgt->tpgt_tag > tagid) { + tagid = cfgt->tpgt_tag; + } + + cfgt = cfgt->tpgt_next; + } + + if ((tpgt_tag > ISCSIT_DEFAULT_TPGT) && (tpgt_tag < MAXTAG) && + (tagid_used[tpgt_tag] == 0)) { + /* ok to use requested */ + tagid = tpgt_tag; + } else if (tagid == MAXTAG) { + /* + * The highest value is used, find an available id. + */ + tagid = ISCSIT_DEFAULT_TPGT + 1; + for (; tagid < MAXTAG; tagid++) { + if (tagid_used[tagid] == 0) { + break; + } + } + if (tagid >= MAXTAG) { + return (E2BIG); + } + } else { + /* next available ID */ + tagid++; + } + + ptr = calloc(1, sizeof (it_tpgt_t)); + if (!ptr) { + return (ENOMEM); + } + + (void) strlcpy(ptr->tpgt_tpg_name, tpg_name, + sizeof (ptr->tpgt_tpg_name)); + ptr->tpgt_generation = 1; + ptr->tpgt_tag = tagid; + + ptr->tpgt_next = tgt->tgt_tpgt_list; + tgt->tgt_tpgt_list = ptr; + tgt->tgt_tpgt_count++; + tgt->tgt_generation++; + + *tpgt = ptr; + + return (0); +} + +/* + * Function: it_tpgt_delete() + * + * Delete the target portal group tag represented by 'tpgt', where + * 'tpgt' is an existing is_tpgt_t structure within the target 'tgt'. + * The target portal group tag removal will not take effect until the + * modified configuration is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to the iSCSI target structure associated + * with the target portal group tag + * tpgt Pointer to a target portal group tag structure + */ +void +it_tpgt_delete(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t *tpgt) +{ + it_tpgt_t *ptr; + it_tpgt_t *prev = NULL; + + if (!cfg || !tgt || !tpgt) { + return; + } + + ptr = tgt->tgt_tpgt_list; + while (ptr) { + if (ptr->tpgt_tag == tpgt->tpgt_tag) { + break; + } + prev = ptr; + ptr = ptr->tpgt_next; + } + + if (!ptr) { + return; + } + + if (prev) { + prev->tpgt_next = ptr->tpgt_next; + } else { + tgt->tgt_tpgt_list = ptr->tpgt_next; + } + ptr->tpgt_next = NULL; + + tgt->tgt_tpgt_count--; + tgt->tgt_generation++; + + it_tpgt_free(ptr); +} + +/* + * Function: it_tpgt_free() + * + * Deallocates resources of an it_tpgt_t structure. If tpgt->next + * is not NULL, frees all members of the list. + */ +void +it_tpgt_free(it_tpgt_t *tpgt) +{ + it_tpgt_free_cmn(tpgt); +} + +/* + * Function: it_tpg_create() + * + * Allocate and create an it_tpg_t structure representing a new iSCSI + * target portal group. The new it_tpg_t structure is added to the global + * tpg list (cfg_tgt_list) in the it_config_t structure. The new target + * portal group will not be instantiated until the modified configuration + * is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tpg Pointer to the it_tpg_t structure representing + * the target portal group + * tpg_name Identifier for the target portal group + * portal_ip_port A string containing an appropriatedly formatted + * IP address:port. Both IPv4 and IPv6 addresses are + * permitted. This value becomes the first portal in + * the TPG -- applications can add additional values + * using it_portal_create() before committing the TPG. + * Return Values: + * 0 Success + * ENOMEM Cannot allocate resources + * EINVAL Invalid parameter + * EEXIST Requested portal in use by another target portal + * group + */ +int +it_tpg_create(it_config_t *cfg, it_tpg_t **tpg, char *tpg_name, + char *portal_ip_port) +{ + int ret; + it_tpg_t *ptr; + it_portal_t *portal = NULL; + + if (!cfg || !tpg || !tpg_name || !portal_ip_port) { + return (EINVAL); + } + + *tpg = NULL; + + ptr = cfg->config_tpg_list; + while (ptr) { + if (strcmp(tpg_name, ptr->tpg_name) == 0) { + break; + } + ptr = ptr->tpg_next; + } + + if (ptr) { + return (EEXIST); + } + + ptr = calloc(1, sizeof (it_tpg_t)); + if (!ptr) { + return (ENOMEM); + } + + ptr->tpg_generation = 1; + (void) strlcpy(ptr->tpg_name, tpg_name, sizeof (ptr->tpg_name)); + + /* create the portal */ + ret = it_portal_create(cfg, ptr, &portal, portal_ip_port); + if (ret != 0) { + free(ptr); + return (ret); + } + + ptr->tpg_next = cfg->config_tpg_list; + cfg->config_tpg_list = ptr; + cfg->config_tpg_count++; + + *tpg = ptr; + + return (0); +} + +/* + * Function: it_tpg_delete() + * + * Delete target portal group represented by 'tpg', where 'tpg' is an + * existing it_tpg_t structure within the global configuration 'cfg'. + * The target portal group removal will not take effect until the + * modified configuration is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tpg Pointer to the it_tpg_t structure representing + * the target portal group + * force Remove this target portal group even if it's + * associated with one or more targets. + * + * Return Values: + * 0 Success + * EINVAL Invalid parameter + * EBUSY Portal group associated with one or more targets. + */ +int +it_tpg_delete(it_config_t *cfg, it_tpg_t *tpg, boolean_t force) +{ + it_tpg_t *ptr; + it_tpg_t *prev = NULL; + it_tgt_t *tgt; + it_tpgt_t *tpgt; + it_tpgt_t *ntpgt; + + if (!cfg || !tpg) { + return (EINVAL); + } + + ptr = cfg->config_tpg_list; + while (ptr) { + if (strcmp(ptr->tpg_name, tpg->tpg_name) == 0) { + break; + } + prev = ptr; + ptr = ptr->tpg_next; + } + + if (!ptr) { + return (0); + } + + /* + * See if any targets are using this portal group. + * If there are, and the force flag is not set, fail. + */ + tgt = cfg->config_tgt_list; + while (tgt) { + tpgt = tgt->tgt_tpgt_list; + while (tpgt) { + ntpgt = tpgt->tpgt_next; + + if (strcmp(tpgt->tpgt_tpg_name, tpg->tpg_name) + == 0) { + if (!force) { + return (EBUSY); + } + it_tpgt_delete(cfg, tgt, tpgt); + } + + tpgt = ntpgt; + } + tgt = tgt->tgt_next; + } + + /* Now that it's not in use anywhere, remove the TPG */ + if (prev) { + prev->tpg_next = ptr->tpg_next; + } else { + cfg->config_tpg_list = ptr->tpg_next; + } + ptr->tpg_next = NULL; + + cfg->config_tpg_count--; + + it_tpg_free(ptr); + + return (0); +} + +/* + * Function: it_tpg_free() + * + * Deallocates resources associated with an it_tpg_t structure. + * If tpg->next is not NULL, frees all members of the list. + */ +void +it_tpg_free(it_tpg_t *tpg) +{ + it_tpg_free_cmn(tpg); +} + +/* + * Function: it_portal_create() + * + * Add an it_portal_t structure presenting a new portal to the specified + * target portal group. The change to the target portal group will not take + * effect until the modified configuration is committed by calling + * it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configration obtained from + * it_config_load() + * tpg Pointer to the it_tpg_t structure representing the + * target portal group + * portal Pointer to the it_portal_t structure representing + * the portal + * portal_ip_port A string containing an appropriately formatted + * IP address or IP address:port in either IPv4 or + * IPv6 format. + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter + * EEXIST Portal already configured for another portal group + */ +int +it_portal_create(it_config_t *cfg, it_tpg_t *tpg, it_portal_t **portal, + char *portal_ip_port) +{ + struct sockaddr_storage sa; + it_portal_t *ptr; + it_tpg_t *ctpg = NULL; + + if (!cfg || !tpg || !portal || !portal_ip_port) { + return (EINVAL); + } + + if ((it_common_convert_sa(portal_ip_port, &sa, ISCSI_LISTEN_PORT)) + == NULL) { + return (EINVAL); + } + + /* Check that this portal doesn't appear in any other tag */ + ctpg = cfg->config_tpg_list; + while (ctpg) { + ptr = ctpg->tpg_portal_list; + for (; ptr != NULL; ptr = ptr->next) { + if (it_sa_compare(&(ptr->portal_addr), &sa) != 0) { + continue; + } + + /* + * Existing in the same group is not an error, + * but don't add it again. + */ + if (strcmp(ctpg->tpg_name, tpg->tpg_name) == 0) { + return (0); + } else { + /* Not allowed */ + return (EEXIST); + } + } + ctpg = ctpg->tpg_next; + } + + ptr = calloc(1, sizeof (it_portal_t)); + if (!ptr) { + return (ENOMEM); + } + + (void) memcpy(&(ptr->portal_addr), &sa, + sizeof (struct sockaddr_storage)); + ptr->next = tpg->tpg_portal_list; + tpg->tpg_portal_list = ptr; + tpg->tpg_portal_count++; + tpg->tpg_generation++; + + return (0); +} + +/* + * Function: it_portal_delete() + * + * Remove the specified portal from the specified target portal group. + * The portal removal will not take effect until the modified configuration + * is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configration obtained from + * it_config_load() + * tpg Pointer to the it_tpg_t structure representing the + * target portal group + * portal Pointer to the it_portal_t structure representing + * the portal + */ +void +it_portal_delete(it_config_t *cfg, it_tpg_t *tpg, it_portal_t *portal) +{ + it_portal_t *ptr; + it_portal_t *prev; + + if (!cfg || !tpg || !portal) { + return; + } + + ptr = tpg->tpg_portal_list; + while (ptr) { + if (memcmp(&(ptr->portal_addr), &(portal->portal_addr), + sizeof (ptr->portal_addr)) == 0) { + break; + } + prev = ptr; + ptr = ptr->next; + } + + if (!ptr) { + return; + } + + if (prev) { + prev->next = ptr->next; + } else { + tpg->tpg_portal_list = ptr->next; + } + tpg->tpg_portal_count--; + tpg->tpg_generation++; + + free(ptr); +} + +/* + * Function: it_ini_create() + * + * Add an initiator context to the global configuration. The new + * initiator context will not be instantiated until the modified + * configuration is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configration obtained from + * it_config_load() + * ini Pointer to the it_ini_t structure representing + * the initiator context. + * ini_node_name The iSCSI node name of the remote initiator. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter. + * EFAULT Invalid initiator name + */ +int +it_ini_create(it_config_t *cfg, it_ini_t **ini, char *ini_node_name) +{ + it_ini_t *ptr; + + if (!cfg || !ini || !ini_node_name) { + return (EINVAL); + } + + /* + * Ensure this is a valid ini name + */ + if (!validate_iscsi_name(ini_node_name)) { + return (EFAULT); + } + + ptr = cfg->config_ini_list; + while (ptr) { + if (strcmp(ptr->ini_name, ini_node_name) == 0) { + break; + } + ptr = ptr->ini_next; + } + + if (ptr) { + return (EEXIST); + } + + ptr = calloc(1, sizeof (it_ini_t)); + if (!ptr) { + return (ENOMEM); + } + + (void) strlcpy(ptr->ini_name, ini_node_name, sizeof (ptr->ini_name)); + ptr->ini_generation = 1; + /* nvlist for props? */ + + ptr->ini_next = cfg->config_ini_list; + cfg->config_ini_list = ptr; + cfg->config_ini_count++; + + *ini = ptr; + + return (0); +} + +/* + * Function: it_ini_setprop() + * + * Validate the provided property list and set the initiator properties. + * If errlist is not NULL, returns detailed errors for each property + * that failed. The format for errorlist is key = property, + * value = error string. + * + * Parameters: + * + * ini The initiator being updated. + * proplist nvlist_t containing properties for this target. + * errlist (optional) nvlist_t of errors encountered when + * validating the properties. + * + * Return Values: + * 0 Success + * EINVAL Invalid property + * + */ +int +it_ini_setprop(it_ini_t *ini, nvlist_t *proplist, nvlist_t **errlist) +{ + int ret; + nvlist_t *iprops = NULL; + char *val = NULL; + + if (!ini || !proplist) { + return (EINVAL); + } + + if (errlist) { + (void) nvlist_alloc(errlist, 0, 0); + } + + /* + * copy the existing properties, merge, then validate + * the merged properties before committing them. + */ + if (ini->ini_properties) { + ret = nvlist_dup(ini->ini_properties, &iprops, 0); + } else { + ret = nvlist_alloc(&iprops, NV_UNIQUE_NAME, 0); + } + + if (ret == 0) { + ret = nvlist_merge(iprops, proplist, 0); + } + + /* unset chap username if requested */ + if ((nvlist_lookup_string(proplist, PROP_CHAP_USER, &val)) == 0) { + if (strcasecmp(val, "none") == 0) { + (void) nvlist_remove_all(iprops, PROP_CHAP_USER); + } + } + + /* base64 encode the CHAP secret, if it's changed */ + if ((nvlist_lookup_string(proplist, PROP_CHAP_SECRET, &val)) == 0) { + char bsecret[MAX_BASE64_LEN]; + + ret = it_val_pass(PROP_CHAP_SECRET, val, *errlist); + if (ret == 0) { + (void) memset(bsecret, 0, MAX_BASE64_LEN); + + ret = iscsi_binary_to_base64_str((uint8_t *)val, + strlen(val), bsecret, MAX_BASE64_LEN); + + if (ret == 0) { + /* replace the value in the nvlist */ + ret = nvlist_add_string(iprops, + PROP_CHAP_SECRET, bsecret); + } + } + } + + if (ret == 0) { + ret = it_validate_iniprops(iprops, *errlist); + } + + if (ret != 0) { + if (iprops) { + nvlist_free(iprops); + } + return (ret); + } + + if (ini->ini_properties) { + nvlist_free(ini->ini_properties); + } + ini->ini_properties = iprops; + + return (0); +} + +/* + * Function: it_ini_delete() + * + * Remove the specified initiator context from the global configuration. + * The removal will not take effect until the modified configuration is + * committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configration obtained from + * it_config_load() + * ini Pointer to the it_ini_t structure representing + * the initiator context. + */ +void +it_ini_delete(it_config_t *cfg, it_ini_t *ini) +{ + it_ini_t *ptr; + it_ini_t *prev = NULL; + + if (!cfg || !ini) { + return; + } + + ptr = cfg->config_ini_list; + while (ptr) { + if (strcmp(ptr->ini_name, ini->ini_name) == 0) { + break; + } + prev = ptr; + ptr = ptr->ini_next; + } + + if (!ptr) { + return; + } + + if (prev) { + prev->ini_next = ptr->ini_next; + } else { + cfg->config_ini_list = ptr->ini_next; + } + + ptr->ini_next = NULL; /* Only free this initiator */ + + cfg->config_ini_count--; + + it_ini_free(ptr); +} + +/* + * Function: it_ini_free() + * + * Deallocates resources of an it_ini_t structure. If ini->next is + * not NULL, frees all members of the list. + */ +void +it_ini_free(it_ini_t *ini) +{ + it_ini_free_cmn(ini); +} + +/* + * Goes through the target property list and validates + * each entry. If errs is non-NULL, will return explicit errors + * for each property that fails validation. + */ +static int +it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs) +{ + int errcnt = 0; + nvpair_t *nvp = NULL; + data_type_t nvtype; + char *name; + char *val; + char *auth = NULL; + + if (!nvl) { + return (0); + } + + while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { + name = nvpair_name(nvp); + nvtype = nvpair_type(nvp); + + if (!name) { + continue; + } + + val = NULL; + if (strcmp(name, PROP_TARGET_CHAP_USER) == 0) { + if (nvtype != DATA_TYPE_STRING) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + } else if (strcmp(name, PROP_TARGET_CHAP_SECRET) == 0) { + /* + * must be between 12 and 255 chars in cleartext. + * will be base64 encoded when it's set. + */ + if (nvtype == DATA_TYPE_STRING) { + (void) nvpair_value_string(nvp, &val); + } + + if (!val) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + } else if (strcmp(name, PROP_ALIAS) == 0) { + if (nvtype != DATA_TYPE_STRING) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + } else if (strcmp(name, PROP_AUTH) == 0) { + if (nvtype == DATA_TYPE_STRING) { + val = NULL; + (void) nvpair_value_string(nvp, &val); + } + + if (!val) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + if ((strcmp(val, PA_AUTH_NONE) != 0) && + (strcmp(val, PA_AUTH_CHAP) != 0) && + (strcmp(val, PA_AUTH_RADIUS) != 0) && + (strcmp(val, "default") != 0)) { + PROPERR(errs, val, gettext( + "must be none, chap, radius or default")); + errcnt++; + } + auth = val; + continue; + } else if (strcmp(name, PROP_OLD_TARGET_NAME) == 0) { + continue; + } else { + /* unrecognized property */ + PROPERR(errs, name, gettext("unrecognized property")); + errcnt++; + } + } + + if (errcnt) { + return (EINVAL); + } + + /* if auth is being set to default, remove from this nvlist */ + if (auth && (strcmp(auth, "default") == 0)) { + (void) nvlist_remove_all(nvl, PROP_AUTH); + } + + return (0); +} + +/* + * Goes through the config property list and validates + * each entry. If errs is non-NULL, will return explicit errors + * for each property that fails validation. + */ +static int +it_validate_configprops(nvlist_t *nvl, nvlist_t *errs) +{ + int errcnt = 0; + nvpair_t *nvp = NULL; + data_type_t nvtype; + char *name; + char *val; + struct sockaddr_storage sa; + char *auth = NULL; + + if (!nvl) { + return (0); + } + + while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { + name = nvpair_name(nvp); + nvtype = nvpair_type(nvp); + + if (!name) { + continue; + } + + val = NULL; + + /* prefetch string value as we mostly need it */ + if (nvtype == DATA_TYPE_STRING) { + (void) nvpair_value_string(nvp, &val); + } + + if (strcmp(name, PROP_ALIAS) == 0) { + if (!val) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + } + } else if (strcmp(name, PROP_AUTH) == 0) { + if (!val) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + + if ((strcmp(val, PA_AUTH_NONE) != 0) && + (strcmp(val, PA_AUTH_CHAP) != 0) && + (strcmp(val, PA_AUTH_RADIUS) != 0)) { + PROPERR(errs, PROP_AUTH, + gettext("must be none, chap or radius")); + errcnt++; + } + + auth = val; + + } else if (strcmp(name, PROP_ISNS_ENABLED) == 0) { + if (nvtype != DATA_TYPE_BOOLEAN_VALUE) { + PROPERR(errs, name, + gettext("must be a boolean value")); + errcnt++; + } + } else if (strcmp(name, PROP_ISNS_SERVER) == 0) { + char **arr = NULL; + uint32_t acount = 0; + + (void) nvlist_lookup_string_array(nvl, name, + &arr, &acount); + + while (acount > 0) { + if (strcasecmp(arr[acount - 1], "none") == 0) { + break; + } + if ((it_common_convert_sa(arr[acount - 1], + &sa, 0)) == NULL) { + PROPERR(errs, arr[acount - 1], + gettext("invalid address")); + errcnt++; + } + acount--; + } + + } else if (strcmp(name, PROP_RADIUS_SECRET) == 0) { + if (!val) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + } else if (strcmp(name, PROP_RADIUS_SERVER) == 0) { + struct sockaddr_storage sa; + + if (!val) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + + if ((it_common_convert_sa(val, &sa, + DEFAULT_RADIUS_PORT)) == NULL) { + PROPERR(errs, name, + gettext("invalid address")); + errcnt++; + } else { + /* + * rewrite this property to ensure port + * number is added. + */ + char *rad = NULL; + + if (sockaddr_to_str(&sa, &rad) == 0) { + (void) nvlist_add_string(nvl, + name, rad); + } + } + } else { + /* unrecognized property */ + PROPERR(errs, name, gettext("unrecognized property")); + errcnt++; + } + } + + /* + * if auth = radius, ensure radius server & secret are set. + */ + if (auth) { + if (strcmp(auth, PA_AUTH_RADIUS) == 0) { + /* need server & secret for radius */ + if (!nvlist_exists(nvl, PROP_RADIUS_SERVER)) { + PROPERR(errs, PROP_RADIUS_SERVER, + gettext("missing required property")); + errcnt++; + } + if (!nvlist_exists(nvl, PROP_RADIUS_SECRET)) { + PROPERR(errs, PROP_RADIUS_SECRET, + gettext("missing required property")); + errcnt++; + } + } + } + + if (errcnt) { + return (EINVAL); + } + + return (0); +} + +/* + * Goes through the ini property list and validates + * each entry. If errs is non-NULL, will return explicit errors + * for each property that fails validation. + */ +static int +it_validate_iniprops(nvlist_t *nvl, nvlist_t *errs) +{ + int errcnt = 0; + nvpair_t *nvp = NULL; + data_type_t nvtype; + char *name; + char *val; + + if (!nvl) { + return (0); + } + + while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { + name = nvpair_name(nvp); + nvtype = nvpair_type(nvp); + + if (!name) { + continue; + } + + if (strcmp(name, PROP_CHAP_USER) == 0) { + if (nvtype != DATA_TYPE_STRING) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + } else if (strcmp(name, PROP_CHAP_SECRET) == 0) { + /* + * must be between 12 and 255 chars in cleartext. + * will be base64 encoded when it's set. + */ + if (nvtype == DATA_TYPE_STRING) { + val = NULL; + (void) nvpair_value_string(nvp, &val); + } + + if (!val) { + PROPERR(errs, name, + gettext("must be a string value")); + errcnt++; + continue; + } + } else { + /* unrecognized property */ + PROPERR(errs, name, gettext("unrecognized property")); + errcnt++; + } + } + + if (errcnt) { + return (EINVAL); + } + + return (0); +} + +static int +it_iqn_generate(char *iqn_buf, int iqn_buf_len, char *opt_iqn_suffix) +{ + int ret; + uuid_t id; + char id_str[UUID_PRINTABLE_STRING_LENGTH]; + + uuid_generate_random(id); + uuid_unparse(id, id_str); + + if (opt_iqn_suffix) { + ret = snprintf(iqn_buf, iqn_buf_len, "iqn.1986-03.com.sun:" + "%02d:%s.%s", TARGET_NAME_VERS, id_str, opt_iqn_suffix); + } else { + ret = snprintf(iqn_buf, iqn_buf_len, "iqn.1986-03.com.sun:" + "%02d:%s", TARGET_NAME_VERS, id_str); + } + + if (ret > iqn_buf_len) { + return (1); + } + + return (0); +} + +static int +it_val_pass(char *name, char *val, nvlist_t *e) +{ + size_t sz; + + if (!name || !val) { + return (EINVAL); + } + + /* + * must be at least 12 chars and less than 256 chars cleartext. + */ + sz = strlen(val); + + /* + * Since we will be automatically encoding secrets we don't really + * need the prefix anymore. + */ + if (sz < 12) { + PROPERR(e, name, gettext("secret too short")); + } else if (sz > 255) { + PROPERR(e, name, gettext("secret too long")); + } else { + /* all is well */ + return (0); + } + + return (1); +} + +/* + * Function: validate_iscsi_name() + * + * Ensures the passed-in string is a valid IQN or EUI iSCSI name + * + */ +boolean_t +validate_iscsi_name(char *in_name) +{ + size_t in_len; + int i; + char month[3]; + + if (in_name == NULL) { + return (B_FALSE); + } + + in_len = strlen(in_name); + if (in_len < 12) { + return (B_FALSE); + } + + if (strncasecmp(in_name, "iqn.", 4) == 0) { + /* + * IQN names are iqn.yyyy-mm.<xxx> + */ + if ((!isdigit(in_name[4])) || + (!isdigit(in_name[5])) || + (!isdigit(in_name[6])) || + (!isdigit(in_name[7])) || + (in_name[8] != '-') || + (!isdigit(in_name[9])) || + (!isdigit(in_name[10])) || + (in_name[11] != '.')) { + return (B_FALSE); + } + + (void) strncpy(month, &(in_name[9]), 2); + month[2] = '\0'; + + i = atoi(month); + if ((i < 0) || (i > 12)) { + return (B_FALSE); + } + + /* Finally, validate the overall length, in wide chars */ + in_len = mbstowcs(NULL, in_name, 0); + if (in_len > ISCSI_NAME_LEN_MAX) { + return (B_FALSE); + } + } else if (strncasecmp(in_name, "eui.", 4) == 0) { + /* + * EUI names are "eui." + 16 hex chars + */ + if (in_len != 20) { + return (B_FALSE); + } + + for (i = 4; i < in_len; i++) { + if (!isxdigit(in_name[i])) { + return (B_FALSE); + } + } + } else { + return (B_FALSE); + } + + return (B_TRUE); +} diff --git a/usr/src/lib/libiscsit/common/libiscsit.h b/usr/src/lib/libiscsit/common/libiscsit.h new file mode 100644 index 0000000000..598a46a09c --- /dev/null +++ b/usr/src/lib/libiscsit/common/libiscsit.h @@ -0,0 +1,747 @@ +/* + * 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 _LIBISCSIT_H +#define _LIBISCSIT_H + +#ifndef _KERNEL +#include <libnvpair.h> +#include <sys/socket.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISCSIT_MODNAME "iscsit" +#define ISCSIT_NODE "/devices/pseudo/iscsit@0:iscsit" + +#define MAX_TPGT 256 +#define CFG_TPGTLIST "tpgt-list" + +/* + * Object Hierarchy + * + * _______________________ + * | | + * | iSCSI Target Config | + * | it_config_t | + * |_______________________| + * | | + * | | + * | | ________ ________ ________ + * | | | | | | | | + * | | | Target |-->| Target |-- - - -->| Target | + * | | |________| |________| |________| + * | | | + * | | | + * | | | + * | | | ______ ______ + * | | | | | | | + * | | +----->| TPGT |-- - - -->| TPGT | + * | | |______| |______| + * | | | | + * | +--+ | | + * | | _______ _______ | ______ | + * | | | | | |<--+ | |<--+ + * | +->| TPG |-->| TPG |-- - - -->| TPG | + * | |_______| |_______| |______| + * | + * | ___________ ___________ ___________ + * | | | | | | | + * +---->| Initiator |-->| Initiator |-- - - -->| Initiator | + * | Context | | Context | | Context | + * |___________| |___________| |___________| + * + * + * it_config_t includes a list of global properties + * + * Targets include a list of properties which override the global properties + * if set + * + * Initiators also include a list of properties but never inherit properties + * from the global config. + */ + +/* Maximum size of a Target Portal Group name */ +#define MAX_TPG_NAMELEN 256 /* XXX */ + +/* Maximum size of an iSCSI Target Node name */ +#define MAX_ISCSI_NODENAMELEN 256 /* XXX */ + +/* + * A target portal group tag is a binding between a target and a target + * portal group along with a numerical value associated with that binding. + * The numerical identifier is used as the 'target portal group tag' defined + * in RFC3720. + * + * tpgt_tpg_name The name of the target portal group associated with + * this target portal group tag. + * tpgt_generation Generation number which is incremented each time the + * structure changes. + * tpgt_next Next target portal group tag in th list of target portal + * group tags. If tpgt_next is NUL, then this is the last + * target portal group in the list. + * tpgt_tag A numerical identifier that uniquely identifies a + * target portal group within the associated target node. + */ +typedef struct it_tpgt_s { + char tpgt_tpg_name[MAX_TPG_NAMELEN]; + uint64_t tpgt_generation; + struct it_tpgt_s *tpgt_next; + uint16_t tpgt_tag; +} it_tpgt_t; + +/* + * An iSCSI target node is represented by an it_tgt_structure. Each + * target node includes a list of associated target portal group tags + * and a list of properties. + * + * tgt_name The iSCSI target node name in either IQN or EUI + * format (see RFC3720). + * tgt_generation Generation number which is incremented each time + * the structure changes. + * tgt_next Next target in the list of targets. If tgt_next + * is NULL, then this is the last target in the list. + * tgt_tpgt_list A linked list representing the current target + * portal group tags associated with this target. + * tgt_tpgt_count The number of currently defined target portal + * group tags. + * tgt_properties An nvlist representation of the properties + * associated with this target. This list can be + * manipulated using libnvpair(3lib), and should be + * validated and stored using it_tgt_setprop(). + * + * Target nvlist Properties: + * + * nvlist Key Type Valid Values + * -------------------------------------------------------------------- + * targetchapuser string any string or "none" to remove + * targetchapsecret string string of at least 12 characters + * but not more than 255 characters. + * secret will be base64 encoded when + * stored. + * alias string any string or "none" to remove + * auth string "radius", "chap", or "none" + * + */ +typedef struct it_tgt_s { + char tgt_name[MAX_ISCSI_NODENAMELEN]; + uint64_t tgt_generation; + struct it_tgt_s *tgt_next; + it_tpgt_t *tgt_tpgt_list; + uint32_t tgt_tpgt_count; + nvlist_t *tgt_properties; +} it_tgt_t; + +/* + * A target portal is represented by an IP address and a listening + * TCP port. + * + * portal_addr sockaddr_storage structure representing the + * IPv4 or IPv6 address and TCP port associated + * with the portal. + * portal_next Next portal in the list of portals. If + * portal_next is NULL, this is the last portal + * in the list. + */ +typedef struct it_portal_s { + struct sockaddr_storage portal_addr; + struct it_portal_s *next; +} it_portal_t; + +/* + * A portal is an IP address and TCP port and a portal group is a set + * of portals. Each defined portal belongs to exactly one portal group. + * Applications can associate a target portal group with a particular + * target using a target portal group name. Initiators can only connect + * to targets through the portals associated with the target's target + * portal group tags. + * + * tpg_name Identifier for the target portal group. + * tpg_generation Generation number which is incremented each + * time this structure changes. + * tpg_next Next target portal group in the list of target + * portal groups. If tpg_next is NULL, this is the + * last target portal group in the list. + * tpg_portal_count Number of it_portal_t structures in the list. + * tpg_portal_list Linked list of it_portal_t structures. + */ +typedef struct it_tpg_s { + char tpg_name[MAX_TPG_NAMELEN]; + uint64_t tpg_generation; + struct it_tpg_s *tpg_next; + uint32_t tpg_portal_count; + it_portal_t *tpg_portal_list; +} it_tpg_t; + +/* + * A context representing a remote iSCSI initiator node. The purpose + * of this structure is to maintain information specific to a remote + * initiator such as the CHAP username and CHAP secret. + * + * ini_name the iSCSI node name of the remote initiator. + * ini_generation Generation number which is incremented each + * time this structure changes. + * ini_next Next initiator in the list of initiators. + * If ini_next is NULL, this is the last initiator + * in the list. + * ini_properties Name/Value list containing the properties + * associated with the initiator context. This list + * can be manipulated using libnvpair(3lib), and should + * be validated and stored using it_ini_setprop(). + * + * Initiator nvlist Properties: + * + * nvlist Key Type Valid Values + * -------------------------------------------------------------------- + * chapuser string any string + * chapsecret string string of at least 12 characters + * but not more than 255 characters. + * secret will be base64 encoded when + * stored. + */ +typedef struct it_ini_s { + char ini_name[MAX_ISCSI_NODENAMELEN]; + uint64_t ini_generation; + struct it_ini_s *ini_next; + nvlist_t *ini_properties; +} it_ini_t; + + +/* + * This structure represents a complete configuration for the iscsit + * port provider. In addition to the global configuration, it_config_t + * includes lists of child objects including targets, target portal + * groups and initiator contexts. Each object includes a "generation" + * value which is used by the iscsit kernel driver to identify changes + * from one configuration update to the next. + * + * stmf_token A uint64_t that contains the value returned from a + * successful call to stmfGetProviderDataProt(3STMF). + * This token is used to verify that the configuration + * data persistently stored in COMSTAR has not been + * modified since this version was loaded. + * config_version Version number for this configuration structure + * config_tgt_list Linked list of target contexts representing the + * currently defined targets. Applications can add + * targets to or remove targets from this list using + * the it_tgt_create and it_tgt_delete functions. + * config_tgt_count The number of currently defined targets. + * config_tpg_list Linked list of target portal group contexts. + * Applications can add or remove target portal groups + * to/from this list using the it_tpg_create and + * it_tpg_delete functions. + * config_tpg_count The number of currently defined target portal groups + * config_ini_list Linked list of initiator contexts. Applications + * can add initiator contexts or remove initiator + * contexts from this list using the it_ini_create + * and it_ini_delete functions. + * config_ini_count The number of currently defined initiator contexts. + * config_global_properties + * Name/Value list representing the current global + * property settings. This list can be manipulated + * using libnvpair(3lib), and should be validated + * and stored using it_config_setprop(). + * config_isns_svr_list + * Linked list of currently defined iSNS servers. + * Applications can add or remove iSNS servers by + * using the it_config_setprop() function and changing + * the array of iSNS servers stored in the "isnsserver" + * property. + * config_isns_svr_count + * The number of currently defined iSNS servers. + * + * Global nvlist Properties: + * + * nvlist Key Type Valid Values + * -------------------------------------------------------------------- + * alias string any string + * auth string "radius", "chap", or "none" + * isns boolean B_TRUE, B_FALSE + * isnsserver string array Array of portal specifications of + * the form IPaddress:port. Port + * is optional; if not specified, the + * default iSNS port number of 3205 will + * be used. IPv6 addresses should + * be enclosed in square brackets '[' ']'. + * If "none" is specified, all defined + * iSNS servers will be removed from the + * configuration. + * radiusserver string IPaddress:port specification as + * described for 'isnsserver'. + * radiussecret string string of at least 12 characters + * but not more than 255 characters. + * secret will be base64 encoded when + * stored. + */ +typedef struct it_config_s { + uint64_t stmf_token; + uint32_t config_version; + it_tgt_t *config_tgt_list; + uint32_t config_tgt_count; + it_tpg_t *config_tpg_list; + uint32_t config_tpg_count; + it_ini_t *config_ini_list; + uint32_t config_ini_count; + it_portal_t *config_isns_svr_list; + uint32_t config_isns_svr_count; + nvlist_t *config_global_properties; +} it_config_t; + +/* + * Function: it_config_load() + * + * Allocate and create an it_config_t structure representing the + * current iSCSI configuration. This structure is compiled using + * the 'provider' data returned by stmfGetProviderData(). If there + * is no provider data associated with iscsit, the it_config_t + * structure will be set to a default configuration. + * + * Parameters: + * cfg A C representation of the current iSCSI configuration + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter + */ +int +it_config_load(it_config_t **cfg); + +/* + * Function: it_config_commit() + * + * Informs the iscsit service that the configuration has changed and + * commits the new configuration to persistent store by calling + * stmfSetProviderData. This function can be called multiple times + * during a configuration sequence if necessary. + * + * Parameters: + * cfg A C representation of the current iSCSI configuration + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid it_config_t structure + * STMF_ERROR_SERVICE_DATA_VERSION Configuration was updated by another + * client. See stmfSetProviderDataProt(). + */ +int +it_config_commit(it_config_t *cfg); + +/* + * Function: it_config_setprop() + * + * Validate the provided property list and set the global properties + * for iSCSI Target. If errlist is not NULL, returns detailed + * errors for each property that failed. The format for errorlist + * is key = property, value = error string. + * + * Parameters: + * + * cfg The current iSCSI configuration obtained from + * it_config_load() + * proplist nvlist_t containing properties for this target. + * errlist (optional) nvlist_t of errors encountered when + * validating the properties. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid property + * + */ +int +it_config_setprop(it_config_t *cfg, nvlist_t *proplist, nvlist_t **errlist); + +/* + * Function: it_config_free() + * + * Free any resources associated with the it_config_t structure. + * + * Parameters: + * cfg A C representation of the current iSCSI configuration + */ +void +it_config_free(it_config_t *cfg); + +/* + * Function: it_tgt_create() + * + * Allocate and create an it_tgt_t structure representing a new iSCSI + * target node. If tgt_name is NULL, then a unique target node name will + * be generated automatically. Otherwise, the value of tgt_name will be + * used as the target node name. The new it_tgt_t structure is added to + * the target list (cfg_tgt_list) in the configuration structure, and the + * new target will not be instantiated until the modified configuration + * is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to an iSCSI target structure + * tgt_name The target node name for the target to be created. + * The name must be in either IQN or EUI format. If + * this value is NULL, a node name will be generated + * automatically in IQN format. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter + * EEXIST The requested target node name is already configured + * EFAULT Invalid iSCSI target name + */ +int +it_tgt_create(it_config_t *cfg, it_tgt_t **tgt, char *tgt_name); + +/* + * Function: it_tgt_setprop() + * + * Validate the provided property list and set the properties for + * the specified target. If errlist is not NULL, returns detailed + * errors for each property that failed. The format for errorlist + * is key = property, value = error string. + * + * Parameters: + * + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to an iSCSI target structure + * proplist nvlist_t containing properties for this target. + * errlist (optional) nvlist_t of errors encountered when + * validating the properties. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid property + * + */ +int +it_tgt_setprop(it_config_t *cfg, it_tgt_t *tgt, nvlist_t *proplist, + nvlist_t **errlist); + + +/* + * Function: it_tgt_delete() + * + * Delete target represented by 'tgt', where 'tgt' is an existing + * it_tgt_t structure within the configuration 'cfg'. The target removal + * will not take effect until the modified configuration is committed + * by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to an iSCSI target structure + * force Set the target to offline before removing it from + * the config. If not specified, the operation will + * fail if the target is determined to be online. + * + * Return Values: + * 0 Success + * EBUSY Target is online + */ +int +it_tgt_delete(it_config_t *cfg, it_tgt_t *tgt, boolean_t force); + +/* + * Function: it_tpgt_create() + * + * Allocate and create an it_tpgt_t structure representing a new iSCSI + * target portal group tag. The new it_tpgt_t structure is added to the + * target tpgt list (tgt_tpgt_list) in the it_tgt_t structure. The new + * target portal group tag will not be instantiated until the modified + * configuration is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to the iSCSI target structure associated + * with the target portal group tag + * tpgt Pointer to a target portal group tag structure + * tpg_name The name of the TPG to be associated with this TPGT + * tpgt_tag 16-bit numerical identifier for this TPGT. Valid + * values are 2 through 65535. If tpgt_tag is '0', + * this function will assign an appropriate tag number. + * If tpgt_tag is != 0, and the requested number is + * unavailable, another value will be chosen. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter + * EEXIST Specified TPG is already associated with the target + * E2BIG All tag numbers already in use + */ +int +it_tpgt_create(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t **tpgt, + char *tpg_name, uint16_t tpgt_tag); + +/* + * Function: it_tpgt_delete() + * + * Delete the target portal group tag represented by 'tpgt', where + * 'tpgt' is an existing is_tpgt_t structure within the target 'tgt'. + * The target portal group tag removal will not take effect until the + * modified configuation is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tgt Pointer to the iSCSI target structure associated + * with the target portal group tag + * tpgt Pointer to a target portal group tag structure + */ +void +it_tpgt_delete(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t *tpgt); + +/* + * Function: it_tpg_create() + * + * Allocate and create an it_tpg_t structure representing a new iSCSI + * target portal group. The new it_tpg_t structure is added to the global + * tpg list (cfg_tgt_list) in the it_config_t structure. The new target + * portal group will not be instantiated until the modified configuration + * is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tpg Pointer to the it_tpg_t structure representing + * the target portal group + * tpg_name Identifier for the target portal group + * portal_ip_port A string containing an appropriatedly formatted + * IP address:port. Both IPv4 and IPv6 addresses are + * permitted. This value becomes the first portal in + * the TPG -- applications can add additional values + * using it_portal_create() before committing the TPG. + * Return Values: + * 0 Success + * ENOMEM Cannot allocate resources + * EINVAL Invalid parameter + * EEXIST Portal already configured for another portal group + * associated with this target. + */ +int +it_tpg_create(it_config_t *cfg, it_tpg_t **tpg, char *tpg_name, + char *portal_ip_port); + +/* + * Function: it_tpg_delete() + * + * Delete target portal group represented by 'tpg', where 'tpg' is an + * existing it_tpg_t structure within the global configuration 'cfg'. + * The target portal group removal will not take effect until the + * modified configuration is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configuration obtained from + * it_config_load() + * tpg Pointer to the it_tpg_t structure representing + * the target portal group + * force Remove this target portal group even if it's + * associated with one or more targets. + * + * Return Values: + * 0 Success + * EINVAL Invalid parameter + * EBUSY Portal group associated with one or more targets. + */ +int +it_tpg_delete(it_config_t *cfg, it_tpg_t *tpg, boolean_t force); + +/* + * Function: it_portal_create() + * + * Add an it_portal_t structure representing a new portal to the specified + * target portal group. The change to the target portal group will not take + * effect until the modified configuration is committed by calling + * it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configration obtained from + * it_config_load() + * tpg Pointer to the it_tpg_t structure representing the + * target portal group or "none" to remove + * portal Pointer to the it_portal_t structure representing + * the portal + * portal_ip_port A string containing an appropriately formatted + * IP address or IP address:port in either IPv4 or + * IPv6 format. + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter + * EEXIST Portal already configured for another portal group + */ +int +it_portal_create(it_config_t *cfg, it_tpg_t *tpg, it_portal_t **portal, + char *portal_ip_port); + +/* + * Function: it_portal_delete() + * + * Remove the specified portal from the specified target portal group. + * The portal removal will not take effect until the modified configuration + * is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configration obtained from + * it_config_load() + * tpg Pointer to the it_tpg_t structure representing the + * target portal group + * portal Pointer to the it_portal_t structure representing + * the portal + */ +void +it_portal_delete(it_config_t *cfg, it_tpg_t *tpg, it_portal_t *portal); + +/* + * Function: it_ini_create() + * + * Add an initiator context to the global configuration. The new + * initiator context will not be instantiated until the modified + * configuration is committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configration obtained from + * it_config_load() + * ini Pointer to the it_ini_t structure representing + * the initiator context. + * ini_node_name The iSCSI node name of the remote initiator. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid parameter. + * EEXIST Initiator already configured + * EFAULT Invalid initiator name + */ +int +it_ini_create(it_config_t *cfg, it_ini_t **ini, char *ini_node_name); + +/* + * Function: it_ini_setprop() + * + * Validate the provided property list and set the initiator properties. + * If errlist is not NULL, returns detailed errors for each property + * that failed. The format for errorlist is + * key = property, value = error string. + * + * Parameters: + * + * ini The initiator being updated. + * proplist nvlist_t containing properties for this target. + * errlist (optional) nvlist_t of errors encountered when + * validating the properties. + * + * Return Values: + * 0 Success + * ENOMEM Could not allocate resources + * EINVAL Invalid property + * + */ +int +it_ini_setprop(it_ini_t *ini, nvlist_t *proplist, nvlist_t **errlist); + +/* + * Function: it_ini_delete() + * + * Remove the specified initiator context from the global configuration. + * The removal will not take effect until the modified configuration is + * committed by calling it_config_commit(). + * + * Parameters: + * cfg The current iSCSI configration obtained from + * it_config_load() + * ini Pointer to the it_ini_t structure representing + * the initiator context. + */ +void +it_ini_delete(it_config_t *cfg, it_ini_t *ini); + +/* + * Function: it_config_free() + * + * Free any resources associated with the it_config_t structure. + * + * Parameters: + * cfg A C representation of the current iSCSI configuration + */ +void +it_config_free(it_config_t *cfg); + +/* + * Function: it_tgt_free() + * + * Frees an it_tgt_t structure. If tgt_next is not NULL, frees + * all structures in the list. + */ +void +it_tgt_free(it_tgt_t *tgt); + +/* + * Function: it_tpgt_free() + * + * Deallocates resources of an it_tpgt_t structure. If tpgt->next + * is not NULL, frees all members of the list. + */ +void +it_tpgt_free(it_tpgt_t *tpgt); + +/* + * Function: it_tpg_free() + * + * Deallocates resources associated with an it_tpg_t structure. + * If tpg->next is not NULL, frees all members of the list. + */ +void +it_tpg_free(it_tpg_t *tpg); + +/* + * Function: it_ini_free() + * + * Deallocates resources of an it_ini_t structure. If ini->next is + * not NULL, frees all members of the list. + */ +void +it_ini_free(it_ini_t *ini); + +/* + * Function: validate_iscsi_name() + * + * Ensures the passed-in string is a valid IQN or EUI iSCSI name + */ +boolean_t +validate_iscsi_name(char *in_name); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBISCSIT_H */ diff --git a/usr/src/lib/libiscsit/common/llib-liscsit b/usr/src/lib/libiscsit/common/llib-liscsit new file mode 100644 index 0000000000..8d9fc33604 --- /dev/null +++ b/usr/src/lib/libiscsit/common/llib-liscsit @@ -0,0 +1,30 @@ +/* + * 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. + */ + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <libiscsit.h> +#include <sys/iscsit/iscsit_common.h> diff --git a/usr/src/lib/libiscsit/common/mapfile-vers b/usr/src/lib/libiscsit/common/mapfile-vers new file mode 100644 index 0000000000..cceac0978d --- /dev/null +++ b/usr/src/lib/libiscsit/common/mapfile-vers @@ -0,0 +1,79 @@ +# +# 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. +# +SUNW_1.1 { + global: + it_config_load; + it_config_commit; + it_config_setprop; + it_config_free; + it_tgt_create; + it_tgt_setprop; + it_tgt_delete; + it_tgt_free; + it_tpg_create; + it_tpg_delete; + it_tpg_free; + it_ini_create; + it_ini_delete; + it_ini_setprop; + it_ini_free; + it_tpgt_create; + it_tpgt_delete; + it_tpgt_free; + it_portal_create; +}; + +SUNWprivate { + global: + it_config_to_nv; + it_nv_to_config; + it_nv_to_tgtlist; + it_tgtlist_to_nv; + it_tgt_to_nv; + it_nv_to_tgt; + it_tpgt_to_nv; + it_nv_to_tpgt; + it_tpgtlist_to_nv; + it_nv_to_tpgtlist; + it_tpg_to_nv; + it_nv_to_tpg; + it_tpglist_to_nv; + it_nv_to_tpglist; + it_ini_to_nv; + it_nv_to_ini; + it_inilist_to_nv; + it_nv_to_inilist; + it_common_convert_sa; + it_config_free_cmn; + it_tgt_free_cmn; + it_tpg_free_cmn; + it_ini_free_cmn; + it_tpgt_free_cmn; + sockaddr_to_str; + validate_iscsi_name; + local: + *; +}; + |