2299 lines
85 KiB
C
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
|
|
****************************************************************************
|
|
*/
|