1089 lines
34 KiB
C
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
|
|
****************************************************************************
|
|
*/
|