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