/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Commmon routines, handling iscsi boot props
*/
#include <sys/types.h>
#include <sys/null.h>
#include <sys/bootprops.h>
#include <sys/cmn_err.h>
#include <sys/socket.h>
#include <sys/kmem.h>
#include <netinet/in.h>
extern void *memset(void *s, int c, size_t n);
extern int memcmp(const void *s1, const void *s2, size_t n);
extern void bcopy(const void *s1, void *s2, size_t n);
extern size_t strlen(const char *s);
static void kinet_ntoa(char *buf, void *in, int af);
extern ib_boot_prop_t *iscsiboot_prop;
int iscsi_print_bootprop = 0;
#define ISCSI_BOOTPROP_BUFLEN 256
static int replace_sp_c(unsigned char *dst, unsigned char *source, size_t n);
static void
iscsi_bootprop_print(int level, char *str)
{
if (str == NULL) {
return;
}
if (iscsi_print_bootprop == 1) {
cmn_err(level, "%s", str);
}
}
static void
iscsi_print_initiator_property(ib_ini_prop_t *ibinitp)
{
char outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
if (ibinitp == NULL) {
return;
}
if (ibinitp->ini_name != NULL) {
(void) sprintf(outbuf,
"Initiator Name : %s\n",
ibinitp->ini_name);
iscsi_bootprop_print(CE_CONT, outbuf);
}
if (ibinitp->ini_chap_name != NULL) {
(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
(void) sprintf(outbuf,
"Initiator CHAP Name : %s\n",
ibinitp->ini_chap_name);
iscsi_bootprop_print(CE_CONT, outbuf);
}
}
static void
iscsi_print_nic_property(ib_nic_prop_t *nicp)
{
char outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
char ipaddr[50] = {0};
int n = 0;
if (nicp == NULL) {
return;
}
kinet_ntoa(ipaddr, &nicp->nic_ip_u, nicp->sin_family);
n = snprintf(outbuf, ISCSI_BOOTPROP_BUFLEN,
"Local IP addr : %s\n", ipaddr);
(void) memset(ipaddr, 0, 50);
kinet_ntoa(ipaddr, &nicp->nic_gw_u, nicp->sin_family);
n = n + snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
"Local gateway : %s\n", ipaddr);
(void) memset(ipaddr, 0, 50);
kinet_ntoa(ipaddr, &nicp->nic_dhcp_u, nicp->sin_family);
n = n + snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
"Local DHCP : %s\n", ipaddr);
(void) snprintf(outbuf + n, ISCSI_BOOTPROP_BUFLEN - n,
"Local MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
nicp->nic_mac[0],
nicp->nic_mac[1],
nicp->nic_mac[2],
nicp->nic_mac[3],
nicp->nic_mac[4],
nicp->nic_mac[5]);
iscsi_bootprop_print(CE_CONT, outbuf);
}
static void
iscsi_print_tgt_property(ib_tgt_prop_t *itgtp)
{
char outbuf[ISCSI_BOOTPROP_BUFLEN] = {0};
char ipaddr[50] = {0};
if (itgtp == NULL) {
return;
}
if (itgtp->tgt_name != NULL) {
(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
(void) sprintf(outbuf,
"Target Name : %s\n",
itgtp->tgt_name);
iscsi_bootprop_print(CE_CONT, outbuf);
}
kinet_ntoa(ipaddr, &itgtp->tgt_ip_u, itgtp->sin_family);
(void) sprintf(outbuf,
"Target IP : %s\n"
"Target Port : %d\n"
"Boot LUN : %02x%02x-%02x%02x-%02x%02x-%02x%02x\n",
ipaddr,
itgtp->tgt_port,
itgtp->tgt_boot_lun[0],
itgtp->tgt_boot_lun[1],
itgtp->tgt_boot_lun[2],
itgtp->tgt_boot_lun[3],
itgtp->tgt_boot_lun[4],
itgtp->tgt_boot_lun[5],
itgtp->tgt_boot_lun[6],
itgtp->tgt_boot_lun[7]);
iscsi_bootprop_print(CE_CONT, outbuf);
if (itgtp->tgt_chap_name != NULL) {
(void) memset(outbuf, 0, ISCSI_BOOTPROP_BUFLEN);
(void) sprintf(outbuf,
"CHAP Name : %s\n",
itgtp->tgt_chap_name);
iscsi_bootprop_print(CE_CONT, outbuf);
}
}
void
iscsi_print_boot_property()
{
if (iscsiboot_prop == NULL) {
return;
}
iscsi_print_initiator_property(
&iscsiboot_prop->boot_init);
iscsi_print_nic_property(&iscsiboot_prop->boot_nic);
iscsi_print_tgt_property(&iscsiboot_prop->boot_tgt);
}
void
iscsi_boot_free_ini(ib_ini_prop_t *init)
{
if (init == NULL) {
return;
}
if (init->ini_name != NULL) {
kmem_free(init->ini_name, init->ini_name_len);
init->ini_name = NULL;
init->ini_name_len = 0;
}
if (init->ini_chap_name != NULL) {
kmem_free(init->ini_chap_name,
init->ini_chap_name_len);
init->ini_chap_name = NULL;
init->ini_chap_name_len = 0;
}
if (init->ini_chap_sec != NULL) {
kmem_free(init->ini_chap_sec,
init->ini_chap_sec_len);
init->ini_chap_sec = NULL;
init->ini_chap_sec_len = 0;
}
}
void
iscsi_boot_free_tgt(ib_tgt_prop_t *target)
{
if (target == NULL) {
return;
}
if (target->tgt_name != NULL) {
kmem_free(target->tgt_name,
target->tgt_name_len);
target->tgt_name = NULL;
target->tgt_name_len = 0;
}
if (target->tgt_chap_name != NULL) {
kmem_free(target->tgt_chap_name,
target->tgt_chap_name_len);
target->tgt_chap_name = NULL;
target->tgt_chap_name_len = 0;
}
if (target->tgt_chap_sec != NULL) {
kmem_free(target->tgt_chap_sec,
target->tgt_chap_sec_len);
target->tgt_chap_sec = NULL;
target->tgt_chap_sec_len = 0;
}
if (target->tgt_boot_par != NULL) {
kmem_free(target->tgt_boot_par,
target->tgt_boot_par_len);
target->tgt_boot_par = NULL;
target->tgt_boot_par_len = 0;
}
}
/*
* Free the memory used by boot property.
*/
void
iscsi_boot_prop_free()
{
ib_boot_prop_t *tmp;
if (iscsiboot_prop == NULL) {
return;
}
tmp = iscsiboot_prop;
iscsiboot_prop = NULL;
iscsi_boot_free_ini(&(tmp->boot_init));
iscsi_boot_free_tgt(&(tmp->boot_tgt));
}
static void
kinet_ntoa(char *buf, void *in, int af)
{
unsigned char *p = NULL;
int i = 0;
if (buf == NULL || in == NULL) {
return;
}
p = (unsigned char *)in;
if (af == AF_INET) {
(void) sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
} else {
for (i = 0; i < 14; i = i + 2) {
(void) sprintf(buf, "%02x%02x:", p[i], p[i+1]);
buf = buf + 5;
}
(void) sprintf(buf, "%02x%02x", p[i], p[i+1]);
}
}
#ifndef BO_MAXOBJNAME
#define BO_MAXOBJNAME 256
#endif
#ifndef ISCSI_BOOT_ISID
#define ISCSI_BOOT_ISID "0000"
#endif
/*
* Generate the 'ssd' bootpath of an iSCSI boot device
* The caller is responsible to alloc the buf with BO_MAXOBJNAME length
*/
void
get_iscsi_bootpath_vhci(char *bootpath)
{
uint16_t *lun_num;
if (iscsiboot_prop == NULL)
ld_ib_prop();
if (iscsiboot_prop == NULL)
return;
lun_num = (uint16_t *)(&iscsiboot_prop->boot_tgt.tgt_boot_lun[0]);
(void) snprintf(bootpath, BO_MAXOBJNAME, "/iscsi/ssd@%s%s%04X,%d:%s",
ISCSI_BOOT_ISID, iscsiboot_prop->boot_tgt.tgt_name,
iscsiboot_prop->boot_tgt.tgt_tpgt, lun_num[0],
iscsiboot_prop->boot_tgt.tgt_boot_par);
}
/*
* Generate the 'disk' bootpath of an iSCSI boot device
* The caller is responsible to alloc the buf with BO_MAXOBJNAME length
*/
void
get_iscsi_bootpath_phy(char *bootpath)
{
uint16_t lun_num = 0;
uchar_t replaced_name[BO_MAXOBJNAME] = {0};
if (iscsiboot_prop == NULL)
ld_ib_prop();
if (iscsiboot_prop == NULL)
return;
if (replace_sp_c(replaced_name, iscsiboot_prop->boot_tgt.tgt_name,
iscsiboot_prop->boot_tgt.tgt_name_len) != 0) {
return;
}
lun_num = *(uint16_t *)(&iscsiboot_prop->boot_tgt.tgt_boot_lun[0]);
(void) snprintf(bootpath, BO_MAXOBJNAME, "/iscsi/disk@%s%s%04X,%d:%s",
ISCSI_BOOT_ISID, replaced_name, iscsiboot_prop->boot_tgt.tgt_tpgt,
lun_num, iscsiboot_prop->boot_tgt.tgt_boot_par);
}
static int replace_sp_c(unsigned char *dst, unsigned char *source, size_t n)
{
unsigned char *p = NULL;
int i = 0;
if (source == NULL || dst == NULL || n == 0) {
return (-1);
}
for (p = source; *p != '\0'; p++, i++) {
if (i >= n) {
return (-1);
}
switch (*p) {
case ':':
*dst = '%';
dst++;
*dst = '3';
dst++;
*dst = 'A';
dst++;
break;
case ' ':
*dst = '%';
dst++;
*dst = '2';
dst++;
*dst = '0';
dst++;
break;
case '@':
*dst = '%';
dst++;
*dst = '4';
dst++;
*dst = '0';
dst++;
break;
case '/':
*dst = '%';
dst++;
*dst = '2';
dst++;
*dst = 'F';
dst++;
break;
default:
*dst = *p;
dst++;
}
}
*dst = '\0';
return (0);
}