xref: /illumos-gate/usr/src/common/iscsi/utils.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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