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

1139 lines
42 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6pm_lma.c,v $ $Revision: 1.15 $
* $Source: /home/interpeak/CVSRoot/ipmip6pm/src/ipmip6pm_lma.c,v $
* $Author: jhorteli $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipmip6pm_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#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_ipd.h>
#include <ipcom_syslog.h>
#include <ipnet.h>
#include <ipmip.h>
#include <private/ipmip_util.h>
#include <private/ipmip_dhcp.h>
#include <private/ipmip_sysvar.h>
#include <ipmip6.h>
#include <private/ipmip6_context.h>
#include <private/ipmip6_pkt.h>
#include <private/ipmip6_if.h>
#include <private/ipmip6_mh.h>
#include <private/ipmip6_mh_pkt.h>
#include <private/ipmip6_netlink.h>
#include <private/ipmip6_util.h>
#include "ipmip6pm.h"
#include "ipmip6pm_h.h"
#include "ipmip6pm_node.h"
#include "ipmip6pm_attr_h.h"
#include "ipmip6pm_cli.h"
#include "ipmip6pm_ifevent.h"
#include "ipmip6pm_mh.h"
#include "ipmip6pm_if.h"
#include "ipmip6pm_route.h"
#include "ipmip6pm_pktbuf.h"
#include "ipmip6pm_lma.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
struct Ipmip6pm_lma_cb
{
Ipmip6pm_context_t *ctx;
Ipmip6pm_if_t *ife;
};
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC unsigned
ipmip6pm_lma_key_hash_nai(struct Ip_in6_addr *endpoint)
{
return ipcom_hash_update(endpoint, sizeof(*endpoint), 0);
}
IP_STATIC unsigned
ipmip6pm_lma_obj_hash_nai(Ipmip6pm_lma_t *lma)
{
return ipmip6pm_lma_key_hash_nai(&lma->endpoint);
}
IP_STATIC Ip_bool
ipmip6pm_lma_cmp_nai(Ipmip6pm_lma_t *lma, struct Ip_in6_addr *endpoint)
{
return IP_IN6_ARE_ADDR_EQUAL(&lma->endpoint, endpoint);
}
IP_STATIC void
ipmip6pm_lma_free_bri(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_br_t *bri)
{
if (bri->next.head != IP_NULL)
{
ipcom_list_remove(&bri->next);
/* Already have something outstanding? */
ipmip_context_id_lock(ctx->bri);
ipmip_context_id_release(ctx->bri, bri);
ipmip_context_id_unlock(ctx->bri);
/**/
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &bri->retransmit);
/**/
ipcom_free(bri);
}
}
IP_STATIC void
ipmip6pm_lma_delete_locked(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma)
{
Ipmip6pm_br_t *bri;
IPMIP6_EVENT_IF(DEBUG, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Deleted LMA %s",
ipmip_ntop_inet6(proc, &lma->endpoint, &lma->ifp->ipmip6.iff)));
while ((bri = IPCOM_LIST_FIRST(&lma->bri)) != IP_NULL)
ipmip6pm_lma_free_bri(ctx, proc, bri);
/* Clear lma */
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &lma->timer);
ipcom_hash_remove(lma->ifp->lma_table, lma);
ipcom_free(lma);
}
IP_STATIC Ipmip6pm_lma_t *
ipmip6pm_lma_new_locked(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
struct Ipmip6pm_if *ifp,
struct Ip_in6_addr *addr,
Ip_u32 inet_endpoint,
Ip_bool permanent)
{
Ipmip6pm_lma_t *lma = ipcom_calloc(1, sizeof(*lma));
ipcom_memcpy(&lma->endpoint, addr, sizeof(*addr));
lma->ifp = ifp;
lma->permanent = permanent;
lma->inet_endpoint = inet_endpoint;
ipcom_list_init(&lma->bri);
/* Clear lma */
ipcom_hash_add(ifp->lma_table, lma);
/* */
IPMIP6_EVENT_IF(DEBUG, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Added LMA %s",
ipmip_ntop_inet6(proc, &lma->endpoint, &ifp->ipmip6.iff)));
return lma;
}
IP_STATIC void
ipmip6pm_lma_release_locked(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma)
{
/**/
if (--lma->references == 0)
{
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &lma->timer);
if (!lma->permanent)
ipmip6pm_lma_delete_locked(ctx, proc, lma);
}
}
IP_STATIC void
ipmip6pm_lma_delete_cb(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma,
void *arg1,
void *arg2)
{
IPMIP_UNUSED_PARAMETER(arg1);
IPMIP_UNUSED_PARAMETER(arg2);
/* Delete */
ipmip6pm_lma_delete_locked(ctx, proc, lma);
}
IP_STATIC Ip_bool
ipmip6pm_lma_heartbeat_response(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_if_t *ifp,
struct Ip_in6_addr *dst,
Ip_u32 seq,
Ip_u16 flags)
{
/**/
Ipmip6_pktbuf_t *pkt;
Ipmip6_mh_heartbeat_message_t *bh;
Ipmip6_mh_mo_heartbeat_restart_counter_option_t rc;
int err;
/* Grab a packet */
pkt = (Ipmip6_pktbuf_t *) ipmip6_mh_pkt_alloc(&ctx->ipmip6,
proc,
sizeof(Ipmip6_mh_heartbeat_message_t),
IPMIP6_MH_HEARTBEAT_MESSAGE);
/* Out of memory? */
if (pkt == IP_NULL)
return IP_FALSE;
/* Get the MH header */
bh = (Ipmip6_mh_heartbeat_message_t *) IPMIP_BUFFER_PTR(&pkt->ipmip.packet);
IP_SET_HTONS(&bh->bh_flags, flags | IPMIP6_MH_HEARTBEAT_FLAG_R);
IP_SET_HTONL(&bh->bh_seq, seq);
rc.hdr.val = IPMIP6_MH_MO_HEARTBEAT_RESTART_COUNTER;
rc.hdr.len = 4;
IP_SET_HTONL(&rc.restart_counter, ctx->ipmip6.restart_counter);
/**/
ipmip6_mh_pkt_opt_add_mo(&ctx->ipmip6,
proc,
pkt,
&rc.hdr);
/**/
/* Force it to go out using the CoA */
if (ifp->UseIPv4UDPEncapForSignalingMessages)
{
/* Ipv4 transport */
ipmip6_pkt_pktinfo_opt_add(pkt,
&ifp->ifaddr.prefix,
&ifp->iftunnels[IPMIP_TUNNELTYPE_IPIP]->ipmip6);
}
else
ipmip6_pkt_pktinfo_src_opt_add(pkt, &ifp->ifaddr.prefix);
if ((err = ipmip6_pkt_send(&ctx->ipmip6, proc, ctx->ipmip6.pkt->fd_mh, pkt, dst)) != 0)
{
IPCOM_LOG2(INFO,
"%s: Error sending MH HeartBeat Response = %x",
ctx->ipmip6.ipmip.name,
err);
return IP_FALSE;
}
return IP_TRUE;
}
IP_STATIC Ip_bool
ipmip6pm_lma_send_heartbeat_request_locked(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma)
{
/**/
Ipmip6_pktbuf_t *pkt;
Ipmip6_mh_heartbeat_message_t *bh;
int err;
/* Grab a packet */
pkt = (Ipmip6_pktbuf_t *) ipmip6_mh_pkt_alloc(&ctx->ipmip6,
proc,
sizeof(Ipmip6_mh_heartbeat_message_t),
IPMIP6_MH_HEARTBEAT_MESSAGE);
/* Out of memory? */
if (pkt == IP_NULL)
return IP_FALSE;
/* Get the MH header */
bh = (Ipmip6_mh_heartbeat_message_t *) IPMIP_BUFFER_PTR(&pkt->ipmip.packet);
IP_SET_HTONS(&bh->bh_flags, 0);
lma->sequence++;
lma->unacked++;
IP_SET_HTONL(&bh->bh_seq, lma->sequence);
/**/
ipmip6pm_lma_route_mh(ctx, proc, lma->ifp, &lma->endpoint, lma->inet_endpoint);
/**/
/* Force it to go out using the CoA */
if (lma->ifp->UseIPv4UDPEncapForSignalingMessages)
{
/* Ipv4 transport */
ipmip6_pkt_pktinfo_opt_add(pkt,
&lma->ifp->ifaddr.prefix,
&lma->ifp->iftunnels[IPMIP_TUNNELTYPE_IPIP]->ipmip6);
}
else
ipmip6_pkt_pktinfo_src_opt_add(pkt, &lma->ifp->ifaddr.prefix);
/* Send */
if ((err = ipmip6_pkt_send(&ctx->ipmip6, proc, ctx->ipmip6.pkt->fd_mh, pkt, &lma->endpoint)) != 0)
{
IPCOM_LOG2(INFO,
"%s: Error sending MH HeartBeat = %x",
ctx->ipmip6.ipmip.name,
err);
return IP_FALSE;
}
return IP_TRUE;
}
IP_STATIC int
ipmip6pm_lma_send_heartbeat_unsolicited_locked(int event,
Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma,
void *unused)
{
IPMIP_UNUSED_PARAMETER(unused);
if (event == IPMIP_TIMER_EVENT_RUN)
{
ipmip6pm_lma_route(ctx, proc, lma);
ipmip6pm_lma_heartbeat_response(ctx,
proc,
lma->ifp,
&lma->endpoint,
0,
IPMIP6_MH_HEARTBEAT_FLAG_U);
}
return IPMIP_TIMER_RET_DONE; /* do not reschedule the timeout */
}
IP_STATIC int
ipmip6pm_lma_send_heartbeat_timeout_locked(int event,
Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma,
void *unused)
{
IPMIP_UNUSED_PARAMETER(unused);
if (event == IPMIP_TIMER_EVENT_RUN)
{
if (lma->unacked > lma->ifp->HeartBeatMissAllowed)
{
IPMIP6_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"LMA %s seems DEAD - no HeartBeat response",
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL)));
}
/**/
ipmip6pm_lma_send_heartbeat_request_locked(ctx, proc, lma);
ipmip_timer_request(&ctx->ipmip6.ipmip,
proc,
&lma->timer,
lma->ifp->ipmip6.iff_lock,
(Ipmip_timer_func_t)ipmip6pm_lma_send_heartbeat_timeout_locked,
lma,
IP_NULL,
lma->ifp->HeartBeatInterval * 1000);
}
return IPMIP_TIMER_RET_DONE; /* do not reschedule the timeout */
}
IP_STATIC Ip_u32
ipmip6pm_lma_reference_locked(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
return ++lma->references;
}
IP_STATIC Ipmip6pm_lma_t *
ipmip6pm_lma_get_locked(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
struct Ipmip6pm_if *ifp,
struct Ip_in6_addr *endpoint,
Ip_u32 inet_endpoint,
unsigned flags)
{
Ipmip6pm_lma_t *lma;
lma = ipcom_hash_get(ifp->lma_table, endpoint);
if (lma == IP_NULL && IP_BIT_ISSET(flags, IPMIP6PM_LMA_CREATE))
lma = ipmip6pm_lma_new_locked(ctx, proc, ifp, endpoint, inet_endpoint, IP_BIT_ISTRUE(flags, IPMIP6PM_LMA_PERMANENT));
/**/
if (lma)
{
if (ipmip6pm_lma_reference_locked(ctx, proc, lma) == 1 && lma->ifp->HeartBeatEnabled && !lma->disabled)
ipmip_timer_request(&ctx->ipmip6.ipmip, proc, &lma->timer, lma->ifp->ipmip6.iff_lock, (Ipmip_timer_func_t)ipmip6pm_lma_send_heartbeat_timeout_locked, lma, IP_NULL, 0);
}
return lma;
}
IP_STATIC void
ipmip6pm_lma_configure_foreach(struct Ipmip_proc *proc,
char *name,
char *subkey,
const char *value,
struct Ipmip6pm_lma_cb *cb)
{
struct Ip_in6_addr endpoint;
Ip_u32 inet_endpoint = 0;
Ipmip6pm_lma_t *lma;
#ifdef IPMIP_USE_INET
const char *needle;
#endif
IPMIP_UNUSED_PARAMETER(name);
ipmip_util_inet6(subkey, &endpoint, IP_NULL);
#ifdef IPMIP_USE_INET
if ((needle = ipcom_strchr(subkey, '/')) != IP_NULL)
ipmip_util_inet(needle + 1, &inet_endpoint, IP_NULL);
#endif
lma = ipmip6pm_lma_get_locked(cb->ctx, proc, cb->ife, &endpoint, inet_endpoint, IPMIP6PM_LMA_CREATE|IPMIP6PM_LMA_PERMANENT);
if (lma)
{
int enabled = ipmip_sysvar_cmd_str_to_key(ipmip_sysvar_bool_ops, value);
lma->disabled = (enabled == 0);
/**/
if (lma->disabled == IP_FALSE)
{
ipmip_timer_cancel(&cb->ctx->ipmip6.ipmip, proc, &lma->timer);
ipmip_timer_request(&cb->ctx->ipmip6.ipmip, proc, &lma->timer, cb->ife->ipmip6.iff_lock, (Ipmip_timer_func_t)ipmip6pm_lma_send_heartbeat_unsolicited_locked, lma, IP_NULL, 0);
}
--lma->references;
}
}
IP_STATIC void
ipmip6pm_lma_configure_dump_foreach(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma,
Ipmip_buffer_t *buffer,
Ipmip6pm_if_t *ife)
{
IPMIP_UNUSED_PARAMETER(ctx);
/**/
if (lma->permanent)
{
#ifdef IPMIP_USE_INET
if (lma->inet_endpoint)
ipmip_cli_config_printf(buffer,
"ipmip6pm.interface.%s.LMA.%s/%s=%s",
ife->ipmip6.iff.ifname,
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL),
ipmip_ntop_inet(proc, lma->inet_endpoint),
lma->disabled? "disabled" : "enabled");
else
#endif
ipmip_cli_config_printf(buffer,
"ipmip6pm.interface.%s.LMA.%s=%s",
ife->ipmip6.iff.ifname,
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL),
lma->disabled? "disabled" : "enabled");
}
}
IP_STATIC void
ipmip6pm_lma_restart_counter_foreach(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_node_t *node,
Ipmip6pm_lma_t *lma,
void *unused)
{
IPMIP_UNUSED_PARAMETER(unused);
if (node->lma == lma)
{
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &node->expire);
ipmip_timer_request(&ctx->ipmip6.ipmip,proc,
&node->expire,
node->lock,
(Ipmip_timer_func_t)ipmip6pm_node_registration_timeout,
node,
"timeout due to LMA restart",
0);
}
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
IP_GLOBAL void
ipmip6pm_lma_route_mh(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_if_t *ifp,
struct Ip_in6_addr *endpoint,
Ip_u32 inet_address)
{
#ifdef IPMIP_USE_INET
Ipmip_netlink_kern_compare_t scmp;
if (inet_address)
{
/* Create inbound tunnel route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
IP_WRMOB6_NEW_TYPE_TEMPORARY,
ctx->iftable_pm_inet,
ifp->iftunnels[IPMIP_TUNNELTYPE_IPIP]->ipmip6.iff.ifindex,
endpoint,
sizeof(struct Ip_in6_addr),
128,
&inet_address,
sizeof(struct Ip_in_addr),
ifp->UseIPv4UDPEncapForSignalingMessages? ip_htons(IPMIP6_DSMIP_UDP_PORT) : 0,
ipmip_netlink_route_src_add_protocol(ipmip_netlink_route_src_egress_ifindex(&scmp, ifp->iftunnels[IPMIP_TUNNELTYPE_IPIP]->ipmip6.iff.ifindex), IP_IPPROTO_MH),
IP_NULL,
IPMIP_LINK_SEND,
IP_NULL,
IPNET_RTF_TUNNELEND);
}
#else
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(ifp);
IPMIP_UNUSED_PARAMETER(endpoint);
IPMIP_UNUSED_PARAMETER(inet_address);
#endif
}
IP_GLOBAL void
ipmip6pm_lma_route(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma)
{
ipmip6pm_lma_route_mh(ctx, proc, lma->ifp, &lma->endpoint, lma->inet_endpoint);
}
IP_GLOBAL void
ipmip6pm_lma_route_pbuf(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_pktbuf_t *pbuf)
{
#ifdef IPMIP_USE_INET
if (pbuf->ipmip6.recvinfo.encapsulation != IP_NULL && pbuf->ipmip6.recvinfo.encapsulation->sa.sa_family == IP_AF_INET)
ipmip6pm_lma_route_mh(ctx, proc, pbuf->iff.priv, &pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr, pbuf->ipmip6.recvinfo.encapsulation->sin.sin_addr.s_addr);
#else
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(pbuf);
#endif
}
IP_GLOBAL Ipmip6pm_lma_t *
ipmip6pm_lma_get(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
struct Ipmip6pm_if *ifp,
struct Ip_in6_addr *endpoint,
Ip_u32 inet_endpoint,
unsigned flags)
{
Ipmip6pm_lma_t *lma;
ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, ifp->ipmip6.iff_lock);
lma = ipmip6pm_lma_get_locked(ctx, proc, ifp, endpoint, inet_endpoint, flags);
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, ifp->ipmip6.iff_lock);
return lma;
}
IP_GLOBAL void
ipmip6pm_lma_release(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma)
{
if (lma != IP_NULL)
{
Ipmip_timer_lock_t *lock = ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, lma->ifp->ipmip6.iff_lock);
ipmip6pm_lma_release_locked(ctx, proc, lma);
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, lock);
}
}
IP_GLOBAL void
ipmip6pm_lma_reference(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma)
{
if (lma != IP_NULL)
{
Ipmip_timer_lock_t *lock = ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, lma->ifp->ipmip6.iff_lock);
ipmip6pm_lma_reference_locked(ctx, proc, lma);
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, lock);
}
}
IP_GLOBAL void
ipmip6pm_lma_configure(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
struct Ipmip6pm_if *ife)
{
struct Ipmip6pm_lma_cb cb;
ife->lma_table= ipcom_hash_new((Ipcom_hash_obj_func) ipmip6pm_lma_obj_hash_nai,
(Ipcom_hash_key_func) ipmip6pm_lma_key_hash_nai,
(Ipcom_hash_cmp_func) ipmip6pm_lma_cmp_nai);
ife->HeartBeatInterval = ipmip_sysvar_ulong(ipmip_sysvar_ulong(60, "ipmip6pm.HeartBeatInterval"), "ipmip6pm.interface.%s.HeartBeatInterval", ife->ipmip6.iff.ifname);
ife->HeartBeatMissAllowed = ipmip_sysvar_ulong(ipmip_sysvar_ulong(3, "ipmip6pm.HeartBeatMissAllowed"), "ipmip6pm.interface.%s.HeartBeatMissAllowed", ife->ipmip6.iff.ifname);
ife->HeartBeatEnabled = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmip6pm.HeartBeatEnabled"), "ipmip6pm.interface.%s.HeartBeatEnabled", ife->ipmip6.iff.ifname);
cb.ctx = ctx;
cb.ife = ife;
/* Read The permanent LMA's */
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6pm_lma_configure_foreach,
&cb,
"ipmip6pm.LMA.*");
ipmip_sysvar_foreach(proc,
(Ipmip_sysvar_foreach_t) ipmip6pm_lma_configure_foreach,
&cb,
"ipmip6pm.interface.%s.LMA.*", ife->ipmip6.iff.ifname);
}
IP_GLOBAL void
ipmip6pm_lma_unconfigure(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
struct Ipmip6pm_if *ifp)
{
if (ifp->lma_table)
{
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
proc,
ifp->lma_table,
(Ipmip_util_hash_foreach_t)ipmip6pm_lma_delete_cb,
IP_NULL,
IP_NULL);
ipcom_hash_delete(ifp->lma_table);
ifp->lma_table = IP_NULL;
}
}
IP_GLOBAL void
ipmip6pm_lma_configure_dump(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_if_t *ife,
Ipmip_buffer_t *buffer)
{
ipmip_cli_config_printf(buffer,
"ipmip6pm.interface.%s.HeartBeatInterval=%d",
ife->ipmip6.iff.ifname, ife->HeartBeatInterval);
ipmip_cli_config_printf(buffer,
"ipmip6pm.interface.%s.HeartBeatMissAllowed=%d",
ife->ipmip6.iff.ifname, ife->HeartBeatMissAllowed);
ipmip_cli_config_printf(buffer,
"ipmip6pm.interface.%s.HeartBeatEnabled=%s",
ife->ipmip6.iff.ifname, ife->HeartBeatEnabled? "enabled" : "disabled");
/* Dump permanent rules */
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
proc,
ife->lma_table,
(Ipmip_util_hash_foreach_t)ipmip6pm_lma_configure_dump_foreach,
buffer,
ife);
}
IP_STATIC Ip_bool
ipmip6pm_lma_heartbeat_restart_counter_update(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma,
Ipmip6_mh_mo_heartbeat_restart_counter_option_t *mo)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
if (mo != IP_NULL)
{
Ip_u32 restart_counter = IP_GET_NTOHL(&mo->restart_counter);
Ip_bool changed = (lma->have_restart_counter && restart_counter != lma->restart_counter);
lma->restart_counter = restart_counter;
lma->have_restart_counter = IP_TRUE;
return changed;
}
return IP_FALSE;
}
IP_STATIC Ip_bool
ipmip6pm_lma_heartbeat_restart_counter(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma,
Ip_bool unsolicited,
Ipmip6_mh_mo_heartbeat_restart_counter_option_t *mo)
{
if (ipmip6pm_lma_heartbeat_restart_counter_update(ctx, proc, lma, mo) || unsolicited)
{
if (lma->references > 1)
{
/* There are nodes */
ipmip_context_id_lock(ctx->idents);
ipmip_context_id_foreach(&ctx->ipmip6.ipmip,
proc,
ctx->idents,
(Ipmip_util_hash_foreach_t)ipmip6pm_lma_restart_counter_foreach,
lma,
IP_NULL);
ipmip_context_id_unlock(ctx->idents);
}
return IP_TRUE;
}
return IP_FALSE;
}
IP_GLOBAL Ip_bool
ipmip6pm_lma_heartbeat_input(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_pktbuf_t *pbuf)
{
if (pbuf->iff.priv->HeartBeatEnabled)
{
Ipmip6_mh_heartbeat_message_t *hb = IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet);
Ip_u16 flags = IP_GET_NTOHS(&hb->bh_flags);
Ip_u32 seq = IP_GET_NTOHL(&hb->bh_seq);
if (IP_BIT_ISFALSE(flags, IPMIP6_MH_HEARTBEAT_FLAG_R))
{
IPMIP6_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"HeartBeat Request from LMA %s -- replying with %x",
ipmip_ntop_inet6(proc, &pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr, IP_NULL),
ctx->ipmip6.restart_counter));
/* */
/**/
ipmip6pm_lma_route_pbuf(ctx, proc, pbuf);
ipmip6pm_lma_heartbeat_response(ctx,
proc,
pbuf->iff.priv,
&pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr,
seq,
0);
}
else
{
/* Reply */
Ipmip6pm_lma_t *lma = ipmip6pm_lma_get(ctx, proc, pbuf->iff.priv, &pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr, 0, 0);
if (lma != IP_NULL)
{
if (IP_BIT_ISSET(flags, IPMIP6_MH_HEARTBEAT_FLAG_U))
{
IPMIP6_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"UNSOLICITED HeartBeat Response from LMA %s",
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL)));
/* Deal with unsolicited - and if it does not contain a restart counter */
ipmip6pm_lma_heartbeat_restart_counter(ctx, proc, lma, IP_TRUE, pbuf->ipmip6.mo.restart_option);
}
else
{
if (seq == lma->sequence)
{
lma->unacked = 0;
if (ipmip6pm_lma_heartbeat_restart_counter(ctx, proc, lma, IP_FALSE, pbuf->ipmip6.mo.restart_option))
{
IPMIP6_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"SOLICITED IN-SEQUENCE HeartBeat Response with changed Restart Counter (%x) from LMA %s",
lma->restart_counter,
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL)));
}
else
{
#ifdef IPTESTENGINE
IPMIP6_EVENT_IF(INFO, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"SOLICITED IN-SEQUENCE HeartBeat Response with unchanged Restart Counter (%x) from LMA %s",
lma->restart_counter,
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL)));
#else
IPMIP6_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"SOLICITED IN-SEQUENCE HeartBeat Response with unchanged Restart Counter (%x) from LMA %s",
lma->restart_counter,
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL)));
#endif
}
}
else
{
IPMIP6_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"SOLICITED OUT-OF-SEQUENCE HeartBeat Response from LMA %s",
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL)));
}
}
ipmip6pm_lma_release(ctx, proc, lma);
}
else
{
IPMIP6_EVENT_IF(INFO, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"SOLICITED HeartBeat Response from unknown LMA %s",
ipmip_ntop_inet6(proc, &pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr, IP_NULL)));
}
}
}
else
{
ipmip6pm_lma_route_pbuf(ctx, proc, pbuf);
return IP_FALSE;
}
/* */
ipmip_pktbuf_free(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip);
return IP_TRUE;
}
IP_GLOBAL Ip_bool
ipmip6pm_lma_heartbeat_binding_error_input(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_pktbuf_t *pbuf)
{
Ipmip6_mh_binding_error_t *be = IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet);
if (be->be_status == IPMIP6_MH_BE_STATUS_ERROR_UNKNOWN_MH_TYPE)
{
Ipmip6pm_lma_t *lma = ipmip6pm_lma_get(ctx, proc, pbuf->iff.priv, &pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr, 0, 0);
if (lma != IP_NULL)
{
/* */
if (lma->unacked != 0 && lma->disabled == IP_FALSE)
{
IPMIP6_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Binding Error received from LMA %s, HeartBeat disabled",
ipmip_ntop_inet6(proc, &lma->endpoint, IP_NULL)));
lma->disabled = IP_TRUE;
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &lma->timer);
/* */
ipmip6pm_lma_release(ctx, proc, lma);
}
}
}
/* */
ipmip_pktbuf_free(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip);
return IP_TRUE;
}
IP_STATIC void
ipmip6pm_lma_attr_get_foreach(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma,
Ipmip_buffer_t *buffer,
Ipmip6pm_if_t *ife)
{
Ip_size_t rta = ipmip_attr_begin(buffer, IPMIP6PM_CLI_ATTR_LMA);
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
/* */
ipmip_attr_put_inet6(buffer, IPMIP6PM_CLI_ATTR_BC_P_HOME_AGENT, &lma->endpoint);
#ifdef IPMIP_USE_INET
ipmip_attr_put_inet(buffer, IPMIP6PM_CLI_ATTR_BC_P_HOME_AGENT_INET, lma->inet_endpoint);
#endif
ipmip_attr_put_str(buffer, IPMIP6PM_CLI_ATTR_BC_P_IFNAME, ife->ipmip6.iff.ifname);
ipmip_attr_end(buffer, rta);
}
IP_GLOBAL void
ipmip6pm_lma_attr_get(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_if_t *ife,
Ipmip_buffer_t *buffer)
{
/* Dump permanent rules */
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
proc,
ife->lma_table,
(Ipmip_util_hash_foreach_t)ipmip6pm_lma_attr_get_foreach,
buffer,
ife);
}
IP_STATIC void
ipmip6pm_lma_revoke_node(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_node_t *node,
Ipmip6pm_br_t *bri,
void *unused)
{
IPMIP_UNUSED_PARAMETER(unused);
if (node->lma == bri->lma)
{
/* REVOKE */
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &node->revoke);
ipmip_timer_request(&ctx->ipmip6.ipmip,
proc,
&node->revoke,
node->lock,
(Ipmip_timer_func_t)ipmip6pm_node_timeout,
node,
"global revocation acknowledged",
0);
}
}
IP_STATIC int
ipmip6pm_lma_bri_timeout(int event,
Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_br_t *bri,
void *extarg)
{
IPMIP_UNUSED_PARAMETER(extarg);
if (event == IPMIP_TIMER_EVENT_RUN)
{
if (++bri->xmits > bri->lma->ifp->BRIMaxRetriesNumber)
{
ipmip_context_id_lock(ctx->idents);
/* Terminate any matching this MAG */
ipmip_context_id_foreach(&ctx->ipmip6.ipmip,
proc,
ctx->idents,
(Ipmip_util_hash_foreach_t)ipmip6pm_lma_revoke_node,
bri,
IP_NULL);
ipmip_context_id_unlock(ctx->idents);
/**/
ipmip6pm_lma_free_bri(ctx, proc, bri);
}
else
{
/* Retransmit */
ipmip6pm_mh_bri_send(ctx, proc, IP_NULL, bri);
return IPMIP_TIMER_RET_REINSERT;
}
}
return IPMIP_TIMER_RET_DONE;
}
IP_STATIC int
ipmip6pm_lma_bri_reply_locked(int event,
Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_br_t *bri,
Ipmip6pm_pktbuf_t *pbuf)
{
if (event == IPMIP_TIMER_EVENT_RUN)
{
/* Wipeout the nodes associated with this BRI */
Ipmip6_mh_bra_message_t *bra = (Ipmip6_mh_bra_message_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet);
IPMIP6_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Global Binding Revocation Acknowledgement received with status code %d", bra->bra_status));
/* Process */
if (bra->bra_status <= IPMIP6_MH_BRA_STATUS_PARTIAL_SUCCESS)
{
/* Accept */
ipmip_context_id_lock(ctx->idents);
/* Terminate any matching this MAG */
ipmip_context_id_foreach(&ctx->ipmip6.ipmip,
proc,
ctx->idents,
(Ipmip_util_hash_foreach_t)ipmip6pm_lma_revoke_node,
bri,
IP_NULL);
ipmip_context_id_unlock(ctx->idents);
}
else
{
IPMIP6_EVENT_IF(INFO, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"LMA %s unable to revoke, due to error %s",
ipmip_ntop_inet6(proc, &bri->lma->endpoint, IP_NULL),
ipmip6_mh_bra_error_str(bra->bra_status)));
}
}
/**/
ipmip6pm_lma_free_bri(ctx, proc, bri);
if (pbuf != IP_NULL)
ipmip_pktbuf_free(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip);
return IPMIP_TIMER_RET_DONE; /* do not reschedule the timeout */
}
IP_GLOBAL void
ipmip6pm_lma_revoke(Ipmip6pm_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6pm_lma_t *lma,
Ip_u8 reason)
{
Ipmip6pm_br_t *bri = ipcom_calloc(1, sizeof(*bri));
ipmip_context_id_lock(ctx->bri);
ipmip_context_id_allocate(ctx->bri, bri);
ipmip_context_id_unlock(ctx->bri);
bri->reason = reason? reason : IPMIP6_MH_BRI_TRIGGER_PER_PEER_POLICY;
bri->xmits = 0;
bri->lock = lma->ifp->ipmip6.iff_lock;
bri->opaque = IP_NULL;
bri->flags = IPMIP6_MH_BRI_FLAG_G;
bri->inet = IP_FALSE;
bri->reply = (Ipmip_timer_func_t)ipmip6pm_lma_bri_reply_locked;
bri->lma = lma;
bri->flags |= IPMIP6_MH_BRI_FLAG_P;
ipcom_list_insert_last(&lma->bri, &bri->next);
ipmip6pm_mh_bri_send(ctx, proc, IP_NULL, bri);
/* Need the ACK before we do the processing */
ipmip_timer_request(&ctx->ipmip6.ipmip,
proc,
&bri->retransmit,
lma->ifp->ipmip6.iff_lock,
(Ipmip_timer_func_t)ipmip6pm_lma_bri_timeout,
bri,
IP_NULL,
lma->ifp->MINDelayBRIs);
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/