/* * 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 #include #ifdef _KERNEL #include #else #include #include #include #include #include #include /* * 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 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 */