/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6ha_config.h" #ifdef IPMIP_USE_INET /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 **************************************************************************** */