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