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