|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Common handling for iSNS message parsing
|
|
Packit |
1c819f |
*
|
|
Packit |
1c819f |
* Copyright (C) 2007 Olaf Kirch <olaf.kirch@oracle.com>
|
|
Packit |
1c819f |
*
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
#include <stdlib.h>
|
|
Packit |
1c819f |
#include <string.h>
|
|
Packit |
1c819f |
#include "config.h"
|
|
Packit |
1c819f |
#include <libisns/isns.h>
|
|
Packit |
1c819f |
#include <libisns/attrs.h>
|
|
Packit |
1c819f |
#include <libisns/message.h>
|
|
Packit |
1c819f |
#include "objects.h"
|
|
Packit |
1c819f |
#include "security.h"
|
|
Packit |
1c819f |
#include "socket.h"
|
|
Packit |
1c819f |
#include <libisns/util.h>
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
typedef void isns_simple_callback_fn_t(uint32_t, int status, isns_simple_t *);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
static int isns_attr_list_scanner_get_pg(struct isns_attr_list_scanner *st);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Allocate an empty simple message
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
static isns_simple_t *
|
|
Packit |
1c819f |
__isns_alloc_simple(void)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_simple_t *simp;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
simp = isns_calloc(1, sizeof(*simp));
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_init(&simp->is_message_attrs);
|
|
Packit |
1c819f |
isns_attr_list_init(&simp->is_operating_attrs);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
return simp;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Create a simple message, and set the source name
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
isns_simple_t *
|
|
Packit |
1c819f |
isns_simple_create(uint32_t function, isns_source_t *source,
|
|
Packit |
1c819f |
const isns_attr_list_t *key)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_simple_t *simp;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
simp = __isns_alloc_simple();
|
|
Packit |
1c819f |
simp->is_function = function;
|
|
Packit |
1c819f |
simp->is_source = source;
|
|
Packit |
1c819f |
if (source != NULL)
|
|
Packit |
1c819f |
source->is_users++;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (key)
|
|
Packit |
1c819f |
isns_attr_list_copy(&simp->is_message_attrs, key);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
return simp;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Perform a call to the server, waiting for the response.
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_simple_call(isns_socket_t *sock, isns_simple_t **inout)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_simple_t *simp = *inout;
|
|
Packit |
1c819f |
isns_message_t *msg, *resp;
|
|
Packit |
1c819f |
int status;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_simple_print(simp, isns_debug_message);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = isns_simple_encode(simp, &msg;;
|
|
Packit |
1c819f |
if (status != ISNS_SUCCESS) {
|
|
Packit |
1c819f |
isns_error("Unable to encode %s: %s\n",
|
|
Packit |
1c819f |
isns_function_name(simp->is_function),
|
|
Packit |
1c819f |
isns_strerror(status));
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_debug_message("Sending request, len=%d\n",
|
|
Packit |
1c819f |
buf_avail(msg->im_payload));
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
resp = isns_socket_call(sock, msg,
|
|
Packit |
1c819f |
isns_config.ic_network.call_timeout);
|
|
Packit |
1c819f |
isns_assert(msg->im_users == 1);
|
|
Packit |
1c819f |
isns_message_release(msg);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (resp == NULL) {
|
|
Packit |
1c819f |
isns_error("Timed out while waiting for reply\n");
|
|
Packit |
1c819f |
return ISNS_INTERNAL_ERROR;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_debug_message("Received reply, len=%d\n",
|
|
Packit |
1c819f |
buf_avail(resp->im_payload));
|
|
Packit |
1c819f |
isns_assert(resp->im_users == 1);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = isns_message_status(resp);
|
|
Packit |
1c819f |
if (status != ISNS_SUCCESS) {
|
|
Packit |
1c819f |
isns_message_release(resp);
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = isns_simple_decode(resp, &simp);
|
|
Packit |
1c819f |
isns_message_release(resp);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (status) {
|
|
Packit |
1c819f |
isns_error("Unable to decode server response: %s (status 0x%04x)\n",
|
|
Packit |
1c819f |
isns_strerror(status), status);
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_simple_print(simp, isns_debug_message);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_simple_free(*inout);
|
|
Packit |
1c819f |
*inout = simp;
|
|
Packit |
1c819f |
return ISNS_SUCCESS;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* This callback is invoked from the network layer when
|
|
Packit |
1c819f |
* we received a response to an async message
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
static void
|
|
Packit |
1c819f |
isns_simple_recv_response(isns_message_t *cmsg, isns_message_t *rmsg)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_simple_callback_fn_t *user_callback;
|
|
Packit |
1c819f |
isns_simple_t *resp = NULL;
|
|
Packit |
1c819f |
int status = ISNS_INTERNAL_ERROR;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* rmsg being NULL means the call timed out. */
|
|
Packit |
1c819f |
if (rmsg == NULL)
|
|
Packit |
1c819f |
goto callback;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = isns_message_status(rmsg);
|
|
Packit |
1c819f |
if (status != ISNS_SUCCESS) {
|
|
Packit |
1c819f |
isns_error("Server flags error: %s (status 0x%04x)\n",
|
|
Packit |
1c819f |
isns_strerror(status), status);
|
|
Packit |
1c819f |
goto callback;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = isns_simple_decode(rmsg, &resp);
|
|
Packit |
1c819f |
if (status) {
|
|
Packit |
1c819f |
isns_error("Unable to decode server response: %s (status 0x%04x)\n",
|
|
Packit |
1c819f |
isns_strerror(status), status);
|
|
Packit |
1c819f |
resp = NULL;
|
|
Packit |
1c819f |
goto callback;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_simple_print(resp, isns_debug_message);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
callback:
|
|
Packit |
1c819f |
user_callback = cmsg->im_calldata;
|
|
Packit |
1c819f |
if (user_callback)
|
|
Packit |
1c819f |
user_callback(cmsg->im_xid, status, resp);
|
|
Packit |
1c819f |
if (resp)
|
|
Packit |
1c819f |
isns_simple_free(resp);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Transmit a call, without waiting for the response.
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_simple_transmit(isns_socket_t *sock, isns_simple_t *call,
|
|
Packit |
1c819f |
const isns_portal_info_t *dest,
|
|
Packit |
1c819f |
unsigned int timeout,
|
|
Packit |
1c819f |
isns_simple_callback_fn_t *user_callback)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_message_t *msg;
|
|
Packit |
1c819f |
int status;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_simple_print(call, isns_debug_message);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = isns_simple_encode(call, &msg;;
|
|
Packit |
1c819f |
if (status != ISNS_SUCCESS) {
|
|
Packit |
1c819f |
isns_error("Unable to encode %s: %s\n",
|
|
Packit |
1c819f |
isns_function_name(call->is_function),
|
|
Packit |
1c819f |
isns_strerror(status));
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_debug_message("Sending message, len=%d\n",
|
|
Packit |
1c819f |
buf_avail(msg->im_payload));
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (user_callback) {
|
|
Packit |
1c819f |
msg->im_callback = isns_simple_recv_response;
|
|
Packit |
1c819f |
msg->im_calldata = user_callback;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (!isns_socket_submit(sock, msg, timeout))
|
|
Packit |
1c819f |
status = ISNS_INTERNAL_ERROR;
|
|
Packit |
1c819f |
isns_message_release(msg);
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Delete the simple message object
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
void
|
|
Packit |
1c819f |
isns_simple_free(isns_simple_t *simp)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
if (simp == NULL)
|
|
Packit |
1c819f |
return;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_destroy(&simp->is_message_attrs);
|
|
Packit |
1c819f |
isns_attr_list_destroy(&simp->is_operating_attrs);
|
|
Packit |
1c819f |
isns_source_release(simp->is_source);
|
|
Packit |
1c819f |
isns_policy_release(simp->is_policy);
|
|
Packit |
1c819f |
isns_free(simp);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Get the source associated with this simple message
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
isns_source_t *
|
|
Packit |
1c819f |
isns_simple_get_source(isns_simple_t *simp)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
return simp->is_source;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
const isns_attr_list_t *
|
|
Packit |
1c819f |
isns_simple_get_attrs(isns_simple_t *simp)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
return &simp->is_operating_attrs;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Determine whether message includes a source attr.
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
static inline int
|
|
Packit |
1c819f |
isns_simple_include_source(uint16_t function)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
if (function & 0x8000)
|
|
Packit |
1c819f |
return 0;
|
|
Packit |
1c819f |
switch (function) {
|
|
Packit |
1c819f |
case ISNS_STATE_CHANGE_NOTIFICATION:
|
|
Packit |
1c819f |
case ISNS_ENTITY_STATUS_INQUIRY:
|
|
Packit |
1c819f |
return 0;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
return 1;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Decode a simple message
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_simple_decode(isns_message_t *msg, isns_simple_t **result)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_simple_t *simp = __isns_alloc_simple();
|
|
Packit |
1c819f |
buf_t *bp = msg->im_payload;
|
|
Packit |
1c819f |
int status = ISNS_SUCCESS;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
simp->is_function = msg->im_header.i_function;
|
|
Packit |
1c819f |
simp->is_xid = msg->im_xid;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (isns_simple_include_source(simp->is_function)) {
|
|
Packit |
1c819f |
status = isns_source_decode(bp, &simp->is_source);
|
|
Packit |
1c819f |
if (status != ISNS_SUCCESS)
|
|
Packit |
1c819f |
goto out;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
switch (simp->is_function & 0x7FFF) {
|
|
Packit |
1c819f |
case ISNS_ENTITY_STATUS_INQUIRY:
|
|
Packit |
1c819f |
case ISNS_STATE_CHANGE_NOTIFICATION:
|
|
Packit |
1c819f |
/* Server messages do not include a source */
|
|
Packit |
1c819f |
status = isns_attr_list_decode(bp,
|
|
Packit |
1c819f |
&simp->is_message_attrs);
|
|
Packit |
1c819f |
break;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
default:
|
|
Packit |
1c819f |
status = isns_attr_list_decode_delimited(bp,
|
|
Packit |
1c819f |
&simp->is_message_attrs);
|
|
Packit |
1c819f |
if (status == ISNS_SUCCESS)
|
|
Packit |
1c819f |
status = isns_attr_list_decode(bp,
|
|
Packit |
1c819f |
&simp->is_operating_attrs);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (msg->im_header.i_flags & ISNS_F_REPLACE)
|
|
Packit |
1c819f |
simp->is_replace = 1;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
out:
|
|
Packit |
1c819f |
if (status == ISNS_SUCCESS) {
|
|
Packit |
1c819f |
*result = simp;
|
|
Packit |
1c819f |
} else {
|
|
Packit |
1c819f |
isns_simple_free(simp);
|
|
Packit |
1c819f |
*result = NULL;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Encode a simple message reply or response
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
static int
|
|
Packit |
1c819f |
__isns_simple_encode(isns_simple_t *simp, buf_t *bp)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
int status = ISNS_SUCCESS;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (isns_simple_include_source(simp->is_function)) {
|
|
Packit |
1c819f |
if (simp->is_source == NULL) {
|
|
Packit |
1c819f |
isns_error("Cannot encode %s message - caller forgot to set source\n",
|
|
Packit |
1c819f |
isns_function_name(simp->is_function));
|
|
Packit |
1c819f |
return ISNS_SOURCE_UNKNOWN;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
status = isns_source_encode(bp, simp->is_source);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (status == ISNS_SUCCESS)
|
|
Packit |
1c819f |
status = isns_attr_list_encode(bp, &simp->is_message_attrs);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* Some functions have just one set of attrs. */
|
|
Packit |
1c819f |
switch (simp->is_function & 0x7fff) {
|
|
Packit |
1c819f |
/* It's not entirely clear which calls actually have the delimiter.
|
|
Packit |
1c819f |
* The spec is sometimes a little vague on this. */
|
|
Packit |
1c819f |
case ISNS_SCN_DEREGISTER:
|
|
Packit |
1c819f |
case ISNS_ENTITY_STATUS_INQUIRY:
|
|
Packit |
1c819f |
case ISNS_STATE_CHANGE_NOTIFICATION:
|
|
Packit |
1c819f |
break;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
default:
|
|
Packit |
1c819f |
if (status == ISNS_SUCCESS)
|
|
Packit |
1c819f |
status = isns_encode_delimiter(bp);
|
|
Packit |
1c819f |
if (status == ISNS_SUCCESS)
|
|
Packit |
1c819f |
status = isns_attr_list_encode(bp, &simp->is_operating_attrs);
|
|
Packit |
1c819f |
break;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_simple_encode(isns_simple_t *simp, isns_message_t **result)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_message_t *msg;
|
|
Packit |
1c819f |
int status, flags;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
flags = ISNS_F_CLIENT;
|
|
Packit |
1c819f |
if (simp->is_replace)
|
|
Packit |
1c819f |
flags |= ISNS_F_REPLACE;
|
|
Packit |
1c819f |
msg = isns_create_message(simp->is_function, flags);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* FIXME: for UDP sockets, isns_simple_t may contain a
|
|
Packit |
1c819f |
destination address. */
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = __isns_simple_encode(simp, msg->im_payload);
|
|
Packit |
1c819f |
if (status != ISNS_SUCCESS) {
|
|
Packit |
1c819f |
isns_message_release(msg);
|
|
Packit |
1c819f |
msg = NULL;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* Report the XID to the caller */
|
|
Packit |
1c819f |
simp->is_xid = msg->im_xid;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
*result = msg;
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_simple_encode_response(isns_simple_t *reg,
|
|
Packit |
1c819f |
const isns_message_t *request, isns_message_t **result)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_message_t *msg;
|
|
Packit |
1c819f |
int status;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
msg = isns_create_reply(request);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = __isns_simple_encode(reg, msg->im_payload);
|
|
Packit |
1c819f |
if (status != ISNS_SUCCESS) {
|
|
Packit |
1c819f |
isns_message_release(msg);
|
|
Packit |
1c819f |
msg = NULL;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
*result = msg;
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_simple_decode_response(isns_message_t *resp, isns_simple_t **result)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
return isns_simple_decode(resp, result);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Extract the list of objects from a DevAttrReg/DevAttrQry
|
|
Packit |
1c819f |
* response or similar.
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_simple_response_get_objects(isns_simple_t *resp,
|
|
Packit |
1c819f |
isns_object_list_t *result)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
struct isns_attr_list_scanner state;
|
|
Packit |
1c819f |
int status = ISNS_SUCCESS;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_scanner_init(&state, NULL, &resp->is_operating_attrs);
|
|
Packit |
1c819f |
while (1) {
|
|
Packit |
1c819f |
isns_object_t *obj;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
status = isns_attr_list_scanner_next(&state);
|
|
Packit |
1c819f |
if (status == ISNS_NO_SUCH_ENTRY) {
|
|
Packit |
1c819f |
status = ISNS_SUCCESS;
|
|
Packit |
1c819f |
break;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
if (status)
|
|
Packit |
1c819f |
break;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
obj = isns_create_object(state.tmpl, &state.keys, NULL);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_object_set_attrlist(obj, &state.attrs);
|
|
Packit |
1c819f |
if (obj != state.key_obj)
|
|
Packit |
1c819f |
isns_object_list_append(result, obj);
|
|
Packit |
1c819f |
isns_object_release(obj);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_scanner_destroy(&state);
|
|
Packit |
1c819f |
return status;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Print a simple message object
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
void
|
|
Packit |
1c819f |
isns_simple_print(isns_simple_t *simp, isns_print_fn_t *fn)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
char buffer[256];
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (fn == isns_debug_message
|
|
Packit |
1c819f |
&& !isns_debug_enabled(DBG_MESSAGE))
|
|
Packit |
1c819f |
return;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
fn("---%s%s---\n",
|
|
Packit |
1c819f |
isns_function_name(simp->is_function),
|
|
Packit |
1c819f |
simp->is_replace? "[REPLACE]" : "");
|
|
Packit |
1c819f |
if (simp->is_source) {
|
|
Packit |
1c819f |
fn("Source:\n", buffer);
|
|
Packit |
1c819f |
isns_attr_print(simp->is_source->is_attr, fn);
|
|
Packit |
1c819f |
} else {
|
|
Packit |
1c819f |
fn("Source: <empty>\n");
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (simp->is_message_attrs.ial_count == 0) {
|
|
Packit |
1c819f |
fn("Message attributes: <empty list>\n");
|
|
Packit |
1c819f |
} else {
|
|
Packit |
1c819f |
fn("Message attributes:\n");
|
|
Packit |
1c819f |
isns_attr_list_print(&simp->is_message_attrs, fn);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
if (simp->is_operating_attrs.ial_count == 0) {
|
|
Packit |
1c819f |
fn("Operating attributes: <empty list>\n");
|
|
Packit |
1c819f |
} else {
|
|
Packit |
1c819f |
fn("Operating attributes:\n");
|
|
Packit |
1c819f |
isns_attr_list_print(&simp->is_operating_attrs, fn);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* This set of functions analyzes the operating attrs of a registration,
|
|
Packit |
1c819f |
* or a query response, and chops it up into separate chunks, one
|
|
Packit |
1c819f |
* per objects.
|
|
Packit |
1c819f |
*
|
|
Packit |
1c819f |
* It always returns the keys and attrs for one object,
|
|
Packit |
1c819f |
* following the ordering constraints laid out in the RFC.
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
void
|
|
Packit |
1c819f |
isns_attr_list_scanner_init(struct isns_attr_list_scanner *st,
|
|
Packit |
1c819f |
isns_object_t *key_obj,
|
|
Packit |
1c819f |
const isns_attr_list_t *attrs)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
memset(st, 0, sizeof(*st));
|
|
Packit |
1c819f |
st->orig_attrs = *attrs;
|
|
Packit |
1c819f |
st->key_obj = key_obj;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
void
|
|
Packit |
1c819f |
isns_attr_list_scanner_destroy(struct isns_attr_list_scanner *st)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_attr_list_destroy(&st->keys);
|
|
Packit |
1c819f |
isns_attr_list_destroy(&st->attrs);
|
|
Packit |
1c819f |
memset(st, 0, sizeof(*st));
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_attr_list_scanner_next(struct isns_attr_list_scanner *st)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_attr_t *attr;
|
|
Packit |
1c819f |
unsigned int i, pos = st->pos;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_destroy(&st->keys);
|
|
Packit |
1c819f |
isns_attr_list_destroy(&st->attrs);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (st->orig_attrs.ial_count <= pos)
|
|
Packit |
1c819f |
return ISNS_NO_SUCH_ENTRY;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
attr = st->orig_attrs.ial_data[pos];
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* handle those funky inlined PGT definitions */
|
|
Packit |
1c819f |
if (st->pgt_next_attr && attr->ia_tag_id == st->pgt_next_attr)
|
|
Packit |
1c819f |
return isns_attr_list_scanner_get_pg(st);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* This isn't really structured programming anymore */
|
|
Packit |
1c819f |
if (st->index_acceptable
|
|
Packit |
1c819f |
&& (st->tmpl = isns_object_template_for_index_tag(attr->ia_tag_id)))
|
|
Packit |
1c819f |
goto copy_attrs;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Find the object template for the given key attr(s).
|
|
Packit |
1c819f |
* This function also enforces restrictions on the
|
|
Packit |
1c819f |
* order of key attributes.
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
st->tmpl = isns_object_template_find(attr->ia_tag_id);
|
|
Packit |
1c819f |
if (st->tmpl == NULL) {
|
|
Packit |
1c819f |
isns_debug_protocol("%s: attr %u is not a key attr\n",
|
|
Packit |
1c819f |
__FUNCTION__, attr->ia_tag_id);
|
|
Packit |
1c819f |
return ISNS_INVALID_REGISTRATION;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* Copy the key attrs */
|
|
Packit |
1c819f |
for (i = 0; i < st->tmpl->iot_num_keys; ++i, ++pos) {
|
|
Packit |
1c819f |
if (pos >= st->orig_attrs.ial_count) {
|
|
Packit |
1c819f |
isns_debug_protocol("%s: incomplete %s object "
|
|
Packit |
1c819f |
"(key attr %u missing)\n",
|
|
Packit |
1c819f |
__FUNCTION__, st->tmpl->iot_name, pos);
|
|
Packit |
1c819f |
return ISNS_INVALID_REGISTRATION;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
attr = st->orig_attrs.ial_data[pos];
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* Make sure key attrs are complete and in order */
|
|
Packit |
1c819f |
if (attr->ia_tag_id != st->tmpl->iot_keys[i]) {
|
|
Packit |
1c819f |
isns_debug_protocol("%s: incomplete %s object "
|
|
Packit |
1c819f |
"(key attr %u missing)\n",
|
|
Packit |
1c819f |
__FUNCTION__, st->tmpl->iot_name, pos);
|
|
Packit |
1c819f |
return ISNS_INVALID_REGISTRATION;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_append_attr(&st->keys, attr);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Consume all non-key attributes corresponding to the
|
|
Packit |
1c819f |
* object class. We stop whenever we hit another
|
|
Packit |
1c819f |
* key attribute, or an attribute that does not belong to
|
|
Packit |
1c819f |
* the object type (eg when a storage node is followed by
|
|
Packit |
1c819f |
* a PGT attribute, as described in section 5.6.5.1).
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
copy_attrs:
|
|
Packit |
1c819f |
while (pos < st->orig_attrs.ial_count) {
|
|
Packit |
1c819f |
uint32_t tag;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
attr = st->orig_attrs.ial_data[pos];
|
|
Packit |
1c819f |
tag = attr->ia_tag_id;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (!isns_object_attr_valid(st->tmpl, tag)
|
|
Packit |
1c819f |
|| isns_object_template_find(tag) != NULL)
|
|
Packit |
1c819f |
break;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
pos++;
|
|
Packit |
1c819f |
isns_attr_list_append_attr(&st->attrs, attr);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
st->pos = pos;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
return ISNS_SUCCESS;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
int
|
|
Packit |
1c819f |
isns_attr_list_scanner_get_pg(struct isns_attr_list_scanner *st)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
isns_attr_t *attr, *next = NULL;
|
|
Packit |
1c819f |
unsigned int pos = st->pos;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
attr = st->orig_attrs.ial_data[st->pos++];
|
|
Packit |
1c819f |
if (st->pgt_next_attr == ISNS_TAG_PG_TAG) {
|
|
Packit |
1c819f |
isns_object_t *base = st->pgt_base_object;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (ISNS_ATTR_IS_NIL(attr))
|
|
Packit |
1c819f |
st->pgt_value = 0;
|
|
Packit |
1c819f |
else if (ISNS_ATTR_IS_UINT32(attr))
|
|
Packit |
1c819f |
st->pgt_value = attr->ia_value.iv_uint32;
|
|
Packit |
1c819f |
else
|
|
Packit |
1c819f |
return ISNS_INVALID_REGISTRATION;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (ISNS_IS_PORTAL(base)
|
|
Packit |
1c819f |
&& isns_portal_from_object(&st->pgt_portal_info,
|
|
Packit |
1c819f |
ISNS_TAG_PORTAL_IP_ADDRESS,
|
|
Packit |
1c819f |
ISNS_TAG_PORTAL_TCP_UDP_PORT,
|
|
Packit |
1c819f |
base)) {
|
|
Packit |
1c819f |
st->pgt_next_attr = ISNS_TAG_PG_ISCSI_NAME;
|
|
Packit |
1c819f |
} else
|
|
Packit |
1c819f |
if (ISNS_IS_ISCSI_NODE(base)
|
|
Packit |
1c819f |
&& isns_object_get_string(base,
|
|
Packit |
1c819f |
ISNS_TAG_ISCSI_NAME,
|
|
Packit |
1c819f |
&st->pgt_iscsi_name)) {
|
|
Packit |
1c819f |
st->pgt_next_attr = ISNS_TAG_PG_PORTAL_IP_ADDR;
|
|
Packit |
1c819f |
} else {
|
|
Packit |
1c819f |
return ISNS_INTERNAL_ERROR;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* Trailing PGT at end of list. Shrug. */
|
|
Packit |
1c819f |
if (st->pos >= st->orig_attrs.ial_count)
|
|
Packit |
1c819f |
return ISNS_NO_SUCH_ENTRY;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
attr = st->orig_attrs.ial_data[st->pos++];
|
|
Packit |
1c819f |
if (attr->ia_tag_id != st->pgt_next_attr) {
|
|
Packit |
1c819f |
/* Some clients may do this; catch them so
|
|
Packit |
1c819f |
* we can fix it. */
|
|
Packit |
1c819f |
isns_error("Oops, client sends PGT followed by <%s>\n",
|
|
Packit |
1c819f |
attr->ia_tag->it_name);
|
|
Packit |
1c819f |
return ISNS_INVALID_REGISTRATION;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
st->tmpl = &isns_iscsi_pg_template;
|
|
Packit |
1c819f |
if (st->pgt_next_attr == ISNS_TAG_PG_ISCSI_NAME) {
|
|
Packit |
1c819f |
isns_attr_list_append_attr(&st->keys, attr);
|
|
Packit |
1c819f |
isns_portal_to_attr_list(&st->pgt_portal_info,
|
|
Packit |
1c819f |
ISNS_TAG_PG_PORTAL_IP_ADDR,
|
|
Packit |
1c819f |
ISNS_TAG_PG_PORTAL_TCP_UDP_PORT,
|
|
Packit |
1c819f |
&st->keys);
|
|
Packit |
1c819f |
} else
|
|
Packit |
1c819f |
if (st->pgt_next_attr == ISNS_TAG_PG_PORTAL_IP_ADDR) {
|
|
Packit |
1c819f |
if (st->pos >= st->orig_attrs.ial_count)
|
|
Packit |
1c819f |
return ISNS_INVALID_REGISTRATION;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
next = st->orig_attrs.ial_data[st->pos++];
|
|
Packit |
1c819f |
if (next->ia_tag_id != ISNS_TAG_PG_PORTAL_TCP_UDP_PORT)
|
|
Packit |
1c819f |
return ISNS_INVALID_REGISTRATION;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_append_string(&st->keys,
|
|
Packit |
1c819f |
ISNS_TAG_PG_ISCSI_NAME,
|
|
Packit |
1c819f |
st->pgt_iscsi_name);
|
|
Packit |
1c819f |
isns_attr_list_append_attr(&st->keys, attr);
|
|
Packit |
1c819f |
isns_attr_list_append_attr(&st->keys, next);
|
|
Packit |
1c819f |
} else {
|
|
Packit |
1c819f |
return ISNS_INTERNAL_ERROR;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_append_uint32(&st->attrs,
|
|
Packit |
1c819f |
ISNS_TAG_PG_TAG,
|
|
Packit |
1c819f |
st->pgt_value);
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/* Copy other PG attributes if present */
|
|
Packit |
1c819f |
for (pos = st->pos; pos < st->orig_attrs.ial_count; ++pos) {
|
|
Packit |
1c819f |
uint32_t tag;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
attr = st->orig_attrs.ial_data[pos];
|
|
Packit |
1c819f |
tag = attr->ia_tag_id;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Additional sets of PGTs and PG iSCSI Names to be
|
|
Packit |
1c819f |
* associated to the registered Portal MAY follow.
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
if (tag == ISNS_TAG_PG_TAG) {
|
|
Packit |
1c819f |
st->pgt_next_attr = tag;
|
|
Packit |
1c819f |
break;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
if (tag == ISNS_TAG_PG_ISCSI_NAME
|
|
Packit |
1c819f |
|| tag == ISNS_TAG_PG_PORTAL_IP_ADDR
|
|
Packit |
1c819f |
|| tag == ISNS_TAG_PG_PORTAL_TCP_UDP_PORT
|
|
Packit |
1c819f |
|| !isns_object_attr_valid(st->tmpl, tag))
|
|
Packit |
1c819f |
break;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
isns_attr_list_append_attr(&st->attrs, attr);
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
st->pos = pos;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
return ISNS_SUCCESS;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
/*
|
|
Packit |
1c819f |
* Get the name of a function
|
|
Packit |
1c819f |
*/
|
|
Packit |
1c819f |
#define __ISNS_MAX_FUNCTION 16
|
|
Packit |
1c819f |
static const char * isns_req_function_names[__ISNS_MAX_FUNCTION] = {
|
|
Packit |
1c819f |
[ISNS_DEVICE_ATTRIBUTE_REGISTER]= "DevAttrReg",
|
|
Packit |
1c819f |
[ISNS_DEVICE_ATTRIBUTE_QUERY] = "DevAttrQry",
|
|
Packit |
1c819f |
[ISNS_DEVICE_GET_NEXT] = "DevGetNext",
|
|
Packit |
1c819f |
[ISNS_DEVICE_DEREGISTER] = "DevDereg",
|
|
Packit |
1c819f |
[ISNS_SCN_REGISTER] = "SCNReg",
|
|
Packit |
1c819f |
[ISNS_SCN_DEREGISTER] = "SCNDereg",
|
|
Packit |
1c819f |
[ISNS_SCN_EVENT] = "SCNEvent",
|
|
Packit |
1c819f |
[ISNS_STATE_CHANGE_NOTIFICATION]= "SCN",
|
|
Packit |
1c819f |
[ISNS_DD_REGISTER] = "DDReg",
|
|
Packit |
1c819f |
[ISNS_DD_DEREGISTER] = "DDDereg",
|
|
Packit |
1c819f |
[ISNS_DDS_REGISTER] = "DDSReg",
|
|
Packit |
1c819f |
[ISNS_DDS_DEREGISTER] = "DDSDereg",
|
|
Packit |
1c819f |
[ISNS_ENTITY_STATUS_INQUIRY] = "ESI",
|
|
Packit |
1c819f |
[ISNS_HEARTBEAT] = "Heartbeat",
|
|
Packit |
1c819f |
};
|
|
Packit |
1c819f |
static const char * isns_resp_function_names[__ISNS_MAX_FUNCTION] = {
|
|
Packit |
1c819f |
[ISNS_DEVICE_ATTRIBUTE_REGISTER]= "DevAttrRegResp",
|
|
Packit |
1c819f |
[ISNS_DEVICE_ATTRIBUTE_QUERY] = "DevAttrQryResp",
|
|
Packit |
1c819f |
[ISNS_DEVICE_GET_NEXT] = "DevGetNextResp",
|
|
Packit |
1c819f |
[ISNS_DEVICE_DEREGISTER] = "DevDeregResp",
|
|
Packit |
1c819f |
[ISNS_SCN_REGISTER] = "SCNRegResp",
|
|
Packit |
1c819f |
[ISNS_SCN_DEREGISTER] = "SCNDeregResp",
|
|
Packit |
1c819f |
[ISNS_SCN_EVENT] = "SCNEventResp",
|
|
Packit |
1c819f |
[ISNS_STATE_CHANGE_NOTIFICATION]= "SCNResp",
|
|
Packit |
1c819f |
[ISNS_DD_REGISTER] = "DDRegResp",
|
|
Packit |
1c819f |
[ISNS_DD_DEREGISTER] = "DDDeregResp",
|
|
Packit |
1c819f |
[ISNS_DDS_REGISTER] = "DDSRegResp",
|
|
Packit |
1c819f |
[ISNS_DDS_DEREGISTER] = "DDSDeregResp",
|
|
Packit |
1c819f |
[ISNS_ENTITY_STATUS_INQUIRY] = "ESIRsp",
|
|
Packit |
1c819f |
/* No response code for heartbeat */
|
|
Packit |
1c819f |
};
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
const char *
|
|
Packit |
1c819f |
isns_function_name(uint32_t function)
|
|
Packit |
1c819f |
{
|
|
Packit |
1c819f |
static char namebuf[32];
|
|
Packit |
1c819f |
const char **names, *name;
|
|
Packit |
1c819f |
unsigned int num = function;
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
names = isns_req_function_names;
|
|
Packit |
1c819f |
if (num & 0x8000) {
|
|
Packit |
1c819f |
names = isns_resp_function_names;
|
|
Packit |
1c819f |
num &= 0x7fff;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
name = NULL;
|
|
Packit |
1c819f |
if (num < __ISNS_MAX_FUNCTION)
|
|
Packit |
1c819f |
name = names[num];
|
|
Packit |
1c819f |
if (name == NULL) {
|
|
Packit |
1c819f |
snprintf(namebuf, sizeof(namebuf),
|
|
Packit |
1c819f |
"<function %08x>",
|
|
Packit |
1c819f |
function);
|
|
Packit |
1c819f |
name = namebuf;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|
|
Packit |
1c819f |
return name;
|
|
Packit |
1c819f |
}
|
|
Packit |
1c819f |
|