17978SPeter.Dunlap@Sun.COM /*
27978SPeter.Dunlap@Sun.COM  * CDDL HEADER START
37978SPeter.Dunlap@Sun.COM  *
47978SPeter.Dunlap@Sun.COM  * The contents of this file are subject to the terms of the
57978SPeter.Dunlap@Sun.COM  * Common Development and Distribution License (the "License").
67978SPeter.Dunlap@Sun.COM  * You may not use this file except in compliance with the License.
77978SPeter.Dunlap@Sun.COM  *
87978SPeter.Dunlap@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97978SPeter.Dunlap@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107978SPeter.Dunlap@Sun.COM  * See the License for the specific language governing permissions
117978SPeter.Dunlap@Sun.COM  * and limitations under the License.
127978SPeter.Dunlap@Sun.COM  *
137978SPeter.Dunlap@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147978SPeter.Dunlap@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157978SPeter.Dunlap@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167978SPeter.Dunlap@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177978SPeter.Dunlap@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187978SPeter.Dunlap@Sun.COM  *
197978SPeter.Dunlap@Sun.COM  * CDDL HEADER END
207978SPeter.Dunlap@Sun.COM  */
217978SPeter.Dunlap@Sun.COM /*
2212370SPeter.Gill@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237978SPeter.Dunlap@Sun.COM  */
247978SPeter.Dunlap@Sun.COM 
257978SPeter.Dunlap@Sun.COM #include <sys/types.h>
267978SPeter.Dunlap@Sun.COM #include <sys/stat.h>
277978SPeter.Dunlap@Sun.COM #include <ctype.h>
287978SPeter.Dunlap@Sun.COM #include <fcntl.h>
297978SPeter.Dunlap@Sun.COM #include <uuid/uuid.h>
307978SPeter.Dunlap@Sun.COM #include <errno.h>
317978SPeter.Dunlap@Sun.COM #include <unistd.h>
327978SPeter.Dunlap@Sun.COM #include <strings.h>
337978SPeter.Dunlap@Sun.COM #include <libintl.h>
3410849SSusan.Gleeson@Sun.COM #include <libscf.h>
357978SPeter.Dunlap@Sun.COM 
367978SPeter.Dunlap@Sun.COM #include <libstmf.h>
377978SPeter.Dunlap@Sun.COM #include <libiscsit.h>
387978SPeter.Dunlap@Sun.COM #include <sys/iscsi_protocol.h>
397978SPeter.Dunlap@Sun.COM #include <sys/iscsit/isns_protocol.h>
407978SPeter.Dunlap@Sun.COM 
417978SPeter.Dunlap@Sun.COM /* From iscsitgtd */
427978SPeter.Dunlap@Sun.COM #define	TARGET_NAME_VERS	2
437978SPeter.Dunlap@Sun.COM 
447978SPeter.Dunlap@Sun.COM /* this should be defined someplace central... */
457978SPeter.Dunlap@Sun.COM #define	ISCSI_NAME_LEN_MAX	223
467978SPeter.Dunlap@Sun.COM 
477978SPeter.Dunlap@Sun.COM /* max length of a base64 encoded secret */
487978SPeter.Dunlap@Sun.COM #define	MAX_BASE64_LEN		341
497978SPeter.Dunlap@Sun.COM 
507978SPeter.Dunlap@Sun.COM /* Default RADIUS server port */
517978SPeter.Dunlap@Sun.COM #define	DEFAULT_RADIUS_PORT	1812
527978SPeter.Dunlap@Sun.COM 
5310849SSusan.Gleeson@Sun.COM /* The iscsit SMF service FMRI */
5410849SSusan.Gleeson@Sun.COM #define	ISCSIT_FMRI		"svc:/network/iscsi/target:default"
557978SPeter.Dunlap@Sun.COM /*
567978SPeter.Dunlap@Sun.COM  * The kernel reserves target portal group tag value 1 as the default.
577978SPeter.Dunlap@Sun.COM  */
587978SPeter.Dunlap@Sun.COM #define	ISCSIT_DEFAULT_TPGT	1
597978SPeter.Dunlap@Sun.COM #define	MAXTAG			0xffff
607978SPeter.Dunlap@Sun.COM 
617978SPeter.Dunlap@Sun.COM /* helper for property list validation */
627978SPeter.Dunlap@Sun.COM #define	PROPERR(lst, key, value) { \
637978SPeter.Dunlap@Sun.COM 	if (lst) { \
647978SPeter.Dunlap@Sun.COM 		(void) nvlist_add_string(lst, key, value); \
657978SPeter.Dunlap@Sun.COM 	} \
667978SPeter.Dunlap@Sun.COM }
677978SPeter.Dunlap@Sun.COM 
687978SPeter.Dunlap@Sun.COM /* helper function declarations */
697978SPeter.Dunlap@Sun.COM static int
707978SPeter.Dunlap@Sun.COM it_iqn_generate(char *iqn_buf, int iqn_buf_len, char *opt_iqn_suffix);
717978SPeter.Dunlap@Sun.COM 
727978SPeter.Dunlap@Sun.COM static int
737978SPeter.Dunlap@Sun.COM it_val_pass(char *name, char *val, nvlist_t *e);
747978SPeter.Dunlap@Sun.COM 
757978SPeter.Dunlap@Sun.COM /* consider making validate funcs public */
767978SPeter.Dunlap@Sun.COM static int
777978SPeter.Dunlap@Sun.COM it_validate_configprops(nvlist_t *nvl, nvlist_t *errs);
787978SPeter.Dunlap@Sun.COM 
797978SPeter.Dunlap@Sun.COM static int
807978SPeter.Dunlap@Sun.COM it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs);
817978SPeter.Dunlap@Sun.COM 
827978SPeter.Dunlap@Sun.COM static int
837978SPeter.Dunlap@Sun.COM it_validate_iniprops(nvlist_t *nvl, nvlist_t *errs);
847978SPeter.Dunlap@Sun.COM 
8510849SSusan.Gleeson@Sun.COM static boolean_t
8610849SSusan.Gleeson@Sun.COM is_iscsit_enabled(void);
8710849SSusan.Gleeson@Sun.COM 
8810855SCharles.Ting@Sun.COM static void
8910855SCharles.Ting@Sun.COM iqnstr(char *s);
9010855SCharles.Ting@Sun.COM 
9110855SCharles.Ting@Sun.COM static void
9210855SCharles.Ting@Sun.COM euistr(char *s);
9310855SCharles.Ting@Sun.COM 
947978SPeter.Dunlap@Sun.COM /*
957978SPeter.Dunlap@Sun.COM  * Function:  it_config_load()
967978SPeter.Dunlap@Sun.COM  *
977978SPeter.Dunlap@Sun.COM  * Allocate and create an it_config_t structure representing the
987978SPeter.Dunlap@Sun.COM  * current iSCSI configuration.  This structure is compiled using
997978SPeter.Dunlap@Sun.COM  * the 'provider' data returned by stmfGetProviderData().  If there
1007978SPeter.Dunlap@Sun.COM  * is no provider data associated with iscsit, the it_config_t
1017978SPeter.Dunlap@Sun.COM  * structure will be set to a default configuration.
1027978SPeter.Dunlap@Sun.COM  *
1037978SPeter.Dunlap@Sun.COM  * Parameters:
1047978SPeter.Dunlap@Sun.COM  *    cfg	A C representation of the current iSCSI configuration
1057978SPeter.Dunlap@Sun.COM  *
1067978SPeter.Dunlap@Sun.COM  * Return Values:
1077978SPeter.Dunlap@Sun.COM  *    0		Success
1087978SPeter.Dunlap@Sun.COM  *    ENOMEM	Could not allocate resources
1097978SPeter.Dunlap@Sun.COM  *    EINVAL	Invalid parameter
1107978SPeter.Dunlap@Sun.COM  */
1117978SPeter.Dunlap@Sun.COM int
1127978SPeter.Dunlap@Sun.COM it_config_load(it_config_t **cfg)
1137978SPeter.Dunlap@Sun.COM {
1147978SPeter.Dunlap@Sun.COM 	int		ret = 0;
1157978SPeter.Dunlap@Sun.COM 	nvlist_t	*cfg_nv = NULL;
1167978SPeter.Dunlap@Sun.COM 	it_config_t	*newcfg = NULL;
1177978SPeter.Dunlap@Sun.COM 	uint64_t	stmf_token = 0;
1187978SPeter.Dunlap@Sun.COM 
1197978SPeter.Dunlap@Sun.COM 	if (!cfg) {
1207978SPeter.Dunlap@Sun.COM 		return (EINVAL);
1217978SPeter.Dunlap@Sun.COM 	}
1227978SPeter.Dunlap@Sun.COM 
1237978SPeter.Dunlap@Sun.COM 	*cfg = NULL;
1247978SPeter.Dunlap@Sun.COM 
1257978SPeter.Dunlap@Sun.COM 	ret = stmfGetProviderDataProt(ISCSIT_MODNAME, &cfg_nv,
1267978SPeter.Dunlap@Sun.COM 	    STMF_PORT_PROVIDER_TYPE, &stmf_token);
1277978SPeter.Dunlap@Sun.COM 
1287978SPeter.Dunlap@Sun.COM 	if ((ret == STMF_STATUS_SUCCESS) ||
1297978SPeter.Dunlap@Sun.COM 	    (ret == STMF_ERROR_NOT_FOUND)) {
1307978SPeter.Dunlap@Sun.COM 		/*
1317978SPeter.Dunlap@Sun.COM 		 * If not initialized yet, return empty it_config_t
1327978SPeter.Dunlap@Sun.COM 		 * Else, convert nvlist to struct
1337978SPeter.Dunlap@Sun.COM 		 */
1347978SPeter.Dunlap@Sun.COM 		ret = it_nv_to_config(cfg_nv, &newcfg);
1357978SPeter.Dunlap@Sun.COM 	}
1367978SPeter.Dunlap@Sun.COM 
1377978SPeter.Dunlap@Sun.COM 	if (ret == 0) {
1387978SPeter.Dunlap@Sun.COM 		newcfg->stmf_token = stmf_token;
1397978SPeter.Dunlap@Sun.COM 		*cfg = newcfg;
1407978SPeter.Dunlap@Sun.COM 	}
1417978SPeter.Dunlap@Sun.COM 
14210149SCharles.Ting@Sun.COM 	if (cfg_nv) {
14310149SCharles.Ting@Sun.COM 		nvlist_free(cfg_nv);
14410149SCharles.Ting@Sun.COM 	}
14510149SCharles.Ting@Sun.COM 
1467978SPeter.Dunlap@Sun.COM 	return (ret);
1477978SPeter.Dunlap@Sun.COM }
1487978SPeter.Dunlap@Sun.COM 
1497978SPeter.Dunlap@Sun.COM /*
1507978SPeter.Dunlap@Sun.COM  * Function:  it_config_commit()
1517978SPeter.Dunlap@Sun.COM  *
1527978SPeter.Dunlap@Sun.COM  * Informs the iscsit service that the configuration has changed and
1537978SPeter.Dunlap@Sun.COM  * commits the new configuration to persistent store by calling
1547978SPeter.Dunlap@Sun.COM  * stmfSetProviderData.  This function can be called multiple times
1557978SPeter.Dunlap@Sun.COM  * during a configuration sequence if necessary.
1567978SPeter.Dunlap@Sun.COM  *
1577978SPeter.Dunlap@Sun.COM  * Parameters:
1587978SPeter.Dunlap@Sun.COM  *    cfg	A C representation of the current iSCSI configuration
1597978SPeter.Dunlap@Sun.COM  *
1607978SPeter.Dunlap@Sun.COM  * Return Values:
1617978SPeter.Dunlap@Sun.COM  *    0		Success
1627978SPeter.Dunlap@Sun.COM  *    ENOMEM	Could not allocate resources
1637978SPeter.Dunlap@Sun.COM  *    EINVAL	Invalid it_config_t structure
1647978SPeter.Dunlap@Sun.COM  *    TBD	ioctl() failed
1657978SPeter.Dunlap@Sun.COM  *    TBD	could not save config to STMF
1667978SPeter.Dunlap@Sun.COM  */
1677978SPeter.Dunlap@Sun.COM int
1687978SPeter.Dunlap@Sun.COM it_config_commit(it_config_t *cfg)
1697978SPeter.Dunlap@Sun.COM {
1707978SPeter.Dunlap@Sun.COM 	int			ret;
1717978SPeter.Dunlap@Sun.COM 	nvlist_t		*cfgnv = NULL;
1727978SPeter.Dunlap@Sun.COM 	char			*packednv = NULL;
1737978SPeter.Dunlap@Sun.COM 	int			iscsit_fd = -1;
1747978SPeter.Dunlap@Sun.COM 	size_t			pnv_size;
1757978SPeter.Dunlap@Sun.COM 	iscsit_ioc_set_config_t	iop;
1767978SPeter.Dunlap@Sun.COM 	it_tgt_t		*tgtp;
1777978SPeter.Dunlap@Sun.COM 
1787978SPeter.Dunlap@Sun.COM 	if (!cfg) {
1797978SPeter.Dunlap@Sun.COM 		return (EINVAL);
1807978SPeter.Dunlap@Sun.COM 	}
1817978SPeter.Dunlap@Sun.COM 
1827978SPeter.Dunlap@Sun.COM 	ret = it_config_to_nv(cfg, &cfgnv);
1837978SPeter.Dunlap@Sun.COM 	if (ret == 0) {
1847978SPeter.Dunlap@Sun.COM 		ret = nvlist_size(cfgnv, &pnv_size, NV_ENCODE_NATIVE);
1857978SPeter.Dunlap@Sun.COM 	}
1867978SPeter.Dunlap@Sun.COM 
18710849SSusan.Gleeson@Sun.COM 	/*
18810849SSusan.Gleeson@Sun.COM 	 * If the iscsit service is enabled, send the changes to the
18910849SSusan.Gleeson@Sun.COM 	 * kernel first.  Kernel will be the final sanity check before
19010849SSusan.Gleeson@Sun.COM 	 * the config is saved persistently.
19110849SSusan.Gleeson@Sun.COM 	 *
19210849SSusan.Gleeson@Sun.COM 	 * This somewhat leaves open the simultaneous-change hole
19310849SSusan.Gleeson@Sun.COM 	 * that STMF was trying to solve, but is a better sanity
19410849SSusan.Gleeson@Sun.COM 	 * check and allows for graceful handling of target renames.
19510849SSusan.Gleeson@Sun.COM 	 */
19610849SSusan.Gleeson@Sun.COM 	if ((ret == 0) && is_iscsit_enabled()) {
1977978SPeter.Dunlap@Sun.COM 		packednv = malloc(pnv_size);
1987978SPeter.Dunlap@Sun.COM 		if (!packednv) {
1997978SPeter.Dunlap@Sun.COM 			ret = ENOMEM;
2007978SPeter.Dunlap@Sun.COM 		} else {
2017978SPeter.Dunlap@Sun.COM 			ret = nvlist_pack(cfgnv, &packednv, &pnv_size,
2027978SPeter.Dunlap@Sun.COM 			    NV_ENCODE_NATIVE, 0);
2037978SPeter.Dunlap@Sun.COM 		}
2047978SPeter.Dunlap@Sun.COM 
20510849SSusan.Gleeson@Sun.COM 		if (ret == 0) {
20610849SSusan.Gleeson@Sun.COM 			iscsit_fd = open(ISCSIT_NODE, O_RDWR|O_EXCL);
20710849SSusan.Gleeson@Sun.COM 			if (iscsit_fd != -1) {
20810849SSusan.Gleeson@Sun.COM 				iop.set_cfg_vers = ISCSIT_API_VERS0;
20910849SSusan.Gleeson@Sun.COM 				iop.set_cfg_pnvlist = packednv;
21010849SSusan.Gleeson@Sun.COM 				iop.set_cfg_pnvlist_len = pnv_size;
21110849SSusan.Gleeson@Sun.COM 				if ((ioctl(iscsit_fd, ISCSIT_IOC_SET_CONFIG,
21210849SSusan.Gleeson@Sun.COM 				    &iop)) != 0) {
21310849SSusan.Gleeson@Sun.COM 					ret = errno;
21410849SSusan.Gleeson@Sun.COM 				}
21510849SSusan.Gleeson@Sun.COM 
21610849SSusan.Gleeson@Sun.COM 				(void) close(iscsit_fd);
21710849SSusan.Gleeson@Sun.COM 			} else {
21810849SSusan.Gleeson@Sun.COM 				ret = errno;
21910849SSusan.Gleeson@Sun.COM 			}
22010849SSusan.Gleeson@Sun.COM 		}
22110849SSusan.Gleeson@Sun.COM 
22210849SSusan.Gleeson@Sun.COM 		if (packednv != NULL) {
22310849SSusan.Gleeson@Sun.COM 			free(packednv);
2247978SPeter.Dunlap@Sun.COM 		}
2257978SPeter.Dunlap@Sun.COM 	}
2267978SPeter.Dunlap@Sun.COM 
2277978SPeter.Dunlap@Sun.COM 	/*
2287978SPeter.Dunlap@Sun.COM 	 * Before saving the config persistently, remove any
2297978SPeter.Dunlap@Sun.COM 	 * PROP_OLD_TARGET_NAME entries.  This is only interesting to
2307978SPeter.Dunlap@Sun.COM 	 * the active service.
2317978SPeter.Dunlap@Sun.COM 	 */
2327978SPeter.Dunlap@Sun.COM 	if (ret == 0) {
23310849SSusan.Gleeson@Sun.COM 		boolean_t	changed = B_FALSE;
23410849SSusan.Gleeson@Sun.COM 
2357978SPeter.Dunlap@Sun.COM 		tgtp = cfg->config_tgt_list;
2367978SPeter.Dunlap@Sun.COM 		for (; tgtp != NULL; tgtp = tgtp->tgt_next) {
2377978SPeter.Dunlap@Sun.COM 			if (!tgtp->tgt_properties) {
2387978SPeter.Dunlap@Sun.COM 				continue;
2397978SPeter.Dunlap@Sun.COM 			}
2407978SPeter.Dunlap@Sun.COM 			if (nvlist_exists(tgtp->tgt_properties,
2417978SPeter.Dunlap@Sun.COM 			    PROP_OLD_TARGET_NAME)) {
2427978SPeter.Dunlap@Sun.COM 				(void) nvlist_remove_all(tgtp->tgt_properties,
2437978SPeter.Dunlap@Sun.COM 				    PROP_OLD_TARGET_NAME);
24410849SSusan.Gleeson@Sun.COM 				changed = B_TRUE;
2457978SPeter.Dunlap@Sun.COM 			}
2467978SPeter.Dunlap@Sun.COM 		}
24710849SSusan.Gleeson@Sun.COM 
24810849SSusan.Gleeson@Sun.COM 		if (changed) {
24910849SSusan.Gleeson@Sun.COM 			/* rebuild the config nvlist */
25010849SSusan.Gleeson@Sun.COM 			nvlist_free(cfgnv);
25110849SSusan.Gleeson@Sun.COM 			cfgnv = NULL;
25210849SSusan.Gleeson@Sun.COM 			ret = it_config_to_nv(cfg, &cfgnv);
25310849SSusan.Gleeson@Sun.COM 		}
2547978SPeter.Dunlap@Sun.COM 	}
2557978SPeter.Dunlap@Sun.COM 
2567978SPeter.Dunlap@Sun.COM 	/*
2577978SPeter.Dunlap@Sun.COM 	 * stmfGetProviderDataProt() checks to ensure
2587978SPeter.Dunlap@Sun.COM 	 * that the config data hasn't changed since we fetched it.
2597978SPeter.Dunlap@Sun.COM 	 *
2607978SPeter.Dunlap@Sun.COM 	 * The kernel now has a version we need to save persistently.
2617978SPeter.Dunlap@Sun.COM 	 * CLI will 'do the right thing' and warn the user if it
2627978SPeter.Dunlap@Sun.COM 	 * gets STMF_ERROR_PROV_DATA_STALE.  We'll try once to revert
2637978SPeter.Dunlap@Sun.COM 	 * the kernel to the persistently saved data, but ultimately,
2647978SPeter.Dunlap@Sun.COM 	 * it's up to the administrator to validate things are as they
2657978SPeter.Dunlap@Sun.COM 	 * want them to be.
2667978SPeter.Dunlap@Sun.COM 	 */
2677978SPeter.Dunlap@Sun.COM 	if (ret == 0) {
2687978SPeter.Dunlap@Sun.COM 		ret = stmfSetProviderDataProt(ISCSIT_MODNAME, cfgnv,
2697978SPeter.Dunlap@Sun.COM 		    STMF_PORT_PROVIDER_TYPE, &(cfg->stmf_token));
2707978SPeter.Dunlap@Sun.COM 
2717978SPeter.Dunlap@Sun.COM 		if (ret == STMF_STATUS_SUCCESS) {
2727978SPeter.Dunlap@Sun.COM 			ret = 0;
2737978SPeter.Dunlap@Sun.COM 		} else if (ret == STMF_ERROR_NOMEM) {
2747978SPeter.Dunlap@Sun.COM 			ret = ENOMEM;
2757978SPeter.Dunlap@Sun.COM 		} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
2767978SPeter.Dunlap@Sun.COM 			int		st;
2777978SPeter.Dunlap@Sun.COM 			it_config_t	*rcfg = NULL;
2787978SPeter.Dunlap@Sun.COM 
2797978SPeter.Dunlap@Sun.COM 			st = it_config_load(&rcfg);
2807978SPeter.Dunlap@Sun.COM 			if (st == 0) {
2817978SPeter.Dunlap@Sun.COM 				(void) it_config_commit(rcfg);
2827978SPeter.Dunlap@Sun.COM 				it_config_free(rcfg);
2837978SPeter.Dunlap@Sun.COM 			}
2847978SPeter.Dunlap@Sun.COM 		}
2857978SPeter.Dunlap@Sun.COM 	}
2867978SPeter.Dunlap@Sun.COM 
2877978SPeter.Dunlap@Sun.COM 	if (cfgnv) {
2887978SPeter.Dunlap@Sun.COM 		nvlist_free(cfgnv);
2897978SPeter.Dunlap@Sun.COM 	}
2907978SPeter.Dunlap@Sun.COM 
2917978SPeter.Dunlap@Sun.COM 	return (ret);
2927978SPeter.Dunlap@Sun.COM }
2937978SPeter.Dunlap@Sun.COM 
2947978SPeter.Dunlap@Sun.COM /*
2957978SPeter.Dunlap@Sun.COM  * Function:  it_config_setprop()
2967978SPeter.Dunlap@Sun.COM  *
2977978SPeter.Dunlap@Sun.COM  * Validate the provided property list and set the global properties
2987978SPeter.Dunlap@Sun.COM  * for iSCSI Target.  If errlist is not NULL, returns detailed
2997978SPeter.Dunlap@Sun.COM  * errors for each property that failed.  The format for errorlist
3007978SPeter.Dunlap@Sun.COM  * is key = property, value = error string.
3017978SPeter.Dunlap@Sun.COM  *
3027978SPeter.Dunlap@Sun.COM  * Parameters:
3037978SPeter.Dunlap@Sun.COM  *
3047978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configuration obtained from
3057978SPeter.Dunlap@Sun.COM  *			it_config_load()
3067978SPeter.Dunlap@Sun.COM  *    proplist		nvlist_t containing properties for this target.
3077978SPeter.Dunlap@Sun.COM  *    errlist		(optional)  nvlist_t of errors encountered when
3087978SPeter.Dunlap@Sun.COM  *                      validating the properties.
3097978SPeter.Dunlap@Sun.COM  *
3107978SPeter.Dunlap@Sun.COM  * Return Values:
3117978SPeter.Dunlap@Sun.COM  *    0			Success
3127978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid property
3137978SPeter.Dunlap@Sun.COM  *
3147978SPeter.Dunlap@Sun.COM  */
3157978SPeter.Dunlap@Sun.COM int
3167978SPeter.Dunlap@Sun.COM it_config_setprop(it_config_t *cfg, nvlist_t *proplist, nvlist_t **errlist)
3177978SPeter.Dunlap@Sun.COM {
3187978SPeter.Dunlap@Sun.COM 	int		ret;
31911514SPeter.Gill@Sun.COM 	nvlist_t	*errs = NULL;
3207978SPeter.Dunlap@Sun.COM 	it_portal_t	*isns = NULL;
3217978SPeter.Dunlap@Sun.COM 	it_portal_t	*pnext = NULL;
3227978SPeter.Dunlap@Sun.COM 	it_portal_t	*newisnslist = NULL;
3237978SPeter.Dunlap@Sun.COM 	char		**arr;
3247978SPeter.Dunlap@Sun.COM 	uint32_t	count;
3257978SPeter.Dunlap@Sun.COM 	uint32_t	newcount;
3267978SPeter.Dunlap@Sun.COM 	nvlist_t	*cprops = NULL;
3277978SPeter.Dunlap@Sun.COM 	char		*val = NULL;
3287978SPeter.Dunlap@Sun.COM 
3297978SPeter.Dunlap@Sun.COM 	if (!cfg || !proplist) {
3307978SPeter.Dunlap@Sun.COM 		return (EINVAL);
3317978SPeter.Dunlap@Sun.COM 	}
3327978SPeter.Dunlap@Sun.COM 
3337978SPeter.Dunlap@Sun.COM 	if (errlist) {
33411514SPeter.Gill@Sun.COM 		(void) nvlist_alloc(&errs, 0, 0);
33511514SPeter.Gill@Sun.COM 		*errlist = errs;
3367978SPeter.Dunlap@Sun.COM 	}
3377978SPeter.Dunlap@Sun.COM 
3387978SPeter.Dunlap@Sun.COM 	/*
3397978SPeter.Dunlap@Sun.COM 	 * copy the existing properties, merge, then validate
3407978SPeter.Dunlap@Sun.COM 	 * the merged properties before committing them.
3417978SPeter.Dunlap@Sun.COM 	 */
3427978SPeter.Dunlap@Sun.COM 	if (cfg->config_global_properties) {
3437978SPeter.Dunlap@Sun.COM 		ret = nvlist_dup(cfg->config_global_properties, &cprops, 0);
3447978SPeter.Dunlap@Sun.COM 	} else {
3457978SPeter.Dunlap@Sun.COM 		ret = nvlist_alloc(&cprops, NV_UNIQUE_NAME, 0);
3467978SPeter.Dunlap@Sun.COM 	}
3477978SPeter.Dunlap@Sun.COM 
34811702SPeter.Gill@Sun.COM 	if (ret != 0) {
34911702SPeter.Gill@Sun.COM 		return (ret);
35011702SPeter.Gill@Sun.COM 	}
35111702SPeter.Gill@Sun.COM 
35211702SPeter.Gill@Sun.COM 	ret = nvlist_merge(cprops, proplist, 0);
35311702SPeter.Gill@Sun.COM 	if (ret != 0) {
35411702SPeter.Gill@Sun.COM 		nvlist_free(cprops);
35511702SPeter.Gill@Sun.COM 		return (ret);
35611702SPeter.Gill@Sun.COM 	}
35711702SPeter.Gill@Sun.COM 
35811702SPeter.Gill@Sun.COM 	/*
35911702SPeter.Gill@Sun.COM 	 * base64 encode the radius secret, if it's changed.
36011702SPeter.Gill@Sun.COM 	 */
3617978SPeter.Dunlap@Sun.COM 	val = NULL;
3627978SPeter.Dunlap@Sun.COM 	(void) nvlist_lookup_string(proplist, PROP_RADIUS_SECRET, &val);
3637978SPeter.Dunlap@Sun.COM 	if (val) {
3647978SPeter.Dunlap@Sun.COM 		char		bsecret[MAX_BASE64_LEN];
3657978SPeter.Dunlap@Sun.COM 
36611514SPeter.Gill@Sun.COM 		ret = it_val_pass(PROP_RADIUS_SECRET, val, errs);
3677978SPeter.Dunlap@Sun.COM 
3687978SPeter.Dunlap@Sun.COM 		if (ret == 0) {
3697978SPeter.Dunlap@Sun.COM 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
3707978SPeter.Dunlap@Sun.COM 
3717978SPeter.Dunlap@Sun.COM 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
3727978SPeter.Dunlap@Sun.COM 			    strlen(val), bsecret, MAX_BASE64_LEN);
3737978SPeter.Dunlap@Sun.COM 
3747978SPeter.Dunlap@Sun.COM 			if (ret == 0) {
3757978SPeter.Dunlap@Sun.COM 				/* replace the value in the nvlist */
37611702SPeter.Gill@Sun.COM 				ret = nvlist_add_string(cprops,
3777978SPeter.Dunlap@Sun.COM 				    PROP_RADIUS_SECRET, bsecret);
3787978SPeter.Dunlap@Sun.COM 			}
3797978SPeter.Dunlap@Sun.COM 		}
3807978SPeter.Dunlap@Sun.COM 	}
3817978SPeter.Dunlap@Sun.COM 
38211702SPeter.Gill@Sun.COM 	if (ret != 0) {
38311702SPeter.Gill@Sun.COM 		nvlist_free(cprops);
38411702SPeter.Gill@Sun.COM 		return (ret);
3857978SPeter.Dunlap@Sun.COM 	}
3867978SPeter.Dunlap@Sun.COM 
3877978SPeter.Dunlap@Sun.COM 	/* see if we need to remove the radius server setting */
3887978SPeter.Dunlap@Sun.COM 	val = NULL;
3897978SPeter.Dunlap@Sun.COM 	(void) nvlist_lookup_string(cprops, PROP_RADIUS_SERVER, &val);
3907978SPeter.Dunlap@Sun.COM 	if (val && (strcasecmp(val, "none") == 0)) {
3917978SPeter.Dunlap@Sun.COM 		(void) nvlist_remove_all(cprops, PROP_RADIUS_SERVER);
3927978SPeter.Dunlap@Sun.COM 	}
3937978SPeter.Dunlap@Sun.COM 
3947978SPeter.Dunlap@Sun.COM 	/* and/or remove the alias */
3957978SPeter.Dunlap@Sun.COM 	val = NULL;
3967978SPeter.Dunlap@Sun.COM 	(void) nvlist_lookup_string(cprops, PROP_ALIAS, &val);
3977978SPeter.Dunlap@Sun.COM 	if (val && (strcasecmp(val, "none") == 0)) {
3987978SPeter.Dunlap@Sun.COM 		(void) nvlist_remove_all(cprops, PROP_ALIAS);
3997978SPeter.Dunlap@Sun.COM 	}
4007978SPeter.Dunlap@Sun.COM 
40111702SPeter.Gill@Sun.COM 	ret = it_validate_configprops(cprops, errs);
4027978SPeter.Dunlap@Sun.COM 	if (ret != 0) {
4037978SPeter.Dunlap@Sun.COM 		if (cprops) {
4047978SPeter.Dunlap@Sun.COM 			nvlist_free(cprops);
4057978SPeter.Dunlap@Sun.COM 		}
4067978SPeter.Dunlap@Sun.COM 		return (ret);
4077978SPeter.Dunlap@Sun.COM 	}
4087978SPeter.Dunlap@Sun.COM 
4097978SPeter.Dunlap@Sun.COM 	/*
4107978SPeter.Dunlap@Sun.COM 	 * Update iSNS server list, if exists in provided property list.
4117978SPeter.Dunlap@Sun.COM 	 */
4127978SPeter.Dunlap@Sun.COM 	ret = nvlist_lookup_string_array(proplist, PROP_ISNS_SERVER,
4137978SPeter.Dunlap@Sun.COM 	    &arr, &count);
4147978SPeter.Dunlap@Sun.COM 
4157978SPeter.Dunlap@Sun.COM 	if (ret == 0) {
4167978SPeter.Dunlap@Sun.COM 		/* special case:  if "none", remove all defined */
4177978SPeter.Dunlap@Sun.COM 		if (strcasecmp(arr[0], "none") != 0) {
4187978SPeter.Dunlap@Sun.COM 			ret = it_array_to_portallist(arr, count,
4197978SPeter.Dunlap@Sun.COM 			    ISNS_DEFAULT_SERVER_PORT, &newisnslist, &newcount);
4207978SPeter.Dunlap@Sun.COM 		} else {
4217978SPeter.Dunlap@Sun.COM 			newisnslist = NULL;
4227978SPeter.Dunlap@Sun.COM 			newcount = 0;
4237978SPeter.Dunlap@Sun.COM 			(void) nvlist_remove_all(cprops, PROP_ISNS_SERVER);
4247978SPeter.Dunlap@Sun.COM 		}
4257978SPeter.Dunlap@Sun.COM 
4267978SPeter.Dunlap@Sun.COM 		if (ret == 0) {
4277978SPeter.Dunlap@Sun.COM 			isns = cfg->config_isns_svr_list;
4287978SPeter.Dunlap@Sun.COM 			while (isns) {
42912370SPeter.Gill@Sun.COM 				pnext = isns->portal_next;
4307978SPeter.Dunlap@Sun.COM 				free(isns);
4317978SPeter.Dunlap@Sun.COM 				isns = pnext;
4327978SPeter.Dunlap@Sun.COM 			}
4337978SPeter.Dunlap@Sun.COM 
4347978SPeter.Dunlap@Sun.COM 			cfg->config_isns_svr_list = newisnslist;
4357978SPeter.Dunlap@Sun.COM 			cfg->config_isns_svr_count = newcount;
4367978SPeter.Dunlap@Sun.COM 
4377978SPeter.Dunlap@Sun.COM 			/*
4387978SPeter.Dunlap@Sun.COM 			 * Replace the array in the nvlist to ensure
4397978SPeter.Dunlap@Sun.COM 			 * duplicates are properly removed & port numbers
4407978SPeter.Dunlap@Sun.COM 			 * are added.
4417978SPeter.Dunlap@Sun.COM 			 */
4427978SPeter.Dunlap@Sun.COM 			if (newcount > 0) {
4437978SPeter.Dunlap@Sun.COM 				int	i = 0;
4447978SPeter.Dunlap@Sun.COM 				char	**newarray;
4457978SPeter.Dunlap@Sun.COM 
4467978SPeter.Dunlap@Sun.COM 				newarray = malloc(sizeof (char *) * newcount);
4477978SPeter.Dunlap@Sun.COM 				if (newarray == NULL) {
4487978SPeter.Dunlap@Sun.COM 					ret = ENOMEM;
4497978SPeter.Dunlap@Sun.COM 				} else {
4507978SPeter.Dunlap@Sun.COM 					for (isns = newisnslist; isns != NULL;
45112370SPeter.Gill@Sun.COM 					    isns = isns->portal_next) {
4527978SPeter.Dunlap@Sun.COM 						(void) sockaddr_to_str(
4537978SPeter.Dunlap@Sun.COM 						    &(isns->portal_addr),
4547978SPeter.Dunlap@Sun.COM 						    &(newarray[i++]));
4557978SPeter.Dunlap@Sun.COM 					}
4567978SPeter.Dunlap@Sun.COM 					(void) nvlist_add_string_array(cprops,
4577978SPeter.Dunlap@Sun.COM 					    PROP_ISNS_SERVER, newarray,
4587978SPeter.Dunlap@Sun.COM 					    newcount);
4597978SPeter.Dunlap@Sun.COM 
4607978SPeter.Dunlap@Sun.COM 					for (i = 0; i < newcount; i++) {
4617978SPeter.Dunlap@Sun.COM 						if (newarray[i]) {
4627978SPeter.Dunlap@Sun.COM 							free(newarray[i]);
4637978SPeter.Dunlap@Sun.COM 						}
4647978SPeter.Dunlap@Sun.COM 					}
4657978SPeter.Dunlap@Sun.COM 					free(newarray);
4667978SPeter.Dunlap@Sun.COM 				}
4677978SPeter.Dunlap@Sun.COM 			}
4687978SPeter.Dunlap@Sun.COM 		}
4697978SPeter.Dunlap@Sun.COM 	} else if (ret == ENOENT) {
4707978SPeter.Dunlap@Sun.COM 		/* not an error */
4717978SPeter.Dunlap@Sun.COM 		ret = 0;
4727978SPeter.Dunlap@Sun.COM 	}
4737978SPeter.Dunlap@Sun.COM 
4747978SPeter.Dunlap@Sun.COM 	if (ret == 0) {
4757978SPeter.Dunlap@Sun.COM 		/* replace the global properties list */
4767978SPeter.Dunlap@Sun.COM 		nvlist_free(cfg->config_global_properties);
4777978SPeter.Dunlap@Sun.COM 		cfg->config_global_properties = cprops;
4787978SPeter.Dunlap@Sun.COM 	} else {
4797978SPeter.Dunlap@Sun.COM 		if (cprops) {
4807978SPeter.Dunlap@Sun.COM 			nvlist_free(cprops);
4817978SPeter.Dunlap@Sun.COM 		}
4827978SPeter.Dunlap@Sun.COM 	}
4837978SPeter.Dunlap@Sun.COM 
4847978SPeter.Dunlap@Sun.COM 	return (ret);
4857978SPeter.Dunlap@Sun.COM }
4867978SPeter.Dunlap@Sun.COM 
4877978SPeter.Dunlap@Sun.COM /*
4887978SPeter.Dunlap@Sun.COM  * Function:  it_config_free()
4897978SPeter.Dunlap@Sun.COM  *
4907978SPeter.Dunlap@Sun.COM  * Free any resources associated with the it_config_t structure.
4917978SPeter.Dunlap@Sun.COM  *
4927978SPeter.Dunlap@Sun.COM  * Parameters:
4937978SPeter.Dunlap@Sun.COM  *    cfg	A C representation of the current iSCSI configuration
4947978SPeter.Dunlap@Sun.COM  */
4957978SPeter.Dunlap@Sun.COM void
4967978SPeter.Dunlap@Sun.COM it_config_free(it_config_t *cfg)
4977978SPeter.Dunlap@Sun.COM {
4987978SPeter.Dunlap@Sun.COM 	it_config_free_cmn(cfg);
4997978SPeter.Dunlap@Sun.COM }
5007978SPeter.Dunlap@Sun.COM 
5017978SPeter.Dunlap@Sun.COM /*
5027978SPeter.Dunlap@Sun.COM  * Function:  it_tgt_create()
5037978SPeter.Dunlap@Sun.COM  *
5047978SPeter.Dunlap@Sun.COM  * Allocate and create an it_tgt_t structure representing a new iSCSI
5057978SPeter.Dunlap@Sun.COM  * target node.  If tgt_name is NULL, then a unique target node name will
5067978SPeter.Dunlap@Sun.COM  * be generated automatically.  Otherwise, the value of tgt_name will be
5077978SPeter.Dunlap@Sun.COM  * used as the target node name.  The new it_tgt_t structure is added to
5087978SPeter.Dunlap@Sun.COM  * the target list (cfg_tgt_list) in the configuration structure, and the
5097978SPeter.Dunlap@Sun.COM  * new target will not be instantiated until the modified configuration
5107978SPeter.Dunlap@Sun.COM  * is committed by calling it_config_commit().
5117978SPeter.Dunlap@Sun.COM  *
5127978SPeter.Dunlap@Sun.COM  * Parameters:
5137978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configuration obtained from
5147978SPeter.Dunlap@Sun.COM  *			it_config_load()
5157978SPeter.Dunlap@Sun.COM  *    tgt		Pointer to an iSCSI target structure
5167978SPeter.Dunlap@Sun.COM  *    tgt_name		The target node name for the target to be created.
5177978SPeter.Dunlap@Sun.COM  *			The name must be in either IQN or EUI format.  If
5187978SPeter.Dunlap@Sun.COM  *			this value is NULL, a node name will be generated
5197978SPeter.Dunlap@Sun.COM  *			automatically in IQN format.
5207978SPeter.Dunlap@Sun.COM  *
5217978SPeter.Dunlap@Sun.COM  * Return Values:
5227978SPeter.Dunlap@Sun.COM  *    0			Success
5237978SPeter.Dunlap@Sun.COM  *    ENOMEM		Could not allocated resources
5247978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid parameter
5257978SPeter.Dunlap@Sun.COM  *    EFAULT		Invalid iSCSI name specified
5268812SSam.Cramer@Sun.COM  *    E2BIG		Too many already exist
5277978SPeter.Dunlap@Sun.COM  */
5287978SPeter.Dunlap@Sun.COM int
5297978SPeter.Dunlap@Sun.COM it_tgt_create(it_config_t *cfg, it_tgt_t **tgt, char *tgt_name)
5307978SPeter.Dunlap@Sun.COM {
5317978SPeter.Dunlap@Sun.COM 	int		ret = 0;
5327978SPeter.Dunlap@Sun.COM 	it_tgt_t	*ptr;
5337978SPeter.Dunlap@Sun.COM 	it_tgt_t	*cfgtgt;
53410855SCharles.Ting@Sun.COM 	char		*namep;
5357978SPeter.Dunlap@Sun.COM 	char		buf[ISCSI_NAME_LEN_MAX + 1];
5367978SPeter.Dunlap@Sun.COM 
5377978SPeter.Dunlap@Sun.COM 	if (!cfg || !tgt) {
5387978SPeter.Dunlap@Sun.COM 		return (EINVAL);
5397978SPeter.Dunlap@Sun.COM 	}
5407978SPeter.Dunlap@Sun.COM 
54110855SCharles.Ting@Sun.COM 	if (!tgt_name) {
5427978SPeter.Dunlap@Sun.COM 		/* generate a name */
5437978SPeter.Dunlap@Sun.COM 		ret = it_iqn_generate(buf, sizeof (buf), NULL);
5447978SPeter.Dunlap@Sun.COM 		if (ret != 0) {
5457978SPeter.Dunlap@Sun.COM 			return (ret);
5467978SPeter.Dunlap@Sun.COM 		}
5477978SPeter.Dunlap@Sun.COM 	} else {
5487978SPeter.Dunlap@Sun.COM 		/* validate the passed-in name */
54910855SCharles.Ting@Sun.COM 		if (!validate_iscsi_name(tgt_name)) {
5507978SPeter.Dunlap@Sun.COM 			return (EFAULT);
5517978SPeter.Dunlap@Sun.COM 		}
55210855SCharles.Ting@Sun.COM 		(void) strlcpy(buf, tgt_name, sizeof (buf));
55310855SCharles.Ting@Sun.COM 		canonical_iscsi_name(buf);
5547978SPeter.Dunlap@Sun.COM 	}
55510855SCharles.Ting@Sun.COM 	namep = buf;
5567978SPeter.Dunlap@Sun.COM 
5577978SPeter.Dunlap@Sun.COM 	/* make sure this name isn't already on the list */
5587978SPeter.Dunlap@Sun.COM 	cfgtgt = cfg->config_tgt_list;
5597978SPeter.Dunlap@Sun.COM 	while (cfgtgt != NULL) {
56010855SCharles.Ting@Sun.COM 		if (strcasecmp(namep, cfgtgt->tgt_name) == 0) {
5617978SPeter.Dunlap@Sun.COM 			return (EEXIST);
5627978SPeter.Dunlap@Sun.COM 		}
5637978SPeter.Dunlap@Sun.COM 		cfgtgt = cfgtgt->tgt_next;
5647978SPeter.Dunlap@Sun.COM 	}
5657978SPeter.Dunlap@Sun.COM 
56610390SCharles.Ting@Sun.COM 	/* Too many targets? */
56710390SCharles.Ting@Sun.COM 	if (cfg->config_tgt_count >= MAX_TARGETS) {
56810390SCharles.Ting@Sun.COM 		return (E2BIG);
56910390SCharles.Ting@Sun.COM 	}
57010390SCharles.Ting@Sun.COM 
5717978SPeter.Dunlap@Sun.COM 	ptr = calloc(1, sizeof (it_tgt_t));
5727978SPeter.Dunlap@Sun.COM 	if (ptr == NULL) {
5737978SPeter.Dunlap@Sun.COM 		return (ENOMEM);
5747978SPeter.Dunlap@Sun.COM 	}
5757978SPeter.Dunlap@Sun.COM 
5767978SPeter.Dunlap@Sun.COM 	(void) strlcpy(ptr->tgt_name, namep, sizeof (ptr->tgt_name));
5777978SPeter.Dunlap@Sun.COM 	ptr->tgt_generation = 1;
5787978SPeter.Dunlap@Sun.COM 	ptr->tgt_next = cfg->config_tgt_list;
5797978SPeter.Dunlap@Sun.COM 	cfg->config_tgt_list = ptr;
5807978SPeter.Dunlap@Sun.COM 	cfg->config_tgt_count++;
5817978SPeter.Dunlap@Sun.COM 
5827978SPeter.Dunlap@Sun.COM 	*tgt = ptr;
5837978SPeter.Dunlap@Sun.COM 
5847978SPeter.Dunlap@Sun.COM 	return (0);
5857978SPeter.Dunlap@Sun.COM }
5867978SPeter.Dunlap@Sun.COM 
5877978SPeter.Dunlap@Sun.COM /*
5887978SPeter.Dunlap@Sun.COM  * Function:  it_tgt_setprop()
5897978SPeter.Dunlap@Sun.COM  *
5907978SPeter.Dunlap@Sun.COM  * Validate the provided property list and set the properties for
5917978SPeter.Dunlap@Sun.COM  * the specified target.  If errlist is not NULL, returns detailed
5927978SPeter.Dunlap@Sun.COM  * errors for each property that failed.  The format for errorlist
5937978SPeter.Dunlap@Sun.COM  * is key = property, value = error string.
5947978SPeter.Dunlap@Sun.COM  *
5957978SPeter.Dunlap@Sun.COM  * Parameters:
5967978SPeter.Dunlap@Sun.COM  *
5977978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configuration obtained from
5987978SPeter.Dunlap@Sun.COM  *			it_config_load()
5997978SPeter.Dunlap@Sun.COM  *    tgt		Pointer to an iSCSI target structure
6007978SPeter.Dunlap@Sun.COM  *    proplist		nvlist_t containing properties for this target.
6017978SPeter.Dunlap@Sun.COM  *    errlist		(optional)  nvlist_t of errors encountered when
6027978SPeter.Dunlap@Sun.COM  *			validating the properties.
6037978SPeter.Dunlap@Sun.COM  *
6047978SPeter.Dunlap@Sun.COM  * Return Values:
6057978SPeter.Dunlap@Sun.COM  *    0			Success
6067978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid property
6077978SPeter.Dunlap@Sun.COM  *
6087978SPeter.Dunlap@Sun.COM  */
6097978SPeter.Dunlap@Sun.COM int
6107978SPeter.Dunlap@Sun.COM it_tgt_setprop(it_config_t *cfg, it_tgt_t *tgt, nvlist_t *proplist,
6117978SPeter.Dunlap@Sun.COM     nvlist_t **errlist)
6127978SPeter.Dunlap@Sun.COM {
6137978SPeter.Dunlap@Sun.COM 	int		ret;
61411514SPeter.Gill@Sun.COM 	nvlist_t	*errs = NULL;
6157978SPeter.Dunlap@Sun.COM 	nvlist_t	*tprops = NULL;
6167978SPeter.Dunlap@Sun.COM 	char		*val = NULL;
6177978SPeter.Dunlap@Sun.COM 
6187978SPeter.Dunlap@Sun.COM 	if (!cfg || !tgt || !proplist) {
6197978SPeter.Dunlap@Sun.COM 		return (EINVAL);
6207978SPeter.Dunlap@Sun.COM 	}
6217978SPeter.Dunlap@Sun.COM 
62210855SCharles.Ting@Sun.COM 	/* verify the target name in case the target node is renamed */
62310855SCharles.Ting@Sun.COM 	if (!validate_iscsi_name(tgt->tgt_name)) {
62410855SCharles.Ting@Sun.COM 		return (EINVAL);
62510855SCharles.Ting@Sun.COM 	}
62610855SCharles.Ting@Sun.COM 	canonical_iscsi_name(tgt->tgt_name);
62710855SCharles.Ting@Sun.COM 
6287978SPeter.Dunlap@Sun.COM 	if (errlist) {
62911514SPeter.Gill@Sun.COM 		(void) nvlist_alloc(&errs, 0, 0);
63011514SPeter.Gill@Sun.COM 		*errlist = errs;
6317978SPeter.Dunlap@Sun.COM 	}
6327978SPeter.Dunlap@Sun.COM 
6337978SPeter.Dunlap@Sun.COM 	/*
6347978SPeter.Dunlap@Sun.COM 	 * copy the existing properties, merge, then validate
6357978SPeter.Dunlap@Sun.COM 	 * the merged properties before committing them.
6367978SPeter.Dunlap@Sun.COM 	 */
6377978SPeter.Dunlap@Sun.COM 	if (tgt->tgt_properties) {
6387978SPeter.Dunlap@Sun.COM 		ret = nvlist_dup(tgt->tgt_properties, &tprops, 0);
6397978SPeter.Dunlap@Sun.COM 	} else {
6407978SPeter.Dunlap@Sun.COM 		ret = nvlist_alloc(&tprops, NV_UNIQUE_NAME, 0);
6417978SPeter.Dunlap@Sun.COM 	}
6427978SPeter.Dunlap@Sun.COM 
64311702SPeter.Gill@Sun.COM 	if (ret != 0) {
64411702SPeter.Gill@Sun.COM 		return (ret);
64511702SPeter.Gill@Sun.COM 	}
64611702SPeter.Gill@Sun.COM 
64711702SPeter.Gill@Sun.COM 	ret = nvlist_merge(tprops, proplist, 0);
64811702SPeter.Gill@Sun.COM 	if (ret != 0) {
64911702SPeter.Gill@Sun.COM 		nvlist_free(tprops);
65011702SPeter.Gill@Sun.COM 		return (ret);
6517978SPeter.Dunlap@Sun.COM 	}
6527978SPeter.Dunlap@Sun.COM 
6537978SPeter.Dunlap@Sun.COM 	/* unset chap username or alias if requested */
6547978SPeter.Dunlap@Sun.COM 	val = NULL;
6557978SPeter.Dunlap@Sun.COM 	(void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_USER, &val);
6567978SPeter.Dunlap@Sun.COM 	if (val && (strcasecmp(val, "none") == 0)) {
6577978SPeter.Dunlap@Sun.COM 		(void) nvlist_remove_all(tprops, PROP_TARGET_CHAP_USER);
6587978SPeter.Dunlap@Sun.COM 	}
6597978SPeter.Dunlap@Sun.COM 
6607978SPeter.Dunlap@Sun.COM 	val = NULL;
6617978SPeter.Dunlap@Sun.COM 	(void) nvlist_lookup_string(proplist, PROP_ALIAS, &val);
6627978SPeter.Dunlap@Sun.COM 	if (val && (strcasecmp(val, "none") == 0)) {
6637978SPeter.Dunlap@Sun.COM 		(void) nvlist_remove_all(tprops, PROP_ALIAS);
6647978SPeter.Dunlap@Sun.COM 	}
6657978SPeter.Dunlap@Sun.COM 
6667978SPeter.Dunlap@Sun.COM 	/* base64 encode the CHAP secret, if it's changed */
6677978SPeter.Dunlap@Sun.COM 	val = NULL;
6687978SPeter.Dunlap@Sun.COM 	(void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_SECRET, &val);
6697978SPeter.Dunlap@Sun.COM 	if (val) {
6707978SPeter.Dunlap@Sun.COM 		char		bsecret[MAX_BASE64_LEN];
6717978SPeter.Dunlap@Sun.COM 
67211514SPeter.Gill@Sun.COM 		ret = it_val_pass(PROP_TARGET_CHAP_SECRET, val, errs);
6737978SPeter.Dunlap@Sun.COM 
6747978SPeter.Dunlap@Sun.COM 		if (ret == 0) {
6757978SPeter.Dunlap@Sun.COM 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
6767978SPeter.Dunlap@Sun.COM 
6777978SPeter.Dunlap@Sun.COM 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
6787978SPeter.Dunlap@Sun.COM 			    strlen(val), bsecret, MAX_BASE64_LEN);
6797978SPeter.Dunlap@Sun.COM 
6807978SPeter.Dunlap@Sun.COM 			if (ret == 0) {
6817978SPeter.Dunlap@Sun.COM 				/* replace the value in the nvlist */
6827978SPeter.Dunlap@Sun.COM 				ret = nvlist_add_string(tprops,
6837978SPeter.Dunlap@Sun.COM 				    PROP_TARGET_CHAP_SECRET, bsecret);
6847978SPeter.Dunlap@Sun.COM 			}
6857978SPeter.Dunlap@Sun.COM 		}
6867978SPeter.Dunlap@Sun.COM 	}
6877978SPeter.Dunlap@Sun.COM 
6887978SPeter.Dunlap@Sun.COM 	if (ret == 0) {
68911514SPeter.Gill@Sun.COM 		ret = it_validate_tgtprops(tprops, errs);
6907978SPeter.Dunlap@Sun.COM 	}
6917978SPeter.Dunlap@Sun.COM 
6927978SPeter.Dunlap@Sun.COM 	if (ret != 0) {
6937978SPeter.Dunlap@Sun.COM 		if (tprops) {
6947978SPeter.Dunlap@Sun.COM 			nvlist_free(tprops);
6957978SPeter.Dunlap@Sun.COM 		}
6967978SPeter.Dunlap@Sun.COM 		return (ret);
6977978SPeter.Dunlap@Sun.COM 	}
6987978SPeter.Dunlap@Sun.COM 
6997978SPeter.Dunlap@Sun.COM 	if (tgt->tgt_properties) {
7007978SPeter.Dunlap@Sun.COM 		nvlist_free(tgt->tgt_properties);
7017978SPeter.Dunlap@Sun.COM 	}
7027978SPeter.Dunlap@Sun.COM 	tgt->tgt_properties = tprops;
7037978SPeter.Dunlap@Sun.COM 
7047978SPeter.Dunlap@Sun.COM 	return (0);
7057978SPeter.Dunlap@Sun.COM }
7067978SPeter.Dunlap@Sun.COM 
7077978SPeter.Dunlap@Sun.COM 
7087978SPeter.Dunlap@Sun.COM /*
7097978SPeter.Dunlap@Sun.COM  * Function:  it_tgt_delete()
7107978SPeter.Dunlap@Sun.COM  *
7117978SPeter.Dunlap@Sun.COM  * Delete target represented by 'tgt', where 'tgt' is an existing
7127978SPeter.Dunlap@Sun.COM  * it_tgt_structure within the configuration 'cfg'.  The target removal
7137978SPeter.Dunlap@Sun.COM  * will not take effect until the modified configuration is committed
7147978SPeter.Dunlap@Sun.COM  * by calling it_config_commit().
7157978SPeter.Dunlap@Sun.COM  *
7167978SPeter.Dunlap@Sun.COM  * Parameters:
7177978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configuration obtained from
7187978SPeter.Dunlap@Sun.COM  *			it_config_load()
7197978SPeter.Dunlap@Sun.COM  *    tgt		Pointer to an iSCSI target structure
7207978SPeter.Dunlap@Sun.COM  *
7217978SPeter.Dunlap@Sun.COM  *    force		Set the target to offline before removing it from
7227978SPeter.Dunlap@Sun.COM  *			the config.  If not specified, the operation will
7237978SPeter.Dunlap@Sun.COM  *			fail if the target is determined to be online.
7247978SPeter.Dunlap@Sun.COM  * Return Values:
7257978SPeter.Dunlap@Sun.COM  *    0			Success
7267978SPeter.Dunlap@Sun.COM  *    EBUSY		Target is online
7277978SPeter.Dunlap@Sun.COM  */
7287978SPeter.Dunlap@Sun.COM int
7297978SPeter.Dunlap@Sun.COM it_tgt_delete(it_config_t *cfg, it_tgt_t *tgt, boolean_t force)
7307978SPeter.Dunlap@Sun.COM {
7317978SPeter.Dunlap@Sun.COM 	int			ret;
7327978SPeter.Dunlap@Sun.COM 	it_tgt_t		*ptgt;
7337978SPeter.Dunlap@Sun.COM 	it_tgt_t		*prev = NULL;
7347978SPeter.Dunlap@Sun.COM 	stmfDevid		devid;
7357978SPeter.Dunlap@Sun.COM 	stmfTargetProperties	props;
7367978SPeter.Dunlap@Sun.COM 
7377978SPeter.Dunlap@Sun.COM 	if (!cfg || !tgt) {
7387978SPeter.Dunlap@Sun.COM 		return (0);
7397978SPeter.Dunlap@Sun.COM 	}
7407978SPeter.Dunlap@Sun.COM 
7417978SPeter.Dunlap@Sun.COM 	ptgt = cfg->config_tgt_list;
7427978SPeter.Dunlap@Sun.COM 	while (ptgt != NULL) {
74310855SCharles.Ting@Sun.COM 		if (strcasecmp(tgt->tgt_name, ptgt->tgt_name) == 0) {
7447978SPeter.Dunlap@Sun.COM 			break;
7457978SPeter.Dunlap@Sun.COM 		}
7467978SPeter.Dunlap@Sun.COM 		prev = ptgt;
7477978SPeter.Dunlap@Sun.COM 		ptgt = ptgt->tgt_next;
7487978SPeter.Dunlap@Sun.COM 	}
7497978SPeter.Dunlap@Sun.COM 
7507978SPeter.Dunlap@Sun.COM 	if (!ptgt) {
7517978SPeter.Dunlap@Sun.COM 		return (0);
7527978SPeter.Dunlap@Sun.COM 	}
7537978SPeter.Dunlap@Sun.COM 
7547978SPeter.Dunlap@Sun.COM 	/*
7557978SPeter.Dunlap@Sun.COM 	 * check to see if this target is offline.  If it is not,
7567978SPeter.Dunlap@Sun.COM 	 * and the 'force' flag is TRUE, tell STMF to offline it
7577978SPeter.Dunlap@Sun.COM 	 * before removing from the configuration.
7587978SPeter.Dunlap@Sun.COM 	 */
7597978SPeter.Dunlap@Sun.COM 	ret = stmfDevidFromIscsiName(ptgt->tgt_name, &devid);
7607978SPeter.Dunlap@Sun.COM 	if (ret != STMF_STATUS_SUCCESS) {
7617978SPeter.Dunlap@Sun.COM 		/* can't happen? */
7627978SPeter.Dunlap@Sun.COM 		return (EINVAL);
7637978SPeter.Dunlap@Sun.COM 	}
7647978SPeter.Dunlap@Sun.COM 
7657978SPeter.Dunlap@Sun.COM 	ret = stmfGetTargetProperties(&devid, &props);
7667978SPeter.Dunlap@Sun.COM 	if (ret == STMF_STATUS_SUCCESS) {
7677978SPeter.Dunlap@Sun.COM 		/*
7687978SPeter.Dunlap@Sun.COM 		 * only other return is STMF_ERROR_NOT_FOUND, which
7697978SPeter.Dunlap@Sun.COM 		 * means we don't have to offline it.
7707978SPeter.Dunlap@Sun.COM 		 */
7717978SPeter.Dunlap@Sun.COM 		if (props.status == STMF_TARGET_PORT_ONLINE) {
7727978SPeter.Dunlap@Sun.COM 			if (!force) {
7737978SPeter.Dunlap@Sun.COM 				return (EBUSY);
7747978SPeter.Dunlap@Sun.COM 			}
7757978SPeter.Dunlap@Sun.COM 			ret = stmfOfflineTarget(&devid);
7767978SPeter.Dunlap@Sun.COM 			if (ret != 0) {
7777978SPeter.Dunlap@Sun.COM 				return (EBUSY);
7787978SPeter.Dunlap@Sun.COM 			}
7797978SPeter.Dunlap@Sun.COM 		}
7807978SPeter.Dunlap@Sun.COM 	}
7817978SPeter.Dunlap@Sun.COM 
7827978SPeter.Dunlap@Sun.COM 	if (prev) {
7837978SPeter.Dunlap@Sun.COM 		prev->tgt_next = ptgt->tgt_next;
7847978SPeter.Dunlap@Sun.COM 	} else {
7857978SPeter.Dunlap@Sun.COM 		/* first one on the list */
7867978SPeter.Dunlap@Sun.COM 		cfg->config_tgt_list = ptgt->tgt_next;
7877978SPeter.Dunlap@Sun.COM 	}
7887978SPeter.Dunlap@Sun.COM 
7897978SPeter.Dunlap@Sun.COM 	ptgt->tgt_next = NULL; /* Only free this target */
7907978SPeter.Dunlap@Sun.COM 
7917978SPeter.Dunlap@Sun.COM 	cfg->config_tgt_count--;
7927978SPeter.Dunlap@Sun.COM 	it_tgt_free(ptgt);
7937978SPeter.Dunlap@Sun.COM 
7947978SPeter.Dunlap@Sun.COM 	return (0);
7957978SPeter.Dunlap@Sun.COM }
7967978SPeter.Dunlap@Sun.COM 
7977978SPeter.Dunlap@Sun.COM /*
7987978SPeter.Dunlap@Sun.COM  * Function:  it_tgt_free()
7997978SPeter.Dunlap@Sun.COM  *
8007978SPeter.Dunlap@Sun.COM  * Frees an it_tgt_t structure.  If tgt_next is not NULL, frees
8017978SPeter.Dunlap@Sun.COM  * all structures in the list.
8027978SPeter.Dunlap@Sun.COM  */
8037978SPeter.Dunlap@Sun.COM void
8047978SPeter.Dunlap@Sun.COM it_tgt_free(it_tgt_t *tgt)
8057978SPeter.Dunlap@Sun.COM {
8067978SPeter.Dunlap@Sun.COM 	it_tgt_free_cmn(tgt);
8077978SPeter.Dunlap@Sun.COM }
8087978SPeter.Dunlap@Sun.COM 
8097978SPeter.Dunlap@Sun.COM /*
8107978SPeter.Dunlap@Sun.COM  * Function:  it_tpgt_create()
8117978SPeter.Dunlap@Sun.COM  *
8127978SPeter.Dunlap@Sun.COM  * Allocate and create an it_tpgt_t structure representing a new iSCSI
8137978SPeter.Dunlap@Sun.COM  * target portal group tag.  The new it_tpgt_t structure is added to the
8147978SPeter.Dunlap@Sun.COM  * target tpgt list (tgt_tpgt_list) in the it_tgt_t structure.  The new
8157978SPeter.Dunlap@Sun.COM  * target portal group tag will not be instantiated until the modified
8167978SPeter.Dunlap@Sun.COM  * configuration is committed by calling it_config_commit().
8177978SPeter.Dunlap@Sun.COM  *
8187978SPeter.Dunlap@Sun.COM  * Parameters:
8197978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configuration obtained from
8207978SPeter.Dunlap@Sun.COM  *			it_config_load()
8217978SPeter.Dunlap@Sun.COM  *    tgt		Pointer to the iSCSI target structure associated
8227978SPeter.Dunlap@Sun.COM  *			with the target portal group tag
8237978SPeter.Dunlap@Sun.COM  *    tpgt		Pointer to a target portal group tag structure
8247978SPeter.Dunlap@Sun.COM  *    tpg_name		The name of the TPG to be associated with this TPGT
8257978SPeter.Dunlap@Sun.COM  *    tpgt_tag		16-bit numerical identifier for this TPGT.  If
8267978SPeter.Dunlap@Sun.COM  *			tpgt_tag is '0', this function will choose the
8277978SPeter.Dunlap@Sun.COM  *			tag number.  If tpgt_tag is >0, and the requested
8287978SPeter.Dunlap@Sun.COM  *			tag is determined to be in use, another value
8297978SPeter.Dunlap@Sun.COM  *			will be chosen.
8307978SPeter.Dunlap@Sun.COM  *
8317978SPeter.Dunlap@Sun.COM  * Return Values:
8327978SPeter.Dunlap@Sun.COM  *    0			Success
8337978SPeter.Dunlap@Sun.COM  *    ENOMEM		Could not allocate resources
8347978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid parameter
8357978SPeter.Dunlap@Sun.COM  *    EEXIST		Specified tag name is already used.
8367978SPeter.Dunlap@Sun.COM  *    E2BIG		No available tag numbers
8377978SPeter.Dunlap@Sun.COM  */
8387978SPeter.Dunlap@Sun.COM int
8397978SPeter.Dunlap@Sun.COM it_tpgt_create(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t **tpgt,
8407978SPeter.Dunlap@Sun.COM     char *tpg_name, uint16_t tpgt_tag)
8417978SPeter.Dunlap@Sun.COM {
8427978SPeter.Dunlap@Sun.COM 	it_tpgt_t	*ptr = NULL;
8437978SPeter.Dunlap@Sun.COM 	it_tpgt_t	*cfgt;
8447978SPeter.Dunlap@Sun.COM 	char		tagid_used[MAXTAG + 1];
8457978SPeter.Dunlap@Sun.COM 	uint16_t	tagid = ISCSIT_DEFAULT_TPGT;
8467978SPeter.Dunlap@Sun.COM 
8477978SPeter.Dunlap@Sun.COM 	if (!cfg || !tgt || !tpgt || !tpg_name) {
8487978SPeter.Dunlap@Sun.COM 		return (EINVAL);
8497978SPeter.Dunlap@Sun.COM 	}
8507978SPeter.Dunlap@Sun.COM 
8517978SPeter.Dunlap@Sun.COM 	(void) memset(&(tagid_used[0]), 0, sizeof (tagid_used));
8527978SPeter.Dunlap@Sun.COM 
8537978SPeter.Dunlap@Sun.COM 	/*
8547978SPeter.Dunlap@Sun.COM 	 * Make sure this name and/or tag isn't already on the list
8557978SPeter.Dunlap@Sun.COM 	 * At the same time, capture all tag ids in use for this target
8567978SPeter.Dunlap@Sun.COM 	 *
8577978SPeter.Dunlap@Sun.COM 	 * About tag numbering -- since tag numbers are used by
8587978SPeter.Dunlap@Sun.COM 	 * the iSCSI protocol, we should be careful about reusing
8597978SPeter.Dunlap@Sun.COM 	 * them too quickly.  Start with a value greater than the
8607978SPeter.Dunlap@Sun.COM 	 * highest one currently defined.  If current == MAXTAG,
8617978SPeter.Dunlap@Sun.COM 	 * just find an unused tag.
8627978SPeter.Dunlap@Sun.COM 	 */
8637978SPeter.Dunlap@Sun.COM 	cfgt = tgt->tgt_tpgt_list;
8647978SPeter.Dunlap@Sun.COM 	while (cfgt != NULL) {
8657978SPeter.Dunlap@Sun.COM 		tagid_used[cfgt->tpgt_tag] = 1;
8667978SPeter.Dunlap@Sun.COM 
8677978SPeter.Dunlap@Sun.COM 		if (strcmp(tpg_name, cfgt->tpgt_tpg_name) == 0) {
8687978SPeter.Dunlap@Sun.COM 			return (EEXIST);
8697978SPeter.Dunlap@Sun.COM 		}
8707978SPeter.Dunlap@Sun.COM 
8717978SPeter.Dunlap@Sun.COM 		if (cfgt->tpgt_tag > tagid) {
8727978SPeter.Dunlap@Sun.COM 			tagid = cfgt->tpgt_tag;
8737978SPeter.Dunlap@Sun.COM 		}
8747978SPeter.Dunlap@Sun.COM 
8757978SPeter.Dunlap@Sun.COM 		cfgt = cfgt->tpgt_next;
8767978SPeter.Dunlap@Sun.COM 	}
8777978SPeter.Dunlap@Sun.COM 
8787978SPeter.Dunlap@Sun.COM 	if ((tpgt_tag > ISCSIT_DEFAULT_TPGT) && (tpgt_tag < MAXTAG) &&
8797978SPeter.Dunlap@Sun.COM 	    (tagid_used[tpgt_tag] == 0)) {
8807978SPeter.Dunlap@Sun.COM 		/* ok to use requested */
8817978SPeter.Dunlap@Sun.COM 		tagid = tpgt_tag;
8827978SPeter.Dunlap@Sun.COM 	} else if (tagid == MAXTAG) {
8837978SPeter.Dunlap@Sun.COM 		/*
8847978SPeter.Dunlap@Sun.COM 		 * The highest value is used, find an available id.
8857978SPeter.Dunlap@Sun.COM 		 */
8867978SPeter.Dunlap@Sun.COM 		tagid = ISCSIT_DEFAULT_TPGT + 1;
8877978SPeter.Dunlap@Sun.COM 		for (; tagid < MAXTAG; tagid++) {
8887978SPeter.Dunlap@Sun.COM 			if (tagid_used[tagid] == 0) {
8897978SPeter.Dunlap@Sun.COM 				break;
8907978SPeter.Dunlap@Sun.COM 			}
8917978SPeter.Dunlap@Sun.COM 		}
8927978SPeter.Dunlap@Sun.COM 		if (tagid >= MAXTAG) {
8937978SPeter.Dunlap@Sun.COM 			return (E2BIG);
8947978SPeter.Dunlap@Sun.COM 		}
8957978SPeter.Dunlap@Sun.COM 	} else {
8967978SPeter.Dunlap@Sun.COM 		/* next available ID */
8977978SPeter.Dunlap@Sun.COM 		tagid++;
8987978SPeter.Dunlap@Sun.COM 	}
8997978SPeter.Dunlap@Sun.COM 
9007978SPeter.Dunlap@Sun.COM 	ptr = calloc(1, sizeof (it_tpgt_t));
9017978SPeter.Dunlap@Sun.COM 	if (!ptr) {
9027978SPeter.Dunlap@Sun.COM 		return (ENOMEM);
9037978SPeter.Dunlap@Sun.COM 	}
9047978SPeter.Dunlap@Sun.COM 
9057978SPeter.Dunlap@Sun.COM 	(void) strlcpy(ptr->tpgt_tpg_name, tpg_name,
9067978SPeter.Dunlap@Sun.COM 	    sizeof (ptr->tpgt_tpg_name));
9077978SPeter.Dunlap@Sun.COM 	ptr->tpgt_generation = 1;
9087978SPeter.Dunlap@Sun.COM 	ptr->tpgt_tag = tagid;
9097978SPeter.Dunlap@Sun.COM 
9107978SPeter.Dunlap@Sun.COM 	ptr->tpgt_next = tgt->tgt_tpgt_list;
9117978SPeter.Dunlap@Sun.COM 	tgt->tgt_tpgt_list = ptr;
9127978SPeter.Dunlap@Sun.COM 	tgt->tgt_tpgt_count++;
9137978SPeter.Dunlap@Sun.COM 	tgt->tgt_generation++;
9147978SPeter.Dunlap@Sun.COM 
9157978SPeter.Dunlap@Sun.COM 	*tpgt = ptr;
9167978SPeter.Dunlap@Sun.COM 
9177978SPeter.Dunlap@Sun.COM 	return (0);
9187978SPeter.Dunlap@Sun.COM }
9197978SPeter.Dunlap@Sun.COM 
9207978SPeter.Dunlap@Sun.COM /*
9217978SPeter.Dunlap@Sun.COM  * Function:  it_tpgt_delete()
9227978SPeter.Dunlap@Sun.COM  *
9237978SPeter.Dunlap@Sun.COM  * Delete the target portal group tag represented by 'tpgt', where
9247978SPeter.Dunlap@Sun.COM  * 'tpgt' is an existing is_tpgt_t structure within the target 'tgt'.
9257978SPeter.Dunlap@Sun.COM  * The target portal group tag removal will not take effect until the
9267978SPeter.Dunlap@Sun.COM  * modified configuration is committed by calling it_config_commit().
9277978SPeter.Dunlap@Sun.COM  *
9287978SPeter.Dunlap@Sun.COM  * Parameters:
9297978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configuration obtained from
9307978SPeter.Dunlap@Sun.COM  *			it_config_load()
9317978SPeter.Dunlap@Sun.COM  *    tgt		Pointer to the iSCSI target structure associated
9327978SPeter.Dunlap@Sun.COM  *			with the target portal group tag
9337978SPeter.Dunlap@Sun.COM  *    tpgt		Pointer to a target portal group tag structure
9347978SPeter.Dunlap@Sun.COM  */
9357978SPeter.Dunlap@Sun.COM void
9367978SPeter.Dunlap@Sun.COM it_tpgt_delete(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t *tpgt)
9377978SPeter.Dunlap@Sun.COM {
9387978SPeter.Dunlap@Sun.COM 	it_tpgt_t	*ptr;
9397978SPeter.Dunlap@Sun.COM 	it_tpgt_t	*prev = NULL;
9407978SPeter.Dunlap@Sun.COM 
9417978SPeter.Dunlap@Sun.COM 	if (!cfg || !tgt || !tpgt) {
9427978SPeter.Dunlap@Sun.COM 		return;
9437978SPeter.Dunlap@Sun.COM 	}
9447978SPeter.Dunlap@Sun.COM 
9457978SPeter.Dunlap@Sun.COM 	ptr = tgt->tgt_tpgt_list;
9467978SPeter.Dunlap@Sun.COM 	while (ptr) {
9477978SPeter.Dunlap@Sun.COM 		if (ptr->tpgt_tag == tpgt->tpgt_tag) {
9487978SPeter.Dunlap@Sun.COM 			break;
9497978SPeter.Dunlap@Sun.COM 		}
9507978SPeter.Dunlap@Sun.COM 		prev = ptr;
9517978SPeter.Dunlap@Sun.COM 		ptr = ptr->tpgt_next;
9527978SPeter.Dunlap@Sun.COM 	}
9537978SPeter.Dunlap@Sun.COM 
9547978SPeter.Dunlap@Sun.COM 	if (!ptr) {
9557978SPeter.Dunlap@Sun.COM 		return;
9567978SPeter.Dunlap@Sun.COM 	}
9577978SPeter.Dunlap@Sun.COM 
9587978SPeter.Dunlap@Sun.COM 	if (prev) {
9597978SPeter.Dunlap@Sun.COM 		prev->tpgt_next = ptr->tpgt_next;
9607978SPeter.Dunlap@Sun.COM 	} else {
9617978SPeter.Dunlap@Sun.COM 		tgt->tgt_tpgt_list = ptr->tpgt_next;
9627978SPeter.Dunlap@Sun.COM 	}
9637978SPeter.Dunlap@Sun.COM 	ptr->tpgt_next = NULL;
9647978SPeter.Dunlap@Sun.COM 
9657978SPeter.Dunlap@Sun.COM 	tgt->tgt_tpgt_count--;
9667978SPeter.Dunlap@Sun.COM 	tgt->tgt_generation++;
9677978SPeter.Dunlap@Sun.COM 
9687978SPeter.Dunlap@Sun.COM 	it_tpgt_free(ptr);
9697978SPeter.Dunlap@Sun.COM }
9707978SPeter.Dunlap@Sun.COM 
9717978SPeter.Dunlap@Sun.COM /*
9727978SPeter.Dunlap@Sun.COM  * Function:  it_tpgt_free()
9737978SPeter.Dunlap@Sun.COM  *
9747978SPeter.Dunlap@Sun.COM  * Deallocates resources of an it_tpgt_t structure.  If tpgt->next
9757978SPeter.Dunlap@Sun.COM  * is not NULL, frees all members of the list.
9767978SPeter.Dunlap@Sun.COM  */
9777978SPeter.Dunlap@Sun.COM void
9787978SPeter.Dunlap@Sun.COM it_tpgt_free(it_tpgt_t *tpgt)
9797978SPeter.Dunlap@Sun.COM {
9807978SPeter.Dunlap@Sun.COM 	it_tpgt_free_cmn(tpgt);
9817978SPeter.Dunlap@Sun.COM }
9827978SPeter.Dunlap@Sun.COM 
9837978SPeter.Dunlap@Sun.COM /*
9847978SPeter.Dunlap@Sun.COM  * Function:  it_tpg_create()
9857978SPeter.Dunlap@Sun.COM  *
9867978SPeter.Dunlap@Sun.COM  * Allocate and create an it_tpg_t structure representing a new iSCSI
9877978SPeter.Dunlap@Sun.COM  * target portal group.  The new it_tpg_t structure is added to the global
9887978SPeter.Dunlap@Sun.COM  * tpg list (cfg_tgt_list) in the it_config_t structure.  The new target
9897978SPeter.Dunlap@Sun.COM  * portal group will not be instantiated until the modified configuration
9907978SPeter.Dunlap@Sun.COM  * is committed by calling it_config_commit().
9917978SPeter.Dunlap@Sun.COM  *
9927978SPeter.Dunlap@Sun.COM  * Parameters:
9937978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configuration obtained from
9947978SPeter.Dunlap@Sun.COM  *			it_config_load()
9957978SPeter.Dunlap@Sun.COM  *    tpg		Pointer to the it_tpg_t structure representing
9967978SPeter.Dunlap@Sun.COM  *			the target portal group
9977978SPeter.Dunlap@Sun.COM  *    tpg_name		Identifier for the target portal group
9987978SPeter.Dunlap@Sun.COM  *    portal_ip_port	A string containing an appropriatedly formatted
9997978SPeter.Dunlap@Sun.COM  *			IP address:port.  Both IPv4 and IPv6 addresses are
10007978SPeter.Dunlap@Sun.COM  *			permitted.  This value becomes the first portal in
10017978SPeter.Dunlap@Sun.COM  *			the TPG -- applications can add additional values
10027978SPeter.Dunlap@Sun.COM  *			using it_portal_create() before committing the TPG.
10037978SPeter.Dunlap@Sun.COM  * Return Values:
10047978SPeter.Dunlap@Sun.COM  *    0			Success
10057978SPeter.Dunlap@Sun.COM  *    ENOMEM		Cannot allocate resources
10067978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid parameter
10077978SPeter.Dunlap@Sun.COM  *    EEXIST		Requested portal in use by another target portal
10087978SPeter.Dunlap@Sun.COM  *			group
10097978SPeter.Dunlap@Sun.COM  */
10107978SPeter.Dunlap@Sun.COM int
10117978SPeter.Dunlap@Sun.COM it_tpg_create(it_config_t *cfg, it_tpg_t **tpg, char *tpg_name,
10127978SPeter.Dunlap@Sun.COM     char *portal_ip_port)
10137978SPeter.Dunlap@Sun.COM {
10147978SPeter.Dunlap@Sun.COM 	int		ret;
10157978SPeter.Dunlap@Sun.COM 	it_tpg_t	*ptr;
10167978SPeter.Dunlap@Sun.COM 	it_portal_t	*portal = NULL;
10177978SPeter.Dunlap@Sun.COM 
10187978SPeter.Dunlap@Sun.COM 	if (!cfg || !tpg || !tpg_name || !portal_ip_port) {
10197978SPeter.Dunlap@Sun.COM 		return (EINVAL);
10207978SPeter.Dunlap@Sun.COM 	}
10217978SPeter.Dunlap@Sun.COM 
10227978SPeter.Dunlap@Sun.COM 	*tpg = NULL;
10237978SPeter.Dunlap@Sun.COM 
10247978SPeter.Dunlap@Sun.COM 	ptr = cfg->config_tpg_list;
10257978SPeter.Dunlap@Sun.COM 	while (ptr) {
10267978SPeter.Dunlap@Sun.COM 		if (strcmp(tpg_name, ptr->tpg_name) == 0) {
10277978SPeter.Dunlap@Sun.COM 			break;
10287978SPeter.Dunlap@Sun.COM 		}
10297978SPeter.Dunlap@Sun.COM 		ptr = ptr->tpg_next;
10307978SPeter.Dunlap@Sun.COM 	}
10317978SPeter.Dunlap@Sun.COM 
10327978SPeter.Dunlap@Sun.COM 	if (ptr) {
10337978SPeter.Dunlap@Sun.COM 		return (EEXIST);
10347978SPeter.Dunlap@Sun.COM 	}
10357978SPeter.Dunlap@Sun.COM 
10367978SPeter.Dunlap@Sun.COM 	ptr = calloc(1, sizeof (it_tpg_t));
10377978SPeter.Dunlap@Sun.COM 	if (!ptr) {
10387978SPeter.Dunlap@Sun.COM 		return (ENOMEM);
10397978SPeter.Dunlap@Sun.COM 	}
10407978SPeter.Dunlap@Sun.COM 
10417978SPeter.Dunlap@Sun.COM 	ptr->tpg_generation = 1;
10427978SPeter.Dunlap@Sun.COM 	(void) strlcpy(ptr->tpg_name, tpg_name, sizeof (ptr->tpg_name));
10437978SPeter.Dunlap@Sun.COM 
10447978SPeter.Dunlap@Sun.COM 	/* create the portal */
10457978SPeter.Dunlap@Sun.COM 	ret = it_portal_create(cfg, ptr, &portal, portal_ip_port);
10467978SPeter.Dunlap@Sun.COM 	if (ret != 0) {
10477978SPeter.Dunlap@Sun.COM 		free(ptr);
10487978SPeter.Dunlap@Sun.COM 		return (ret);
10497978SPeter.Dunlap@Sun.COM 	}
10507978SPeter.Dunlap@Sun.COM 
10517978SPeter.Dunlap@Sun.COM 	ptr->tpg_next = cfg->config_tpg_list;
10527978SPeter.Dunlap@Sun.COM 	cfg->config_tpg_list = ptr;
10537978SPeter.Dunlap@Sun.COM 	cfg->config_tpg_count++;
10547978SPeter.Dunlap@Sun.COM 
10557978SPeter.Dunlap@Sun.COM 	*tpg = ptr;
10567978SPeter.Dunlap@Sun.COM 
10577978SPeter.Dunlap@Sun.COM 	return (0);
10587978SPeter.Dunlap@Sun.COM }
10597978SPeter.Dunlap@Sun.COM 
10607978SPeter.Dunlap@Sun.COM /*
10617978SPeter.Dunlap@Sun.COM  * Function:  it_tpg_delete()
10627978SPeter.Dunlap@Sun.COM  *
10637978SPeter.Dunlap@Sun.COM  * Delete target portal group represented by 'tpg', where 'tpg' is an
10647978SPeter.Dunlap@Sun.COM  * existing it_tpg_t structure within the global configuration 'cfg'.
10657978SPeter.Dunlap@Sun.COM  * The target portal group removal will not take effect until the
10667978SPeter.Dunlap@Sun.COM  * modified configuration is committed by calling it_config_commit().
10677978SPeter.Dunlap@Sun.COM  *
10687978SPeter.Dunlap@Sun.COM  * Parameters:
10697978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configuration obtained from
10707978SPeter.Dunlap@Sun.COM  *			it_config_load()
10717978SPeter.Dunlap@Sun.COM  *    tpg		Pointer to the it_tpg_t structure representing
10727978SPeter.Dunlap@Sun.COM  *			the target portal group
10737978SPeter.Dunlap@Sun.COM  *    force		Remove this target portal group even if it's
10747978SPeter.Dunlap@Sun.COM  *			associated with one or more targets.
10757978SPeter.Dunlap@Sun.COM  *
10767978SPeter.Dunlap@Sun.COM  * Return Values:
10777978SPeter.Dunlap@Sun.COM  *    0			Success
10787978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid parameter
10797978SPeter.Dunlap@Sun.COM  *    EBUSY		Portal group associated with one or more targets.
10807978SPeter.Dunlap@Sun.COM  */
10817978SPeter.Dunlap@Sun.COM int
10827978SPeter.Dunlap@Sun.COM it_tpg_delete(it_config_t *cfg, it_tpg_t *tpg, boolean_t force)
10837978SPeter.Dunlap@Sun.COM {
10847978SPeter.Dunlap@Sun.COM 	it_tpg_t	*ptr;
10857978SPeter.Dunlap@Sun.COM 	it_tpg_t	*prev = NULL;
10867978SPeter.Dunlap@Sun.COM 	it_tgt_t	*tgt;
10877978SPeter.Dunlap@Sun.COM 	it_tpgt_t	*tpgt;
10887978SPeter.Dunlap@Sun.COM 	it_tpgt_t	*ntpgt;
10897978SPeter.Dunlap@Sun.COM 
10907978SPeter.Dunlap@Sun.COM 	if (!cfg || !tpg) {
10917978SPeter.Dunlap@Sun.COM 		return (EINVAL);
10927978SPeter.Dunlap@Sun.COM 	}
10937978SPeter.Dunlap@Sun.COM 
10947978SPeter.Dunlap@Sun.COM 	ptr = cfg->config_tpg_list;
10957978SPeter.Dunlap@Sun.COM 	while (ptr) {
10967978SPeter.Dunlap@Sun.COM 		if (strcmp(ptr->tpg_name, tpg->tpg_name) == 0) {
10977978SPeter.Dunlap@Sun.COM 			break;
10987978SPeter.Dunlap@Sun.COM 		}
10997978SPeter.Dunlap@Sun.COM 		prev = ptr;
11007978SPeter.Dunlap@Sun.COM 		ptr = ptr->tpg_next;
11017978SPeter.Dunlap@Sun.COM 	}
11027978SPeter.Dunlap@Sun.COM 
11037978SPeter.Dunlap@Sun.COM 	if (!ptr) {
11047978SPeter.Dunlap@Sun.COM 		return (0);
11057978SPeter.Dunlap@Sun.COM 	}
11067978SPeter.Dunlap@Sun.COM 
11077978SPeter.Dunlap@Sun.COM 	/*
11087978SPeter.Dunlap@Sun.COM 	 * See if any targets are using this portal group.
11097978SPeter.Dunlap@Sun.COM 	 * If there are, and the force flag is not set, fail.
11107978SPeter.Dunlap@Sun.COM 	 */
11117978SPeter.Dunlap@Sun.COM 	tgt = cfg->config_tgt_list;
11127978SPeter.Dunlap@Sun.COM 	while (tgt) {
11137978SPeter.Dunlap@Sun.COM 		tpgt = tgt->tgt_tpgt_list;
11147978SPeter.Dunlap@Sun.COM 		while (tpgt) {
11157978SPeter.Dunlap@Sun.COM 			ntpgt = tpgt->tpgt_next;
11167978SPeter.Dunlap@Sun.COM 
11177978SPeter.Dunlap@Sun.COM 			if (strcmp(tpgt->tpgt_tpg_name, tpg->tpg_name)
11187978SPeter.Dunlap@Sun.COM 			    == 0) {
11197978SPeter.Dunlap@Sun.COM 				if (!force) {
11207978SPeter.Dunlap@Sun.COM 					return (EBUSY);
11217978SPeter.Dunlap@Sun.COM 				}
11227978SPeter.Dunlap@Sun.COM 				it_tpgt_delete(cfg, tgt, tpgt);
11237978SPeter.Dunlap@Sun.COM 			}
11247978SPeter.Dunlap@Sun.COM 
11257978SPeter.Dunlap@Sun.COM 			tpgt = ntpgt;
11267978SPeter.Dunlap@Sun.COM 		}
11277978SPeter.Dunlap@Sun.COM 		tgt = tgt->tgt_next;
11287978SPeter.Dunlap@Sun.COM 	}
11297978SPeter.Dunlap@Sun.COM 
11307978SPeter.Dunlap@Sun.COM 	/* Now that it's not in use anywhere, remove the TPG */
11317978SPeter.Dunlap@Sun.COM 	if (prev) {
11327978SPeter.Dunlap@Sun.COM 		prev->tpg_next = ptr->tpg_next;
11337978SPeter.Dunlap@Sun.COM 	} else {
11347978SPeter.Dunlap@Sun.COM 		cfg->config_tpg_list = ptr->tpg_next;
11357978SPeter.Dunlap@Sun.COM 	}
11367978SPeter.Dunlap@Sun.COM 	ptr->tpg_next = NULL;
11377978SPeter.Dunlap@Sun.COM 
11387978SPeter.Dunlap@Sun.COM 	cfg->config_tpg_count--;
11397978SPeter.Dunlap@Sun.COM 
11407978SPeter.Dunlap@Sun.COM 	it_tpg_free(ptr);
11417978SPeter.Dunlap@Sun.COM 
11427978SPeter.Dunlap@Sun.COM 	return (0);
11437978SPeter.Dunlap@Sun.COM }
11447978SPeter.Dunlap@Sun.COM 
11457978SPeter.Dunlap@Sun.COM /*
11467978SPeter.Dunlap@Sun.COM  * Function:  it_tpg_free()
11477978SPeter.Dunlap@Sun.COM  *
11487978SPeter.Dunlap@Sun.COM  * Deallocates resources associated with an it_tpg_t structure.
11497978SPeter.Dunlap@Sun.COM  * If tpg->next is not NULL, frees all members of the list.
11507978SPeter.Dunlap@Sun.COM  */
11517978SPeter.Dunlap@Sun.COM void
11527978SPeter.Dunlap@Sun.COM it_tpg_free(it_tpg_t *tpg)
11537978SPeter.Dunlap@Sun.COM {
11547978SPeter.Dunlap@Sun.COM 	it_tpg_free_cmn(tpg);
11557978SPeter.Dunlap@Sun.COM }
11567978SPeter.Dunlap@Sun.COM 
11577978SPeter.Dunlap@Sun.COM /*
11587978SPeter.Dunlap@Sun.COM  * Function:  it_portal_create()
11597978SPeter.Dunlap@Sun.COM  *
11607978SPeter.Dunlap@Sun.COM  * Add an it_portal_t structure presenting a new portal to the specified
11617978SPeter.Dunlap@Sun.COM  * target portal group.  The change to the target portal group will not take
11627978SPeter.Dunlap@Sun.COM  * effect until the modified configuration is committed by calling
11637978SPeter.Dunlap@Sun.COM  * it_config_commit().
11647978SPeter.Dunlap@Sun.COM  *
11657978SPeter.Dunlap@Sun.COM  * Parameters:
11667978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configration obtained from
11677978SPeter.Dunlap@Sun.COM  *			it_config_load()
11687978SPeter.Dunlap@Sun.COM  *    tpg		Pointer to the it_tpg_t structure representing the
11697978SPeter.Dunlap@Sun.COM  *			target portal group
11707978SPeter.Dunlap@Sun.COM  *    portal		Pointer to the it_portal_t structure representing
11717978SPeter.Dunlap@Sun.COM  *			the portal
11727978SPeter.Dunlap@Sun.COM  *    portal_ip_port	A string containing an appropriately formatted
11737978SPeter.Dunlap@Sun.COM  *			IP address or IP address:port in either IPv4 or
11747978SPeter.Dunlap@Sun.COM  *			IPv6 format.
11757978SPeter.Dunlap@Sun.COM  * Return Values:
11767978SPeter.Dunlap@Sun.COM  *    0			Success
11777978SPeter.Dunlap@Sun.COM  *    ENOMEM		Could not allocate resources
11787978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid parameter
11797978SPeter.Dunlap@Sun.COM  *    EEXIST		Portal already configured for another portal group
11807978SPeter.Dunlap@Sun.COM  */
11817978SPeter.Dunlap@Sun.COM int
11827978SPeter.Dunlap@Sun.COM it_portal_create(it_config_t *cfg, it_tpg_t *tpg, it_portal_t **portal,
11837978SPeter.Dunlap@Sun.COM     char *portal_ip_port)
11847978SPeter.Dunlap@Sun.COM {
11857978SPeter.Dunlap@Sun.COM 	struct sockaddr_storage		sa;
11867978SPeter.Dunlap@Sun.COM 	it_portal_t			*ptr;
11877978SPeter.Dunlap@Sun.COM 	it_tpg_t			*ctpg = NULL;
11887978SPeter.Dunlap@Sun.COM 
11897978SPeter.Dunlap@Sun.COM 	if (!cfg || !tpg || !portal || !portal_ip_port) {
11907978SPeter.Dunlap@Sun.COM 		return (EINVAL);
11917978SPeter.Dunlap@Sun.COM 	}
11927978SPeter.Dunlap@Sun.COM 
11937978SPeter.Dunlap@Sun.COM 	if ((it_common_convert_sa(portal_ip_port, &sa, ISCSI_LISTEN_PORT))
11947978SPeter.Dunlap@Sun.COM 	    == NULL) {
11957978SPeter.Dunlap@Sun.COM 		return (EINVAL);
11967978SPeter.Dunlap@Sun.COM 	}
11977978SPeter.Dunlap@Sun.COM 
11987978SPeter.Dunlap@Sun.COM 	/* Check that this portal doesn't appear in any other tag */
11997978SPeter.Dunlap@Sun.COM 	ctpg = cfg->config_tpg_list;
12007978SPeter.Dunlap@Sun.COM 	while (ctpg) {
12017978SPeter.Dunlap@Sun.COM 		ptr = ctpg->tpg_portal_list;
120212370SPeter.Gill@Sun.COM 		for (; ptr != NULL; ptr = ptr->portal_next) {
12037978SPeter.Dunlap@Sun.COM 			if (it_sa_compare(&(ptr->portal_addr), &sa) != 0) {
12047978SPeter.Dunlap@Sun.COM 				continue;
12057978SPeter.Dunlap@Sun.COM 			}
12067978SPeter.Dunlap@Sun.COM 
12077978SPeter.Dunlap@Sun.COM 			/*
12087978SPeter.Dunlap@Sun.COM 			 * Existing in the same group is not an error,
12097978SPeter.Dunlap@Sun.COM 			 * but don't add it again.
12107978SPeter.Dunlap@Sun.COM 			 */
12117978SPeter.Dunlap@Sun.COM 			if (strcmp(ctpg->tpg_name, tpg->tpg_name) == 0) {
12127978SPeter.Dunlap@Sun.COM 				return (0);
12137978SPeter.Dunlap@Sun.COM 			} else {
12147978SPeter.Dunlap@Sun.COM 				/* Not allowed */
12157978SPeter.Dunlap@Sun.COM 				return (EEXIST);
12167978SPeter.Dunlap@Sun.COM 			}
12177978SPeter.Dunlap@Sun.COM 		}
12187978SPeter.Dunlap@Sun.COM 		ctpg = ctpg->tpg_next;
12197978SPeter.Dunlap@Sun.COM 	}
12207978SPeter.Dunlap@Sun.COM 
12217978SPeter.Dunlap@Sun.COM 	ptr = calloc(1, sizeof (it_portal_t));
12227978SPeter.Dunlap@Sun.COM 	if (!ptr) {
12237978SPeter.Dunlap@Sun.COM 		return (ENOMEM);
12247978SPeter.Dunlap@Sun.COM 	}
12257978SPeter.Dunlap@Sun.COM 
12267978SPeter.Dunlap@Sun.COM 	(void) memcpy(&(ptr->portal_addr), &sa,
12277978SPeter.Dunlap@Sun.COM 	    sizeof (struct sockaddr_storage));
122812370SPeter.Gill@Sun.COM 	ptr->portal_next = tpg->tpg_portal_list;
12297978SPeter.Dunlap@Sun.COM 	tpg->tpg_portal_list = ptr;
12307978SPeter.Dunlap@Sun.COM 	tpg->tpg_portal_count++;
12317978SPeter.Dunlap@Sun.COM 	tpg->tpg_generation++;
12327978SPeter.Dunlap@Sun.COM 
12337978SPeter.Dunlap@Sun.COM 	return (0);
12347978SPeter.Dunlap@Sun.COM }
12357978SPeter.Dunlap@Sun.COM 
12367978SPeter.Dunlap@Sun.COM /*
12377978SPeter.Dunlap@Sun.COM  * Function:  it_portal_delete()
12387978SPeter.Dunlap@Sun.COM  *
12397978SPeter.Dunlap@Sun.COM  * Remove the specified portal from the specified target portal group.
12407978SPeter.Dunlap@Sun.COM  * The portal removal will not take effect until the modified configuration
12417978SPeter.Dunlap@Sun.COM  * is committed by calling it_config_commit().
12427978SPeter.Dunlap@Sun.COM  *
12437978SPeter.Dunlap@Sun.COM  * Parameters:
12447978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configration obtained from
12457978SPeter.Dunlap@Sun.COM  *			it_config_load()
12467978SPeter.Dunlap@Sun.COM  *    tpg		Pointer to the it_tpg_t structure representing the
12477978SPeter.Dunlap@Sun.COM  *			target portal group
12487978SPeter.Dunlap@Sun.COM  *    portal		Pointer to the it_portal_t structure representing
12497978SPeter.Dunlap@Sun.COM  *			the portal
12507978SPeter.Dunlap@Sun.COM  */
12517978SPeter.Dunlap@Sun.COM void
12527978SPeter.Dunlap@Sun.COM it_portal_delete(it_config_t *cfg, it_tpg_t *tpg, it_portal_t *portal)
12537978SPeter.Dunlap@Sun.COM {
12547978SPeter.Dunlap@Sun.COM 	it_portal_t	*ptr;
125512370SPeter.Gill@Sun.COM 	it_portal_t	*prev = NULL;
12567978SPeter.Dunlap@Sun.COM 
12577978SPeter.Dunlap@Sun.COM 	if (!cfg || !tpg || !portal) {
12587978SPeter.Dunlap@Sun.COM 		return;
12597978SPeter.Dunlap@Sun.COM 	}
12607978SPeter.Dunlap@Sun.COM 
12617978SPeter.Dunlap@Sun.COM 	ptr = tpg->tpg_portal_list;
12627978SPeter.Dunlap@Sun.COM 	while (ptr) {
12637978SPeter.Dunlap@Sun.COM 		if (memcmp(&(ptr->portal_addr), &(portal->portal_addr),
12647978SPeter.Dunlap@Sun.COM 		    sizeof (ptr->portal_addr)) == 0) {
12657978SPeter.Dunlap@Sun.COM 			break;
12667978SPeter.Dunlap@Sun.COM 		}
12677978SPeter.Dunlap@Sun.COM 		prev = ptr;
126812370SPeter.Gill@Sun.COM 		ptr = ptr->portal_next;
12697978SPeter.Dunlap@Sun.COM 	}
12707978SPeter.Dunlap@Sun.COM 
12717978SPeter.Dunlap@Sun.COM 	if (!ptr) {
12727978SPeter.Dunlap@Sun.COM 		return;
12737978SPeter.Dunlap@Sun.COM 	}
12747978SPeter.Dunlap@Sun.COM 
12757978SPeter.Dunlap@Sun.COM 	if (prev) {
127612370SPeter.Gill@Sun.COM 		prev->portal_next = ptr->portal_next;
12777978SPeter.Dunlap@Sun.COM 	} else {
127812370SPeter.Gill@Sun.COM 		tpg->tpg_portal_list = ptr->portal_next;
12797978SPeter.Dunlap@Sun.COM 	}
12807978SPeter.Dunlap@Sun.COM 	tpg->tpg_portal_count--;
12817978SPeter.Dunlap@Sun.COM 	tpg->tpg_generation++;
12827978SPeter.Dunlap@Sun.COM 
12837978SPeter.Dunlap@Sun.COM 	free(ptr);
12847978SPeter.Dunlap@Sun.COM }
12857978SPeter.Dunlap@Sun.COM 
12867978SPeter.Dunlap@Sun.COM /*
12877978SPeter.Dunlap@Sun.COM  * Function:  it_ini_create()
12887978SPeter.Dunlap@Sun.COM  *
12897978SPeter.Dunlap@Sun.COM  * Add an initiator context to the global configuration. The new
12907978SPeter.Dunlap@Sun.COM  * initiator context will not be instantiated until the modified
12917978SPeter.Dunlap@Sun.COM  * configuration is committed by calling it_config_commit().
12927978SPeter.Dunlap@Sun.COM  *
12937978SPeter.Dunlap@Sun.COM  * Parameters:
12947978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configration obtained from
12957978SPeter.Dunlap@Sun.COM  *			it_config_load()
12967978SPeter.Dunlap@Sun.COM  *    ini		Pointer to the it_ini_t structure representing
12977978SPeter.Dunlap@Sun.COM  *			the initiator context.
12987978SPeter.Dunlap@Sun.COM  *    ini_node_name	The iSCSI node name of the remote initiator.
12997978SPeter.Dunlap@Sun.COM  *
13007978SPeter.Dunlap@Sun.COM  * Return Values:
13017978SPeter.Dunlap@Sun.COM  *    0			Success
13027978SPeter.Dunlap@Sun.COM  *    ENOMEM		Could not allocate resources
13037978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid parameter.
13047978SPeter.Dunlap@Sun.COM  *    EFAULT		Invalid initiator name
13057978SPeter.Dunlap@Sun.COM  */
13067978SPeter.Dunlap@Sun.COM int
13077978SPeter.Dunlap@Sun.COM it_ini_create(it_config_t *cfg, it_ini_t **ini, char *ini_node_name)
13087978SPeter.Dunlap@Sun.COM {
13097978SPeter.Dunlap@Sun.COM 	it_ini_t	*ptr;
13107978SPeter.Dunlap@Sun.COM 
13117978SPeter.Dunlap@Sun.COM 	if (!cfg || !ini || !ini_node_name) {
13127978SPeter.Dunlap@Sun.COM 		return (EINVAL);
13137978SPeter.Dunlap@Sun.COM 	}
13147978SPeter.Dunlap@Sun.COM 
13157978SPeter.Dunlap@Sun.COM 	/*
13167978SPeter.Dunlap@Sun.COM 	 * Ensure this is a valid ini name
13177978SPeter.Dunlap@Sun.COM 	 */
13187978SPeter.Dunlap@Sun.COM 	if (!validate_iscsi_name(ini_node_name)) {
13197978SPeter.Dunlap@Sun.COM 		return (EFAULT);
13207978SPeter.Dunlap@Sun.COM 	}
13217978SPeter.Dunlap@Sun.COM 
13227978SPeter.Dunlap@Sun.COM 	ptr = cfg->config_ini_list;
13237978SPeter.Dunlap@Sun.COM 	while (ptr) {
132411163SCharles.Ting@Sun.COM 		if (strcasecmp(ptr->ini_name, ini_node_name) == 0) {
13257978SPeter.Dunlap@Sun.COM 			break;
13267978SPeter.Dunlap@Sun.COM 		}
13277978SPeter.Dunlap@Sun.COM 		ptr = ptr->ini_next;
13287978SPeter.Dunlap@Sun.COM 	}
13297978SPeter.Dunlap@Sun.COM 
13307978SPeter.Dunlap@Sun.COM 	if (ptr) {
13317978SPeter.Dunlap@Sun.COM 		return (EEXIST);
13327978SPeter.Dunlap@Sun.COM 	}
13337978SPeter.Dunlap@Sun.COM 
13347978SPeter.Dunlap@Sun.COM 	ptr = calloc(1, sizeof (it_ini_t));
13357978SPeter.Dunlap@Sun.COM 	if (!ptr) {
13367978SPeter.Dunlap@Sun.COM 		return (ENOMEM);
13377978SPeter.Dunlap@Sun.COM 	}
13387978SPeter.Dunlap@Sun.COM 
13397978SPeter.Dunlap@Sun.COM 	(void) strlcpy(ptr->ini_name, ini_node_name, sizeof (ptr->ini_name));
13407978SPeter.Dunlap@Sun.COM 	ptr->ini_generation = 1;
13417978SPeter.Dunlap@Sun.COM 	/* nvlist for props? */
13427978SPeter.Dunlap@Sun.COM 
13437978SPeter.Dunlap@Sun.COM 	ptr->ini_next = cfg->config_ini_list;
13447978SPeter.Dunlap@Sun.COM 	cfg->config_ini_list = ptr;
13457978SPeter.Dunlap@Sun.COM 	cfg->config_ini_count++;
13467978SPeter.Dunlap@Sun.COM 
13477978SPeter.Dunlap@Sun.COM 	*ini = ptr;
13487978SPeter.Dunlap@Sun.COM 
13497978SPeter.Dunlap@Sun.COM 	return (0);
13507978SPeter.Dunlap@Sun.COM }
13517978SPeter.Dunlap@Sun.COM 
13527978SPeter.Dunlap@Sun.COM /*
13537978SPeter.Dunlap@Sun.COM  * Function:  it_ini_setprop()
13547978SPeter.Dunlap@Sun.COM  *
13557978SPeter.Dunlap@Sun.COM  * Validate the provided property list and set the initiator properties.
13567978SPeter.Dunlap@Sun.COM  * If errlist is not NULL, returns detailed errors for each property
13577978SPeter.Dunlap@Sun.COM  * that failed.  The format for errorlist is key = property,
13587978SPeter.Dunlap@Sun.COM  * value = error string.
13597978SPeter.Dunlap@Sun.COM  *
13607978SPeter.Dunlap@Sun.COM  * Parameters:
13617978SPeter.Dunlap@Sun.COM  *
13627978SPeter.Dunlap@Sun.COM  *    ini		The initiator being updated.
13637978SPeter.Dunlap@Sun.COM  *    proplist		nvlist_t containing properties for this target.
13647978SPeter.Dunlap@Sun.COM  *    errlist		(optional)  nvlist_t of errors encountered when
13657978SPeter.Dunlap@Sun.COM  *			validating the properties.
13667978SPeter.Dunlap@Sun.COM  *
13677978SPeter.Dunlap@Sun.COM  * Return Values:
13687978SPeter.Dunlap@Sun.COM  *    0			Success
13697978SPeter.Dunlap@Sun.COM  *    EINVAL		Invalid property
13707978SPeter.Dunlap@Sun.COM  *
13717978SPeter.Dunlap@Sun.COM  */
13727978SPeter.Dunlap@Sun.COM int
13737978SPeter.Dunlap@Sun.COM it_ini_setprop(it_ini_t *ini, nvlist_t *proplist, nvlist_t **errlist)
13747978SPeter.Dunlap@Sun.COM {
13757978SPeter.Dunlap@Sun.COM 	int		ret;
137611514SPeter.Gill@Sun.COM 	nvlist_t	*errs = NULL;
13777978SPeter.Dunlap@Sun.COM 	nvlist_t	*iprops = NULL;
13787978SPeter.Dunlap@Sun.COM 	char		*val = NULL;
13797978SPeter.Dunlap@Sun.COM 
13807978SPeter.Dunlap@Sun.COM 	if (!ini || !proplist) {
13817978SPeter.Dunlap@Sun.COM 		return (EINVAL);
13827978SPeter.Dunlap@Sun.COM 	}
13837978SPeter.Dunlap@Sun.COM 
13847978SPeter.Dunlap@Sun.COM 	if (errlist) {
138511514SPeter.Gill@Sun.COM 		(void) nvlist_alloc(&errs, 0, 0);
138611514SPeter.Gill@Sun.COM 		*errlist = errs;
13877978SPeter.Dunlap@Sun.COM 	}
13887978SPeter.Dunlap@Sun.COM 
13897978SPeter.Dunlap@Sun.COM 	/*
13907978SPeter.Dunlap@Sun.COM 	 * copy the existing properties, merge, then validate
13917978SPeter.Dunlap@Sun.COM 	 * the merged properties before committing them.
13927978SPeter.Dunlap@Sun.COM 	 */
13937978SPeter.Dunlap@Sun.COM 	if (ini->ini_properties) {
13947978SPeter.Dunlap@Sun.COM 		ret = nvlist_dup(ini->ini_properties, &iprops, 0);
13957978SPeter.Dunlap@Sun.COM 	} else {
13967978SPeter.Dunlap@Sun.COM 		ret = nvlist_alloc(&iprops, NV_UNIQUE_NAME, 0);
13977978SPeter.Dunlap@Sun.COM 	}
13987978SPeter.Dunlap@Sun.COM 
139911702SPeter.Gill@Sun.COM 	if (ret != 0) {
140011702SPeter.Gill@Sun.COM 		return (ret);
140111702SPeter.Gill@Sun.COM 	}
140211702SPeter.Gill@Sun.COM 
140311702SPeter.Gill@Sun.COM 	ret = nvlist_merge(iprops, proplist, 0);
140411702SPeter.Gill@Sun.COM 	if (ret != 0) {
140511702SPeter.Gill@Sun.COM 		nvlist_free(iprops);
140611702SPeter.Gill@Sun.COM 		return (ret);
14077978SPeter.Dunlap@Sun.COM 	}
14087978SPeter.Dunlap@Sun.COM 
14097978SPeter.Dunlap@Sun.COM 	/* unset chap username if requested */
14107978SPeter.Dunlap@Sun.COM 	if ((nvlist_lookup_string(proplist, PROP_CHAP_USER, &val)) == 0) {
14117978SPeter.Dunlap@Sun.COM 		if (strcasecmp(val, "none") == 0) {
14127978SPeter.Dunlap@Sun.COM 			(void) nvlist_remove_all(iprops, PROP_CHAP_USER);
14137978SPeter.Dunlap@Sun.COM 		}
14147978SPeter.Dunlap@Sun.COM 	}
14157978SPeter.Dunlap@Sun.COM 
14167978SPeter.Dunlap@Sun.COM 	/* base64 encode the CHAP secret, if it's changed */
14177978SPeter.Dunlap@Sun.COM 	if ((nvlist_lookup_string(proplist, PROP_CHAP_SECRET, &val)) == 0) {
14187978SPeter.Dunlap@Sun.COM 		char		bsecret[MAX_BASE64_LEN];
14197978SPeter.Dunlap@Sun.COM 
142011514SPeter.Gill@Sun.COM 		ret = it_val_pass(PROP_CHAP_SECRET, val, errs);
14217978SPeter.Dunlap@Sun.COM 		if (ret == 0) {
14227978SPeter.Dunlap@Sun.COM 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
14237978SPeter.Dunlap@Sun.COM 
14247978SPeter.Dunlap@Sun.COM 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
14257978SPeter.Dunlap@Sun.COM 			    strlen(val), bsecret, MAX_BASE64_LEN);
14267978SPeter.Dunlap@Sun.COM 
14277978SPeter.Dunlap@Sun.COM 			if (ret == 0) {
14287978SPeter.Dunlap@Sun.COM 				/* replace the value in the nvlist */
14297978SPeter.Dunlap@Sun.COM 				ret = nvlist_add_string(iprops,
14307978SPeter.Dunlap@Sun.COM 				    PROP_CHAP_SECRET, bsecret);
14317978SPeter.Dunlap@Sun.COM 			}
14327978SPeter.Dunlap@Sun.COM 		}
14337978SPeter.Dunlap@Sun.COM 	}
14347978SPeter.Dunlap@Sun.COM 
14357978SPeter.Dunlap@Sun.COM 	if (ret == 0) {
143611514SPeter.Gill@Sun.COM 		ret = it_validate_iniprops(iprops, errs);
14377978SPeter.Dunlap@Sun.COM 	}
14387978SPeter.Dunlap@Sun.COM 
14397978SPeter.Dunlap@Sun.COM 	if (ret != 0) {
14407978SPeter.Dunlap@Sun.COM 		if (iprops) {
14417978SPeter.Dunlap@Sun.COM 			nvlist_free(iprops);
14427978SPeter.Dunlap@Sun.COM 		}
14437978SPeter.Dunlap@Sun.COM 		return (ret);
14447978SPeter.Dunlap@Sun.COM 	}
14457978SPeter.Dunlap@Sun.COM 
14467978SPeter.Dunlap@Sun.COM 	if (ini->ini_properties) {
14477978SPeter.Dunlap@Sun.COM 		nvlist_free(ini->ini_properties);
14487978SPeter.Dunlap@Sun.COM 	}
14497978SPeter.Dunlap@Sun.COM 	ini->ini_properties = iprops;
14507978SPeter.Dunlap@Sun.COM 
14517978SPeter.Dunlap@Sun.COM 	return (0);
14527978SPeter.Dunlap@Sun.COM }
14537978SPeter.Dunlap@Sun.COM 
14547978SPeter.Dunlap@Sun.COM /*
14557978SPeter.Dunlap@Sun.COM  * Function:  it_ini_delete()
14567978SPeter.Dunlap@Sun.COM  *
14577978SPeter.Dunlap@Sun.COM  * Remove the specified initiator context from the global configuration.
14587978SPeter.Dunlap@Sun.COM  * The removal will not take effect until the modified configuration is
14597978SPeter.Dunlap@Sun.COM  * committed by calling it_config_commit().
14607978SPeter.Dunlap@Sun.COM  *
14617978SPeter.Dunlap@Sun.COM  * Parameters:
14627978SPeter.Dunlap@Sun.COM  *    cfg		The current iSCSI configration obtained from
14637978SPeter.Dunlap@Sun.COM  *			it_config_load()
14647978SPeter.Dunlap@Sun.COM  *    ini		Pointer to the it_ini_t structure representing
14657978SPeter.Dunlap@Sun.COM  *			the initiator context.
14667978SPeter.Dunlap@Sun.COM  */
14677978SPeter.Dunlap@Sun.COM void
14687978SPeter.Dunlap@Sun.COM it_ini_delete(it_config_t *cfg, it_ini_t *ini)
14697978SPeter.Dunlap@Sun.COM {
14707978SPeter.Dunlap@Sun.COM 	it_ini_t	*ptr;
14717978SPeter.Dunlap@Sun.COM 	it_ini_t	*prev = NULL;
14727978SPeter.Dunlap@Sun.COM 
14737978SPeter.Dunlap@Sun.COM 	if (!cfg || !ini) {
14747978SPeter.Dunlap@Sun.COM 		return;
14757978SPeter.Dunlap@Sun.COM 	}
14767978SPeter.Dunlap@Sun.COM 
14777978SPeter.Dunlap@Sun.COM 	ptr = cfg->config_ini_list;
14787978SPeter.Dunlap@Sun.COM 	while (ptr) {
147911163SCharles.Ting@Sun.COM 		if (strcasecmp(ptr->ini_name, ini->ini_name) == 0) {
14807978SPeter.Dunlap@Sun.COM 			break;
14817978SPeter.Dunlap@Sun.COM 		}
14827978SPeter.Dunlap@Sun.COM 		prev = ptr;
14837978SPeter.Dunlap@Sun.COM 		ptr = ptr->ini_next;
14847978SPeter.Dunlap@Sun.COM 	}
14857978SPeter.Dunlap@Sun.COM 
14867978SPeter.Dunlap@Sun.COM 	if (!ptr) {
14877978SPeter.Dunlap@Sun.COM 		return;
14887978SPeter.Dunlap@Sun.COM 	}
14897978SPeter.Dunlap@Sun.COM 
14907978SPeter.Dunlap@Sun.COM 	if (prev) {
14917978SPeter.Dunlap@Sun.COM 		prev->ini_next = ptr->ini_next;
14927978SPeter.Dunlap@Sun.COM 	} else {
14937978SPeter.Dunlap@Sun.COM 		cfg->config_ini_list = ptr->ini_next;
14947978SPeter.Dunlap@Sun.COM 	}
14957978SPeter.Dunlap@Sun.COM 
14967978SPeter.Dunlap@Sun.COM 	ptr->ini_next = NULL; /* Only free this initiator */
14977978SPeter.Dunlap@Sun.COM 
14987978SPeter.Dunlap@Sun.COM 	cfg->config_ini_count--;
14997978SPeter.Dunlap@Sun.COM 
15007978SPeter.Dunlap@Sun.COM 	it_ini_free(ptr);
15017978SPeter.Dunlap@Sun.COM }
15027978SPeter.Dunlap@Sun.COM 
15037978SPeter.Dunlap@Sun.COM /*
15047978SPeter.Dunlap@Sun.COM  * Function:  it_ini_free()
15057978SPeter.Dunlap@Sun.COM  *
15067978SPeter.Dunlap@Sun.COM  * Deallocates resources of an it_ini_t structure. If ini->next is
15077978SPeter.Dunlap@Sun.COM  * not NULL, frees all members of the list.
15087978SPeter.Dunlap@Sun.COM  */
15097978SPeter.Dunlap@Sun.COM void
15107978SPeter.Dunlap@Sun.COM it_ini_free(it_ini_t *ini)
15117978SPeter.Dunlap@Sun.COM {
15127978SPeter.Dunlap@Sun.COM 	it_ini_free_cmn(ini);
15137978SPeter.Dunlap@Sun.COM }
15147978SPeter.Dunlap@Sun.COM 
15157978SPeter.Dunlap@Sun.COM /*
15167978SPeter.Dunlap@Sun.COM  * Goes through the target property list and validates
15177978SPeter.Dunlap@Sun.COM  * each entry.  If errs is non-NULL, will return explicit errors
15187978SPeter.Dunlap@Sun.COM  * for each property that fails validation.
15197978SPeter.Dunlap@Sun.COM  */
15207978SPeter.Dunlap@Sun.COM static int
15217978SPeter.Dunlap@Sun.COM it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs)
15227978SPeter.Dunlap@Sun.COM {
15237978SPeter.Dunlap@Sun.COM 	int		errcnt = 0;
15247978SPeter.Dunlap@Sun.COM 	nvpair_t	*nvp = NULL;
15257978SPeter.Dunlap@Sun.COM 	data_type_t	nvtype;
15267978SPeter.Dunlap@Sun.COM 	char		*name;
15277978SPeter.Dunlap@Sun.COM 	char		*val;
15287978SPeter.Dunlap@Sun.COM 	char		*auth = NULL;
15297978SPeter.Dunlap@Sun.COM 
15307978SPeter.Dunlap@Sun.COM 	if (!nvl) {
15317978SPeter.Dunlap@Sun.COM 		return (0);
15327978SPeter.Dunlap@Sun.COM 	}
15337978SPeter.Dunlap@Sun.COM 
15347978SPeter.Dunlap@Sun.COM 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
15357978SPeter.Dunlap@Sun.COM 		name = nvpair_name(nvp);
15367978SPeter.Dunlap@Sun.COM 		nvtype = nvpair_type(nvp);
15377978SPeter.Dunlap@Sun.COM 
15387978SPeter.Dunlap@Sun.COM 		if (!name) {
15397978SPeter.Dunlap@Sun.COM 			continue;
15407978SPeter.Dunlap@Sun.COM 		}
15417978SPeter.Dunlap@Sun.COM 
15427978SPeter.Dunlap@Sun.COM 		val = NULL;
15437978SPeter.Dunlap@Sun.COM 		if (strcmp(name, PROP_TARGET_CHAP_USER) == 0) {
15447978SPeter.Dunlap@Sun.COM 			if (nvtype != DATA_TYPE_STRING) {
15457978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
15467978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
15477978SPeter.Dunlap@Sun.COM 				errcnt++;
15487978SPeter.Dunlap@Sun.COM 				continue;
15497978SPeter.Dunlap@Sun.COM 			}
15507978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_TARGET_CHAP_SECRET) == 0) {
15517978SPeter.Dunlap@Sun.COM 			/*
15527978SPeter.Dunlap@Sun.COM 			 * must be between 12 and 255 chars in cleartext.
15537978SPeter.Dunlap@Sun.COM 			 * will be base64 encoded when it's set.
15547978SPeter.Dunlap@Sun.COM 			 */
15557978SPeter.Dunlap@Sun.COM 			if (nvtype == DATA_TYPE_STRING) {
15567978SPeter.Dunlap@Sun.COM 				(void) nvpair_value_string(nvp, &val);
15577978SPeter.Dunlap@Sun.COM 			}
15587978SPeter.Dunlap@Sun.COM 
15597978SPeter.Dunlap@Sun.COM 			if (!val) {
15607978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
15617978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
15627978SPeter.Dunlap@Sun.COM 				errcnt++;
15637978SPeter.Dunlap@Sun.COM 				continue;
15647978SPeter.Dunlap@Sun.COM 			}
15657978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_ALIAS) == 0) {
15667978SPeter.Dunlap@Sun.COM 			if (nvtype != DATA_TYPE_STRING) {
15677978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
15687978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
15697978SPeter.Dunlap@Sun.COM 				errcnt++;
15707978SPeter.Dunlap@Sun.COM 				continue;
15717978SPeter.Dunlap@Sun.COM 			}
15727978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_AUTH) == 0) {
15737978SPeter.Dunlap@Sun.COM 			if (nvtype == DATA_TYPE_STRING) {
15747978SPeter.Dunlap@Sun.COM 				val = NULL;
15757978SPeter.Dunlap@Sun.COM 				(void) nvpair_value_string(nvp, &val);
15767978SPeter.Dunlap@Sun.COM 			}
15777978SPeter.Dunlap@Sun.COM 
15787978SPeter.Dunlap@Sun.COM 			if (!val) {
15797978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
15807978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
15817978SPeter.Dunlap@Sun.COM 				errcnt++;
15827978SPeter.Dunlap@Sun.COM 				continue;
15837978SPeter.Dunlap@Sun.COM 			}
15847978SPeter.Dunlap@Sun.COM 			if ((strcmp(val, PA_AUTH_NONE) != 0) &&
15857978SPeter.Dunlap@Sun.COM 			    (strcmp(val, PA_AUTH_CHAP) != 0) &&
15867978SPeter.Dunlap@Sun.COM 			    (strcmp(val, PA_AUTH_RADIUS) != 0) &&
15877978SPeter.Dunlap@Sun.COM 			    (strcmp(val, "default") != 0)) {
15887978SPeter.Dunlap@Sun.COM 				PROPERR(errs, val, gettext(
15897978SPeter.Dunlap@Sun.COM 				    "must be none, chap, radius or default"));
15907978SPeter.Dunlap@Sun.COM 				errcnt++;
15917978SPeter.Dunlap@Sun.COM 			}
15927978SPeter.Dunlap@Sun.COM 			auth = val;
15937978SPeter.Dunlap@Sun.COM 			continue;
15947978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_OLD_TARGET_NAME) == 0) {
15957978SPeter.Dunlap@Sun.COM 			continue;
15967978SPeter.Dunlap@Sun.COM 		} else {
15977978SPeter.Dunlap@Sun.COM 			/* unrecognized property */
15987978SPeter.Dunlap@Sun.COM 			PROPERR(errs, name, gettext("unrecognized property"));
15997978SPeter.Dunlap@Sun.COM 			errcnt++;
16007978SPeter.Dunlap@Sun.COM 		}
16017978SPeter.Dunlap@Sun.COM 	}
16027978SPeter.Dunlap@Sun.COM 
16037978SPeter.Dunlap@Sun.COM 	if (errcnt) {
16047978SPeter.Dunlap@Sun.COM 		return (EINVAL);
16057978SPeter.Dunlap@Sun.COM 	}
16067978SPeter.Dunlap@Sun.COM 
16077978SPeter.Dunlap@Sun.COM 	/* if auth is being set to default, remove from this nvlist */
16087978SPeter.Dunlap@Sun.COM 	if (auth && (strcmp(auth, "default") == 0)) {
16097978SPeter.Dunlap@Sun.COM 		(void) nvlist_remove_all(nvl, PROP_AUTH);
16107978SPeter.Dunlap@Sun.COM 	}
16117978SPeter.Dunlap@Sun.COM 
16127978SPeter.Dunlap@Sun.COM 	return (0);
16137978SPeter.Dunlap@Sun.COM }
16147978SPeter.Dunlap@Sun.COM 
16157978SPeter.Dunlap@Sun.COM /*
16167978SPeter.Dunlap@Sun.COM  * Goes through the config property list and validates
16177978SPeter.Dunlap@Sun.COM  * each entry.  If errs is non-NULL, will return explicit errors
16187978SPeter.Dunlap@Sun.COM  * for each property that fails validation.
16197978SPeter.Dunlap@Sun.COM  */
16207978SPeter.Dunlap@Sun.COM static int
16217978SPeter.Dunlap@Sun.COM it_validate_configprops(nvlist_t *nvl, nvlist_t *errs)
16227978SPeter.Dunlap@Sun.COM {
16237978SPeter.Dunlap@Sun.COM 	int				errcnt = 0;
16247978SPeter.Dunlap@Sun.COM 	nvpair_t			*nvp = NULL;
16257978SPeter.Dunlap@Sun.COM 	data_type_t			nvtype;
16267978SPeter.Dunlap@Sun.COM 	char				*name;
16277978SPeter.Dunlap@Sun.COM 	char				*val;
16287978SPeter.Dunlap@Sun.COM 	struct sockaddr_storage		sa;
16298062SPeter.Dunlap@Sun.COM 	boolean_t			update_rad_server = B_FALSE;
16308062SPeter.Dunlap@Sun.COM 	char				*rad_server;
16317978SPeter.Dunlap@Sun.COM 	char				*auth = NULL;
16327978SPeter.Dunlap@Sun.COM 
16337978SPeter.Dunlap@Sun.COM 	if (!nvl) {
16347978SPeter.Dunlap@Sun.COM 		return (0);
16357978SPeter.Dunlap@Sun.COM 	}
16367978SPeter.Dunlap@Sun.COM 
16377978SPeter.Dunlap@Sun.COM 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
16387978SPeter.Dunlap@Sun.COM 		name = nvpair_name(nvp);
16397978SPeter.Dunlap@Sun.COM 		nvtype = nvpair_type(nvp);
16407978SPeter.Dunlap@Sun.COM 
16417978SPeter.Dunlap@Sun.COM 		if (!name) {
16427978SPeter.Dunlap@Sun.COM 			continue;
16437978SPeter.Dunlap@Sun.COM 		}
16447978SPeter.Dunlap@Sun.COM 
16457978SPeter.Dunlap@Sun.COM 		val = NULL;
16467978SPeter.Dunlap@Sun.COM 
16477978SPeter.Dunlap@Sun.COM 		/* prefetch string value as we mostly need it */
16487978SPeter.Dunlap@Sun.COM 		if (nvtype == DATA_TYPE_STRING) {
16497978SPeter.Dunlap@Sun.COM 			(void) nvpair_value_string(nvp, &val);
16507978SPeter.Dunlap@Sun.COM 		}
16517978SPeter.Dunlap@Sun.COM 
16527978SPeter.Dunlap@Sun.COM 		if (strcmp(name, PROP_ALIAS) == 0) {
16537978SPeter.Dunlap@Sun.COM 			if (!val) {
16547978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
16557978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
16567978SPeter.Dunlap@Sun.COM 				errcnt++;
16577978SPeter.Dunlap@Sun.COM 			}
16587978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_AUTH) == 0) {
16597978SPeter.Dunlap@Sun.COM 			if (!val) {
16607978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
16617978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
16627978SPeter.Dunlap@Sun.COM 				errcnt++;
16637978SPeter.Dunlap@Sun.COM 				continue;
16647978SPeter.Dunlap@Sun.COM 			}
16657978SPeter.Dunlap@Sun.COM 
16667978SPeter.Dunlap@Sun.COM 			if ((strcmp(val, PA_AUTH_NONE) != 0) &&
16677978SPeter.Dunlap@Sun.COM 			    (strcmp(val, PA_AUTH_CHAP) != 0) &&
16687978SPeter.Dunlap@Sun.COM 			    (strcmp(val, PA_AUTH_RADIUS) != 0)) {
16697978SPeter.Dunlap@Sun.COM 				PROPERR(errs, PROP_AUTH,
16707978SPeter.Dunlap@Sun.COM 				    gettext("must be none, chap or radius"));
16717978SPeter.Dunlap@Sun.COM 				errcnt++;
16727978SPeter.Dunlap@Sun.COM 			}
16737978SPeter.Dunlap@Sun.COM 
16747978SPeter.Dunlap@Sun.COM 			auth = val;
16757978SPeter.Dunlap@Sun.COM 
16767978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_ISNS_ENABLED) == 0) {
16777978SPeter.Dunlap@Sun.COM 			if (nvtype != DATA_TYPE_BOOLEAN_VALUE) {
16787978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
16797978SPeter.Dunlap@Sun.COM 				    gettext("must be a boolean value"));
16807978SPeter.Dunlap@Sun.COM 				errcnt++;
16817978SPeter.Dunlap@Sun.COM 			}
16827978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_ISNS_SERVER) == 0) {
16837978SPeter.Dunlap@Sun.COM 			char		**arr = NULL;
16847978SPeter.Dunlap@Sun.COM 			uint32_t	acount = 0;
16857978SPeter.Dunlap@Sun.COM 
16867978SPeter.Dunlap@Sun.COM 			(void) nvlist_lookup_string_array(nvl, name,
16877978SPeter.Dunlap@Sun.COM 			    &arr, &acount);
16887978SPeter.Dunlap@Sun.COM 
16897978SPeter.Dunlap@Sun.COM 			while (acount > 0) {
16907978SPeter.Dunlap@Sun.COM 				if (strcasecmp(arr[acount - 1], "none") == 0) {
16917978SPeter.Dunlap@Sun.COM 					break;
16927978SPeter.Dunlap@Sun.COM 				}
16937978SPeter.Dunlap@Sun.COM 				if ((it_common_convert_sa(arr[acount - 1],
16947978SPeter.Dunlap@Sun.COM 				    &sa, 0)) == NULL) {
16957978SPeter.Dunlap@Sun.COM 					PROPERR(errs, arr[acount - 1],
16967978SPeter.Dunlap@Sun.COM 					    gettext("invalid address"));
16977978SPeter.Dunlap@Sun.COM 					errcnt++;
16987978SPeter.Dunlap@Sun.COM 				}
16997978SPeter.Dunlap@Sun.COM 				acount--;
17007978SPeter.Dunlap@Sun.COM 			}
17017978SPeter.Dunlap@Sun.COM 
17027978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_RADIUS_SECRET) == 0) {
17037978SPeter.Dunlap@Sun.COM 			if (!val) {
17047978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
17057978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
17067978SPeter.Dunlap@Sun.COM 				errcnt++;
17077978SPeter.Dunlap@Sun.COM 				continue;
17087978SPeter.Dunlap@Sun.COM 			}
17097978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_RADIUS_SERVER) == 0) {
17107978SPeter.Dunlap@Sun.COM 			struct sockaddr_storage		sa;
17117978SPeter.Dunlap@Sun.COM 			if (!val) {
17127978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
17137978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
17147978SPeter.Dunlap@Sun.COM 				errcnt++;
17157978SPeter.Dunlap@Sun.COM 				continue;
17167978SPeter.Dunlap@Sun.COM 			}
17177978SPeter.Dunlap@Sun.COM 
17187978SPeter.Dunlap@Sun.COM 			if ((it_common_convert_sa(val, &sa,
17197978SPeter.Dunlap@Sun.COM 			    DEFAULT_RADIUS_PORT)) == NULL) {
17207978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
17217978SPeter.Dunlap@Sun.COM 				    gettext("invalid address"));
17227978SPeter.Dunlap@Sun.COM 				errcnt++;
17237978SPeter.Dunlap@Sun.COM 			} else {
17247978SPeter.Dunlap@Sun.COM 				/*
17257978SPeter.Dunlap@Sun.COM 				 * rewrite this property to ensure port
17267978SPeter.Dunlap@Sun.COM 				 * number is added.
17277978SPeter.Dunlap@Sun.COM 				 */
17287978SPeter.Dunlap@Sun.COM 
17298062SPeter.Dunlap@Sun.COM 				if (sockaddr_to_str(&sa, &rad_server) == 0) {
17308062SPeter.Dunlap@Sun.COM 					update_rad_server = B_TRUE;
17317978SPeter.Dunlap@Sun.COM 				}
17327978SPeter.Dunlap@Sun.COM 			}
17337978SPeter.Dunlap@Sun.COM 		} else {
17347978SPeter.Dunlap@Sun.COM 			/* unrecognized property */
17357978SPeter.Dunlap@Sun.COM 			PROPERR(errs, name, gettext("unrecognized property"));
17367978SPeter.Dunlap@Sun.COM 			errcnt++;
17377978SPeter.Dunlap@Sun.COM 		}
17387978SPeter.Dunlap@Sun.COM 	}
17397978SPeter.Dunlap@Sun.COM 
17407978SPeter.Dunlap@Sun.COM 	/*
17418062SPeter.Dunlap@Sun.COM 	 * If we successfully reformatted the radius server to add the port
17428062SPeter.Dunlap@Sun.COM 	 * number then update the nvlist
17438062SPeter.Dunlap@Sun.COM 	 */
17448062SPeter.Dunlap@Sun.COM 	if (update_rad_server) {
17458256SPriya.Krishnan@Sun.COM 		(void) nvlist_add_string(nvl, PROP_RADIUS_SERVER, rad_server);
174611852SSrivijitha.Dugganapalli@Sun.COM 		free(rad_server);
17478062SPeter.Dunlap@Sun.COM 	}
17488062SPeter.Dunlap@Sun.COM 
17498062SPeter.Dunlap@Sun.COM 	/*
17507978SPeter.Dunlap@Sun.COM 	 * if auth = radius, ensure radius server & secret are set.
17517978SPeter.Dunlap@Sun.COM 	 */
17527978SPeter.Dunlap@Sun.COM 	if (auth) {
17537978SPeter.Dunlap@Sun.COM 		if (strcmp(auth, PA_AUTH_RADIUS) == 0) {
17547978SPeter.Dunlap@Sun.COM 			/* need server & secret for radius */
17557978SPeter.Dunlap@Sun.COM 			if (!nvlist_exists(nvl, PROP_RADIUS_SERVER)) {
17567978SPeter.Dunlap@Sun.COM 				PROPERR(errs, PROP_RADIUS_SERVER,
17577978SPeter.Dunlap@Sun.COM 				    gettext("missing required property"));
17587978SPeter.Dunlap@Sun.COM 				errcnt++;
17597978SPeter.Dunlap@Sun.COM 			}
17607978SPeter.Dunlap@Sun.COM 			if (!nvlist_exists(nvl, PROP_RADIUS_SECRET)) {
17617978SPeter.Dunlap@Sun.COM 				PROPERR(errs, PROP_RADIUS_SECRET,
17627978SPeter.Dunlap@Sun.COM 				    gettext("missing required property"));
17637978SPeter.Dunlap@Sun.COM 				errcnt++;
17647978SPeter.Dunlap@Sun.COM 			}
17657978SPeter.Dunlap@Sun.COM 		}
17667978SPeter.Dunlap@Sun.COM 	}
17677978SPeter.Dunlap@Sun.COM 
17687978SPeter.Dunlap@Sun.COM 	if (errcnt) {
17697978SPeter.Dunlap@Sun.COM 		return (EINVAL);
17707978SPeter.Dunlap@Sun.COM 	}
17717978SPeter.Dunlap@Sun.COM 
17727978SPeter.Dunlap@Sun.COM 	return (0);
17737978SPeter.Dunlap@Sun.COM }
17747978SPeter.Dunlap@Sun.COM 
17757978SPeter.Dunlap@Sun.COM /*
17767978SPeter.Dunlap@Sun.COM  * Goes through the ini property list and validates
17777978SPeter.Dunlap@Sun.COM  * each entry.  If errs is non-NULL, will return explicit errors
17787978SPeter.Dunlap@Sun.COM  * for each property that fails validation.
17797978SPeter.Dunlap@Sun.COM  */
17807978SPeter.Dunlap@Sun.COM static int
17817978SPeter.Dunlap@Sun.COM it_validate_iniprops(nvlist_t *nvl, nvlist_t *errs)
17827978SPeter.Dunlap@Sun.COM {
17837978SPeter.Dunlap@Sun.COM 	int				errcnt = 0;
17847978SPeter.Dunlap@Sun.COM 	nvpair_t			*nvp = NULL;
17857978SPeter.Dunlap@Sun.COM 	data_type_t			nvtype;
17867978SPeter.Dunlap@Sun.COM 	char				*name;
17877978SPeter.Dunlap@Sun.COM 	char				*val;
17887978SPeter.Dunlap@Sun.COM 
17897978SPeter.Dunlap@Sun.COM 	if (!nvl) {
17907978SPeter.Dunlap@Sun.COM 		return (0);
17917978SPeter.Dunlap@Sun.COM 	}
17927978SPeter.Dunlap@Sun.COM 
17937978SPeter.Dunlap@Sun.COM 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
17947978SPeter.Dunlap@Sun.COM 		name = nvpair_name(nvp);
17957978SPeter.Dunlap@Sun.COM 		nvtype = nvpair_type(nvp);
17967978SPeter.Dunlap@Sun.COM 
17977978SPeter.Dunlap@Sun.COM 		if (!name) {
17987978SPeter.Dunlap@Sun.COM 			continue;
17997978SPeter.Dunlap@Sun.COM 		}
18007978SPeter.Dunlap@Sun.COM 
18017978SPeter.Dunlap@Sun.COM 		if (strcmp(name, PROP_CHAP_USER) == 0) {
18027978SPeter.Dunlap@Sun.COM 			if (nvtype != DATA_TYPE_STRING) {
18037978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
18047978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
18057978SPeter.Dunlap@Sun.COM 				errcnt++;
18067978SPeter.Dunlap@Sun.COM 				continue;
18077978SPeter.Dunlap@Sun.COM 			}
18087978SPeter.Dunlap@Sun.COM 		} else if (strcmp(name, PROP_CHAP_SECRET) == 0) {
18097978SPeter.Dunlap@Sun.COM 			/*
18107978SPeter.Dunlap@Sun.COM 			 * must be between 12 and 255 chars in cleartext.
18117978SPeter.Dunlap@Sun.COM 			 * will be base64 encoded when it's set.
18127978SPeter.Dunlap@Sun.COM 			 */
18137978SPeter.Dunlap@Sun.COM 			if (nvtype == DATA_TYPE_STRING) {
18147978SPeter.Dunlap@Sun.COM 				val = NULL;
18157978SPeter.Dunlap@Sun.COM 				(void) nvpair_value_string(nvp, &val);
18167978SPeter.Dunlap@Sun.COM 			}
18177978SPeter.Dunlap@Sun.COM 
18187978SPeter.Dunlap@Sun.COM 			if (!val) {
18197978SPeter.Dunlap@Sun.COM 				PROPERR(errs, name,
18207978SPeter.Dunlap@Sun.COM 				    gettext("must be a string value"));
18217978SPeter.Dunlap@Sun.COM 				errcnt++;
18227978SPeter.Dunlap@Sun.COM 				continue;
18237978SPeter.Dunlap@Sun.COM 			}
18247978SPeter.Dunlap@Sun.COM 		} else {
18257978SPeter.Dunlap@Sun.COM 			/* unrecognized property */
18267978SPeter.Dunlap@Sun.COM 			PROPERR(errs, name, gettext("unrecognized property"));
18277978SPeter.Dunlap@Sun.COM 			errcnt++;
18287978SPeter.Dunlap@Sun.COM 		}
18297978SPeter.Dunlap@Sun.COM 	}
18307978SPeter.Dunlap@Sun.COM 
18317978SPeter.Dunlap@Sun.COM 	if (errcnt) {
18327978SPeter.Dunlap@Sun.COM 		return (EINVAL);
18337978SPeter.Dunlap@Sun.COM 	}
18347978SPeter.Dunlap@Sun.COM 
18357978SPeter.Dunlap@Sun.COM 	return (0);
18367978SPeter.Dunlap@Sun.COM }
18377978SPeter.Dunlap@Sun.COM 
18387978SPeter.Dunlap@Sun.COM static int
18397978SPeter.Dunlap@Sun.COM it_iqn_generate(char *iqn_buf, int iqn_buf_len, char *opt_iqn_suffix)
18407978SPeter.Dunlap@Sun.COM {
18417978SPeter.Dunlap@Sun.COM 	int		ret;
18427978SPeter.Dunlap@Sun.COM 	uuid_t		id;
18437978SPeter.Dunlap@Sun.COM 	char		id_str[UUID_PRINTABLE_STRING_LENGTH];
18447978SPeter.Dunlap@Sun.COM 
18457978SPeter.Dunlap@Sun.COM 	uuid_generate_random(id);
18467978SPeter.Dunlap@Sun.COM 	uuid_unparse(id, id_str);
18477978SPeter.Dunlap@Sun.COM 
18487978SPeter.Dunlap@Sun.COM 	if (opt_iqn_suffix) {
18497978SPeter.Dunlap@Sun.COM 		ret = snprintf(iqn_buf, iqn_buf_len, "iqn.1986-03.com.sun:"
18507978SPeter.Dunlap@Sun.COM 		    "%02d:%s.%s", TARGET_NAME_VERS, id_str, opt_iqn_suffix);
18517978SPeter.Dunlap@Sun.COM 	} else {
18527978SPeter.Dunlap@Sun.COM 		ret = snprintf(iqn_buf, iqn_buf_len, "iqn.1986-03.com.sun:"
18537978SPeter.Dunlap@Sun.COM 		    "%02d:%s", TARGET_NAME_VERS, id_str);
18547978SPeter.Dunlap@Sun.COM 	}
18557978SPeter.Dunlap@Sun.COM 
18567978SPeter.Dunlap@Sun.COM 	if (ret > iqn_buf_len) {
18577978SPeter.Dunlap@Sun.COM 		return (1);
18587978SPeter.Dunlap@Sun.COM 	}
18597978SPeter.Dunlap@Sun.COM 
18607978SPeter.Dunlap@Sun.COM 	return (0);
18617978SPeter.Dunlap@Sun.COM }
18627978SPeter.Dunlap@Sun.COM 
18637978SPeter.Dunlap@Sun.COM static int
18647978SPeter.Dunlap@Sun.COM it_val_pass(char *name, char *val, nvlist_t *e)
18657978SPeter.Dunlap@Sun.COM {
18667978SPeter.Dunlap@Sun.COM 	size_t		sz;
18677978SPeter.Dunlap@Sun.COM 
18687978SPeter.Dunlap@Sun.COM 	if (!name || !val) {
18697978SPeter.Dunlap@Sun.COM 		return (EINVAL);
18707978SPeter.Dunlap@Sun.COM 	}
18717978SPeter.Dunlap@Sun.COM 
18727978SPeter.Dunlap@Sun.COM 	/*
18737978SPeter.Dunlap@Sun.COM 	 * must be at least 12 chars and less than 256 chars cleartext.
18747978SPeter.Dunlap@Sun.COM 	 */
18757978SPeter.Dunlap@Sun.COM 	sz = strlen(val);
18767978SPeter.Dunlap@Sun.COM 
18777978SPeter.Dunlap@Sun.COM 	/*
18787978SPeter.Dunlap@Sun.COM 	 * Since we will be automatically encoding secrets we don't really
18797978SPeter.Dunlap@Sun.COM 	 * need the prefix anymore.
18807978SPeter.Dunlap@Sun.COM 	 */
18817978SPeter.Dunlap@Sun.COM 	if (sz < 12) {
18827978SPeter.Dunlap@Sun.COM 		PROPERR(e, name, gettext("secret too short"));
18837978SPeter.Dunlap@Sun.COM 	} else if (sz > 255) {
18847978SPeter.Dunlap@Sun.COM 		PROPERR(e, name, gettext("secret too long"));
18857978SPeter.Dunlap@Sun.COM 	} else {
18867978SPeter.Dunlap@Sun.COM 		/* all is well */
18877978SPeter.Dunlap@Sun.COM 		return (0);
18887978SPeter.Dunlap@Sun.COM 	}
18897978SPeter.Dunlap@Sun.COM 
18907978SPeter.Dunlap@Sun.COM 	return (1);
18917978SPeter.Dunlap@Sun.COM }
18927978SPeter.Dunlap@Sun.COM 
18937978SPeter.Dunlap@Sun.COM /*
18947978SPeter.Dunlap@Sun.COM  * Function:  validate_iscsi_name()
18957978SPeter.Dunlap@Sun.COM  *
18967978SPeter.Dunlap@Sun.COM  * Ensures the passed-in string is a valid IQN or EUI iSCSI name
18977978SPeter.Dunlap@Sun.COM  *
18987978SPeter.Dunlap@Sun.COM  */
18997978SPeter.Dunlap@Sun.COM boolean_t
19007978SPeter.Dunlap@Sun.COM validate_iscsi_name(char *in_name)
19017978SPeter.Dunlap@Sun.COM {
19027978SPeter.Dunlap@Sun.COM 	size_t		in_len;
19037978SPeter.Dunlap@Sun.COM 	int		i;
19047978SPeter.Dunlap@Sun.COM 	char		month[3];
19057978SPeter.Dunlap@Sun.COM 
19067978SPeter.Dunlap@Sun.COM 	if (in_name == NULL) {
19077978SPeter.Dunlap@Sun.COM 		return (B_FALSE);
19087978SPeter.Dunlap@Sun.COM 	}
19097978SPeter.Dunlap@Sun.COM 
19107978SPeter.Dunlap@Sun.COM 	in_len = strlen(in_name);
19117978SPeter.Dunlap@Sun.COM 	if (in_len < 12) {
19127978SPeter.Dunlap@Sun.COM 		return (B_FALSE);
19137978SPeter.Dunlap@Sun.COM 	}
19147978SPeter.Dunlap@Sun.COM 
191510855SCharles.Ting@Sun.COM 	if (IS_IQN_NAME(in_name)) {
19167978SPeter.Dunlap@Sun.COM 		/*
19177978SPeter.Dunlap@Sun.COM 		 * IQN names are iqn.yyyy-mm.<xxx>
19187978SPeter.Dunlap@Sun.COM 		 */
19197978SPeter.Dunlap@Sun.COM 		if ((!isdigit(in_name[4])) ||
19207978SPeter.Dunlap@Sun.COM 		    (!isdigit(in_name[5])) ||
19217978SPeter.Dunlap@Sun.COM 		    (!isdigit(in_name[6])) ||
19227978SPeter.Dunlap@Sun.COM 		    (!isdigit(in_name[7])) ||
19237978SPeter.Dunlap@Sun.COM 		    (in_name[8] != '-') ||
19247978SPeter.Dunlap@Sun.COM 		    (!isdigit(in_name[9])) ||
19257978SPeter.Dunlap@Sun.COM 		    (!isdigit(in_name[10])) ||
19267978SPeter.Dunlap@Sun.COM 		    (in_name[11] != '.')) {
19277978SPeter.Dunlap@Sun.COM 			return (B_FALSE);
19287978SPeter.Dunlap@Sun.COM 		}
19297978SPeter.Dunlap@Sun.COM 
19307978SPeter.Dunlap@Sun.COM 		(void) strncpy(month, &(in_name[9]), 2);
19317978SPeter.Dunlap@Sun.COM 		month[2] = '\0';
19327978SPeter.Dunlap@Sun.COM 
19337978SPeter.Dunlap@Sun.COM 		i = atoi(month);
19347978SPeter.Dunlap@Sun.COM 		if ((i < 0) || (i > 12)) {
19357978SPeter.Dunlap@Sun.COM 			return (B_FALSE);
19367978SPeter.Dunlap@Sun.COM 		}
19377978SPeter.Dunlap@Sun.COM 
19388812SSam.Cramer@Sun.COM 		/*
19398812SSam.Cramer@Sun.COM 		 * RFC 3722: if using only ASCII chars, only the following
19408812SSam.Cramer@Sun.COM 		 * chars are allowed: dash, dot, colon, lower case a-z, 0-9.
19418812SSam.Cramer@Sun.COM 		 * We allow upper case names, which should be folded
19428812SSam.Cramer@Sun.COM 		 * to lower case names later.
19438812SSam.Cramer@Sun.COM 		 */
19448812SSam.Cramer@Sun.COM 		for (i = 12; i < in_len; i++) {
19458812SSam.Cramer@Sun.COM 			char c = in_name[i];
19468812SSam.Cramer@Sun.COM 
19478812SSam.Cramer@Sun.COM 			if ((c != '-') && (c != '.') && (c != ':') &&
19488812SSam.Cramer@Sun.COM 			    !isalpha(c) && !isdigit(c)) {
19498812SSam.Cramer@Sun.COM 				return (B_FALSE);
19508812SSam.Cramer@Sun.COM 			}
19518812SSam.Cramer@Sun.COM 		}
19528812SSam.Cramer@Sun.COM 
19537978SPeter.Dunlap@Sun.COM 		/* Finally, validate the overall length, in wide chars */
19547978SPeter.Dunlap@Sun.COM 		in_len = mbstowcs(NULL, in_name, 0);
19557978SPeter.Dunlap@Sun.COM 		if (in_len > ISCSI_NAME_LEN_MAX) {
19567978SPeter.Dunlap@Sun.COM 			return (B_FALSE);
19577978SPeter.Dunlap@Sun.COM 		}
195810855SCharles.Ting@Sun.COM 	} else if (IS_EUI_NAME(in_name)) {
19597978SPeter.Dunlap@Sun.COM 		/*
19607978SPeter.Dunlap@Sun.COM 		 * EUI names are "eui." + 16 hex chars
19617978SPeter.Dunlap@Sun.COM 		 */
19627978SPeter.Dunlap@Sun.COM 		if (in_len != 20) {
19637978SPeter.Dunlap@Sun.COM 			return (B_FALSE);
19647978SPeter.Dunlap@Sun.COM 		}
19657978SPeter.Dunlap@Sun.COM 
19667978SPeter.Dunlap@Sun.COM 		for (i = 4; i < in_len; i++) {
19677978SPeter.Dunlap@Sun.COM 			if (!isxdigit(in_name[i])) {
19687978SPeter.Dunlap@Sun.COM 				return (B_FALSE);
19697978SPeter.Dunlap@Sun.COM 			}
19707978SPeter.Dunlap@Sun.COM 		}
19717978SPeter.Dunlap@Sun.COM 	} else {
19727978SPeter.Dunlap@Sun.COM 		return (B_FALSE);
19737978SPeter.Dunlap@Sun.COM 	}
19747978SPeter.Dunlap@Sun.COM 
19757978SPeter.Dunlap@Sun.COM 	return (B_TRUE);
19767978SPeter.Dunlap@Sun.COM }
197710849SSusan.Gleeson@Sun.COM 
197810849SSusan.Gleeson@Sun.COM static boolean_t
197910849SSusan.Gleeson@Sun.COM is_iscsit_enabled(void)
198010849SSusan.Gleeson@Sun.COM {
198110849SSusan.Gleeson@Sun.COM 	char		*state;
198210849SSusan.Gleeson@Sun.COM 
198310849SSusan.Gleeson@Sun.COM 	state = smf_get_state(ISCSIT_FMRI);
198410849SSusan.Gleeson@Sun.COM 	if (state != NULL) {
198510849SSusan.Gleeson@Sun.COM 		if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) {
1986*12396SPeter.Gill@Sun.COM 			free(state);
198710849SSusan.Gleeson@Sun.COM 			return (B_TRUE);
198810849SSusan.Gleeson@Sun.COM 		}
198911852SSrivijitha.Dugganapalli@Sun.COM 		free(state);
199010849SSusan.Gleeson@Sun.COM 	}
199110849SSusan.Gleeson@Sun.COM 
199210849SSusan.Gleeson@Sun.COM 	return (B_FALSE);
199310849SSusan.Gleeson@Sun.COM }
199410855SCharles.Ting@Sun.COM 
199510855SCharles.Ting@Sun.COM /*
199610855SCharles.Ting@Sun.COM  * Function:  canonical_iscsi_name()
199710855SCharles.Ting@Sun.COM  *
199810855SCharles.Ting@Sun.COM  * Fold the iqn iscsi name to lower-case and the EUI-64 identifier of
199910855SCharles.Ting@Sun.COM  * the eui iscsi name to upper-case.
200010855SCharles.Ting@Sun.COM  * Ensures the passed-in string is a valid IQN or EUI iSCSI name
200110855SCharles.Ting@Sun.COM  */
200210855SCharles.Ting@Sun.COM void
200310855SCharles.Ting@Sun.COM canonical_iscsi_name(char *tgt)
200410855SCharles.Ting@Sun.COM {
200510855SCharles.Ting@Sun.COM 	if (IS_IQN_NAME(tgt)) {
200610855SCharles.Ting@Sun.COM 		/* lowercase iqn names */
200710855SCharles.Ting@Sun.COM 		iqnstr(tgt);
200810855SCharles.Ting@Sun.COM 	} else {
200910855SCharles.Ting@Sun.COM 		/* uppercase EUI-64 identifier */
201010855SCharles.Ting@Sun.COM 		euistr(tgt);
201110855SCharles.Ting@Sun.COM 	}
201210855SCharles.Ting@Sun.COM }
201310855SCharles.Ting@Sun.COM 
201410855SCharles.Ting@Sun.COM /*
201510855SCharles.Ting@Sun.COM  * Fold an iqn name to lower-case.
201610855SCharles.Ting@Sun.COM  */
201710855SCharles.Ting@Sun.COM static void
201810855SCharles.Ting@Sun.COM iqnstr(char *s)
201910855SCharles.Ting@Sun.COM {
202010855SCharles.Ting@Sun.COM 	if (s != NULL) {
202110855SCharles.Ting@Sun.COM 		while (*s) {
202210855SCharles.Ting@Sun.COM 			*s = tolower(*s);
202310855SCharles.Ting@Sun.COM 			s++;
202410855SCharles.Ting@Sun.COM 		}
202510855SCharles.Ting@Sun.COM 	}
202610855SCharles.Ting@Sun.COM }
202710855SCharles.Ting@Sun.COM 
202810855SCharles.Ting@Sun.COM /*
202910855SCharles.Ting@Sun.COM  * Fold the EUI-64 identifier of a eui name to upper-case.
203010855SCharles.Ting@Sun.COM  */
203110855SCharles.Ting@Sun.COM static void
203210855SCharles.Ting@Sun.COM euistr(char *s)
203310855SCharles.Ting@Sun.COM {
203410855SCharles.Ting@Sun.COM 	if (s != NULL) {
203510855SCharles.Ting@Sun.COM 		char *l = s + 4;
203610855SCharles.Ting@Sun.COM 		while (*l) {
203710855SCharles.Ting@Sun.COM 			*l = toupper(*l);
203810855SCharles.Ting@Sun.COM 			l++;
203910855SCharles.Ting@Sun.COM 		}
204010855SCharles.Ting@Sun.COM 	}
204110855SCharles.Ting@Sun.COM }
2042