Files
m241Neelima/components/ip_net2-6.9/ipmip6pm/src/ipmip6pm_attr.c
T
2026-07-30 11:19:44 +05:30

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(&notify->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(&notify->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(&notify->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(&notify->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
****************************************************************************
*/