xref: /titanic_44/usr/src/lib/libiscsit/common/libiscsit.c (revision 9fc69cd99026dc35cc62ad524193fa0dfd4de20f)
1a6d42e7dSPeter Dunlap /*
2a6d42e7dSPeter Dunlap  * CDDL HEADER START
3a6d42e7dSPeter Dunlap  *
4a6d42e7dSPeter Dunlap  * The contents of this file are subject to the terms of the
5a6d42e7dSPeter Dunlap  * Common Development and Distribution License (the "License").
6a6d42e7dSPeter Dunlap  * You may not use this file except in compliance with the License.
7a6d42e7dSPeter Dunlap  *
8a6d42e7dSPeter Dunlap  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a6d42e7dSPeter Dunlap  * or http://www.opensolaris.org/os/licensing.
10a6d42e7dSPeter Dunlap  * See the License for the specific language governing permissions
11a6d42e7dSPeter Dunlap  * and limitations under the License.
12a6d42e7dSPeter Dunlap  *
13a6d42e7dSPeter Dunlap  * When distributing Covered Code, include this CDDL HEADER in each
14a6d42e7dSPeter Dunlap  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a6d42e7dSPeter Dunlap  * If applicable, add the following below this CDDL HEADER, with the
16a6d42e7dSPeter Dunlap  * fields enclosed by brackets "[]" replaced with your own identifying
17a6d42e7dSPeter Dunlap  * information: Portions Copyright [yyyy] [name of copyright owner]
18a6d42e7dSPeter Dunlap  *
19a6d42e7dSPeter Dunlap  * CDDL HEADER END
20a6d42e7dSPeter Dunlap  */
21a6d42e7dSPeter Dunlap /*
2242bf653bSPeter Gill  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23a6d42e7dSPeter Dunlap  */
24*9fc69cd9SShampavman /*
25*9fc69cd9SShampavman  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
26*9fc69cd9SShampavman  */
27a6d42e7dSPeter Dunlap 
28a6d42e7dSPeter Dunlap #include <sys/types.h>
29a6d42e7dSPeter Dunlap #include <sys/stat.h>
30a6d42e7dSPeter Dunlap #include <ctype.h>
31a6d42e7dSPeter Dunlap #include <fcntl.h>
32a6d42e7dSPeter Dunlap #include <uuid/uuid.h>
33a6d42e7dSPeter Dunlap #include <errno.h>
34a6d42e7dSPeter Dunlap #include <unistd.h>
35a6d42e7dSPeter Dunlap #include <strings.h>
36a6d42e7dSPeter Dunlap #include <libintl.h>
375de03f84SSue Gleeson #include <libscf.h>
38a6d42e7dSPeter Dunlap 
39a6d42e7dSPeter Dunlap #include <libstmf.h>
40a6d42e7dSPeter Dunlap #include <libiscsit.h>
41a6d42e7dSPeter Dunlap #include <sys/iscsi_protocol.h>
42a6d42e7dSPeter Dunlap #include <sys/iscsit/isns_protocol.h>
43a6d42e7dSPeter Dunlap 
44a6d42e7dSPeter Dunlap /* From iscsitgtd */
45a6d42e7dSPeter Dunlap #define	TARGET_NAME_VERS	2
46a6d42e7dSPeter Dunlap 
47a6d42e7dSPeter Dunlap /* this should be defined someplace central... */
48a6d42e7dSPeter Dunlap #define	ISCSI_NAME_LEN_MAX	223
49a6d42e7dSPeter Dunlap 
50a6d42e7dSPeter Dunlap /* max length of a base64 encoded secret */
51a6d42e7dSPeter Dunlap #define	MAX_BASE64_LEN		341
52a6d42e7dSPeter Dunlap 
53a6d42e7dSPeter Dunlap /* Default RADIUS server port */
54a6d42e7dSPeter Dunlap #define	DEFAULT_RADIUS_PORT	1812
55a6d42e7dSPeter Dunlap 
565de03f84SSue Gleeson /* The iscsit SMF service FMRI */
575de03f84SSue Gleeson #define	ISCSIT_FMRI		"svc:/network/iscsi/target:default"
58a6d42e7dSPeter Dunlap /*
59a6d42e7dSPeter Dunlap  * The kernel reserves target portal group tag value 1 as the default.
60a6d42e7dSPeter Dunlap  */
61a6d42e7dSPeter Dunlap #define	ISCSIT_DEFAULT_TPGT	1
62a6d42e7dSPeter Dunlap #define	MAXTAG			0xffff
63a6d42e7dSPeter Dunlap 
64a6d42e7dSPeter Dunlap /* helper for property list validation */
65a6d42e7dSPeter Dunlap #define	PROPERR(lst, key, value) { \
66a6d42e7dSPeter Dunlap 	if (lst) { \
67a6d42e7dSPeter Dunlap 		(void) nvlist_add_string(lst, key, value); \
68a6d42e7dSPeter Dunlap 	} \
69a6d42e7dSPeter Dunlap }
70a6d42e7dSPeter Dunlap 
71a6d42e7dSPeter Dunlap /* helper function declarations */
72a6d42e7dSPeter Dunlap static int
73a6d42e7dSPeter Dunlap it_iqn_generate(char *iqn_buf, int iqn_buf_len, char *opt_iqn_suffix);
74a6d42e7dSPeter Dunlap 
75a6d42e7dSPeter Dunlap static int
76a6d42e7dSPeter Dunlap it_val_pass(char *name, char *val, nvlist_t *e);
77a6d42e7dSPeter Dunlap 
78a6d42e7dSPeter Dunlap /* consider making validate funcs public */
79a6d42e7dSPeter Dunlap static int
80a6d42e7dSPeter Dunlap it_validate_configprops(nvlist_t *nvl, nvlist_t *errs);
81a6d42e7dSPeter Dunlap 
82a6d42e7dSPeter Dunlap static int
83a6d42e7dSPeter Dunlap it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs);
84a6d42e7dSPeter Dunlap 
85a6d42e7dSPeter Dunlap static int
86a6d42e7dSPeter Dunlap it_validate_iniprops(nvlist_t *nvl, nvlist_t *errs);
87a6d42e7dSPeter Dunlap 
885de03f84SSue Gleeson static boolean_t
895de03f84SSue Gleeson is_iscsit_enabled(void);
905de03f84SSue Gleeson 
91fcc214c3SCharles Ting static void
92fcc214c3SCharles Ting iqnstr(char *s);
93fcc214c3SCharles Ting 
94fcc214c3SCharles Ting static void
95fcc214c3SCharles Ting euistr(char *s);
96fcc214c3SCharles Ting 
97a6d42e7dSPeter Dunlap /*
98a6d42e7dSPeter Dunlap  * Function:  it_config_load()
99a6d42e7dSPeter Dunlap  *
100a6d42e7dSPeter Dunlap  * Allocate and create an it_config_t structure representing the
101a6d42e7dSPeter Dunlap  * current iSCSI configuration.  This structure is compiled using
102a6d42e7dSPeter Dunlap  * the 'provider' data returned by stmfGetProviderData().  If there
103a6d42e7dSPeter Dunlap  * is no provider data associated with iscsit, the it_config_t
104a6d42e7dSPeter Dunlap  * structure will be set to a default configuration.
105a6d42e7dSPeter Dunlap  *
106a6d42e7dSPeter Dunlap  * Parameters:
107a6d42e7dSPeter Dunlap  *    cfg	A C representation of the current iSCSI configuration
108a6d42e7dSPeter Dunlap  *
109a6d42e7dSPeter Dunlap  * Return Values:
110a6d42e7dSPeter Dunlap  *    0		Success
111a6d42e7dSPeter Dunlap  *    ENOMEM	Could not allocate resources
112a6d42e7dSPeter Dunlap  *    EINVAL	Invalid parameter
113a6d42e7dSPeter Dunlap  */
114a6d42e7dSPeter Dunlap int
it_config_load(it_config_t ** cfg)115a6d42e7dSPeter Dunlap it_config_load(it_config_t **cfg)
116a6d42e7dSPeter Dunlap {
117a6d42e7dSPeter Dunlap 	int		ret = 0;
118a6d42e7dSPeter Dunlap 	nvlist_t	*cfg_nv = NULL;
119a6d42e7dSPeter Dunlap 	it_config_t	*newcfg = NULL;
120a6d42e7dSPeter Dunlap 	uint64_t	stmf_token = 0;
121a6d42e7dSPeter Dunlap 
122a6d42e7dSPeter Dunlap 	if (!cfg) {
123a6d42e7dSPeter Dunlap 		return (EINVAL);
124a6d42e7dSPeter Dunlap 	}
125a6d42e7dSPeter Dunlap 
126a6d42e7dSPeter Dunlap 	*cfg = NULL;
127a6d42e7dSPeter Dunlap 
128a6d42e7dSPeter Dunlap 	ret = stmfGetProviderDataProt(ISCSIT_MODNAME, &cfg_nv,
129a6d42e7dSPeter Dunlap 	    STMF_PORT_PROVIDER_TYPE, &stmf_token);
130a6d42e7dSPeter Dunlap 
131a6d42e7dSPeter Dunlap 	if ((ret == STMF_STATUS_SUCCESS) ||
132a6d42e7dSPeter Dunlap 	    (ret == STMF_ERROR_NOT_FOUND)) {
133a6d42e7dSPeter Dunlap 		/*
134a6d42e7dSPeter Dunlap 		 * If not initialized yet, return empty it_config_t
135a6d42e7dSPeter Dunlap 		 * Else, convert nvlist to struct
136a6d42e7dSPeter Dunlap 		 */
137a6d42e7dSPeter Dunlap 		ret = it_nv_to_config(cfg_nv, &newcfg);
138a6d42e7dSPeter Dunlap 	}
139a6d42e7dSPeter Dunlap 
140a6d42e7dSPeter Dunlap 	if (ret == 0) {
141a6d42e7dSPeter Dunlap 		newcfg->stmf_token = stmf_token;
142a6d42e7dSPeter Dunlap 		*cfg = newcfg;
143a6d42e7dSPeter Dunlap 	}
144a6d42e7dSPeter Dunlap 
1453c006dd5SCharles Ting 	if (cfg_nv) {
1463c006dd5SCharles Ting 		nvlist_free(cfg_nv);
1473c006dd5SCharles Ting 	}
1483c006dd5SCharles Ting 
149a6d42e7dSPeter Dunlap 	return (ret);
150a6d42e7dSPeter Dunlap }
151a6d42e7dSPeter Dunlap 
152a6d42e7dSPeter Dunlap /*
153a6d42e7dSPeter Dunlap  * Function:  it_config_commit()
154a6d42e7dSPeter Dunlap  *
155a6d42e7dSPeter Dunlap  * Informs the iscsit service that the configuration has changed and
156a6d42e7dSPeter Dunlap  * commits the new configuration to persistent store by calling
157a6d42e7dSPeter Dunlap  * stmfSetProviderData.  This function can be called multiple times
158a6d42e7dSPeter Dunlap  * during a configuration sequence if necessary.
159a6d42e7dSPeter Dunlap  *
160a6d42e7dSPeter Dunlap  * Parameters:
161a6d42e7dSPeter Dunlap  *    cfg	A C representation of the current iSCSI configuration
162a6d42e7dSPeter Dunlap  *
163a6d42e7dSPeter Dunlap  * Return Values:
164a6d42e7dSPeter Dunlap  *    0		Success
165a6d42e7dSPeter Dunlap  *    ENOMEM	Could not allocate resources
166a6d42e7dSPeter Dunlap  *    EINVAL	Invalid it_config_t structure
167a6d42e7dSPeter Dunlap  *    TBD	ioctl() failed
168a6d42e7dSPeter Dunlap  *    TBD	could not save config to STMF
169a6d42e7dSPeter Dunlap  */
170a6d42e7dSPeter Dunlap int
it_config_commit(it_config_t * cfg)171a6d42e7dSPeter Dunlap it_config_commit(it_config_t *cfg)
172a6d42e7dSPeter Dunlap {
173a6d42e7dSPeter Dunlap 	int			ret;
174a6d42e7dSPeter Dunlap 	nvlist_t		*cfgnv = NULL;
175a6d42e7dSPeter Dunlap 	char			*packednv = NULL;
176a6d42e7dSPeter Dunlap 	int			iscsit_fd = -1;
177a6d42e7dSPeter Dunlap 	size_t			pnv_size;
178a6d42e7dSPeter Dunlap 	iscsit_ioc_set_config_t	iop;
179a6d42e7dSPeter Dunlap 	it_tgt_t		*tgtp;
180a6d42e7dSPeter Dunlap 
181a6d42e7dSPeter Dunlap 	if (!cfg) {
182a6d42e7dSPeter Dunlap 		return (EINVAL);
183a6d42e7dSPeter Dunlap 	}
184a6d42e7dSPeter Dunlap 
185a6d42e7dSPeter Dunlap 	ret = it_config_to_nv(cfg, &cfgnv);
186a6d42e7dSPeter Dunlap 	if (ret == 0) {
187a6d42e7dSPeter Dunlap 		ret = nvlist_size(cfgnv, &pnv_size, NV_ENCODE_NATIVE);
188a6d42e7dSPeter Dunlap 	}
189a6d42e7dSPeter Dunlap 
1905de03f84SSue Gleeson 	/*
1915de03f84SSue Gleeson 	 * If the iscsit service is enabled, send the changes to the
1925de03f84SSue Gleeson 	 * kernel first.  Kernel will be the final sanity check before
1935de03f84SSue Gleeson 	 * the config is saved persistently.
1945de03f84SSue Gleeson 	 *
1955de03f84SSue Gleeson 	 * This somewhat leaves open the simultaneous-change hole
1965de03f84SSue Gleeson 	 * that STMF was trying to solve, but is a better sanity
1975de03f84SSue Gleeson 	 * check and allows for graceful handling of target renames.
1985de03f84SSue Gleeson 	 */
1995de03f84SSue Gleeson 	if ((ret == 0) && is_iscsit_enabled()) {
200a6d42e7dSPeter Dunlap 		packednv = malloc(pnv_size);
201a6d42e7dSPeter Dunlap 		if (!packednv) {
202a6d42e7dSPeter Dunlap 			ret = ENOMEM;
203a6d42e7dSPeter Dunlap 		} else {
204a6d42e7dSPeter Dunlap 			ret = nvlist_pack(cfgnv, &packednv, &pnv_size,
205a6d42e7dSPeter Dunlap 			    NV_ENCODE_NATIVE, 0);
206a6d42e7dSPeter Dunlap 		}
207a6d42e7dSPeter Dunlap 
208a6d42e7dSPeter Dunlap 		if (ret == 0) {
2095de03f84SSue Gleeson 			iscsit_fd = open(ISCSIT_NODE, O_RDWR|O_EXCL);
2105de03f84SSue Gleeson 			if (iscsit_fd != -1) {
211a6d42e7dSPeter Dunlap 				iop.set_cfg_vers = ISCSIT_API_VERS0;
212a6d42e7dSPeter Dunlap 				iop.set_cfg_pnvlist = packednv;
213a6d42e7dSPeter Dunlap 				iop.set_cfg_pnvlist_len = pnv_size;
2145de03f84SSue Gleeson 				if ((ioctl(iscsit_fd, ISCSIT_IOC_SET_CONFIG,
2155de03f84SSue Gleeson 				    &iop)) != 0) {
216a6d42e7dSPeter Dunlap 					ret = errno;
217a6d42e7dSPeter Dunlap 				}
2185de03f84SSue Gleeson 
2195de03f84SSue Gleeson 				(void) close(iscsit_fd);
2205de03f84SSue Gleeson 			} else {
2215de03f84SSue Gleeson 				ret = errno;
2225de03f84SSue Gleeson 			}
2235de03f84SSue Gleeson 		}
2245de03f84SSue Gleeson 
2255de03f84SSue Gleeson 		if (packednv != NULL) {
2265de03f84SSue Gleeson 			free(packednv);
2275de03f84SSue Gleeson 		}
228a6d42e7dSPeter Dunlap 	}
229a6d42e7dSPeter Dunlap 
230a6d42e7dSPeter Dunlap 	/*
231a6d42e7dSPeter Dunlap 	 * Before saving the config persistently, remove any
232a6d42e7dSPeter Dunlap 	 * PROP_OLD_TARGET_NAME entries.  This is only interesting to
233a6d42e7dSPeter Dunlap 	 * the active service.
234a6d42e7dSPeter Dunlap 	 */
235a6d42e7dSPeter Dunlap 	if (ret == 0) {
2365de03f84SSue Gleeson 		boolean_t	changed = B_FALSE;
2375de03f84SSue Gleeson 
238a6d42e7dSPeter Dunlap 		tgtp = cfg->config_tgt_list;
239a6d42e7dSPeter Dunlap 		for (; tgtp != NULL; tgtp = tgtp->tgt_next) {
240a6d42e7dSPeter Dunlap 			if (!tgtp->tgt_properties) {
241a6d42e7dSPeter Dunlap 				continue;
242a6d42e7dSPeter Dunlap 			}
243a6d42e7dSPeter Dunlap 			if (nvlist_exists(tgtp->tgt_properties,
244a6d42e7dSPeter Dunlap 			    PROP_OLD_TARGET_NAME)) {
245a6d42e7dSPeter Dunlap 				(void) nvlist_remove_all(tgtp->tgt_properties,
246a6d42e7dSPeter Dunlap 				    PROP_OLD_TARGET_NAME);
2475de03f84SSue Gleeson 				changed = B_TRUE;
248a6d42e7dSPeter Dunlap 			}
249a6d42e7dSPeter Dunlap 		}
2505de03f84SSue Gleeson 
2515de03f84SSue Gleeson 		if (changed) {
2525de03f84SSue Gleeson 			/* rebuild the config nvlist */
2535de03f84SSue Gleeson 			nvlist_free(cfgnv);
2545de03f84SSue Gleeson 			cfgnv = NULL;
2555de03f84SSue Gleeson 			ret = it_config_to_nv(cfg, &cfgnv);
2565de03f84SSue Gleeson 		}
257a6d42e7dSPeter Dunlap 	}
258a6d42e7dSPeter Dunlap 
259a6d42e7dSPeter Dunlap 	/*
260a6d42e7dSPeter Dunlap 	 * stmfGetProviderDataProt() checks to ensure
261a6d42e7dSPeter Dunlap 	 * that the config data hasn't changed since we fetched it.
262a6d42e7dSPeter Dunlap 	 *
263a6d42e7dSPeter Dunlap 	 * The kernel now has a version we need to save persistently.
264a6d42e7dSPeter Dunlap 	 * CLI will 'do the right thing' and warn the user if it
265a6d42e7dSPeter Dunlap 	 * gets STMF_ERROR_PROV_DATA_STALE.  We'll try once to revert
266a6d42e7dSPeter Dunlap 	 * the kernel to the persistently saved data, but ultimately,
267a6d42e7dSPeter Dunlap 	 * it's up to the administrator to validate things are as they
268a6d42e7dSPeter Dunlap 	 * want them to be.
269a6d42e7dSPeter Dunlap 	 */
270a6d42e7dSPeter Dunlap 	if (ret == 0) {
271a6d42e7dSPeter Dunlap 		ret = stmfSetProviderDataProt(ISCSIT_MODNAME, cfgnv,
272a6d42e7dSPeter Dunlap 		    STMF_PORT_PROVIDER_TYPE, &(cfg->stmf_token));
273a6d42e7dSPeter Dunlap 
274a6d42e7dSPeter Dunlap 		if (ret == STMF_STATUS_SUCCESS) {
275a6d42e7dSPeter Dunlap 			ret = 0;
276a6d42e7dSPeter Dunlap 		} else if (ret == STMF_ERROR_NOMEM) {
277a6d42e7dSPeter Dunlap 			ret = ENOMEM;
278a6d42e7dSPeter Dunlap 		} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
279a6d42e7dSPeter Dunlap 			int		st;
280a6d42e7dSPeter Dunlap 			it_config_t	*rcfg = NULL;
281a6d42e7dSPeter Dunlap 
282a6d42e7dSPeter Dunlap 			st = it_config_load(&rcfg);
283a6d42e7dSPeter Dunlap 			if (st == 0) {
284a6d42e7dSPeter Dunlap 				(void) it_config_commit(rcfg);
285a6d42e7dSPeter Dunlap 				it_config_free(rcfg);
286a6d42e7dSPeter Dunlap 			}
287a6d42e7dSPeter Dunlap 		}
288a6d42e7dSPeter Dunlap 	}
289a6d42e7dSPeter Dunlap 
290a6d42e7dSPeter Dunlap 	if (cfgnv) {
291a6d42e7dSPeter Dunlap 		nvlist_free(cfgnv);
292a6d42e7dSPeter Dunlap 	}
293a6d42e7dSPeter Dunlap 
294a6d42e7dSPeter Dunlap 	return (ret);
295a6d42e7dSPeter Dunlap }
296a6d42e7dSPeter Dunlap 
297a6d42e7dSPeter Dunlap /*
298a6d42e7dSPeter Dunlap  * Function:  it_config_setprop()
299a6d42e7dSPeter Dunlap  *
300a6d42e7dSPeter Dunlap  * Validate the provided property list and set the global properties
301a6d42e7dSPeter Dunlap  * for iSCSI Target.  If errlist is not NULL, returns detailed
302a6d42e7dSPeter Dunlap  * errors for each property that failed.  The format for errorlist
303a6d42e7dSPeter Dunlap  * is key = property, value = error string.
304a6d42e7dSPeter Dunlap  *
305a6d42e7dSPeter Dunlap  * Parameters:
306a6d42e7dSPeter Dunlap  *
307a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
308a6d42e7dSPeter Dunlap  *			it_config_load()
309a6d42e7dSPeter Dunlap  *    proplist		nvlist_t containing properties for this target.
310a6d42e7dSPeter Dunlap  *    errlist		(optional)  nvlist_t of errors encountered when
311a6d42e7dSPeter Dunlap  *                      validating the properties.
312a6d42e7dSPeter Dunlap  *
313a6d42e7dSPeter Dunlap  * Return Values:
314a6d42e7dSPeter Dunlap  *    0			Success
315a6d42e7dSPeter Dunlap  *    EINVAL		Invalid property
316a6d42e7dSPeter Dunlap  *
317a6d42e7dSPeter Dunlap  */
318a6d42e7dSPeter Dunlap int
it_config_setprop(it_config_t * cfg,nvlist_t * proplist,nvlist_t ** errlist)319a6d42e7dSPeter Dunlap it_config_setprop(it_config_t *cfg, nvlist_t *proplist, nvlist_t **errlist)
320a6d42e7dSPeter Dunlap {
321a6d42e7dSPeter Dunlap 	int		ret;
3228175704fSPeter Gill 	nvlist_t	*errs = NULL;
323a6d42e7dSPeter Dunlap 	it_portal_t	*isns = NULL;
324a6d42e7dSPeter Dunlap 	it_portal_t	*pnext = NULL;
325a6d42e7dSPeter Dunlap 	it_portal_t	*newisnslist = NULL;
326a6d42e7dSPeter Dunlap 	char		**arr;
327a6d42e7dSPeter Dunlap 	uint32_t	count;
328a6d42e7dSPeter Dunlap 	uint32_t	newcount;
329a6d42e7dSPeter Dunlap 	nvlist_t	*cprops = NULL;
330a6d42e7dSPeter Dunlap 	char		*val = NULL;
331a6d42e7dSPeter Dunlap 
332a6d42e7dSPeter Dunlap 	if (!cfg || !proplist) {
333a6d42e7dSPeter Dunlap 		return (EINVAL);
334a6d42e7dSPeter Dunlap 	}
335a6d42e7dSPeter Dunlap 
336a6d42e7dSPeter Dunlap 	if (errlist) {
3378175704fSPeter Gill 		(void) nvlist_alloc(&errs, 0, 0);
3388175704fSPeter Gill 		*errlist = errs;
339a6d42e7dSPeter Dunlap 	}
340a6d42e7dSPeter Dunlap 
341a6d42e7dSPeter Dunlap 	/*
342a6d42e7dSPeter Dunlap 	 * copy the existing properties, merge, then validate
343a6d42e7dSPeter Dunlap 	 * the merged properties before committing them.
344a6d42e7dSPeter Dunlap 	 */
345a6d42e7dSPeter Dunlap 	if (cfg->config_global_properties) {
346a6d42e7dSPeter Dunlap 		ret = nvlist_dup(cfg->config_global_properties, &cprops, 0);
347a6d42e7dSPeter Dunlap 	} else {
348a6d42e7dSPeter Dunlap 		ret = nvlist_alloc(&cprops, NV_UNIQUE_NAME, 0);
349a6d42e7dSPeter Dunlap 	}
350a6d42e7dSPeter Dunlap 
3517f6f3ee7SPeter Gill 	if (ret != 0) {
3527f6f3ee7SPeter Gill 		return (ret);
3537f6f3ee7SPeter Gill 	}
3547f6f3ee7SPeter Gill 
3557f6f3ee7SPeter Gill 	ret = nvlist_merge(cprops, proplist, 0);
3567f6f3ee7SPeter Gill 	if (ret != 0) {
3577f6f3ee7SPeter Gill 		nvlist_free(cprops);
3587f6f3ee7SPeter Gill 		return (ret);
3597f6f3ee7SPeter Gill 	}
3607f6f3ee7SPeter Gill 
3617f6f3ee7SPeter Gill 	/*
3627f6f3ee7SPeter Gill 	 * base64 encode the radius secret, if it's changed.
3637f6f3ee7SPeter Gill 	 */
364a6d42e7dSPeter Dunlap 	val = NULL;
365a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(proplist, PROP_RADIUS_SECRET, &val);
366a6d42e7dSPeter Dunlap 	if (val) {
367a6d42e7dSPeter Dunlap 		char		bsecret[MAX_BASE64_LEN];
368a6d42e7dSPeter Dunlap 
3698175704fSPeter Gill 		ret = it_val_pass(PROP_RADIUS_SECRET, val, errs);
370a6d42e7dSPeter Dunlap 
371a6d42e7dSPeter Dunlap 		if (ret == 0) {
372a6d42e7dSPeter Dunlap 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
373a6d42e7dSPeter Dunlap 
374a6d42e7dSPeter Dunlap 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
375a6d42e7dSPeter Dunlap 			    strlen(val), bsecret, MAX_BASE64_LEN);
376a6d42e7dSPeter Dunlap 
377a6d42e7dSPeter Dunlap 			if (ret == 0) {
378a6d42e7dSPeter Dunlap 				/* replace the value in the nvlist */
3797f6f3ee7SPeter Gill 				ret = nvlist_add_string(cprops,
380a6d42e7dSPeter Dunlap 				    PROP_RADIUS_SECRET, bsecret);
381a6d42e7dSPeter Dunlap 			}
382a6d42e7dSPeter Dunlap 		}
383a6d42e7dSPeter Dunlap 	}
384a6d42e7dSPeter Dunlap 
3857f6f3ee7SPeter Gill 	if (ret != 0) {
3867f6f3ee7SPeter Gill 		nvlist_free(cprops);
3877f6f3ee7SPeter Gill 		return (ret);
388a6d42e7dSPeter Dunlap 	}
389a6d42e7dSPeter Dunlap 
390a6d42e7dSPeter Dunlap 	/* see if we need to remove the radius server setting */
391a6d42e7dSPeter Dunlap 	val = NULL;
392a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(cprops, PROP_RADIUS_SERVER, &val);
393a6d42e7dSPeter Dunlap 	if (val && (strcasecmp(val, "none") == 0)) {
394a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(cprops, PROP_RADIUS_SERVER);
395a6d42e7dSPeter Dunlap 	}
396a6d42e7dSPeter Dunlap 
397a6d42e7dSPeter Dunlap 	/* and/or remove the alias */
398a6d42e7dSPeter Dunlap 	val = NULL;
399a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(cprops, PROP_ALIAS, &val);
400a6d42e7dSPeter Dunlap 	if (val && (strcasecmp(val, "none") == 0)) {
401a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(cprops, PROP_ALIAS);
402a6d42e7dSPeter Dunlap 	}
403a6d42e7dSPeter Dunlap 
4048175704fSPeter Gill 	ret = it_validate_configprops(cprops, errs);
405a6d42e7dSPeter Dunlap 	if (ret != 0) {
406a6d42e7dSPeter Dunlap 		if (cprops) {
407a6d42e7dSPeter Dunlap 			nvlist_free(cprops);
408a6d42e7dSPeter Dunlap 		}
409a6d42e7dSPeter Dunlap 		return (ret);
410a6d42e7dSPeter Dunlap 	}
411a6d42e7dSPeter Dunlap 
412a6d42e7dSPeter Dunlap 	/*
413a6d42e7dSPeter Dunlap 	 * Update iSNS server list, if exists in provided property list.
414a6d42e7dSPeter Dunlap 	 */
415a6d42e7dSPeter Dunlap 	ret = nvlist_lookup_string_array(proplist, PROP_ISNS_SERVER,
416a6d42e7dSPeter Dunlap 	    &arr, &count);
417a6d42e7dSPeter Dunlap 
418a6d42e7dSPeter Dunlap 	if (ret == 0) {
419a6d42e7dSPeter Dunlap 		/* special case:  if "none", remove all defined */
420a6d42e7dSPeter Dunlap 		if (strcasecmp(arr[0], "none") != 0) {
421a6d42e7dSPeter Dunlap 			ret = it_array_to_portallist(arr, count,
422a6d42e7dSPeter Dunlap 			    ISNS_DEFAULT_SERVER_PORT, &newisnslist, &newcount);
423a6d42e7dSPeter Dunlap 		} else {
424a6d42e7dSPeter Dunlap 			newisnslist = NULL;
425a6d42e7dSPeter Dunlap 			newcount = 0;
426a6d42e7dSPeter Dunlap 			(void) nvlist_remove_all(cprops, PROP_ISNS_SERVER);
427a6d42e7dSPeter Dunlap 		}
428a6d42e7dSPeter Dunlap 
429a6d42e7dSPeter Dunlap 		if (ret == 0) {
430a6d42e7dSPeter Dunlap 			isns = cfg->config_isns_svr_list;
431a6d42e7dSPeter Dunlap 			while (isns) {
43242bf653bSPeter Gill 				pnext = isns->portal_next;
433a6d42e7dSPeter Dunlap 				free(isns);
434a6d42e7dSPeter Dunlap 				isns = pnext;
435a6d42e7dSPeter Dunlap 			}
436a6d42e7dSPeter Dunlap 
437a6d42e7dSPeter Dunlap 			cfg->config_isns_svr_list = newisnslist;
438a6d42e7dSPeter Dunlap 			cfg->config_isns_svr_count = newcount;
439a6d42e7dSPeter Dunlap 
440a6d42e7dSPeter Dunlap 			/*
441a6d42e7dSPeter Dunlap 			 * Replace the array in the nvlist to ensure
442a6d42e7dSPeter Dunlap 			 * duplicates are properly removed & port numbers
443a6d42e7dSPeter Dunlap 			 * are added.
444a6d42e7dSPeter Dunlap 			 */
445a6d42e7dSPeter Dunlap 			if (newcount > 0) {
446a6d42e7dSPeter Dunlap 				int	i = 0;
447a6d42e7dSPeter Dunlap 				char	**newarray;
448a6d42e7dSPeter Dunlap 
449a6d42e7dSPeter Dunlap 				newarray = malloc(sizeof (char *) * newcount);
450a6d42e7dSPeter Dunlap 				if (newarray == NULL) {
451a6d42e7dSPeter Dunlap 					ret = ENOMEM;
452a6d42e7dSPeter Dunlap 				} else {
453a6d42e7dSPeter Dunlap 					for (isns = newisnslist; isns != NULL;
45442bf653bSPeter Gill 					    isns = isns->portal_next) {
455a6d42e7dSPeter Dunlap 						(void) sockaddr_to_str(
456a6d42e7dSPeter Dunlap 						    &(isns->portal_addr),
457a6d42e7dSPeter Dunlap 						    &(newarray[i++]));
458a6d42e7dSPeter Dunlap 					}
459a6d42e7dSPeter Dunlap 					(void) nvlist_add_string_array(cprops,
460a6d42e7dSPeter Dunlap 					    PROP_ISNS_SERVER, newarray,
461a6d42e7dSPeter Dunlap 					    newcount);
462a6d42e7dSPeter Dunlap 
463a6d42e7dSPeter Dunlap 					for (i = 0; i < newcount; i++) {
464a6d42e7dSPeter Dunlap 						if (newarray[i]) {
465a6d42e7dSPeter Dunlap 							free(newarray[i]);
466a6d42e7dSPeter Dunlap 						}
467a6d42e7dSPeter Dunlap 					}
468a6d42e7dSPeter Dunlap 					free(newarray);
469a6d42e7dSPeter Dunlap 				}
470a6d42e7dSPeter Dunlap 			}
471a6d42e7dSPeter Dunlap 		}
472a6d42e7dSPeter Dunlap 	} else if (ret == ENOENT) {
473a6d42e7dSPeter Dunlap 		/* not an error */
474a6d42e7dSPeter Dunlap 		ret = 0;
475a6d42e7dSPeter Dunlap 	}
476a6d42e7dSPeter Dunlap 
477a6d42e7dSPeter Dunlap 	if (ret == 0) {
478a6d42e7dSPeter Dunlap 		/* replace the global properties list */
479a6d42e7dSPeter Dunlap 		nvlist_free(cfg->config_global_properties);
480a6d42e7dSPeter Dunlap 		cfg->config_global_properties = cprops;
481a6d42e7dSPeter Dunlap 	} else {
482a6d42e7dSPeter Dunlap 		if (cprops) {
483a6d42e7dSPeter Dunlap 			nvlist_free(cprops);
484a6d42e7dSPeter Dunlap 		}
485a6d42e7dSPeter Dunlap 	}
486a6d42e7dSPeter Dunlap 
487a6d42e7dSPeter Dunlap 	return (ret);
488a6d42e7dSPeter Dunlap }
489a6d42e7dSPeter Dunlap 
490a6d42e7dSPeter Dunlap /*
491a6d42e7dSPeter Dunlap  * Function:  it_config_free()
492a6d42e7dSPeter Dunlap  *
493a6d42e7dSPeter Dunlap  * Free any resources associated with the it_config_t structure.
494a6d42e7dSPeter Dunlap  *
495a6d42e7dSPeter Dunlap  * Parameters:
496a6d42e7dSPeter Dunlap  *    cfg	A C representation of the current iSCSI configuration
497a6d42e7dSPeter Dunlap  */
498a6d42e7dSPeter Dunlap void
it_config_free(it_config_t * cfg)499a6d42e7dSPeter Dunlap it_config_free(it_config_t *cfg)
500a6d42e7dSPeter Dunlap {
501a6d42e7dSPeter Dunlap 	it_config_free_cmn(cfg);
502a6d42e7dSPeter Dunlap }
503a6d42e7dSPeter Dunlap 
504a6d42e7dSPeter Dunlap /*
505a6d42e7dSPeter Dunlap  * Function:  it_tgt_create()
506a6d42e7dSPeter Dunlap  *
507a6d42e7dSPeter Dunlap  * Allocate and create an it_tgt_t structure representing a new iSCSI
508a6d42e7dSPeter Dunlap  * target node.  If tgt_name is NULL, then a unique target node name will
509a6d42e7dSPeter Dunlap  * be generated automatically.  Otherwise, the value of tgt_name will be
510a6d42e7dSPeter Dunlap  * used as the target node name.  The new it_tgt_t structure is added to
511a6d42e7dSPeter Dunlap  * the target list (cfg_tgt_list) in the configuration structure, and the
512a6d42e7dSPeter Dunlap  * new target will not be instantiated until the modified configuration
513a6d42e7dSPeter Dunlap  * is committed by calling it_config_commit().
514a6d42e7dSPeter Dunlap  *
515a6d42e7dSPeter Dunlap  * Parameters:
516a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
517a6d42e7dSPeter Dunlap  *			it_config_load()
518a6d42e7dSPeter Dunlap  *    tgt		Pointer to an iSCSI target structure
519a6d42e7dSPeter Dunlap  *    tgt_name		The target node name for the target to be created.
520a6d42e7dSPeter Dunlap  *			The name must be in either IQN or EUI format.  If
521a6d42e7dSPeter Dunlap  *			this value is NULL, a node name will be generated
522a6d42e7dSPeter Dunlap  *			automatically in IQN format.
523a6d42e7dSPeter Dunlap  *
524a6d42e7dSPeter Dunlap  * Return Values:
525a6d42e7dSPeter Dunlap  *    0			Success
526a6d42e7dSPeter Dunlap  *    ENOMEM		Could not allocated resources
527a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
528a6d42e7dSPeter Dunlap  *    EFAULT		Invalid iSCSI name specified
529836fc322SSam Cramer  *    E2BIG		Too many already exist
530a6d42e7dSPeter Dunlap  */
531a6d42e7dSPeter Dunlap int
it_tgt_create(it_config_t * cfg,it_tgt_t ** tgt,char * tgt_name)532a6d42e7dSPeter Dunlap it_tgt_create(it_config_t *cfg, it_tgt_t **tgt, char *tgt_name)
533a6d42e7dSPeter Dunlap {
534a6d42e7dSPeter Dunlap 	int		ret = 0;
535a6d42e7dSPeter Dunlap 	it_tgt_t	*ptr;
536a6d42e7dSPeter Dunlap 	it_tgt_t	*cfgtgt;
537fcc214c3SCharles Ting 	char		*namep;
538a6d42e7dSPeter Dunlap 	char		buf[ISCSI_NAME_LEN_MAX + 1];
539a6d42e7dSPeter Dunlap 
540a6d42e7dSPeter Dunlap 	if (!cfg || !tgt) {
541a6d42e7dSPeter Dunlap 		return (EINVAL);
542a6d42e7dSPeter Dunlap 	}
543a6d42e7dSPeter Dunlap 
544fcc214c3SCharles Ting 	if (!tgt_name) {
545a6d42e7dSPeter Dunlap 		/* generate a name */
546a6d42e7dSPeter Dunlap 		ret = it_iqn_generate(buf, sizeof (buf), NULL);
547a6d42e7dSPeter Dunlap 		if (ret != 0) {
548a6d42e7dSPeter Dunlap 			return (ret);
549a6d42e7dSPeter Dunlap 		}
550a6d42e7dSPeter Dunlap 	} else {
551a6d42e7dSPeter Dunlap 		/* validate the passed-in name */
552fcc214c3SCharles Ting 		if (!validate_iscsi_name(tgt_name)) {
553a6d42e7dSPeter Dunlap 			return (EFAULT);
554a6d42e7dSPeter Dunlap 		}
555fcc214c3SCharles Ting 		(void) strlcpy(buf, tgt_name, sizeof (buf));
556fcc214c3SCharles Ting 		canonical_iscsi_name(buf);
557a6d42e7dSPeter Dunlap 	}
558fcc214c3SCharles Ting 	namep = buf;
559a6d42e7dSPeter Dunlap 
560a6d42e7dSPeter Dunlap 	/* make sure this name isn't already on the list */
561a6d42e7dSPeter Dunlap 	cfgtgt = cfg->config_tgt_list;
562a6d42e7dSPeter Dunlap 	while (cfgtgt != NULL) {
563fcc214c3SCharles Ting 		if (strcasecmp(namep, cfgtgt->tgt_name) == 0) {
564a6d42e7dSPeter Dunlap 			return (EEXIST);
565a6d42e7dSPeter Dunlap 		}
566a6d42e7dSPeter Dunlap 		cfgtgt = cfgtgt->tgt_next;
567a6d42e7dSPeter Dunlap 	}
568a6d42e7dSPeter Dunlap 
569ade94d8bSCharles Ting 	/* Too many targets? */
570ade94d8bSCharles Ting 	if (cfg->config_tgt_count >= MAX_TARGETS) {
571ade94d8bSCharles Ting 		return (E2BIG);
572ade94d8bSCharles Ting 	}
573ade94d8bSCharles Ting 
574a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_tgt_t));
575a6d42e7dSPeter Dunlap 	if (ptr == NULL) {
576a6d42e7dSPeter Dunlap 		return (ENOMEM);
577a6d42e7dSPeter Dunlap 	}
578a6d42e7dSPeter Dunlap 
579a6d42e7dSPeter Dunlap 	(void) strlcpy(ptr->tgt_name, namep, sizeof (ptr->tgt_name));
580a6d42e7dSPeter Dunlap 	ptr->tgt_generation = 1;
581a6d42e7dSPeter Dunlap 	ptr->tgt_next = cfg->config_tgt_list;
582a6d42e7dSPeter Dunlap 	cfg->config_tgt_list = ptr;
583a6d42e7dSPeter Dunlap 	cfg->config_tgt_count++;
584a6d42e7dSPeter Dunlap 
585a6d42e7dSPeter Dunlap 	*tgt = ptr;
586a6d42e7dSPeter Dunlap 
587a6d42e7dSPeter Dunlap 	return (0);
588a6d42e7dSPeter Dunlap }
589a6d42e7dSPeter Dunlap 
590a6d42e7dSPeter Dunlap /*
591a6d42e7dSPeter Dunlap  * Function:  it_tgt_setprop()
592a6d42e7dSPeter Dunlap  *
593a6d42e7dSPeter Dunlap  * Validate the provided property list and set the properties for
594a6d42e7dSPeter Dunlap  * the specified target.  If errlist is not NULL, returns detailed
595a6d42e7dSPeter Dunlap  * errors for each property that failed.  The format for errorlist
596a6d42e7dSPeter Dunlap  * is key = property, value = error string.
597a6d42e7dSPeter Dunlap  *
598a6d42e7dSPeter Dunlap  * Parameters:
599a6d42e7dSPeter Dunlap  *
600a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
601a6d42e7dSPeter Dunlap  *			it_config_load()
602a6d42e7dSPeter Dunlap  *    tgt		Pointer to an iSCSI target structure
603a6d42e7dSPeter Dunlap  *    proplist		nvlist_t containing properties for this target.
604a6d42e7dSPeter Dunlap  *    errlist		(optional)  nvlist_t of errors encountered when
605a6d42e7dSPeter Dunlap  *			validating the properties.
606a6d42e7dSPeter Dunlap  *
607a6d42e7dSPeter Dunlap  * Return Values:
608a6d42e7dSPeter Dunlap  *    0			Success
609a6d42e7dSPeter Dunlap  *    EINVAL		Invalid property
610a6d42e7dSPeter Dunlap  *
611a6d42e7dSPeter Dunlap  */
612a6d42e7dSPeter Dunlap int
it_tgt_setprop(it_config_t * cfg,it_tgt_t * tgt,nvlist_t * proplist,nvlist_t ** errlist)613a6d42e7dSPeter Dunlap it_tgt_setprop(it_config_t *cfg, it_tgt_t *tgt, nvlist_t *proplist,
614a6d42e7dSPeter Dunlap     nvlist_t **errlist)
615a6d42e7dSPeter Dunlap {
616a6d42e7dSPeter Dunlap 	int		ret;
6178175704fSPeter Gill 	nvlist_t	*errs = NULL;
618a6d42e7dSPeter Dunlap 	nvlist_t	*tprops = NULL;
619a6d42e7dSPeter Dunlap 	char		*val = NULL;
620a6d42e7dSPeter Dunlap 
621a6d42e7dSPeter Dunlap 	if (!cfg || !tgt || !proplist) {
622a6d42e7dSPeter Dunlap 		return (EINVAL);
623a6d42e7dSPeter Dunlap 	}
624a6d42e7dSPeter Dunlap 
625fcc214c3SCharles Ting 	/* verify the target name in case the target node is renamed */
626fcc214c3SCharles Ting 	if (!validate_iscsi_name(tgt->tgt_name)) {
627fcc214c3SCharles Ting 		return (EINVAL);
628fcc214c3SCharles Ting 	}
629fcc214c3SCharles Ting 	canonical_iscsi_name(tgt->tgt_name);
630fcc214c3SCharles Ting 
631a6d42e7dSPeter Dunlap 	if (errlist) {
6328175704fSPeter Gill 		(void) nvlist_alloc(&errs, 0, 0);
6338175704fSPeter Gill 		*errlist = errs;
634a6d42e7dSPeter Dunlap 	}
635a6d42e7dSPeter Dunlap 
636a6d42e7dSPeter Dunlap 	/*
637a6d42e7dSPeter Dunlap 	 * copy the existing properties, merge, then validate
638a6d42e7dSPeter Dunlap 	 * the merged properties before committing them.
639a6d42e7dSPeter Dunlap 	 */
640a6d42e7dSPeter Dunlap 	if (tgt->tgt_properties) {
641a6d42e7dSPeter Dunlap 		ret = nvlist_dup(tgt->tgt_properties, &tprops, 0);
642a6d42e7dSPeter Dunlap 	} else {
643a6d42e7dSPeter Dunlap 		ret = nvlist_alloc(&tprops, NV_UNIQUE_NAME, 0);
644a6d42e7dSPeter Dunlap 	}
645a6d42e7dSPeter Dunlap 
6467f6f3ee7SPeter Gill 	if (ret != 0) {
6477f6f3ee7SPeter Gill 		return (ret);
6487f6f3ee7SPeter Gill 	}
6497f6f3ee7SPeter Gill 
650a6d42e7dSPeter Dunlap 	ret = nvlist_merge(tprops, proplist, 0);
6517f6f3ee7SPeter Gill 	if (ret != 0) {
6527f6f3ee7SPeter Gill 		nvlist_free(tprops);
6537f6f3ee7SPeter Gill 		return (ret);
654a6d42e7dSPeter Dunlap 	}
655a6d42e7dSPeter Dunlap 
656a6d42e7dSPeter Dunlap 	/* unset chap username or alias if requested */
657a6d42e7dSPeter Dunlap 	val = NULL;
658a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_USER, &val);
659a6d42e7dSPeter Dunlap 	if (val && (strcasecmp(val, "none") == 0)) {
660a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(tprops, PROP_TARGET_CHAP_USER);
661a6d42e7dSPeter Dunlap 	}
662a6d42e7dSPeter Dunlap 
663a6d42e7dSPeter Dunlap 	val = NULL;
664a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(proplist, PROP_ALIAS, &val);
665a6d42e7dSPeter Dunlap 	if (val && (strcasecmp(val, "none") == 0)) {
666a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(tprops, PROP_ALIAS);
667a6d42e7dSPeter Dunlap 	}
668a6d42e7dSPeter Dunlap 
669a6d42e7dSPeter Dunlap 	/* base64 encode the CHAP secret, if it's changed */
670a6d42e7dSPeter Dunlap 	val = NULL;
671a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_SECRET, &val);
672a6d42e7dSPeter Dunlap 	if (val) {
673a6d42e7dSPeter Dunlap 		char		bsecret[MAX_BASE64_LEN];
674a6d42e7dSPeter Dunlap 
6758175704fSPeter Gill 		ret = it_val_pass(PROP_TARGET_CHAP_SECRET, val, errs);
676a6d42e7dSPeter Dunlap 
677a6d42e7dSPeter Dunlap 		if (ret == 0) {
678a6d42e7dSPeter Dunlap 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
679a6d42e7dSPeter Dunlap 
680a6d42e7dSPeter Dunlap 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
681a6d42e7dSPeter Dunlap 			    strlen(val), bsecret, MAX_BASE64_LEN);
682a6d42e7dSPeter Dunlap 
683a6d42e7dSPeter Dunlap 			if (ret == 0) {
684a6d42e7dSPeter Dunlap 				/* replace the value in the nvlist */
685a6d42e7dSPeter Dunlap 				ret = nvlist_add_string(tprops,
686a6d42e7dSPeter Dunlap 				    PROP_TARGET_CHAP_SECRET, bsecret);
687a6d42e7dSPeter Dunlap 			}
688a6d42e7dSPeter Dunlap 		}
689a6d42e7dSPeter Dunlap 	}
690a6d42e7dSPeter Dunlap 
691a6d42e7dSPeter Dunlap 	if (ret == 0) {
6928175704fSPeter Gill 		ret = it_validate_tgtprops(tprops, errs);
693a6d42e7dSPeter Dunlap 	}
694a6d42e7dSPeter Dunlap 
695a6d42e7dSPeter Dunlap 	if (ret != 0) {
696a6d42e7dSPeter Dunlap 		if (tprops) {
697a6d42e7dSPeter Dunlap 			nvlist_free(tprops);
698a6d42e7dSPeter Dunlap 		}
699a6d42e7dSPeter Dunlap 		return (ret);
700a6d42e7dSPeter Dunlap 	}
701a6d42e7dSPeter Dunlap 
702a6d42e7dSPeter Dunlap 	if (tgt->tgt_properties) {
703a6d42e7dSPeter Dunlap 		nvlist_free(tgt->tgt_properties);
704a6d42e7dSPeter Dunlap 	}
705a6d42e7dSPeter Dunlap 	tgt->tgt_properties = tprops;
706a6d42e7dSPeter Dunlap 
707a6d42e7dSPeter Dunlap 	return (0);
708a6d42e7dSPeter Dunlap }
709a6d42e7dSPeter Dunlap 
710a6d42e7dSPeter Dunlap 
711a6d42e7dSPeter Dunlap /*
712a6d42e7dSPeter Dunlap  * Function:  it_tgt_delete()
713a6d42e7dSPeter Dunlap  *
714a6d42e7dSPeter Dunlap  * Delete target represented by 'tgt', where 'tgt' is an existing
715a6d42e7dSPeter Dunlap  * it_tgt_structure within the configuration 'cfg'.  The target removal
716a6d42e7dSPeter Dunlap  * will not take effect until the modified configuration is committed
717a6d42e7dSPeter Dunlap  * by calling it_config_commit().
718a6d42e7dSPeter Dunlap  *
719a6d42e7dSPeter Dunlap  * Parameters:
720a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
721a6d42e7dSPeter Dunlap  *			it_config_load()
722a6d42e7dSPeter Dunlap  *    tgt		Pointer to an iSCSI target structure
723a6d42e7dSPeter Dunlap  *
724a6d42e7dSPeter Dunlap  *    force		Set the target to offline before removing it from
725a6d42e7dSPeter Dunlap  *			the config.  If not specified, the operation will
726a6d42e7dSPeter Dunlap  *			fail if the target is determined to be online.
727a6d42e7dSPeter Dunlap  * Return Values:
728a6d42e7dSPeter Dunlap  *    0			Success
729a6d42e7dSPeter Dunlap  *    EBUSY		Target is online
730a6d42e7dSPeter Dunlap  */
731a6d42e7dSPeter Dunlap int
it_tgt_delete(it_config_t * cfg,it_tgt_t * tgt,boolean_t force)732a6d42e7dSPeter Dunlap it_tgt_delete(it_config_t *cfg, it_tgt_t *tgt, boolean_t force)
733a6d42e7dSPeter Dunlap {
734a6d42e7dSPeter Dunlap 	int			ret;
735a6d42e7dSPeter Dunlap 	it_tgt_t		*ptgt;
736a6d42e7dSPeter Dunlap 	it_tgt_t		*prev = NULL;
737a6d42e7dSPeter Dunlap 	stmfDevid		devid;
738a6d42e7dSPeter Dunlap 	stmfTargetProperties	props;
739a6d42e7dSPeter Dunlap 
740a6d42e7dSPeter Dunlap 	if (!cfg || !tgt) {
741a6d42e7dSPeter Dunlap 		return (0);
742a6d42e7dSPeter Dunlap 	}
743a6d42e7dSPeter Dunlap 
744a6d42e7dSPeter Dunlap 	ptgt = cfg->config_tgt_list;
745a6d42e7dSPeter Dunlap 	while (ptgt != NULL) {
746fcc214c3SCharles Ting 		if (strcasecmp(tgt->tgt_name, ptgt->tgt_name) == 0) {
747a6d42e7dSPeter Dunlap 			break;
748a6d42e7dSPeter Dunlap 		}
749a6d42e7dSPeter Dunlap 		prev = ptgt;
750a6d42e7dSPeter Dunlap 		ptgt = ptgt->tgt_next;
751a6d42e7dSPeter Dunlap 	}
752a6d42e7dSPeter Dunlap 
753a6d42e7dSPeter Dunlap 	if (!ptgt) {
754a6d42e7dSPeter Dunlap 		return (0);
755a6d42e7dSPeter Dunlap 	}
756a6d42e7dSPeter Dunlap 
757a6d42e7dSPeter Dunlap 	/*
758a6d42e7dSPeter Dunlap 	 * check to see if this target is offline.  If it is not,
759a6d42e7dSPeter Dunlap 	 * and the 'force' flag is TRUE, tell STMF to offline it
760a6d42e7dSPeter Dunlap 	 * before removing from the configuration.
761a6d42e7dSPeter Dunlap 	 */
762a6d42e7dSPeter Dunlap 	ret = stmfDevidFromIscsiName(ptgt->tgt_name, &devid);
763a6d42e7dSPeter Dunlap 	if (ret != STMF_STATUS_SUCCESS) {
764a6d42e7dSPeter Dunlap 		/* can't happen? */
765a6d42e7dSPeter Dunlap 		return (EINVAL);
766a6d42e7dSPeter Dunlap 	}
767a6d42e7dSPeter Dunlap 
768a6d42e7dSPeter Dunlap 	ret = stmfGetTargetProperties(&devid, &props);
769a6d42e7dSPeter Dunlap 	if (ret == STMF_STATUS_SUCCESS) {
770a6d42e7dSPeter Dunlap 		/*
771a6d42e7dSPeter Dunlap 		 * only other return is STMF_ERROR_NOT_FOUND, which
772a6d42e7dSPeter Dunlap 		 * means we don't have to offline it.
773a6d42e7dSPeter Dunlap 		 */
774a6d42e7dSPeter Dunlap 		if (props.status == STMF_TARGET_PORT_ONLINE) {
775a6d42e7dSPeter Dunlap 			if (!force) {
776a6d42e7dSPeter Dunlap 				return (EBUSY);
777a6d42e7dSPeter Dunlap 			}
778a6d42e7dSPeter Dunlap 			ret = stmfOfflineTarget(&devid);
779a6d42e7dSPeter Dunlap 			if (ret != 0) {
780a6d42e7dSPeter Dunlap 				return (EBUSY);
781a6d42e7dSPeter Dunlap 			}
782a6d42e7dSPeter Dunlap 		}
783a6d42e7dSPeter Dunlap 	}
784a6d42e7dSPeter Dunlap 
785a6d42e7dSPeter Dunlap 	if (prev) {
786a6d42e7dSPeter Dunlap 		prev->tgt_next = ptgt->tgt_next;
787a6d42e7dSPeter Dunlap 	} else {
788a6d42e7dSPeter Dunlap 		/* first one on the list */
789a6d42e7dSPeter Dunlap 		cfg->config_tgt_list = ptgt->tgt_next;
790a6d42e7dSPeter Dunlap 	}
791a6d42e7dSPeter Dunlap 
792a6d42e7dSPeter Dunlap 	ptgt->tgt_next = NULL; /* Only free this target */
793a6d42e7dSPeter Dunlap 
794a6d42e7dSPeter Dunlap 	cfg->config_tgt_count--;
795a6d42e7dSPeter Dunlap 	it_tgt_free(ptgt);
796a6d42e7dSPeter Dunlap 
797a6d42e7dSPeter Dunlap 	return (0);
798a6d42e7dSPeter Dunlap }
799a6d42e7dSPeter Dunlap 
800a6d42e7dSPeter Dunlap /*
801a6d42e7dSPeter Dunlap  * Function:  it_tgt_free()
802a6d42e7dSPeter Dunlap  *
803a6d42e7dSPeter Dunlap  * Frees an it_tgt_t structure.  If tgt_next is not NULL, frees
804a6d42e7dSPeter Dunlap  * all structures in the list.
805a6d42e7dSPeter Dunlap  */
806a6d42e7dSPeter Dunlap void
it_tgt_free(it_tgt_t * tgt)807a6d42e7dSPeter Dunlap it_tgt_free(it_tgt_t *tgt)
808a6d42e7dSPeter Dunlap {
809a6d42e7dSPeter Dunlap 	it_tgt_free_cmn(tgt);
810a6d42e7dSPeter Dunlap }
811a6d42e7dSPeter Dunlap 
812a6d42e7dSPeter Dunlap /*
813a6d42e7dSPeter Dunlap  * Function:  it_tpgt_create()
814a6d42e7dSPeter Dunlap  *
815a6d42e7dSPeter Dunlap  * Allocate and create an it_tpgt_t structure representing a new iSCSI
816a6d42e7dSPeter Dunlap  * target portal group tag.  The new it_tpgt_t structure is added to the
817a6d42e7dSPeter Dunlap  * target tpgt list (tgt_tpgt_list) in the it_tgt_t structure.  The new
818a6d42e7dSPeter Dunlap  * target portal group tag will not be instantiated until the modified
819a6d42e7dSPeter Dunlap  * configuration is committed by calling it_config_commit().
820a6d42e7dSPeter Dunlap  *
821a6d42e7dSPeter Dunlap  * Parameters:
822a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
823a6d42e7dSPeter Dunlap  *			it_config_load()
824a6d42e7dSPeter Dunlap  *    tgt		Pointer to the iSCSI target structure associated
825a6d42e7dSPeter Dunlap  *			with the target portal group tag
826a6d42e7dSPeter Dunlap  *    tpgt		Pointer to a target portal group tag structure
827a6d42e7dSPeter Dunlap  *    tpg_name		The name of the TPG to be associated with this TPGT
828a6d42e7dSPeter Dunlap  *    tpgt_tag		16-bit numerical identifier for this TPGT.  If
829a6d42e7dSPeter Dunlap  *			tpgt_tag is '0', this function will choose the
830a6d42e7dSPeter Dunlap  *			tag number.  If tpgt_tag is >0, and the requested
831a6d42e7dSPeter Dunlap  *			tag is determined to be in use, another value
832a6d42e7dSPeter Dunlap  *			will be chosen.
833a6d42e7dSPeter Dunlap  *
834a6d42e7dSPeter Dunlap  * Return Values:
835a6d42e7dSPeter Dunlap  *    0			Success
836a6d42e7dSPeter Dunlap  *    ENOMEM		Could not allocate resources
837a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
838a6d42e7dSPeter Dunlap  *    EEXIST		Specified tag name is already used.
839a6d42e7dSPeter Dunlap  *    E2BIG		No available tag numbers
840a6d42e7dSPeter Dunlap  */
841a6d42e7dSPeter Dunlap int
it_tpgt_create(it_config_t * cfg,it_tgt_t * tgt,it_tpgt_t ** tpgt,char * tpg_name,uint16_t tpgt_tag)842a6d42e7dSPeter Dunlap it_tpgt_create(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t **tpgt,
843a6d42e7dSPeter Dunlap     char *tpg_name, uint16_t tpgt_tag)
844a6d42e7dSPeter Dunlap {
845a6d42e7dSPeter Dunlap 	it_tpgt_t	*ptr = NULL;
846a6d42e7dSPeter Dunlap 	it_tpgt_t	*cfgt;
847a6d42e7dSPeter Dunlap 	char		tagid_used[MAXTAG + 1];
848a6d42e7dSPeter Dunlap 	uint16_t	tagid = ISCSIT_DEFAULT_TPGT;
849a6d42e7dSPeter Dunlap 
850a6d42e7dSPeter Dunlap 	if (!cfg || !tgt || !tpgt || !tpg_name) {
851a6d42e7dSPeter Dunlap 		return (EINVAL);
852a6d42e7dSPeter Dunlap 	}
853a6d42e7dSPeter Dunlap 
854a6d42e7dSPeter Dunlap 	(void) memset(&(tagid_used[0]), 0, sizeof (tagid_used));
855a6d42e7dSPeter Dunlap 
856a6d42e7dSPeter Dunlap 	/*
857a6d42e7dSPeter Dunlap 	 * Make sure this name and/or tag isn't already on the list
858a6d42e7dSPeter Dunlap 	 * At the same time, capture all tag ids in use for this target
859a6d42e7dSPeter Dunlap 	 *
860a6d42e7dSPeter Dunlap 	 * About tag numbering -- since tag numbers are used by
861a6d42e7dSPeter Dunlap 	 * the iSCSI protocol, we should be careful about reusing
862a6d42e7dSPeter Dunlap 	 * them too quickly.  Start with a value greater than the
863a6d42e7dSPeter Dunlap 	 * highest one currently defined.  If current == MAXTAG,
864a6d42e7dSPeter Dunlap 	 * just find an unused tag.
865a6d42e7dSPeter Dunlap 	 */
866a6d42e7dSPeter Dunlap 	cfgt = tgt->tgt_tpgt_list;
867a6d42e7dSPeter Dunlap 	while (cfgt != NULL) {
868a6d42e7dSPeter Dunlap 		tagid_used[cfgt->tpgt_tag] = 1;
869a6d42e7dSPeter Dunlap 
870a6d42e7dSPeter Dunlap 		if (strcmp(tpg_name, cfgt->tpgt_tpg_name) == 0) {
871a6d42e7dSPeter Dunlap 			return (EEXIST);
872a6d42e7dSPeter Dunlap 		}
873a6d42e7dSPeter Dunlap 
874a6d42e7dSPeter Dunlap 		if (cfgt->tpgt_tag > tagid) {
875a6d42e7dSPeter Dunlap 			tagid = cfgt->tpgt_tag;
876a6d42e7dSPeter Dunlap 		}
877a6d42e7dSPeter Dunlap 
878a6d42e7dSPeter Dunlap 		cfgt = cfgt->tpgt_next;
879a6d42e7dSPeter Dunlap 	}
880a6d42e7dSPeter Dunlap 
881a6d42e7dSPeter Dunlap 	if ((tpgt_tag > ISCSIT_DEFAULT_TPGT) && (tpgt_tag < MAXTAG) &&
882a6d42e7dSPeter Dunlap 	    (tagid_used[tpgt_tag] == 0)) {
883a6d42e7dSPeter Dunlap 		/* ok to use requested */
884a6d42e7dSPeter Dunlap 		tagid = tpgt_tag;
885a6d42e7dSPeter Dunlap 	} else if (tagid == MAXTAG) {
886a6d42e7dSPeter Dunlap 		/*
887a6d42e7dSPeter Dunlap 		 * The highest value is used, find an available id.
888a6d42e7dSPeter Dunlap 		 */
889a6d42e7dSPeter Dunlap 		tagid = ISCSIT_DEFAULT_TPGT + 1;
890a6d42e7dSPeter Dunlap 		for (; tagid < MAXTAG; tagid++) {
891a6d42e7dSPeter Dunlap 			if (tagid_used[tagid] == 0) {
892a6d42e7dSPeter Dunlap 				break;
893a6d42e7dSPeter Dunlap 			}
894a6d42e7dSPeter Dunlap 		}
895a6d42e7dSPeter Dunlap 		if (tagid >= MAXTAG) {
896a6d42e7dSPeter Dunlap 			return (E2BIG);
897a6d42e7dSPeter Dunlap 		}
898a6d42e7dSPeter Dunlap 	} else {
899a6d42e7dSPeter Dunlap 		/* next available ID */
900a6d42e7dSPeter Dunlap 		tagid++;
901a6d42e7dSPeter Dunlap 	}
902a6d42e7dSPeter Dunlap 
903a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_tpgt_t));
904a6d42e7dSPeter Dunlap 	if (!ptr) {
905a6d42e7dSPeter Dunlap 		return (ENOMEM);
906a6d42e7dSPeter Dunlap 	}
907a6d42e7dSPeter Dunlap 
908a6d42e7dSPeter Dunlap 	(void) strlcpy(ptr->tpgt_tpg_name, tpg_name,
909a6d42e7dSPeter Dunlap 	    sizeof (ptr->tpgt_tpg_name));
910a6d42e7dSPeter Dunlap 	ptr->tpgt_generation = 1;
911a6d42e7dSPeter Dunlap 	ptr->tpgt_tag = tagid;
912a6d42e7dSPeter Dunlap 
913a6d42e7dSPeter Dunlap 	ptr->tpgt_next = tgt->tgt_tpgt_list;
914a6d42e7dSPeter Dunlap 	tgt->tgt_tpgt_list = ptr;
915a6d42e7dSPeter Dunlap 	tgt->tgt_tpgt_count++;
916a6d42e7dSPeter Dunlap 	tgt->tgt_generation++;
917a6d42e7dSPeter Dunlap 
918a6d42e7dSPeter Dunlap 	*tpgt = ptr;
919a6d42e7dSPeter Dunlap 
920a6d42e7dSPeter Dunlap 	return (0);
921a6d42e7dSPeter Dunlap }
922a6d42e7dSPeter Dunlap 
923a6d42e7dSPeter Dunlap /*
924a6d42e7dSPeter Dunlap  * Function:  it_tpgt_delete()
925a6d42e7dSPeter Dunlap  *
926a6d42e7dSPeter Dunlap  * Delete the target portal group tag represented by 'tpgt', where
927a6d42e7dSPeter Dunlap  * 'tpgt' is an existing is_tpgt_t structure within the target 'tgt'.
928a6d42e7dSPeter Dunlap  * The target portal group tag removal will not take effect until the
929a6d42e7dSPeter Dunlap  * modified configuration is committed by calling it_config_commit().
930a6d42e7dSPeter Dunlap  *
931a6d42e7dSPeter Dunlap  * Parameters:
932a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
933a6d42e7dSPeter Dunlap  *			it_config_load()
934a6d42e7dSPeter Dunlap  *    tgt		Pointer to the iSCSI target structure associated
935a6d42e7dSPeter Dunlap  *			with the target portal group tag
936a6d42e7dSPeter Dunlap  *    tpgt		Pointer to a target portal group tag structure
937a6d42e7dSPeter Dunlap  */
938a6d42e7dSPeter Dunlap void
it_tpgt_delete(it_config_t * cfg,it_tgt_t * tgt,it_tpgt_t * tpgt)939a6d42e7dSPeter Dunlap it_tpgt_delete(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t *tpgt)
940a6d42e7dSPeter Dunlap {
941a6d42e7dSPeter Dunlap 	it_tpgt_t	*ptr;
942a6d42e7dSPeter Dunlap 	it_tpgt_t	*prev = NULL;
943a6d42e7dSPeter Dunlap 
944a6d42e7dSPeter Dunlap 	if (!cfg || !tgt || !tpgt) {
945a6d42e7dSPeter Dunlap 		return;
946a6d42e7dSPeter Dunlap 	}
947a6d42e7dSPeter Dunlap 
948a6d42e7dSPeter Dunlap 	ptr = tgt->tgt_tpgt_list;
949a6d42e7dSPeter Dunlap 	while (ptr) {
950a6d42e7dSPeter Dunlap 		if (ptr->tpgt_tag == tpgt->tpgt_tag) {
951a6d42e7dSPeter Dunlap 			break;
952a6d42e7dSPeter Dunlap 		}
953a6d42e7dSPeter Dunlap 		prev = ptr;
954a6d42e7dSPeter Dunlap 		ptr = ptr->tpgt_next;
955a6d42e7dSPeter Dunlap 	}
956a6d42e7dSPeter Dunlap 
957a6d42e7dSPeter Dunlap 	if (!ptr) {
958a6d42e7dSPeter Dunlap 		return;
959a6d42e7dSPeter Dunlap 	}
960a6d42e7dSPeter Dunlap 
961a6d42e7dSPeter Dunlap 	if (prev) {
962a6d42e7dSPeter Dunlap 		prev->tpgt_next = ptr->tpgt_next;
963a6d42e7dSPeter Dunlap 	} else {
964a6d42e7dSPeter Dunlap 		tgt->tgt_tpgt_list = ptr->tpgt_next;
965a6d42e7dSPeter Dunlap 	}
966a6d42e7dSPeter Dunlap 	ptr->tpgt_next = NULL;
967a6d42e7dSPeter Dunlap 
968a6d42e7dSPeter Dunlap 	tgt->tgt_tpgt_count--;
969a6d42e7dSPeter Dunlap 	tgt->tgt_generation++;
970a6d42e7dSPeter Dunlap 
971a6d42e7dSPeter Dunlap 	it_tpgt_free(ptr);
972a6d42e7dSPeter Dunlap }
973a6d42e7dSPeter Dunlap 
974a6d42e7dSPeter Dunlap /*
975a6d42e7dSPeter Dunlap  * Function:  it_tpgt_free()
976a6d42e7dSPeter Dunlap  *
977a6d42e7dSPeter Dunlap  * Deallocates resources of an it_tpgt_t structure.  If tpgt->next
978a6d42e7dSPeter Dunlap  * is not NULL, frees all members of the list.
979a6d42e7dSPeter Dunlap  */
980a6d42e7dSPeter Dunlap void
it_tpgt_free(it_tpgt_t * tpgt)981a6d42e7dSPeter Dunlap it_tpgt_free(it_tpgt_t *tpgt)
982a6d42e7dSPeter Dunlap {
983a6d42e7dSPeter Dunlap 	it_tpgt_free_cmn(tpgt);
984a6d42e7dSPeter Dunlap }
985a6d42e7dSPeter Dunlap 
986a6d42e7dSPeter Dunlap /*
987a6d42e7dSPeter Dunlap  * Function:  it_tpg_create()
988a6d42e7dSPeter Dunlap  *
989a6d42e7dSPeter Dunlap  * Allocate and create an it_tpg_t structure representing a new iSCSI
990a6d42e7dSPeter Dunlap  * target portal group.  The new it_tpg_t structure is added to the global
991a6d42e7dSPeter Dunlap  * tpg list (cfg_tgt_list) in the it_config_t structure.  The new target
992a6d42e7dSPeter Dunlap  * portal group will not be instantiated until the modified configuration
993a6d42e7dSPeter Dunlap  * is committed by calling it_config_commit().
994a6d42e7dSPeter Dunlap  *
995a6d42e7dSPeter Dunlap  * Parameters:
996a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
997a6d42e7dSPeter Dunlap  *			it_config_load()
998a6d42e7dSPeter Dunlap  *    tpg		Pointer to the it_tpg_t structure representing
999a6d42e7dSPeter Dunlap  *			the target portal group
1000a6d42e7dSPeter Dunlap  *    tpg_name		Identifier for the target portal group
1001a6d42e7dSPeter Dunlap  *    portal_ip_port	A string containing an appropriatedly formatted
1002a6d42e7dSPeter Dunlap  *			IP address:port.  Both IPv4 and IPv6 addresses are
1003a6d42e7dSPeter Dunlap  *			permitted.  This value becomes the first portal in
1004a6d42e7dSPeter Dunlap  *			the TPG -- applications can add additional values
1005a6d42e7dSPeter Dunlap  *			using it_portal_create() before committing the TPG.
1006a6d42e7dSPeter Dunlap  * Return Values:
1007a6d42e7dSPeter Dunlap  *    0			Success
1008a6d42e7dSPeter Dunlap  *    ENOMEM		Cannot allocate resources
1009a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
1010a6d42e7dSPeter Dunlap  *    EEXIST		Requested portal in use by another target portal
1011a6d42e7dSPeter Dunlap  *			group
1012a6d42e7dSPeter Dunlap  */
1013a6d42e7dSPeter Dunlap int
it_tpg_create(it_config_t * cfg,it_tpg_t ** tpg,char * tpg_name,char * portal_ip_port)1014a6d42e7dSPeter Dunlap it_tpg_create(it_config_t *cfg, it_tpg_t **tpg, char *tpg_name,
1015a6d42e7dSPeter Dunlap     char *portal_ip_port)
1016a6d42e7dSPeter Dunlap {
1017a6d42e7dSPeter Dunlap 	int		ret;
1018a6d42e7dSPeter Dunlap 	it_tpg_t	*ptr;
1019a6d42e7dSPeter Dunlap 	it_portal_t	*portal = NULL;
1020a6d42e7dSPeter Dunlap 
1021a6d42e7dSPeter Dunlap 	if (!cfg || !tpg || !tpg_name || !portal_ip_port) {
1022a6d42e7dSPeter Dunlap 		return (EINVAL);
1023a6d42e7dSPeter Dunlap 	}
1024a6d42e7dSPeter Dunlap 
1025a6d42e7dSPeter Dunlap 	*tpg = NULL;
1026a6d42e7dSPeter Dunlap 
1027a6d42e7dSPeter Dunlap 	ptr = cfg->config_tpg_list;
1028a6d42e7dSPeter Dunlap 	while (ptr) {
1029a6d42e7dSPeter Dunlap 		if (strcmp(tpg_name, ptr->tpg_name) == 0) {
1030a6d42e7dSPeter Dunlap 			break;
1031a6d42e7dSPeter Dunlap 		}
1032a6d42e7dSPeter Dunlap 		ptr = ptr->tpg_next;
1033a6d42e7dSPeter Dunlap 	}
1034a6d42e7dSPeter Dunlap 
1035a6d42e7dSPeter Dunlap 	if (ptr) {
1036a6d42e7dSPeter Dunlap 		return (EEXIST);
1037a6d42e7dSPeter Dunlap 	}
1038a6d42e7dSPeter Dunlap 
1039a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_tpg_t));
1040a6d42e7dSPeter Dunlap 	if (!ptr) {
1041a6d42e7dSPeter Dunlap 		return (ENOMEM);
1042a6d42e7dSPeter Dunlap 	}
1043a6d42e7dSPeter Dunlap 
1044a6d42e7dSPeter Dunlap 	ptr->tpg_generation = 1;
1045a6d42e7dSPeter Dunlap 	(void) strlcpy(ptr->tpg_name, tpg_name, sizeof (ptr->tpg_name));
1046a6d42e7dSPeter Dunlap 
1047a6d42e7dSPeter Dunlap 	/* create the portal */
1048a6d42e7dSPeter Dunlap 	ret = it_portal_create(cfg, ptr, &portal, portal_ip_port);
1049a6d42e7dSPeter Dunlap 	if (ret != 0) {
1050a6d42e7dSPeter Dunlap 		free(ptr);
1051a6d42e7dSPeter Dunlap 		return (ret);
1052a6d42e7dSPeter Dunlap 	}
1053a6d42e7dSPeter Dunlap 
1054a6d42e7dSPeter Dunlap 	ptr->tpg_next = cfg->config_tpg_list;
1055a6d42e7dSPeter Dunlap 	cfg->config_tpg_list = ptr;
1056a6d42e7dSPeter Dunlap 	cfg->config_tpg_count++;
1057a6d42e7dSPeter Dunlap 
1058a6d42e7dSPeter Dunlap 	*tpg = ptr;
1059a6d42e7dSPeter Dunlap 
1060a6d42e7dSPeter Dunlap 	return (0);
1061a6d42e7dSPeter Dunlap }
1062a6d42e7dSPeter Dunlap 
1063a6d42e7dSPeter Dunlap /*
1064a6d42e7dSPeter Dunlap  * Function:  it_tpg_delete()
1065a6d42e7dSPeter Dunlap  *
1066a6d42e7dSPeter Dunlap  * Delete target portal group represented by 'tpg', where 'tpg' is an
1067a6d42e7dSPeter Dunlap  * existing it_tpg_t structure within the global configuration 'cfg'.
1068a6d42e7dSPeter Dunlap  * The target portal group removal will not take effect until the
1069a6d42e7dSPeter Dunlap  * modified configuration is committed by calling it_config_commit().
1070a6d42e7dSPeter Dunlap  *
1071a6d42e7dSPeter Dunlap  * Parameters:
1072a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
1073a6d42e7dSPeter Dunlap  *			it_config_load()
1074a6d42e7dSPeter Dunlap  *    tpg		Pointer to the it_tpg_t structure representing
1075a6d42e7dSPeter Dunlap  *			the target portal group
1076a6d42e7dSPeter Dunlap  *    force		Remove this target portal group even if it's
1077a6d42e7dSPeter Dunlap  *			associated with one or more targets.
1078a6d42e7dSPeter Dunlap  *
1079a6d42e7dSPeter Dunlap  * Return Values:
1080a6d42e7dSPeter Dunlap  *    0			Success
1081a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
1082a6d42e7dSPeter Dunlap  *    EBUSY		Portal group associated with one or more targets.
1083a6d42e7dSPeter Dunlap  */
1084a6d42e7dSPeter Dunlap int
it_tpg_delete(it_config_t * cfg,it_tpg_t * tpg,boolean_t force)1085a6d42e7dSPeter Dunlap it_tpg_delete(it_config_t *cfg, it_tpg_t *tpg, boolean_t force)
1086a6d42e7dSPeter Dunlap {
1087a6d42e7dSPeter Dunlap 	it_tpg_t	*ptr;
1088a6d42e7dSPeter Dunlap 	it_tpg_t	*prev = NULL;
1089a6d42e7dSPeter Dunlap 	it_tgt_t	*tgt;
1090a6d42e7dSPeter Dunlap 	it_tpgt_t	*tpgt;
1091a6d42e7dSPeter Dunlap 	it_tpgt_t	*ntpgt;
1092a6d42e7dSPeter Dunlap 
1093a6d42e7dSPeter Dunlap 	if (!cfg || !tpg) {
1094a6d42e7dSPeter Dunlap 		return (EINVAL);
1095a6d42e7dSPeter Dunlap 	}
1096a6d42e7dSPeter Dunlap 
1097a6d42e7dSPeter Dunlap 	ptr = cfg->config_tpg_list;
1098a6d42e7dSPeter Dunlap 	while (ptr) {
1099a6d42e7dSPeter Dunlap 		if (strcmp(ptr->tpg_name, tpg->tpg_name) == 0) {
1100a6d42e7dSPeter Dunlap 			break;
1101a6d42e7dSPeter Dunlap 		}
1102a6d42e7dSPeter Dunlap 		prev = ptr;
1103a6d42e7dSPeter Dunlap 		ptr = ptr->tpg_next;
1104a6d42e7dSPeter Dunlap 	}
1105a6d42e7dSPeter Dunlap 
1106a6d42e7dSPeter Dunlap 	if (!ptr) {
1107a6d42e7dSPeter Dunlap 		return (0);
1108a6d42e7dSPeter Dunlap 	}
1109a6d42e7dSPeter Dunlap 
1110a6d42e7dSPeter Dunlap 	/*
1111a6d42e7dSPeter Dunlap 	 * See if any targets are using this portal group.
1112a6d42e7dSPeter Dunlap 	 * If there are, and the force flag is not set, fail.
1113a6d42e7dSPeter Dunlap 	 */
1114a6d42e7dSPeter Dunlap 	tgt = cfg->config_tgt_list;
1115a6d42e7dSPeter Dunlap 	while (tgt) {
1116a6d42e7dSPeter Dunlap 		tpgt = tgt->tgt_tpgt_list;
1117a6d42e7dSPeter Dunlap 		while (tpgt) {
1118a6d42e7dSPeter Dunlap 			ntpgt = tpgt->tpgt_next;
1119a6d42e7dSPeter Dunlap 
1120a6d42e7dSPeter Dunlap 			if (strcmp(tpgt->tpgt_tpg_name, tpg->tpg_name)
1121a6d42e7dSPeter Dunlap 			    == 0) {
1122a6d42e7dSPeter Dunlap 				if (!force) {
1123a6d42e7dSPeter Dunlap 					return (EBUSY);
1124a6d42e7dSPeter Dunlap 				}
1125a6d42e7dSPeter Dunlap 				it_tpgt_delete(cfg, tgt, tpgt);
1126a6d42e7dSPeter Dunlap 			}
1127a6d42e7dSPeter Dunlap 
1128a6d42e7dSPeter Dunlap 			tpgt = ntpgt;
1129a6d42e7dSPeter Dunlap 		}
1130a6d42e7dSPeter Dunlap 		tgt = tgt->tgt_next;
1131a6d42e7dSPeter Dunlap 	}
1132a6d42e7dSPeter Dunlap 
1133a6d42e7dSPeter Dunlap 	/* Now that it's not in use anywhere, remove the TPG */
1134a6d42e7dSPeter Dunlap 	if (prev) {
1135a6d42e7dSPeter Dunlap 		prev->tpg_next = ptr->tpg_next;
1136a6d42e7dSPeter Dunlap 	} else {
1137a6d42e7dSPeter Dunlap 		cfg->config_tpg_list = ptr->tpg_next;
1138a6d42e7dSPeter Dunlap 	}
1139a6d42e7dSPeter Dunlap 	ptr->tpg_next = NULL;
1140a6d42e7dSPeter Dunlap 
1141a6d42e7dSPeter Dunlap 	cfg->config_tpg_count--;
1142a6d42e7dSPeter Dunlap 
1143a6d42e7dSPeter Dunlap 	it_tpg_free(ptr);
1144a6d42e7dSPeter Dunlap 
1145a6d42e7dSPeter Dunlap 	return (0);
1146a6d42e7dSPeter Dunlap }
1147a6d42e7dSPeter Dunlap 
1148a6d42e7dSPeter Dunlap /*
1149a6d42e7dSPeter Dunlap  * Function:  it_tpg_free()
1150a6d42e7dSPeter Dunlap  *
1151a6d42e7dSPeter Dunlap  * Deallocates resources associated with an it_tpg_t structure.
1152a6d42e7dSPeter Dunlap  * If tpg->next is not NULL, frees all members of the list.
1153a6d42e7dSPeter Dunlap  */
1154a6d42e7dSPeter Dunlap void
it_tpg_free(it_tpg_t * tpg)1155a6d42e7dSPeter Dunlap it_tpg_free(it_tpg_t *tpg)
1156a6d42e7dSPeter Dunlap {
1157a6d42e7dSPeter Dunlap 	it_tpg_free_cmn(tpg);
1158a6d42e7dSPeter Dunlap }
1159a6d42e7dSPeter Dunlap 
1160a6d42e7dSPeter Dunlap /*
1161a6d42e7dSPeter Dunlap  * Function:  it_portal_create()
1162a6d42e7dSPeter Dunlap  *
1163a6d42e7dSPeter Dunlap  * Add an it_portal_t structure presenting a new portal to the specified
1164a6d42e7dSPeter Dunlap  * target portal group.  The change to the target portal group will not take
1165a6d42e7dSPeter Dunlap  * effect until the modified configuration is committed by calling
1166a6d42e7dSPeter Dunlap  * it_config_commit().
1167a6d42e7dSPeter Dunlap  *
1168a6d42e7dSPeter Dunlap  * Parameters:
1169a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configration obtained from
1170a6d42e7dSPeter Dunlap  *			it_config_load()
1171a6d42e7dSPeter Dunlap  *    tpg		Pointer to the it_tpg_t structure representing the
1172a6d42e7dSPeter Dunlap  *			target portal group
1173a6d42e7dSPeter Dunlap  *    portal		Pointer to the it_portal_t structure representing
1174a6d42e7dSPeter Dunlap  *			the portal
1175a6d42e7dSPeter Dunlap  *    portal_ip_port	A string containing an appropriately formatted
1176a6d42e7dSPeter Dunlap  *			IP address or IP address:port in either IPv4 or
1177a6d42e7dSPeter Dunlap  *			IPv6 format.
1178a6d42e7dSPeter Dunlap  * Return Values:
1179a6d42e7dSPeter Dunlap  *    0			Success
1180a6d42e7dSPeter Dunlap  *    ENOMEM		Could not allocate resources
1181a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
1182a6d42e7dSPeter Dunlap  *    EEXIST		Portal already configured for another portal group
1183a6d42e7dSPeter Dunlap  */
1184a6d42e7dSPeter Dunlap int
it_portal_create(it_config_t * cfg,it_tpg_t * tpg,it_portal_t ** portal,char * portal_ip_port)1185a6d42e7dSPeter Dunlap it_portal_create(it_config_t *cfg, it_tpg_t *tpg, it_portal_t **portal,
1186a6d42e7dSPeter Dunlap     char *portal_ip_port)
1187a6d42e7dSPeter Dunlap {
1188a6d42e7dSPeter Dunlap 	struct sockaddr_storage		sa;
1189a6d42e7dSPeter Dunlap 	it_portal_t			*ptr;
1190a6d42e7dSPeter Dunlap 	it_tpg_t			*ctpg = NULL;
1191a6d42e7dSPeter Dunlap 
1192a6d42e7dSPeter Dunlap 	if (!cfg || !tpg || !portal || !portal_ip_port) {
1193a6d42e7dSPeter Dunlap 		return (EINVAL);
1194a6d42e7dSPeter Dunlap 	}
1195a6d42e7dSPeter Dunlap 
1196a6d42e7dSPeter Dunlap 	if ((it_common_convert_sa(portal_ip_port, &sa, ISCSI_LISTEN_PORT))
1197a6d42e7dSPeter Dunlap 	    == NULL) {
1198a6d42e7dSPeter Dunlap 		return (EINVAL);
1199a6d42e7dSPeter Dunlap 	}
1200a6d42e7dSPeter Dunlap 
1201a6d42e7dSPeter Dunlap 	/* Check that this portal doesn't appear in any other tag */
1202a6d42e7dSPeter Dunlap 	ctpg = cfg->config_tpg_list;
1203a6d42e7dSPeter Dunlap 	while (ctpg) {
1204a6d42e7dSPeter Dunlap 		ptr = ctpg->tpg_portal_list;
120542bf653bSPeter Gill 		for (; ptr != NULL; ptr = ptr->portal_next) {
1206a6d42e7dSPeter Dunlap 			if (it_sa_compare(&(ptr->portal_addr), &sa) != 0) {
1207a6d42e7dSPeter Dunlap 				continue;
1208a6d42e7dSPeter Dunlap 			}
1209a6d42e7dSPeter Dunlap 
1210a6d42e7dSPeter Dunlap 			/*
1211a6d42e7dSPeter Dunlap 			 * Existing in the same group is not an error,
1212a6d42e7dSPeter Dunlap 			 * but don't add it again.
1213a6d42e7dSPeter Dunlap 			 */
1214a6d42e7dSPeter Dunlap 			if (strcmp(ctpg->tpg_name, tpg->tpg_name) == 0) {
1215a6d42e7dSPeter Dunlap 				return (0);
1216a6d42e7dSPeter Dunlap 			} else {
1217a6d42e7dSPeter Dunlap 				/* Not allowed */
1218a6d42e7dSPeter Dunlap 				return (EEXIST);
1219a6d42e7dSPeter Dunlap 			}
1220a6d42e7dSPeter Dunlap 		}
1221a6d42e7dSPeter Dunlap 		ctpg = ctpg->tpg_next;
1222a6d42e7dSPeter Dunlap 	}
1223a6d42e7dSPeter Dunlap 
1224a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_portal_t));
1225a6d42e7dSPeter Dunlap 	if (!ptr) {
1226a6d42e7dSPeter Dunlap 		return (ENOMEM);
1227a6d42e7dSPeter Dunlap 	}
1228a6d42e7dSPeter Dunlap 
1229a6d42e7dSPeter Dunlap 	(void) memcpy(&(ptr->portal_addr), &sa,
1230a6d42e7dSPeter Dunlap 	    sizeof (struct sockaddr_storage));
123142bf653bSPeter Gill 	ptr->portal_next = tpg->tpg_portal_list;
1232a6d42e7dSPeter Dunlap 	tpg->tpg_portal_list = ptr;
1233a6d42e7dSPeter Dunlap 	tpg->tpg_portal_count++;
1234a6d42e7dSPeter Dunlap 	tpg->tpg_generation++;
1235a6d42e7dSPeter Dunlap 
1236a6d42e7dSPeter Dunlap 	return (0);
1237a6d42e7dSPeter Dunlap }
1238a6d42e7dSPeter Dunlap 
1239a6d42e7dSPeter Dunlap /*
1240a6d42e7dSPeter Dunlap  * Function:  it_portal_delete()
1241a6d42e7dSPeter Dunlap  *
1242a6d42e7dSPeter Dunlap  * Remove the specified portal from the specified target portal group.
1243a6d42e7dSPeter Dunlap  * The portal removal will not take effect until the modified configuration
1244a6d42e7dSPeter Dunlap  * is committed by calling it_config_commit().
1245a6d42e7dSPeter Dunlap  *
1246a6d42e7dSPeter Dunlap  * Parameters:
1247a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configration obtained from
1248a6d42e7dSPeter Dunlap  *			it_config_load()
1249a6d42e7dSPeter Dunlap  *    tpg		Pointer to the it_tpg_t structure representing the
1250a6d42e7dSPeter Dunlap  *			target portal group
1251a6d42e7dSPeter Dunlap  *    portal		Pointer to the it_portal_t structure representing
1252a6d42e7dSPeter Dunlap  *			the portal
1253a6d42e7dSPeter Dunlap  */
1254a6d42e7dSPeter Dunlap void
it_portal_delete(it_config_t * cfg,it_tpg_t * tpg,it_portal_t * portal)1255a6d42e7dSPeter Dunlap it_portal_delete(it_config_t *cfg, it_tpg_t *tpg, it_portal_t *portal)
1256a6d42e7dSPeter Dunlap {
1257a6d42e7dSPeter Dunlap 	it_portal_t	*ptr;
125842bf653bSPeter Gill 	it_portal_t	*prev = NULL;
1259a6d42e7dSPeter Dunlap 
1260a6d42e7dSPeter Dunlap 	if (!cfg || !tpg || !portal) {
1261a6d42e7dSPeter Dunlap 		return;
1262a6d42e7dSPeter Dunlap 	}
1263a6d42e7dSPeter Dunlap 
1264a6d42e7dSPeter Dunlap 	ptr = tpg->tpg_portal_list;
1265a6d42e7dSPeter Dunlap 	while (ptr) {
1266a6d42e7dSPeter Dunlap 		if (memcmp(&(ptr->portal_addr), &(portal->portal_addr),
1267a6d42e7dSPeter Dunlap 		    sizeof (ptr->portal_addr)) == 0) {
1268a6d42e7dSPeter Dunlap 			break;
1269a6d42e7dSPeter Dunlap 		}
1270a6d42e7dSPeter Dunlap 		prev = ptr;
127142bf653bSPeter Gill 		ptr = ptr->portal_next;
1272a6d42e7dSPeter Dunlap 	}
1273a6d42e7dSPeter Dunlap 
1274a6d42e7dSPeter Dunlap 	if (!ptr) {
1275a6d42e7dSPeter Dunlap 		return;
1276a6d42e7dSPeter Dunlap 	}
1277a6d42e7dSPeter Dunlap 
1278a6d42e7dSPeter Dunlap 	if (prev) {
127942bf653bSPeter Gill 		prev->portal_next = ptr->portal_next;
1280a6d42e7dSPeter Dunlap 	} else {
128142bf653bSPeter Gill 		tpg->tpg_portal_list = ptr->portal_next;
1282a6d42e7dSPeter Dunlap 	}
1283a6d42e7dSPeter Dunlap 	tpg->tpg_portal_count--;
1284a6d42e7dSPeter Dunlap 	tpg->tpg_generation++;
1285a6d42e7dSPeter Dunlap 
1286a6d42e7dSPeter Dunlap 	free(ptr);
1287a6d42e7dSPeter Dunlap }
1288a6d42e7dSPeter Dunlap 
1289a6d42e7dSPeter Dunlap /*
1290a6d42e7dSPeter Dunlap  * Function:  it_ini_create()
1291a6d42e7dSPeter Dunlap  *
1292a6d42e7dSPeter Dunlap  * Add an initiator context to the global configuration. The new
1293a6d42e7dSPeter Dunlap  * initiator context will not be instantiated until the modified
1294a6d42e7dSPeter Dunlap  * configuration is committed by calling it_config_commit().
1295a6d42e7dSPeter Dunlap  *
1296a6d42e7dSPeter Dunlap  * Parameters:
1297a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configration obtained from
1298a6d42e7dSPeter Dunlap  *			it_config_load()
1299a6d42e7dSPeter Dunlap  *    ini		Pointer to the it_ini_t structure representing
1300a6d42e7dSPeter Dunlap  *			the initiator context.
1301a6d42e7dSPeter Dunlap  *    ini_node_name	The iSCSI node name of the remote initiator.
1302a6d42e7dSPeter Dunlap  *
1303a6d42e7dSPeter Dunlap  * Return Values:
1304a6d42e7dSPeter Dunlap  *    0			Success
1305a6d42e7dSPeter Dunlap  *    ENOMEM		Could not allocate resources
1306a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter.
1307a6d42e7dSPeter Dunlap  *    EFAULT		Invalid initiator name
1308a6d42e7dSPeter Dunlap  */
1309a6d42e7dSPeter Dunlap int
it_ini_create(it_config_t * cfg,it_ini_t ** ini,char * ini_node_name)1310a6d42e7dSPeter Dunlap it_ini_create(it_config_t *cfg, it_ini_t **ini, char *ini_node_name)
1311a6d42e7dSPeter Dunlap {
1312a6d42e7dSPeter Dunlap 	it_ini_t	*ptr;
1313a6d42e7dSPeter Dunlap 
1314a6d42e7dSPeter Dunlap 	if (!cfg || !ini || !ini_node_name) {
1315a6d42e7dSPeter Dunlap 		return (EINVAL);
1316a6d42e7dSPeter Dunlap 	}
1317a6d42e7dSPeter Dunlap 
1318a6d42e7dSPeter Dunlap 	/*
1319a6d42e7dSPeter Dunlap 	 * Ensure this is a valid ini name
1320a6d42e7dSPeter Dunlap 	 */
1321a6d42e7dSPeter Dunlap 	if (!validate_iscsi_name(ini_node_name)) {
1322a6d42e7dSPeter Dunlap 		return (EFAULT);
1323a6d42e7dSPeter Dunlap 	}
1324a6d42e7dSPeter Dunlap 
1325a6d42e7dSPeter Dunlap 	ptr = cfg->config_ini_list;
1326a6d42e7dSPeter Dunlap 	while (ptr) {
1327e20dd2eeSCharles Ting 		if (strcasecmp(ptr->ini_name, ini_node_name) == 0) {
1328a6d42e7dSPeter Dunlap 			break;
1329a6d42e7dSPeter Dunlap 		}
1330a6d42e7dSPeter Dunlap 		ptr = ptr->ini_next;
1331a6d42e7dSPeter Dunlap 	}
1332a6d42e7dSPeter Dunlap 
1333a6d42e7dSPeter Dunlap 	if (ptr) {
1334a6d42e7dSPeter Dunlap 		return (EEXIST);
1335a6d42e7dSPeter Dunlap 	}
1336a6d42e7dSPeter Dunlap 
1337a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_ini_t));
1338a6d42e7dSPeter Dunlap 	if (!ptr) {
1339a6d42e7dSPeter Dunlap 		return (ENOMEM);
1340a6d42e7dSPeter Dunlap 	}
1341a6d42e7dSPeter Dunlap 
1342a6d42e7dSPeter Dunlap 	(void) strlcpy(ptr->ini_name, ini_node_name, sizeof (ptr->ini_name));
1343a6d42e7dSPeter Dunlap 	ptr->ini_generation = 1;
1344a6d42e7dSPeter Dunlap 	/* nvlist for props? */
1345a6d42e7dSPeter Dunlap 
1346a6d42e7dSPeter Dunlap 	ptr->ini_next = cfg->config_ini_list;
1347a6d42e7dSPeter Dunlap 	cfg->config_ini_list = ptr;
1348a6d42e7dSPeter Dunlap 	cfg->config_ini_count++;
1349a6d42e7dSPeter Dunlap 
1350a6d42e7dSPeter Dunlap 	*ini = ptr;
1351a6d42e7dSPeter Dunlap 
1352a6d42e7dSPeter Dunlap 	return (0);
1353a6d42e7dSPeter Dunlap }
1354a6d42e7dSPeter Dunlap 
1355a6d42e7dSPeter Dunlap /*
1356a6d42e7dSPeter Dunlap  * Function:  it_ini_setprop()
1357a6d42e7dSPeter Dunlap  *
1358a6d42e7dSPeter Dunlap  * Validate the provided property list and set the initiator properties.
1359a6d42e7dSPeter Dunlap  * If errlist is not NULL, returns detailed errors for each property
1360a6d42e7dSPeter Dunlap  * that failed.  The format for errorlist is key = property,
1361a6d42e7dSPeter Dunlap  * value = error string.
1362a6d42e7dSPeter Dunlap  *
1363a6d42e7dSPeter Dunlap  * Parameters:
1364a6d42e7dSPeter Dunlap  *
1365a6d42e7dSPeter Dunlap  *    ini		The initiator being updated.
1366a6d42e7dSPeter Dunlap  *    proplist		nvlist_t containing properties for this target.
1367a6d42e7dSPeter Dunlap  *    errlist		(optional)  nvlist_t of errors encountered when
1368a6d42e7dSPeter Dunlap  *			validating the properties.
1369a6d42e7dSPeter Dunlap  *
1370a6d42e7dSPeter Dunlap  * Return Values:
1371a6d42e7dSPeter Dunlap  *    0			Success
1372a6d42e7dSPeter Dunlap  *    EINVAL		Invalid property
1373a6d42e7dSPeter Dunlap  *
1374a6d42e7dSPeter Dunlap  */
1375a6d42e7dSPeter Dunlap int
it_ini_setprop(it_ini_t * ini,nvlist_t * proplist,nvlist_t ** errlist)1376a6d42e7dSPeter Dunlap it_ini_setprop(it_ini_t *ini, nvlist_t *proplist, nvlist_t **errlist)
1377a6d42e7dSPeter Dunlap {
1378a6d42e7dSPeter Dunlap 	int		ret;
13798175704fSPeter Gill 	nvlist_t	*errs = NULL;
1380a6d42e7dSPeter Dunlap 	nvlist_t	*iprops = NULL;
1381a6d42e7dSPeter Dunlap 	char		*val = NULL;
1382a6d42e7dSPeter Dunlap 
1383a6d42e7dSPeter Dunlap 	if (!ini || !proplist) {
1384a6d42e7dSPeter Dunlap 		return (EINVAL);
1385a6d42e7dSPeter Dunlap 	}
1386a6d42e7dSPeter Dunlap 
1387a6d42e7dSPeter Dunlap 	if (errlist) {
13888175704fSPeter Gill 		(void) nvlist_alloc(&errs, 0, 0);
13898175704fSPeter Gill 		*errlist = errs;
1390a6d42e7dSPeter Dunlap 	}
1391a6d42e7dSPeter Dunlap 
1392a6d42e7dSPeter Dunlap 	/*
1393a6d42e7dSPeter Dunlap 	 * copy the existing properties, merge, then validate
1394a6d42e7dSPeter Dunlap 	 * the merged properties before committing them.
1395a6d42e7dSPeter Dunlap 	 */
1396a6d42e7dSPeter Dunlap 	if (ini->ini_properties) {
1397a6d42e7dSPeter Dunlap 		ret = nvlist_dup(ini->ini_properties, &iprops, 0);
1398a6d42e7dSPeter Dunlap 	} else {
1399a6d42e7dSPeter Dunlap 		ret = nvlist_alloc(&iprops, NV_UNIQUE_NAME, 0);
1400a6d42e7dSPeter Dunlap 	}
1401a6d42e7dSPeter Dunlap 
14027f6f3ee7SPeter Gill 	if (ret != 0) {
14037f6f3ee7SPeter Gill 		return (ret);
14047f6f3ee7SPeter Gill 	}
14057f6f3ee7SPeter Gill 
1406a6d42e7dSPeter Dunlap 	ret = nvlist_merge(iprops, proplist, 0);
14077f6f3ee7SPeter Gill 	if (ret != 0) {
14087f6f3ee7SPeter Gill 		nvlist_free(iprops);
14097f6f3ee7SPeter Gill 		return (ret);
1410a6d42e7dSPeter Dunlap 	}
1411a6d42e7dSPeter Dunlap 
1412a6d42e7dSPeter Dunlap 	/* unset chap username if requested */
1413a6d42e7dSPeter Dunlap 	if ((nvlist_lookup_string(proplist, PROP_CHAP_USER, &val)) == 0) {
1414a6d42e7dSPeter Dunlap 		if (strcasecmp(val, "none") == 0) {
1415a6d42e7dSPeter Dunlap 			(void) nvlist_remove_all(iprops, PROP_CHAP_USER);
1416a6d42e7dSPeter Dunlap 		}
1417a6d42e7dSPeter Dunlap 	}
1418a6d42e7dSPeter Dunlap 
1419a6d42e7dSPeter Dunlap 	/* base64 encode the CHAP secret, if it's changed */
1420a6d42e7dSPeter Dunlap 	if ((nvlist_lookup_string(proplist, PROP_CHAP_SECRET, &val)) == 0) {
1421a6d42e7dSPeter Dunlap 		char		bsecret[MAX_BASE64_LEN];
1422a6d42e7dSPeter Dunlap 
14238175704fSPeter Gill 		ret = it_val_pass(PROP_CHAP_SECRET, val, errs);
1424a6d42e7dSPeter Dunlap 		if (ret == 0) {
1425a6d42e7dSPeter Dunlap 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
1426a6d42e7dSPeter Dunlap 
1427a6d42e7dSPeter Dunlap 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
1428a6d42e7dSPeter Dunlap 			    strlen(val), bsecret, MAX_BASE64_LEN);
1429a6d42e7dSPeter Dunlap 
1430a6d42e7dSPeter Dunlap 			if (ret == 0) {
1431a6d42e7dSPeter Dunlap 				/* replace the value in the nvlist */
1432a6d42e7dSPeter Dunlap 				ret = nvlist_add_string(iprops,
1433a6d42e7dSPeter Dunlap 				    PROP_CHAP_SECRET, bsecret);
1434a6d42e7dSPeter Dunlap 			}
1435a6d42e7dSPeter Dunlap 		}
1436a6d42e7dSPeter Dunlap 	}
1437a6d42e7dSPeter Dunlap 
1438a6d42e7dSPeter Dunlap 	if (ret == 0) {
14398175704fSPeter Gill 		ret = it_validate_iniprops(iprops, errs);
1440a6d42e7dSPeter Dunlap 	}
1441a6d42e7dSPeter Dunlap 
1442a6d42e7dSPeter Dunlap 	if (ret != 0) {
1443a6d42e7dSPeter Dunlap 		if (iprops) {
1444a6d42e7dSPeter Dunlap 			nvlist_free(iprops);
1445a6d42e7dSPeter Dunlap 		}
1446a6d42e7dSPeter Dunlap 		return (ret);
1447a6d42e7dSPeter Dunlap 	}
1448a6d42e7dSPeter Dunlap 
1449a6d42e7dSPeter Dunlap 	if (ini->ini_properties) {
1450a6d42e7dSPeter Dunlap 		nvlist_free(ini->ini_properties);
1451a6d42e7dSPeter Dunlap 	}
1452a6d42e7dSPeter Dunlap 	ini->ini_properties = iprops;
1453a6d42e7dSPeter Dunlap 
1454a6d42e7dSPeter Dunlap 	return (0);
1455a6d42e7dSPeter Dunlap }
1456a6d42e7dSPeter Dunlap 
1457a6d42e7dSPeter Dunlap /*
1458a6d42e7dSPeter Dunlap  * Function:  it_ini_delete()
1459a6d42e7dSPeter Dunlap  *
1460a6d42e7dSPeter Dunlap  * Remove the specified initiator context from the global configuration.
1461a6d42e7dSPeter Dunlap  * The removal will not take effect until the modified configuration is
1462a6d42e7dSPeter Dunlap  * committed by calling it_config_commit().
1463a6d42e7dSPeter Dunlap  *
1464a6d42e7dSPeter Dunlap  * Parameters:
1465a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configration obtained from
1466a6d42e7dSPeter Dunlap  *			it_config_load()
1467a6d42e7dSPeter Dunlap  *    ini		Pointer to the it_ini_t structure representing
1468a6d42e7dSPeter Dunlap  *			the initiator context.
1469a6d42e7dSPeter Dunlap  */
1470a6d42e7dSPeter Dunlap void
it_ini_delete(it_config_t * cfg,it_ini_t * ini)1471a6d42e7dSPeter Dunlap it_ini_delete(it_config_t *cfg, it_ini_t *ini)
1472a6d42e7dSPeter Dunlap {
1473a6d42e7dSPeter Dunlap 	it_ini_t	*ptr;
1474a6d42e7dSPeter Dunlap 	it_ini_t	*prev = NULL;
1475a6d42e7dSPeter Dunlap 
1476a6d42e7dSPeter Dunlap 	if (!cfg || !ini) {
1477a6d42e7dSPeter Dunlap 		return;
1478a6d42e7dSPeter Dunlap 	}
1479a6d42e7dSPeter Dunlap 
1480a6d42e7dSPeter Dunlap 	ptr = cfg->config_ini_list;
1481a6d42e7dSPeter Dunlap 	while (ptr) {
1482e20dd2eeSCharles Ting 		if (strcasecmp(ptr->ini_name, ini->ini_name) == 0) {
1483a6d42e7dSPeter Dunlap 			break;
1484a6d42e7dSPeter Dunlap 		}
1485a6d42e7dSPeter Dunlap 		prev = ptr;
1486a6d42e7dSPeter Dunlap 		ptr = ptr->ini_next;
1487a6d42e7dSPeter Dunlap 	}
1488a6d42e7dSPeter Dunlap 
1489a6d42e7dSPeter Dunlap 	if (!ptr) {
1490a6d42e7dSPeter Dunlap 		return;
1491a6d42e7dSPeter Dunlap 	}
1492a6d42e7dSPeter Dunlap 
1493a6d42e7dSPeter Dunlap 	if (prev) {
1494a6d42e7dSPeter Dunlap 		prev->ini_next = ptr->ini_next;
1495a6d42e7dSPeter Dunlap 	} else {
1496a6d42e7dSPeter Dunlap 		cfg->config_ini_list = ptr->ini_next;
1497a6d42e7dSPeter Dunlap 	}
1498a6d42e7dSPeter Dunlap 
1499a6d42e7dSPeter Dunlap 	ptr->ini_next = NULL; /* Only free this initiator */
1500a6d42e7dSPeter Dunlap 
1501a6d42e7dSPeter Dunlap 	cfg->config_ini_count--;
1502a6d42e7dSPeter Dunlap 
1503a6d42e7dSPeter Dunlap 	it_ini_free(ptr);
1504a6d42e7dSPeter Dunlap }
1505a6d42e7dSPeter Dunlap 
1506a6d42e7dSPeter Dunlap /*
1507a6d42e7dSPeter Dunlap  * Function:  it_ini_free()
1508a6d42e7dSPeter Dunlap  *
1509a6d42e7dSPeter Dunlap  * Deallocates resources of an it_ini_t structure. If ini->next is
1510a6d42e7dSPeter Dunlap  * not NULL, frees all members of the list.
1511a6d42e7dSPeter Dunlap  */
1512a6d42e7dSPeter Dunlap void
it_ini_free(it_ini_t * ini)1513a6d42e7dSPeter Dunlap it_ini_free(it_ini_t *ini)
1514a6d42e7dSPeter Dunlap {
1515a6d42e7dSPeter Dunlap 	it_ini_free_cmn(ini);
1516a6d42e7dSPeter Dunlap }
1517a6d42e7dSPeter Dunlap 
1518a6d42e7dSPeter Dunlap /*
1519a6d42e7dSPeter Dunlap  * Goes through the target property list and validates
1520a6d42e7dSPeter Dunlap  * each entry.  If errs is non-NULL, will return explicit errors
1521a6d42e7dSPeter Dunlap  * for each property that fails validation.
1522a6d42e7dSPeter Dunlap  */
1523a6d42e7dSPeter Dunlap static int
it_validate_tgtprops(nvlist_t * nvl,nvlist_t * errs)1524a6d42e7dSPeter Dunlap it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs)
1525a6d42e7dSPeter Dunlap {
1526a6d42e7dSPeter Dunlap 	int		errcnt = 0;
1527a6d42e7dSPeter Dunlap 	nvpair_t	*nvp = NULL;
1528a6d42e7dSPeter Dunlap 	data_type_t	nvtype;
1529a6d42e7dSPeter Dunlap 	char		*name;
1530a6d42e7dSPeter Dunlap 	char		*val;
1531a6d42e7dSPeter Dunlap 	char		*auth = NULL;
1532a6d42e7dSPeter Dunlap 
1533a6d42e7dSPeter Dunlap 	if (!nvl) {
1534a6d42e7dSPeter Dunlap 		return (0);
1535a6d42e7dSPeter Dunlap 	}
1536a6d42e7dSPeter Dunlap 
1537a6d42e7dSPeter Dunlap 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1538a6d42e7dSPeter Dunlap 		name = nvpair_name(nvp);
1539a6d42e7dSPeter Dunlap 		nvtype = nvpair_type(nvp);
1540a6d42e7dSPeter Dunlap 
1541a6d42e7dSPeter Dunlap 		if (!name) {
1542a6d42e7dSPeter Dunlap 			continue;
1543a6d42e7dSPeter Dunlap 		}
1544a6d42e7dSPeter Dunlap 
1545a6d42e7dSPeter Dunlap 		val = NULL;
1546a6d42e7dSPeter Dunlap 		if (strcmp(name, PROP_TARGET_CHAP_USER) == 0) {
1547a6d42e7dSPeter Dunlap 			if (nvtype != DATA_TYPE_STRING) {
1548a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1549a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1550a6d42e7dSPeter Dunlap 				errcnt++;
1551a6d42e7dSPeter Dunlap 				continue;
1552a6d42e7dSPeter Dunlap 			}
1553a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_TARGET_CHAP_SECRET) == 0) {
1554a6d42e7dSPeter Dunlap 			/*
1555a6d42e7dSPeter Dunlap 			 * must be between 12 and 255 chars in cleartext.
1556a6d42e7dSPeter Dunlap 			 * will be base64 encoded when it's set.
1557a6d42e7dSPeter Dunlap 			 */
1558a6d42e7dSPeter Dunlap 			if (nvtype == DATA_TYPE_STRING) {
1559a6d42e7dSPeter Dunlap 				(void) nvpair_value_string(nvp, &val);
1560a6d42e7dSPeter Dunlap 			}
1561a6d42e7dSPeter Dunlap 
1562a6d42e7dSPeter Dunlap 			if (!val) {
1563a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1564a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1565a6d42e7dSPeter Dunlap 				errcnt++;
1566a6d42e7dSPeter Dunlap 				continue;
1567a6d42e7dSPeter Dunlap 			}
1568a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_ALIAS) == 0) {
1569a6d42e7dSPeter Dunlap 			if (nvtype != DATA_TYPE_STRING) {
1570a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1571a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1572a6d42e7dSPeter Dunlap 				errcnt++;
1573a6d42e7dSPeter Dunlap 				continue;
1574a6d42e7dSPeter Dunlap 			}
1575a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_AUTH) == 0) {
1576a6d42e7dSPeter Dunlap 			if (nvtype == DATA_TYPE_STRING) {
1577a6d42e7dSPeter Dunlap 				val = NULL;
1578a6d42e7dSPeter Dunlap 				(void) nvpair_value_string(nvp, &val);
1579a6d42e7dSPeter Dunlap 			}
1580a6d42e7dSPeter Dunlap 
1581a6d42e7dSPeter Dunlap 			if (!val) {
1582a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1583a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1584a6d42e7dSPeter Dunlap 				errcnt++;
1585a6d42e7dSPeter Dunlap 				continue;
1586a6d42e7dSPeter Dunlap 			}
1587a6d42e7dSPeter Dunlap 			if ((strcmp(val, PA_AUTH_NONE) != 0) &&
1588a6d42e7dSPeter Dunlap 			    (strcmp(val, PA_AUTH_CHAP) != 0) &&
1589a6d42e7dSPeter Dunlap 			    (strcmp(val, PA_AUTH_RADIUS) != 0) &&
1590a6d42e7dSPeter Dunlap 			    (strcmp(val, "default") != 0)) {
1591a6d42e7dSPeter Dunlap 				PROPERR(errs, val, gettext(
1592a6d42e7dSPeter Dunlap 				    "must be none, chap, radius or default"));
1593a6d42e7dSPeter Dunlap 				errcnt++;
1594a6d42e7dSPeter Dunlap 			}
1595a6d42e7dSPeter Dunlap 			auth = val;
1596a6d42e7dSPeter Dunlap 			continue;
1597a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_OLD_TARGET_NAME) == 0) {
1598a6d42e7dSPeter Dunlap 			continue;
1599a6d42e7dSPeter Dunlap 		} else {
1600a6d42e7dSPeter Dunlap 			/* unrecognized property */
1601a6d42e7dSPeter Dunlap 			PROPERR(errs, name, gettext("unrecognized property"));
1602a6d42e7dSPeter Dunlap 			errcnt++;
1603a6d42e7dSPeter Dunlap 		}
1604a6d42e7dSPeter Dunlap 	}
1605a6d42e7dSPeter Dunlap 
1606a6d42e7dSPeter Dunlap 	if (errcnt) {
1607a6d42e7dSPeter Dunlap 		return (EINVAL);
1608a6d42e7dSPeter Dunlap 	}
1609a6d42e7dSPeter Dunlap 
1610a6d42e7dSPeter Dunlap 	/* if auth is being set to default, remove from this nvlist */
1611a6d42e7dSPeter Dunlap 	if (auth && (strcmp(auth, "default") == 0)) {
1612a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(nvl, PROP_AUTH);
1613a6d42e7dSPeter Dunlap 	}
1614a6d42e7dSPeter Dunlap 
1615a6d42e7dSPeter Dunlap 	return (0);
1616a6d42e7dSPeter Dunlap }
1617a6d42e7dSPeter Dunlap 
1618a6d42e7dSPeter Dunlap /*
1619a6d42e7dSPeter Dunlap  * Goes through the config property list and validates
1620a6d42e7dSPeter Dunlap  * each entry.  If errs is non-NULL, will return explicit errors
1621a6d42e7dSPeter Dunlap  * for each property that fails validation.
1622a6d42e7dSPeter Dunlap  */
1623a6d42e7dSPeter Dunlap static int
it_validate_configprops(nvlist_t * nvl,nvlist_t * errs)1624a6d42e7dSPeter Dunlap it_validate_configprops(nvlist_t *nvl, nvlist_t *errs)
1625a6d42e7dSPeter Dunlap {
1626a6d42e7dSPeter Dunlap 	int				errcnt = 0;
1627a6d42e7dSPeter Dunlap 	nvpair_t			*nvp = NULL;
1628a6d42e7dSPeter Dunlap 	data_type_t			nvtype;
1629a6d42e7dSPeter Dunlap 	char				*name;
1630a6d42e7dSPeter Dunlap 	char				*val;
1631a6d42e7dSPeter Dunlap 	struct sockaddr_storage		sa;
1632bf604c64SPeter Dunlap 	boolean_t			update_rad_server = B_FALSE;
1633bf604c64SPeter Dunlap 	char				*rad_server;
1634a6d42e7dSPeter Dunlap 	char				*auth = NULL;
1635a6d42e7dSPeter Dunlap 
1636a6d42e7dSPeter Dunlap 	if (!nvl) {
1637a6d42e7dSPeter Dunlap 		return (0);
1638a6d42e7dSPeter Dunlap 	}
1639a6d42e7dSPeter Dunlap 
1640a6d42e7dSPeter Dunlap 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1641a6d42e7dSPeter Dunlap 		name = nvpair_name(nvp);
1642a6d42e7dSPeter Dunlap 		nvtype = nvpair_type(nvp);
1643a6d42e7dSPeter Dunlap 
1644a6d42e7dSPeter Dunlap 		if (!name) {
1645a6d42e7dSPeter Dunlap 			continue;
1646a6d42e7dSPeter Dunlap 		}
1647a6d42e7dSPeter Dunlap 
1648a6d42e7dSPeter Dunlap 		val = NULL;
1649a6d42e7dSPeter Dunlap 
1650a6d42e7dSPeter Dunlap 		/* prefetch string value as we mostly need it */
1651a6d42e7dSPeter Dunlap 		if (nvtype == DATA_TYPE_STRING) {
1652a6d42e7dSPeter Dunlap 			(void) nvpair_value_string(nvp, &val);
1653a6d42e7dSPeter Dunlap 		}
1654a6d42e7dSPeter Dunlap 
1655a6d42e7dSPeter Dunlap 		if (strcmp(name, PROP_ALIAS) == 0) {
1656a6d42e7dSPeter Dunlap 			if (!val) {
1657a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1658a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1659a6d42e7dSPeter Dunlap 				errcnt++;
1660a6d42e7dSPeter Dunlap 			}
1661a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_AUTH) == 0) {
1662a6d42e7dSPeter Dunlap 			if (!val) {
1663a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1664a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1665a6d42e7dSPeter Dunlap 				errcnt++;
1666a6d42e7dSPeter Dunlap 				continue;
1667a6d42e7dSPeter Dunlap 			}
1668a6d42e7dSPeter Dunlap 
1669a6d42e7dSPeter Dunlap 			if ((strcmp(val, PA_AUTH_NONE) != 0) &&
1670a6d42e7dSPeter Dunlap 			    (strcmp(val, PA_AUTH_CHAP) != 0) &&
1671a6d42e7dSPeter Dunlap 			    (strcmp(val, PA_AUTH_RADIUS) != 0)) {
1672a6d42e7dSPeter Dunlap 				PROPERR(errs, PROP_AUTH,
1673a6d42e7dSPeter Dunlap 				    gettext("must be none, chap or radius"));
1674a6d42e7dSPeter Dunlap 				errcnt++;
1675a6d42e7dSPeter Dunlap 			}
1676a6d42e7dSPeter Dunlap 
1677a6d42e7dSPeter Dunlap 			auth = val;
1678a6d42e7dSPeter Dunlap 
1679a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_ISNS_ENABLED) == 0) {
1680a6d42e7dSPeter Dunlap 			if (nvtype != DATA_TYPE_BOOLEAN_VALUE) {
1681a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1682a6d42e7dSPeter Dunlap 				    gettext("must be a boolean value"));
1683a6d42e7dSPeter Dunlap 				errcnt++;
1684a6d42e7dSPeter Dunlap 			}
1685a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_ISNS_SERVER) == 0) {
1686a6d42e7dSPeter Dunlap 			char		**arr = NULL;
1687a6d42e7dSPeter Dunlap 			uint32_t	acount = 0;
1688a6d42e7dSPeter Dunlap 
1689a6d42e7dSPeter Dunlap 			(void) nvlist_lookup_string_array(nvl, name,
1690a6d42e7dSPeter Dunlap 			    &arr, &acount);
1691a6d42e7dSPeter Dunlap 
1692a6d42e7dSPeter Dunlap 			while (acount > 0) {
1693a6d42e7dSPeter Dunlap 				if (strcasecmp(arr[acount - 1], "none") == 0) {
1694a6d42e7dSPeter Dunlap 					break;
1695a6d42e7dSPeter Dunlap 				}
1696a6d42e7dSPeter Dunlap 				if ((it_common_convert_sa(arr[acount - 1],
1697a6d42e7dSPeter Dunlap 				    &sa, 0)) == NULL) {
1698a6d42e7dSPeter Dunlap 					PROPERR(errs, arr[acount - 1],
1699a6d42e7dSPeter Dunlap 					    gettext("invalid address"));
1700a6d42e7dSPeter Dunlap 					errcnt++;
1701a6d42e7dSPeter Dunlap 				}
1702a6d42e7dSPeter Dunlap 				acount--;
1703a6d42e7dSPeter Dunlap 			}
1704a6d42e7dSPeter Dunlap 
1705a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_RADIUS_SECRET) == 0) {
1706a6d42e7dSPeter Dunlap 			if (!val) {
1707a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1708a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1709a6d42e7dSPeter Dunlap 				errcnt++;
1710a6d42e7dSPeter Dunlap 				continue;
1711a6d42e7dSPeter Dunlap 			}
1712a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_RADIUS_SERVER) == 0) {
1713a6d42e7dSPeter Dunlap 			struct sockaddr_storage		sa;
1714a6d42e7dSPeter Dunlap 			if (!val) {
1715a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1716a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1717a6d42e7dSPeter Dunlap 				errcnt++;
1718a6d42e7dSPeter Dunlap 				continue;
1719a6d42e7dSPeter Dunlap 			}
1720a6d42e7dSPeter Dunlap 
1721a6d42e7dSPeter Dunlap 			if ((it_common_convert_sa(val, &sa,
1722a6d42e7dSPeter Dunlap 			    DEFAULT_RADIUS_PORT)) == NULL) {
1723a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1724a6d42e7dSPeter Dunlap 				    gettext("invalid address"));
1725a6d42e7dSPeter Dunlap 				errcnt++;
1726a6d42e7dSPeter Dunlap 			} else {
1727a6d42e7dSPeter Dunlap 				/*
1728a6d42e7dSPeter Dunlap 				 * rewrite this property to ensure port
1729a6d42e7dSPeter Dunlap 				 * number is added.
1730a6d42e7dSPeter Dunlap 				 */
1731a6d42e7dSPeter Dunlap 
1732bf604c64SPeter Dunlap 				if (sockaddr_to_str(&sa, &rad_server) == 0) {
1733bf604c64SPeter Dunlap 					update_rad_server = B_TRUE;
1734a6d42e7dSPeter Dunlap 				}
1735a6d42e7dSPeter Dunlap 			}
1736a6d42e7dSPeter Dunlap 		} else {
1737a6d42e7dSPeter Dunlap 			/* unrecognized property */
1738a6d42e7dSPeter Dunlap 			PROPERR(errs, name, gettext("unrecognized property"));
1739a6d42e7dSPeter Dunlap 			errcnt++;
1740a6d42e7dSPeter Dunlap 		}
1741a6d42e7dSPeter Dunlap 	}
1742a6d42e7dSPeter Dunlap 
1743a6d42e7dSPeter Dunlap 	/*
1744bf604c64SPeter Dunlap 	 * If we successfully reformatted the radius server to add the port
1745bf604c64SPeter Dunlap 	 * number then update the nvlist
1746bf604c64SPeter Dunlap 	 */
1747bf604c64SPeter Dunlap 	if (update_rad_server) {
17486ced70a9SPriya Krishnan 		(void) nvlist_add_string(nvl, PROP_RADIUS_SERVER, rad_server);
17494f1fc35dSsrivijitha dugganapalli 		free(rad_server);
1750bf604c64SPeter Dunlap 	}
1751bf604c64SPeter Dunlap 
1752bf604c64SPeter Dunlap 	/*
1753a6d42e7dSPeter Dunlap 	 * if auth = radius, ensure radius server & secret are set.
1754a6d42e7dSPeter Dunlap 	 */
1755a6d42e7dSPeter Dunlap 	if (auth) {
1756a6d42e7dSPeter Dunlap 		if (strcmp(auth, PA_AUTH_RADIUS) == 0) {
1757a6d42e7dSPeter Dunlap 			/* need server & secret for radius */
1758a6d42e7dSPeter Dunlap 			if (!nvlist_exists(nvl, PROP_RADIUS_SERVER)) {
1759a6d42e7dSPeter Dunlap 				PROPERR(errs, PROP_RADIUS_SERVER,
1760a6d42e7dSPeter Dunlap 				    gettext("missing required property"));
1761a6d42e7dSPeter Dunlap 				errcnt++;
1762a6d42e7dSPeter Dunlap 			}
1763a6d42e7dSPeter Dunlap 			if (!nvlist_exists(nvl, PROP_RADIUS_SECRET)) {
1764a6d42e7dSPeter Dunlap 				PROPERR(errs, PROP_RADIUS_SECRET,
1765a6d42e7dSPeter Dunlap 				    gettext("missing required property"));
1766a6d42e7dSPeter Dunlap 				errcnt++;
1767a6d42e7dSPeter Dunlap 			}
1768a6d42e7dSPeter Dunlap 		}
1769a6d42e7dSPeter Dunlap 	}
1770a6d42e7dSPeter Dunlap 
1771a6d42e7dSPeter Dunlap 	if (errcnt) {
1772a6d42e7dSPeter Dunlap 		return (EINVAL);
1773a6d42e7dSPeter Dunlap 	}
1774a6d42e7dSPeter Dunlap 
1775a6d42e7dSPeter Dunlap 	return (0);
1776a6d42e7dSPeter Dunlap }
1777a6d42e7dSPeter Dunlap 
1778a6d42e7dSPeter Dunlap /*
1779a6d42e7dSPeter Dunlap  * Goes through the ini property list and validates
1780a6d42e7dSPeter Dunlap  * each entry.  If errs is non-NULL, will return explicit errors
1781a6d42e7dSPeter Dunlap  * for each property that fails validation.
1782a6d42e7dSPeter Dunlap  */
1783a6d42e7dSPeter Dunlap static int
it_validate_iniprops(nvlist_t * nvl,nvlist_t * errs)1784a6d42e7dSPeter Dunlap it_validate_iniprops(nvlist_t *nvl, nvlist_t *errs)
1785a6d42e7dSPeter Dunlap {
1786a6d42e7dSPeter Dunlap 	int				errcnt = 0;
1787a6d42e7dSPeter Dunlap 	nvpair_t			*nvp = NULL;
1788a6d42e7dSPeter Dunlap 	data_type_t			nvtype;
1789a6d42e7dSPeter Dunlap 	char				*name;
1790a6d42e7dSPeter Dunlap 	char				*val;
1791a6d42e7dSPeter Dunlap 
1792a6d42e7dSPeter Dunlap 	if (!nvl) {
1793a6d42e7dSPeter Dunlap 		return (0);
1794a6d42e7dSPeter Dunlap 	}
1795a6d42e7dSPeter Dunlap 
1796a6d42e7dSPeter Dunlap 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1797a6d42e7dSPeter Dunlap 		name = nvpair_name(nvp);
1798a6d42e7dSPeter Dunlap 		nvtype = nvpair_type(nvp);
1799a6d42e7dSPeter Dunlap 
1800a6d42e7dSPeter Dunlap 		if (!name) {
1801a6d42e7dSPeter Dunlap 			continue;
1802a6d42e7dSPeter Dunlap 		}
1803a6d42e7dSPeter Dunlap 
1804a6d42e7dSPeter Dunlap 		if (strcmp(name, PROP_CHAP_USER) == 0) {
1805a6d42e7dSPeter Dunlap 			if (nvtype != DATA_TYPE_STRING) {
1806a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1807a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1808a6d42e7dSPeter Dunlap 				errcnt++;
1809a6d42e7dSPeter Dunlap 				continue;
1810a6d42e7dSPeter Dunlap 			}
1811a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_CHAP_SECRET) == 0) {
1812a6d42e7dSPeter Dunlap 			/*
1813a6d42e7dSPeter Dunlap 			 * must be between 12 and 255 chars in cleartext.
1814a6d42e7dSPeter Dunlap 			 * will be base64 encoded when it's set.
1815a6d42e7dSPeter Dunlap 			 */
1816a6d42e7dSPeter Dunlap 			if (nvtype == DATA_TYPE_STRING) {
1817a6d42e7dSPeter Dunlap 				val = NULL;
1818a6d42e7dSPeter Dunlap 				(void) nvpair_value_string(nvp, &val);
1819a6d42e7dSPeter Dunlap 			}
1820a6d42e7dSPeter Dunlap 
1821a6d42e7dSPeter Dunlap 			if (!val) {
1822a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1823a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1824a6d42e7dSPeter Dunlap 				errcnt++;
1825a6d42e7dSPeter Dunlap 				continue;
1826a6d42e7dSPeter Dunlap 			}
1827a6d42e7dSPeter Dunlap 		} else {
1828a6d42e7dSPeter Dunlap 			/* unrecognized property */
1829a6d42e7dSPeter Dunlap 			PROPERR(errs, name, gettext("unrecognized property"));
1830a6d42e7dSPeter Dunlap 			errcnt++;
1831a6d42e7dSPeter Dunlap 		}
1832a6d42e7dSPeter Dunlap 	}
1833a6d42e7dSPeter Dunlap 
1834a6d42e7dSPeter Dunlap 	if (errcnt) {
1835a6d42e7dSPeter Dunlap 		return (EINVAL);
1836a6d42e7dSPeter Dunlap 	}
1837a6d42e7dSPeter Dunlap 
1838a6d42e7dSPeter Dunlap 	return (0);
1839a6d42e7dSPeter Dunlap }
1840a6d42e7dSPeter Dunlap 
1841a6d42e7dSPeter Dunlap static int
it_iqn_generate(char * iqn_buf,int iqn_buf_len,char * opt_iqn_suffix)1842a6d42e7dSPeter Dunlap it_iqn_generate(char *iqn_buf, int iqn_buf_len, char *opt_iqn_suffix)
1843a6d42e7dSPeter Dunlap {
1844a6d42e7dSPeter Dunlap 	int		ret;
1845a6d42e7dSPeter Dunlap 	uuid_t		id;
1846a6d42e7dSPeter Dunlap 	char		id_str[UUID_PRINTABLE_STRING_LENGTH];
1847a6d42e7dSPeter Dunlap 
1848a6d42e7dSPeter Dunlap 	uuid_generate_random(id);
1849a6d42e7dSPeter Dunlap 	uuid_unparse(id, id_str);
1850a6d42e7dSPeter Dunlap 
1851a6d42e7dSPeter Dunlap 	if (opt_iqn_suffix) {
1852*9fc69cd9SShampavman 		ret = snprintf(iqn_buf, iqn_buf_len, DEFAULT_IQN
1853a6d42e7dSPeter Dunlap 		    "%02d:%s.%s", TARGET_NAME_VERS, id_str, opt_iqn_suffix);
1854a6d42e7dSPeter Dunlap 	} else {
1855*9fc69cd9SShampavman 		ret = snprintf(iqn_buf, iqn_buf_len, DEFAULT_IQN
1856a6d42e7dSPeter Dunlap 		    "%02d:%s", TARGET_NAME_VERS, id_str);
1857a6d42e7dSPeter Dunlap 	}
1858a6d42e7dSPeter Dunlap 
1859a6d42e7dSPeter Dunlap 	if (ret > iqn_buf_len) {
1860a6d42e7dSPeter Dunlap 		return (1);
1861a6d42e7dSPeter Dunlap 	}
1862a6d42e7dSPeter Dunlap 
1863a6d42e7dSPeter Dunlap 	return (0);
1864a6d42e7dSPeter Dunlap }
1865a6d42e7dSPeter Dunlap 
1866a6d42e7dSPeter Dunlap static int
it_val_pass(char * name,char * val,nvlist_t * e)1867a6d42e7dSPeter Dunlap it_val_pass(char *name, char *val, nvlist_t *e)
1868a6d42e7dSPeter Dunlap {
1869a6d42e7dSPeter Dunlap 	size_t		sz;
1870a6d42e7dSPeter Dunlap 
1871a6d42e7dSPeter Dunlap 	if (!name || !val) {
1872a6d42e7dSPeter Dunlap 		return (EINVAL);
1873a6d42e7dSPeter Dunlap 	}
1874a6d42e7dSPeter Dunlap 
1875a6d42e7dSPeter Dunlap 	/*
1876a6d42e7dSPeter Dunlap 	 * must be at least 12 chars and less than 256 chars cleartext.
1877a6d42e7dSPeter Dunlap 	 */
1878a6d42e7dSPeter Dunlap 	sz = strlen(val);
1879a6d42e7dSPeter Dunlap 
1880a6d42e7dSPeter Dunlap 	/*
1881a6d42e7dSPeter Dunlap 	 * Since we will be automatically encoding secrets we don't really
1882a6d42e7dSPeter Dunlap 	 * need the prefix anymore.
1883a6d42e7dSPeter Dunlap 	 */
1884a6d42e7dSPeter Dunlap 	if (sz < 12) {
1885a6d42e7dSPeter Dunlap 		PROPERR(e, name, gettext("secret too short"));
1886a6d42e7dSPeter Dunlap 	} else if (sz > 255) {
1887a6d42e7dSPeter Dunlap 		PROPERR(e, name, gettext("secret too long"));
1888a6d42e7dSPeter Dunlap 	} else {
1889a6d42e7dSPeter Dunlap 		/* all is well */
1890a6d42e7dSPeter Dunlap 		return (0);
1891a6d42e7dSPeter Dunlap 	}
1892a6d42e7dSPeter Dunlap 
1893a6d42e7dSPeter Dunlap 	return (1);
1894a6d42e7dSPeter Dunlap }
1895a6d42e7dSPeter Dunlap 
1896a6d42e7dSPeter Dunlap /*
1897a6d42e7dSPeter Dunlap  * Function:  validate_iscsi_name()
1898a6d42e7dSPeter Dunlap  *
1899a6d42e7dSPeter Dunlap  * Ensures the passed-in string is a valid IQN or EUI iSCSI name
1900a6d42e7dSPeter Dunlap  *
1901a6d42e7dSPeter Dunlap  */
1902a6d42e7dSPeter Dunlap boolean_t
validate_iscsi_name(char * in_name)1903a6d42e7dSPeter Dunlap validate_iscsi_name(char *in_name)
1904a6d42e7dSPeter Dunlap {
1905a6d42e7dSPeter Dunlap 	size_t		in_len;
1906a6d42e7dSPeter Dunlap 	int		i;
1907a6d42e7dSPeter Dunlap 	char		month[3];
1908a6d42e7dSPeter Dunlap 
1909a6d42e7dSPeter Dunlap 	if (in_name == NULL) {
1910a6d42e7dSPeter Dunlap 		return (B_FALSE);
1911a6d42e7dSPeter Dunlap 	}
1912a6d42e7dSPeter Dunlap 
1913a6d42e7dSPeter Dunlap 	in_len = strlen(in_name);
1914a6d42e7dSPeter Dunlap 	if (in_len < 12) {
1915a6d42e7dSPeter Dunlap 		return (B_FALSE);
1916a6d42e7dSPeter Dunlap 	}
1917a6d42e7dSPeter Dunlap 
1918fcc214c3SCharles Ting 	if (IS_IQN_NAME(in_name)) {
1919a6d42e7dSPeter Dunlap 		/*
1920a6d42e7dSPeter Dunlap 		 * IQN names are iqn.yyyy-mm.<xxx>
1921a6d42e7dSPeter Dunlap 		 */
1922a6d42e7dSPeter Dunlap 		if ((!isdigit(in_name[4])) ||
1923a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[5])) ||
1924a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[6])) ||
1925a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[7])) ||
1926a6d42e7dSPeter Dunlap 		    (in_name[8] != '-') ||
1927a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[9])) ||
1928a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[10])) ||
1929a6d42e7dSPeter Dunlap 		    (in_name[11] != '.')) {
1930a6d42e7dSPeter Dunlap 			return (B_FALSE);
1931a6d42e7dSPeter Dunlap 		}
1932a6d42e7dSPeter Dunlap 
1933a6d42e7dSPeter Dunlap 		(void) strncpy(month, &(in_name[9]), 2);
1934a6d42e7dSPeter Dunlap 		month[2] = '\0';
1935a6d42e7dSPeter Dunlap 
1936a6d42e7dSPeter Dunlap 		i = atoi(month);
1937a6d42e7dSPeter Dunlap 		if ((i < 0) || (i > 12)) {
1938a6d42e7dSPeter Dunlap 			return (B_FALSE);
1939a6d42e7dSPeter Dunlap 		}
1940a6d42e7dSPeter Dunlap 
1941836fc322SSam Cramer 		/*
1942836fc322SSam Cramer 		 * RFC 3722: if using only ASCII chars, only the following
1943836fc322SSam Cramer 		 * chars are allowed: dash, dot, colon, lower case a-z, 0-9.
1944836fc322SSam Cramer 		 * We allow upper case names, which should be folded
1945836fc322SSam Cramer 		 * to lower case names later.
1946836fc322SSam Cramer 		 */
1947836fc322SSam Cramer 		for (i = 12; i < in_len; i++) {
1948836fc322SSam Cramer 			char c = in_name[i];
1949836fc322SSam Cramer 
1950836fc322SSam Cramer 			if ((c != '-') && (c != '.') && (c != ':') &&
1951836fc322SSam Cramer 			    !isalpha(c) && !isdigit(c)) {
1952836fc322SSam Cramer 				return (B_FALSE);
1953836fc322SSam Cramer 			}
1954836fc322SSam Cramer 		}
1955836fc322SSam Cramer 
1956a6d42e7dSPeter Dunlap 		/* Finally, validate the overall length, in wide chars */
1957a6d42e7dSPeter Dunlap 		in_len = mbstowcs(NULL, in_name, 0);
1958a6d42e7dSPeter Dunlap 		if (in_len > ISCSI_NAME_LEN_MAX) {
1959a6d42e7dSPeter Dunlap 			return (B_FALSE);
1960a6d42e7dSPeter Dunlap 		}
1961fcc214c3SCharles Ting 	} else if (IS_EUI_NAME(in_name)) {
1962a6d42e7dSPeter Dunlap 		/*
1963a6d42e7dSPeter Dunlap 		 * EUI names are "eui." + 16 hex chars
1964a6d42e7dSPeter Dunlap 		 */
1965a6d42e7dSPeter Dunlap 		if (in_len != 20) {
1966a6d42e7dSPeter Dunlap 			return (B_FALSE);
1967a6d42e7dSPeter Dunlap 		}
1968a6d42e7dSPeter Dunlap 
1969a6d42e7dSPeter Dunlap 		for (i = 4; i < in_len; i++) {
1970a6d42e7dSPeter Dunlap 			if (!isxdigit(in_name[i])) {
1971a6d42e7dSPeter Dunlap 				return (B_FALSE);
1972a6d42e7dSPeter Dunlap 			}
1973a6d42e7dSPeter Dunlap 		}
1974a6d42e7dSPeter Dunlap 	} else {
1975a6d42e7dSPeter Dunlap 		return (B_FALSE);
1976a6d42e7dSPeter Dunlap 	}
1977a6d42e7dSPeter Dunlap 
1978a6d42e7dSPeter Dunlap 	return (B_TRUE);
1979a6d42e7dSPeter Dunlap }
19805de03f84SSue Gleeson 
19815de03f84SSue Gleeson static boolean_t
is_iscsit_enabled(void)19825de03f84SSue Gleeson is_iscsit_enabled(void)
19835de03f84SSue Gleeson {
19845de03f84SSue Gleeson 	char		*state;
19855de03f84SSue Gleeson 
19865de03f84SSue Gleeson 	state = smf_get_state(ISCSIT_FMRI);
19875de03f84SSue Gleeson 	if (state != NULL) {
19885de03f84SSue Gleeson 		if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) {
198923d7d581SPeter Gill 			free(state);
19905de03f84SSue Gleeson 			return (B_TRUE);
19915de03f84SSue Gleeson 		}
19924f1fc35dSsrivijitha dugganapalli 		free(state);
19935de03f84SSue Gleeson 	}
19945de03f84SSue Gleeson 
19955de03f84SSue Gleeson 	return (B_FALSE);
19965de03f84SSue Gleeson }
1997fcc214c3SCharles Ting 
1998fcc214c3SCharles Ting /*
1999fcc214c3SCharles Ting  * Function:  canonical_iscsi_name()
2000fcc214c3SCharles Ting  *
2001fcc214c3SCharles Ting  * Fold the iqn iscsi name to lower-case and the EUI-64 identifier of
2002fcc214c3SCharles Ting  * the eui iscsi name to upper-case.
2003fcc214c3SCharles Ting  * Ensures the passed-in string is a valid IQN or EUI iSCSI name
2004fcc214c3SCharles Ting  */
2005fcc214c3SCharles Ting void
canonical_iscsi_name(char * tgt)2006fcc214c3SCharles Ting canonical_iscsi_name(char *tgt)
2007fcc214c3SCharles Ting {
2008fcc214c3SCharles Ting 	if (IS_IQN_NAME(tgt)) {
2009fcc214c3SCharles Ting 		/* lowercase iqn names */
2010fcc214c3SCharles Ting 		iqnstr(tgt);
2011fcc214c3SCharles Ting 	} else {
2012fcc214c3SCharles Ting 		/* uppercase EUI-64 identifier */
2013fcc214c3SCharles Ting 		euistr(tgt);
2014fcc214c3SCharles Ting 	}
2015fcc214c3SCharles Ting }
2016fcc214c3SCharles Ting 
2017fcc214c3SCharles Ting /*
2018fcc214c3SCharles Ting  * Fold an iqn name to lower-case.
2019fcc214c3SCharles Ting  */
2020fcc214c3SCharles Ting static void
iqnstr(char * s)2021fcc214c3SCharles Ting iqnstr(char *s)
2022fcc214c3SCharles Ting {
2023fcc214c3SCharles Ting 	if (s != NULL) {
2024fcc214c3SCharles Ting 		while (*s) {
2025fcc214c3SCharles Ting 			*s = tolower(*s);
2026fcc214c3SCharles Ting 			s++;
2027fcc214c3SCharles Ting 		}
2028fcc214c3SCharles Ting 	}
2029fcc214c3SCharles Ting }
2030fcc214c3SCharles Ting 
2031fcc214c3SCharles Ting /*
2032fcc214c3SCharles Ting  * Fold the EUI-64 identifier of a eui name to upper-case.
2033fcc214c3SCharles Ting  */
2034fcc214c3SCharles Ting static void
euistr(char * s)2035fcc214c3SCharles Ting euistr(char *s)
2036fcc214c3SCharles Ting {
2037fcc214c3SCharles Ting 	if (s != NULL) {
2038fcc214c3SCharles Ting 		char *l = s + 4;
2039fcc214c3SCharles Ting 		while (*l) {
2040fcc214c3SCharles Ting 			*l = toupper(*l);
2041fcc214c3SCharles Ting 			l++;
2042fcc214c3SCharles Ting 		}
2043fcc214c3SCharles Ting 	}
2044fcc214c3SCharles Ting }
2045