1102 lines
43 KiB
C
1102 lines
43 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6pm_attr.c,v $ $Revision: 1.22 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmip6pm/src/ipmip6pm_attr.c,v $
|
|
* $Author: jhorteli $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipmip6pm_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_ipd.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock2.h>
|
|
#include <ipcom_sysctl.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_route.h>
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_buffer.h>
|
|
#include <private/ipmip_util.h>
|
|
|
|
#include <ipmip6.h>
|
|
#include <private/ipmip6_context.h>
|
|
#include <private/ipmip6_mh.h>
|
|
#include <private/ipmip6_mh_pkt.h>
|
|
#include <private/ipmip6_if.h>
|
|
#include <private/ipmip6_util.h>
|
|
|
|
#include "ipmip6pm_h.h"
|
|
#include "ipmip6pm_attr.h"
|
|
#include "ipmip6pm_attr_h.h"
|
|
#include "ipmip6pm_node.h"
|
|
#include "ipmip6pm_if.h"
|
|
#include "ipmip6pm_mh.h"
|
|
#include "ipmip6pm_route.h"
|
|
#include "ipmip6pm_lma.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
struct Ipmip6pm_attr_op
|
|
{
|
|
Ipmip_cli_message_t *request;
|
|
Ipmip6pm_node_lookup_t nargs;
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
const char *ipmip6pm_attr_status_desc[IPMIP6PM_CLI_ATTR_BC_P_STATUS_MAX] =
|
|
{
|
|
"created",
|
|
"pending",
|
|
"retransmit",
|
|
"timeout",
|
|
"error",
|
|
"deleted",
|
|
"registered",
|
|
"running"
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipfa_node_del_cb
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmip6pm_attr_list_nodes(Ipmip6pm_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6pm_node_t *node,
|
|
struct Ipmip6pm_attr_op *ops,
|
|
void *unused)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(unused);
|
|
|
|
/* Match NAI */
|
|
if (ops->nargs.nai_mn != IP_NULL && ops->nargs.nai_mn_len > 0)
|
|
{
|
|
if (!ipmip_util_strnncmp(ops->nargs.nai_mn, ops->nargs.nai_mn_len, (char *)&node->mo_nai_mn->nai[0], node->mo_nai_mn->hdr.len - 1))
|
|
return;
|
|
}
|
|
|
|
if (!ipmip6pm_node_compare(node, &ops->nargs))
|
|
return;
|
|
|
|
/* Add this node */
|
|
ipmip_attr_put_u32(&ops->request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_HANDLE,
|
|
node->identity);
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip6pm_attr_build_lookup(Ipmip6pm_node_lookup_t *nargs,
|
|
struct Ipmip_attr **idattr)
|
|
{
|
|
/* NAI */
|
|
if (idattr[IPMIP6PM_CLI_ATTR_BC_P_MOBILE_NAI] != IP_NULL)
|
|
{
|
|
nargs->nai_mn = IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_MOBILE_NAI]);
|
|
nargs->nai_mn_len = ipmip_util_strnlen(nargs->nai_mn, IPMIP_ATTR_PAYLOAD(idattr[IPMIP6PM_CLI_ATTR_BC_P_MOBILE_NAI]));
|
|
}
|
|
|
|
if (idattr[IPMIP6PM_CLI_ATTR_BC_P_IFIDENT] != IP_NULL)
|
|
{
|
|
nargs->args.lladdr = IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_IFIDENT]);
|
|
nargs->args.lladdr_len = IPMIP_ATTR_PAYLOAD(idattr[IPMIP6PM_CLI_ATTR_BC_P_IFIDENT]);
|
|
IP_BIT_SET(nargs->search_params, IPMIP6PM_NODE_LOOKUP_LLADDR);
|
|
}
|
|
|
|
if (idattr[IPMIP6PM_CLI_ATTR_BC_P_IFNAME] != IP_NULL)
|
|
{
|
|
nargs->args.ifname = IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_IFNAME]);
|
|
IP_BIT_SET(nargs->search_params, IPMIP6PM_NODE_LOOKUP_IFNAME);
|
|
}
|
|
|
|
if (idattr[IPMIP6PM_CLI_ATTR_BC_P_ACCESS_TYPE] != IP_NULL)
|
|
{
|
|
nargs->args.access_type = ipmip_attr_get_u32(idattr[IPMIP6PM_CLI_ATTR_BC_P_ACCESS_TYPE]);
|
|
IP_BIT_SET(nargs->search_params, IPMIP6PM_NODE_LOOKUP_ACCESS_TYPE);
|
|
}
|
|
|
|
if (idattr[IPMIP6PM_CLI_ATTR_BC_P_HOME_PREFIX_LIST] != IP_NULL)
|
|
{
|
|
nargs->args.home_prefix = IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_HOME_PREFIX_LIST]);
|
|
nargs->args.home_prefix_size = IPMIP_ATTR_PAYLOAD(idattr[IPMIP6PM_CLI_ATTR_BC_P_HOME_PREFIX_LIST]) / sizeof(Ipmip6_address_t);
|
|
IP_BIT_SET(nargs->search_params, IPMIP6PM_NODE_LOOKUP_HOME_PREFIX);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IP_STATIC int
|
|
ipmip6pm_attr_node_dump(int event,
|
|
Ipmip6pm_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip_cli_message_t *request,
|
|
Ipmip6pm_node_t *node)
|
|
{
|
|
if (event == IPMIP_TIMER_EVENT_RUN)
|
|
{
|
|
struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request);
|
|
Ip_size_t rhdr = 0;
|
|
Ip_size_t rta;
|
|
Ip_size_t rta_sub;
|
|
|
|
if (node == IP_NULL)
|
|
rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_ENOENT, IP_NULL);
|
|
else
|
|
{
|
|
/* Do retrieve statistics */
|
|
ipmip6pm_netlink_get_handle_stat(ctx, proc, node);
|
|
switch (IPMIP_ATTR_HDR_TYPE(hdr))
|
|
{
|
|
case IPMIP6PM_CLI_BC_P_GET:
|
|
{
|
|
Ip_u32 f, i;
|
|
|
|
/**/
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
|
|
|
|
rta = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P);
|
|
|
|
/* Put the home address entry */
|
|
ipmip_attr_put_str(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_IFNAME,
|
|
node->ifp_private.ipmip6.ifp->iff.ifname);
|
|
ipmip_attr_put_str(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_COA_IFNAME,
|
|
node->ifp_public->ipmip6.iff.ifname);
|
|
|
|
/* Add the MO for MN NAI */
|
|
ipmip_attr_put_strn(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_MOBILE_NAI,
|
|
(char *)&node->mo_nai_mn->nai[0],
|
|
node->mo_nai_mn->hdr.len - 1);
|
|
|
|
ipmip_attr_put_u32(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_ACCESS_TYPE,
|
|
node->mo_access_type->att);
|
|
|
|
ipmip_attr_put_u32(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_HANDOFF_INDICATOR,
|
|
node->mo_handoff_indicator->hi);
|
|
|
|
ipmip_attr_put_inet6(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_HOME_AGENT,
|
|
&node->homeagent);
|
|
|
|
ipmip_attr_put_u32(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_TUNNEL_TYPE,
|
|
node->transport_tunnel_type);
|
|
|
|
ipmip_attr_put_u32(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_HANDLE,
|
|
node->identity);
|
|
|
|
ipmip_attr_put_u32(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_TRANSPORT_MASK,
|
|
node->supported_tunnel_types);
|
|
|
|
ipmip_attr_put_str(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_TUNNEL_IFNAME,
|
|
node->ifp_public->iftunnels[node->transport_tunnel_type]->ipmip6.iff.ifname);
|
|
|
|
/* We're GRE */
|
|
if (IPMIP_TUNNELTYPE_IS_GRE(node->transport_tunnel_type))
|
|
{
|
|
rta_sub = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P_GRE);
|
|
if (IPMIP6PM_NODE_USE_GRE_KEYS(node))
|
|
{
|
|
Ip_size_t off = ipmip_buffer_append(&request->message, IP_NULL, sizeof(Ip_u32) * 2);
|
|
Ip_u32 *v = ipmip_buffer_offset(&request->message, off);
|
|
|
|
IP_SET_HTONL(&v[0], node->gre_key[0]);
|
|
IP_SET_HTONL(&v[1], node->gre_key[1]);
|
|
}
|
|
ipmip_attr_end(&request->message, rta_sub);
|
|
}
|
|
|
|
if (IPMIP6PM_NODE_HOMEAGENT_INET(node))
|
|
{
|
|
ipmip_attr_put_inet(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_HOME_AGENT_INET,
|
|
IPMIP6PM_NODE_HOMEAGENT_INET(node));
|
|
}
|
|
|
|
/* */
|
|
if (node->mo_link_layer_id)
|
|
{
|
|
ipmip_attr_put(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_IFIDENT,
|
|
node->mo_link_layer_id->hdr.len - 2,
|
|
&node->mo_link_layer_id->lli[0]);
|
|
}
|
|
|
|
/* Send the LLA if it exists */
|
|
if (node->lla)
|
|
{
|
|
ipmip_attr_put(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_IFLLA,
|
|
node->lla->len,
|
|
node->lla);
|
|
}
|
|
|
|
ipmip_attr_put_time_t(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_CREATED,
|
|
node->created);
|
|
|
|
ipmip_attr_put_u32(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_STATUS,
|
|
node->status);
|
|
|
|
|
|
rta_sub = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HOME_PREFIX_LIST);
|
|
for (i = 0; i < node->mo_home_prefix_size; i++)
|
|
{
|
|
Ipmip6_address_t addr;
|
|
ipcom_memcpy(&addr.prefix, &node->mo_home_prefix[i].prefix, sizeof(addr.prefix));
|
|
addr.len = node->mo_home_prefix[i].prefix_length;
|
|
ipmip_buffer_append(&request->message, &addr, sizeof(addr));
|
|
}
|
|
|
|
ipmip_attr_end(&request->message, rta_sub);
|
|
|
|
#ifdef IPMIP_USE_INET
|
|
if (node->mo_dsmipv6_home_prefix.prefix != 0)
|
|
{
|
|
ipmip_attr_put(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_HOME_ADDRESS_INET,
|
|
sizeof(node->mo_dsmipv6_home_prefix),
|
|
&node->mo_dsmipv6_home_prefix);
|
|
}
|
|
#endif
|
|
|
|
/**/
|
|
ipmip_attr_put(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_MIB_mip6MnBLTable,
|
|
sizeof(node->mip6MnBLTable),
|
|
&node->mip6MnBLTable);
|
|
|
|
ipmip_attr_put(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_MIB_mip6NodeTrafficEntry,
|
|
sizeof(node->mip6NodeTrafficEntry),
|
|
&node->mip6NodeTrafficEntry);
|
|
|
|
/* */
|
|
if (node->ifp_private.ipmip6.ifp->iff.lladdr)
|
|
{
|
|
ipmip_attr_put(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_MAG_Link_Layer,
|
|
IPMIP_LLADDR_LEN(node->ifp_private.ipmip6.ifp->iff.lladdr),
|
|
node->ifp_private.ipmip6.ifp->iff.lladdr);
|
|
}
|
|
|
|
|
|
for (f = 0; f < IPMIP6PM_FUNCTION_MAX; f++)
|
|
{
|
|
for (i = 0; i < ctx->extensions[f].num; i++)
|
|
{
|
|
if ((node->supported[f] & (1 << i)) && ctx->extensions[f].functions[i]->setup != IP_NULL)
|
|
(*ctx->extensions[f].functions[i]->setup) (ctx, proc, IPMIP_CALLBACK_CONFIG_DUMP, ctx->extdata[f][i], node->ifp_public->extdata[f][i], node->extdata[f][i], node, IP_NULL, request);
|
|
}
|
|
}
|
|
|
|
ipmip_attr_end(&request->message, rta);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If we have a reply header; terminate it */
|
|
ipmip_attr_hdr_finalize(&request->message, rhdr);
|
|
|
|
/* Commit the reply */
|
|
ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request);
|
|
}
|
|
else
|
|
{
|
|
/* Free the request */
|
|
ipmip_cli_message_free(&ctx->ipmip6.ipmip, proc, request);
|
|
}
|
|
|
|
/**/
|
|
return IPMIP_TIMER_RET_DONE;
|
|
}
|
|
/*
|
|
*===========================================================================
|
|
* ipmip6pm_attr_node_create
|
|
*===========================================================================
|
|
* Description: Create a node
|
|
* Parameters: event - Current event
|
|
* data - Data
|
|
* proc - Current process
|
|
* lock - Command locking structure
|
|
* node - Node.
|
|
* Returns: IP_FALSE
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmip6pm_attr_node_create(int event,
|
|
Ipmip6pm_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip_cli_message_t *request,
|
|
Ipmip6pm_node_t *node)
|
|
{
|
|
int ret = IPCOM_SUCCESS;
|
|
if (event == IPMIP_TIMER_EVENT_RUN)
|
|
{
|
|
struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request);
|
|
Ip_size_t rhdr = 0;
|
|
struct Ipmip_attr *idattr[IPMIP6PM_CLI_ATTR_BC_P_MAX + 1];
|
|
Ipmip6pm_node_lookup_t nargs;
|
|
Ipmip6pm_node_t *head = node;
|
|
Ipmip6pm_node_t *mnode = IP_NULL;
|
|
Ip_u8 hi = IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_UNKNOWN;
|
|
Ip_u32 identity = 0;
|
|
|
|
ipcom_memset(&nargs, 0, sizeof(nargs));
|
|
|
|
/* parse it */
|
|
ipmip_attr_hdr_parse(IPMIP6PM_CLI_ATTR_BC_P_MAX, hdr, idattr);
|
|
|
|
ipmip6pm_attr_build_lookup(&nargs, idattr);
|
|
|
|
/* Need to determine HI */
|
|
if (idattr[IPMIP6PM_CLI_ATTR_BC_P_HANDOFF_INDICATOR])
|
|
hi = (Ip_u8)ipmip_attr_get_u32(idattr[IPMIP6PM_CLI_ATTR_BC_P_HANDOFF_INDICATOR]);
|
|
|
|
if (node)
|
|
{
|
|
switch (hi)
|
|
{
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_DIFFERENT_INTERFACE:
|
|
{
|
|
if (head->next != IP_NULL)
|
|
{
|
|
IPMIP6_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Ambigous specifiers for 'different interface' handover indication for node %s",
|
|
ipmip6pm_node_describe(proc, node)));
|
|
|
|
/* Unable to determine what node we're dealing with */
|
|
ret = -IP_ERRNO_EEXIST;
|
|
goto error_out;
|
|
}
|
|
|
|
mnode = head;
|
|
}
|
|
break;
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_UNKNOWN:
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_SAME_INTERFACE_NEW_MAG:
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_NEW_INTERFACE:
|
|
{
|
|
/* New interface? We need to match this and verify that nothing we currently have
|
|
* matches it */
|
|
|
|
/* Attached IFINDEX may not be enough to identify */
|
|
nargs.search_params &= ~IPMIP6PM_NODE_LOOKUP_IFNAME;
|
|
while (node != IP_NULL)
|
|
{
|
|
if (ipmip6pm_node_compare(node, &nargs))
|
|
{
|
|
ret = -IP_ERRNO_EEXIST;
|
|
IPMIP6_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Ambigous specifiers for 'unknown/new/same interface' handover indication for node %s",
|
|
ipmip6pm_node_describe(proc, node)));
|
|
goto error_out;
|
|
}
|
|
node = node->next;
|
|
}
|
|
}
|
|
break;
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_NOT_CHANGED:
|
|
IPMIP6_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Invalid 'not changed' handover indication for node %s",
|
|
ipmip6pm_node_describe(proc, node)));
|
|
/* FALL THROUGH */
|
|
default:
|
|
ret = -IP_ERRNO_EINVAL;
|
|
goto error_out;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (hi)
|
|
{
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_DIFFERENT_INTERFACE:
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_UNKNOWN:
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_SAME_INTERFACE_NEW_MAG:
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_NEW_INTERFACE:
|
|
break;
|
|
case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_NOT_CHANGED:
|
|
IPMIP6_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Invalid 'not changed' handover indication for new node"));
|
|
/* FALL THROUGH */
|
|
default:
|
|
ret = -IP_ERRNO_EINVAL;
|
|
goto error_out;
|
|
}
|
|
}
|
|
|
|
if (mnode)
|
|
{
|
|
identity = mnode->identity;
|
|
ret = ipmip6pm_node_handoff(ctx, proc, mnode, hi, idattr);
|
|
}
|
|
else
|
|
{
|
|
ret = ipmip6pm_node_create(ctx, proc, head, hi, hdr, idattr, &identity);
|
|
}
|
|
|
|
error_out:
|
|
if (ret < 0)
|
|
rhdr = ipmip_attr_hdr_err(&request->message, hdr, -ret, IP_NULL);
|
|
else
|
|
{
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
|
|
/* Return the Identity */
|
|
ipmip_attr_put_u32(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HANDLE, identity);
|
|
}
|
|
|
|
/* If we have a reply header; terminate it */
|
|
ipmip_attr_hdr_finalize(&request->message, rhdr);
|
|
|
|
/* Commit the reply */
|
|
ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request);
|
|
}
|
|
else
|
|
{
|
|
/* Free the request */
|
|
ipmip_cli_message_free(&ctx->ipmip6.ipmip, proc, request);
|
|
}
|
|
|
|
/**/
|
|
return ret <= 0? IPMIP_TIMER_RET_DONE : ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip6pm_attr_node_delete
|
|
*===========================================================================
|
|
* Description: Create a node
|
|
* Parameters: event - Current event
|
|
* data - Data
|
|
* proc - Current process
|
|
* lock - Command locking structure
|
|
* node - Node.
|
|
* Returns: IP_FALSE
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmip6pm_attr_node_delete(int event,
|
|
Ipmip6pm_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip_cli_message_t *request,
|
|
Ipmip6pm_node_t *node)
|
|
{
|
|
int ret = IPMIP_TIMER_RET_DONE;
|
|
if (event == IPMIP_TIMER_EVENT_RUN)
|
|
{
|
|
struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request);
|
|
Ip_size_t rhdr = 0;
|
|
Ip_u16 reqtype = IPMIP_ATTR_HDR_TYPE(hdr);
|
|
|
|
if (node == IP_NULL)
|
|
rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_ENOENT, IP_NULL);
|
|
else
|
|
{
|
|
/* If we have a reply header; terminate it */
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
|
|
switch (reqtype)
|
|
{
|
|
case IPMIP6PM_CLI_BC_P_DEREGISTER_DELETE:
|
|
IP_BIT_SET(node->flags, IPMIP6PM_NODE_FLAG_DEREGISTER);
|
|
ipmip6pm_mh_ha_send_binding_update(ctx, proc, node, IP_FALSE, IP_FALSE);
|
|
/* FALL THROUGH */
|
|
|
|
case IPMIP6PM_CLI_BC_P_DELETE:
|
|
ret = ipmip6pm_node_terminate(ctx, proc, node, "unconditional administrative deletion");
|
|
break;
|
|
case IPMIP6PM_CLI_BC_P_DEREGISTER:
|
|
/* Mark it as de-register, and transmit a binding update */
|
|
IP_BIT_SET(node->flags, IPMIP6PM_NODE_FLAG_DEREGISTER);
|
|
ipmip6pm_mh_ha_send_binding_update(ctx, proc, node, IP_FALSE, IP_TRUE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ipmip_attr_hdr_finalize(&request->message, rhdr);
|
|
|
|
/* Commit the reply */
|
|
ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request);
|
|
}
|
|
else
|
|
{
|
|
/* Free the request */
|
|
ipmip_cli_message_free(&ctx->ipmip6.ipmip, proc, request);
|
|
}
|
|
|
|
/**/
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip6pm_attr_node_delete
|
|
*===========================================================================
|
|
* Description: Create a node
|
|
* Parameters: event - Current event
|
|
* data - Data
|
|
* proc - Current process
|
|
* lock - Command locking structure
|
|
* node - Node.
|
|
* Returns: IP_FALSE
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmip6pm_attr_node_revoke(int event,
|
|
Ipmip6pm_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip_cli_message_t *request,
|
|
Ipmip6pm_node_t *node)
|
|
{
|
|
int ret = IPMIP_TIMER_RET_DONE;
|
|
if (event == IPMIP_TIMER_EVENT_RUN)
|
|
{
|
|
struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request);
|
|
Ip_size_t rhdr = 0;
|
|
Ip_u16 reqtype = IPMIP_ATTR_HDR_TYPE(hdr);
|
|
|
|
if (node == IP_NULL)
|
|
rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_ENOENT, IP_NULL);
|
|
else
|
|
{
|
|
Ip_u8 reason = ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_REVOKE_REASON);
|
|
|
|
/* If we have a reply header; terminate it */
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
|
|
if (reason == 0)
|
|
reason = IPMIP6_MH_BRI_TRIGGER_ADMINISTRATIVE_REASON;
|
|
|
|
/* Do revoke this node */
|
|
switch (reqtype)
|
|
{
|
|
case IPMIP6PM_CLI_BC_P_REVOKE:
|
|
ret = ipmip6pm_node_revoke(ctx, proc, node, IP_FALSE, reason, IP_NULL);
|
|
break;
|
|
case IPMIP6PM_CLI_BC_P_REVOKE_INET:
|
|
ret = ipmip6pm_node_revoke(ctx, proc, node, IP_TRUE, reason, IP_NULL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ipmip_attr_hdr_finalize(&request->message, rhdr);
|
|
|
|
/* Commit the reply */
|
|
ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request);
|
|
}
|
|
else
|
|
{
|
|
/* Free the request */
|
|
ipmip_cli_message_free(&ctx->ipmip6.ipmip, proc, request);
|
|
}
|
|
|
|
/**/
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
IP_GLOBAL int
|
|
ipmip6pm_attr_command(struct Ipmip6pm_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmip_cli_message *request)
|
|
{
|
|
struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request);
|
|
Ip_size_t rhdr = 0;
|
|
struct Ipmip_attr *idattr[IPMIP6PM_CLI_ATTR_BC_P_MAX + 1];
|
|
|
|
|
|
switch (IPMIP_ATTR_HDR_TYPE(hdr))
|
|
{
|
|
case IPMIP6PM_CLI_BC_P_LIST:
|
|
{
|
|
struct Ipmip6pm_attr_op aop;
|
|
|
|
ipcom_memset(&aop, 0, sizeof(aop));
|
|
|
|
aop.request = request;
|
|
|
|
ipmip_attr_hdr_parse(IPMIP6PM_CLI_ATTR_BC_P_MAX, hdr, idattr);
|
|
|
|
ipmip6pm_attr_build_lookup(&aop.nargs, idattr);
|
|
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
/* Add all nodes */
|
|
ipmip_context_id_lock(ctx->idents);
|
|
ipmip_context_id_foreach(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
ctx->idents,
|
|
(Ipmip_util_hash_foreach_t)ipmip6pm_attr_list_nodes,
|
|
&aop,
|
|
IP_NULL);
|
|
ipmip_context_id_unlock(ctx->idents);
|
|
}
|
|
break;
|
|
|
|
case IPMIP6PM_CLI_BC_P_GET:
|
|
{
|
|
Ip_u32 handle = ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_HANDLE);
|
|
/**/
|
|
if (handle == 0)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
/* Get by identity */
|
|
ipmip6pm_node_lookup_handle(ctx,
|
|
proc,
|
|
handle,
|
|
&request->timer,
|
|
(Ipmip_timer_func_t)ipmip6pm_attr_node_dump,
|
|
request);
|
|
return 0;
|
|
}
|
|
case IPMIP6PM_CLI_BC_P_CREATE:
|
|
{
|
|
Ipmip6pm_node_lookup_t nargs;
|
|
Ipmip6pm_if_t *coa_ifp = IP_NULL;
|
|
|
|
ipcom_memset(&nargs, 0, sizeof(nargs));
|
|
|
|
/* parse it */
|
|
ipmip_attr_hdr_parse(IPMIP6PM_CLI_ATTR_BC_P_MAX,hdr, idattr);
|
|
|
|
ipmip6pm_attr_build_lookup(&nargs, idattr);
|
|
|
|
/* NAI */
|
|
if (nargs.nai_mn == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
if (IP_BIT_ISFALSE(nargs.search_params, IPMIP6PM_NODE_LOOKUP_ACCESS_TYPE))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
if (IP_BIT_ISFALSE(nargs.search_params, IPMIP6PM_NODE_LOOKUP_IFNAME))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
/* Dont match anything but NAI */
|
|
nargs.search_params = 0;
|
|
|
|
if (idattr[IPMIP6PM_CLI_ATTR_BC_P_COA_IFNAME] == IP_NULL)
|
|
{
|
|
Ipmip6pm_if_notify_t *notify = IPCOM_LIST_FIRST(&ctx->ifs);
|
|
if (notify)
|
|
coa_ifp = (Ipmip6pm_if_t *)notify->ipmip6.ifp;
|
|
}
|
|
else
|
|
{
|
|
/* Locate this CoA */
|
|
coa_ifp = ipmip6pm_if_findbyifname(ctx, proc, IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_COA_IFNAME]));
|
|
}
|
|
|
|
if (coa_ifp == IP_NULL)
|
|
return -IP_ERRNO_ENXIO;
|
|
|
|
/* Get by identity */
|
|
ipmip6pm_node_search(ctx,
|
|
proc,
|
|
coa_ifp,
|
|
&nargs,
|
|
&request->timer,
|
|
(Ipmip_timer_func_t)ipmip6pm_attr_node_create,
|
|
request);
|
|
return 0;
|
|
}
|
|
case IPMIP6PM_CLI_BC_P_DELETE:
|
|
case IPMIP6PM_CLI_BC_P_DEREGISTER_DELETE:
|
|
case IPMIP6PM_CLI_BC_P_DEREGISTER:
|
|
{
|
|
Ip_u32 handle = ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_HANDLE);
|
|
/**/
|
|
if (handle == 0)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
/* Get by identity */
|
|
ipmip6pm_node_lookup_handle(ctx,
|
|
proc,
|
|
handle,
|
|
&request->timer,
|
|
(Ipmip_timer_func_t)ipmip6pm_attr_node_delete,
|
|
request);
|
|
return 0;
|
|
}
|
|
case IPMIP6PM_CLI_BC_P_REVOKE:
|
|
#ifdef IPMIP_USE_INET
|
|
case IPMIP6PM_CLI_BC_P_REVOKE_INET:
|
|
#endif
|
|
{
|
|
Ip_u32 handle = ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_HANDLE);
|
|
/**/
|
|
if (handle == 0)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
/* Get by identity */
|
|
ipmip6pm_node_lookup_handle(ctx,
|
|
proc,
|
|
handle,
|
|
&request->timer,
|
|
(Ipmip_timer_func_t)ipmip6pm_attr_node_revoke,
|
|
request);
|
|
return 0;
|
|
}
|
|
case IPMIP_CLI_NAME_LIST:
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
{
|
|
/* Dump each configuration item we've currently got in human readable form */
|
|
Ipmip6pm_if_notify_t *notify;
|
|
|
|
ipmip_attr_put_str(&request->message,
|
|
IPMIP_CLI_ITEM_NAME,
|
|
"global");
|
|
|
|
/* Add interfaces */
|
|
for (notify = IPCOM_LIST_FIRST(&ctx->ifs); notify != IP_NULL; notify = IPCOM_LIST_NEXT(¬ify->next))
|
|
ipmip_attr_put_str(&request->message, IPMIP_CLI_ITEM_NAME, notify->ipmip6.ifp->iff.ifname);
|
|
}
|
|
break;
|
|
case IPMIP6PM_CLI_BC_P_LIST_LINK:
|
|
case IPMIP6PM_CLI_BC_P_LIST_SERVICE:
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
{
|
|
Ip_u32 i;
|
|
Ip_u32 elem = IPMIP_ATTR_HDR_TYPE(hdr) == IPMIP6PM_CLI_BC_P_LIST_SERVICE? IPMIP6PM_FUNCTION_SERVICE : IPMIP6PM_FUNCTION_LINK;
|
|
Ip_u32 rta_elem = IPMIP_ATTR_HDR_TYPE(hdr) == IPMIP6PM_CLI_BC_P_LIST_SERVICE? IPMIP6PM_CLI_ATTR_BC_P_SERVICE : IPMIP6PM_CLI_ATTR_BC_P_LINK;
|
|
|
|
for (i = 0; i < ctx->extensions[elem].num; i++)
|
|
{
|
|
if (ctx->extensions[elem].functions[i]->syntax)
|
|
{
|
|
Ip_size_t rta = ipmip_attr_begin(&request->message, rta_elem);
|
|
|
|
ipmip_attr_put_str(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_SRV_MODULE,
|
|
ctx->extensions[elem].functions[i]->name);
|
|
|
|
ipmip_attr_put_str(&request->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_SRV_VALUE,
|
|
ctx->extensions[elem].functions[i]->syntax);
|
|
|
|
ipmip_attr_end(&request->message, rta);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case IPMIP6PM_CLI_BC_P_GET_LMA:
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
{
|
|
Ipmip6pm_if_notify_t *notify;
|
|
/* Clear any old interfaces */
|
|
for (notify = IPCOM_LIST_FIRST(&ctx->ifs); notify != IP_NULL; notify = IPCOM_LIST_NEXT(¬ify->next))
|
|
ipmip6pm_lma_attr_get(ctx, proc, (Ipmip6pm_if_t *)notify->ipmip6.ifp, &request->message);
|
|
}
|
|
break;
|
|
|
|
case IPMIP6PM_CLI_BC_P_REVOKE_LMA:
|
|
/* Must locate MAG and */
|
|
{
|
|
const char *m_ifname = ipmip_attr_hdr_find_str(hdr, IPMIP6PM_CLI_ATTR_BC_P_IFNAME);
|
|
struct Ip_in6_addr *m_addr = ipmip_attr_hdr_find_inet6(hdr, IPMIP6PM_CLI_ATTR_BC_P_HOME_AGENT);
|
|
Ipmip6pm_if_notify_t *notify;
|
|
Ipmip6pm_if_t *ife;
|
|
Ipmip6pm_lma_t *lma;
|
|
|
|
/**/
|
|
if (m_ifname == IP_NULL || m_addr == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
for (notify = IPCOM_LIST_FIRST(&ctx->ifs); notify != IP_NULL; notify = IPCOM_LIST_NEXT(¬ify->next))
|
|
{
|
|
ife = (Ipmip6pm_if_t *)notify->ipmip6.ifp;
|
|
if (ipcom_strcasecmp(ife->ipmip6.iff.ifname, m_ifname) == 0)
|
|
break;
|
|
}
|
|
|
|
if (notify == IP_NULL)
|
|
return -IP_ERRNO_ENXIO;
|
|
|
|
/* Time to find the MAG */
|
|
lma = ipmip6pm_lma_get(ctx, proc, ife, m_addr, 0, 0);
|
|
if (lma == IP_NULL)
|
|
return -IP_ERRNO_ENOENT;
|
|
|
|
/* Time to revoke */
|
|
ipmip6pm_lma_revoke(ctx, proc, lma, ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_REVOKE_REASON));
|
|
|
|
/* Must release */
|
|
ipmip6pm_lma_release(ctx, proc, lma);
|
|
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
}
|
|
break;
|
|
|
|
case IPMIP_CLI_CONFIG_GET:
|
|
rhdr = ipmip_attr_hdr_ack(&request->message, hdr);
|
|
|
|
{
|
|
/* Dump each configuration item we've currently got in human readable form */
|
|
unsigned int si, f;
|
|
Ipmip6pm_if_notify_t *notify;
|
|
char *name = ipmip_attr_hdr_find_str(hdr, IPMIP_CLI_ITEM_NAME);
|
|
|
|
if (name == IP_NULL || ipcom_strcasecmp("global", name) == 0)
|
|
{
|
|
for (f = 0; f < IPMIP6PM_FUNCTION_MAX; f++)
|
|
{
|
|
for (si = 0; si < ctx->extensions[f].num; si++)
|
|
{
|
|
if (ctx->extensions[f].functions[si]->config_global != IP_NULL && ctx->extdata[f][si] != IP_NULL)
|
|
(*ctx->extensions[f].functions[si]->config_global) (ctx, proc, IPMIP_CALLBACK_CONFIG_DUMP, ctx->extdata[f][si], request);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Clear any old interfaces */
|
|
for (notify = IPCOM_LIST_FIRST(&ctx->ifs); notify != IP_NULL; notify = IPCOM_LIST_NEXT(¬ify->next))
|
|
{
|
|
Ipmip6pm_if_t *ife = (Ipmip6pm_if_t *)notify->ipmip6.ifp;
|
|
|
|
if (name != IP_NULL && ipcom_strcasecmp(ife->ipmip6.iff.ifname, name) != 0)
|
|
continue;
|
|
|
|
/**/
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.lifetime=%d",
|
|
ife->ipmip6.iff.ifname, ife->lifetime);
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.tunnel.ip6ip6=%s",
|
|
ife->ipmip6.iff.ifname, ife->ifenabled[IPMIP_TUNNELTYPE_IP6IP6]? "enabled" : "disabled");
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.tunnel.gre=%s",
|
|
ife->ipmip6.iff.ifname, ife->ifenabled[IPMIP_TUNNELTYPE_GRE6]? "enabled" : "disabled");
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.care_of_address=%s",
|
|
ife->ipmip6.iff.ifname, ipmip_ntop_inet6(proc, &ife->ifaddr.prefix, IP_NULL));
|
|
#ifdef IPMIP_USE_INET
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.inet.care_of_address=%s",
|
|
ife->ipmip6.iff.ifname, ipmip_ntop_inet(proc, ife->ifinet));
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.inet.tunnel.gre=%s",
|
|
ife->ipmip6.iff.ifname, ife->ifenabled[IPMIP_TUNNELTYPE_GRE]? "enabled" : "disabled");
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.inet.tunnel.ipip=%s",
|
|
ife->ipmip6.iff.ifname, ife->ifenabled[IPMIP_TUNNELTYPE_IPIP]? "enabled" : "disabled");
|
|
#endif
|
|
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.InitialBindackTimeoutFirstReg=%d",
|
|
ife->ipmip6.iff.ifname, ife->InitialBindackTimeoutFirstReg);
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.TimestampBasedApproachInUse=%s",
|
|
ife->ipmip6.iff.ifname, ife->TimestampBasedApproachInUse? "enabled" : "disabled");
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.BRIMaxRetriesNumber=%d",
|
|
ife->ipmip6.iff.ifname, ife->BRIMaxRetriesNumber);
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.MINDelayBRIs=%d",
|
|
ife->ipmip6.iff.ifname, ife->MINDelayBRIs);
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.tunnel.gre.Preferred=%s",
|
|
ife->ipmip6.iff.ifname, ife->GRE_Preferred? "enabled" : "disabled");
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.tunnel.gre.UseKeys=%s",
|
|
ife->ipmip6.iff.ifname, ife->GRE_UseKeys? "enabled" : "disabled");
|
|
|
|
#ifdef IPMIP_USE_INET
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.inet.UseIPv4UDPEncapForSignalingMessages=%s",
|
|
ife->ipmip6.iff.ifname, ife->UseIPv4UDPEncapForSignalingMessages? "true" : "false");
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.inet.ForceIPv4UDPEncapsulationSupport=%s",
|
|
ife->ipmip6.iff.ifname, ife->ForceIPv4UDPEncapsulationSupport? "true" : "false");
|
|
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmip6pm.interface.%s.inet.IPv4UDPEncapsulationNATTimeout=%d",
|
|
ife->ipmip6.iff.ifname, ife->IPv4UDPEncapsulationNATTimeout);
|
|
#endif
|
|
|
|
ipmip6pm_lma_configure_dump(ctx, proc, ife, &request->message);
|
|
|
|
for (f = 0; f < IPMIP6PM_FUNCTION_MAX; f++)
|
|
{
|
|
for (si = 0; si < ctx->extensions[f].num; si++)
|
|
{
|
|
if (ctx->extensions[f].functions[si]->config_ifp != IP_NULL && ife->extdata[f][si] != IP_NULL)
|
|
(*ctx->extensions[f].functions[si]->config_ifp) (ctx, proc, IPMIP_CALLBACK_CONFIG_DUMP, ife, ctx->extdata[f][si], ife->extdata[f][si], request);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
break;
|
|
default:
|
|
/**/
|
|
return ipmip6_attr_command(&ctx->ipmip6, proc, request);
|
|
}
|
|
|
|
/* If we have a reply header; terminate it */
|
|
ipmip_attr_hdr_finalize(&request->message, rhdr);
|
|
|
|
/* Commit the reply */
|
|
ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request);
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
IP_GLOBAL void
|
|
ipmip6pm_attr_status_change(Ipmip6pm_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6pm_node_t *node,
|
|
Ip_u32 status)
|
|
{
|
|
/* Status updates */
|
|
if (status != node->status)
|
|
{
|
|
#ifdef IPMIP6PM_MULTICAST_STATUS
|
|
/* If there's anyone listening */
|
|
if (ctx->ipmip6.ipmip.cli->clients.size > 0)
|
|
{
|
|
Ipmip_cli_message_t *msg = ipmip_cli_message_alloc(IP_NULL);
|
|
Ip_size_t rhdr = ipmip_attr_hdr_ack_create(&msg->message, 0, 0, IPMIP6PM_CLI_BC_P_STATUS);
|
|
Ip_size_t rta = ipmip_attr_begin(&msg->message, IPMIP6PM_CLI_ATTR_BC_P);
|
|
|
|
ipmip_attr_put_u32(&msg->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_HANDLE,
|
|
node->identity);
|
|
|
|
ipmip_attr_put_u32(&msg->message,
|
|
IPMIP6PM_CLI_ATTR_BC_P_STATUS,
|
|
status);
|
|
|
|
ipmip_attr_end(&msg->message, rta);
|
|
|
|
/* If we have a reply header; terminate it */
|
|
ipmip_attr_hdr_finalize(&msg->message, rhdr);
|
|
|
|
/* Broadcast */
|
|
ipmip_cli_message_multicast(&ctx->ipmip6.ipmip, proc, IP_NULL, IPMIP6PM_CLI_BC_P_STATUS, msg);
|
|
}
|
|
#endif
|
|
node->status = status;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|