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

1089 lines
34 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6_ipsec.c,v $ $Revision: 1.8.16.1 $
* $Source: /home/interpeak/CVSRoot/ipmip6/src/ipmip6_ipsec.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 "ipmip6_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_os.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_inet.h>
#include <ipcom_list.h>
#include <ipcom_err.h>
#include <ipcom_syslog.h>
#include <ipcom_sysvar.h>
#include <ipmip.h>
#include <private/ipmip_sysvar.h>
#include "ipmip6_h.h"
#include <private/ipmip6_context.h>
#include <private/ipmip6_pkt.h>
#include <private/ipmip6_ipsec.h>
#include <private/ipmip6_util.h>
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmip6_ipsec_key_parse
*===========================================================================
* Description: Parse a key based on the string description.
* Parameters: context - The context
* key - Where to store the key.
* kstr - The string description
* Returns: IP_TRUE if successful.
*
*/
IP_STATIC Ip_bool
ipmip6_ipsec_key_parse(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6_ipsec_key_t *key,
char *kstr)
{
Ip_u32 len;
IPMIP_UNUSED_PARAMETER(proc);
if (ipcom_strncasecmp(kstr, "0x", 2) == 0)
{
Ip_u32 i;
/* Skip the '0x' */
kstr += 2;
/* Each two bytes are a hex value */
len = ipcom_strlen(kstr);
len >>= 1;
/* Create key */
key->iik_key = ipcom_malloc(len);
key->iik_key_len = len;
if (key->iik_key == IP_NULL)
{
IPCOM_LOG1(CRIT,
"%s: IPSEC Failed to allocate memory for SA Key",
ctx->ipmip.name);
return IP_FALSE;
}
for (i = 0; i < len; i++)
{
unsigned int value;
char buf[3];
/* Copy the first two bytes */
ipcom_strncpy(buf, kstr, sizeof(buf));
/* Parse them */
value = ipcom_strtoul(buf, IP_NULL, 16);
/* Store the value */
key->iik_key[i] = (Ip_u8) value;
/* Read next two */
kstr += 2;
}
}
else
{
/* Calculate the length */
len = ipcom_strlen(kstr);
/* */
key->iik_key = (Ip_u8 *)ipcom_strdup(kstr);
key->iik_key_len = len;
if (key->iik_key == IP_NULL)
{
IPCOM_LOG1(CRIT,
"%s: IPSEC Failed to allocate memory for SA Key",
ctx->ipmip.name);
return IP_FALSE;
}
}
return IP_TRUE;
}
/*
*===========================================================================
* ipmip6_ipsec_find_spi
*===========================================================================
* Description: Locate a specific SA based on SPI
* Parameters: sa - The SA
* spi - The SPI to look for.
* Returns:
*
*/
IP_STATIC Ipmip6_ipsec_sa_t *
ipmip6_ipsec_find_spi(Ipcom_list *sas, Ip_u32 spi)
{
Ipmip6_ipsec_sa_t *sa;
for (sa = IPCOM_LIST_FIRST(sas); sa != IP_NULL; sa = IPCOM_LIST_NEXT(&sa->iis_next))
if (sa->iis_spi == spi)
return sa;
/* Do they match? */
return IP_NULL;
}
/*
*===========================================================================
* ipmip6_ipsec_move_flow_dst
*===========================================================================
* Description: Move the the peer destination endpoint in the flow
* Parameters: flow - The flow
* peer - The peer
* Returns: IP_TRUE
*
*/
IP_STATIC Ip_bool
ipmip6_ipsec_move_flow_dst(Ipmip6_ipsec_flow_t *flow,
struct Ip_in6_addr *peer)
{
ipcom_memcpy(&flow->iif_dst, peer, sizeof(*peer));
ipcom_memcpy(&flow->iif_dst_mask, &ipmip6_in6addr_allmask, sizeof(ipmip6_in6addr_allmask));
return IP_TRUE;
}
/*
*===========================================================================
* ipmip6_ipsec_move_flow_src
*===========================================================================
* Description: Move the the peer source endpoint in the flow
* Parameters: flow - The flow
* peer - The peer
* Returns: IP_TRUE
*
*/
IP_STATIC Ip_bool
ipmip6_ipsec_move_flow_src(Ipmip6_ipsec_flow_t *flow,
struct Ip_in6_addr *peer)
{
ipcom_memcpy(&flow->iif_src, peer, sizeof(*peer));
ipcom_memcpy(&flow->iif_src_mask, &ipmip6_in6addr_allmask, sizeof(ipmip6_in6addr_allmask));
return IP_TRUE;
}
/*
*===========================================================================
* ipmip6_ipsec_free
*===========================================================================
* Description: Delete all memory associated with a SA
* Parameters: sa - The SA
* Returns:
*
*/
IP_STATIC void
ipmip6_ipsec_free(Ipmip6_ipsec_sa_t *sa)
{
if (sa->iis_auth.iik_mode != IP_NULL)
ipcom_free(sa->iis_auth.iik_mode);
if (sa->iis_auth.iik_key != IP_NULL)
ipcom_free(sa->iis_auth.iik_key);
if (sa->iis_enc.iik_mode != IP_NULL)
ipcom_free(sa->iis_enc.iik_mode);
if (sa->iis_enc.iik_key != IP_NULL)
ipcom_free(sa->iis_enc.iik_key);
ipcom_free(sa);
}
/*
*===========================================================================
* ipmip6_ipsec_reference
*===========================================================================
* Description: Increase the reference count for the SA.
* Parameters: sa - The SA.
* Returns:
*
*/
IP_STATIC void
ipmip6_ipsec_reference(Ipmip6_ipsec_sa_t *sa,
Ipmip6_ipsec_flow_t *flow)
{
/* Insert the flow */
ipcom_list_insert_first(&sa->iis_flows, &flow->iif_next);
++sa->iis_references;
}
/*
*===========================================================================
* ipmip6_ipsec_dereference
*===========================================================================
* Description: Decrease the reference count for the SA. Deletes the SA
* if it reaches zero.
* Parameters: sa - The SA.
* Returns:
*
*/
IP_STATIC void
ipmip6_ipsec_dereference(Ipmip6_ipsec_sa_t *sa,
Ipmip6_ipsec_flow_t *flow)
{
/* Remove the flow from the linked list */
ipcom_list_remove(&flow->iif_next);
--sa->iis_references;
}
/*
*===========================================================================
* ipmip6_ipsec_install
*===========================================================================
* Description: Installs a SA if required.
* Parameters: sa - The SA to install.
* Returns: IP_TRUE if successful.
*
*/
IP_STATIC Ip_bool
ipmip6_ipsec_install(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6_ipsec_sa_t *sa)
{
if (sa->iis_installed == 0)
{
/* Not yet installed */
if (ipmip6_port_ipsec_install(ctx, proc, sa) == IP_FALSE)
return IP_FALSE;
}
/* Increase the installed count */
sa->iis_installed++;
/* Already installed */
return IP_TRUE;
}
/*
*===========================================================================
* ipmip6_ipsec_uninstall
*===========================================================================
* Description: Uninstalls a SA if there are no more installed references.
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipmip6_ipsec_uninstall(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6_ipsec_sa_t *sa)
{
/* Is it installed at all? */
if (sa->iis_installed > 0)
{
/* Was this the last reference? */
if (--sa->iis_installed == 0)
{
/* Apparently, remove it */
ipmip6_port_ipsec_uninstall(ctx, proc, sa);
}
}
}
/*
*===========================================================================
* ipmip6_ipsec_uninstall_flow
*===========================================================================
* Description: Uninstall a flow.
* Parameters: flow - The flow to uninstall.
* Returns:
*
*/
IP_STATIC void
ipmip6_ipsec_uninstall_flow(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6_ipsec_flow_t *flow)
{
/* Is it installed? */
if (flow->iif_installed)
{
/* Do a port removal of this flow */
ipmip6_port_ipsec_uninstall_flow(ctx, proc, flow);
/* Mark it as uninstalled */
flow->iif_installed = IP_FALSE;
/* Uninstall the SA */
ipmip6_ipsec_uninstall(ctx, proc, flow->iif_sa);
}
}
/*
*===========================================================================
* ipmip6_ipsec_install_flow
*===========================================================================
* Description: Install a flow.
* Parameters: flow - The flow to install.
* Returns:
*
*/
IP_STATIC Ip_bool
ipmip6_ipsec_install_flow(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6_ipsec_flow_t *flow)
{
/* Is it installed? */
if (flow->iif_sa != IP_NULL && flow->iif_installed == IP_FALSE)
{
/* Install the SA */
if (ipmip6_ipsec_install(ctx, proc, flow->iif_sa))
{
/* Do a port removal of this flow */
if (ipmip6_port_ipsec_install_flow(ctx, proc, flow))
{
/* Mark it as uninstalled */
flow->iif_installed = IP_TRUE;
return IP_TRUE;
}
/* Failed to install the flow, deinstall the SA */
ipmip6_ipsec_uninstall(ctx, proc, flow->iif_sa);
}
}
/* No go */
return IP_FALSE;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmip6_ipsec_setup_flow
*===========================================================================
* Description: Setup a flow
* Parameters: flow - The flow to setup.
* spi - The spi number.
* direction - IPMIP6_IPSEC_SA_DIR_IN or IPMIP6_IPSEC_SA_DIR_OUT
* endpoint - IPMIP6_IPSEC_SA_ENDPOINT_MOVEABLE or
* IPMIP6_IPSEC_SA_ENDPOINT_STATIC
* protocol - The protocol
* mode - IPMIP6_IPSEC_SA_MODE_TRANSPORT or
* IPMIP6_IPSEC_SA_MODE_TUNNEL
* dst - Destination address
* dst_mask - Destination mask
* src - Source address
* src_mask - Source mask
* ife - Interface pointer.
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_setup_flow(Ipmip6_ipsec_flow_t *flow,
Ip_u32 spi,
Ip_u8 direction,
Ip_u8 endpoint,
Ip_u8 protocol,
Ip_u8 mode,
const struct Ip_in6_addr *dst,
const struct Ip_in6_addr *dst_mask,
const struct Ip_in6_addr *src,
const struct Ip_in6_addr *src_mask,
struct Ipmip6_if *ife)
{
/* Set base information */
flow->iif_spi = spi;
flow->iif_dir = direction;
flow->iif_endpoint = endpoint;
flow->iif_protocol = protocol;
flow->iif_mode = mode;
/* Store the addresses */
if (dst)
ipcom_memcpy(&flow->iif_dst, dst, sizeof(struct Ip_in6_addr));
if (dst_mask)
ipcom_memcpy(&flow->iif_dst_mask, dst_mask, sizeof(struct Ip_in6_addr));
if (src)
ipcom_memcpy(&flow->iif_src, src, sizeof(struct Ip_in6_addr));
if (src_mask)
ipcom_memcpy(&flow->iif_src_mask, src_mask, sizeof(struct Ip_in6_addr));
/* Store the interface */
flow->iif_if = ife;
}
/*
*===========================================================================
* ipmip6_ipsec_load_sa
*===========================================================================
* Description: Load an SA and store it into the specified list.
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_bool
ipmip6_ipsec_load_sa(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas,
Ip_u32 spi,
const char *product,
const char *configuration,
const char *feature)
{
Ipmip6_ipsec_sa_t *sa;
/* Try locate it among the already existing */
if (ipmip6_ipsec_find_spi(sas, spi) == IP_NULL)
{
static Ipmip_sysvar_key_map_t transport[] =
{
{ IPMIP6_IPSEC_SA_PROTOCOL_ESP, "esp" },
{ IPMIP6_IPSEC_SA_PROTOCOL_AH, "ah" },
{ 0, 0 }
};
int i;
char *ikey;
/* Allocate new SA */
sa = ipcom_calloc(1, sizeof(*sa));
if (sa == IP_NULL)
{
IPCOM_LOG1(CRIT,
"%s: IPSEC Failed to allocate memory for SA",
ctx->ipmip);
return IP_FALSE;
}
/* Init the flow list */
ipcom_list_init(&sa->iis_flows);
/* Store the SPI value */
sa->iis_spi = spi;
if ((i = ipmip_sysvar_key(-1, transport, "%s.%s.%s.%u.transport", product, configuration, feature, spi)) != -1 ||
(i = ipmip_sysvar_key(-1, transport, "%s.%s.%s.transport", product, configuration, feature)) != -1)
sa->iis_protocol = (Ip_u8)i;
/* Create the Auth algorithm key */
if ((ikey = ipmip_sysvar("%s.%s.%s.%u.authmode", product, configuration, feature, spi)) == IP_NULL &&
(ikey = ipmip_sysvar("%s.%s.%s.authmode", product, configuration, feature)) == IP_NULL)
{
IPCOM_LOG2(CRIT,
"%s: IPSEC missing/invalid 'authalg' for SPI=%u",
ctx->ipmip.name, spi);
goto failed;
}
/* Save the key */
sa->iis_auth.iik_mode = ikey;
/* Create the Auth algorithm key */
if ((ikey = ipmip_sysvar("%s.%s.%s.%u.authkey", product, configuration, feature, spi)) == IP_NULL &&
(ikey = ipmip_sysvar("%s.%s.%s.authkey", product, configuration, feature)) == IP_NULL)
{
IPCOM_LOG2(CRIT,
"%s: IPSEC missing/invalid 'authkey' for SPI=%u",
ctx->ipmip.name, spi);
goto failed;
}
/* Parse the key */
if (ipmip6_ipsec_key_parse(ctx, proc, &sa->iis_auth, ikey) == IP_FALSE)
{
ipcom_free(ikey);
goto failed;
}
ipcom_free(ikey);
/* Create the Enc algorithm key */
if ((ikey = ipmip_sysvar("%s.%s.%s.%u.encmode", product, configuration, feature, spi)) == IP_NULL &&
(ikey = ipmip_sysvar("%s.%s.%s.encmode", product, configuration, feature)) == IP_NULL)
{
IPCOM_LOG2(CRIT,
"%s: IPSEC missing/invalid 'encalg' for SPI=%u",
ctx->ipmip.name, spi);
goto failed;
}
sa->iis_enc.iik_mode = ikey;
/* Create the Auth algorithm key */
if ((ikey = ipmip_sysvar("%s.%s.%s.%u.enckey", product, configuration, feature, spi)) == IP_NULL &&
(ikey = ipmip_sysvar("%s.%s.%s.enckey", product, configuration, feature)) == IP_NULL)
{
IPCOM_LOG2(CRIT,
"%s: IPSEC missing/invalid 'enckey' for SPI=%u",
ctx->ipmip.name, spi);
goto failed;
}
/* Parse the key */
if (ipmip6_ipsec_key_parse(ctx, proc, &sa->iis_enc, ikey) == IP_FALSE)
{
ipcom_free(ikey);
goto failed;
}
ipcom_free(ikey);
/* We've built ourselves a SA */
ipcom_list_insert_first(sas, &sa->iis_next);
}
return IP_TRUE;
failed:
/* Failed to create the SA */
ipmip6_ipsec_free(sa);
return IP_FALSE;
}
/*
*===========================================================================
* ipmip6_ipsec_attach_flow
*===========================================================================
* Description: Reads the ipsec parameters from the sysvar interface
* based on a given mask.
* Parameters: sas - SA list
* flow - The flow key to configure.
* Returns:
*
*/
IP_GLOBAL Ip_bool
ipmip6_ipsec_attach_flow(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas,
Ipmip6_ipsec_flow_t *flow)
{
Ipmip6_ipsec_sa_t *sa;
IPMIP_UNUSED_PARAMETER(proc);
/* Try locate it among the already existing */
if ((sa = ipmip6_ipsec_find_spi(sas, flow->iif_spi)) == IP_NULL)
return IP_FALSE;
/* Store the SA */
flow->iif_sa = sa;
ipmip6_ipsec_reference(sa, flow);
/* Direction mismatch? */
if (sa->iis_dir != flow->iif_dir)
{
/* Mark it, if unspecified */
if (sa->iis_dir == 0)
{
/* Mark it with the same direction as the flow */
sa->iis_dir = flow->iif_dir;
}
else
{
IPCOM_LOG4(CRIT,
"%s: IPSEC %s flow cannot attach to %s SA [SPI=%u]",
ctx->ipmip.name,
flow->iif_dir == IPMIP6_IPSEC_SA_DIR_IN? "inbound" : "outbound",
sa->iis_dir == IPMIP6_IPSEC_SA_DIR_IN? "inbound" : "outbound",
flow->iif_spi);
ipmip6_ipsec_dereference(sa, flow);
return IP_FALSE;
}
}
/* Moveable? */
if (sa->iis_endpoint != flow->iif_endpoint)
{
/* Current definition */
if (sa->iis_endpoint == 0)
{
/* Mark it with the same moveability as the flow */
sa->iis_endpoint = flow->iif_endpoint;
}
else
{
IPCOM_LOG4(CRIT,
"%s: IPSEC %s flow cannot attach to %s SA [SPI=%u]",
ctx->ipmip.name,
flow->iif_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_MOVEABLE? "moveable" : "static",
sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_MOVEABLE? "moveable" : "static",
flow->iif_spi);
ipmip6_ipsec_dereference(sa, flow);
return IP_FALSE;
}
}
/* Verify that mode is correct */
if (sa->iis_mode != flow->iif_mode)
{
if (sa->iis_mode == 0)
{
/* Mark it with the same mode as the flow */
sa->iis_mode = flow->iif_mode;
}
else
{
IPCOM_LOG4(CRIT,
"%s: IPSEC %s mode flow cannot attach to %s mode SA [SPI=%u]",
ctx->ipmip.name,
flow->iif_mode == IPMIP6_IPSEC_SA_MODE_TRANSPORT? "transport" : "tunnel",
sa->iis_mode == IPMIP6_IPSEC_SA_MODE_TRANSPORT? "transport" : "tunnel",
flow->iif_spi);
ipmip6_ipsec_dereference(sa, flow);
return IP_FALSE;
}
}
/* Works */
return IP_TRUE;
}
/*
*===========================================================================
* ipmip6_ipsec_detach_flow
*===========================================================================
* Description: Detach a flow.
* Parameters: flow - The flow
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_detach_flow(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6_ipsec_flow_t *flow)
{
if (flow->iif_sa != IP_NULL)
{
/* Uninstall the flow */
ipmip6_ipsec_uninstall_flow(ctx, proc, flow);
/* Dereference the SA */
ipmip6_ipsec_dereference(flow->iif_sa, flow);
}
}
/*
*===========================================================================
* ipmip6_ipsec_move_sa_coa
*===========================================================================
* Description: Move the endpoint of all moveable SA's
* Parameters: sa - The list of SA's
* coa - The new CoA.
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_move_sa_coa(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas,
struct Ip_in6_addr *coa)
{
Ipmip6_ipsec_sa_t *sa, *nsa;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
/* Go through the list */
for (sa = IPCOM_LIST_FIRST(sas); sa != IP_NULL; sa = nsa)
{
nsa = IPCOM_LIST_NEXT(&sa->iis_next);
/* Only touch moveable endpoints */
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_MOVEABLE)
{
/* Depending on direction */
if (sa->iis_dir == IPMIP6_IPSEC_SA_DIR_IN)
{
/* Inbound SA. The destination is the COA */
ipcom_memcpy(&sa->iis_dst, coa, sizeof(*coa));
}
else if (sa->iis_dir == IPMIP6_IPSEC_SA_DIR_OUT)
{
/* Outbound SA. The source is the COA */
ipcom_memcpy(&sa->iis_src, coa, sizeof(*coa));
}
}
}
}
/*
*===========================================================================
* ipmip6_ipsec_move_sa_peer
*===========================================================================
* Description: Move the peer endpoint of all SA's
* Parameters: sa - The list of SA's
* peer - The new peer.
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_move_sa_peer(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas,
struct Ip_in6_addr *peer)
{
Ipmip6_ipsec_sa_t *sa, *nsa;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
/* Go through the list */
for (sa = IPCOM_LIST_FIRST(sas); sa != IP_NULL; sa = nsa)
{
Ipmip6_ipsec_flow_t *flow, *nflow;
nsa = IPCOM_LIST_NEXT(&sa->iis_next);
/* Depending on direction */
if (sa->iis_dir == IPMIP6_IPSEC_SA_DIR_IN)
{
/* Inbound SA. The source is the peer */
ipcom_memcpy(&sa->iis_src, peer, sizeof(*peer));
/* Repoint static flows */
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_STATIC)
{
/* Inbound, set flow destination */
for (flow = IPCOM_LIST_FIRST(&sa->iis_flows); flow != IP_NULL; flow = nflow)
{
nflow = IPCOM_LIST_NEXT(&flow->iif_next);
ipmip6_ipsec_move_flow_src(flow, peer);
}
}
}
else if (sa->iis_dir == IPMIP6_IPSEC_SA_DIR_OUT)
{
/* Outbound SA. destination is the peer */
ipcom_memcpy(&sa->iis_dst, peer, sizeof(*peer));
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_STATIC)
{
/* Inbound, set flow destination */
for (flow = IPCOM_LIST_FIRST(&sa->iis_flows); flow != IP_NULL; flow = nflow)
{
nflow = IPCOM_LIST_NEXT(&flow->iif_next);
ipmip6_ipsec_move_flow_dst(flow, peer);
}
}
}
}
}
/*
*===========================================================================
* ipmip6_ipsec_move_sa_home
*===========================================================================
* Description: Move the home endpoint of all SA's
* Parameters: sa - The list of SA's
* home - The new home.
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_move_sa_home(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas,
struct Ip_in6_addr *home)
{
Ipmip6_ipsec_sa_t *sa, *nsa;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
/* Go through the list */
for (sa = IPCOM_LIST_FIRST(sas); sa != IP_NULL; sa = nsa)
{
Ipmip6_ipsec_flow_t *flow, *nflow;
nsa = IPCOM_LIST_NEXT(&sa->iis_next);
/* Depending on direction */
if (sa->iis_dir == IPMIP6_IPSEC_SA_DIR_IN)
{
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_STATIC)
{
/* Inbound SA. The destination is home if it's static */
ipcom_memcpy(&sa->iis_dst, home, sizeof(*home));
}
/* Inbound, set flow destination */
for (flow = IPCOM_LIST_FIRST(&sa->iis_flows); flow != IP_NULL; flow = nflow)
{
nflow = IPCOM_LIST_NEXT(&flow->iif_next);
ipmip6_ipsec_move_flow_dst(flow, home);
}
}
else if (sa->iis_dir == IPMIP6_IPSEC_SA_DIR_OUT)
{
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_STATIC)
{
/* Outbound SA. The source should be home if it's static */
ipcom_memcpy(&sa->iis_src, home, sizeof(*home));
}
/* Outbound, set flow source */
for (flow = IPCOM_LIST_FIRST(&sa->iis_flows); flow != IP_NULL; flow = nflow)
{
nflow = IPCOM_LIST_NEXT(&flow->iif_next);
ipmip6_ipsec_move_flow_src(flow, home);
}
}
}
}
/*
*===========================================================================
* ipmip6_ipsec_install_sa_moveable
*===========================================================================
* Description: Installs all moveable SA's and their attached flows.
* Parameters: sas - The list of SA's
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_install_sa_moveable(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas)
{
Ipmip6_ipsec_sa_t *sa, *nsa;
for (sa = IPCOM_LIST_FIRST(sas); sa != IP_NULL; sa = nsa)
{
nsa = IPCOM_LIST_NEXT(&sa->iis_next);
/* Only touch moveable endpoints */
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_MOVEABLE)
{
Ipmip6_ipsec_flow_t *flow, *nflow;
for (flow = IPCOM_LIST_FIRST(&sa->iis_flows); flow != IP_NULL; flow = nflow)
{
nflow = IPCOM_LIST_NEXT(&flow->iif_next);
ipmip6_ipsec_install_flow(ctx, proc, flow);
}
}
}
}
/*
*===========================================================================
* ipmip6_ipsec_uninstall_sa_moveable
*===========================================================================
* Description: Uninnstalls all moveable SA's and their attached flows.
* Parameters: sas - The list of SA's
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_uninstall_sa_moveable(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas)
{
Ipmip6_ipsec_sa_t *sa, *nsa;
for (sa = IPCOM_LIST_FIRST(sas); sa != IP_NULL; sa = nsa)
{
nsa = IPCOM_LIST_NEXT(&sa->iis_next);
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_MOVEABLE)
{
Ipmip6_ipsec_flow_t *flow, *nflow;
for (flow = IPCOM_LIST_FIRST(&sa->iis_flows); flow != IP_NULL; flow = nflow)
{
nflow = IPCOM_LIST_NEXT(&flow->iif_next);
ipmip6_ipsec_uninstall_flow(ctx, proc, flow);
}
}
}
}
/*
*===========================================================================
* ipmip6_ipsec_install_sa_static
*===========================================================================
* Description: Installs all static SA's and their attached flows.
* Parameters: sas - The list of SA's
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_install_sa_static(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas)
{
Ipmip6_ipsec_sa_t *sa, *nsa;
for (sa = IPCOM_LIST_FIRST(sas); sa != IP_NULL; sa = nsa)
{
nsa = IPCOM_LIST_NEXT(&sa->iis_next);
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_STATIC)
{
Ipmip6_ipsec_flow_t *flow, *nflow;
for (flow = IPCOM_LIST_FIRST(&sa->iis_flows); flow != IP_NULL; flow = nflow)
{
nflow = IPCOM_LIST_NEXT(&flow->iif_next);
ipmip6_ipsec_install_flow(ctx, proc, flow);
}
}
}
}
/*
*===========================================================================
* ipmip6_ipsec_delete_sa
*===========================================================================
* Description: Delete all SAS in a specified list.
* Parameters: sas - The list.
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_delete_sa(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas)
{
Ipmip6_ipsec_sa_t *sa;
/* Make certain it's all uninstalled */
ipmip6_ipsec_uninstall_sa_moveable(ctx, proc, sas);
ipmip6_ipsec_uninstall_sa_static(ctx, proc, sas);
/* Remove all SAS */
while ((sa = IPCOM_LIST_FIRST(sas)) != IP_NULL)
{
/* Remove STATIC endpoints */
ipmip6_ipsec_uninstall(ctx, proc, sa);
/* Go */
ipcom_list_remove(&sa->iis_next);
ipmip6_ipsec_free(sa);
}
}
/*
*===========================================================================
* ipmip6_ipsec_uninstall_sa_static
*===========================================================================
* Description: Uninstalls all static SA's and their attached flows.
* Parameters: sas - The list of SA's
* Returns:
*
*/
IP_GLOBAL void
ipmip6_ipsec_uninstall_sa_static(Ipmip6_context_t *ctx,
Ipmip_proc_t *proc,
Ipcom_list *sas)
{
Ipmip6_ipsec_sa_t *sa, *nsa;
for (sa = IPCOM_LIST_FIRST(sas); sa != IP_NULL; sa = nsa)
{
nsa = IPCOM_LIST_NEXT(&sa->iis_next);
if (sa->iis_endpoint == IPMIP6_IPSEC_SA_ENDPOINT_STATIC)
{
Ipmip6_ipsec_flow_t *flow, *nflow;
for (flow = IPCOM_LIST_FIRST(&sa->iis_flows); flow != IP_NULL; flow = nflow)
{
nflow = IPCOM_LIST_NEXT(&flow->iif_next);
ipmip6_ipsec_uninstall_flow(ctx, proc, flow);
}
}
}
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/