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