summaryrefslogtreecommitdiff
path: root/usr/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/common')
-rw-r--r--usr/src/common/cmdparse/cmdparse.c681
-rw-r--r--usr/src/common/cmdparse/cmdparse.h222
-rw-r--r--usr/src/common/iscsi/base64.c255
-rw-r--r--usr/src/common/iscsit/iscsit_common.c1588
4 files changed, 2746 insertions, 0 deletions
diff --git a/usr/src/common/cmdparse/cmdparse.c b/usr/src/common/cmdparse/cmdparse.c
new file mode 100644
index 0000000..7a9e575
--- /dev/null
+++ b/usr/src/common/cmdparse/cmdparse.c
@@ -0,0 +1,681 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <cmdparse.h>
+
+
+/* Usage types */
+#define GENERAL_USAGE 1
+#define DETAIL_USAGE 2
+
+/* printable ascii character set len */
+#define MAXOPTIONS (uint_t)('~' - '!' + 1)
+
+/*
+ * MAXOPTIONSTRING is the max length of the options string used in getopt and
+ * will be the printable character set + ':' for each character,
+ * providing for options with arguments. e.g. "t:Cs:hglr:"
+ */
+#define MAXOPTIONSTRING MAXOPTIONS * 2
+
+/* standard command options table to support -?, -V */
+struct option standardCmdOptions[] = {
+ {"help", no_argument, NULL, '?'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+/* standard subcommand options table to support -? */
+struct option standardSubCmdOptions[] = {
+ {"help", no_argument, NULL, '?'},
+ {NULL, 0, NULL, 0}
+};
+
+/* forward declarations */
+static int getSubcommandProps(char *, subCommandProps_t **);
+static char *getExecBasename(char *);
+static void usage(uint_t);
+static void subUsage(uint_t, subCommandProps_t *);
+static char *getLongOption(int);
+static char *getOptionArgDesc(int);
+
+/* global data */
+static struct option *_longOptions;
+static subCommandProps_t *_subCommandProps;
+static optionTbl_t *_clientOptionTbl;
+static char *commandName;
+
+
+/*
+ * input:
+ * subCommand - subcommand value
+ * output:
+ * subCommandProps - pointer to subCommandProps_t structure allocated by caller
+ *
+ * On successful return, subCommandProps contains the properties for the value
+ * in subCommand. On failure, the contents of subCommandProps is unspecified.
+ *
+ * Returns:
+ * zero on success
+ * non-zero on failure
+ *
+ */
+static int
+getSubcommandProps(char *subCommand, subCommandProps_t **subCommandProps)
+{
+ subCommandProps_t *sp;
+ int len;
+
+ for (sp = _subCommandProps; sp->name; sp++) {
+ len = strlen(subCommand);
+ if (len == strlen(sp->name) &&
+ strncasecmp(subCommand, sp->name, len) == 0) {
+ *subCommandProps = sp;
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * input:
+ * shortOption - short option character for which to return the
+ * associated long option string
+ *
+ * Returns:
+ * on success, long option name
+ * on failure, NULL
+ */
+static char *
+getLongOption(int shortOption)
+{
+ struct option *op;
+ for (op = _longOptions; op->name; op++) {
+ if (shortOption == op->val) {
+ return (op->name);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * input
+ * shortOption - short option character for which to return the
+ * option argument
+ * Returns:
+ * on success, argument string
+ * on failure, NULL
+ */
+static char *
+getOptionArgDesc(int shortOption)
+{
+ optionTbl_t *op;
+ for (op = _clientOptionTbl; op->name; op++) {
+ if (op->val == shortOption &&
+ op->has_arg == required_argument) {
+ return (op->argDesc);
+ }
+ }
+ return (NULL);
+}
+
+
+/*
+ * Print usage for a subcommand.
+ *
+ * input:
+ * usage type - GENERAL_USAGE, DETAIL_USAGE
+ * subcommand - pointer to subCommandProps_t structure
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+subUsage(uint_t usageType, subCommandProps_t *subcommand)
+{
+ int i;
+ char *optionArgDesc;
+ char *longOpt;
+
+ if (usageType == GENERAL_USAGE) {
+ (void) printf("%s:\t%s %s [", gettext("Usage"), commandName,
+ subcommand->name);
+ for (i = 0; standardSubCmdOptions[i].name; i++) {
+ (void) printf("-%c", standardSubCmdOptions[i].val);
+ if (standardSubCmdOptions[i+1].name)
+ (void) printf(",");
+ }
+ (void) fprintf(stdout, "]\n");
+ return;
+ }
+
+ /* print subcommand usage */
+ (void) printf("\n%s:\t%s %s ", gettext("Usage"), commandName,
+ subcommand->name);
+
+ /* print options if applicable */
+ if (subcommand->optionString != NULL) {
+ if (subcommand->required) {
+ (void) printf("%s", gettext("<"));
+ } else {
+ (void) printf("%s", gettext("["));
+ }
+ (void) printf("%s", gettext("OPTIONS"));
+ if (subcommand->required) {
+ (void) printf("%s ", gettext(">"));
+ } else {
+ (void) printf("%s ", gettext("]"));
+ }
+ }
+
+ /* print operand requirements */
+ if (!(subcommand->operand & OPERAND_NONE) &&
+ !(subcommand->operand & OPERAND_MANDATORY)) {
+ (void) printf(gettext("["));
+ }
+
+ if (subcommand->operand & OPERAND_MANDATORY) {
+ (void) printf(gettext("<"));
+ }
+
+ if (!(subcommand->operand & OPERAND_NONE)) {
+ assert(subcommand->operandDefinition);
+ (void) printf("%s", subcommand->operandDefinition);
+ }
+
+ if (subcommand->operand & OPERAND_MULTIPLE) {
+ (void) printf(gettext(" ..."));
+ }
+
+ if (subcommand->operand & OPERAND_MANDATORY) {
+ (void) printf(gettext(">"));
+ }
+
+ if (!(subcommand->operand & OPERAND_NONE) &&
+ !(subcommand->operand & OPERAND_MANDATORY)) {
+ (void) printf(gettext("]"));
+ }
+
+ /* print options for subcommand */
+ if (subcommand->optionString != NULL) {
+ (void) printf("\n\t%s:", gettext("OPTIONS"));
+ for (i = 0; i < strlen(subcommand->optionString); i++) {
+ assert((longOpt = getLongOption(
+ subcommand->optionString[i])) != NULL);
+ (void) printf("\n\t\t-%c, --%s ",
+ subcommand->optionString[i],
+ longOpt);
+ optionArgDesc =
+ getOptionArgDesc(subcommand->optionString[i]);
+ if (optionArgDesc != NULL) {
+ (void) printf("<%s>", optionArgDesc);
+ }
+ if (subcommand->exclusive &&
+ strchr(subcommand->exclusive,
+ subcommand->optionString[i])) {
+ (void) printf(" (%s)", gettext("exclusive"));
+ }
+ }
+ }
+ (void) fprintf(stdout, "\n");
+ if (subcommand->helpText) {
+ (void) printf("%s\n", subcommand->helpText);
+ }
+}
+
+/*
+ * input:
+ * type of usage statement to print
+ *
+ * Returns:
+ * return value of subUsage
+ */
+static void
+usage(uint_t usageType)
+{
+ int i;
+ subCommandProps_t *sp;
+
+ /* print general command usage */
+ (void) printf("%s:\t%s ", gettext("Usage"), commandName);
+
+ for (i = 0; standardCmdOptions[i].name; i++) {
+ (void) printf("-%c", standardCmdOptions[i].val);
+ if (standardCmdOptions[i+1].name)
+ (void) printf(",");
+ }
+
+ if (usageType == GENERAL_USAGE) {
+ for (i = 0; standardSubCmdOptions[i].name; i++) {
+ (void) printf(",--%s", standardSubCmdOptions[i].name);
+ if (standardSubCmdOptions[i+1].name)
+ (void) printf(",");
+ }
+ }
+
+ (void) fprintf(stdout, "\n");
+
+
+ /* print all subcommand usage */
+ for (sp = _subCommandProps; sp->name; sp++) {
+ subUsage(usageType, sp);
+ }
+}
+
+/*
+ * input:
+ * execFullName - exec name of program (argv[0])
+ *
+ * Returns:
+ * command name portion of execFullName
+ */
+static char *
+getExecBasename(char *execFullname)
+{
+ char *lastSlash, *execBasename;
+
+ /* guard against '/' at end of command invocation */
+ for (;;) {
+ lastSlash = strrchr(execFullname, '/');
+ if (lastSlash == NULL) {
+ execBasename = execFullname;
+ break;
+ } else {
+ execBasename = lastSlash + 1;
+ if (*execBasename == '\0') {
+ *lastSlash = '\0';
+ continue;
+ }
+ break;
+ }
+ }
+ return (execBasename);
+}
+
+/*
+ * cmdParse is a parser that checks syntax of the input command against
+ * various rules tables.
+ *
+ * It provides usage feedback based upon the passed rules tables by calling
+ * two usage functions, usage, subUsage
+ *
+ * When syntax is successfully validated, the associated function is called
+ * using the subcommands table functions.
+ *
+ * Syntax is as follows:
+ * command subcommand [<options>] [<operand>]
+ *
+ * There are two standard short and long options assumed:
+ * -?, --help Provides usage on a command or subcommand
+ * and stops further processing of the arguments
+ *
+ * -V, --version Provides version information on the command
+ * and stops further processing of the arguments
+ *
+ * These options are loaded by this function.
+ *
+ * input:
+ * argc, argv from main
+ * syntax rules tables (synTables_t structure)
+ * callArgs - void * passed by caller to be passed to subcommand function
+ *
+ * output:
+ * funcRet - pointer to int that holds subcommand function return value
+ *
+ * Returns:
+ *
+ * zero on successful syntax parse and function call
+ *
+ * 1 on unsuccessful syntax parse (no function has been called)
+ * This could be due to a version or help call or simply a
+ * general usage call.
+ *
+ * -1 check errno, call failed
+ *
+ * This module is not MT-safe.
+ *
+ */
+int
+cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs,
+ int *funcRet)
+{
+ int getoptargc;
+ char **getoptargv;
+ int opt;
+ int operInd;
+ int i, j;
+ int len;
+ int requiredOptionCnt = 0, requiredOptionEntered = 0;
+ char *availOptions;
+ char *versionString;
+ char optionStringAll[MAXOPTIONSTRING + 1];
+ subCommandProps_t *subcommand;
+ cmdOptions_t cmdOptions[MAXOPTIONS + 1];
+ optionTbl_t *optionTbl;
+ struct option *lp;
+ struct option intLongOpt[MAXOPTIONS + 1];
+
+ /*
+ * Check for NULLs on mandatory input arguments
+ *
+ * Note: longOptionTbl can be NULL in the case
+ * where there is no caller defined options
+ *
+ */
+ assert(synTable.versionString);
+ assert(synTable.subCommandPropsTbl);
+ assert(funcRet);
+
+ versionString = synTable.versionString;
+
+ /* set global command name */
+ commandName = getExecBasename(argv[0]);
+
+ /* Set unbuffered output */
+ setbuf(stdout, NULL);
+
+ /* load globals */
+ _subCommandProps = synTable.subCommandPropsTbl;
+ _clientOptionTbl = synTable.longOptionTbl;
+
+ /* There must be at least two arguments */
+ if (argc < 2) {
+ usage(GENERAL_USAGE);
+ return (1);
+ }
+
+ (void) memset(&intLongOpt[0], 0, sizeof (intLongOpt));
+
+ /*
+ * load standard subcommand options to internal long options table
+ * Two separate getopt_long(3C) tables are used.
+ */
+ for (i = 0; standardSubCmdOptions[i].name; i++) {
+ intLongOpt[i].name = standardSubCmdOptions[i].name;
+ intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg;
+ intLongOpt[i].flag = standardSubCmdOptions[i].flag;
+ intLongOpt[i].val = standardSubCmdOptions[i].val;
+ }
+
+ /*
+ * copy caller's long options into internal long options table
+ * We do this for two reasons:
+ * 1) We need to use the getopt_long option structure internally
+ * 2) We need to prepend the table with the standard option
+ * for all subcommands (currently -?)
+ */
+ for (optionTbl = synTable.longOptionTbl;
+ optionTbl && optionTbl->name; optionTbl++, i++) {
+ if (i > MAXOPTIONS - 1) {
+ /* option table too long */
+ assert(0);
+ }
+ intLongOpt[i].name = optionTbl->name;
+ intLongOpt[i].has_arg = optionTbl->has_arg;
+ intLongOpt[i].flag = NULL;
+ intLongOpt[i].val = optionTbl->val;
+ }
+
+ /* set option table global */
+ _longOptions = &intLongOpt[0];
+
+
+ /*
+ * Check for help/version request immediately following command
+ * '+' in option string ensures POSIX compliance in getopt_long()
+ * which means that processing will stop at first non-option
+ * argument.
+ */
+ while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions,
+ NULL)) != EOF) {
+ switch (opt) {
+ case '?':
+ /*
+ * getopt can return a '?' when no
+ * option letters match string. Check for
+ * the 'real' '?' in optopt.
+ */
+ if (optopt == '?') {
+ usage(DETAIL_USAGE);
+ exit(0);
+ } else {
+ usage(GENERAL_USAGE);
+ return (1);
+ }
+ break;
+ case 'V':
+ (void) fprintf(stdout, "%s: %s %s\n",
+ commandName, gettext("Version"),
+ versionString);
+ exit(0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * subcommand is always in the second argument. If there is no
+ * recognized subcommand in the second argument, print error,
+ * general usage and then return.
+ */
+ if (getSubcommandProps(argv[1], &subcommand) != 0) {
+ (void) printf("%s: %s\n", commandName,
+ gettext("invalid subcommand"));
+ usage(GENERAL_USAGE);
+ return (1);
+ }
+
+ getoptargv = argv;
+ getoptargv++;
+ getoptargc = argc;
+ getoptargc -= 1;
+
+ (void) memset(optionStringAll, 0, sizeof (optionStringAll));
+ (void) memset(&cmdOptions[0], 0, sizeof (cmdOptions));
+
+ j = 0;
+ /*
+ * Build optionStringAll from long options table
+ */
+ for (lp = _longOptions; lp->name; lp++, j++) {
+ /* sanity check on string length */
+ if (j + 1 >= sizeof (optionStringAll)) {
+ /* option table too long */
+ assert(0);
+ }
+ optionStringAll[j] = lp->val;
+ if (lp->has_arg == required_argument) {
+ optionStringAll[++j] = ':';
+ }
+ }
+
+ i = 0;
+ /*
+ * Run getopt for all arguments against all possible options
+ * Store all options/option arguments in an array for retrieval
+ * later.
+ *
+ * Once all options are retrieved, a validity check against
+ * subcommand table is performed.
+ */
+ while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll,
+ _longOptions, NULL)) != EOF) {
+ switch (opt) {
+ case '?':
+ subUsage(DETAIL_USAGE, subcommand);
+ /*
+ * getopt can return a '?' when no
+ * option letters match string. Check for
+ * the 'real' '?' in optopt.
+ */
+ if (optopt == '?') {
+ exit(0);
+ } else {
+ exit(1);
+ }
+ default:
+ cmdOptions[i].optval = opt;
+ if (optarg) {
+ len = strlen(optarg);
+ if (len > sizeof (cmdOptions[i].optarg)
+ - 1) {
+ (void) printf("%s: %s\n",
+ commandName,
+ gettext("option too long"));
+ errno = EINVAL;
+ return (-1);
+ }
+ (void) strncpy(cmdOptions[i].optarg,
+ optarg, len);
+ }
+ i++;
+ break;
+ }
+ }
+
+ /*
+ * increment past last option
+ */
+ operInd = optind + 1;
+
+ /*
+ * Check validity of given options, if any were given
+ */
+
+ /* get option string for this subcommand */
+ availOptions = subcommand->optionString;
+
+ /* Get count of required options */
+ if (subcommand->required) {
+ requiredOptionCnt = strlen(subcommand->required);
+ }
+
+ if (cmdOptions[0].optval != 0) { /* options were input */
+ if (availOptions == NULL) { /* no options permitted */
+ (void) printf("%s: %s\n", commandName,
+ gettext("no options permitted"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+ for (i = 0; cmdOptions[i].optval; i++) {
+ /* is the option in the available option string? */
+ if (!(strchr(availOptions, cmdOptions[i].optval))) {
+ (void) printf("%s: '-%c': %s\n", commandName,
+ cmdOptions[i].optval,
+ gettext("invalid option"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ /* increment required options entered */
+ } else if (subcommand->required &&
+ (strchr(subcommand->required,
+ cmdOptions[i].optval))) {
+ requiredOptionEntered++;
+ /* Check for exclusive options */
+ } else if (cmdOptions[1].optval != 0 &&
+ subcommand->exclusive &&
+ strchr(subcommand->exclusive,
+ cmdOptions[i].optval)) {
+ (void) printf("%s: '-%c': %s\n",
+ commandName, cmdOptions[i].optval,
+ gettext("is an exclusive option"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+ }
+ } else { /* no options were input */
+ if (availOptions != NULL && subcommand->required) {
+ (void) printf("%s: %s\n", commandName,
+ gettext("at least one option required"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+ }
+
+ /* Were all required options entered? */
+ if (requiredOptionEntered != requiredOptionCnt) {
+ (void) printf("%s: %s: %s\n", commandName,
+ gettext("Following option(s) required"),
+ subcommand->required);
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+
+
+ /*
+ * If there are no operands,
+ * check to see if this is okay
+ */
+ if ((operInd == argc) &&
+ (subcommand->operand & OPERAND_MANDATORY)) {
+ (void) printf("%s: %s %s\n", commandName, subcommand->name,
+ gettext("requires an operand"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+
+ /*
+ * If there are more operands,
+ * check to see if this is okay
+ */
+ if ((argc > operInd) &&
+ (subcommand->operand & OPERAND_NONE)) {
+ (void) fprintf(stderr, "%s: %s %s\n", commandName,
+ subcommand->name, gettext("takes no operands"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+
+ /*
+ * If there is more than one more operand,
+ * check to see if this is okay
+ */
+ if ((argc > operInd) && ((argc - operInd) != 1) &&
+ (subcommand->operand & OPERAND_SINGLE)) {
+ (void) printf("%s: %s %s\n", commandName,
+ subcommand->name, gettext("accepts only a single operand"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+
+ /* Finished syntax checks */
+
+
+ /* Call appropriate function */
+ *funcRet = subcommand->handler(argc - operInd, &argv[operInd],
+ &cmdOptions[0], callArgs);
+
+ return (0);
+}
diff --git a/usr/src/common/cmdparse/cmdparse.h b/usr/src/common/cmdparse/cmdparse.h
new file mode 100644
index 0000000..47dab55
--- /dev/null
+++ b/usr/src/common/cmdparse/cmdparse.h
@@ -0,0 +1,222 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _CMDPARSE_H
+#define _CMDPARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <getopt.h>
+
+#define SUBCOMMAND_BASE 1
+
+/* bit defines for operand macros */
+#define OPERAND_SINGLE 0x2
+#define OPERAND_MULTIPLE 0x4
+#define OPERAND_MANDATORY 0x8
+#define OPERAND_OPTIONAL 0x10
+
+/* maximum length of an option argument */
+#define MAXOPTARGLEN 512
+
+
+/* Following are used to express operand requirements */
+#define OPERAND_NONE 0x1
+#define OPERAND_MANDATORY_SINGLE (OPERAND_MANDATORY | OPERAND_SINGLE)
+#define OPERAND_OPTIONAL_SINGLE (OPERAND_OPTIONAL | OPERAND_SINGLE)
+#define OPERAND_MANDATORY_MULTIPLE (OPERAND_MANDATORY | OPERAND_MULTIPLE)
+#define OPERAND_OPTIONAL_MULTIPLE (OPERAND_OPTIONAL | OPERAND_MULTIPLE)
+
+/* subcommands must have a single bit on and must have exclusive values */
+#define SUBCOMMAND(x) (SUBCOMMAND_BASE << x)
+
+/*
+ * This structure is passed into the caller's callback function and
+ * will contain a list of all options entered and their associated
+ * option arguments if applicable
+ */
+typedef struct _cmdOptions {
+ int optval;
+ char optarg[MAXOPTARGLEN + 1];
+} cmdOptions_t;
+
+/*
+ * subcommand callback function
+ *
+ * argc - number of arguments in argv
+ * argv - operand arguments
+ * options - options entered on command line
+ * callData - pointer to caller data to be passed to subcommand function
+ */
+typedef int (*handler_t)(int argc, char *argv[], cmdOptions_t *options,
+ void *callData);
+
+/*
+ * list of subcommands and associated properties
+ *
+ * name -> subcommand name
+ * handler -> function to call on successful syntax check
+ * optionString -> short options that are valid
+ * required -> Does it require at least one option?
+ * exclusive -> short options that are required to be exclusively entered
+ * operand -> Type of operand input. Can be:
+ *
+ * NO_OPERAND
+ * OPERAND_MANDATORY_SINGLE
+ * OPERAND_OPTIONAL_SINGLE
+ * OPERAND_MANDATORY_MULTIPLE
+ * OPERAND_OPTIONAL_MULTIPLE
+ *
+ * operandDefinition -> char * definition of the operand
+ *
+ * The long options table specifies whether an option argument is required.
+ *
+ *
+ * EXAMPLE:
+ *
+ * Based on "list-target" entry below:
+ *
+ * "list-target" is expected as the subcommand input
+ * listTarget is the function to be called on success
+ * "list-target" accepts -i, -s, -t and -l
+ * "list-target" requires the option 'i'.
+ * "list-target" has no exclusive options
+ * "list-target" may have one or more operands
+ * "list-target" operand description is "target-name"
+ *
+ *
+ * optionRules_t optionRules[] = {
+ * {"list-target", listTarget, "istl", "i", NULL,
+ * OPERAND_OPTIONAL_MULTIPLE, "target-name"},
+ * {"modify-target", modifyTarget, "t", "t", NULL,
+ * OPERAND_MANDATORY_MULTIPLE, "target-name"},
+ * {"enable", enable, NULL, NULL, NULL, NO_OPERAND, NULL},
+ * {NULL, 0, 0, NULL, 0, NULL}
+ * };
+ */
+typedef struct _subCommandProps {
+ char *name;
+ handler_t handler;
+ char *optionString;
+ char *required;
+ char *exclusive;
+ int operand;
+ char *operandDefinition;
+ char *helpText;
+ uint8_t reserved[60];
+} subCommandProps_t;
+
+
+
+#define required_arg required_argument
+#define no_arg no_argument
+
+/*
+ * Add short options and long options here
+ *
+ * name -> long option name
+ * has_arg -> required_arg, no_arg
+ * val -> short option character
+ * argDesc -> description of option argument
+ *
+ * Note: This structure may not be used if your CLI has no
+ * options. However, -?, --help and -V, --version will still be supported
+ * as they are standard for every CLI.
+ *
+ * EXAMPLE:
+ *
+ * optionTbl_t options[] = {
+ * {"filename", arg_required, 'f', "out-filename"},
+ * {NULL, 0, 0}
+ * };
+ *
+ */
+typedef struct _optionTbl {
+ char *name;
+ int has_arg;
+ int val;
+ char *argDesc;
+} optionTbl_t;
+
+/*
+ * After tables are set, assign them to this structure
+ * for passing into cmdparse()
+ */
+typedef struct _synTables {
+ char *versionString;
+ optionTbl_t *longOptionTbl;
+ subCommandProps_t *subCommandPropsTbl;
+} synTables_t;
+
+/*
+ * cmdParse is a parser that checks syntax of the input command against
+ * rules and property tables.
+ *
+ * When syntax is successfully validated, the function associated with the
+ * subcommand is called using the subcommands table functions.
+ *
+ * Syntax for the command is as follows:
+ *
+ * command [options] subcommand [<options>] [<operand ...>]
+ *
+ *
+ * There are two standard short and long options assumed:
+ * -?, --help Provides usage on a command or subcommand
+ * and stops further processing of the arguments
+ *
+ * -V, --version Provides version information on the command
+ * and stops further processing of the arguments
+ *
+ * These options are loaded by this function.
+ *
+ * input:
+ * argc, argv from main
+ * syntax rules tables (synTables_t structure)
+ * callArgs - void * passed by caller to be passed to subcommand function
+ *
+ * output:
+ * funcRet - pointer to int that holds subcommand function return value
+ *
+ * Returns:
+ *
+ * zero on successful syntax parse and function call
+ *
+ * 1 on unsuccessful syntax parse (no function has been called)
+ * This could be due to a version or help call or simply a
+ * general usage call.
+ *
+ * -1 check errno, call failed
+ *
+ */
+int cmdParse(int numOperands, char *operands[], synTables_t synTables,
+ void *callerArgs, int *funcRet);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CMDPARSE_H */
diff --git a/usr/src/common/iscsi/base64.c b/usr/src/common/iscsi/base64.c
new file mode 100644
index 0000000..f4f3364
--- /dev/null
+++ b/usr/src/common/iscsi/base64.c
@@ -0,0 +1,255 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/sunddi.h>
+#include <sys/errno.h>
+#else
+#include <string.h>
+#include <errno.h>
+#endif /* _KERNEL */
+
+/*
+ * base64 decoding table (from uudecode.c)
+ */
+/* BEGIN CSTYLED */
+ static char base64_decode_tab[] = {
+ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+ '\377', '\377', '\377', 62, '\377', '\377', '\377', 63,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, '\377', '\377', '\377', '\377', '\377', '\377',
+ '\377', 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, '\377', '\377', '\377', '\377', '\377',
+ '\377', 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, '\377', '\377', '\377', '\377', '\377'
+};
+/* END CSTYLED */
+
+/* true if the character is in the base64 encoding table */
+#define validbase64(c) (('A' <= (c) && (c) <= 'Z') || \
+ ('a' <= (c) && (c) <= 'z') || \
+ ('0' <= (c) && (c) <= '9') || \
+ (c) == '+' || (c) == '/')
+
+static int
+outdec64(unsigned char *out, unsigned char *chr, int num)
+{
+
+ unsigned char char1, char2, char3, char4;
+ unsigned char *outptr = out;
+ int rc = 0;
+
+ switch (num) {
+ case 0:
+ case 1: /* these are impossible */
+ default:
+ break;
+ case 2: /* 2 base64 bytes == 1 decoded byte */
+ char1 = base64_decode_tab[chr[0]] & 0xFF;
+ char2 = base64_decode_tab[chr[1]] & 0xFF;
+ *(outptr++) = ((char1 << 2) & 0xFC) |
+ ((char2 >> 4) & 0x03);
+ rc = 1;
+ break;
+ case 3: /* 3 base64 bytes == 2 decoded bytes */
+ char1 = base64_decode_tab[chr[0]] & 0xFF;
+ char2 = base64_decode_tab[chr[1]] & 0xFF;
+ char3 = base64_decode_tab[chr[2]] & 0xFF;
+ *(outptr++) = ((char1 << 2) & 0xFC) |
+ ((char2 >> 4) & 0x03);
+ *(outptr++) = ((char2 << 4) & 0xF0) |
+ ((char3 >> 2) & 0x0F);
+ rc = 2;
+ break;
+ case 4: /* 4 base64 bytes == 3 decoded bytes */
+ char1 = base64_decode_tab[chr[0]] & 0xFF;
+ char2 = base64_decode_tab[chr[1]] & 0xFF;
+ char3 = base64_decode_tab[chr[2]] & 0xFF;
+ char4 = base64_decode_tab[chr[3]] & 0xFF;
+ *(outptr++) = ((char1 << 2) & 0xFC) |
+ ((char2 >> 4) & 0x03);
+ *(outptr++) = ((char2 << 4) & 0xF0) |
+ ((char3 >> 2) & 0x0F);
+ *(outptr++) = ((char3 << 6) & 0xC0) |
+ (char4 & 0x3F);
+ rc = 3;
+ break;
+ }
+ return (rc);
+}
+
+#define BUFSIZE 12
+
+int
+iscsi_base64_str_to_binary(char *hstr, int hstr_len,
+ uint8_t *binary, int binary_buf_len, int *out_len)
+{
+ char *iptr;
+ uint8_t tmp_out[BUFSIZE];
+ int octets, endseen, numbase64chars;
+ unsigned char chr[4], curchr;
+
+ /*
+ * base64 decode algorith, adapted from uudecode.c
+ *
+ * A valid base64 string is a multiple of 4 bytes in length
+ */
+ if ((hstr_len % 4) != 0)
+ return (EINVAL);
+
+ endseen = numbase64chars = 0;
+ *out_len = 0;
+ iptr = hstr;
+
+ while (((curchr = *(iptr++)) != NULL) &&
+ (((uintptr_t)iptr - (uintptr_t)hstr) <= hstr_len)) {
+ /* decode chars */
+ if (curchr == '=') /* if end */
+ endseen++;
+
+ if (validbase64(curchr))
+ chr[numbase64chars++] = curchr;
+ /*
+ * if we've gathered 4 base64 octets
+ * we need to decode and output them
+ */
+ if (numbase64chars == 4) {
+ octets = outdec64(tmp_out, chr, 4);
+ numbase64chars = 0;
+
+ if (*out_len + octets > binary_buf_len)
+ return (E2BIG);
+
+ (void) memcpy(binary + *out_len, tmp_out, octets);
+ *out_len += octets;
+ }
+
+ /*
+ * handle any remaining base64 octets at end
+ */
+ if (endseen && numbase64chars > 0) {
+ octets = outdec64(tmp_out, chr, numbase64chars);
+ numbase64chars = 0;
+ if (*out_len + octets > binary_buf_len)
+ return (E2BIG);
+
+ (void) memcpy(binary + *out_len, tmp_out, octets);
+ *out_len += octets;
+ }
+ }
+
+ return (0);
+}
+
+
+static char base64_encode_tab[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define ENC(c) base64_encode_tab[(c) & 0x3f]
+
+#define BASE64_BUF_HAS_ROOM(bytes_needed) \
+ ((optr + (bytes_needed)) <= base64_str_buf + base64_buf_len)
+
+int
+iscsi_binary_to_base64_str(uint8_t *in_buf, int in_buf_len,
+ char *base64_str_buf, int base64_buf_len)
+{
+ uint8_t *iptr;
+ char *optr;
+ int in_bytes_remaining;
+
+ /* base64 encode algorith, adapted from uuencode.c */
+ iptr = in_buf;
+ optr = base64_str_buf;
+
+ /*
+ * read must be a multiple of 3 bytes for
+ * this algorithm to work, and also must
+ * be small enough that read_size * (4/3)
+ * will always be 76 bytes or less, since
+ * base64 lines can be no longer than that
+ */
+ while (iptr + 3 <= in_buf + in_buf_len) {
+ if (!BASE64_BUF_HAS_ROOM(4))
+ return (E2BIG);
+
+ *(optr++) = ENC(*iptr >> 2);
+ *(optr++) = ENC((*iptr << 4) & 060 |
+ (*(iptr + 1) >> 4) & 017);
+ *(optr++) = ENC((*(iptr + 1) << 2)
+ & 074 | (*(iptr + 2) >> 6) & 03);
+ *(optr++) = ENC(*(iptr + 2) & 077);
+
+ iptr += 3;
+ }
+
+ /* need output padding ? */
+ in_bytes_remaining = ((uintptr_t)in_buf + in_buf_len) - (uintptr_t)iptr;
+ /* ASSERT(in_bytes_remaining < 3); */
+ switch (in_bytes_remaining) {
+ case 0:
+ /* no-op - 24 bits of data encoded */
+ if (!BASE64_BUF_HAS_ROOM(1))
+ return (E2BIG);
+ *(optr++) = '\0';
+ break;
+ case 1:
+ /* 8 bits encoded - pad with 2 '=' */
+ if (!BASE64_BUF_HAS_ROOM(5))
+ return (E2BIG);
+ *(optr++) = ENC((*iptr & 0xFC) >> 2);
+ *(optr++) = ENC((*iptr & 0x03) << 4);
+ *(optr++) = '=';
+ *(optr++) = '=';
+ *(optr++) = '\0';
+ break;
+ case 2:
+ /* 16 bits encoded - pad with 1 '=' */
+ if (!BASE64_BUF_HAS_ROOM(5))
+ return (E2BIG);
+ *(optr++) = ENC((*iptr & 0xFC) >> 2);
+ *(optr++) = ENC(((*iptr & 0x03) << 4) |
+ ((*(iptr + 1) & 0xF0) >> 4));
+ *(optr++) = ENC((*(iptr + 1) & 0x0F) << 2);
+ *(optr++) = '=';
+ *(optr++) = '\0';
+ break;
+ default:
+ /* impossible */
+ break;
+ }
+
+ return (0);
+}
diff --git a/usr/src/common/iscsit/iscsit_common.c b/usr/src/common/iscsit/iscsit_common.c
new file mode 100644
index 0000000..7b2b18e
--- /dev/null
+++ b/usr/src/common/iscsit/iscsit_common.c
@@ -0,0 +1,1588 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/time.h>
+
+#if defined(_KERNEL)
+#include <sys/ddi.h>
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/socket.h>
+#include <inet/tcp.h>
+#else
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include <sys/iscsit/iscsit_common.h>
+#include <sys/iscsi_protocol.h>
+#include <sys/iscsit/isns_protocol.h>
+
+void *
+iscsit_zalloc(size_t size)
+{
+#if defined(_KERNEL)
+ return (kmem_zalloc(size, KM_SLEEP));
+#else
+ return (calloc(1, size));
+#endif
+}
+
+void
+iscsit_free(void *buf, size_t size) /* ARGSUSED */
+{
+#if defined(_KERNEL)
+ kmem_free(buf, size);
+#else
+ free(buf);
+#endif
+}
+
+/*
+ * default_port should be the port to be used, if not specified
+ * as part of the supplied string 'arg'.
+ */
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+
+struct sockaddr_storage *
+it_common_convert_sa(char *arg, struct sockaddr_storage *buf,
+ uint32_t default_port)
+{
+ /* Why does addrbuf need to be this big!??! XXX */
+ char addrbuf[NI_MAXHOST + NI_MAXSERV + 1];
+ char *addr_str;
+ char *port_str;
+#ifndef _KERNEL
+ char *errchr;
+#endif
+ long tmp_port = 0;
+ sa_family_t af;
+
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_storage *sa = buf;
+
+ if (!arg || !buf) {
+ return (NULL);
+ }
+
+ bzero(buf, sizeof (struct sockaddr_storage));
+
+ /* don't modify the passed-in string */
+ (void) strlcpy(addrbuf, arg, sizeof (addrbuf));
+
+ addr_str = addrbuf;
+
+ if (*addr_str == '[') {
+ /*
+ * An IPv6 address must be inside square brackets
+ */
+ port_str = strchr(addr_str, ']');
+ if (!port_str) {
+ /* No closing bracket */
+ return (NULL);
+ }
+
+ /* strip off the square brackets so we can convert */
+ addr_str++;
+ *port_str = '\0';
+ port_str++;
+
+ if (*port_str == ':') {
+ /* TCP port to follow */
+ port_str++;
+ } else if (*port_str == '\0') {
+ /* No port specified */
+ port_str = NULL;
+ } else {
+ /* malformed */
+ return (NULL);
+ }
+ af = AF_INET6;
+ } else {
+ port_str = strchr(addr_str, ':');
+ if (port_str) {
+ *port_str = '\0';
+ port_str++;
+ }
+ af = AF_INET;
+ }
+
+ if (port_str) {
+#if defined(_KERNEL)
+ if (ddi_strtol(port_str, NULL, 10, &tmp_port) != 0) {
+ return (NULL);
+ }
+#else
+ tmp_port = strtol(port_str, &errchr, 10);
+#endif
+ if (tmp_port < 0 || tmp_port > 65535) {
+ return (NULL);
+ }
+ } else {
+ tmp_port = default_port;
+ }
+
+ sa->ss_family = af;
+
+ sin = (struct sockaddr_in *)sa;
+ if (af == AF_INET) {
+ if (inet_pton(af, addr_str,
+ (void *)&(sin->sin_addr.s_addr)) != 1) {
+ return (NULL);
+ }
+ /*
+ * intet_pton does not seem to convert to network
+ * order in kernel. This is a workaround until the
+ * inet_pton works or we have our own inet_pton function.
+ */
+#ifdef _KERNEL
+ sin->sin_addr.s_addr = ntohl((uint32_t)sin->sin_addr.s_addr);
+#endif
+ sin->sin_port = htons(tmp_port);
+ } else {
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (inet_pton(af, addr_str,
+ (void *)&(sin6->sin6_addr.s6_addr)) != 1) {
+ return (NULL);
+ }
+ sin6->sin6_port = htons(tmp_port);
+ }
+
+ /* successful */
+ return (sa);
+}
+
+
+/* Functions to convert iSCSI target structures to/from nvlists. */
+
+#ifndef _KERNEL
+int
+it_config_to_nv(it_config_t *cfg, nvlist_t **nvl)
+{
+ int ret;
+ nvlist_t *nv;
+ nvlist_t *lnv = NULL;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ *nvl = NULL;
+
+ ret = nvlist_alloc(&nv, NV_UNIQUE_NAME_TYPE, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ /* if there's no config, store an empty list */
+ if (!cfg) {
+ *nvl = nv;
+ return (0);
+ }
+
+ ret = nvlist_add_uint32(nv, "cfgVersion", cfg->config_version);
+ if (ret == 0) {
+ ret = it_tgtlist_to_nv(cfg->config_tgt_list, &lnv);
+ }
+
+ if ((ret == 0) && (lnv != NULL)) {
+ ret = nvlist_add_nvlist(nv, "targetList", lnv);
+ nvlist_free(lnv);
+ lnv = NULL;
+ }
+
+ if (ret == 0) {
+ ret = it_tpglist_to_nv(cfg->config_tpg_list, &lnv);
+ }
+
+ if ((ret == 0) && (lnv != NULL)) {
+ ret = nvlist_add_nvlist(nv, "tpgList", lnv);
+ nvlist_free(lnv);
+ lnv = NULL;
+ }
+
+ if (ret == 0) {
+ ret = it_inilist_to_nv(cfg->config_ini_list, &lnv);
+ }
+
+ if ((ret == 0) && (lnv != NULL)) {
+ ret = nvlist_add_nvlist(nv, "iniList", lnv);
+ nvlist_free(lnv);
+ lnv = NULL;
+ }
+
+ if (ret == 0) {
+ ret = nvlist_add_nvlist(nv, "globalProperties",
+ cfg->config_global_properties);
+ }
+
+ if (ret == 0) {
+ *nvl = nv;
+ } else {
+ nvlist_free(nv);
+ }
+
+ return (ret);
+}
+#endif /* !_KERNEL */
+
+/*
+ * nvlist version of config is 3 list-of-list, + 1 proplist. arrays
+ * are interesting, but lists-of-lists are more useful when doing
+ * individual lookups when we later add support for it. Also, no
+ * need to store name in individual struct representation.
+ */
+int
+it_nv_to_config(nvlist_t *nvl, it_config_t **cfg)
+{
+ int ret;
+ uint32_t intval;
+ nvlist_t *listval;
+ it_config_t *tmpcfg;
+
+ if (!cfg) {
+ return (EINVAL);
+ }
+
+ /* initialize output */
+ *cfg = NULL;
+
+ tmpcfg = iscsit_zalloc(sizeof (it_config_t));
+ if (tmpcfg == NULL) {
+ return (ENOMEM);
+ }
+
+ if (!nvl) {
+ /* nothing to decode, but return the empty cfg struct */
+ ret = nvlist_alloc(&tmpcfg->config_global_properties,
+ NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ iscsit_free(tmpcfg, sizeof (it_config_t));
+ return (ret);
+ }
+ *cfg = tmpcfg;
+ return (0);
+ }
+
+ ret = nvlist_lookup_uint32(nvl, "cfgVersion", &intval);
+ if (ret != 0) {
+ iscsit_free(tmpcfg, sizeof (it_config_t));
+ return (ret);
+ }
+
+ tmpcfg->config_version = intval;
+
+ ret = nvlist_lookup_nvlist(nvl, "targetList", &listval);
+ if (ret == 0) {
+ /* decode list of it_tgt_t */
+ ret = it_nv_to_tgtlist(listval, &(tmpcfg->config_tgt_count),
+ &(tmpcfg->config_tgt_list));
+ }
+
+ ret = nvlist_lookup_nvlist(nvl, "tpgList", &listval);
+ if (ret == 0) {
+ /* decode list of it_tpg_t */
+ ret = it_nv_to_tpglist(listval, &(tmpcfg->config_tpg_count),
+ &(tmpcfg->config_tpg_list));
+ }
+
+ ret = nvlist_lookup_nvlist(nvl, "iniList", &listval);
+ if (ret == 0) {
+ /* decode list of initiators */
+ ret = it_nv_to_inilist(listval, &(tmpcfg->config_ini_count),
+ &(tmpcfg->config_ini_list));
+ }
+
+ ret = nvlist_lookup_nvlist(nvl, "globalProperties", &listval);
+ if (ret == 0) {
+ /*
+ * don't depend on the original nvlist staying in-scope,
+ * duplicate the nvlist
+ */
+ ret = nvlist_dup(listval, &(tmpcfg->config_global_properties),
+ 0);
+ } else if (ret == ENOENT) {
+ /*
+ * No global properties defined, make an empty list
+ */
+ ret = nvlist_alloc(&tmpcfg->config_global_properties,
+ NV_UNIQUE_NAME, 0);
+ }
+
+ if (ret == 0) {
+ char **isnsArray = NULL;
+ uint32_t numisns = 0;
+
+ /*
+ * decode the list of iSNS server information to make
+ * references from the kernel simpler.
+ */
+ if (tmpcfg->config_global_properties) {
+ ret = nvlist_lookup_string_array(
+ tmpcfg->config_global_properties,
+ PROP_ISNS_SERVER,
+ &isnsArray, &numisns);
+ if (ret == 0) {
+ ret = it_array_to_portallist(isnsArray,
+ numisns, ISNS_DEFAULT_SERVER_PORT,
+ &tmpcfg->config_isns_svr_list,
+ &tmpcfg->config_isns_svr_count);
+ } else if (ret == ENOENT) {
+ /* It's OK if we don't have any iSNS servers */
+ ret = 0;
+ }
+ }
+ }
+
+ if (ret == 0) {
+ *cfg = tmpcfg;
+ } else {
+ it_config_free_cmn(tmpcfg);
+ }
+
+ return (ret);
+}
+
+it_tgt_t *
+it_tgt_lookup(it_config_t *cfg, char *tgt_name)
+{
+ it_tgt_t *cfg_tgt = NULL;
+
+ for (cfg_tgt = cfg->config_tgt_list;
+ cfg_tgt != NULL;
+ cfg_tgt = cfg_tgt->tgt_next) {
+ if (strncmp(cfg_tgt->tgt_name, tgt_name,
+ MAX_ISCSI_NODENAMELEN) == 0) {
+ return (cfg_tgt);
+ }
+ }
+
+ return (NULL);
+}
+
+int
+it_nv_to_tgtlist(nvlist_t *nvl, uint32_t *count, it_tgt_t **tgtlist)
+{
+ int ret = 0;
+ it_tgt_t *tgt;
+ it_tgt_t *prev = NULL;
+ nvpair_t *nvp = NULL;
+ nvlist_t *nvt;
+ char *name;
+
+ if (!tgtlist || !count) {
+ return (EINVAL);
+ }
+
+ *tgtlist = NULL;
+ *count = 0;
+
+ if (!nvl) {
+ /* nothing to do */
+ return (0);
+ }
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ name = nvpair_name(nvp);
+
+ ret = nvpair_value_nvlist(nvp, &nvt);
+ if (ret != 0) {
+ /* invalid entry? */
+ continue;
+ }
+
+ ret = it_nv_to_tgt(nvt, name, &tgt);
+ if (ret != 0) {
+ break;
+ }
+
+ (*count)++;
+
+ if (*tgtlist == NULL) {
+ *tgtlist = tgt;
+ } else {
+ prev->tgt_next = tgt;
+ }
+ prev = tgt;
+ }
+
+ if (ret != 0) {
+ it_tgt_free_cmn(*tgtlist);
+ *tgtlist = NULL;
+ }
+
+ return (ret);
+}
+
+int
+it_tgtlist_to_nv(it_tgt_t *tgtlist, nvlist_t **nvl)
+{
+ int ret;
+ it_tgt_t *tgtp = tgtlist;
+ nvlist_t *pnv = NULL;
+ nvlist_t *tnv;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ if (!tgtlist) {
+ /* nothing to do */
+ return (0);
+ }
+
+ /* create the target list if required */
+ if (*nvl == NULL) {
+ ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+ *nvl = pnv;
+ }
+
+ while (tgtp) {
+ ret = it_tgt_to_nv(tgtp, &tnv);
+
+ if (ret != 0) {
+ break;
+ }
+
+ ret = nvlist_add_nvlist(*nvl, tgtp->tgt_name, tnv);
+
+ if (ret != 0) {
+ break;
+ }
+
+ nvlist_free(tnv);
+
+ tgtp = tgtp->tgt_next;
+ }
+
+ if (ret != 0) {
+ if (pnv) {
+ nvlist_free(pnv);
+ *nvl = NULL;
+ }
+ }
+
+ return (ret);
+}
+
+int
+it_tgt_to_nv(it_tgt_t *tgt, nvlist_t **nvl)
+{
+ int ret;
+ nvlist_t *tnv = NULL;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ if (!tgt) {
+ /* nothing to do */
+ return (0);
+ }
+
+ ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ if (tgt->tgt_properties) {
+ ret = nvlist_add_nvlist(*nvl, "properties",
+ tgt->tgt_properties);
+ }
+
+ if (ret == 0) {
+ ret = nvlist_add_uint64(*nvl, "generation",
+ tgt->tgt_generation);
+ }
+
+ if (ret == 0) {
+ ret = it_tpgtlist_to_nv(tgt->tgt_tpgt_list, &tnv);
+ }
+
+ if ((ret == 0) && tnv) {
+ ret = nvlist_add_nvlist(*nvl, "tpgtList", tnv);
+ nvlist_free(tnv);
+ }
+
+ if (ret != 0) {
+ nvlist_free(*nvl);
+ *nvl = NULL;
+ }
+
+ return (ret);
+}
+
+int
+it_nv_to_tgt(nvlist_t *nvl, char *name, it_tgt_t **tgt)
+{
+ int ret;
+ it_tgt_t *ttgt;
+ nvlist_t *listval;
+ uint32_t intval;
+
+ if (!nvl || !tgt || !name) {
+ return (EINVAL);
+ }
+
+ *tgt = NULL;
+
+ ttgt = iscsit_zalloc(sizeof (it_tgt_t));
+ if (!ttgt) {
+ return (ENOMEM);
+ }
+
+ (void) strlcpy(ttgt->tgt_name, name, sizeof (ttgt->tgt_name));
+
+ ret = nvlist_lookup_nvlist(nvl, "properties", &listval);
+ if (ret == 0) {
+ /* duplicate list so it does not go out of context */
+ ret = nvlist_dup(listval, &(ttgt->tgt_properties), 0);
+ } else if (ret == ENOENT) {
+ ret = 0;
+ }
+
+ if (ret == 0) {
+ ret = nvlist_lookup_uint64(nvl, "generation",
+ &(ttgt->tgt_generation));
+ } else if (ret == ENOENT) {
+ ret = 0;
+ }
+
+ if (ret == 0) {
+ ret = nvlist_lookup_nvlist(nvl, "tpgtList", &listval);
+ }
+
+ if (ret == 0) {
+ ret = it_nv_to_tpgtlist(listval, &intval,
+ &(ttgt->tgt_tpgt_list));
+ ttgt->tgt_tpgt_count = intval;
+ } else if (ret == ENOENT) {
+ ret = 0;
+ }
+
+ if (ret == 0) {
+ *tgt = ttgt;
+ } else {
+ it_tgt_free_cmn(ttgt);
+ }
+
+ return (ret);
+}
+
+int
+it_tpgt_to_nv(it_tpgt_t *tpgt, nvlist_t **nvl)
+{
+ int ret;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ if (!tpgt) {
+ /* nothing to do */
+ return (0);
+ }
+
+ ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ ret = nvlist_add_uint16(*nvl, "tag", tpgt->tpgt_tag);
+ if (ret == 0) {
+ ret = nvlist_add_uint64(*nvl, "generation",
+ tpgt->tpgt_generation);
+ }
+
+ if (ret != 0) {
+ nvlist_free(*nvl);
+ *nvl = NULL;
+ }
+
+ return (ret);
+}
+
+int
+it_nv_to_tpgt(nvlist_t *nvl, char *name, it_tpgt_t **tpgt)
+{
+ int ret;
+ it_tpgt_t *ptr;
+
+ if (!tpgt || !name) {
+ return (EINVAL);
+ }
+
+ *tpgt = NULL;
+
+ if (!nvl) {
+ return (0);
+ }
+
+ ptr = iscsit_zalloc(sizeof (it_tpgt_t));
+ if (!ptr) {
+ return (ENOMEM);
+ }
+
+ (void) strlcpy(ptr->tpgt_tpg_name, name, sizeof (ptr->tpgt_tpg_name));
+
+ ret = nvlist_lookup_uint16(nvl, "tag", &(ptr->tpgt_tag));
+ if (ret == 0) {
+ ret = nvlist_lookup_uint64(nvl, "generation",
+ &(ptr->tpgt_generation));
+ }
+
+ if (ret == 0) {
+ *tpgt = ptr;
+ } else {
+ iscsit_free(ptr, sizeof (it_tpgt_t));
+ }
+
+ return (ret);
+}
+
+int
+it_tpgtlist_to_nv(it_tpgt_t *tpgtlist, nvlist_t **nvl)
+{
+ int ret;
+ nvlist_t *pnv = NULL;
+ nvlist_t *tnv;
+ it_tpgt_t *ptr = tpgtlist;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ if (!tpgtlist) {
+ /* nothing to do */
+ return (0);
+ }
+
+ /* create the target list if required */
+ if (*nvl == NULL) {
+ ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+ *nvl = pnv;
+ }
+
+ while (ptr) {
+ ret = it_tpgt_to_nv(ptr, &tnv);
+
+ if (ret != 0) {
+ break;
+ }
+
+ ret = nvlist_add_nvlist(*nvl, ptr->tpgt_tpg_name, tnv);
+
+ if (ret != 0) {
+ break;
+ }
+
+ nvlist_free(tnv);
+
+ ptr = ptr->tpgt_next;
+ }
+
+ if (ret != 0) {
+ if (pnv) {
+ nvlist_free(pnv);
+ *nvl = NULL;
+ }
+ }
+
+ return (ret);
+}
+
+int
+it_nv_to_tpgtlist(nvlist_t *nvl, uint32_t *count, it_tpgt_t **tpgtlist)
+{
+ int ret = 0;
+ it_tpgt_t *tpgt;
+ it_tpgt_t *prev = NULL;
+ nvpair_t *nvp = NULL;
+ nvlist_t *nvt;
+ char *name;
+
+ if (!tpgtlist || !count) {
+ return (EINVAL);
+ }
+
+ *tpgtlist = NULL;
+ *count = 0;
+
+ if (!nvl) {
+ /* nothing to do */
+ return (0);
+ }
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ name = nvpair_name(nvp);
+
+ ret = nvpair_value_nvlist(nvp, &nvt);
+ if (ret != 0) {
+ /* invalid entry? */
+ continue;
+ }
+
+ ret = it_nv_to_tpgt(nvt, name, &tpgt);
+ if (ret != 0) {
+ break;
+ }
+
+ (*count)++;
+
+ if (*tpgtlist == NULL) {
+ *tpgtlist = tpgt;
+ } else {
+ prev->tpgt_next = tpgt;
+ }
+
+ prev = tpgt;
+ }
+
+ if (ret != 0) {
+ it_tpgt_free_cmn(*tpgtlist);
+ *tpgtlist = NULL;
+ }
+
+ return (ret);
+}
+
+#ifndef _KERNEL
+int
+it_tpg_to_nv(it_tpg_t *tpg, nvlist_t **nvl)
+{
+ int ret;
+ char **portalArray = NULL;
+ int i;
+ it_portal_t *ptr;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ if (!tpg) {
+ /* nothing to do */
+ return (0);
+ }
+
+ ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ ret = nvlist_add_uint64(*nvl, "generation", tpg->tpg_generation);
+
+ if ((ret == 0) && tpg->tpg_portal_list) {
+ /* add the portals */
+ portalArray = iscsit_zalloc(tpg->tpg_portal_count *
+ sizeof (it_portal_t));
+ if (portalArray == NULL) {
+ nvlist_free(*nvl);
+ *nvl = NULL;
+ return (ENOMEM);
+ }
+
+ i = 0;
+ ptr = tpg->tpg_portal_list;
+
+ while (ptr && (i < tpg->tpg_portal_count)) {
+ ret = sockaddr_to_str(&(ptr->portal_addr),
+ &(portalArray[i]));
+ if (ret != 0) {
+ break;
+ }
+ ptr = ptr->portal_next;
+ i++;
+ }
+ }
+
+ if ((ret == 0) && portalArray) {
+ ret = nvlist_add_string_array(*nvl, "portalList",
+ portalArray, i);
+ }
+
+
+ if (portalArray) {
+ while (--i >= 0) {
+ if (portalArray[i]) {
+ iscsit_free(portalArray[i],
+ strlen(portalArray[i] + 1));
+ }
+ }
+ iscsit_free(portalArray,
+ tpg->tpg_portal_count * sizeof (it_portal_t));
+ }
+
+ if (ret != 0) {
+ nvlist_free(*nvl);
+ *nvl = NULL;
+ }
+
+ return (ret);
+}
+#endif /* !_KERNEL */
+
+int
+it_nv_to_tpg(nvlist_t *nvl, char *name, it_tpg_t **tpg)
+{
+ int ret;
+ it_tpg_t *ptpg;
+ char **portalArray = NULL;
+ uint32_t count = 0;
+
+ if (!name || !tpg) {
+ return (EINVAL);
+ }
+
+ *tpg = NULL;
+
+ ptpg = iscsit_zalloc(sizeof (it_tpg_t));
+ if (ptpg == NULL) {
+ return (ENOMEM);
+ }
+
+ (void) strlcpy(ptpg->tpg_name, name, sizeof (ptpg->tpg_name));
+
+ ret = nvlist_lookup_uint64(nvl, "generation",
+ &(ptpg->tpg_generation));
+
+ if (ret == 0) {
+ ret = nvlist_lookup_string_array(nvl, "portalList",
+ &portalArray, &count);
+ }
+
+ if (ret == 0) {
+ /* set the portals */
+ ret = it_array_to_portallist(portalArray, count,
+ ISCSI_LISTEN_PORT, &ptpg->tpg_portal_list,
+ &ptpg->tpg_portal_count);
+ } else if (ret == ENOENT) {
+ ret = 0;
+ }
+
+ if (ret == 0) {
+ *tpg = ptpg;
+ } else {
+ it_tpg_free_cmn(ptpg);
+ }
+
+ return (ret);
+}
+
+
+
+
+#ifndef _KERNEL
+int
+it_tpglist_to_nv(it_tpg_t *tpglist, nvlist_t **nvl)
+{
+ int ret;
+ nvlist_t *pnv = NULL;
+ nvlist_t *tnv;
+ it_tpg_t *ptr = tpglist;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ if (!tpglist) {
+ /* nothing to do */
+ return (0);
+ }
+
+ /* create the target portal group list if required */
+ if (*nvl == NULL) {
+ ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+ *nvl = pnv;
+ }
+
+ while (ptr) {
+ ret = it_tpg_to_nv(ptr, &tnv);
+
+ if (ret != 0) {
+ break;
+ }
+
+ ret = nvlist_add_nvlist(*nvl, ptr->tpg_name, tnv);
+
+ if (ret != 0) {
+ break;
+ }
+
+ nvlist_free(tnv);
+
+ ptr = ptr->tpg_next;
+ }
+
+ if (ret != 0) {
+ if (pnv) {
+ nvlist_free(pnv);
+ *nvl = NULL;
+ }
+ }
+
+ return (ret);
+}
+#endif /* !_KERNEL */
+
+it_tpg_t *
+it_tpg_lookup(it_config_t *cfg, char *tpg_name)
+{
+ it_tpg_t *cfg_tpg = NULL;
+
+ for (cfg_tpg = cfg->config_tpg_list;
+ cfg_tpg != NULL;
+ cfg_tpg = cfg_tpg->tpg_next) {
+ if (strncmp(&cfg_tpg->tpg_name[0], tpg_name,
+ MAX_TPG_NAMELEN) == 0) {
+ return (cfg_tpg);
+ }
+ }
+
+ return (NULL);
+}
+
+int
+it_sa_compare(struct sockaddr_storage *sa1, struct sockaddr_storage *sa2)
+{
+ struct sockaddr_in *sin1, *sin2;
+ struct sockaddr_in6 *sin6_1, *sin6_2;
+
+ /*
+ * XXX - should we check here for IPv4 addrs mapped to v6?
+ * see also iscsit_is_v4_mapped in iscsit_login.c
+ */
+
+ if (sa1->ss_family != sa2->ss_family) {
+ return (1);
+ }
+
+ /*
+ * sockaddr_in has padding which may not be initialized.
+ * be more specific in the comparison, and don't trust the
+ * caller has fully initialized the structure.
+ */
+ if (sa1->ss_family == AF_INET) {
+ sin1 = (struct sockaddr_in *)sa1;
+ sin2 = (struct sockaddr_in *)sa2;
+ if ((bcmp(&sin1->sin_addr, &sin2->sin_addr,
+ sizeof (struct in_addr)) == 0) &&
+ (sin1->sin_port == sin2->sin_port)) {
+ return (0);
+ }
+ } else if (sa1->ss_family == AF_INET6) {
+ sin6_1 = (struct sockaddr_in6 *)sa1;
+ sin6_2 = (struct sockaddr_in6 *)sa2;
+ if (bcmp(sin6_1, sin6_2, sizeof (struct sockaddr_in6)) == 0) {
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+it_portal_t *
+it_portal_lookup(it_tpg_t *tpg, struct sockaddr_storage *sa)
+{
+ it_portal_t *cfg_portal;
+
+ for (cfg_portal = tpg->tpg_portal_list;
+ cfg_portal != NULL;
+ cfg_portal = cfg_portal->portal_next) {
+ if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0)
+ return (cfg_portal);
+ }
+
+ return (NULL);
+}
+
+it_portal_t *
+it_sns_svr_lookup(it_config_t *cfg, struct sockaddr_storage *sa)
+{
+ it_portal_t *cfg_portal;
+
+ for (cfg_portal = cfg->config_isns_svr_list;
+ cfg_portal != NULL;
+ cfg_portal = cfg_portal->portal_next) {
+ if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0)
+ return (cfg_portal);
+ }
+
+ return (NULL);
+}
+
+int
+it_nv_to_tpglist(nvlist_t *nvl, uint32_t *count, it_tpg_t **tpglist)
+{
+ int ret = 0;
+ it_tpg_t *tpg;
+ it_tpg_t *prev = NULL;
+ nvpair_t *nvp = NULL;
+ nvlist_t *nvt;
+ char *name;
+
+ if (!tpglist || !count) {
+ return (EINVAL);
+ }
+
+ *tpglist = NULL;
+ *count = 0;
+
+ if (!nvl) {
+ /* nothing to do */
+ return (0);
+ }
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ name = nvpair_name(nvp);
+
+ ret = nvpair_value_nvlist(nvp, &nvt);
+ if (ret != 0) {
+ /* invalid entry? */
+ continue;
+ }
+
+ ret = it_nv_to_tpg(nvt, name, &tpg);
+ if (ret != 0) {
+ break;
+ }
+
+ (*count)++;
+
+ if (*tpglist == NULL) {
+ *tpglist = tpg;
+ } else {
+ prev->tpg_next = tpg;
+ }
+ prev = tpg;
+ }
+
+ if (ret != 0) {
+ it_tpg_free_cmn(*tpglist);
+ *tpglist = NULL;
+ }
+
+ return (ret);
+}
+
+int
+it_ini_to_nv(it_ini_t *ini, nvlist_t **nvl)
+{
+ int ret;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ if (!ini) {
+ return (0);
+ }
+
+ ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ if (ini->ini_properties) {
+ ret = nvlist_add_nvlist(*nvl, "properties",
+ ini->ini_properties);
+ }
+
+ if (ret == 0) {
+ ret = nvlist_add_uint64(*nvl, "generation",
+ ini->ini_generation);
+ } else if (ret == ENOENT) {
+ ret = 0;
+ }
+
+ if (ret != 0) {
+ nvlist_free(*nvl);
+ *nvl = NULL;
+ }
+
+ return (ret);
+}
+
+int
+it_nv_to_ini(nvlist_t *nvl, char *name, it_ini_t **ini)
+{
+ int ret;
+ it_ini_t *inip;
+ nvlist_t *listval;
+
+ if (!name || !ini) {
+ return (EINVAL);
+ }
+
+ *ini = NULL;
+
+ if (!nvl) {
+ return (0);
+ }
+
+ inip = iscsit_zalloc(sizeof (it_ini_t));
+ if (!inip) {
+ return (ENOMEM);
+ }
+
+ (void) strlcpy(inip->ini_name, name, sizeof (inip->ini_name));
+
+ ret = nvlist_lookup_nvlist(nvl, "properties", &listval);
+ if (ret == 0) {
+ ret = nvlist_dup(listval, &(inip->ini_properties), 0);
+ } else if (ret == ENOENT) {
+ ret = 0;
+ }
+
+ if (ret == 0) {
+ ret = nvlist_lookup_uint64(nvl, "generation",
+ &(inip->ini_generation));
+ }
+
+ if (ret == 0) {
+ *ini = inip;
+ } else {
+ it_ini_free_cmn(inip);
+ }
+
+ return (ret);
+}
+
+int
+it_inilist_to_nv(it_ini_t *inilist, nvlist_t **nvl)
+{
+ int ret;
+ nvlist_t *pnv = NULL;
+ nvlist_t *tnv;
+ it_ini_t *ptr = inilist;
+
+ if (!nvl) {
+ return (EINVAL);
+ }
+
+ if (!inilist) {
+ return (0);
+ }
+
+ /* create the target list if required */
+ if (*nvl == NULL) {
+ ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ return (ret);
+ }
+ *nvl = pnv;
+ }
+
+ while (ptr) {
+ ret = it_ini_to_nv(ptr, &tnv);
+
+ if (ret != 0) {
+ break;
+ }
+
+ ret = nvlist_add_nvlist(*nvl, ptr->ini_name, tnv);
+
+ if (ret != 0) {
+ break;
+ }
+
+ nvlist_free(tnv);
+
+ ptr = ptr->ini_next;
+ }
+
+ if (ret != 0) {
+ if (pnv) {
+ nvlist_free(pnv);
+ *nvl = NULL;
+ }
+ }
+
+ return (ret);
+}
+
+int
+it_nv_to_inilist(nvlist_t *nvl, uint32_t *count, it_ini_t **inilist)
+{
+ int ret = 0;
+ it_ini_t *inip;
+ it_ini_t *prev = NULL;
+ nvpair_t *nvp = NULL;
+ nvlist_t *nvt;
+ char *name;
+
+ if (!inilist || !count) {
+ return (EINVAL);
+ }
+
+ *inilist = NULL;
+ *count = 0;
+
+ if (!nvl) {
+ /* nothing to do */
+ return (0);
+ }
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ name = nvpair_name(nvp);
+
+ ret = nvpair_value_nvlist(nvp, &nvt);
+ if (ret != 0) {
+ /* invalid entry? */
+ continue;
+ }
+
+ ret = it_nv_to_ini(nvt, name, &inip);
+ if (ret != 0) {
+ break;
+ }
+
+ (*count)++;
+
+ if (*inilist == NULL) {
+ *inilist = inip;
+ } else {
+ prev->ini_next = inip;
+ }
+ prev = inip;
+ }
+
+ if (ret != 0) {
+ it_ini_free_cmn(*inilist);
+ *inilist = NULL;
+ }
+
+ return (ret);
+}
+
+/*
+ * Convert a sockaddr to the string representation, suitable for
+ * storing in an nvlist or printing out in a list.
+ */
+#ifndef _KERNEL
+int
+sockaddr_to_str(struct sockaddr_storage *sa, char **addr)
+{
+ int ret;
+ char buf[INET6_ADDRSTRLEN + 7]; /* addr : port */
+ char pbuf[7];
+ const char *bufp;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ uint16_t port;
+
+ if (!sa || !addr) {
+ return (EINVAL);
+ }
+
+ buf[0] = '\0';
+
+ if (sa->ss_family == AF_INET) {
+ sin = (struct sockaddr_in *)sa;
+ bufp = inet_ntop(AF_INET,
+ (const void *)&(sin->sin_addr.s_addr),
+ buf, sizeof (buf));
+ if (bufp == NULL) {
+ ret = errno;
+ return (ret);
+ }
+ port = ntohs(sin->sin_port);
+ } else if (sa->ss_family == AF_INET6) {
+ (void) strlcat(buf, "[", sizeof (buf));
+ sin6 = (struct sockaddr_in6 *)sa;
+ bufp = inet_ntop(AF_INET6,
+ (const void *)&sin6->sin6_addr.s6_addr,
+ &buf[1], (sizeof (buf) - 1));
+ if (bufp == NULL) {
+ ret = errno;
+ return (ret);
+ }
+ (void) strlcat(buf, "]", sizeof (buf));
+ port = ntohs(sin6->sin6_port);
+ } else {
+ return (EINVAL);
+ }
+
+
+ (void) snprintf(pbuf, sizeof (pbuf), ":%u", port);
+ (void) strlcat(buf, pbuf, sizeof (buf));
+
+ *addr = strdup(buf);
+ if (*addr == NULL) {
+ return (ENOMEM);
+ }
+
+ return (0);
+}
+#endif /* !_KERNEL */
+
+int
+it_array_to_portallist(char **arr, uint32_t count, uint32_t default_port,
+ it_portal_t **portallist, uint32_t *list_count)
+{
+ int ret = 0;
+ int i;
+ it_portal_t *portal;
+ it_portal_t *prev = NULL;
+ it_portal_t *tmp;
+
+ if (!arr || !portallist || !list_count) {
+ return (EINVAL);
+ }
+
+ *list_count = 0;
+ *portallist = NULL;
+
+ for (i = 0; i < count; i++) {
+ if (!arr[i]) {
+ /* should never happen */
+ continue;
+ }
+ portal = iscsit_zalloc(sizeof (it_portal_t));
+ if (!portal) {
+ ret = ENOMEM;
+ break;
+ }
+ if (it_common_convert_sa(arr[i],
+ &(portal->portal_addr), default_port) == NULL) {
+ iscsit_free(portal, sizeof (it_portal_t));
+ ret = EINVAL;
+ break;
+ }
+
+ /* make sure no duplicates */
+ tmp = *portallist;
+ while (tmp) {
+ if (it_sa_compare(&(tmp->portal_addr),
+ &(portal->portal_addr)) == 0) {
+ iscsit_free(portal, sizeof (it_portal_t));
+ portal = NULL;
+ break;
+ }
+ tmp = tmp->portal_next;
+ }
+
+ if (!portal) {
+ continue;
+ }
+
+ /*
+ * The first time through the loop, *portallist == NULL
+ * because we assigned it to NULL above. Subsequently
+ * prev will have been set. Therefor it's OK to put
+ * lint override before prev->portal_next assignment.
+ */
+ if (*portallist == NULL) {
+ *portallist = portal;
+ } else {
+ prev->portal_next = portal;
+ }
+
+ prev = portal;
+ (*list_count)++;
+ }
+
+ return (ret);
+}
+
+/*
+ * Function: it_config_free_cmn()
+ *
+ * Free any resources associated with the it_config_t structure.
+ *
+ * Parameters:
+ * cfg A C representation of the current iSCSI configuration
+ */
+void
+it_config_free_cmn(it_config_t *cfg)
+{
+ if (!cfg) {
+ return;
+ }
+
+ if (cfg->config_tgt_list) {
+ it_tgt_free_cmn(cfg->config_tgt_list);
+ }
+
+ if (cfg->config_tpg_list) {
+ it_tpg_free_cmn(cfg->config_tpg_list);
+ }
+
+ if (cfg->config_ini_list) {
+ it_ini_free_cmn(cfg->config_ini_list);
+ }
+
+ if (cfg->config_global_properties) {
+ nvlist_free(cfg->config_global_properties);
+ }
+
+ if (cfg->config_isns_svr_list) {
+ it_portal_t *pp = cfg->config_isns_svr_list;
+ it_portal_t *pp_next;
+
+ while (pp) {
+ pp_next = pp->portal_next;
+ iscsit_free(pp, sizeof (it_portal_t));
+ pp = pp_next;
+ }
+ }
+
+ iscsit_free(cfg, sizeof (it_config_t));
+}
+
+/*
+ * Function: it_tgt_free_cmn()
+ *
+ * Frees an it_tgt_t structure. If tgt_next is not NULL, frees
+ * all structures in the list.
+ */
+void
+it_tgt_free_cmn(it_tgt_t *tgt)
+{
+ it_tgt_t *tgtp = tgt;
+ it_tgt_t *next;
+
+ if (!tgt) {
+ return;
+ }
+
+ while (tgtp) {
+ next = tgtp->tgt_next;
+
+ if (tgtp->tgt_tpgt_list) {
+ it_tpgt_free_cmn(tgtp->tgt_tpgt_list);
+ }
+
+ if (tgtp->tgt_properties) {
+ nvlist_free(tgtp->tgt_properties);
+ }
+
+ iscsit_free(tgtp, sizeof (it_tgt_t));
+
+ tgtp = next;
+ }
+}
+
+/*
+ * Function: it_tpgt_free_cmn()
+ *
+ * Deallocates resources of an it_tpgt_t structure. If tpgt->next
+ * is not NULL, frees all members of the list.
+ */
+void
+it_tpgt_free_cmn(it_tpgt_t *tpgt)
+{
+ it_tpgt_t *tpgtp = tpgt;
+ it_tpgt_t *next;
+
+ if (!tpgt) {
+ return;
+ }
+
+ while (tpgtp) {
+ next = tpgtp->tpgt_next;
+
+ iscsit_free(tpgtp, sizeof (it_tpgt_t));
+
+ tpgtp = next;
+ }
+}
+
+/*
+ * Function: it_tpg_free_cmn()
+ *
+ * Deallocates resources associated with an it_tpg_t structure.
+ * If tpg->next is not NULL, frees all members of the list.
+ */
+void
+it_tpg_free_cmn(it_tpg_t *tpg)
+{
+ it_tpg_t *tpgp = tpg;
+ it_tpg_t *next;
+ it_portal_t *portalp;
+ it_portal_t *pnext;
+
+ while (tpgp) {
+ next = tpgp->tpg_next;
+
+ portalp = tpgp->tpg_portal_list;
+
+ while (portalp) {
+ pnext = portalp->portal_next;
+ iscsit_free(portalp, sizeof (it_portal_t));
+ portalp = pnext;
+ }
+
+ iscsit_free(tpgp, sizeof (it_tpg_t));
+
+ tpgp = next;
+ }
+}
+
+/*
+ * Function: it_ini_free_cmn()
+ *
+ * Deallocates resources of an it_ini_t structure. If ini->next is
+ * not NULL, frees all members of the list.
+ */
+void
+it_ini_free_cmn(it_ini_t *ini)
+{
+ it_ini_t *inip = ini;
+ it_ini_t *next;
+
+ if (!ini) {
+ return;
+ }
+
+ while (inip) {
+ next = inip->ini_next;
+
+ if (inip->ini_properties) {
+ nvlist_free(inip->ini_properties);
+ }
+
+ iscsit_free(inip, sizeof (it_ini_t));
+
+ inip = next;
+ }
+}