1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Commmon routines, handling iscsi boot props
29  */
30 
31 #include <sys/types.h>
32 #include <sys/null.h>
33 #include <sys/bootprops.h>
34 #include <sys/cmn_err.h>
35 #include <sys/socket.h>
36 #include <sys/kmem.h>
37 #include <netinet/in.h>
38 
39 extern void *memset(void *s, int c, size_t n);
40 extern int memcmp(const void *s1, const void *s2, size_t n);
41 extern void bcopy(const void *s1, void *s2, size_t n);
42 extern size_t strlen(const char *s);
43 static void kinet_ntoa(char *buf, void *in, int af);
44 extern ib_boot_prop_t *iscsiboot_prop;
45 
46 int  iscsi_print_bootprop	=	0;
47 
48 #define	ISCSI_BOOTPROP_BUFLEN	256
49 
50 static int replace_sp_c(unsigned char *dst, unsigned char *source, size_t n);
51 
52 static void
iscsi_bootprop_print(int level,char * str)53 iscsi_bootprop_print(int level, char *str)
54 {
55 	if (str == NULL) {
56 		return;
57 	}
58 	if (iscsi_print_bootprop == 1) {
59 		cmn_err(level, "%s", str);
60 	}
61 }
62 
63 static void
iscsi_print_initiator_property(ib_ini_prop_t * ibinitp)64 iscsi_print_initiator_property(ib_ini_prop_t *ibinitp)
65 {
66 	char	outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
67 
68 	if (ibinitp == NULL) {
69 		return;
70 	}
71 
72 	if (ibinitp->ini_name != NULL) {
73 		(void) sprintf(outbuf,
74 		    "Initiator Name : %s\n",
75 		    ibinitp->ini_name);
76 		iscsi_bootprop_print(CE_CONT, outbuf);
77 	}
78 
79 	if (ibinitp->ini_chap_name != NULL) {
80 		(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
81 		(void) sprintf(outbuf,
82 		    "Initiator CHAP Name  : %s\n",
83 		    ibinitp->ini_chap_name);
84 
85 		iscsi_bootprop_print(CE_CONT, outbuf);
86 	}
87 }
88 
89 static void
iscsi_print_nic_property(ib_nic_prop_t * nicp)90 iscsi_print_nic_property(ib_nic_prop_t *nicp)
91 {
92 	char	outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
93 	char	ipaddr[50]  =	{0};
94 	int	n	    =	0;
95 
96 	if (nicp == NULL) {
97 		return;
98 	}
99 
100 	kinet_ntoa(ipaddr, &nicp->nic_ip_u, nicp->sin_family);
101 	n = snprintf(outbuf, ISCSI_BOOTPROP_BUFLEN,
102 	    "Local IP addr  : %s\n", ipaddr);
103 
104 	(void) memset(ipaddr, 0, 50);
105 	kinet_ntoa(ipaddr, &nicp->nic_gw_u, nicp->sin_family);
106 	n = n + snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
107 	    "Local gateway  : %s\n", ipaddr);
108 
109 	(void) memset(ipaddr, 0, 50);
110 	kinet_ntoa(ipaddr, &nicp->nic_dhcp_u, nicp->sin_family);
111 	n = n + snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
112 	    "Local DHCP     : %s\n", ipaddr);
113 
114 	(void) snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
115 	    "Local MAC      : %02x:%02x:%02x:%02x:%02x:%02x\n",
116 	    nicp->nic_mac[0],
117 	    nicp->nic_mac[1],
118 	    nicp->nic_mac[2],
119 	    nicp->nic_mac[3],
120 	    nicp->nic_mac[4],
121 	    nicp->nic_mac[5]);
122 
123 	iscsi_bootprop_print(CE_CONT, outbuf);
124 }
125 
126 static void
iscsi_print_tgt_property(ib_tgt_prop_t * itgtp)127 iscsi_print_tgt_property(ib_tgt_prop_t *itgtp)
128 {
129 	char	outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
130 	char	ipaddr[50]  =	{0};
131 
132 	if (itgtp == NULL) {
133 		return;
134 	}
135 
136 	if (itgtp->tgt_name != NULL) {
137 		(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
138 		(void) sprintf(outbuf,
139 		    "Target Name    : %s\n",
140 		    itgtp->tgt_name);
141 		iscsi_bootprop_print(CE_CONT, outbuf);
142 	}
143 
144 	kinet_ntoa(ipaddr, &itgtp->tgt_ip_u, itgtp->sin_family);
145 	(void) sprintf(outbuf,
146 	    "Target IP      : %s\n"
147 	    "Target Port    : %d\n"
148 	    "Boot LUN       : %02x%02x-%02x%02x-%02x%02x-%02x%02x\n",
149 	    ipaddr,
150 	    itgtp->tgt_port,
151 	    itgtp->tgt_boot_lun[0],
152 	    itgtp->tgt_boot_lun[1],
153 	    itgtp->tgt_boot_lun[2],
154 	    itgtp->tgt_boot_lun[3],
155 	    itgtp->tgt_boot_lun[4],
156 	    itgtp->tgt_boot_lun[5],
157 	    itgtp->tgt_boot_lun[6],
158 	    itgtp->tgt_boot_lun[7]);
159 	iscsi_bootprop_print(CE_CONT, outbuf);
160 
161 	if (itgtp->tgt_chap_name != NULL) {
162 		(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
163 		(void) sprintf(outbuf,
164 		    "CHAP Name      : %s\n",
165 		    itgtp->tgt_chap_name);
166 		iscsi_bootprop_print(CE_CONT, outbuf);
167 	}
168 }
169 
170 void
iscsi_print_boot_property()171 iscsi_print_boot_property()
172 {
173 	if (iscsiboot_prop == NULL) {
174 		return;
175 	}
176 
177 	iscsi_print_initiator_property(
178 	    &iscsiboot_prop->boot_init);
179 
180 	iscsi_print_nic_property(&iscsiboot_prop->boot_nic);
181 
182 	iscsi_print_tgt_property(&iscsiboot_prop->boot_tgt);
183 }
184 
185 void
iscsi_boot_free_ini(ib_ini_prop_t * init)186 iscsi_boot_free_ini(ib_ini_prop_t *init)
187 {
188 	if (init == NULL) {
189 		return;
190 	}
191 
192 	if (init->ini_name != NULL) {
193 		kmem_free(init->ini_name, init->ini_name_len);
194 		init->ini_name = NULL;
195 		init->ini_name_len = 0;
196 	}
197 	if (init->ini_chap_name != NULL) {
198 		kmem_free(init->ini_chap_name,
199 		    init->ini_chap_name_len);
200 		init->ini_chap_name = NULL;
201 		init->ini_chap_name_len = 0;
202 	}
203 	if (init->ini_chap_sec != NULL) {
204 		kmem_free(init->ini_chap_sec,
205 		    init->ini_chap_sec_len);
206 		init->ini_chap_sec = NULL;
207 		init->ini_chap_sec_len = 0;
208 	}
209 }
210 
211 void
iscsi_boot_free_tgt(ib_tgt_prop_t * target)212 iscsi_boot_free_tgt(ib_tgt_prop_t *target)
213 {
214 	if (target == NULL) {
215 		return;
216 	}
217 
218 	if (target->tgt_name != NULL) {
219 		kmem_free(target->tgt_name,
220 		    target->tgt_name_len);
221 		target->tgt_name = NULL;
222 		target->tgt_name_len = 0;
223 	}
224 	if (target->tgt_chap_name != NULL) {
225 		kmem_free(target->tgt_chap_name,
226 		    target->tgt_chap_name_len);
227 		target->tgt_chap_name = NULL;
228 		target->tgt_chap_name_len = 0;
229 	}
230 	if (target->tgt_chap_sec != NULL) {
231 		kmem_free(target->tgt_chap_sec,
232 		    target->tgt_chap_sec_len);
233 		target->tgt_chap_sec = NULL;
234 		target->tgt_chap_sec_len = 0;
235 	}
236 	if (target->tgt_boot_par != NULL) {
237 		kmem_free(target->tgt_boot_par,
238 		    target->tgt_boot_par_len);
239 		target->tgt_boot_par = NULL;
240 		target->tgt_boot_par_len = 0;
241 	}
242 }
243 
244 /*
245  * Free the memory used by boot property.
246  */
247 void
iscsi_boot_prop_free()248 iscsi_boot_prop_free()
249 {
250 	ib_boot_prop_t	*tmp;
251 
252 	if (iscsiboot_prop == NULL) {
253 		return;
254 	}
255 	tmp = iscsiboot_prop;
256 	iscsiboot_prop = NULL;
257 	iscsi_boot_free_ini(&(tmp->boot_init));
258 	iscsi_boot_free_tgt(&(tmp->boot_tgt));
259 }
260 
261 static void
kinet_ntoa(char * buf,void * in,int af)262 kinet_ntoa(char *buf, void *in, int af)
263 {
264 	unsigned char   *p =    NULL;
265 	int	i = 0;
266 
267 	if (buf == NULL || in == NULL) {
268 		return;
269 	}
270 	p = (unsigned char *)in;
271 	if (af == AF_INET) {
272 		(void) sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
273 	} else {
274 		for (i = 0; i < 14; i = i + 2) {
275 			(void) sprintf(buf, "%02x%02x:", p[i], p[i+1]);
276 			buf = buf + 5;
277 		}
278 		(void) sprintf(buf, "%02x%02x", p[i], p[i+1]);
279 	}
280 }
281 
282 #ifndef	BO_MAXOBJNAME
283 #define	BO_MAXOBJNAME	256
284 #endif
285 
286 #ifndef ISCSI_BOOT_ISID
287 #define	ISCSI_BOOT_ISID	"0000"
288 #endif
289 
290 /*
291  * Generate the 'ssd' bootpath of an iSCSI boot device
292  * The caller is responsible to alloc the buf with BO_MAXOBJNAME length
293  */
294 void
get_iscsi_bootpath_vhci(char * bootpath)295 get_iscsi_bootpath_vhci(char *bootpath)
296 {
297 	uint16_t	*lun_num;
298 
299 	if (iscsiboot_prop == NULL)
300 		ld_ib_prop();
301 	if (iscsiboot_prop == NULL)
302 		return;
303 	lun_num = (uint16_t *)(&iscsiboot_prop->boot_tgt.tgt_boot_lun[0]);
304 	(void) snprintf(bootpath, BO_MAXOBJNAME, "/iscsi/ssd@%s%s%04X,%d:%s",
305 	    ISCSI_BOOT_ISID, iscsiboot_prop->boot_tgt.tgt_name,
306 	    iscsiboot_prop->boot_tgt.tgt_tpgt, lun_num[0],
307 	    iscsiboot_prop->boot_tgt.tgt_boot_par);
308 }
309 
310 /*
311  * Generate the 'disk' bootpath of an iSCSI boot device
312  * The caller is responsible to alloc the buf with BO_MAXOBJNAME length
313  */
314 void
get_iscsi_bootpath_phy(char * bootpath)315 get_iscsi_bootpath_phy(char *bootpath)
316 {
317 	uint16_t	lun_num		= 0;
318 	uchar_t		replaced_name[BO_MAXOBJNAME] = {0};
319 
320 	if (iscsiboot_prop == NULL)
321 		ld_ib_prop();
322 	if (iscsiboot_prop == NULL)
323 		return;
324 	if (replace_sp_c(replaced_name, iscsiboot_prop->boot_tgt.tgt_name,
325 	    iscsiboot_prop->boot_tgt.tgt_name_len) != 0) {
326 		return;
327 	}
328 	lun_num = *(uint16_t *)(&iscsiboot_prop->boot_tgt.tgt_boot_lun[0]);
329 	(void) snprintf(bootpath, BO_MAXOBJNAME, "/iscsi/disk@%s%s%04X,%d:%s",
330 	    ISCSI_BOOT_ISID, replaced_name, iscsiboot_prop->boot_tgt.tgt_tpgt,
331 	    lun_num, iscsiboot_prop->boot_tgt.tgt_boot_par);
332 }
333 
replace_sp_c(unsigned char * dst,unsigned char * source,size_t n)334 static int replace_sp_c(unsigned char *dst, unsigned char *source, size_t n)
335 {
336 	unsigned char	*p	= NULL;
337 	int		i	= 0;
338 
339 	if (source == NULL || dst == NULL || n == 0) {
340 		return (-1);
341 	}
342 
343 	for (p = source; *p != '\0'; p++, i++) {
344 		if (i >= n) {
345 			return (-1);
346 		}
347 		switch (*p) {
348 		case ':':
349 			*dst = '%';
350 			dst++;
351 			*dst = '3';
352 			dst++;
353 			*dst = 'A';
354 			dst++;
355 			break;
356 		case ' ':
357 			*dst = '%';
358 			dst++;
359 			*dst = '2';
360 			dst++;
361 			*dst = '0';
362 			dst++;
363 			break;
364 		case '@':
365 			*dst = '%';
366 			dst++;
367 			*dst = '4';
368 			dst++;
369 			*dst = '0';
370 			dst++;
371 			break;
372 		case '/':
373 			*dst = '%';
374 			dst++;
375 			*dst = '2';
376 			dst++;
377 			*dst = 'F';
378 			dst++;
379 			break;
380 		default:
381 			*dst = *p;
382 			dst++;
383 		}
384 	}
385 	*dst = '\0';
386 
387 	return (0);
388 }
389