libiscsit.c revision 836fc322d4b4884a4c64c7b5d172a4a3bb6a5772
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <libintl.h>
#include <libstmf.h>
#include <libiscsit.h>
#include <sys/iscsi_protocol.h>
/* From iscsitgtd */
#define TARGET_NAME_VERS 2
/* this should be defined someplace central... */
#define ISCSI_NAME_LEN_MAX 223
/* max length of a base64 encoded secret */
#define MAX_BASE64_LEN 341
/* Default RADIUS server port */
#define DEFAULT_RADIUS_PORT 1812
/*
* The kernel reserves target portal group tag value 1 as the default.
*/
#define ISCSIT_DEFAULT_TPGT 1
#define MAXTAG 0xffff
/* helper for property list validation */
if (lst) { \
} \
}
/* helper function declarations */
static int
static int
/* consider making validate funcs public */
static int
static int
static int
/*
* Function: it_config_load()
*
* Allocate and create an it_config_t structure representing the
* current iSCSI configuration. This structure is compiled using
* the 'provider' data returned by stmfGetProviderData(). If there
* is no provider data associated with iscsit, the it_config_t
* structure will be set to a default configuration.
*
* Parameters:
* cfg A C representation of the current iSCSI configuration
*
* Return Values:
* 0 Success
* ENOMEM Could not allocate resources
* EINVAL Invalid parameter
*/
int
{
int ret = 0;
uint64_t stmf_token = 0;
if (!cfg) {
return (EINVAL);
}
if ((ret == STMF_STATUS_SUCCESS) ||
(ret == STMF_ERROR_NOT_FOUND)) {
/*
* If not initialized yet, return empty it_config_t
* Else, convert nvlist to struct
*/
}
if (ret == 0) {
}
return (ret);
}
/*
* Function: it_config_commit()
*
* Informs the iscsit service that the configuration has changed and
* commits the new configuration to persistent store by calling
* stmfSetProviderData. This function can be called multiple times
* during a configuration sequence if necessary.
*
* Parameters:
* cfg A C representation of the current iSCSI configuration
*
* Return Values:
* 0 Success
* ENOMEM Could not allocate resources
* EINVAL Invalid it_config_t structure
* TBD ioctl() failed
* TBD could not save config to STMF
*/
int
{
int ret;
int iscsit_fd = -1;
if (!cfg) {
return (EINVAL);
}
if (iscsit_fd == -1) {
return (ret);
}
if (ret == 0) {
}
if (ret == 0) {
if (!packednv) {
} else {
NV_ENCODE_NATIVE, 0);
}
}
/*
* Send the changes to the kernel first, for now. Kernel
* will be the final sanity check before config is saved
* persistently.
*
* XXX - this leaves open the simultaneous-change hole
* that STMF was trying to solve, but is a better sanity
* number TBD.
*/
if (ret == 0) {
}
}
/*
* Before saving the config persistently, remove any
* PROP_OLD_TARGET_NAME entries. This is only interesting to
* the active service.
*/
if (ret == 0) {
if (!tgtp->tgt_properties) {
continue;
}
}
}
}
/*
* stmfGetProviderDataProt() checks to ensure
* that the config data hasn't changed since we fetched it.
*
* The kernel now has a version we need to save persistently.
* CLI will 'do the right thing' and warn the user if it
* gets STMF_ERROR_PROV_DATA_STALE. We'll try once to revert
* the kernel to the persistently saved data, but ultimately,
* it's up to the administrator to validate things are as they
* want them to be.
*/
if (ret == 0) {
if (ret == STMF_STATUS_SUCCESS) {
ret = 0;
} else if (ret == STMF_ERROR_NOMEM) {
} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
int st;
if (st == 0) {
(void) it_config_commit(rcfg);
}
}
}
if (packednv) {
}
if (cfgnv) {
}
return (ret);
}
/*
* Function: it_config_setprop()
*
* Validate the provided property list and set the global properties
* for iSCSI Target. If errlist is not NULL, returns detailed
* errors for each property that failed. The format for errorlist
* is key = property, value = error string.
*
* Parameters:
*
* cfg The current iSCSI configuration obtained from
* it_config_load()
* proplist nvlist_t containing properties for this target.
* errlist (optional) nvlist_t of errors encountered when
* validating the properties.
*
* Return Values:
* 0 Success
* EINVAL Invalid property
*
*/
int
{
int ret;
char **arr;
return (EINVAL);
}
if (errlist) {
(void) nvlist_alloc(errlist, 0, 0);
}
/*
* copy the existing properties, merge, then validate
* the merged properties before committing them.
*/
if (cfg->config_global_properties) {
} else {
}
/* base64 encode the radius secret, if it's changed */
if (val) {
char bsecret[MAX_BASE64_LEN];
if (ret == 0) {
if (ret == 0) {
/* replace the value in the nvlist */
}
}
}
if (ret == 0) {
}
/* see if we need to remove the radius server setting */
}
}
if (ret == 0) {
}
if (ret != 0) {
if (cprops) {
}
return (ret);
}
/*
* Update iSNS server list, if exists in provided property list.
*/
if (ret == 0) {
/* special case: if "none", remove all defined */
} else {
newisnslist = NULL;
newcount = 0;
}
if (ret == 0) {
while (isns) {
}
/*
* Replace the array in the nvlist to ensure
* duplicates are properly removed & port numbers
* are added.
*/
if (newcount > 0) {
int i = 0;
char **newarray;
} else {
(void) sockaddr_to_str(
&(isns->portal_addr),
&(newarray[i++]));
}
(void) nvlist_add_string_array(cprops,
newcount);
for (i = 0; i < newcount; i++) {
if (newarray[i]) {
}
}
}
}
}
/* not an error */
ret = 0;
}
if (ret == 0) {
/* replace the global properties list */
} else {
if (cprops) {
}
}
return (ret);
}
/*
* Function: it_config_free()
*
* Free any resources associated with the it_config_t structure.
*
* Parameters:
* cfg A C representation of the current iSCSI configuration
*/
void
{
}
/*
* Function: it_tgt_create()
*
* Allocate and create an it_tgt_t structure representing a new iSCSI
* target node. If tgt_name is NULL, then a unique target node name will
* be generated automatically. Otherwise, the value of tgt_name will be
* used as the target node name. The new it_tgt_t structure is added to
* the target list (cfg_tgt_list) in the configuration structure, and the
* new target will not be instantiated until the modified configuration
* is committed by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configuration obtained from
* it_config_load()
* tgt Pointer to an iSCSI target structure
* tgt_name The target node name for the target to be created.
* The name must be in either IQN or EUI format. If
* this value is NULL, a node name will be generated
* automatically in IQN format.
*
* Return Values:
* 0 Success
* ENOMEM Could not allocated resources
* EINVAL Invalid parameter
* EFAULT Invalid iSCSI name specified
* E2BIG Too many already exist
*/
int
{
int ret = 0;
return (EINVAL);
}
if (!namep) {
/* generate a name */
if (ret != 0) {
return (ret);
}
} else {
/* validate the passed-in name */
if (!validate_iscsi_name(namep)) {
return (EFAULT);
}
}
/* Too many targets? */
return (E2BIG);
}
/* make sure this name isn't already on the list */
return (EEXIST);
}
}
return (ENOMEM);
}
cfg->config_tgt_count++;
return (0);
}
/*
* Function: it_tgt_setprop()
*
* Validate the provided property list and set the properties for
* the specified target. If errlist is not NULL, returns detailed
* errors for each property that failed. The format for errorlist
* is key = property, value = error string.
*
* Parameters:
*
* cfg The current iSCSI configuration obtained from
* it_config_load()
* tgt Pointer to an iSCSI target structure
* proplist nvlist_t containing properties for this target.
* errlist (optional) nvlist_t of errors encountered when
* validating the properties.
*
* Return Values:
* 0 Success
* EINVAL Invalid property
*
*/
int
{
int ret;
return (EINVAL);
}
if (errlist) {
(void) nvlist_alloc(errlist, 0, 0);
}
/*
* copy the existing properties, merge, then validate
* the merged properties before committing them.
*/
if (tgt->tgt_properties) {
} else {
}
if (ret == 0) {
}
/* unset chap username or alias if requested */
}
}
/* base64 encode the CHAP secret, if it's changed */
if (val) {
char bsecret[MAX_BASE64_LEN];
if (ret == 0) {
if (ret == 0) {
/* replace the value in the nvlist */
}
}
}
if (ret == 0) {
}
if (ret != 0) {
if (tprops) {
}
return (ret);
}
if (tgt->tgt_properties) {
}
return (0);
}
/*
* Function: it_tgt_delete()
*
* Delete target represented by 'tgt', where 'tgt' is an existing
* it_tgt_structure within the configuration 'cfg'. The target removal
* will not take effect until the modified configuration is committed
* by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configuration obtained from
* it_config_load()
* tgt Pointer to an iSCSI target structure
*
* force Set the target to offline before removing it from
* the config. If not specified, the operation will
* fail if the target is determined to be online.
* Return Values:
* 0 Success
* EBUSY Target is online
*/
int
{
int ret;
return (0);
}
break;
}
}
if (!ptgt) {
return (0);
}
/*
* check to see if this target is offline. If it is not,
* and the 'force' flag is TRUE, tell STMF to offline it
* before removing from the configuration.
*/
if (ret != STMF_STATUS_SUCCESS) {
/* can't happen? */
return (EINVAL);
}
if (ret == STMF_STATUS_SUCCESS) {
/*
* only other return is STMF_ERROR_NOT_FOUND, which
* means we don't have to offline it.
*/
if (!force) {
return (EBUSY);
}
if (ret != 0) {
return (EBUSY);
}
}
}
if (prev) {
} else {
/* first one on the list */
}
cfg->config_tgt_count--;
return (0);
}
/*
* Function: it_tgt_free()
*
* Frees an it_tgt_t structure. If tgt_next is not NULL, frees
* all structures in the list.
*/
void
{
}
/*
* Function: it_tpgt_create()
*
* Allocate and create an it_tpgt_t structure representing a new iSCSI
* target portal group tag. The new it_tpgt_t structure is added to the
* target tpgt list (tgt_tpgt_list) in the it_tgt_t structure. The new
* target portal group tag will not be instantiated until the modified
* configuration is committed by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configuration obtained from
* it_config_load()
* tgt Pointer to the iSCSI target structure associated
* with the target portal group tag
* tpgt Pointer to a target portal group tag structure
* tpg_name The name of the TPG to be associated with this TPGT
* tpgt_tag 16-bit numerical identifier for this TPGT. If
* tpgt_tag is '0', this function will choose the
* tag number. If tpgt_tag is >0, and the requested
* tag is determined to be in use, another value
* will be chosen.
*
* Return Values:
* 0 Success
* ENOMEM Could not allocate resources
* EINVAL Invalid parameter
* EEXIST Specified tag name is already used.
* E2BIG No available tag numbers
*/
int
{
return (EINVAL);
}
/*
* At the same time, capture all tag ids in use for this target
*
* About tag numbering -- since tag numbers are used by
* the iSCSI protocol, we should be careful about reusing
* them too quickly. Start with a value greater than the
* highest one currently defined. If current == MAXTAG,
* just find an unused tag.
*/
return (EEXIST);
}
}
}
(tagid_used[tpgt_tag] == 0)) {
/* ok to use requested */
/*
* The highest value is used, find an available id.
*/
if (tagid_used[tagid] == 0) {
break;
}
}
return (E2BIG);
}
} else {
/* next available ID */
tagid++;
}
if (!ptr) {
return (ENOMEM);
}
sizeof (ptr->tpgt_tpg_name));
tgt->tgt_tpgt_count++;
tgt->tgt_generation++;
return (0);
}
/*
* Function: it_tpgt_delete()
*
* Delete the target portal group tag represented by 'tpgt', where
* 'tpgt' is an existing is_tpgt_t structure within the target 'tgt'.
* The target portal group tag removal will not take effect until the
* modified configuration is committed by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configuration obtained from
* it_config_load()
* tgt Pointer to the iSCSI target structure associated
* with the target portal group tag
* tpgt Pointer to a target portal group tag structure
*/
void
{
return;
}
while (ptr) {
break;
}
}
if (!ptr) {
return;
}
if (prev) {
} else {
}
tgt->tgt_tpgt_count--;
tgt->tgt_generation++;
}
/*
* Function: it_tpgt_free()
*
* Deallocates resources of an it_tpgt_t structure. If tpgt->next
* is not NULL, frees all members of the list.
*/
void
{
}
/*
* Function: it_tpg_create()
*
* Allocate and create an it_tpg_t structure representing a new iSCSI
* target portal group. The new it_tpg_t structure is added to the global
* tpg list (cfg_tgt_list) in the it_config_t structure. The new target
* portal group will not be instantiated until the modified configuration
* is committed by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configuration obtained from
* it_config_load()
* tpg Pointer to the it_tpg_t structure representing
* the target portal group
* tpg_name Identifier for the target portal group
* portal_ip_port A string containing an appropriatedly formatted
* IP address:port. Both IPv4 and IPv6 addresses are
* permitted. This value becomes the first portal in
* the TPG -- applications can add additional values
* using it_portal_create() before committing the TPG.
* Return Values:
* 0 Success
* ENOMEM Cannot allocate resources
* EINVAL Invalid parameter
* EEXIST Requested portal in use by another target portal
* group
*/
int
char *portal_ip_port)
{
int ret;
return (EINVAL);
}
while (ptr) {
break;
}
}
if (ptr) {
return (EEXIST);
}
if (!ptr) {
return (ENOMEM);
}
/* create the portal */
if (ret != 0) {
return (ret);
}
cfg->config_tpg_count++;
return (0);
}
/*
* Function: it_tpg_delete()
*
* Delete target portal group represented by 'tpg', where 'tpg' is an
* existing it_tpg_t structure within the global configuration 'cfg'.
* The target portal group removal will not take effect until the
* modified configuration is committed by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configuration obtained from
* it_config_load()
* tpg Pointer to the it_tpg_t structure representing
* the target portal group
* force Remove this target portal group even if it's
* associated with one or more targets.
*
* Return Values:
* 0 Success
* EINVAL Invalid parameter
* EBUSY Portal group associated with one or more targets.
*/
int
{
return (EINVAL);
}
while (ptr) {
break;
}
}
if (!ptr) {
return (0);
}
/*
* See if any targets are using this portal group.
* If there are, and the force flag is not set, fail.
*/
while (tgt) {
while (tpgt) {
== 0) {
if (!force) {
return (EBUSY);
}
}
}
}
/* Now that it's not in use anywhere, remove the TPG */
if (prev) {
} else {
}
cfg->config_tpg_count--;
return (0);
}
/*
* Function: it_tpg_free()
*
* Deallocates resources associated with an it_tpg_t structure.
* If tpg->next is not NULL, frees all members of the list.
*/
void
{
}
/*
* Function: it_portal_create()
*
* Add an it_portal_t structure presenting a new portal to the specified
* target portal group. The change to the target portal group will not take
* effect until the modified configuration is committed by calling
* it_config_commit().
*
* Parameters:
* cfg The current iSCSI configration obtained from
* it_config_load()
* tpg Pointer to the it_tpg_t structure representing the
* target portal group
* portal Pointer to the it_portal_t structure representing
* the portal
* portal_ip_port A string containing an appropriately formatted
* IP address or IP address:port in either IPv4 or
* IPv6 format.
* Return Values:
* 0 Success
* ENOMEM Could not allocate resources
* EINVAL Invalid parameter
* EEXIST Portal already configured for another portal group
*/
int
char *portal_ip_port)
{
struct sockaddr_storage sa;
return (EINVAL);
}
== NULL) {
return (EINVAL);
}
/* Check that this portal doesn't appear in any other tag */
while (ctpg) {
continue;
}
/*
* Existing in the same group is not an error,
* but don't add it again.
*/
return (0);
} else {
/* Not allowed */
return (EEXIST);
}
}
}
if (!ptr) {
return (ENOMEM);
}
sizeof (struct sockaddr_storage));
tpg->tpg_portal_count++;
tpg->tpg_generation++;
return (0);
}
/*
* Function: it_portal_delete()
*
* Remove the specified portal from the specified target portal group.
* The portal removal will not take effect until the modified configuration
* is committed by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configration obtained from
* it_config_load()
* tpg Pointer to the it_tpg_t structure representing the
* target portal group
* portal Pointer to the it_portal_t structure representing
* the portal
*/
void
{
return;
}
while (ptr) {
sizeof (ptr->portal_addr)) == 0) {
break;
}
}
if (!ptr) {
return;
}
if (prev) {
} else {
}
tpg->tpg_portal_count--;
tpg->tpg_generation++;
}
/*
* Function: it_ini_create()
*
* Add an initiator context to the global configuration. The new
* initiator context will not be instantiated until the modified
* configuration is committed by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configration obtained from
* it_config_load()
* ini Pointer to the it_ini_t structure representing
* the initiator context.
* ini_node_name The iSCSI node name of the remote initiator.
*
* Return Values:
* 0 Success
* ENOMEM Could not allocate resources
* EINVAL Invalid parameter.
* EFAULT Invalid initiator name
*/
int
{
return (EINVAL);
}
/*
* Ensure this is a valid ini name
*/
if (!validate_iscsi_name(ini_node_name)) {
return (EFAULT);
}
while (ptr) {
break;
}
}
if (ptr) {
return (EEXIST);
}
if (!ptr) {
return (ENOMEM);
}
/* nvlist for props? */
cfg->config_ini_count++;
return (0);
}
/*
* Function: it_ini_setprop()
*
* Validate the provided property list and set the initiator properties.
* If errlist is not NULL, returns detailed errors for each property
* that failed. The format for errorlist is key = property,
* value = error string.
*
* Parameters:
*
* ini The initiator being updated.
* proplist nvlist_t containing properties for this target.
* errlist (optional) nvlist_t of errors encountered when
* validating the properties.
*
* Return Values:
* 0 Success
* EINVAL Invalid property
*
*/
int
{
int ret;
return (EINVAL);
}
if (errlist) {
(void) nvlist_alloc(errlist, 0, 0);
}
/*
* copy the existing properties, merge, then validate
* the merged properties before committing them.
*/
if (ini->ini_properties) {
} else {
}
if (ret == 0) {
}
/* unset chap username if requested */
}
}
/* base64 encode the CHAP secret, if it's changed */
char bsecret[MAX_BASE64_LEN];
if (ret == 0) {
if (ret == 0) {
/* replace the value in the nvlist */
}
}
}
if (ret == 0) {
}
if (ret != 0) {
if (iprops) {
}
return (ret);
}
if (ini->ini_properties) {
}
return (0);
}
/*
* Function: it_ini_delete()
*
* Remove the specified initiator context from the global configuration.
* The removal will not take effect until the modified configuration is
* committed by calling it_config_commit().
*
* Parameters:
* cfg The current iSCSI configration obtained from
* it_config_load()
* ini Pointer to the it_ini_t structure representing
* the initiator context.
*/
void
{
return;
}
while (ptr) {
break;
}
}
if (!ptr) {
return;
}
if (prev) {
} else {
}
cfg->config_ini_count--;
}
/*
* Function: it_ini_free()
*
* Deallocates resources of an it_ini_t structure. If ini->next is
* not NULL, frees all members of the list.
*/
void
{
}
/*
* Goes through the target property list and validates
* each entry. If errs is non-NULL, will return explicit errors
* for each property that fails validation.
*/
static int
{
int errcnt = 0;
char *name;
char *val;
if (!nvl) {
return (0);
}
if (!name) {
continue;
}
if (nvtype != DATA_TYPE_STRING) {
gettext("must be a string value"));
errcnt++;
continue;
}
/*
* must be between 12 and 255 chars in cleartext.
* will be base64 encoded when it's set.
*/
if (nvtype == DATA_TYPE_STRING) {
}
if (!val) {
gettext("must be a string value"));
errcnt++;
continue;
}
if (nvtype != DATA_TYPE_STRING) {
gettext("must be a string value"));
errcnt++;
continue;
}
if (nvtype == DATA_TYPE_STRING) {
}
if (!val) {
gettext("must be a string value"));
errcnt++;
continue;
}
"must be none, chap, radius or default"));
errcnt++;
}
continue;
continue;
} else {
/* unrecognized property */
errcnt++;
}
}
if (errcnt) {
return (EINVAL);
}
/* if auth is being set to default, remove from this nvlist */
}
return (0);
}
/*
* Goes through the config property list and validates
* each entry. If errs is non-NULL, will return explicit errors
* for each property that fails validation.
*/
static int
{
int errcnt = 0;
char *name;
char *val;
struct sockaddr_storage sa;
char *rad_server;
if (!nvl) {
return (0);
}
if (!name) {
continue;
}
/* prefetch string value as we mostly need it */
if (nvtype == DATA_TYPE_STRING) {
}
if (!val) {
gettext("must be a string value"));
errcnt++;
}
if (!val) {
gettext("must be a string value"));
errcnt++;
continue;
}
gettext("must be none, chap or radius"));
errcnt++;
}
if (nvtype != DATA_TYPE_BOOLEAN_VALUE) {
gettext("must be a boolean value"));
errcnt++;
}
while (acount > 0) {
break;
}
gettext("invalid address"));
errcnt++;
}
acount--;
}
if (!val) {
gettext("must be a string value"));
errcnt++;
continue;
}
struct sockaddr_storage sa;
if (!val) {
gettext("must be a string value"));
errcnt++;
continue;
}
DEFAULT_RADIUS_PORT)) == NULL) {
gettext("invalid address"));
errcnt++;
} else {
/*
* rewrite this property to ensure port
* number is added.
*/
}
}
} else {
/* unrecognized property */
errcnt++;
}
}
/*
* If we successfully reformatted the radius server to add the port
* number then update the nvlist
*/
if (update_rad_server) {
}
/*
* if auth = radius, ensure radius server & secret are set.
*/
if (auth) {
/* need server & secret for radius */
gettext("missing required property"));
errcnt++;
}
gettext("missing required property"));
errcnt++;
}
}
}
if (errcnt) {
return (EINVAL);
}
return (0);
}
/*
* Goes through the ini property list and validates
* each entry. If errs is non-NULL, will return explicit errors
* for each property that fails validation.
*/
static int
{
int errcnt = 0;
char *name;
char *val;
if (!nvl) {
return (0);
}
if (!name) {
continue;
}
if (nvtype != DATA_TYPE_STRING) {
gettext("must be a string value"));
errcnt++;
continue;
}
/*
* must be between 12 and 255 chars in cleartext.
* will be base64 encoded when it's set.
*/
if (nvtype == DATA_TYPE_STRING) {
}
if (!val) {
gettext("must be a string value"));
errcnt++;
continue;
}
} else {
/* unrecognized property */
errcnt++;
}
}
if (errcnt) {
return (EINVAL);
}
return (0);
}
static int
{
int ret;
if (opt_iqn_suffix) {
} else {
}
if (ret > iqn_buf_len) {
return (1);
}
return (0);
}
static int
{
return (EINVAL);
}
/*
* must be at least 12 chars and less than 256 chars cleartext.
*/
/*
* Since we will be automatically encoding secrets we don't really
* need the prefix anymore.
*/
if (sz < 12) {
} else if (sz > 255) {
} else {
/* all is well */
return (0);
}
return (1);
}
/*
* Function: validate_iscsi_name()
*
* Ensures the passed-in string is a valid IQN or EUI iSCSI name
*
*/
validate_iscsi_name(char *in_name)
{
int i;
char month[3];
return (B_FALSE);
}
if (in_len < 12) {
return (B_FALSE);
}
/*
* IQN names are iqn.yyyy-mm.<xxx>
*/
return (B_FALSE);
}
if ((i < 0) || (i > 12)) {
return (B_FALSE);
}
/*
* RFC 3722: if using only ASCII chars, only the following
* chars are allowed: dash, dot, colon, lower case a-z, 0-9.
* We allow upper case names, which should be folded
* to lower case names later.
*/
for (i = 12; i < in_len; i++) {
char c = in_name[i];
if ((c != '-') && (c != '.') && (c != ':') &&
return (B_FALSE);
}
}
/* Finally, validate the overall length, in wide chars */
if (in_len > ISCSI_NAME_LEN_MAX) {
return (B_FALSE);
}
/*
* EUI names are "eui." + 16 hex chars
*/
if (in_len != 20) {
return (B_FALSE);
}
for (i = 4; i < in_len; i++) {
return (B_FALSE);
}
}
} else {
return (B_FALSE);
}
return (B_TRUE);
}