1*fcf3ce44SJohn Forte /* 2*fcf3ce44SJohn Forte * CDDL HEADER START 3*fcf3ce44SJohn Forte * 4*fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5*fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6*fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7*fcf3ce44SJohn Forte * 8*fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10*fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11*fcf3ce44SJohn Forte * and limitations under the License. 12*fcf3ce44SJohn Forte * 13*fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14*fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16*fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17*fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18*fcf3ce44SJohn Forte * 19*fcf3ce44SJohn Forte * CDDL HEADER END 20*fcf3ce44SJohn Forte */ 21*fcf3ce44SJohn Forte /* 22*fcf3ce44SJohn Forte * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*fcf3ce44SJohn Forte * Use is subject to license terms. 24*fcf3ce44SJohn Forte */ 25*fcf3ce44SJohn Forte 26*fcf3ce44SJohn Forte #include <sys/types.h> 27*fcf3ce44SJohn Forte #include <sys/socket.h> 28*fcf3ce44SJohn Forte 29*fcf3ce44SJohn Forte 30*fcf3ce44SJohn Forte #ifdef _KERNEL 31*fcf3ce44SJohn Forte #include <sys/sunddi.h> 32*fcf3ce44SJohn Forte #else 33*fcf3ce44SJohn Forte #include <stdio.h> 34*fcf3ce44SJohn Forte #include <stdlib.h> 35*fcf3ce44SJohn Forte #include <strings.h> 36*fcf3ce44SJohn Forte #include <ctype.h> 37*fcf3ce44SJohn Forte #include <netinet/in.h> 38*fcf3ce44SJohn Forte #include <sys/utsname.h> 39*fcf3ce44SJohn Forte 40*fcf3ce44SJohn Forte /* 41*fcf3ce44SJohn Forte * NOTE: This routine is found in libnsl. There's apparently no prototype to 42*fcf3ce44SJohn Forte * be found in any of the header files in /usr/include so defining a prototype 43*fcf3ce44SJohn Forte * here to keep the compiler happy. 44*fcf3ce44SJohn Forte */ 45*fcf3ce44SJohn Forte int getdomainname(char *, int); 46*fcf3ce44SJohn Forte 47*fcf3ce44SJohn Forte static const char *iqn_template = "iqn.2004-02.%s"; 48*fcf3ce44SJohn Forte #endif 49*fcf3ce44SJohn Forte 50*fcf3ce44SJohn Forte #include <sys/scsi/adapters/iscsi_if.h> 51*fcf3ce44SJohn Forte 52*fcf3ce44SJohn Forte typedef struct utils_val_name { 53*fcf3ce44SJohn Forte int u_val; 54*fcf3ce44SJohn Forte char *u_name; 55*fcf3ce44SJohn Forte } utils_val_name_t; 56*fcf3ce44SJohn Forte 57*fcf3ce44SJohn Forte utils_val_name_t param_names[] = { 58*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER, "Sequence In Order"}, 59*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_IMMEDIATE_DATA, "Immediate Data"}, 60*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_INITIAL_R2T, "Inital R2T"}, 61*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER, "Data PDU In Order"}, 62*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_HEADER_DIGEST, "Header Digest"}, 63*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_DATA_DIGEST, "Data Digest"}, 64*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN, "Default Time To Retain"}, 65*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT, "Default Time To Wait"}, 66*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH, 67*fcf3ce44SJohn Forte "Max Recv Data Segment Length"}, 68*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH, "First Burst Length"}, 69*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH, "Max Burst Length"}, 70*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_MAX_CONNECTIONS, "Max Connections"}, 71*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_OUTSTANDING_R2T, "Outstanding R2T"}, 72*fcf3ce44SJohn Forte { ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL, "Error Recovery Level"}, 73*fcf3ce44SJohn Forte { 0, NULL } 74*fcf3ce44SJohn Forte }; 75*fcf3ce44SJohn Forte 76*fcf3ce44SJohn Forte /* 77*fcf3ce44SJohn Forte * utils_map_param -- Given a parameter return it's ascii name 78*fcf3ce44SJohn Forte * 79*fcf3ce44SJohn Forte * This routine was created because previously an array contained in order 80*fcf3ce44SJohn Forte * the parameter names. Once or twice the parameters value changed which 81*fcf3ce44SJohn Forte * changed the order, but not the array. To avoid further confusion we'll 82*fcf3ce44SJohn Forte * do a simple lookup. This code is rarely called so it shouldn't be an 83*fcf3ce44SJohn Forte * issue. 84*fcf3ce44SJohn Forte */ 85*fcf3ce44SJohn Forte char * 86*fcf3ce44SJohn Forte utils_map_param(int p) 87*fcf3ce44SJohn Forte { 88*fcf3ce44SJohn Forte utils_val_name_t *pn; 89*fcf3ce44SJohn Forte 90*fcf3ce44SJohn Forte for (pn = param_names; pn->u_name != NULL; pn++) 91*fcf3ce44SJohn Forte if (pn->u_val == p) 92*fcf3ce44SJohn Forte return (pn->u_name); 93*fcf3ce44SJohn Forte return (NULL); 94*fcf3ce44SJohn Forte } 95*fcf3ce44SJohn Forte 96*fcf3ce44SJohn Forte /* 97*fcf3ce44SJohn Forte * prt_bitmap -- print out ascii strings associated with bit numbers. 98*fcf3ce44SJohn Forte */ 99*fcf3ce44SJohn Forte char * 100*fcf3ce44SJohn Forte prt_bitmap(int bitmap, char *str, char *buf, int size) 101*fcf3ce44SJohn Forte { 102*fcf3ce44SJohn Forte char *p = NULL; 103*fcf3ce44SJohn Forte char *start = buf; 104*fcf3ce44SJohn Forte int do_put = 0; 105*fcf3ce44SJohn Forte 106*fcf3ce44SJohn Forte /* 107*fcf3ce44SJohn Forte * The maximum space required will if the bitmap was all 1's which 108*fcf3ce44SJohn Forte * would cause the octal characters to be replaced by '|'. So make 109*fcf3ce44SJohn Forte * sure the buffer has enough space. 110*fcf3ce44SJohn Forte */ 111*fcf3ce44SJohn Forte if (size < strlen(str)) 112*fcf3ce44SJohn Forte return ("No room"); 113*fcf3ce44SJohn Forte 114*fcf3ce44SJohn Forte for (p = str; size--; p++) { 115*fcf3ce44SJohn Forte if (*p < 0x20) { 116*fcf3ce44SJohn Forte 117*fcf3ce44SJohn Forte /* 118*fcf3ce44SJohn Forte * if we have been putting out stuff add separator 119*fcf3ce44SJohn Forte */ 120*fcf3ce44SJohn Forte if (do_put) 121*fcf3ce44SJohn Forte *buf++ = '|'; 122*fcf3ce44SJohn Forte 123*fcf3ce44SJohn Forte do_put = ((1 << *p) & bitmap); 124*fcf3ce44SJohn Forte bitmap &= ~(1 << *p); 125*fcf3ce44SJohn Forte 126*fcf3ce44SJohn Forte } else if (do_put) 127*fcf3ce44SJohn Forte *buf++ = *p; 128*fcf3ce44SJohn Forte } 129*fcf3ce44SJohn Forte 130*fcf3ce44SJohn Forte /* ---- remove the last separator if it was added ---- */ 131*fcf3ce44SJohn Forte if ((buf > start) && (*(buf - 1) == '|')) 132*fcf3ce44SJohn Forte buf--; 133*fcf3ce44SJohn Forte *buf = '\0'; 134*fcf3ce44SJohn Forte return (start); 135*fcf3ce44SJohn Forte } 136*fcf3ce44SJohn Forte 137*fcf3ce44SJohn Forte /* 138*fcf3ce44SJohn Forte * parse_addr_port_tpgt - Used to parse addr, port and tpgt from string 139*fcf3ce44SJohn Forte * 140*fcf3ce44SJohn Forte * This function is used to parse addr, port and tpgt from a string. Callers 141*fcf3ce44SJohn Forte * of this function are the sendtargets and login redirection code. The 142*fcf3ce44SJohn Forte * caller must be aware that this function will modify the callers string 143*fcf3ce44SJohn Forte * to insert NULL terminators if required. Port and TPGT are optional. 144*fcf3ce44SJohn Forte */ 145*fcf3ce44SJohn Forte boolean_t 146*fcf3ce44SJohn Forte parse_addr_port_tpgt(char *in, char **addr, int *type, char **port, char **tpgt) 147*fcf3ce44SJohn Forte { 148*fcf3ce44SJohn Forte char *t_port, *t_tpgt; 149*fcf3ce44SJohn Forte 150*fcf3ce44SJohn Forte /* default return values if requested */ 151*fcf3ce44SJohn Forte if (addr == NULL) { 152*fcf3ce44SJohn Forte return (B_FALSE); 153*fcf3ce44SJohn Forte } else { 154*fcf3ce44SJohn Forte *addr = NULL; 155*fcf3ce44SJohn Forte } 156*fcf3ce44SJohn Forte if (port != NULL) { 157*fcf3ce44SJohn Forte *port = NULL; 158*fcf3ce44SJohn Forte } 159*fcf3ce44SJohn Forte if (tpgt != NULL) { 160*fcf3ce44SJohn Forte *tpgt = NULL; 161*fcf3ce44SJohn Forte } 162*fcf3ce44SJohn Forte 163*fcf3ce44SJohn Forte /* extract ip or domain name */ 164*fcf3ce44SJohn Forte if (*in == '[') { 165*fcf3ce44SJohn Forte /* IPV6 */ 166*fcf3ce44SJohn Forte *type = AF_INET6; 167*fcf3ce44SJohn Forte *addr = ++in; 168*fcf3ce44SJohn Forte in = strchr(*addr, ']'); 169*fcf3ce44SJohn Forte if (in == NULL) 170*fcf3ce44SJohn Forte return (B_FALSE); 171*fcf3ce44SJohn Forte *in++ = '\0'; 172*fcf3ce44SJohn Forte } else { 173*fcf3ce44SJohn Forte /* IPV4 or domainname */ 174*fcf3ce44SJohn Forte *type = AF_INET; 175*fcf3ce44SJohn Forte *addr = in; 176*fcf3ce44SJohn Forte } 177*fcf3ce44SJohn Forte 178*fcf3ce44SJohn Forte /* extract port */ 179*fcf3ce44SJohn Forte if (port != NULL) { 180*fcf3ce44SJohn Forte t_port = strchr(in, ':'); 181*fcf3ce44SJohn Forte if (t_port != NULL) { 182*fcf3ce44SJohn Forte *t_port++ = '\0'; 183*fcf3ce44SJohn Forte *port = in = t_port; 184*fcf3ce44SJohn Forte } 185*fcf3ce44SJohn Forte } 186*fcf3ce44SJohn Forte 187*fcf3ce44SJohn Forte /* exact tpgt */ 188*fcf3ce44SJohn Forte if (tpgt != NULL) { 189*fcf3ce44SJohn Forte t_tpgt = strchr(in, ','); 190*fcf3ce44SJohn Forte if (t_tpgt != NULL) { 191*fcf3ce44SJohn Forte *t_tpgt++ = '\0'; 192*fcf3ce44SJohn Forte *tpgt = in = t_tpgt; 193*fcf3ce44SJohn Forte } 194*fcf3ce44SJohn Forte } 195*fcf3ce44SJohn Forte 196*fcf3ce44SJohn Forte return (B_TRUE); 197*fcf3ce44SJohn Forte } 198*fcf3ce44SJohn Forte 199*fcf3ce44SJohn Forte #ifndef _KERNEL 200*fcf3ce44SJohn Forte /* 201*fcf3ce44SJohn Forte * []--------------------------------------------------------------[] 202*fcf3ce44SJohn Forte * | reverse_fqdn -- given a fully qualified domain name reverse it | 203*fcf3ce44SJohn Forte * | | 204*fcf3ce44SJohn Forte * | The routine has the obvious problem that it can only handle a | 205*fcf3ce44SJohn Forte * | name with 5 or less dots. This needs to be fixed by counting | 206*fcf3ce44SJohn Forte * | the number of dots in the incoming name, calloc'ing an array | 207*fcf3ce44SJohn Forte * | of the appropriate size and then handling the pointers. | 208*fcf3ce44SJohn Forte * []--------------------------------------------------------------[] 209*fcf3ce44SJohn Forte */ 210*fcf3ce44SJohn Forte static boolean_t 211*fcf3ce44SJohn Forte /* LINTED E_FUNC_ARG_UNUSED for 3rd arg size */ 212*fcf3ce44SJohn Forte reverse_fqdn(const char *domain, char *buf, int size) 213*fcf3ce44SJohn Forte { 214*fcf3ce44SJohn Forte char *ptrs[5]; 215*fcf3ce44SJohn Forte char *dp; 216*fcf3ce44SJohn Forte char *dp1; 217*fcf3ce44SJohn Forte char *p; 218*fcf3ce44SJohn Forte int v = 4; 219*fcf3ce44SJohn Forte 220*fcf3ce44SJohn Forte if ((dp = dp1 = malloc(strlen(domain) + 1)) == NULL) 221*fcf3ce44SJohn Forte return (B_FALSE); 222*fcf3ce44SJohn Forte (void) strcpy(dp, domain); 223*fcf3ce44SJohn Forte while ((p = (char *)strchr(dp, '.')) != NULL) { 224*fcf3ce44SJohn Forte *p = '\0'; 225*fcf3ce44SJohn Forte if (v < 0) { 226*fcf3ce44SJohn Forte free(dp1); 227*fcf3ce44SJohn Forte return (B_FALSE); 228*fcf3ce44SJohn Forte } 229*fcf3ce44SJohn Forte ptrs[v--] = dp; 230*fcf3ce44SJohn Forte dp = p + 1; 231*fcf3ce44SJohn Forte } 232*fcf3ce44SJohn Forte (void) strcpy(buf, dp); 233*fcf3ce44SJohn Forte for (v++; v < 5; v++) { 234*fcf3ce44SJohn Forte (void) strcat(buf, "."); 235*fcf3ce44SJohn Forte (void) strcat(buf, ptrs[v]); 236*fcf3ce44SJohn Forte } 237*fcf3ce44SJohn Forte free(dp1); 238*fcf3ce44SJohn Forte return (B_TRUE); 239*fcf3ce44SJohn Forte } 240*fcf3ce44SJohn Forte 241*fcf3ce44SJohn Forte /* 242*fcf3ce44SJohn Forte * []------------------------------------------------------------------[] 243*fcf3ce44SJohn Forte * | utils_iqn_create -- returns an iqn name for the machine | 244*fcf3ce44SJohn Forte * | | 245*fcf3ce44SJohn Forte * | The information found in the iqn is not correct. The year and | 246*fcf3ce44SJohn Forte * | date should be flexible. Currently this is hardwired to the | 247*fcf3ce44SJohn Forte * | current year and month of this project. | 248*fcf3ce44SJohn Forte * []------------------------------------------------------------------[] 249*fcf3ce44SJohn Forte */ 250*fcf3ce44SJohn Forte boolean_t 251*fcf3ce44SJohn Forte utils_iqn_create(char *iqn_buf, int size) 252*fcf3ce44SJohn Forte { 253*fcf3ce44SJohn Forte struct utsname uts_info; 254*fcf3ce44SJohn Forte char domainname[256]; 255*fcf3ce44SJohn Forte char *temp = NULL; 256*fcf3ce44SJohn Forte char *p; 257*fcf3ce44SJohn Forte char *pmet = NULL; /* temp reversed .. get it */ 258*fcf3ce44SJohn Forte int len; 259*fcf3ce44SJohn Forte boolean_t rval = B_FALSE; /* Default */ 260*fcf3ce44SJohn Forte 261*fcf3ce44SJohn Forte if (uname(&uts_info) == -1) { 262*fcf3ce44SJohn Forte goto out; 263*fcf3ce44SJohn Forte } 264*fcf3ce44SJohn Forte 265*fcf3ce44SJohn Forte if (getdomainname(domainname, sizeof (domainname))) { 266*fcf3ce44SJohn Forte goto out; 267*fcf3ce44SJohn Forte } 268*fcf3ce44SJohn Forte 269*fcf3ce44SJohn Forte if ((temp = malloc(strlen(uts_info.nodename) + 270*fcf3ce44SJohn Forte strlen(domainname) + 2)) == NULL) { 271*fcf3ce44SJohn Forte goto out; 272*fcf3ce44SJohn Forte } 273*fcf3ce44SJohn Forte 274*fcf3ce44SJohn Forte /* 275*fcf3ce44SJohn Forte * getdomainname always returns something in the order of 276*fcf3ce44SJohn Forte * host.domainname so we need to skip over that portion of the 277*fcf3ce44SJohn Forte * host name because we don't care about it. 278*fcf3ce44SJohn Forte */ 279*fcf3ce44SJohn Forte if ((p = strchr(domainname, '.')) == NULL) 280*fcf3ce44SJohn Forte p = domainname; 281*fcf3ce44SJohn Forte else 282*fcf3ce44SJohn Forte p++; 283*fcf3ce44SJohn Forte 284*fcf3ce44SJohn Forte /* ---- Create Fully Qualified Domain Name ---- */ 285*fcf3ce44SJohn Forte (void) snprintf(temp, strlen(p), "%s.%s", uts_info.nodename, p); 286*fcf3ce44SJohn Forte 287*fcf3ce44SJohn Forte /* ---- According to the spec, names must be lower case ---- */ 288*fcf3ce44SJohn Forte for (p = temp; *p; p++) 289*fcf3ce44SJohn Forte if (isupper(*p)) 290*fcf3ce44SJohn Forte *p = tolower(*p); 291*fcf3ce44SJohn Forte 292*fcf3ce44SJohn Forte len = strlen(temp) + 1; 293*fcf3ce44SJohn Forte if ((pmet = malloc(len)) == NULL) { 294*fcf3ce44SJohn Forte goto out; 295*fcf3ce44SJohn Forte } 296*fcf3ce44SJohn Forte 297*fcf3ce44SJohn Forte if (reverse_fqdn(temp, pmet, len) == B_FALSE) { 298*fcf3ce44SJohn Forte goto out; 299*fcf3ce44SJohn Forte } 300*fcf3ce44SJohn Forte 301*fcf3ce44SJohn Forte /* 302*fcf3ce44SJohn Forte * Now use the template with the reversed domainname to create 303*fcf3ce44SJohn Forte * an iSCSI name using the IQN format. Only count it a success 304*fcf3ce44SJohn Forte * if the number of characters formated is less than the buffer 305*fcf3ce44SJohn Forte * size. 306*fcf3ce44SJohn Forte */ 307*fcf3ce44SJohn Forte if (snprintf(iqn_buf, size, iqn_template, pmet) <= size) 308*fcf3ce44SJohn Forte rval = B_TRUE; 309*fcf3ce44SJohn Forte out: 310*fcf3ce44SJohn Forte if (temp) 311*fcf3ce44SJohn Forte free(temp); 312*fcf3ce44SJohn Forte if (pmet) 313*fcf3ce44SJohn Forte free(pmet); 314*fcf3ce44SJohn Forte 315*fcf3ce44SJohn Forte return (rval); 316*fcf3ce44SJohn Forte } 317*fcf3ce44SJohn Forte #endif /* !_KERNEL */ 318