/*
* 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
* 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.
*
* iSNS Client
*/
#include "iscsi.h" /* For ISCSI_MAX_IOVEC */
#include "isns_protocol.h"
#include "isns_client.h"
#include "persistent.h"
#ifdef _KERNEL
#else
#include <stdlib.h>
#endif
/* For local use */
typedef struct isns_reg_arg {
typedef struct isns_async_thread_arg {
void *listening_so;
/* One global queue to serve all LHBA instances. */
/* One global queue to serve all LHBA instances. */
/* One globally maintained transaction ID. */
/*
* One SCN callback registration per LHBA instance. For now, since we
* support only one instance, we create one place holder for the
* callback.
*/
void (*scn_callback_p)(void *);
/*
* One thread, port, local address, and listening socket per LHBA instance.
* For now, since we support only one instance, we create one set of place
* holder for these data.
*/
/*
* This mutex protects all the per LHBA instance variables, i.e.,
* esi_scn_thr_to_shutdown, esi_scn_thr_id, and instance_listening_so.
*/
/* iSNS related helpers */
/* Return status */
#define ISNS_OK 0
static void esi_scn_thr_cleanup(void);
static void register_isns_client(void *arg);
/*
* Make query to all iSNS servers visible to the specified LHBA.
* The query could be made for all target nodes or for a specific target
* node.
*/
/*
* Create DevAttrQuery message requesting portal group information for all
* target nodes. Send it to the specified iSNS server. Parse the
* DevAttrQueryRsp PDU and translate the results into a portal group list
* object.
*/
/*
* Create DevAttrQuery message requesting portal group information for the
* specified target node. Send it to the specified iSNS server. Parse the
* DevAttrQueryRsp PDU and translate the results into a portal group list
* object.
*/
/* Transport related helpers */
void *listening_so);
/* iSNS protocol related helpers */
static uint16_t create_xid(void);
static size_t isns_create_dev_attr_reg_pdu(
isns_pdu_t **out_pdu);
/*
* Process and parse a DevAttrQryRsp message. The routine creates a list
* of Portal Group objects if the message is parasable without any issue.
* If the parsing is not successful, the pg_list will be set to NULL.
*/
void
{
1, TASKQ_DEFAULTPRI, 0);
1, TASKQ_DEFAULTPRI, 0);
/* MISC initializations. */
xid = 0;
}
void
{
}
void (*scn_callback)(void *))
{
int i;
int list_space;
/* Look up the iSNS Server address(es) based on the specified ISID */
ISNS_OK) {
return (isns_no_svr_found);
}
/* No iSNS server discovered - no registration needed. */
if (isns_server_addr_list->al_out_cnt == 0) {
list_space = sizeof (iscsi_addr_list_t);
return (isns_no_svr_found);
}
for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
break;
}
}
if (i == isns_server_addr_list->al_out_cnt) {
/*
* Free the server list
*/
list_space = sizeof (iscsi_addr_list_t);
if (isns_server_addr_list->al_out_cnt > 0) {
list_space += (sizeof (iscsi_addr_t) *
}
return (isns_internal_err);
}
/* Register against all iSNS servers discovered. */
for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
/* Dispatch the registration request */
}
/* Free the server list */
list_space = sizeof (iscsi_addr_list_t);
if (isns_server_addr_list->al_out_cnt > 0) {
list_space += (sizeof (iscsi_addr_t) *
}
/* Register the scn_callback. */
return (isns_ok);
}
void (*scn_callback)(void *))
{
int status;
sizeof (struct in6_addr));
} else {
return (isns_op_failed);
}
!= ISNS_OK) {
int, status);
return (isns_internal_err);
}
/* Dispatch the registration request */
/* Register the scn_callback. */
return (isns_ok);
}
{
int i;
int isns_svr_lst_sz;
int list_space;
/* Look up the iSNS Server address(es) based on the specified ISID */
ISNS_OK) {
return (isns_no_svr_found);
}
if (isns_server_addr_list->al_out_cnt == 0) {
isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
return (isns_no_svr_found);
}
for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
if (dereg_stat == isns_ok) {
if (combined_dereg_stat != isns_ok) {
}
} else {
if (combined_dereg_stat == isns_ok) {
}
}
}
/* Free the server list. */
list_space = sizeof (iscsi_addr_list_t);
if (isns_server_addr_list->al_out_cnt > 0) {
list_space += (sizeof (iscsi_addr_t) *
}
return (combined_dereg_stat);
}
{
sizeof (struct in6_addr));
} else {
return (isns_op_failed);
}
if (is_last_isns_server_b == B_TRUE) {
/*
* last known iSNS server.
*/
}
return (dereg_stat);
}
{
return (do_isns_query(B_TRUE,
(uint8_t *)"",
pg_list));
}
/* ARGSUSED */
{
pg_list));
}
{
return (do_isns_query(B_FALSE,
pg_list));
}
/* ARGSUSED */
/* Not supported yet. */
return (isns_op_failed);
}
/* ARGSUSED */
static
int
{
entry_t e;
int i;
int list_space;
void *void_p;
/*
* Use supported iSNS server discovery method to find out all the
* iSNS servers. For now, only static configuration method is
* supported.
*/
isns_server_count = 0;
}
list_space = sizeof (iscsi_addr_list_t);
if (isns_server_count > 0) {
}
KM_SLEEP);
i = 0;
sizeof (struct in6_addr));
} else {
return (ISNS_BAD_SVR_ADDR);
}
i++;
}
return (ISNS_OK);
}
static
int
{
/*
* Bringing up of the thread should happen regardless of the
* subsequent registration status. That means, do not destroy the
*/
/* Determine local port and address. */
NULL, &listening_so);
if (listening_so != NULL) {
}
return (ISNS_CANNOT_FIND_LOCAL_ADDR);
}
if (esi_scn_thr_id == NULL) {
int rval;
/* Assume the LHBA handle has a length of 4 */
"isns_client_esi_%x%x%x%x",
lhba_handle[0],
lhba_handle[1],
lhba_handle[2],
lhba_handle[3]) >=
sizeof (thr_name)) {
if (listening_so != NULL) {
listening_so = NULL;
}
return (ISNS_INTERNAL_ERR);
}
if (esi_scn_thr_id == NULL) {
if (listening_so != NULL) {
listening_so = NULL;
}
return (ISNS_INTERNAL_ERR);
}
if (listening_so != NULL) {
listening_so = NULL;
}
return (ISNS_INTERNAL_ERR);
}
(void) iscsi_thread_send_wakeup(esi_scn_thr_id);
}
return (ISNS_OK);
}
static
void
{
/* Deregister stale registration (if any). */
if (status == isns_open_conn_err) {
/* Cannot open connection to the server. Stop proceeding. */
return;
}
/* New registration. */
/* Cleanup */
}
static
{
int rcv_rsp_cnt = 0;
int rsp_status;
if (out_pdu_size == 0) {
return (isns_create_msg_err);
}
ASSERT(out_pdu_size > 0);
/* Log a message and return */
return (isns_open_conn_err);
}
return (isns_send_msg_err);
}
/* Done with the out PDU - free it */
rcv_rsp_cnt = 0;
for (;;) {
if (bytes_received == 0) {
ASSERT(in_pdu_size == 0);
break;
}
ASSERT(in_pdu_size > 0);
rcv_rsp_cnt++;
if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
continue;
} else {
/* Exceed maximum receive count. */
break;
}
}
if (rsp_status != ISNS_RSP_SUCCESSFUL) {
if (rsp_status == ISNS_RSP_SRC_UNAUTHORIZED) {
} else {
}
}
break;
}
return (rval);
}
/* Always register SCN */
if (out_pdu_size == 0) {
return (isns_create_msg_err);
}
ASSERT(out_pdu_size > 0);
return (isns_send_msg_err);
}
/* Done with the out PDU - free it */
rcv_rsp_cnt = 0;
for (;;) {
if (bytes_received == 0) {
ASSERT(in_pdu_size == 0);
break;
}
ASSERT(in_pdu_size > 0);
rcv_rsp_cnt++;
if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
continue;
} else {
/* Exceed maximum receive count. */
break;
}
}
if (rsp_status != ISNS_RSP_SUCCESSFUL) {
}
break;
}
return (rval);
}
static
{
int rcv_rsp_cnt = 0;
int rsp_status;
if (out_pdu_size == 0) {
return (isns_create_msg_err);
}
ASSERT(out_pdu_size > 0);
/* Log a message and return */
return (isns_open_conn_err);
}
return (isns_send_msg_err);
}
/* Done with the out PDU - free it */
rcv_rsp_cnt = 0;
for (;;) {
if (bytes_received == 0) {
ASSERT(in_pdu_size == 0);
break;
}
ASSERT(in_pdu_size > 0);
rcv_rsp_cnt++;
if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
continue;
} else {
/* Exceed maximum receive count. */
break;
}
}
if (rsp_status != ISNS_RSP_SUCCESSFUL) {
}
break;
}
return (rval);
}
/* Always deregister SCN */
if (out_pdu_size == 0) {
return (isns_create_msg_err);
}
ASSERT(out_pdu_size > 0);
return (isns_send_msg_err);
}
/* Done with the out PDU - free it */
rcv_rsp_cnt = 0;
for (;;) {
if (bytes_received == 0) {
ASSERT(in_pdu_size == 0);
break;
}
ASSERT(in_pdu_size > 0);
rcv_rsp_cnt++;
if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
continue;
} else {
/* Exceed maximum receive count. */
break;
}
}
if (rsp_status != ISNS_RSP_SUCCESSFUL) {
}
break;
}
return (rval);
}
static
{
int i, j, k;
/* Look up the iSNS Server address(es) based on the specified ISID */
ISNS_OK) {
return (isns_no_svr_found);
}
if (isns_server_addr_list->al_out_cnt == 0) {
isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
return (isns_no_svr_found);
}
/*
* isns_server_addr_list->al_out_cnt should not be zero by the
* time it comes to this point.
*/
sizeof (isns_portal_group_list_t *);
combined_num_of_pgs = 0;
for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
if (is_query_all_nodes_b) {
&tmp_pg_list);
} else {
&tmp_pg_list);
}
/* Record the portal group list retrieved from this server. */
tmp_pg_lists[i] = tmp_pg_list;
if (tmp_pg_list != NULL) {
}
if (combined_qry_stat != isns_ok) {
}
} else {
if (combined_qry_stat != isns_op_partially_failed) {
if (combined_qry_stat == isns_ok && i > 0) {
} else {
}
}
}
if (is_query_all_nodes_b == B_FALSE) {
/*
* Break out of the loop if we already got
* the node information for one node.
*/
break;
}
}
}
/* Merge the retrieved portal lists */
combined_pg_lst_sz = sizeof (isns_portal_group_list_t);
if (combined_num_of_pgs > 0) {
sizeof (isns_portal_group_t);
}
k = 0;
for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
if (tmp_pg_lists[i] == NULL) {
continue;
}
for (j = 0; j < tmp_pg_lists[i]->pg_out_cnt; j++) {
pg, sizeof (isns_portal_group_t));
k++;
}
tmp_pg_list_sz = sizeof (isns_portal_group_list_t);
if (tmp_pg_lists[i]->pg_out_cnt > 0) {
sizeof (isns_portal_group_t);
}
tmp_pg_lists[i] = NULL;
}
tmp_pg_lists = NULL;
isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
if (isns_server_addr_list->al_out_cnt > 0) {
isns_svr_lst_sz += (sizeof (iscsi_addr_t) *
}
return (combined_qry_stat);
}
static
{
int bytes_received;
int rcv_rsp_cnt = 0;
int rsp_status;
/* Initialize */
/* Log a message and return */
return (isns_open_conn_err);
}
/*
* Then, ask for all PG attributes. Filter the non-target nodes.
*/
if (out_pdu_size == 0) {
return (isns_create_msg_err);
}
ASSERT(out_pdu_size > 0);
return (isns_send_msg_err);
}
/* Done with the out PDU - free it */
rcv_rsp_cnt = 0;
for (;;) {
ASSERT(bytes_received >= 0);
if (bytes_received == 0) {
ASSERT(in_pdu_size == 0);
break;
}
ASSERT(in_pdu_size > 0);
/*
* make sure we are processing the right transaction id
*/
rcv_rsp_cnt++;
if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
continue;
} else {
/* Exceed maximum receive count. */
break;
}
}
/*
* check to see if FIRST and LAST PDU flag is set
* if they are both set, then this response only has one
* pdu and we can process the pdu
*/
pg_list);
break;
}
/*
* this pdu is part of a multi-pdu response. save off the
* the payload of this pdu and continue processing
*/
/* This is the first pdu, make sure sequence ID is 0 */
"first pdu is not sequence ID 0");
return (isns_op_failed);
}
seq_id = 0;
/* create new pdu and copy in data from old pdu */
/* done with in_pdu, free it */
} else {
seq_id++;
"Missing sequence ID %d from isns query "
"response.", seq_id);
if (combined_pdu != NULL) {
combined_pdu = NULL;
}
return (isns_op_failed);
}
/*
* if conbined_pdu_size is still zero, then we never
* processed the first pdu
*/
if (combined_pdu_size == 0) {
"Did not receive first pdu.\n");
return (isns_op_failed);
}
/* save off the old combined pdu */
/*
* alloc a new pdu big enough to also hold the new
* pdu payload
*/
/*
* copy the old pdu into the new allocated pdu buffer
* and append on the new pdu payload that we just
* received
*/
/* free in_pdu and old_combined_pdu */
}
/*
* check to see if this is the LAST pdu.
* if it is, we can process it and move on
* otherwise continue to wait for the next pdu
*/
pg_list);
combined_pdu = NULL;
break;
}
}
if (rsp_status != ISNS_RSP_SUCCESSFUL) {
}
return (qry_stat);
}
/* ARGSUSED */
static
{
int bytes_received;
int rcv_rsp_cnt;
int rsp_status;
/* Obtain the list of target type storage nodes first */
if (out_pdu_size == 0) {
return (isns_create_msg_err);
}
ASSERT(out_pdu_size > 0);
/* Log a message and return */
return (isns_open_conn_err);
}
return (isns_send_msg_err);
}
/* Done with the out PDU - free it */
rcv_rsp_cnt = 0;
for (;;) {
ASSERT(bytes_received >= 0);
if (bytes_received == 0) {
ASSERT(in_pdu_size == 0);
break;
}
ASSERT(in_pdu_size > 0);
rcv_rsp_cnt++;
if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
continue;
} else {
/* Exceed maximum receive count. */
break;
}
}
pg_list);
if (rsp_status != ISNS_RSP_SUCCESSFUL) {
}
break;
}
return (rval);
}
static
void
{
int rval = 0;
union {
} sa_rsvr = { 0 };
void *so;
t_addrlen = sizeof (struct sockaddr_in6);
/* IPv4 */
/* Create socket */
} else {
/* IPv6 */
sizeof (struct in6_addr));
/* Create socket */
}
return (NULL);
}
sizeof (struct sockaddr_in) :
sizeof (struct sockaddr_in6), 0, 0);
if (rval != 0) {
/* Flag value 2 indicates both cantsend and cantrecv */
return (NULL);
}
&t_addrlen);
return (so);
}
static ssize_t
{
int iovlen = 0;
total_len += (ISNSP_HEADER_SIZE);
iovlen++;
iovlen++;
/* Initialization of the message header. */
}
static
{
int poll_cnt;
/* Receive the header first */
/* Initialization of the message header. */
/* Poll and receive the packets. */
poll_cnt = 0;
do {
if (bytes_received == 0) {
/* Not yet. Increase poll count and try again. */
poll_cnt++;
continue;
} else {
/* OK data received. */
break;
}
} while (poll_cnt < ISNS_RCV_RETRY_MAX);
int, poll_cnt, int, bytes_received);
if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
*pdu_size = 0;
return (0);
}
*pdu_size = 0;
return (0);
}
/* Verify the received payload len is within limit */
if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) {
*pdu_size = 0;
return (0);
}
/* Proceed to receive additional data. */
/* Initialization of the message header. */
/* Poll and receive the rest of the PDU. */
poll_cnt = 0;
do {
if (bytes_received == 0) {
/* Not yet. Increase poll count and try again. */
poll_cnt++;
continue;
} else {
/* OK data received. */
break;
}
} while (poll_cnt < ISNS_RCV_RETRY_MAX);
int, poll_cnt, int, bytes_received);
if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
*pdu_size = 0;
return (0);
}
*pdu_size = 0;
return (0);
}
tmp_pdu_data = NULL;
tmp_pdu_hdr = NULL;
return (total_bytes_received);
}
/*
* isns_create_dev_attr_reg_pdu - isns client registration pdu
*/
static size_t
{
/* RFC 4171 section 6.1 - NULLs included in the length. */
if (node_name_len == 1) {
return (0);
}
/*
* Create DevAttrReg Message
*
* Enable the replace bit so that we can update
* existing registration
*/
/* Source attribute */
node_name_len, node_name, 0) != 0) {
return (0);
}
/*
* Message Key Attributes
*
* EID attribute - Section 6.2.1
* This is required for re-registrations or Replace
* Bit is ignored - Section 5.6.5.1
*/
node_name_len, node_name, 0) != 0) {
return (0);
}
/* Delimiter */
!= 0) {
return (0);
}
/* EID attribute - Section 6.2.1 */
node_name_len, node_name, 0) != 0) {
return (0);
}
/* ENTITY Protocol - Section 6.2.2 */
0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
return (0);
}
/* iSCSI Name - Section 6.4.1 */
node_name_len, node_name, 0) != 0) {
return (0);
}
/* iSCSI Alias - Section 6.4.3 Optional */
if (node_alias_len > 1) {
node_alias_len, node_alias, 0) != 0) {
return (0);
}
}
/* iSCSI Node Type - Section 6.4.2 */
0, node_type) != 0) {
return (0);
}
if (instance_listening_so != NULL) {
return (0);
}
} else {
return (0);
}
/* Portal IP Address - Section 6.5.2 */
return (0);
}
/* Portal Port - Section 6.5.3 */
local_port) != 0) {
return (0);
}
/* SCN Port - Section 6.3.7 */
local_port) != 0) {
return (0);
}
/* ESI Port - Section 6.3.5 */
local_port) != 0) {
return (0);
}
return (pdu_size);
}
/*
* isns_create_dev_dereg_pdu - Create an iSNS PDU for deregistration.
*/
static size_t
{
/* RFC 4171 section 6.1 - NULLs included in the length. */
if (node_name_len == 1) {
return (0);
}
/*
* Create DevDeReg Message
*/
/* Source attribute */
node_name_len, node_name, 0) != 0) {
return (0);
}
/* Delimiter */
!= 0) {
return (0);
}
/* Entity Identifier */
node_name_len, node_name, 0) != 0) {
return (0);
}
return (pdu_size);
}
/*
* isns_create_dev_attr_target_nodes_pdu - get all accessible targets
*
* Querys for a list of all accessible target nodes for this
* initiator. Requests all required login information (name,
* ip, port, tpgt).
*/
static size_t
{
/* RFC 4171 section 6.1 - NULLs included in the length. */
if (node_name_len == 1) {
return (0);
}
/* Create DevAttrQry Message */
/* Source attribute */
node_name_len, node_name, 0) != 0) {
return (0);
}
/*
* Message Key Attribute
*
* iSCSI Node Type
* Query target nodes only
*/
4, 0, ISNS_TARGET_NODE_TYPE) != 0) {
return (0);
}
/* Delimiter */
ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) {
return (0);
}
/* PG iSCSI Name - Zero length TLV */
0, 0, 0) != 0) {
return (0);
}
/* PG Portal IP Address - Zero length TLV */
0, 0, 0) != 0) {
return (0);
}
/* PG Portal Port - Zero length TLV */
0, 0, 0) != 0) {
return (0);
}
/* PG Portal Group Tag - Zero length TLV */
ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
return (0);
}
return (pdu_size);
}
static
{
/* RFC 4171 section 6.1 - NULLs included in the length. */
if (source_node_name_len == 1) {
return (0);
}
/* Create DevAttrQry message scoped to target_node_name */
/* Source attribute */
source_node_name_len, source_node_name, 0) != 0) {
return (0);
}
/* Message key attribute */
/* iSCSI Node Name */
target_node_name, 0) != 0) {
return (0);
}
/* Delimiter */
ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) {
return (0);
}
/* PG iSCSI Name - Zero length TLV */
0, 0, 0) != 0) {
return (0);
}
/* PG Portal IP Address - Zero length TLV */
0, 0, 0) != 0) {
return (0);
}
/* PG Portal Port - Zero length TLV */
0, 0, 0) != 0) {
return (0);
}
/* PG Portal Group Tag - Zero length TLV */
ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
return (0);
}
return (pdu_size);
}
static
{
/* RFC 4171 section 6.1 - NULLs included in the length. */
if (node_name_len == 1) {
return (0);
}
/* Create SCNReg Message */
/* Source attribute */
node_name_len, node_name, 0) != 0) {
return (0);
}
/* Message attribute */
node_name_len, node_name, 0) != 0) {
return (0);
}
/* Delimiter */
!= 0) {
return (0);
}
/* Operating attribute */
4,
0,
/*
* Microsoft seems to not differentiate between init and
*/
ISNS_OBJ_UPDATED) != 0) {
return (0);
}
return (pdu_size);
}
static
{
/* RFC 4171 section 6.1 - NULLs included in the length. */
if (node_name_len == 1) {
return (0);
}
/* Create SCNReg Message */
/* Source attribute */
node_name_len, node_name, 0) != 0) {
return (0);
}
/* Message attribute */
node_name_len, node_name, 0) != 0) {
return (0);
}
/* Delimiter */
!= 0) {
return (0);
}
/* No operating attribute */
return (pdu_size);
}
static
{
/* Create ESIRsp Message */
/* Status Code */
payload_len += 4;
(esi_pdu->payload_len));
} else {
}
/* Delimiter */
!= 0) {
return (0);
}
return (pdu_size);
}
static
{
/* Create SCNRsp Message */
/* Status Code */
payload_len += 4;
(scn_pdu->payload_len));
} else {
}
/* Delimiter */
!= 0) {
return (0);
}
return (pdu_size);
}
static
{
/* If this happens the iSNS server may have a problem. */
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
/* Check response's status code */
}
return (ISNS_RSP_SUCCESSFUL);
}
static
{
/* If this happens the iSNS server may have a problem. */
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
/* Check response's status code */
}
return (ISNS_RSP_SUCCESSFUL);
}
static
{
/* If this happens the iSNS server may have a problem. */
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
/* Check response's status code */
}
return (ISNS_RSP_SUCCESSFUL);
}
static
{
/* If this happens the iSNS server may have a problem. */
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
/* Check response's status code */
}
return (ISNS_RSP_SUCCESSFUL);
}
static
{
if (payload_funcId != ISNS_DEV_ATTR_QRY_RSP) {
/* If this happens the iSNS server may have a problem. */
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
}
/*
* If payload is smaller than the length of even 1 attribute
* there is something wrong with the PDU.
*/
if (resp_len < (ISNS_TLV_ATTR_ID_LEN +
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
/*
* Expected DevAttrQryRsp message format:
*
* Status Code
* iSCSI Node Type
* Delimiter
* PG iSCSI Name [Optional]
* PG Portal IP Address [Optional]
* PG Portal Port [Optional]
* PG Tag [Optional]
* PG iSCSI Name [Optional]
* PG Portal IP Address [Optional]
* PG Portal Port [Optional]
* PG Tag [Optional]
* .
* .
* .
*/
num_of_pgs = 0;
/* Find out the number of entries retrieved */
while (!done_b) {
if (found_delimiter_b) {
} else {
}
/*
* Count only those iSCSI node that have a
* non-NULL PGT value as valid Entity.
* Per rfc4171 section 3.4 - If the PGT value
* registered for a specified Portal and iSCSI
* Node is NULL, or if no PGT value is
* registered, then the Portal does not provide
* access to that iSCSI Node in the Entity.
*/
num_of_pgs++;
}
}
if (total_payload_len >= resp_len) {
} else {
data_p += (ISNS_TLV_ATTR_ID_LEN +
}
}
pg_sz = sizeof (isns_portal_group_list_t);
if (num_of_pgs > 0) {
}
int, pg_sz);
/*
* Once we passed this point, if for any reason we need to return
* because of a failure, we need to free the memory allocated for
* the pg_list and nullify it.
*/
(*pg_list)->pg_out_cnt = 0;
/* Assign the isns_server information to all portal groups */
sizeof (iscsi_ipaddr_t));
}
while (!done_b) {
case ISNS_DELIMITER_ATTR_ID:
if (found_delimiter_b) {
} else {
}
break;
(char *)pg->pg_iscsi_name,
char *, (char *)pg->pg_iscsi_name);
break;
if (target_node_type_b) {
/*
* Section 6.3.1 - The Portal IP Address
* is a 16-byte field that may contain
* an IPv4 or IPv6 address. When this
* field contains an IPv4 address, it
* is stored as an IPv4-mapped IPv6
* address
*/
"Received = %d",
attr_tlv_p->attr_len));
return (
}
/*
* Section 6.3.1 and RFC 2373 state
* that an IPv4 address will be denoted
* by the 10 top bytes as all zero
* followed by either 2 bytes of
* 0x0000 or 0xFFFF The 0x0000 states
* that the address is is IPv6 capable
* and 0xFFFF states its not capable.
*/
IPV4_RSVD_BYTES) == 0) &&
0x00) &&
0x00)) ||
0xFF) &&
0xFF)))) {
/* IPv4 */
sizeof (struct in_addr));
sizeof (struct in_addr);
} else {
/* IPv6 */
sizeof (struct in6_addr));
sizeof (struct in6_addr);
}
}
break;
if (target_node_type_b) {
(*attr_tlv_p).
}
break;
case ISNS_PG_TAG_ATTR_ID:
if (target_node_type_b) {
(*attr_tlv_p).
}
/*
* Only the iSCSI node that has a
* non-NULL PGT value is an valid
* Entity.
*/
(*pg_list)->pg_out_cnt++;
}
break;
default:
break;
}
if ((total_payload_len >= resp_len) ||
} else {
data_p += (ISNS_TLV_ATTR_ID_LEN +
}
}
return (ISNS_RSP_SUCCESSFUL);
}
/* ARGSUSED */
static
{
/* There's nothing particular to process for ESI. */
return (ISNS_RSP_SUCCESSFUL);
}
static
{
void (*scn_callback_to_use)(void *);
/* get the lhba_handle to use for the call back */
if (scn_callback_to_use == NULL) {
return (ISNS_RSP_INTERNAL_ERROR);
}
scn_type = 0;
total_payload_len = 0;
/*
* Section 5.6.5.8 states an SCN can have more than one
* source attribute. Process all attributes until we
* each process all the data or encounter the delimiter.
*/
while (!done_b) {
/* ISNS_ISCSI_NAME_ATTR_ID - attribute name */
case ISNS_ISCSI_NAME_ATTR_ID:
/*
* The attribute length must be 4-byte aligned.
* Section 5.1.3, RFC 4171.
*/
(attr_eff_len) :
if (normalized_attr_len !=
/* This SCN is bad. */
return (ISNS_RSP_MSG_FORMAT_ERROR);
}
/* Check if this was the Destination Attribute */
if ((dest_attr_found_b == B_TRUE) &&
(scn_type_found_b == B_TRUE)) {
(char *)src_attr,
/* allocate new callback structure */
sizeof (isns_scn_callback_arg_t),
KM_SLEEP);
sizeof (scn_args_p->source_key_attr));
/* Dispatch the callback to process the SCN */
(void) ddi_taskq_dispatch(scn_taskq,
}
} else {
/* Skip Destination Attribute */
}
break;
/* ISNS_ISCSI_SCN_BITMAP_ATTR_ID - change type */
/*
* Determine the type of action to take for this SCN.
*/
break;
/* ISNS_DELIMITER_ATTR_ID - end of the payload of a message */
case ISNS_DELIMITER_ATTR_ID:
break;
}
/* No more Attributes to process */
} else {
if (scn_pdu_p->payload_len -
/*
* The rest of the data in the PDU
* is less than the size of a valid
* iSNS TLV. This next attribute
* probably spans across the PDU
* boundary. For now, do not
* process it further.
*/
} else {
/* Advance to the next Attribute */
data_p += (ISNS_TLV_ATTR_ID_LEN +
}
}
}
}
return (ISNS_RSP_SUCCESSFUL);
}
static
{
/*
* It should be ok to assume ISNSP_MAX_PDU_SIZE is large enough
* since we are creating our own PDU which is fully under our control.
*/
return (pdu_size);
}
static
int
void *attr_data,
{
/* The attribute length must be 4-byte aligned. Section 5.1.3. */
/* Check if we are going to exceed the maximum PDU length. */
return (1);
}
switch (attr_id) {
case ISNS_DELIMITER_ATTR_ID:
break;
if (attr_numeric_data == sizeof (in_addr_t)) {
/* IPv4 */
sizeof (in_addr_t));
} else if (attr_numeric_data == sizeof (in6_addr_t)) {
/* IPv6 */
sizeof (in6_addr_t));
} else if (attr_numeric_data == 0) {
/* EMPTY */
/* Do nothing */
} else {
return (1);
}
break;
case ISNS_EID_ATTR_ID:
case ISNS_ISCSI_NAME_ATTR_ID:
case ISNS_ISCSI_ALIAS_ATTR_ID:
attr_len);
break;
default:
switch (normalized_attr_len) {
case 0:
break;
case 4:
break;
case 8:
break;
}
}
/*
* Convert the network byte ordered payload length to host byte
* ordered for local address calculation.
*/
/*
* Convert the host byte ordered payload length back to network
* byte ordered - it's now ready to be sent on the wire.
*/
return (0);
}
/* ARGSUSED */
static
void
{
int clnt_len;
union {
} clnt_addr = { 0 };
union {
/* Done using the argument - free it */
t_addrlen = sizeof (struct sockaddr_in6);
if (t_addrlen <= sizeof (local_conn_prop)) {
}
}
for (;;) {
int rval;
/* Blocking call */
if (esi_scn_thr_to_shutdown == B_TRUE) {
/* Terminate the thread if instructed to do so. */
return;
}
if (connecting_so == NULL) {
continue;
}
&in_pdu_size);
continue;
}
if (bytes_received == 0) {
continue;
}
case ISNS_ESI:
case ISNS_SCN:
rval,
&xid,
&out_pdu);
rval,
&xid,
&out_pdu);
} else {
/*
* Ignore all traffics other than
* ESI and SCN.
*/
continue;
}
if (out_pdu_size == 0) {
continue;
}
break;
default:
continue;
}
}
}
static
{
union {
} local_conn_prop = { 0 };
return (B_FALSE);
}
t_addrlen = sizeof (struct sockaddr_in6);
&t_addrlen);
if (t_addrlen > sizeof (local_conn_prop)) {
return (B_FALSE);
}
/* Currently, IPv6 is not supported */
return (B_FALSE);
} else {
return (B_FALSE);
}
return (B_TRUE);
}
static
{
union {
} local_conn_prop = { 0 };
union {
} serv_addr = { 0 };
void *so;
if (listening_so == NULL) {
return (B_FALSE);
}
if (local_addr != NULL) {
*local_addr = NULL;
}
*listening_so = NULL;
t_addrlen = sizeof (struct sockaddr_in6);
/*
* Determine the local IP address.
*/
if (local_addr != NULL) {
return (B_FALSE);
}
if (t_addrlen > sizeof (local_conn_prop)) {
return (B_FALSE);
}
t_addrlen = sizeof (struct sockaddr_in6);
*local_addr =
KM_SLEEP);
/* Currently, IPv6 is not supported */
return (B_FALSE);
} else {
return (B_FALSE);
}
}
/*
* Determine the local IP address. (End)
*/
/*
* Use INADDR_ANY to accept connections from any of the connected
* networks.
*/
/*
* Use port number 0 to allow the system to assign a unique unused
* port.
*/
*local_addr = NULL;
}
return (B_FALSE);
}
sizeof (struct sockaddr), 0, 0) < 0) {
*local_addr = NULL;
}
return (B_FALSE);
}
&t_addrlen);
if (t_addrlen <= sizeof (local_conn_prop)) {
(*local_addr)->a_port =
} else {
}
}
*listening_so = so;
return (B_TRUE);
}
/* ARGSUSED */
static
void
{
/*
* When we support multiple HBA instance we will use lhba_handle
* to look up the associated SCN callback. For now, we only support
* one HBA instance therefore we always return the same SCN callback.
*/
return (scn_callback_p);
}
static
{
}
static
void
{
if (esi_scn_thr_to_shutdown == B_FALSE) {
if (instance_listening_so != NULL &&
instance_listening_so) == B_TRUE)) {
void *connecting_so;
/*
* Open a connection to the local address and send
* a dummy header to unblock the accept call so that
* itself.
*/
if (connecting_so == NULL) {
} else {
&out_pdu);
out_pdu) != 0) {
} else {
}
}
}
if (unblock_esi_scn_thr_b == B_TRUE) {
(void) iscsi_thread_stop(esi_scn_thr_id);
/*
* Shutdown and close the listening socket.
*/
}
}
}