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

2299 lines
85 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6ha_nemo_dsmipv6.c,v $ $Revision: 1.13.16.1 $
* $Source: /home/interpeak/CVSRoot/ipmip6ha/src/ipmip6ha_nemo_dsmipv6.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 "ipmip6ha_config.h"
#ifdef IPMIP_USE_INET
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_os.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_inet.h>
#include <ipcom_list.h>
#include <ipcom_hash.h>
#include <ipcom_err.h>
#include <ipcom_sysvar.h>
#include <ipcom_syslog.h>
#include <ipcom_shell.h>
#include <ipcom_route.h>
#include <ipnet.h>
#include <ipnet_policy_routing.h>
#include <ipmip.h>
#include <private/ipmip_util.h>
#include <private/ipmip_sysvar.h>
#include <private/ipmip_rtab.h>
#include <private/ipmip_dhcp.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_netlink.h>
#include <private/ipmip6_util.h>
#include "ipmip6ha_h.h"
#include "ipmip6ha_pktbuf.h"
#include "ipmip6ha_route.h"
#include "ipmip6ha_attr_h.h"
#include "ipmip6ha_nemo.h"
#include "ipmip6ha_nemo_dsmipv6.h"
#include "ipmip6ha_node.h"
#include "ipmip6ha_if.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipmip6ha_nemo_dsmipv6_entry
{
Ipmip_route_t ipmip;
/* Key & Mask */
Ip_u32 subnet;
Ip_u32 mask;
Ip_u8 mask_len;
Ipmip6ha_node_t *node;
} Ipmip6ha_nemo_dsmipv6_entry_t;
typedef struct Ipmip6ha_nemo_dsmipv6_config_entry
{
Ipmip_route_t ipmip;
Ip_u32 subnet;
Ip_u32 mask;
/* Key & Mask */
Ipmip6ha_nemo_dsmipv6_config_t cfg;
} Ipmip6ha_nemo_dsmipv6_config_entry_t;
typedef struct Ipmip6ha_nemo_dsmipv6_acl_entry
{
Ipmip_route_t ipmip;
/* Key & Mask */
struct Ip_in6_addr subnet;
struct Ip_in6_addr mask;
Ip_u8 mask_len;
Ipmip6ha_nemo_dsmipv6_acl_t acl;
} Ipmip6ha_nemo_dsmipv6_acl_entry_t;
typedef struct Ipmip6ha_nemo_dsmipv6_hash_key
{
char *key;
Ip_size_t key_size;
Ipmip6ha_nemo_dsmipv6_acl_t acl;
} Ipmip6ha_nemo_dsmipv6_hash_key_t;
struct Ipmip6ha_nemo_dsmipv6_cb
{
Ipmip6ha_context_t *ctx;
Ipmip6ha_nemo_dsmipv6_context_t *nemo;
const char *initfmt;
void *opaque;
};
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_key_to_domain(Ipmip6ha_nemo_dsmipv6_hash_key_t *key)
{
while (key->key_size > 0)
{
key->key_size--;
key->key++;
if (key->key[0] == '@')
return IP_TRUE;
}
return IP_FALSE;
}
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_route_resolve_parent(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_rtab_t *rtab,
Ipmip6ha_nemo_dsmipv6_config_entry_t *rt,
void *unused)
{
Ipmip6ha_nemo_dsmipv6_config_entry_t *prt;
IPMIP_UNUSED_PARAMETER(unused);
if ((prt = (Ipmip6ha_nemo_dsmipv6_config_entry_t *)ipmip_route_lookup_parent(rtab, &rt->ipmip)) != IP_NULL)
{
/* Found one parent */
IPMIP6_EVENT_IF(INFO, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Linking configuration data %s/%s -> %s/%s",
ipmip_ntop_inet(proc, rt->subnet),
ipmip_ntop_inet(proc, rt->mask),
ipmip_ntop_inet(proc, prt->subnet),
ipmip_ntop_inet(proc, prt->mask)));
/**/
rt->cfg.parent = &prt->cfg;
}
else
{
IPMIP6_EVENT_IF(INFO, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"No parent found for %s/%s",
ipmip_ntop_inet(proc, rt->subnet),
ipmip_ntop_inet(proc, rt->mask)));
}
if ((prt = (Ipmip6ha_nemo_dsmipv6_config_entry_t *)ipmip_route_lookup_child(rtab, &rt->ipmip)) != IP_NULL)
{
IPMIP6_EVENT_IF(INFO, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Child configuration data %s/%s -> %s/%s",
ipmip_ntop_inet(proc, rt->subnet),
ipmip_ntop_inet(proc, rt->mask),
ipmip_ntop_inet(proc, prt->subnet),
ipmip_ntop_inet(proc, prt->mask)));
}
else
{
IPMIP6_EVENT_IF(INFO, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"No child found for %s/%s",
ipmip_ntop_inet(proc, rt->subnet),
ipmip_ntop_inet(proc, rt->mask)));
}
/**/
return IP_FALSE;
}
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_route_resolve_acl(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_rtab_t *rtab,
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt,
void *unused)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(rtab);
IPMIP_UNUSED_PARAMETER(unused);
if (rt->acl.limit_hoa == 0xFFFFFFFF)
{
if (rt->mask_len == 128 && rt->acl.hoa != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_t *n;
rt->acl.limit_hoa = 0;
/**/
for (n = rt->acl.hoa; n != IP_NULL; n = n->acl_next)
rt->acl.limit_hoa++;
}
else if (rt->acl.pool != IP_NULL || rt->acl.hoa != IP_NULL)
rt->acl.limit_hoa = 1;
else
rt->acl.limit_hoa = 0;
}
if (rt->acl.limit_prefix == 0xFFFFFFFF)
{
if (rt->mask_len == 128 && rt->acl.pd != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_t *n;
rt->acl.limit_prefix = 0;
/**/
for (n = rt->acl.pd; n != IP_NULL; n = n->acl_next)
rt->acl.limit_prefix++;
}
else
rt->acl.limit_prefix = 0;
}
/**/
return IP_FALSE;
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_resolve_acl(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_nemo_dsmipv6_hash_key_t *key,
Ipmip6ha_nemo_dsmipv6_context_t *nemo,
void *unused)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(nemo);
IPMIP_UNUSED_PARAMETER(unused);
if (key->acl.limit_hoa == 0xFFFFFFFF)
{
if (key->key[0] != '@' && key->acl.hoa != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_t *n;
key->acl.limit_hoa = 0;
/**/
for (n = key->acl.hoa; n != IP_NULL; n = n->acl_next)
key->acl.limit_hoa++;
}
else if (key->acl.pool != IP_NULL || key->acl.hoa != IP_NULL)
key->acl.limit_hoa = 1;
else
key->acl.limit_hoa = 0;
}
if (key->acl.limit_prefix == 0xFFFFFFFF)
{
if (key->key[0] != '@' && key->acl.pd != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_t *n;
key->acl.limit_prefix = 0;
/**/
for (n = key->acl.pd; n != IP_NULL; n = n->acl_next)
key->acl.limit_prefix++;
}
else
key->acl.limit_prefix = 0;
}
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_nai_obj_hash
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC unsigned
ipmip6ha_nemo_dsmipv6_nai_obj_hash(Ipmip6ha_nemo_dsmipv6_hash_key_t *key)
{
return ipcom_hash_update(key->key, (int)key->key_size, 0);
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_nai_key_hash
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC unsigned
ipmip6ha_nemo_dsmipv6_nai_key_hash(Ipmip6ha_nemo_dsmipv6_hash_key_t *key)
{
return ipcom_hash_update(key->key, (int)key->key_size, 0);
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_nai_key_cmp
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_nai_key_cmp(Ipmip6ha_nemo_dsmipv6_hash_key_t *key1,
Ipmip6ha_nemo_dsmipv6_hash_key_t *key2)
{
/**/
return ipmip_util_strnncmp(key1->key, key1->key_size, key2->key, key2->key_size);
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_free_acl_data
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipmip6ha_nemo_dsmipv6_free_acl_data(Ipmip6ha_nemo_dsmipv6_acl_t *acl)
{
Ipmip6ha_nemo_dsmipv6_t *nemo;
/**/
while ((nemo = acl->hoa) != IP_NULL)
{
acl->hoa = nemo->acl_next;
ipcom_free(nemo);
}
while ((nemo = acl->pd) != IP_NULL)
{
acl->pd = nemo->acl_next;
ipcom_free(nemo);
}
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_acl_notify(Ipcom_route *rtab,
Ipmip6ha_nemo_dsmipv6_acl_entry_t *acl,
int code)
{
if (code == IPCOM_ROUTE_CODE_REMOVE || code == IPCOM_ROUTE_CODE_DUPLICATE)
ipmip6ha_nemo_dsmipv6_free_acl_data(&acl->acl);
ipmip_route_notify(rtab, &acl->ipmip, code);
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_config_notify(Ipcom_route *rtab,
Ipmip6ha_nemo_dsmipv6_config_entry_t *rt_sub,
int code)
{
if (code == IPCOM_ROUTE_CODE_REMOVE || code == IPCOM_ROUTE_CODE_DUPLICATE)
{
Ipmip_dhcp_option_t *opt;
while ((opt = IPCOM_LIST_FIRST(&rt_sub->cfg.opts)) != IP_NULL)
{
ipcom_list_remove(&opt->next);
ipcom_free(opt);
}
}
ipmip_route_notify(rtab, &rt_sub->ipmip, code);
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_verify_prefix
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_verify_prefix(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_node_t *node,
Ip_u32 *hoa,
Ip_u8 *len,
Ipmip6ha_nemo_dsmipv6_acl_t *acl,
Ipmip6ha_nemo_dsmipv6_t **nemoacl)
{
Ipmip_dhcp_pool_t *pool;
if (acl == IP_NULL)
return IP_FALSE;
if (*len == 32)
{
Ipmip6ha_nemo_dsmipv6_t *nemo;
for (nemo = acl->hoa; nemo != IP_NULL; nemo = nemo->acl_next)
{
if (nemo->next.head != IP_NULL)
continue;
if (*hoa != 0 && *hoa != nemo->prefix)
continue;
*hoa = nemo->prefix;
*nemoacl = nemo;
/* Try alloc */
return ipmip_dhcp_lease_alloc(&ctx->ipmip6.ipmip, proc, IP_NULL, node->ifp_home->nemo->nemo_dsmipv6->nemo_dhcp_rtab, *hoa, 32, (Ip_u8)nemo->netmask, node) != IP_NULL;
}
}
else
{
Ipmip6ha_nemo_dsmipv6_t *nemo;
Ipmip6ha_nemo_dsmipv6_t *bnemo = IP_NULL;
/* */
for (nemo = acl->pd; nemo != IP_NULL; nemo = nemo->acl_next)
{
if (nemo->next.head != IP_NULL)
continue;
if (*hoa == 0)
{
if (bnemo == IP_NULL)
bnemo = nemo;
else
{
/* Which one is the better? */
if (bnemo->len != *len)
{
if (nemo->len == *len || (nemo->len > *len && nemo->len < bnemo->len) || (nemo->len > bnemo->len && bnemo->len < *len))
bnemo = nemo;
}
}
}
else if (nemo->prefix == *hoa)
{
bnemo = nemo;
break;
}
}
if (bnemo != IP_NULL)
{
*nemoacl = bnemo;
*len = (Ip_u8)bnemo->len;
*hoa = bnemo->prefix;
return ipmip_dhcp_lease_alloc(&ctx->ipmip6.ipmip, proc, IP_NULL, node->ifp_home->nemo->nemo_dsmipv6->nemo_dhcp_rtab, bnemo->prefix, (Ip_u8)bnemo->len, (Ip_u8)bnemo->netmask, node) != IP_NULL;
}
}
*nemoacl = IP_NULL;
/* Check pools */
/* Find a pool */
pool = acl->pool;
if (!pool)
return IP_FALSE;
{
/* Time to allocate an address */
Ipmip_dhcp_lease_t *lease = ipmip_dhcp_pool_lease_alloc(&ctx->ipmip6.ipmip, proc, pool, *hoa, *len, IPMIP_DHCP_ALLOC_ANY, node);
if (lease != IP_NULL)
{
*hoa = lease->prefix;
*len = lease->prefix_len;
return IP_TRUE;
}
}
return IP_FALSE;
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_acl_init
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipmip6ha_nemo_dsmipv6_acl_t *
ipmip6ha_nemo_dsmipv6_acl_init(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_node_t *node)
{
Ipmip6_mh_mo_nai_t *nai = (Ipmip6_mh_mo_nai_t *)node->nai_mn;
Ipmip6ha_nemo_dsmipv6_hash_key_t key;
Ipmip6ha_nemo_dsmipv6_hash_key_t *lkey = IP_NULL;
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(ctx);
if (nai != IP_NULL)
{
key.key = (char *)&nai->nai[0];
key.key_size = (Ip_size_t)(nai->hdr.len - 1);
}
/**/
if (IPMIP6_MH_BU_IS_H(node->regflags))
{
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt;
if (ipmip_route_lookup(node->ifp_home->nemo->nemo_dsmipv6->nemo_dsmipv6_acl_mr_hoa, &node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6, (Ipmip_route_t **)&rt) != IPMIP_ROUTE_LOOKUP_MISS)
return &rt->acl;
if (nai != IP_NULL)
{
lkey = ipcom_hash_get(node->ifp_home->nemo->nemo_dsmipv6->nemo_dsmipv6_acl_mr_nai, &key);
if (!lkey && ipmip6ha_nemo_dsmipv6_key_to_domain(&key))
lkey = ipcom_hash_get(node->ifp_home->nemo->nemo_dsmipv6->nemo_dsmipv6_acl_mr_nai, &key);
}
}
else
{
if (nai != IP_NULL)
{
lkey = ipcom_hash_get(node->ifp_home->nemo->nemo_dsmipv6->nemo_dsmipv6_acl_lma_nai, &key);
if (!lkey && ipmip6ha_nemo_dsmipv6_key_to_domain(&key))
lkey = ipcom_hash_get(node->ifp_home->nemo->nemo_dsmipv6->nemo_dsmipv6_acl_lma_nai, &key);
}
}
/**/
if (lkey)
return &lkey->acl;
/**/
return IP_NULL;
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_acl_parse_pool
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_acl_parse_pool(Ipmip6ha_context_t *ctx,
struct Ipmip_proc *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nctx,
Ipmip6ha_nemo_dsmipv6_acl_t *acl,
const char *value)
{
/* Read the ACL list for this Mobile Router */
Ip_u8 *dptr = ipmip_util_explode(value);
Ip_u8 *ptr;
IPMIP_UNUSED_PARAMETER(proc);
ptr = dptr + 1;
while (*ptr != 0)
{
Ipmip_dhcp_pool_t *pool = IP_NULL;
for (pool = IPCOM_LIST_FIRST(&nctx->nemo_dsmipv6_pools); pool != IP_NULL; pool = IPCOM_LIST_NEXT(&pool->next))
{
if (ipcom_strcasecmp((char *)(ptr + 1), pool->name) == 0)
{
/* A matched pool */
acl->pool = pool;
break;
}
}
if (pool == IP_NULL)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Failed to parse: %s", (char *)(ptr + 1)));
}
ptr += *ptr;
}
/* Each entry is a prefix/length */
ipcom_free(dptr);
return IP_TRUE;
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_acl_parse_homeaddress
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_acl_parse_homeaddress(Ipmip6ha_context_t *ctx,
struct Ipmip_proc *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nctx,
Ipmip6ha_nemo_dsmipv6_acl_t *acl,
const char *value)
{
/* Read the ACL list for this Mobile Router */
Ip_u8 *dptr = ipmip_util_explode(value);
Ip_u8 *ptr;
Ipmip6ha_nemo_dsmipv6_t *nemo;
IPMIP_UNUSED_PARAMETER(proc);
/**/
while ((nemo = acl->hoa) != IP_NULL)
{
acl->hoa = nemo->acl_next;
ipcom_free(nemo);
}
ptr = dptr + 1;
while (*ptr != 0)
{
/* Add ACL */
nemo = ipcom_calloc(1, sizeof(*nemo));
IP_BIT_SET(nemo->flags, IPMIP6HA_NEMO_ACL_STATIC);
if (ipmip_util_inet((char *)(ptr + 1), &nemo->prefix, &nemo->netmask))
{
/* Prefix or not? */
nemo->len = 32;
/**/
if (nemo->netmask == 32)
{
Ip_u32 netmask = ipmip6ha_nemo_dsmipv6_subnet_config_netmask(ctx, proc, nctx, nemo->prefix);
if (netmask != 0)
nemo->netmask = netmask;
}
nemo->acl_next = acl->hoa;
acl->hoa = nemo;
}
else
{
ipcom_free(nemo);
}
ptr += *ptr;
}
/* Each entry is a prefix/length */
ipcom_free(dptr);
return IP_TRUE;
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_acl_parse_prefix_delegation
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_acl_parse_prefix_delegation(Ipmip6ha_context_t *ctx,
struct Ipmip_proc *proc,
Ipmip6ha_nemo_dsmipv6_acl_t *acl,
const char *value)
{
/* Read the ACL list for this Mobile Router */
Ip_u8 *dptr = ipmip_util_explode(value);
Ip_u8 *ptr;
Ipmip6ha_nemo_dsmipv6_t *nemo;
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(ctx);
while ((nemo = acl->pd) != IP_NULL)
{
acl->pd = nemo->acl_next;
ipcom_free(nemo);
}
ptr = dptr + 1;
while (*ptr != 0)
{
/* Add ACL */
nemo = ipcom_calloc(1, sizeof(*nemo));
IP_BIT_SET(nemo->flags, IPMIP6HA_NEMO_ACL_STATIC);
if (ipmip_util_inet((char *)(ptr + 1), &nemo->prefix, &nemo->len))
{
/* Prefix or not? */
nemo->netmask = nemo->len;
nemo->acl_next = acl->pd;
acl->pd = nemo;
}
else
{
ipcom_free(nemo);
}
ptr += *ptr;
}
/* Each entry is a prefix/length */
ipcom_free(dptr);
return IP_TRUE;
}
IP_STATIC Ipmip6ha_nemo_dsmipv6_hash_key_t *
ipmip6ha_nemo_dsmipv6_get_or_create_acl(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nemo,
Ip_bool mobile_router,
const char *subkey)
{
Ipmip6ha_nemo_dsmipv6_hash_key_t okey;
Ipmip6ha_nemo_dsmipv6_hash_key_t *nkey;
Ipcom_hash *acl = mobile_router? nemo->nemo_dsmipv6_acl_mr_nai : nemo->nemo_dsmipv6_acl_lma_nai;
okey.key = (char *)subkey;
okey.key_size = ipcom_strlen(subkey);
nkey = ipcom_hash_get(acl, &okey);
if (!nkey)
{
nkey = ipcom_calloc(1, sizeof(*nkey));
if (!nkey)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"DSMIPv6 ACL '%s' unable to allocate memory", subkey));
return IP_NULL;
}
nkey->acl.mobile_router = mobile_router;
nkey->acl.limit_hoa = 0xFFFFFFFF;
nkey->acl.limit_prefix = 0xFFFFFFFF;
nkey->key = ipcom_strdup(subkey);
nkey->key_size = ipcom_strlen(subkey);
ipcom_hash_add(acl, nkey);
}
return nkey;
}
IP_STATIC Ipmip6ha_nemo_dsmipv6_acl_entry_t *
ipmip6ha_nemo_dsmipv6_get_or_create_rt_acl(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nemo,
Ip_bool mobile_router,
const char *subkey)
{
struct Ip_in6_addr addr;
struct Ip_in6_addr subnet;
Ip_u8 plen;
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt;
/* Dont care about subkeys */
if (ipcom_strcasecmp(subkey, "any") == 0)
{
/* Wildcard match */
ipcom_memset(&addr, 0, sizeof(addr));
plen = 0;
}
else
{
if (ipmip_util_inet6(subkey, &addr, &plen) == IP_FALSE)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"DSMIPv6 key '%s' is not a valid address",
subkey));
return IP_NULL;
}
}
ipmip6_address_create_prefix(&subnet, &addr, plen);
/* Found, already in the table */
if ((rt = (Ipmip6ha_nemo_dsmipv6_acl_entry_t *)ipmip_route_lookup_exact(nemo->nemo_dsmipv6_acl_mr_hoa, &subnet, plen)) != IP_NULL)
return rt;
rt = ipcom_calloc(1, sizeof(*rt));
if (!rt)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"DSMIPv6 ACL '%s' unable to allocate memory",
subkey));
return IP_NULL;
}
ipmip_util_create_mask((Ip_u8 *)&rt->mask, plen);
ipmip6_address_create_prefix(&rt->subnet, &addr, plen);
rt->ipmip.hdr.key = &rt->subnet;
rt->ipmip.hdr.mask = &rt->mask;
rt->mask_len = plen;
if (ipmip_route_add(nemo->nemo_dsmipv6_acl_mr_hoa, &rt->ipmip) != IPCOM_SUCCESS)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"DSMIPv6 ACL '%s' unable to add",
subkey));
ipcom_free(rt);
return IP_NULL;
}
rt->acl.mobile_router = mobile_router;
rt->acl.limit_hoa = 0xFFFFFFFF;
rt->acl.limit_prefix = 0xFFFFFFFF;
return rt;
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_homeaddress_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
IPMIP_UNUSED_PARAMETER(name);
if (ipcom_strchr(subkey, '@') != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_hash_key_t *nkey;
if ((nkey = ipmip6ha_nemo_dsmipv6_get_or_create_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
ipmip6ha_nemo_dsmipv6_acl_parse_homeaddress(cb->ctx, proc, cb->nemo, &nkey->acl, value);
}
else
{
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt;
if ((rt = ipmip6ha_nemo_dsmipv6_get_or_create_rt_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
ipmip6ha_nemo_dsmipv6_acl_parse_homeaddress(cb->ctx, proc, cb->nemo, &rt->acl, value);
}
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_limit_homeaddress_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
IPMIP_UNUSED_PARAMETER(name);
if (ipcom_strchr(subkey, '@') != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_hash_key_t *nkey;
if ((nkey = ipmip6ha_nemo_dsmipv6_get_or_create_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
nkey->acl.limit_hoa = (Ip_u32)ipcom_strtoul(value, IP_NULL, 0);
}
else
{
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt;
if ((rt = ipmip6ha_nemo_dsmipv6_get_or_create_rt_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
rt->acl.limit_hoa = (Ip_u32)ipcom_strtoul(value, IP_NULL, 0);
}
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_limit_prefix_delegation_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
IPMIP_UNUSED_PARAMETER(name);
if (ipcom_strchr(subkey, '@') != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_hash_key_t *nkey;
if ((nkey = ipmip6ha_nemo_dsmipv6_get_or_create_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
nkey->acl.limit_prefix = (Ip_u32)ipcom_strtoul(value, IP_NULL, 0);
}
else
{
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt;
if ((rt = ipmip6ha_nemo_dsmipv6_get_or_create_rt_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
rt->acl.limit_prefix = (Ip_u32)ipcom_strtoul(value, IP_NULL, 0);
}
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_prefix_delegation_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
IPMIP_UNUSED_PARAMETER(name);
if (ipcom_strchr(subkey, '@') != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_hash_key_t *nkey;
if ((nkey = ipmip6ha_nemo_dsmipv6_get_or_create_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
ipmip6ha_nemo_dsmipv6_acl_parse_prefix_delegation(cb->ctx, proc, &nkey->acl, value);
}
else
{
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt;
if ((rt = ipmip6ha_nemo_dsmipv6_get_or_create_rt_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
ipmip6ha_nemo_dsmipv6_acl_parse_prefix_delegation(cb->ctx, proc, &rt->acl, value);
}
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_pool_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
IPMIP_UNUSED_PARAMETER(name);
if (ipcom_strchr(subkey, '@') != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_hash_key_t *nkey;
if ((nkey = ipmip6ha_nemo_dsmipv6_get_or_create_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
ipmip6ha_nemo_dsmipv6_acl_parse_pool(cb->ctx, proc, cb->nemo, &nkey->acl, value);
}
else
{
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt;
if ((rt = ipmip6ha_nemo_dsmipv6_get_or_create_rt_acl(cb->ctx, proc, cb->nemo, IP_TRUE, subkey)) == IP_NULL)
return;
ipmip6ha_nemo_dsmipv6_acl_parse_pool(cb->ctx, proc, cb->nemo, &rt->acl, value);
}
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_lma_acl_homeaddress_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
Ipmip6ha_nemo_dsmipv6_hash_key_t *nkey;
IPMIP_UNUSED_PARAMETER(name);
IPMIP_UNUSED_PARAMETER(proc);
if ((nkey = ipmip6ha_nemo_dsmipv6_get_or_create_acl(cb->ctx, proc, cb->nemo, IP_FALSE, subkey)) == IP_NULL)
return;
ipmip6ha_nemo_dsmipv6_acl_parse_homeaddress(cb->ctx, proc, cb->nemo, &nkey->acl, value);
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_lma_acl_pool_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
Ipmip6ha_nemo_dsmipv6_hash_key_t *nkey;
IPMIP_UNUSED_PARAMETER(name);
IPMIP_UNUSED_PARAMETER(proc);
if ((nkey = ipmip6ha_nemo_dsmipv6_get_or_create_acl(cb->ctx, proc, cb->nemo, IP_FALSE, subkey)) == IP_NULL)
return;
if (!ipmip6ha_nemo_dsmipv6_acl_parse_pool(cb->ctx, proc, cb->nemo, &nkey->acl, value))
return;
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_sysvar_pool_foreach
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_pool_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
Ip_u32 addr;
Ip_u32 plen;
Ipmip_dhcp_pool_t *pool = IP_NULL;
Ip_u8 *nptr;
IPMIP_UNUSED_PARAMETER(name);
IPMIP_UNUSED_PARAMETER(proc);
/* Create a pool named subkey */
/* Explode value */
if ((nptr = ipmip_util_explode(value)) != IP_NULL)
{
Ip_u8 *ptr;
/* */
pool = ipmip_dhcp_pool_create(&cb->ctx->ipmip6.ipmip,proc, subkey, cb->nemo->nemo_dhcp_rtab);
if (pool)
{
/**/
ipcom_list_insert_last(&cb->nemo->nemo_dsmipv6_pools, &pool->next);
ptr = nptr + 1;
while (*ptr != 0)
{
char *slice;
char *range;
Ip_u8 slice_size = 32;
Ip_u32 end_addr = 0;
if ((range = ipcom_strchr((char *)ptr + 1, '-')) != IP_NULL)
{
if (!ipmip_util_inet((char *)ptr + 1, &addr, IP_NULL))
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&cb->ctx->ipmip6.ipmip,
proc,
"DSMIPv6 pool slice start '%s' is not a valid address",
(char *)ptr + 1));
goto next;
}
if (!ipmip_util_inet((char *)range + 1, &end_addr, &plen))
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&cb->ctx->ipmip6.ipmip,
proc,
"DSMIPv6 pool slice end '%s' is not a valid address",
(char *)range + 1));
goto next;
}
if ((slice = ipcom_strchr((char *)range, '/')) != IP_NULL &&
(slice = ipcom_strchr((char *)slice + 1, '/')) != IP_NULL)
slice_size = (Ip_u8)ipcom_strtoul(slice + 1, IP_NULL, 10);
if (slice_size > 32)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&cb->ctx->ipmip6.ipmip,
proc,
"DSMIPv6 pool slice size %d is invalid",
slice_size));
goto next;
}
/* */
ipmip_dhcp_pool_add_slice(pool,
addr,
end_addr,
(Ip_u8)plen,
slice_size);
}
else if (ipmip_util_inet((char *)ptr + 1, &addr, &plen) && plen < 32)
{
if ((slice = ipcom_strchr((char *)ptr + 1, '/')) != IP_NULL &&
(slice = ipcom_strchr((char *)slice + 1, '/')) != IP_NULL)
{
slice_size = (Ip_u8)ipcom_strtoul(slice + 1, IP_NULL, 10);
if (slice_size > 32)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&cb->ctx->ipmip6.ipmip,
proc,
"DSMIPv6 pool slice size %d is invalid",
slice_size));
goto next;
}
}
/* */
ipmip_dhcp_pool_add_slice(pool,
addr,
0,
(Ip_u8)plen,
slice_size);
}
else
{
next:
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&cb->ctx->ipmip6.ipmip,
proc,
"DSMIPv6 key '%s' is not a valid address/prefix",
ptr + 1));
}
ptr += *ptr;
}
}
ipcom_free(nptr);
}
}
IP_STATIC Ipmip6ha_nemo_dsmipv6_config_entry_t *
ipmip6ha_nemo_dsmipv6_get_or_create_rt_config(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nemo,
const char *subkey)
{
Ip_u32 subnet;
Ip_u32 mask;
Ip_u32 plen;
Ipmip6ha_nemo_dsmipv6_config_entry_t *rt;
/* Dont care about subkeys */
if (ipcom_strcasecmp(subkey, "any") == 0)
{
/* Wildcard match */
subnet = 0;
plen = 0;
}
else
{
if (ipmip_util_inet(subkey, &subnet, &plen) == IP_FALSE)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"DSMIPv6 key '%s' is not a valid address",
subkey));
return IP_NULL;
}
}
mask = 0;
ipmip_util_create_mask((Ip_u8 *)&mask, (int)plen);
subnet &= mask;
if ((rt = (Ipmip6ha_nemo_dsmipv6_config_entry_t *)ipmip_route_lookup_exact(nemo->nemo_inet_config, &subnet, (Ip_u8)plen)) != IP_NULL)
return rt;
rt = ipcom_calloc(1, sizeof(*rt));
if (!rt)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"DSMIPv6 ACL '%s' unable to allocate memory",
subkey));
return IP_NULL;
}
else
{
rt->mask = mask;
rt->subnet = subnet;
ipcom_list_init(&rt->cfg.opts);
rt->cfg.netmask = mask;
rt->ipmip.hdr.key = &rt->subnet;
rt->ipmip.hdr.mask = &rt->mask;
if (ipmip_route_add(nemo->nemo_inet_config, &rt->ipmip) != IPCOM_SUCCESS)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"DSMIPv6 ACL '%s' unable to add",
subkey));
ipcom_free(rt);
return IP_NULL;
}
return rt;
}
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_sysvar_config_dhcp_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
Ipmip6ha_nemo_dsmipv6_config_entry_t *rt;
Ipmip_dhcp_option_t *opt;
char *subnet;
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(name);
if ((opt = ipmip_dhcp_option_parse_name(proc, subkey, value, &subnet)) != IP_NULL)
{
Ipmip_dhcp_option_t *opts;
if (subnet == IP_NULL)
subnet = "any";
if ((rt = ipmip6ha_nemo_dsmipv6_get_or_create_rt_config(cb->ctx, proc, cb->nemo, subnet)) == IP_NULL)
{
ipcom_free(opt);
return;
}
for (opts = IPCOM_LIST_FIRST(&rt->cfg.opts); opts != IP_NULL; opts = IPCOM_LIST_NEXT(&opts->next))
{
if (opts->option[IPMIP_DHCP_OPT_CODE] == opt->option[IPMIP_DHCP_OPT_CODE])
{
ipcom_list_remove(&opts->next);
ipcom_free(opts);
break;
}
}
/* If its IP's, reserve these addresses in the rtab */
if (opt->type == IPMIP_DHCP_TYPE_IP)
{
Ip_u32 *ips = (Ip_u32 *)&opt->option[IPMIP_DHCP_OPT_DATA];
Ip_u32 ival;
/**/
for (ival = 0; ival < opt->option[IPMIP_DHCP_OPT_LEN] / 4; ival++)
ipmip_dhcp_lease_alloc(&cb->ctx->ipmip6.ipmip, proc, IP_NULL, cb->nemo->nemo_dhcp_rtab, IP_GET_32ON8(&ips[ival]), 32, 32, IP_NULL);
}
/* Store option */
ipcom_list_insert_first(&rt->cfg.opts, &opt->next);
}
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_acl_nai_del_cb
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipmip6ha_nemo_dsmipv6_acl_nai_del_cb(Ipmip6ha_nemo_dsmipv6_hash_key_t *obj,
Ipcom_hash *htable)
{
ipmip6ha_nemo_dsmipv6_free_acl_data(&obj->acl);
ipcom_hash_remove(htable, obj);
ipcom_free(obj->key);
ipcom_free(obj);
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
IP_GLOBAL Ipmip6ha_nemo_dsmipv6_config_t *
ipmip6ha_nemo_dsmipv6_subnet_config_get(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nctx,
Ip_u32 addr)
{
Ipmip6ha_nemo_dsmipv6_config_entry_t *rt;
int ret;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
ret = ipmip_route_lookup(nctx->nemo_inet_config, &addr, (Ipmip_route_t **)&rt);
if (ret != IPMIP_ROUTE_LOOKUP_MISS)
return &rt->cfg;
return IP_NULL;
}
IP_GLOBAL Ip_u32
ipmip6ha_nemo_dsmipv6_subnet_config_gateway(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nemo,
Ip_u32 addr)
{
Ipmip6ha_nemo_dsmipv6_config_t *cfg = ipmip6ha_nemo_dsmipv6_subnet_config_get(ctx, proc, nemo, addr);
while (cfg != IP_NULL)
{
Ipmip_dhcp_option_t *dopt;
dopt = ipmip_dhcp_option_entry_find(&cfg->opts, IPMIP_DHCP_OPTCODE_ROUTERS);
if (dopt != IP_NULL)
return IP_GET_32ON8(&dopt->option[IPMIP_DHCP_OPT_DATA]);
cfg = cfg->parent;
}
return 0;
}
IP_GLOBAL Ip_u32
ipmip6ha_nemo_dsmipv6_subnet_config_netmask(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nemo,
Ip_u32 addr)
{
Ipmip6ha_nemo_dsmipv6_config_t *top_cfg = ipmip6ha_nemo_dsmipv6_subnet_config_get(ctx, proc, nemo, addr);
Ipmip6ha_nemo_dsmipv6_config_t *cfg;
for (cfg = top_cfg; cfg != IP_NULL; cfg = cfg->parent)
{
Ipmip_dhcp_option_t *dopt;
dopt = ipmip_dhcp_option_entry_find(&cfg->opts, IPMIP_DHCP_OPTCODE_SUBNET_MASK);
if (dopt != IP_NULL)
return (Ip_u32)ipcom_mask_to_prefixlen(&dopt->option[IPMIP_DHCP_OPT_DATA], 32);
}
return (Ip_u32) (top_cfg? ipcom_mask_to_prefixlen(&top_cfg->netmask, 32) : 0);
}
/*
*===========================================================================
* ipmip6ha_nemo_dsmipv6_free
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip6ha_nemo_dsmipv6_free(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
Ipmip6ha_nemo_dsmipv6_t *nemo)
{
if ((nemo->flags & IPMIP6HA_NEMO_ACL_ROUTE))
{
Ipmip_dhcp_lease_t *lease;
ipcom_mutex_lock(node->ifp_home->nemo->nemo_dsmipv6->nemo_dhcp_rtab->rtab_lock);
if ((lease = ipmip_dhcp_lease_lookup(&ctx->ipmip6.ipmip, proc, node->ifp_home->nemo->nemo_dsmipv6->nemo_dhcp_rtab, nemo->prefix, (Ip_u8)nemo->len)) != IP_NULL)
{
if (lease->opaque == node)
ipmip_dhcp_lease_delete(&ctx->ipmip6.ipmip, proc, lease);
}
ipcom_mutex_unlock(node->ifp_home->nemo->nemo_dsmipv6->nemo_dhcp_rtab->rtab_lock);
}
if (nemo->next.head != IP_NULL)
ipcom_list_remove(&nemo->next);
if (IP_BIT_ISSET(nemo->flags, IPMIP6HA_NEMO_ACL_STATIC))
{
nemo->flags = IPMIP6HA_NEMO_ACL_STATIC;
return;
}
ipcom_free(nemo);
}
/*
*===========================================================================
* ipmip6ha_nemo_free_list
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip6ha_nemo_dsmipv6_free_list(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
Ipcom_list *nemos)
{
Ipmip6ha_nemo_dsmipv6_t *nemo;
while ((nemo = IPCOM_LIST_FIRST(nemos)) != IP_NULL)
ipmip6ha_nemo_dsmipv6_free(ctx, proc, node, nemo);
}
IP_GLOBAL int
ipmip6ha_nemo_dsmipv6_verify(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_node_t *node,
Ipmip6ha_pktbuf_t *pbuf,
Ip_bool *changed)
{
unsigned i;
Ipmip6ha_nemo_dsmipv6_t *nemo;
Ipmip6_mh_mo_dsmipv6_ipv4_home_address_ack_t mp_ack;
Ipmip6_mh_option_array_t *mo = &pbuf->ipmip6.mo.dsmipv6_prefix_request;
int ret = IPMIP6_MH_BA_STATUS_SUCCESS_ACCEPTED;
unsigned num_hoa = node->nemo_hoa_v4.size;
unsigned num_prefix = node->nemo_prefix_v4.size;
ipcom_mutex_lock(node->ifp_home->nemo->nemo_dsmipv6->nemo_dhcp_rtab->rtab_lock);
mp_ack.hdr.len = 6;
mp_ack.hdr.val = IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_ACK;
/**/
for (nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4); nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->next))
nemo->flags = (Ip_u8) (nemo->flags & ~IPMIP6HA_NEMO_ACL_DELETED);
for (nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4); nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->next))
nemo->flags = (Ip_u8) (nemo->flags & ~IPMIP6HA_NEMO_ACL_DELETED);
/* If we have v4 DSMIPV6; we may be forced to deregister them if no MO's are specified -- otherwise process provided MO's */
if (node->nemo_hoa_v4.size > 0 || node->nemo_prefix_v4.size > 0 || mo->numelem != 0)
{
Ipmip6_mh_mo_dsmipv6_ipv4_home_address_t *mp;
Ip_u16 pflags;
int j, n;
/* Init the ACL list? */
if (node->nemo_acl_v4 == IP_NULL)
node->nemo_acl_v4 = ipmip6ha_nemo_dsmipv6_acl_init(ctx, proc, node);
/**/
nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4);
for (n = 0; n < 2; n++)
{
while (nemo != IP_NULL)
{
Ipmip6ha_nemo_dsmipv6_t *nnemo = IPCOM_LIST_NEXT(&nemo->next);
mp = IP_NULL;
/* Explicit mode */
for (i = 0; i < mo->numelem; i++)
{
mp = (Ipmip6_mh_mo_dsmipv6_ipv4_home_address_t *)mo->hdrs[i];
pflags = IP_GET_NTOHS(&mp->pref_flags);
pflags >>= IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_PREF;
if (nemo->prefix == IP_GET_32ON8(&mp->home_address) && pflags == nemo->len)
break;
}
if (i >= mo->numelem)
{
node->route_change |= IPMIP6HA_ROUTE_STATE_IPV4_NEMO|IPMIP6HA_ROUTE_STATE_IPV4;
nemo->flags |= IPMIP6HA_NEMO_ACL_DELETED;
if (n == 0)
num_hoa--;
else
num_prefix--;
}
nemo = nnemo;
}
nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4);
}
for (j = 1; j >= 0; j--)
{
/* Explicit mode */
for (i = 0; i < mo->numelem; i++)
{
Ip_u8 plen;
Ip_u32 hoa;
mp = (Ipmip6_mh_mo_dsmipv6_ipv4_home_address_t *)mo->hdrs[i];
hoa = IP_GET_32ON8(&mp->home_address);
/* PASS ONE; Explicit Requests
* PASS TWO: Wildcard allocation requests
*/
if (j != !!hoa)
continue;
pflags = IP_GET_NTOHS(&mp->pref_flags);
plen = (Ip_u8) (pflags >> IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_PREF);
/* No prefix; do 32, If prefix MUST not be 32 */
if ((pflags & IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_P) == 0)
plen = 32;
else if (plen == 32)
plen = 0;
/**/
nemo = IP_NULL;
if (hoa != 0)
{
if (plen == 32)
nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4);
else
nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4);
for (; nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->next))
{
if (nemo->prefix == hoa && plen == nemo->len)
break;
}
}
if (!nemo)
{
Ipmip6ha_nemo_dsmipv6_t *nemoacl = IP_NULL;
if (node->nemo_acl_v4 == IP_NULL)
goto unauthorized;
if (plen == 32 && num_hoa == node->nemo_acl_v4->limit_hoa)
{
IPMIP6_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Unable to allocate HoA to %s - LIMIT has been reached",
ipmip6ha_node_describe(proc, node)));
goto prohibit;
}
else if (plen != 32 && num_prefix == node->nemo_acl_v4->limit_prefix)
{
IPMIP6_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Unable to allocate Prefix to %s - LIMIT has been reached",
ipmip6ha_node_describe(proc, node)));
goto prohibit;
}
/**/
if (hoa == 0)
{
/* This is a request */
if (plen == 32)
nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4);
else
nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4);
for (; nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->next))
{
if ((nemo->flags & IPMIP6HA_NEMO_ACL_DELETED) != 0)
break;
}
if (nemo)
{
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_DELETED);
if (plen == 32)
num_hoa++;
else
num_prefix++;
goto acknowledge;
}
}
/* Attempt to allocate new prefix/hoa */
/* Check it is allowed based on configuration and availability */
if (ipmip6ha_nemo_dsmipv6_verify_prefix(ctx, proc, node, &hoa, &plen, node->nemo_acl_v4, &nemoacl))
{
/* Add to NEMOv4 list */
if (!nemoacl)
{
nemo = ipcom_calloc(1, sizeof(*nemo));
nemo->prefix = hoa;
nemo->len = plen;
nemo->netmask = ipmip6ha_nemo_dsmipv6_subnet_config_netmask(ctx, proc, node->ifp_home->nemo->nemo_dsmipv6, hoa);
if (nemo->netmask == 0)
nemo->netmask = plen;
}
else
{
nemo = nemoacl;
}
nemo->flags |= IPMIP6HA_NEMO_ACL_ROUTE|IPMIP6HA_NEMO_ACL_ADDED;
*changed = IP_TRUE;
IPMIP6_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Allocated %s HoA - Request is %s/%d result is %s/%d",
(pflags & IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_P) == 0? "host" : "prefix",
ipmip_ntop_inet(proc, IP_GET_32ON8(&mp->home_address)),
pflags >> IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_PREF,
ipmip_ntop_inet(proc, hoa),
plen));
if (plen == 32)
{
num_hoa++;
ipcom_list_insert_last(&node->nemo_hoa_v4, &nemo->next);
}
else
{
num_prefix++;
ipcom_list_insert_last(&node->nemo_prefix_v4, &nemo->next);
}
}
else
{
unauthorized:
IPMIP6_EVENT_IF(INFO, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Unable to allocate %s HoA - Request is %s/%d",
(pflags & IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_P) == 0? "host" : "prefix",
ipmip_ntop_inet(proc, hoa),
plen));
if (IPMIP6_MH_BU_IS_P(node->regflags))
{
ret = IPMIP6_MH_BA_STATUS_ERROR_NOT_AUTHORIZED_FOR_IPV4_HOME_ADDRESS;
prohibit:
mp_ack.status = IPMIP6_MH_BU_DSMIPV6_HOA_ACK_ADMIN_PROHIBITED;
}
else
{
/* Failed to allocate */
if (hoa == 0)
mp_ack.status = IPMIP6_MH_BU_DSMIPV6_HOA_ACK_DYNAMIC_HOA_UNAVAILABLE;
else
mp_ack.status = (Ip_u8) (plen == 32? IPMIP6_MH_BU_DSMIPV6_HOA_ACK_INCORRECT_HOA : IPMIP6_MH_BU_DSMIPV6_HOA_ACK_PREFIX_UNAUTHORIZED);
}
ipmip_buffer_append(&pbuf->mo_reply, &mp_ack, sizeof(mp_ack));
continue;
}
}
acknowledge:
IP_SET_32ON8(&mp_ack.home_address, nemo->prefix);
if (IPMIP6_MH_BU_IS_P(node->regflags))
mp_ack.pref = (Ip_u8)(nemo->netmask << IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_ACK_PREF);
else
mp_ack.pref = (Ip_u8)(nemo->len << IPMIP6_MH_MO_DSMIPV6_IPV4_HOME_ADDRESS_ACK_PREF);
mp_ack.status = IPMIP6_MH_BU_DSMIPV6_HOA_ACK_SUCCESS;
ipmip_buffer_append(&pbuf->mo_reply, &mp_ack, sizeof(mp_ack));
if (IPMIP6_MH_BU_IS_P(node->regflags))
{
Ipmip6ha_node_P_t *pnode = (Ipmip6ha_node_P_t *)node;
if ((pnode->router = ipmip6ha_nemo_dsmipv6_subnet_config_gateway(ctx, proc, node->ifp_home->nemo->nemo_dsmipv6, nemo->prefix)) == 0)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"No router configured for topology address/subnet %s [dhcp.option.router]",
ipmip_ntop_inet(proc, nemo->prefix)));
ret = IPMIP6_MH_BA_STATUS_ERROR_PROXY_REG_NOT_ENABLED;
}
}
}
}
}
ipcom_mutex_unlock(node->ifp_home->nemo->nemo_dsmipv6->nemo_dhcp_rtab->rtab_lock);
for (nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4); nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->next))
{
if ((nemo->flags & (IPMIP6HA_NEMO_ACL_DELETED|IPMIP6HA_NEMO_ACL_ADDED)))
*changed = IP_TRUE;
}
for (nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4); nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->next))
{
if ((nemo->flags & (IPMIP6HA_NEMO_ACL_DELETED|IPMIP6HA_NEMO_ACL_ADDED)))
*changed = IP_TRUE;
}
return ret;
}
IP_GLOBAL void
ipmip6ha_nemo_dsmipv6_unconfigure(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nemo)
{
if (nemo)
{
Ipmip_dhcp_pool_t *pool;
IPMIP_UNUSED_PARAMETER(proc);
while ((pool = IPCOM_LIST_FIRST(&nemo->nemo_dsmipv6_pools)) != IP_NULL)
{
ipcom_list_remove(&pool->next);
ipmip_dhcp_pool_destroy(&ctx->ipmip6.ipmip, proc, pool);
}
if (nemo->nemo_dsmipv6_acl_mr_hoa != IP_NULL)
{
ipcom_route_free_table(nemo->nemo_dsmipv6_acl_mr_hoa);
nemo->nemo_dsmipv6_acl_mr_hoa = IP_NULL;
}
if (nemo->nemo_dsmipv6_acl_lma_nai != IP_NULL)
{
ipcom_hash_for_each(nemo->nemo_dsmipv6_acl_lma_nai, (Ipcom_hash_foreach_cb_func)ipmip6ha_nemo_dsmipv6_acl_nai_del_cb, nemo->nemo_dsmipv6_acl_lma_nai);
ipcom_hash_delete(nemo->nemo_dsmipv6_acl_lma_nai);
nemo->nemo_dsmipv6_acl_lma_nai = IP_NULL;
}
if (nemo->nemo_dsmipv6_acl_mr_nai != IP_NULL)
{
ipcom_hash_for_each(nemo->nemo_dsmipv6_acl_mr_nai, (Ipcom_hash_foreach_cb_func)ipmip6ha_nemo_dsmipv6_acl_nai_del_cb, nemo->nemo_dsmipv6_acl_mr_nai);
ipcom_hash_delete(nemo->nemo_dsmipv6_acl_mr_nai);
nemo->nemo_dsmipv6_acl_mr_nai = IP_NULL;
}
if (nemo->nemo_inet_config != IP_NULL)
{
ipcom_route_free_table(nemo->nemo_inet_config);
nemo->nemo_inet_config = IP_NULL;
}
ipmip_dhcp_rtab_destroy(nemo->nemo_dhcp_rtab);
ipcom_free(nemo);
}
}
IP_GLOBAL void
ipmip6ha_nemo_dsmipv6_configure(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_nemo_dsmipv6_context_t **nemop,
const char *ifname)
{
Ipmip6ha_nemo_dsmipv6_context_t *nemo;
struct Ipmip6ha_nemo_dsmipv6_cb cb;
char **svar;
Ip_u32 inet_addr;
Ip_u32 inet_plen;
int i;
*nemop = nemo = ipcom_calloc(1, sizeof(*nemo));
nemo->nemo_inet_config = ipcom_route_new_table(sizeof(Ip_u32) * 8,
(Ipcom_route_notify_func) ipmip6ha_nemo_dsmipv6_config_notify);
nemo->nemo_dsmipv6_acl_mr_hoa = ipcom_route_new_table(sizeof(struct Ip_in6_addr) * 8,
(Ipcom_route_notify_func) ipmip6ha_nemo_dsmipv6_acl_notify);
nemo->nemo_dsmipv6_acl_lma_nai= ipcom_hash_new((Ipcom_hash_obj_func) ipmip6ha_nemo_dsmipv6_nai_obj_hash,
(Ipcom_hash_key_func) ipmip6ha_nemo_dsmipv6_nai_key_hash,
(Ipcom_hash_cmp_func) ipmip6ha_nemo_dsmipv6_nai_key_cmp);
nemo->nemo_dsmipv6_acl_mr_nai = ipcom_hash_new((Ipcom_hash_obj_func) ipmip6ha_nemo_dsmipv6_nai_obj_hash,
(Ipcom_hash_key_func) ipmip6ha_nemo_dsmipv6_nai_key_hash,
(Ipcom_hash_cmp_func) ipmip6ha_nemo_dsmipv6_nai_key_cmp);
nemo->nemo_dhcp_rtab = ipmip_dhcp_rtab_create(&ctx->ipmip6.ipmip, proc, IP_NULL);
ipcom_list_init(&nemo->nemo_dsmipv6_pools);
cb.ctx = ctx;
cb.nemo = nemo;
cb.opaque = IP_NULL;
cb.initfmt = ifname;
/* Syntax OPTION_NAME.SUBNET_DEFINITION */
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_config_dhcp_foreach,
&cb,
"ipmip6ha.LMA.inet.topology.dhcp.option.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_config_dhcp_foreach,
&cb,
"ipmip6ha.interface.%s.LMA.inet.topology.dhcp.option.*", ifname);
svar = ipmip_sysvar_strarr("ipmip6ha.inet.topology.reserved");
if (svar != IP_NULL)
{
for (i = 0; svar[i] != IP_NULL; i++)
{
if (ipmip_util_inet(svar[i], &inet_addr, &inet_plen))
ipmip_dhcp_lease_alloc(&ctx->ipmip6.ipmip, proc, IP_NULL, nemo->nemo_dhcp_rtab, inet_addr, (Ip_u8)inet_plen, (Ip_u8)inet_plen, IP_NULL);
}
ipcom_free(svar);
}
svar = ipmip_sysvar_strarr("ipmip6ha.interface.%s.inet.topology.reserved", ifname);
if (svar != IP_NULL)
{
for (i = 0; svar[i] != IP_NULL; i++)
{
if (ipmip_util_inet(svar[i], &inet_addr, &inet_plen))
ipmip_dhcp_lease_alloc(&ctx->ipmip6.ipmip, proc, IP_NULL, nemo->nemo_dhcp_rtab, inet_addr, (Ip_u8)inet_plen, (Ip_u8)inet_plen, IP_NULL);
}
ipcom_free(svar);
}
/* Determine the pools */
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_pool_foreach,
&cb,
"ipmip6ha.inet.pool.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_pool_foreach,
&cb,
"ipmip6ha.interface.%s.inet.pool.*", ifname);
/* Go through address covered pools */
/* INET ACLs */
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_homeaddress_foreach,
&cb,
"ipmip6ha.inet.acl.homeaddress.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_homeaddress_foreach,
&cb,
"ipmip6ha.interface.%s.inet.acl.homeaddress.*", ifname);
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_limit_homeaddress_foreach,
&cb,
"ipmip6ha.inet.acl.limit.homeaddress.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_limit_homeaddress_foreach,
&cb,
"ipmip6ha.interface.%s.inet.acl.limit.homeaddress.*", ifname);
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_limit_prefix_delegation_foreach,
&cb,
"ipmip6ha.inet.acl.limit.prefix_delegation.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_limit_prefix_delegation_foreach,
&cb,
"ipmip6ha.interface.%s.inet.acl.limit.prefix_delegation.*", ifname);
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_prefix_delegation_foreach,
&cb,
"ipmip6ha.mobile_router.inet.acl.prefix_delegation.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_prefix_delegation_foreach,
&cb,
"ipmip6ha.interface.%s.mobile_router.inet.acl.prefix_delegation.*", ifname);
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_pool_foreach,
&cb,
"ipmip6ha.inet.acl.pool.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_mr_acl_pool_foreach,
&cb,
"ipmip6ha.interface.%s.inet.acl.pool.*", ifname);
/* LMA ACLs */
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_lma_acl_homeaddress_foreach,
&cb,
"ipmip6ha.LMA.inet.acl.homeaddress.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_lma_acl_homeaddress_foreach,
&cb,
"ipmip6ha.interface.%s.LMA.inet.acl.homeaddress.*", ifname);
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_lma_acl_pool_foreach,
&cb,
"ipmip6ha.LMA.inet.acl.pool.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6ha_nemo_dsmipv6_sysvar_lma_acl_pool_foreach,
&cb,
"ipmip6ha.interface.%s.LMA.inet.acl.pool.*", ifname);
/* Resolve linkage */
ipmip_route_walk(&ctx->ipmip6.ipmip, proc, nemo->nemo_inet_config, IP_NULL, (Ipmip_route_walk_t)ipmip6ha_nemo_dsmipv6_route_resolve_parent);
ipmip_route_walk(&ctx->ipmip6.ipmip, proc, nemo->nemo_dsmipv6_acl_mr_hoa, IP_NULL, (Ipmip_route_walk_t)ipmip6ha_nemo_dsmipv6_route_resolve_acl);
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
proc,
nemo->nemo_dsmipv6_acl_mr_nai,
(Ipmip_util_hash_foreach_t)ipmip6ha_nemo_dsmipv6_resolve_acl,
nemo,
IP_NULL);
}
IP_GLOBAL void
ipmip6ha_nemo_dsmipv6_context_init(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
}
IP_GLOBAL void
ipmip6ha_nemo_dsmipv6_context_destroy(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
}
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_dump_config_network_rules(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_rtab_t *rtab,
Ipmip6ha_nemo_dsmipv6_acl_entry_t *rt_acl,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
Ipmip6ha_nemo_dsmipv6_t *nemo;
IPMIP_UNUSED_PARAMETER(rtab);
IPMIP_UNUSED_PARAMETER(ctx);
if (rt_acl->acl.pool != IP_NULL)
{
ipmip_cli_config_printf(cb->opaque,
"ipmip6ha.interface.%s.inet.acl.pool.%s/%d=%s",
cb->initfmt, ipmip_ntop_inet6(proc, &rt_acl->subnet, IP_NULL), rt_acl->mask_len, rt_acl->acl.pool->name);
}
if (rt_acl->acl.hoa)
{
ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf),
"ipmip6ha.interface.%s.inet.acl.homeaddress.%s/%d=",
cb->initfmt, ipmip_ntop_inet6(proc, &rt_acl->subnet, IP_NULL), rt_acl->mask_len);
for (nemo = rt_acl->acl.hoa; nemo != IP_NULL; nemo = nemo->acl_next)
{
ipcom_snprintf(proc->ntop.ntop_name, sizeof(proc->ntop.ntop_name), "%s%s/%d", nemo == rt_acl->acl.hoa? "" : ",", ipmip_ntop_inet(proc, nemo->prefix), nemo->netmask);
ipcom_strncat(proc->ntop.ntop_pbuf, proc->ntop.ntop_name, sizeof(proc->ntop.ntop_pbuf));
}
ipmip_cli_config_printf(cb->opaque, proc->ntop.ntop_pbuf);
}
if (rt_acl->acl.pd)
{
ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf),
"ipmip6ha.interface.%s.mobile_router.inet.acl.prefix_delegation.%s/%d=",
cb->initfmt, ipmip_ntop_inet6(proc, &rt_acl->subnet, IP_NULL), rt_acl->mask_len);
for (nemo = rt_acl->acl.hoa; nemo != IP_NULL; nemo = nemo->acl_next)
{
ipcom_snprintf(proc->ntop.ntop_name, sizeof(proc->ntop.ntop_name), "%s%s/%d", nemo == rt_acl->acl.pd? "" : ",", ipmip_ntop_inet(proc, nemo->prefix), nemo->len);
ipcom_strncat(proc->ntop.ntop_pbuf, proc->ntop.ntop_name, sizeof(proc->ntop.ntop_pbuf));
}
ipmip_cli_config_printf(cb->opaque, proc->ntop.ntop_pbuf);
}
if (rt_acl->acl.mobile_router)
{
ipmip_cli_config_printf(cb->opaque,
"ipmip6ha.interface.%s.inet.acl.limit.prefix_delegation.%s/%d=%d",
cb->initfmt, ipmip_ntop_inet6(proc, &rt_acl->subnet, IP_NULL), rt_acl->mask_len, rt_acl->acl.limit_prefix);
ipmip_cli_config_printf(cb->opaque,
"ipmip6ha.interface.%s.inet.acl.limit.homaddress.%s/%d=%d",
cb->initfmt, ipmip_ntop_inet6(proc, &rt_acl->subnet, IP_NULL), rt_acl->mask_len, rt_acl->acl.limit_prefix);
}
return IP_FALSE;
}
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_dump_config_subnet_rules(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_rtab_t *rtab,
Ipmip6ha_nemo_dsmipv6_config_entry_t *rt_sub,
struct Ipmip6ha_nemo_dsmipv6_cb *cb)
{
Ipmip_dhcp_option_t *opt;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(rtab);
/**/
for (opt = IPCOM_LIST_FIRST(&rt_sub->cfg.opts); opt != IP_NULL; opt = IPCOM_LIST_NEXT(&opt->next))
{
const Ipmip_dhcp_option_def_t *dopt = ipmip_dhcp_option_def_code_get(opt->option[IPMIP_DHCP_OPT_CODE]);
if (dopt != IP_NULL)
{
ipmip_cli_config_printf(cb->opaque,
"ipmip6ha.interface.%s.LMA.inet.topology.dhcp.option.%s.%s/%d=%s",
cb->initfmt,
dopt->name,
ipmip_ntop_inet(proc, rt_sub->subnet),
rt_sub->ipmip.bits,
ipmip_dhcp_option_print(proc, opt->option, opt->type));
}
else
{
ipmip_cli_config_printf(cb->opaque,
"ipmip6ha.interface.%s.LMA.inet.topology.dhcp.option.%s.%u.%s/%d=%s",
cb->initfmt,
ipmip_dhcp_type_name[opt->type], opt->option[IPMIP_DHCP_OPT_CODE],
ipmip_ntop_inet(proc, rt_sub->subnet),
rt_sub->ipmip.bits,
ipmip_dhcp_option_print(proc, opt->option, opt->type));
}
}
return IP_FALSE;
}
IP_STATIC void
ipmip6ha_nemo_dsmipv6_dump_config_nai_rules(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_nemo_dsmipv6_hash_key_t *key,
Ipmip_buffer_t *buffer,
const char *pre)
{
Ipmip6ha_nemo_dsmipv6_t *nemo;
IPMIP_UNUSED_PARAMETER(ctx);
if (key->acl.pool != IP_NULL)
{
if (key->acl.mobile_router)
{
ipmip_cli_config_printf(buffer,
"ipmip6ha.interface.%s.inet.acl.pool.%s=%s",
pre, key->key, key->acl.pool->name);
}
else
{
ipmip_cli_config_printf(buffer,
"ipmip6ha.interface.%s.LMA.inet.acl.pool.%s=%s",
pre, key->key, key->acl.pool->name);
}
}
if (key->acl.hoa)
{
if (key->acl.mobile_router)
{
ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf),
"ipmip6ha.interface.%s.inet.acl.homeaddress.%s=",
pre, key->key);
}
else
{
ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf),
"ipmip6ha.interface.%s.LMA.inet.acl.homeaddress.%s=",
pre, key->key);
}
for (nemo = key->acl.hoa; nemo != IP_NULL; nemo = nemo->acl_next)
{
ipcom_snprintf(proc->ntop.ntop_name, sizeof(proc->ntop.ntop_name), "%s%s/%d", nemo == key->acl.hoa? "" : ",", ipmip_ntop_inet(proc, nemo->prefix), nemo->netmask);
ipcom_strncat(proc->ntop.ntop_pbuf, proc->ntop.ntop_name, sizeof(proc->ntop.ntop_pbuf));
}
ipmip_cli_config_printf(buffer, proc->ntop.ntop_pbuf);
}
if (key->acl.pd)
{
ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf),
"ipmip6ha.interface.%s.mobile_router.inet.acl.prefix_delegation.%s=",
pre, key->key);
for (nemo = key->acl.pd; nemo != IP_NULL; nemo = nemo->acl_next)
{
ipcom_snprintf(proc->ntop.ntop_name, sizeof(proc->ntop.ntop_name), "%s%s/%d", nemo == key->acl.pd? "" : ",", ipmip_ntop_inet(proc, nemo->prefix), nemo->len);
ipcom_strncat(proc->ntop.ntop_pbuf, proc->ntop.ntop_name, sizeof(proc->ntop.ntop_pbuf));
}
ipmip_cli_config_printf(buffer, proc->ntop.ntop_pbuf);
}
if (key->acl.mobile_router)
{
ipmip_cli_config_printf(buffer,
"ipmip6ha.interface.%s.inet.acl.limit.prefix_delegation.%s=%d",
pre, key->key, key->acl.limit_prefix);
ipmip_cli_config_printf(buffer,
"ipmip6ha.interface.%s.inet.acl.limit.homaddress.%s=%d",
pre, key->key, key->acl.limit_prefix);
}
}
IP_STATIC Ip_bool
ipmip6ha_nemo_dsmipv6_dump_reserved(Ipmip_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip_rtab_t *rtab,
Ipmip_dhcp_lease_t *lease,
Ip_u32 *noff)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(rtab);
/* Permanent allocation? */
if (lease->pool == IP_NULL && lease->opaque == IP_NULL)
*noff += (Ip_u32)ipcom_snprintf(&proc->ntop.ntop_pbuf[*noff], sizeof(proc->ntop.ntop_pbuf) - *noff, "%s/%d ", ipmip_ntop_inet(proc, lease->prefix), lease->prefix_len);
return IP_FALSE;
}
IP_GLOBAL void
ipmip6ha_nemo_dsmipv6_dump_config(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_nemo_dsmipv6_context_t *nctx,
const char *ifname,
Ipmip_buffer_t *buffer)
{
Ipmip_dhcp_pool_t *pool;
struct Ipmip6ha_nemo_dsmipv6_cb cb;
Ip_u32 soff, eoff;
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
proc,
nctx->nemo_dsmipv6_acl_lma_nai,
(Ipmip_util_hash_foreach_t)ipmip6ha_nemo_dsmipv6_dump_config_nai_rules,
buffer,
(char *)ifname);
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
proc,
nctx->nemo_dsmipv6_acl_mr_nai,
(Ipmip_util_hash_foreach_t)ipmip6ha_nemo_dsmipv6_dump_config_nai_rules,
buffer,
(char *)ifname);
cb.ctx = ctx;
cb.nemo = nctx;
cb.opaque = buffer;
cb.initfmt = ifname;
ipmip_route_walk(&ctx->ipmip6.ipmip, proc, nctx->nemo_dsmipv6_acl_mr_hoa, &cb, (Ipmip_route_walk_t) ipmip6ha_nemo_dsmipv6_dump_config_network_rules);
ipmip_route_walk(&ctx->ipmip6.ipmip, proc, nctx->nemo_inet_config, &cb, (Ipmip_route_walk_t) ipmip6ha_nemo_dsmipv6_dump_config_subnet_rules);
soff = eoff = (Ip_u32)ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf), "ipmip6ha.interface.%s.inet.topology.reserved=", ifname);
ipmip_route_walk(&ctx->ipmip6.ipmip, proc, nctx->nemo_dhcp_rtab->rtab, &eoff, (Ipmip_route_walk_t) ipmip6ha_nemo_dsmipv6_dump_reserved);
if (soff != eoff)
ipmip_cli_config_printf(buffer, proc->ntop.ntop_pbuf);
/**/
for (pool = IPCOM_LIST_FIRST(&nctx->nemo_dsmipv6_pools); pool != IP_NULL; pool = IPCOM_LIST_NEXT(&pool->next))
{
Ipmip_dhcp_slice_t *slice;
ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf), "ipmip6ha.interface.%s.inet.pool.%s=", ifname, pool->name);
/* Free the slices */
for (slice = IPCOM_LIST_FIRST(&pool->slices); slice != IP_NULL; slice = IPCOM_LIST_NEXT(&slice->next))
{
ipcom_snprintf(proc->ntop.ntop_name,
sizeof(proc->ntop.ntop_name),
"%s-%s/%d/%d ",
ipmip_ntop_inet(proc, ip_htonl(slice->start)),
ipmip_ntop_inet(proc, ip_htonl(slice->end)),
slice->netmask_bits,
slice->slice_size);
ipcom_strncat(proc->ntop.ntop_pbuf, proc->ntop.ntop_name, sizeof(proc->ntop.ntop_pbuf));
}
ipmip_cli_config_printf(buffer, proc->ntop.ntop_pbuf);
}
}
#else
int ipmip6ha_nemo_dsmipv6_empty_file = 0;
#endif
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/