1086 lines
40 KiB
C
1086 lines
40 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6ha_mag.c,v $ $Revision: 1.14 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmip6ha/src/ipmip6ha_mag.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"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 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 "ipmip6ha.h"
|
|
#include "ipmip6ha_h.h"
|
|
#include "ipmip6ha_node.h"
|
|
#include "ipmip6ha_nemo.h"
|
|
#include "ipmip6ha_attr_h.h"
|
|
#include "ipmip6ha_cli.h"
|
|
#include "ipmip6ha_ifevent.h"
|
|
#include "ipmip6ha_mh.h"
|
|
#include "ipmip6ha_icmp.h"
|
|
#include "ipmip6ha_if.h"
|
|
#include "ipmip6ha_route.h"
|
|
#include "ipmip6ha_pktbuf.h"
|
|
#include "ipmip6ha_mag.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
struct Ipmip6ha_mag_cb
|
|
{
|
|
Ipmip6ha_context_t *ctx;
|
|
Ipmip6ha_if_t *ife;
|
|
};
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC unsigned
|
|
ipmip6ha_mag_key_hash_nai(struct Ip_in6_addr *endpoint)
|
|
{
|
|
return ipcom_hash_update(endpoint, sizeof(*endpoint), 0);
|
|
}
|
|
|
|
IP_STATIC unsigned
|
|
ipmip6ha_mag_obj_hash_nai(Ipmip6ha_mag_t *mag)
|
|
{
|
|
return ipmip6ha_mag_key_hash_nai(&mag->endpoint);
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip6ha_mag_cmp_nai(Ipmip6ha_mag_t *mag, struct Ip_in6_addr *endpoint)
|
|
{
|
|
return IP_IN6_ARE_ADDR_EQUAL(&mag->endpoint, endpoint);
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_free_bri(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_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);
|
|
|
|
if (bri->match)
|
|
ipcom_free(bri->match);
|
|
/**/
|
|
ipcom_free(bri);
|
|
}
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_delete_locked(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag)
|
|
{
|
|
Ipmip6ha_br_t *bri;
|
|
|
|
IPMIP6_EVENT_IF(DEBUG, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Deleted MAG %s",
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, &mag->ifp->ipmip6.iff)));
|
|
|
|
/* Clear MAG */
|
|
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &mag->timer);
|
|
ipcom_hash_remove(mag->ifp->mag_table, mag);
|
|
|
|
while ((bri = IPCOM_LIST_FIRST(&mag->bri)) != IP_NULL)
|
|
ipmip6ha_mag_free_bri(ctx, proc, bri);
|
|
|
|
ipcom_free(mag);
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip6ha_mag_send_heartbeat_response(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ip_in6_addr *endpoint,
|
|
Ipmip6ha_if_t *ifp,
|
|
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 */
|
|
ipmip6_pkt_pktinfo_src_opt_add(pkt, &ifp->ifaddr.prefix);
|
|
|
|
/* Send */
|
|
if ((err = ipmip6_pkt_send(&ctx->ipmip6, proc, ctx->ipmip6.pkt->fd_mh, pkt, endpoint)) != 0)
|
|
{
|
|
IPCOM_LOG2(INFO,
|
|
"%s: Error sending MH HeartBeat = %x",
|
|
ctx->ipmip6.ipmip.name,
|
|
err);
|
|
return IP_FALSE;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip6ha_mag_send_heartbeat_request_locked(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag)
|
|
{
|
|
/**/
|
|
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);
|
|
mag->sequence++;
|
|
mag->unacked++;
|
|
IP_SET_HTONL(&bh->bh_seq, mag->sequence);
|
|
|
|
/**/
|
|
ipmip6ha_route_direct_temporary(ctx, proc, mag->ifp, &mag->endpoint, &mag->tunnel_endpoint, mag->tunnel_endpoint_type, mag->port);
|
|
|
|
/**/
|
|
/* Force it to go out using the CoA */
|
|
ipmip6_pkt_pktinfo_src_opt_add(pkt, &mag->ifp->ifaddr.prefix);
|
|
|
|
/* Send */
|
|
if ((err = ipmip6_pkt_send(&ctx->ipmip6, proc, ctx->ipmip6.pkt->fd_mh, pkt, &mag->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
|
|
ipmip6ha_mag_send_heartbeat_timeout_locked(int event,
|
|
Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
void *unused)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(unused);
|
|
if (event == IPMIP_TIMER_EVENT_RUN)
|
|
{
|
|
if (mag->unacked > mag->ifp->HeartBeatMissAllowed)
|
|
{
|
|
IPMIP6_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"MAG %s seems DEAD - no HeartBeat response",
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, IP_NULL)));
|
|
}
|
|
|
|
IPMIP6_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Sending HeartBeat request to %s",
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, IP_NULL)));
|
|
/**/
|
|
ipmip6ha_mag_send_heartbeat_request_locked(ctx, proc, mag);
|
|
ipmip_timer_request(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
&mag->timer,
|
|
mag->ifp->ipmip6.iff_lock,
|
|
(Ipmip_timer_func_t)ipmip6ha_mag_send_heartbeat_timeout_locked,
|
|
mag,
|
|
IP_NULL,
|
|
mag->ifp->HeartBeatInterval * 1000);
|
|
}
|
|
|
|
return IPMIP_TIMER_RET_DONE; /* do not reschedule the timeout */
|
|
}
|
|
|
|
|
|
IP_STATIC int
|
|
ipmip6ha_mag_send_heartbeat_unsolicited_locked(int event,
|
|
Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
void *unused)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(unused);
|
|
|
|
if (event == IPMIP_TIMER_EVENT_RUN)
|
|
{
|
|
ipmip6ha_route_direct_temporary(ctx, proc, mag->ifp, &mag->endpoint, &mag->tunnel_endpoint, mag->tunnel_endpoint_type, mag->port);
|
|
ipmip6ha_mag_send_heartbeat_response(ctx,
|
|
proc,
|
|
&mag->endpoint,
|
|
mag->ifp,
|
|
0,
|
|
IPMIP6_MH_HEARTBEAT_FLAG_U);
|
|
}
|
|
|
|
return IPMIP_TIMER_RET_DONE; /* do not reschedule the timeout */
|
|
}
|
|
|
|
|
|
|
|
IP_STATIC Ipmip6ha_mag_t *
|
|
ipmip6ha_mag_new_locked(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip6ha_if *ifp,
|
|
struct Ip_in6_addr *addr,
|
|
Ip_bool permanent)
|
|
{
|
|
Ipmip6ha_mag_t *mag = ipcom_calloc(1, sizeof(*mag));
|
|
|
|
ipcom_memcpy(&mag->endpoint, addr, sizeof(*addr));
|
|
|
|
mag->ifp = ifp;
|
|
mag->permanent = permanent;
|
|
|
|
ipcom_list_init(&mag->bri);
|
|
|
|
/* Clear MAG */
|
|
ipcom_hash_add(ifp->mag_table, mag);
|
|
|
|
/* */
|
|
IPMIP6_EVENT_IF(DEBUG, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Added MAG %s",
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, &ifp->ipmip6.iff)));
|
|
return mag;
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_release_locked(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag)
|
|
{
|
|
/**/
|
|
if (--mag->references == 0)
|
|
{
|
|
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &mag->timer);
|
|
if (!mag->permanent)
|
|
ipmip6ha_mag_delete_locked(ctx, proc, mag);
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_delete_cb(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
void *arg1,
|
|
void *arg2)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(arg1);
|
|
IPMIP_UNUSED_PARAMETER(arg2);
|
|
|
|
/* Delete */
|
|
ipmip6ha_mag_delete_locked(ctx, proc, mag);
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_reference_locked(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag)
|
|
{
|
|
/**/
|
|
if (mag)
|
|
{
|
|
if (++mag->references == 1 && mag->ifp->HeartBeatEnabled && IP_BIT_ISFALSE(mag->flags, IPMIP6HA_MAG_HEARTBEAT_DISABLED))
|
|
ipmip_timer_request(&ctx->ipmip6.ipmip, proc, &mag->timer, mag->ifp->ipmip6.iff_lock, (Ipmip_timer_func_t)ipmip6ha_mag_send_heartbeat_timeout_locked, mag, IP_NULL, 0);
|
|
}
|
|
}
|
|
|
|
|
|
IP_STATIC Ipmip6ha_mag_t *
|
|
ipmip6ha_mag_get_locked(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip6ha_if *ifp,
|
|
struct Ip_in6_addr *endpoint,
|
|
unsigned flags)
|
|
{
|
|
Ipmip6ha_mag_t *mag;
|
|
|
|
mag = ipcom_hash_get(ifp->mag_table, endpoint);
|
|
if (mag == IP_NULL && IP_BIT_ISSET(flags, IPMIP6HA_MAG_CREATE))
|
|
mag = ipmip6ha_mag_new_locked(ctx, proc, ifp, endpoint, IP_BIT_ISTRUE(flags, IPMIP6HA_MAG_PERMANENT));
|
|
|
|
/**/
|
|
ipmip6ha_mag_reference_locked(ctx, proc, mag);
|
|
|
|
return mag;
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_configure_foreach(struct Ipmip_proc *proc,
|
|
char *name,
|
|
char *subkey,
|
|
const char *value,
|
|
struct Ipmip6ha_mag_cb *cb)
|
|
{
|
|
struct Ip_in6_addr endpoint;
|
|
Ipmip6ha_mag_t *mag;
|
|
Ip_u32 inet_endpoint = 0;
|
|
#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
|
|
|
|
mag = ipmip6ha_mag_get_locked(cb->ctx, proc, cb->ife, &endpoint, IPMIP6HA_MAG_CREATE|IPMIP6HA_MAG_PERMANENT);
|
|
if (mag)
|
|
{
|
|
int enabled = ipmip_sysvar_cmd_str_to_key(ipmip_sysvar_bool_ops, value);
|
|
if (inet_endpoint != 0)
|
|
{
|
|
mag->tunnel_endpoint.ipv4.s_addr = inet_endpoint;
|
|
mag->tunnel_endpoint_type = IPMIP6_MIB_InetAddressType_ipv4;
|
|
}
|
|
|
|
if (enabled == 0)
|
|
IP_BIT_SET(mag->flags, IPMIP6HA_MAG_HEARTBEAT_DISABLED);
|
|
if (IP_BIT_ISFALSE(mag->flags, IPMIP6HA_MAG_HEARTBEAT_DISABLED))
|
|
{
|
|
IPMIP6_EVENT_IF(DEBUG, proc,
|
|
ipmip_log_event_add(&cb->ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Scheduling Unsolicited Heartbeat for MAG %s",
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, &cb->ife->ipmip6.iff)));
|
|
ipmip_timer_cancel(&cb->ctx->ipmip6.ipmip, proc, &mag->timer);
|
|
ipmip_timer_request(&cb->ctx->ipmip6.ipmip, proc, &mag->timer, cb->ife->ipmip6.iff_lock, (Ipmip_timer_func_t)ipmip6ha_mag_send_heartbeat_unsolicited_locked, mag, IP_NULL, 0);
|
|
}
|
|
|
|
/* Decrease this reference */
|
|
--mag->references;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_configure_dump_foreach(Ipmip6_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
Ipmip_buffer_t *buffer,
|
|
Ipmip6ha_if_t *ife)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
/**/
|
|
if (mag->permanent)
|
|
{
|
|
#ifdef IPMIP_USE_INET
|
|
if (mag->tunnel_endpoint_type == IPMIP6_MIB_InetAddressType_ipv4)
|
|
{
|
|
ipmip_cli_config_printf(buffer,
|
|
"ipmip6ha.interface.%s.LMA.MAG.%s/%s=%s",
|
|
ife->ipmip6.iff.ifname,
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, IP_NULL),
|
|
ipmip_ntop_inet(proc, mag->tunnel_endpoint.ipv4.s_addr),
|
|
IP_BIT_ISSET(mag->flags, IPMIP6HA_MAG_HEARTBEAT_DISABLED)? "disabled" : "enabled");
|
|
}
|
|
else
|
|
#endif
|
|
ipmip_cli_config_printf(buffer,
|
|
"ipmip6ha.interface.%s.LMA.MAG.%s=%s",
|
|
ife->ipmip6.iff.ifname,
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, IP_NULL),
|
|
IP_BIT_ISSET(mag->flags, IPMIP6HA_MAG_HEARTBEAT_DISABLED)? "disabled" : "enabled");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_GLOBAL Ipmip6ha_mag_t *
|
|
ipmip6ha_mag_get(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip6ha_if *ifp,
|
|
struct Ip_in6_addr *endpoint,
|
|
unsigned flags)
|
|
{
|
|
Ipmip6ha_mag_t *mag;
|
|
|
|
ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, ifp->ipmip6.iff_lock);
|
|
|
|
mag = ipmip6ha_mag_get_locked(ctx, proc, ifp, endpoint, flags);
|
|
|
|
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, ifp->ipmip6.iff_lock);
|
|
|
|
return mag;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_mag_release(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag)
|
|
{
|
|
if (mag != IP_NULL)
|
|
{
|
|
Ipmip_timer_lock_t *lock = ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, mag->ifp->ipmip6.iff_lock);
|
|
|
|
ipmip6ha_mag_release_locked(ctx, proc, mag);
|
|
|
|
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, lock);
|
|
}
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_mag_reference(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag)
|
|
{
|
|
if (mag != IP_NULL)
|
|
{
|
|
Ipmip_timer_lock_t *lock = ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, mag->ifp->ipmip6.iff_lock);
|
|
|
|
ipmip6ha_mag_reference_locked(ctx, proc, mag);
|
|
|
|
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, lock);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_mag_set_tunnel(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
union Ipmip6_mib_InetAddress *tunnel_endpoint,
|
|
Ip_u32 tunnel_endpoint_type,
|
|
Ip_u16 port)
|
|
{
|
|
/* If we have a pointer; the mag cant change endpoint under us due to reference */
|
|
if (!ipmip6_util_InetAddress_cmp(mag->tunnel_endpoint_type, &mag->tunnel_endpoint, tunnel_endpoint_type, tunnel_endpoint) || port != mag->port)
|
|
{
|
|
ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, mag->ifp->ipmip6.iff_lock);
|
|
|
|
ipcom_memcpy(&mag->tunnel_endpoint, tunnel_endpoint, sizeof(*tunnel_endpoint));
|
|
mag->tunnel_endpoint_type = tunnel_endpoint_type;
|
|
mag->port = port;
|
|
|
|
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, mag->ifp->ipmip6.iff_lock);
|
|
}
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_mag_configure(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip6ha_if *ife)
|
|
{
|
|
struct Ipmip6ha_mag_cb cb;
|
|
|
|
ife->HeartBeatInterval = ipmip_sysvar_u32(ipmip_sysvar_u32(60, "ipmip6ha.LMA.HeartBeatInterval"), "ipmip6ha.interface.%s.LMA.HeartBeatInterval", ife->ipmip6.iff.ifname);
|
|
ife->HeartBeatMissAllowed = ipmip_sysvar_u32(ipmip_sysvar_u32(3, "ipmip6ha.LMA.MissingHeartBeatsAllowed"), "ipmip6ha.interface.%s.LMA.MissingHeartBeatsAllowed", ife->ipmip6.iff.ifname);
|
|
ife->HeartBeatEnabled = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmip6ha.LMA.HeartBeatEnabled"), "ipmip6ha.interface.%s.LMA.HeartBeatEnabled", ife->ipmip6.iff.ifname);
|
|
|
|
ife->mag_table= ipcom_hash_new((Ipcom_hash_obj_func) ipmip6ha_mag_obj_hash_nai,
|
|
(Ipcom_hash_key_func) ipmip6ha_mag_key_hash_nai,
|
|
(Ipcom_hash_cmp_func) ipmip6ha_mag_cmp_nai);
|
|
|
|
cb.ctx = ctx;
|
|
cb.ife = ife;
|
|
/* Read The permanent MAG's */
|
|
ipmip_sysvar_foreach(proc,
|
|
(Ipmip_sysvar_foreach_t) ipmip6ha_mag_configure_foreach,
|
|
&cb,
|
|
"ipmip6ha.LMA.MAG.*");
|
|
|
|
ipmip_sysvar_foreach(proc,
|
|
(Ipmip_sysvar_foreach_t) ipmip6ha_mag_configure_foreach,
|
|
&cb,
|
|
"ipmip6ha.interface.%s.LMA.MAG.*", ife->ipmip6.iff.ifname);
|
|
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_mag_unconfigure(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip6ha_if *ifp)
|
|
{
|
|
if (ifp->mag_table)
|
|
{
|
|
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
ifp->mag_table,
|
|
(Ipmip_util_hash_foreach_t)ipmip6ha_mag_delete_cb,
|
|
IP_NULL,
|
|
IP_NULL);
|
|
ipcom_hash_delete(ifp->mag_table);
|
|
ifp->mag_table = IP_NULL;;
|
|
}
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_mag_configure_dump(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_if_t *ife,
|
|
Ipmip_buffer_t *buffer)
|
|
{
|
|
ipmip_cli_config_printf(buffer,
|
|
"ipmip6ha.interface.%s.LMA.HeartBeatInterval=%d",
|
|
ife->ipmip6.iff.ifname, ife->HeartBeatInterval);
|
|
|
|
ipmip_cli_config_printf(buffer,
|
|
"ipmip6ha.interface.%s.LMA.MissingHeartBeatsAllowed=%d",
|
|
ife->ipmip6.iff.ifname, ife->HeartBeatMissAllowed);
|
|
|
|
ipmip_cli_config_printf(buffer,
|
|
"ipmip6ha.interface.%s.LMA.HeartBeatEnabled=%s",
|
|
ife->ipmip6.iff.ifname, ife->HeartBeatEnabled? "enabled" : "disabled");
|
|
|
|
/* Dump permanent rules */
|
|
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
ife->mag_table,
|
|
(Ipmip_util_hash_foreach_t)ipmip6ha_mag_configure_dump_foreach,
|
|
buffer,
|
|
ife);
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_attr_get_foreach(Ipmip6_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
Ipmip_buffer_t *buffer,
|
|
Ipmip6ha_if_t *ife)
|
|
{
|
|
Ip_size_t rta = ipmip_attr_begin(buffer, IPMIP6HA_CLI_ATTR_MAG);
|
|
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
/* */
|
|
ipmip_attr_put_inet6(buffer, IPMIP6HA_CLI_ATTR_MAG_ADDR_V6, &mag->endpoint);
|
|
#ifdef IPMIP_USE_INET
|
|
ipmip_attr_put_inet(buffer, IPMIP6HA_CLI_ATTR_MAG_ADDR_V4, mag->tunnel_endpoint.ipv4.s_addr);
|
|
#endif
|
|
|
|
ipmip_attr_put_str(buffer, IPMIP6HA_CLI_ATTR_MAG_IFNAME, ife->ipmip6.iff.ifname);
|
|
ipmip_attr_put_u32(buffer, IPMIP6HA_CLI_ATTR_MAG_REFERENCES, mag->references);
|
|
ipmip_attr_put_u32(buffer, IPMIP6HA_CLI_ATTR_MAG_HEARTBEAT, (Ip_u32)IP_BIT_ISFALSE(mag->flags, IPMIP6HA_MAG_HEARTBEAT_DISABLED));
|
|
|
|
ipmip_attr_end(buffer, rta);
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip6ha_mag_attr_get(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_if_t *ife,
|
|
Ipmip_buffer_t *buffer)
|
|
{
|
|
/* Dump permanent rules */
|
|
ipmip_util_hash_foreach(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
ife->mag_table,
|
|
(Ipmip_util_hash_foreach_t)ipmip6ha_mag_attr_get_foreach,
|
|
buffer,
|
|
ife);
|
|
}
|
|
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip6ha_mag_heartbeat_restart_counter_update(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
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 = (mag->have_restart_counter && restart_counter != mag->restart_counter);
|
|
|
|
mag->restart_counter = restart_counter;
|
|
mag->have_restart_counter = IP_TRUE;
|
|
|
|
return changed;
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip6ha_mag_heartbeat_restart_counter(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
Ip_bool unsolicited,
|
|
Ipmip6_mh_mo_heartbeat_restart_counter_option_t *mo)
|
|
{
|
|
if (ipmip6ha_mag_heartbeat_restart_counter_update(ctx, proc, mag, mo) || unsolicited)
|
|
{
|
|
|
|
/* Should there be any sort of action? */
|
|
return IP_TRUE;
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipmip6ha_mag_heartbeat_input(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_pktbuf_t *pbuf)
|
|
{
|
|
if (pbuf->iff_transport.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 MAG %s -- replying with %x",
|
|
ipmip_ntop_inet6(proc, &pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr, IP_NULL),
|
|
ctx->ipmip6.restart_counter));
|
|
|
|
/* */
|
|
ipmip6ha_route_update_temporary(ctx, proc, pbuf, IP_TRUE);
|
|
ipmip6ha_mag_send_heartbeat_response(ctx,
|
|
proc,
|
|
&pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr,
|
|
pbuf->iff_transport.priv,
|
|
seq,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
/* Reply */
|
|
Ipmip6ha_mag_t *mag = ipmip6ha_mag_get(ctx, proc, pbuf->iff_transport.priv, &pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr, 0);
|
|
if (mag != 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 from MAG %s",
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, IP_NULL)));
|
|
|
|
ipmip6ha_mag_heartbeat_restart_counter(ctx, proc, mag, IP_TRUE, pbuf->ipmip6.mo.restart_option);
|
|
}
|
|
else
|
|
{
|
|
if (seq == mag->sequence)
|
|
{
|
|
mag->unacked = 0;
|
|
|
|
if (ipmip6ha_mag_heartbeat_restart_counter(ctx, proc, mag, 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 MAG %s",
|
|
mag->restart_counter,
|
|
ipmip_ntop_inet6(proc, &mag->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 MAG %s",
|
|
mag->restart_counter,
|
|
ipmip_ntop_inet6(proc, &mag->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 MAG %s",
|
|
mag->restart_counter,
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, IP_NULL)));
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IPMIP6_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"SOLICITED OUT-OF-SEQUENCE HeartBeat Response from MAG %s",
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, IP_NULL)));
|
|
}
|
|
}
|
|
ipmip6ha_mag_release(ctx, proc, mag);
|
|
}
|
|
else
|
|
{
|
|
IPMIP6_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"SOLICITED HeartBeat Response from unknown MAG %s",
|
|
ipmip_ntop_inet6(proc, &pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr, IP_NULL)));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/**/
|
|
ipmip6ha_route_update_temporary(ctx, proc, pbuf, IP_TRUE);
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/* */
|
|
ipmip_pktbuf_free(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip);
|
|
return IP_TRUE;
|
|
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipmip6ha_mag_binding_error_input(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_pktbuf_t *pbuf,
|
|
Ipmip6ha_mag_t *mag)
|
|
{
|
|
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)
|
|
{
|
|
/* */
|
|
if ((mag->flags & (IPMIP6HA_MAG_HEARTBEAT_SEEN|IPMIP6HA_MAG_HEARTBEAT_DISABLED)) == 0 && mag->unacked != 0)
|
|
{
|
|
IPMIP6_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
"Binding Error received from MAG %s, HeartBeat disabled",
|
|
ipmip_ntop_inet6(proc, &mag->endpoint, IP_NULL)));
|
|
IP_BIT_SET(mag->flags, IPMIP6HA_MAG_HEARTBEAT_DISABLED);
|
|
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &mag->timer);
|
|
}
|
|
}
|
|
|
|
/* */
|
|
ipmip_pktbuf_free(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip);
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmip6ha_mag_revoke_node(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_node_t *node,
|
|
Ipmip6ha_br_t *bri,
|
|
void *unused)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(unused);
|
|
|
|
if (IPMIP6_MH_BU_IS_P(node->regflags))
|
|
{
|
|
Ipmip6ha_node_P_t *pnode = (Ipmip6ha_node_P_t *)node;
|
|
|
|
if (pnode->mag == bri->mag)
|
|
{
|
|
Ipmip6_mh_mo_nai_t *nai = (Ipmip6_mh_mo_nai_t *)node->nai_mn;
|
|
|
|
/* Does the NAI match? */
|
|
if (bri->match == IP_NULL || ipmip_util_strnnmatch(bri->match, bri->match_len, (char *)&nai->nai[0], (Ip_size_t) (nai->hdr.len - 1)))
|
|
{
|
|
/* REVOKE */
|
|
ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &node->revocation);
|
|
ipmip_timer_request(&ctx->ipmip6.ipmip,
|
|
proc,
|
|
&node->revocation,
|
|
node->lock,
|
|
(Ipmip_timer_func_t)ipmip6ha_node_timeout,
|
|
node,
|
|
"global revocation acknowledged",
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IP_STATIC int
|
|
ipmip6ha_mag_bri_timeout(int event,
|
|
Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_br_t *bri,
|
|
void *extarg)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(extarg);
|
|
if (event == IPMIP_TIMER_EVENT_RUN)
|
|
{
|
|
if (++bri->xmits > bri->mag->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)ipmip6ha_mag_revoke_node,
|
|
bri,
|
|
IP_NULL);
|
|
ipmip_context_id_unlock(ctx->idents);
|
|
|
|
/**/
|
|
ipmip6ha_mag_free_bri(ctx, proc, bri);
|
|
}
|
|
else
|
|
{
|
|
/* Retransmit */
|
|
ipmip6ha_mh_bri_send(ctx, proc, IP_NULL, bri);
|
|
return IPMIP_TIMER_RET_REINSERT;
|
|
}
|
|
}
|
|
|
|
return IPMIP_TIMER_RET_DONE;
|
|
}
|
|
|
|
|
|
IP_STATIC int
|
|
ipmip6ha_mag_bri_reply_locked(int event,
|
|
Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_br_t *bri,
|
|
Ipmip6ha_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)ipmip6ha_mag_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,
|
|
"MAG %s unable to revoke, due to error %s",
|
|
ipmip_ntop_inet6(proc, &bri->mag->endpoint, IP_NULL),
|
|
ipmip6_mh_bra_error_str(bra->bra_status)));
|
|
}
|
|
}
|
|
|
|
/**/
|
|
ipmip6ha_mag_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
|
|
ipmip6ha_mag_revoke(Ipmip6ha_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip6ha_mag_t *mag,
|
|
Ip_u8 reason,
|
|
const char *match)
|
|
{
|
|
Ipmip6ha_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 = (Ip_u8) (reason? reason : (match? IPMIP6_MH_BRI_TRIGGER_REVOKING_NODE_LOCAL_POLICY : IPMIP6_MH_BRI_TRIGGER_PER_PEER_POLICY));
|
|
bri->xmits = 0;
|
|
bri->lock = mag->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)ipmip6ha_mag_bri_reply_locked;
|
|
bri->mag = mag;
|
|
bri->flags |= IPMIP6_MH_BRI_FLAG_P;
|
|
|
|
/**/
|
|
if (match)
|
|
{
|
|
bri->match = ipcom_strdup(match);
|
|
bri->match_len = ipcom_strlen(bri->match);
|
|
}
|
|
|
|
ipcom_list_insert_last(&mag->bri, &bri->next);
|
|
ipmip6ha_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,
|
|
mag->ifp->ipmip6.iff_lock,
|
|
(Ipmip_timer_func_t)ipmip6ha_mag_bri_timeout,
|
|
bri,
|
|
IP_NULL,
|
|
mag->ifp->MINDelayBRIs);
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|