original files of m241

This commit is contained in:
neelimap
2026-07-30 11:19:44 +05:30
parent 170c2b3f3a
commit afc7070c1f
12254 changed files with 7655111 additions and 0 deletions
@@ -0,0 +1,790 @@
/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipdhcpc6_shell.c,v $ $Revision: 1.13.18.1 $
* $Source: /home/interpeak/CVSRoot/ipdhcpc6/src/ipdhcpc6_shell.c,v $
* $Author: ulf $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipdhcpc6_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_list.h>
#include <ipcom_hash.h>
#include <ipcom_syslog.h>
#include <ipcom_err.h>
#include <ipcom_tmo2.h>
#include "ipdhcpc6.h"
#include "ipdhcpc6_h.h"
#include "ipdhcpc6_msg.h"
#include "ipdhcpc6_if.h"
#include "ipdhcpc6_ia.h"
#include "ipdhcpc6_shell.h"
#include "ipdhcpc6_attr.h"
#include "ipdhcpc6_rtadv.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipdhcpc6_shell_args
{
Ipdhcpc6_context_t *context;
Ipdhcpc6_tagcomm_buffer_t *buf;
Ipdhcpc6_if_t *ifp;
Ipdhcpc6_ia_t *ia;
Ip_u32 cmd;
} Ipdhcpc6_shell_args_t;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC int ipdhcpc6_shell_parse_ia_command(Ipdhcpc6_shell_args_t *args,
Ipdhcpc6_tagcomm_tag_t *tag);
IP_STATIC int ipdhcpc6_shell_parse_ia_command_attributes(Ipdhcpc6_shell_args_t *args,
Ipdhcpc6_tagcomm_tag_t *tag);
IP_STATIC int ipdhcpc6_shell_parse_ia_ifobj_attributes(Ipdhcpc6_shell_args_t *args,
Ipdhcpc6_tagcomm_tag_t *tag);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
static Ipdhcpc6_tagcomm_parser_t ipdhcpc6_shell_commands[] =
{
{
IPDHCPC6_CMD_IA_INFO,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command
},
{
IPDHCPC6_CMD_IA_REFRESH,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command
},
{
IPDHCPC6_CMD_IA_RELEASE,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command
},
{
IPDHCPC6_CMD_IA_HISTORY_FLUSH,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command
},
{
IPDHCPC6_CMD_IA_RTSOL,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command
},
{
IPDHCPC6_CMD_IA_BOUND_ADD,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command
},
{
IPDHCPC6_CMD_IA_BOUND_DEL,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command
},
{ 0, IP_NULL }
};
static Ipdhcpc6_tagcomm_parser_t ipdhcpc6_shell_ia_command_attributes[] =
{
{
IPDHCPC6_IA_OBJECT_IF,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command_attributes
},
{
IPDHCPC6_IA_IDENT_DUID,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command_attributes
},
{ 0, IP_NULL }
};
static Ipdhcpc6_tagcomm_parser_t ipdhcpc6_shell_ia_ifobj_attributes[] =
{
{
IPDHCPC6_IA_OBJECT_IF_AUTOMATIC,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_ifobj_attributes
},
{
IPDHCPC6_IA_OBJECT_IF_CONFIG,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_ifobj_attributes
},
{
IPDHCPC6_IA_OBJECT_IA,
(Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_ifobj_attributes
},
{ 0, IP_NULL }
};
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdhcpc6_shell_context_client_free
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_shell_context_client_free(Ipdhcpc6_shell_client_t *cfd)
{
ipcom_list_remove(&cfd->next);
ipdhcpc6_util_free(&cfd->rbuf.buffer);
if (cfd->fd != IP_INVALID_SOCKET)
ipcom_socketclose(cfd->fd);
ipdhcpc6_util_free(&cfd);
}
/*
*===========================================================================
* ipdhcpc6_shell_parse_errout
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipdhcpc6_shell_parse_errout(Ipdhcpc6_shell_args_t *args,
Ipdhcpc6_tagcomm_tag_t *tag)
{
ipdhcpc6_tagcomm_failure(args->buf,
tag,
IPDHCPC6_TAGCOMM_STATUS_UNKNOWN_TAG);
return 0;
}
/*
*===========================================================================
* ipdhcpc6_shell_parse_ia_ifobj_attributes
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipdhcpc6_shell_parse_ia_ifobj_attributes(Ipdhcpc6_shell_args_t *args,
Ipdhcpc6_tagcomm_tag_t *tag)
{
Ipdhcpc6_attr_ia_t *iaobj;
switch (tag->tag)
{
case IPDHCPC6_IA_OBJECT_IF_CONFIG:
if (args->cmd == IPDHCPC6_CMD_IA_INFO)
{
ipdhcpc6_tagcomm_enter_tag(args->buf,
IPDHCPC6_IA_OBJECT_IF_CONFIG,
IPDHCPC6_TAGCOMM_STATUS_OK);
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_CONFIG_RAPID_COMMIT,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->conf.rapid_commit,
sizeof(args->ifp->conf.rapid_commit));
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_CONFIG_INFO_ONLY,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->conf.information_only,
sizeof(args->ifp->conf.information_only));
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_CONFIG_DNS,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->conf.dns,
sizeof(args->ifp->conf.dns));
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_CONFIG_SNTP,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->conf.sntp,
sizeof(args->ifp->conf.sntp));
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_CONFIG_INFO_REFRESH,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->conf.information_only,
sizeof(args->ifp->conf.information_only));
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_CONFIG_SIP,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->conf.sip,
sizeof(args->ifp->conf.sip));
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_CONFIG_FQDN,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->conf.fqdn.fqdn,
sizeof(args->ifp->conf.fqdn.fqdn));
ipdhcpc6_tagcomm_leave_tag(args->buf);
}
break;
case IPDHCPC6_IA_OBJECT_IF_AUTOMATIC:
if (args->cmd == IPDHCPC6_CMD_IA_INFO)
{
if (args->ifp->mode == IPDHCPC6_MODE_AUTOMATIC)
{
ipdhcpc6_tagcomm_enter_tag(args->buf,
IPDHCPC6_IA_OBJECT_IF_AUTOMATIC,
IPDHCPC6_TAGCOMM_STATUS_OK);
if (IP_IN6_ARE_ADDR_EQUAL(&args->ifp->automatic.rtr, &ip_in6addr_any) == IP_FALSE)
{
ipdhcpc6_tagcomm_enter_tag(args->buf,
IPDHCPC6_IA_OBJECT_SERVER,
IPDHCPC6_TAGCOMM_STATUS_OK);
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_ADDRESS,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->automatic.rtr,
sizeof(args->ifp->automatic.rtr));
ipdhcpc6_tagcomm_leave_tag(args->buf);
}
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_AUTOMATIC_MANAGED,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->automatic.runtime.managed,
sizeof(args->ifp->automatic.runtime.managed));
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_ATTR_IF_AUTOMATIC_OTHER,
IPDHCPC6_TAGCOMM_STATUS_OK,
&args->ifp->automatic.runtime.other,
sizeof(args->ifp->automatic.runtime.other));
ipdhcpc6_tagcomm_leave_tag(args->buf);
}
}
break;
case IPDHCPC6_IA_OBJECT_IA:
iaobj = ipdhcpc6_attr_ia_parse(tag, IPDHCPC6_TAGCOMM_TAG_IDENTITY);
if (iaobj)
{
if (iaobj->iatype >= IPDHCPC6_IA_TYPE_MAX)
{
ipdhcpc6_tagcomm_failure(args->buf,
tag,
IPDHCPC6_ATTR_TAG_STATUS_UNKNOWN_IA);
}
else
{
/* Not specified */
if (iaobj->ianame == IP_NULL && iaobj->iaid == 0)
{
args->ia = IPCOM_LIST_FIRST(&args->ifp->ia_head[iaobj->iatype]);
while (args->ia != IP_NULL)
{
args->ia->table->attributes(args->cmd,
args->ia,
tag,
args->buf);
/* Next IA */
args->ia = IPCOM_LIST_NEXT(&args->ia->next);
}
}
else
{
args->ia = ipdhcpc6_ia_lookup_by_iaobj(args->ifp, iaobj);
if (args->ia == IP_NULL)
{
ipdhcpc6_tagcomm_failure(args->buf,
tag,
IPDHCPC6_ATTR_TAG_STATUS_UNKNOWN_IA);
}
else
{
args->ia->table->attributes(args->cmd,
args->ia,
tag,
args->buf);
}
}
}
ipdhcpc6_attr_ia_free(&iaobj);
}
else
{
ipdhcpc6_tagcomm_failure(args->buf,
tag,
IPDHCPC6_TAGCOMM_STATUS_PARSE_FAILED);
}
break;
}
return 0;
}
/*
*===========================================================================
* ipdhcpc6_shell_parse_ia_command_attributes
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipdhcpc6_shell_parse_ia_command_attributes(Ipdhcpc6_shell_args_t *args,
Ipdhcpc6_tagcomm_tag_t *tag)
{
int result = 0;
Ipdhcpc6_attr_if_t *ifobj;
/* Store base command */
switch (tag->tag)
{
case IPDHCPC6_IA_OBJECT_IF:
ifobj = ipdhcpc6_attr_if_parse(tag, IPDHCPC6_TAGCOMM_TAG_IDENTITY);
if (ifobj)
{
if (ifobj->ifname == IP_NULL)
{
/* Wild card match */
args->ifp = IPCOM_LIST_FIRST(&args->context->ifctx->ifp_head);
while (args->ifp != IP_NULL)
{
ipdhcpc6_tagcomm_enter_tag(args->buf, tag->tag, IPDHCPC6_TAGCOMM_STATUS_OK);
ipdhcpc6_if_attr_header(args->ifp, args->buf);
switch (args->cmd)
{
case IPDHCPC6_CMD_IA_RTSOL:
ipdhcpc6_rtadv_up(args->ifp->context->context, args->ifp);
break;
default:
result = ipdhcpc6_tagcomm_parse(ipdhcpc6_shell_ia_ifobj_attributes,
(Ipdhcpc6_tagcomm_parse_object_t)ipdhcpc6_shell_parse_errout,
tag,
args);
break;
}
ipdhcpc6_tagcomm_leave_tag(args->buf);
if (result != 0)
break;
/* Next interface */
args->ifp = IPCOM_LIST_NEXT(&args->ifp->next);
}
}
else
{
args->ifp = ipdhcpc6_if_lookup_by_ifobj(args->context, ifobj);
if (args->ifp == IP_NULL)
{
ipdhcpc6_tagcomm_failure(args->buf,
tag,
IPDHCPC6_ATTR_TAG_STATUS_UNKNOWN_INTERFACE);
}
else
{
ipdhcpc6_tagcomm_enter_tag(args->buf, tag->tag, IPDHCPC6_TAGCOMM_STATUS_OK);
ipdhcpc6_if_attr_header(args->ifp, args->buf);
switch (args->cmd)
{
case IPDHCPC6_CMD_IA_RTSOL:
ipdhcpc6_rtadv_up(args->ifp->context->context, args->ifp);
break;
default:
result = ipdhcpc6_tagcomm_parse(ipdhcpc6_shell_ia_ifobj_attributes,
(Ipdhcpc6_tagcomm_parse_object_t)ipdhcpc6_shell_parse_errout,
tag,
args);
break;
}
ipdhcpc6_tagcomm_leave_tag(args->buf);
}
}
ipdhcpc6_attr_if_free(&ifobj);
}
else
{
ipdhcpc6_tagcomm_failure(args->buf,
tag,
IPDHCPC6_TAGCOMM_STATUS_PARSE_FAILED);
}
break;
}
return result;
}
/*
*===========================================================================
* ipdhcpc6_shell_parse_ia_command
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipdhcpc6_shell_parse_ia_command(Ipdhcpc6_shell_args_t *args,
Ipdhcpc6_tagcomm_tag_t *tag)
{
int result;
/* Store base command */
args->cmd = tag->tag;
ipdhcpc6_tagcomm_enter_tag(args->buf, tag->tag, IPDHCPC6_TAGCOMM_STATUS_OK);
/* Add the DUID */
ipdhcpc6_tagcomm_add_tag(args->buf,
IPDHCPC6_IA_IDENT_DUID,
IPDHCPC6_TAGCOMM_STATUS_OK,
args->context->ifctx->duid.head,
args->context->ifctx->duid.offset);
result = ipdhcpc6_tagcomm_parse(ipdhcpc6_shell_ia_command_attributes,
(Ipdhcpc6_tagcomm_parse_object_t)ipdhcpc6_shell_parse_errout,
tag,
args);
ipdhcpc6_tagcomm_leave_tag(args->buf);
return result;
}
/*
*===========================================================================
* ipdhcpc6_shell_command
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipdhcpc6_shell_parse_command(Ipdhcpc6_context_t *context,
Ipdhcpc6_tagcomm_tag_t *tag,
Ipdhcpc6_tagcomm_buffer_t *response)
{
Ipdhcpc6_shell_args_t args;
ipcom_memset(&args, 0, sizeof(args));
args.context = context;
args.buf = response;
return ipdhcpc6_tagcomm_parse(ipdhcpc6_shell_commands,
(Ipdhcpc6_tagcomm_parse_object_t)ipdhcpc6_shell_parse_errout,
tag,
&args);
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdhcpc6_shell_context_alloc
*===========================================================================
* Description: Allocate an shell context
* Parameters: context - The DHCPC6 context.
* Returns: An shell context.
*
*/
IP_GLOBAL Ipdhcpc6_shell_context_t *
ipdhcpc6_shell_context_alloc(struct Ipdhcpc6_context *context)
{
Ipdhcpc6_shell_context_t *shellctx = ipcom_calloc(1, sizeof(*shellctx));
if (shellctx)
{
struct Ip_sockaddr_in6 sin6;
int opt;
shellctx->context = context;
/* Create the client head */
ipcom_list_init(&shellctx->head);
/* Create the FD */
shellctx->client_fd = ipcom_socket(IP_AF_INET6, IP_SOCK_STREAM, IP_IPPROTO_TCP);
if (shellctx->client_fd == IP_INVALID_SOCKET)
goto errout;
ipcom_memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = IP_AF_INET6;
sin6.sin6_len = sizeof(sin6);
sin6.sin6_port = ip_htons(IPDHCPC6_CLIENT_PORT);
sin6.sin6_addr = ip_in6addr_loopback;
opt = 1;
if (ipcom_setsockopt(shellctx->client_fd, IP_SOL_SOCKET, IP_SO_REUSEPORT, (char *)&opt, sizeof(opt)) < 0)
{
IPCOM_LOG2(WARNING,
"%s: Failed to set reuse port on client socket, errno = %d", context->name, ipcom_errno);
}
if (ipcom_bind(shellctx->client_fd, (struct Ip_sockaddr *) &sin6, sizeof(sin6)) < 0)
{
IPCOM_LOG2(ERR,
"%s: Failed to bind client socket, errno = %d", context->name, ipcom_errno);
goto errout;
}
if (ipcom_listen(shellctx->client_fd, 5) < 0)
{
IPCOM_LOG2(ERR,
"%s: Failed to listen on client socket, errno = %d", context->name, ipcom_errno);
goto errout;
}
}
return shellctx;
errout:
if (shellctx->client_fd != IP_INVALID_SOCKET)
ipcom_socketclose(shellctx->client_fd);
ipdhcpc6_util_free(&shellctx);
return IP_NULL;
}
/*
*===========================================================================
* ipdhcpc6_shell_context_free
*===========================================================================
* Description: Free an shell context
* Parameters: shellctxp - Pointer to the DHCPC6 shellcontext.
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_shell_context_free(Ipdhcpc6_shell_context_t **shellctxp)
{
Ipdhcpc6_shell_context_t *shellctx = *shellctxp;
if (shellctx)
{
Ipdhcpc6_shell_client_t *cfd;
while ((cfd = IPCOM_LIST_FIRST(&shellctx->head)) != IP_NULL)
ipdhcpc6_shell_context_client_free(cfd);
ipcom_socketclose(shellctx->client_fd);
ipdhcpc6_util_free(&shellctx);
}
*shellctxp = IP_NULL;
}
/*
*===========================================================================
* ipdhcpc6_shell_context_fdset_init
*===========================================================================
* Description: Initialize all file descriptors of this context
* Parameters: shellctx - Attribute context
* rset - Read set to initialize.
* mfd - Maximum file descriptor.
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_shell_context_fdset_init(Ipdhcpc6_shell_context_t *shellctx,
Ip_fd_set *rset,
int *mfd)
{
int maxfd = *mfd;
Ipdhcpc6_shell_client_t *cfd;
/* Add the client socket */
IP_FD_SET(shellctx->client_fd, rset);
maxfd = IP_MAX(shellctx->client_fd, maxfd);
cfd = IPCOM_LIST_FIRST(&shellctx->head);
while (cfd != IP_NULL)
{
IP_FD_SET(cfd->fd, rset);
maxfd = IP_MAX(cfd->fd, maxfd);
cfd = IPCOM_LIST_NEXT(&cfd->next);
}
*mfd = maxfd;
}
/*
*===========================================================================
* ipdhcpc6_shell_context_fdset_process
*===========================================================================
* Description: Process all file descriptors of this context
* Parameters: shellctx - Attribute context
* rset - Read set to initialize.
* status - Incoming status
* Returns: Outgoing status
*
*/
IP_GLOBAL int
ipdhcpc6_shell_context_fdset_process(Ipdhcpc6_shell_context_t *shellctx,
Ip_fd_set *rset,
int status)
{
Ipdhcpc6_shell_client_t *cfd, *ncfd;
/* Check the clients */
cfd = IPCOM_LIST_FIRST(&shellctx->head);
while (cfd != IP_NULL)
{
Ip_ssize_t ret;
ncfd = IPCOM_LIST_NEXT(&cfd->next);
/**/
if (IP_FD_ISSET(cfd->fd, rset))
{
if (cfd->rbuf.buffer == IP_NULL)
{
if (ipdhcpc6_attr_recvhdr(cfd->fd, &cfd->rbuf) == IP_FALSE)
{
ipdhcpc6_shell_context_client_free(cfd);
cfd = IP_NULL;
}
}
if (cfd)
{
ret = ipdhcpc6_attr_read(cfd->fd, &cfd->rbuf, IP_FALSE);
if (ret < 0)
ipdhcpc6_shell_context_client_free(cfd);
else if (ret == 0)
{
Ipdhcpc6_tagcomm_buffer_t *response = ipdhcpc6_tagcomm_buffer_alloc();
if (response)
{
/* We've got an entire command */
if (ipdhcpc6_shell_parse_command(shellctx->context,
(void *)cfd->rbuf.buffer,
response) == 0)
{
ipdhcpc6_attr_sendmsg(cfd->fd, response);
}
ipdhcpc6_tagcomm_buffer_free(&response);
}
/* Free the current buffer */
ipdhcpc6_util_free(&cfd->rbuf.buffer);
}
}
}
/* Do next */
cfd = ncfd;
}
/* Check the */
if (IP_FD_ISSET(shellctx->client_fd, rset))
{
/* Do create a new client */
ncfd = ipcom_calloc(1, sizeof(*ncfd));
if (ncfd)
{
struct Ip_sockaddr_in6 sin6;
Ip_socklen_t slen = sizeof(sin6);
ipcom_list_insert_last(&shellctx->head, &ncfd->next);
ncfd->fd = ipcom_accept(shellctx->client_fd, (struct Ip_sockaddr *)&sin6, &slen);
if (ncfd->fd == IP_INVALID_SOCKET)
ipdhcpc6_shell_context_client_free(ncfd);
}
}
return status;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/