summaryrefslogtreecommitdiff
path: root/usr/src/common/iscsi/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/common/iscsi/utils.c')
-rw-r--r--usr/src/common/iscsi/utils.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/usr/src/common/iscsi/utils.c b/usr/src/common/iscsi/utils.c
new file mode 100644
index 0000000000..e1106be9fc
--- /dev/null
+++ b/usr/src/common/iscsi/utils.c
@@ -0,0 +1,317 @@
+/*
+ * 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>
+#include <sys/socket.h>
+
+
+#ifdef _KERNEL
+#include <sys/sunddi.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <sys/utsname.h>
+
+/*
+ * NOTE: This routine is found in libnsl. There's apparently no prototype to
+ * be found in any of the header files in /usr/include so defining a prototype
+ * here to keep the compiler happy.
+ */
+int getdomainname(char *, int);
+
+static const char *iqn_template = "iqn.2004-02.%s";
+#endif
+
+#include <sys/scsi/adapters/iscsi_if.h>
+
+typedef struct utils_val_name {
+ int u_val;
+ char *u_name;
+} utils_val_name_t;
+
+utils_val_name_t param_names[] = {
+ { ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER, "Sequence In Order"},
+ { ISCSI_LOGIN_PARAM_IMMEDIATE_DATA, "Immediate Data"},
+ { ISCSI_LOGIN_PARAM_INITIAL_R2T, "Inital R2T"},
+ { ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER, "Data PDU In Order"},
+ { ISCSI_LOGIN_PARAM_HEADER_DIGEST, "Header Digest"},
+ { ISCSI_LOGIN_PARAM_DATA_DIGEST, "Data Digest"},
+ { ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN, "Default Time To Retain"},
+ { ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT, "Default Time To Wait"},
+ { ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH,
+ "Max Recv Data Segment Length"},
+ { ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH, "First Burst Length"},
+ { ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH, "Max Burst Length"},
+ { ISCSI_LOGIN_PARAM_MAX_CONNECTIONS, "Max Connections"},
+ { ISCSI_LOGIN_PARAM_OUTSTANDING_R2T, "Outstanding R2T"},
+ { ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL, "Error Recovery Level"},
+ { 0, NULL }
+};
+
+/*
+ * utils_map_param -- Given a parameter return it's ascii name
+ *
+ * This routine was created because previously an array contained in order
+ * the parameter names. Once or twice the parameters value changed which
+ * changed the order, but not the array. To avoid further confusion we'll
+ * do a simple lookup. This code is rarely called so it shouldn't be an
+ * issue.
+ */
+char *
+utils_map_param(int p)
+{
+ utils_val_name_t *pn;
+
+ for (pn = param_names; pn->u_name != NULL; pn++)
+ if (pn->u_val == p)
+ return (pn->u_name);
+ return (NULL);
+}
+
+/*
+ * prt_bitmap -- print out ascii strings associated with bit numbers.
+ */
+char *
+prt_bitmap(int bitmap, char *str, char *buf, int size)
+{
+ char *p = NULL;
+ char *start = buf;
+ int do_put = 0;
+
+ /*
+ * The maximum space required will if the bitmap was all 1's which
+ * would cause the octal characters to be replaced by '|'. So make
+ * sure the buffer has enough space.
+ */
+ if (size < strlen(str))
+ return ("No room");
+
+ for (p = str; size--; p++) {
+ if (*p < 0x20) {
+
+ /*
+ * if we have been putting out stuff add separator
+ */
+ if (do_put)
+ *buf++ = '|';
+
+ do_put = ((1 << *p) & bitmap);
+ bitmap &= ~(1 << *p);
+
+ } else if (do_put)
+ *buf++ = *p;
+ }
+
+ /* ---- remove the last separator if it was added ---- */
+ if ((buf > start) && (*(buf - 1) == '|'))
+ buf--;
+ *buf = '\0';
+ return (start);
+}
+
+/*
+ * parse_addr_port_tpgt - Used to parse addr, port and tpgt from string
+ *
+ * This function is used to parse addr, port and tpgt from a string. Callers
+ * of this function are the sendtargets and login redirection code. The
+ * caller must be aware that this function will modify the callers string
+ * to insert NULL terminators if required. Port and TPGT are optional.
+ */
+boolean_t
+parse_addr_port_tpgt(char *in, char **addr, int *type, char **port, char **tpgt)
+{
+ char *t_port, *t_tpgt;
+
+ /* default return values if requested */
+ if (addr == NULL) {
+ return (B_FALSE);
+ } else {
+ *addr = NULL;
+ }
+ if (port != NULL) {
+ *port = NULL;
+ }
+ if (tpgt != NULL) {
+ *tpgt = NULL;
+ }
+
+ /* extract ip or domain name */
+ if (*in == '[') {
+ /* IPV6 */
+ *type = AF_INET6;
+ *addr = ++in;
+ in = strchr(*addr, ']');
+ if (in == NULL)
+ return (B_FALSE);
+ *in++ = '\0';
+ } else {
+ /* IPV4 or domainname */
+ *type = AF_INET;
+ *addr = in;
+ }
+
+ /* extract port */
+ if (port != NULL) {
+ t_port = strchr(in, ':');
+ if (t_port != NULL) {
+ *t_port++ = '\0';
+ *port = in = t_port;
+ }
+ }
+
+ /* exact tpgt */
+ if (tpgt != NULL) {
+ t_tpgt = strchr(in, ',');
+ if (t_tpgt != NULL) {
+ *t_tpgt++ = '\0';
+ *tpgt = in = t_tpgt;
+ }
+ }
+
+ return (B_TRUE);
+}
+
+#ifndef _KERNEL
+/*
+ * []--------------------------------------------------------------[]
+ * | reverse_fqdn -- given a fully qualified domain name reverse it |
+ * | |
+ * | The routine has the obvious problem that it can only handle a |
+ * | name with 5 or less dots. This needs to be fixed by counting |
+ * | the number of dots in the incoming name, calloc'ing an array |
+ * | of the appropriate size and then handling the pointers. |
+ * []--------------------------------------------------------------[]
+ */
+static boolean_t
+/* LINTED E_FUNC_ARG_UNUSED for 3rd arg size */
+reverse_fqdn(const char *domain, char *buf, int size)
+{
+ char *ptrs[5];
+ char *dp;
+ char *dp1;
+ char *p;
+ int v = 4;
+
+ if ((dp = dp1 = malloc(strlen(domain) + 1)) == NULL)
+ return (B_FALSE);
+ (void) strcpy(dp, domain);
+ while ((p = (char *)strchr(dp, '.')) != NULL) {
+ *p = '\0';
+ if (v < 0) {
+ free(dp1);
+ return (B_FALSE);
+ }
+ ptrs[v--] = dp;
+ dp = p + 1;
+ }
+ (void) strcpy(buf, dp);
+ for (v++; v < 5; v++) {
+ (void) strcat(buf, ".");
+ (void) strcat(buf, ptrs[v]);
+ }
+ free(dp1);
+ return (B_TRUE);
+}
+
+/*
+ * []------------------------------------------------------------------[]
+ * | utils_iqn_create -- returns an iqn name for the machine |
+ * | |
+ * | The information found in the iqn is not correct. The year and |
+ * | date should be flexible. Currently this is hardwired to the |
+ * | current year and month of this project. |
+ * []------------------------------------------------------------------[]
+ */
+boolean_t
+utils_iqn_create(char *iqn_buf, int size)
+{
+ struct utsname uts_info;
+ char domainname[256];
+ char *temp = NULL;
+ char *p;
+ char *pmet = NULL; /* temp reversed .. get it */
+ int len;
+ boolean_t rval = B_FALSE; /* Default */
+
+ if (uname(&uts_info) == -1) {
+ goto out;
+ }
+
+ if (getdomainname(domainname, sizeof (domainname))) {
+ goto out;
+ }
+
+ if ((temp = malloc(strlen(uts_info.nodename) +
+ strlen(domainname) + 2)) == NULL) {
+ goto out;
+ }
+
+ /*
+ * getdomainname always returns something in the order of
+ * host.domainname so we need to skip over that portion of the
+ * host name because we don't care about it.
+ */
+ if ((p = strchr(domainname, '.')) == NULL)
+ p = domainname;
+ else
+ p++;
+
+ /* ---- Create Fully Qualified Domain Name ---- */
+ (void) snprintf(temp, strlen(p), "%s.%s", uts_info.nodename, p);
+
+ /* ---- According to the spec, names must be lower case ---- */
+ for (p = temp; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ len = strlen(temp) + 1;
+ if ((pmet = malloc(len)) == NULL) {
+ goto out;
+ }
+
+ if (reverse_fqdn(temp, pmet, len) == B_FALSE) {
+ goto out;
+ }
+
+ /*
+ * Now use the template with the reversed domainname to create
+ * an iSCSI name using the IQN format. Only count it a success
+ * if the number of characters formated is less than the buffer
+ * size.
+ */
+ if (snprintf(iqn_buf, size, iqn_template, pmet) <= size)
+ rval = B_TRUE;
+out:
+ if (temp)
+ free(temp);
+ if (pmet)
+ free(pmet);
+
+ return (rval);
+}
+#endif /* !_KERNEL */