Blame simple.c

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