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

1266 lines
36 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipipsec_ctrl.c,v $ $Revision: 1.53.2.6 $
* $Source: /home/interpeak/CVSRoot/ipipsec2/src/ipipsec_ctrl.c,v $
* $Author: jren $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Lennart Bang <lob@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipipsec_config.h"
/* Define to support full ctrl api (deprecated, replaced by ioctls)
#define IPIPSEC_USE_FULL_CTRL_API
*/
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_type.h>
#include <ipcom_time.h>
#include <ipcom_cstyle.h>
#include <ipcom_clib.h>
#include <ipcom_inet.h>
#include <ipcom_err.h>
#include <ipcom_os.h>
#include <ipcom_sysvar.h>
#include <ipcom_syslog.h>
#include "ipipsec_h.h"
#include "ipipsec_pfkeyv2.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPIPSEC_LEAVE(xerrval) do { retval = xerrval; goto leave; } while(0)
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
#ifndef IP_PORT_LAS
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
IP_EXTERN Ipipsec_data ipipsec;
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC int
ipipsec_get_sadir(Ipipsec_sa *sa);
IP_STATIC Ipipsec_sa *
ipipsec_sa_lex_get(Ipipsec_sa_handle *sah, Ipipsec_sa_handle *sah_next);
/*IP_STATIC Ipipsec_flow *ipipsec_flow_lex_get(Ip_u32 id);*/
IP_STATIC Ipipsec_flow *ipipsec_flow_sort_get(Ip_u32 id);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipipsec_sa_to_handle
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipipsec_sa_to_handle(Ipipsec_sa *sa, Ipipsec_sa_handle *handle)
{
ip_assert(sa != IP_NULL);
ipcom_memset(handle, 0, sizeof(Ipipsec_sa_handle));
ipcom_memcpy(&handle->dst, &sa->key.dst, sa->in_addr_size);
ipcom_memcpy(&handle->src, &sa->key.src, sa->in_addr_size);
handle->spi_n = sa->key.ports.espah_spi_n;
handle->protocol = IPIPSEC_SADB_GET_PROTO(sa->sadb_msg_satype);
handle->direction = sa->key.direction;
handle->domain = sa->key.domain;
handle->satype = sa->sadb_msg_satype;
handle->priority = sa->key.priority;
handle->dscp = sa->key.dscp;
}
/*
*===========================================================================
* ipipsec_handle_to_key
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipipsec_handle_to_key(Ipipsec_sa_handle *sah, Ipipsec_key *key)
{
ipcom_memset(key, 0, sizeof(Ipipsec_key));
ipcom_memcpy(&key->dst, &sah->dst, sah->domain == IP_AF_INET ? 4 : 16);
ipcom_memcpy(&key->src, &sah->src, sah->domain == IP_AF_INET ? 4 : 16);
key->ports.espah_spi_n = sah->spi_n;
key->proto = sah->protocol;
key->direction = sah->direction;
key->domain = sah->domain;
/* satype */
key->priority = sah->priority;
key->dscp = sah->dscp;
}
/*
*===========================================================================
* ipipsec_sa_get_dir
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipipsec_get_sadir(Ipipsec_sa *sa)
{
if (sa->bytes[IPIPSEC_DIR_IN] || sa->packets[IPIPSEC_DIR_IN])
return IPIPSEC_SADIR_INPUT;
if (sa->bytes[IPIPSEC_DIR_OUT] || sa->packets[IPIPSEC_DIR_OUT])
return IPIPSEC_SADIR_OUTPUT;
return IPIPSEC_SADIR_ANY;
}
/*
*===========================================================================
* ipipsec_sa_lex_get
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipipsec_sa *
ipipsec_sa_lex_get(Ipipsec_sa_handle *sah, Ipipsec_sa_handle *sah_next)
{
Ipipsec_sa *cur, *sa;
int domain_index;
if (sah->spi_n)
{
Ipipsec_key key;
ipipsec_handle_to_key(sah, &key);
cur = ipipsec_sa_lookup_exact(&key);
}
else
cur = IP_NULL;
/* Scan SA's (IPv4 first) */
for (domain_index = 0; domain_index < 2; domain_index++)
for (sa = IPCOM_LIST_FIRST(&ipipsec.shm->sa_head[domain_index]);
sa != IP_NULL;
sa = IPCOM_LIST_NEXT(&sa->sa_list))
{
/* First fast-forward to the current SA */
if (cur != IP_NULL)
{
if (cur == sa)
cur = IP_NULL;
continue;
}
/* IP_IPPROTO_ESP, IP_IPPROTO_AH or 0 for any */
if (sah_next->protocol != 0
&& sah_next->protocol != sa->key.proto)
continue;
/* 0,1 = input/output, 2 = any direction SA */
if (sah_next->direction != IPIPSEC_SADIR_ANY
&& sah_next->direction != ipipsec_get_sadir(sa))
continue;
/* IP_AF_INET or IP_AF_INET6 or 0 for any */
if (sah_next->domain
&& sah_next->domain != sa->key.domain)
continue;
return sa;
}
return IP_NULL;
}
/*
*===========================================================================
* ipipsec_flow_sort_get
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipipsec_flow *
ipipsec_flow_sort_get(Ip_u32 id)
{
Ipipsec_flow *flow, *next;
int flowdir, domain_index;
/* Check flows (IPv4 and input first) */
for (domain_index = 0; domain_index < 2; domain_index++)
for (flowdir = 0; flowdir < 2; flowdir++)
for (flow = IPCOM_LIST_FIRST(&ipipsec.shm->flow_head[domain_index][flowdir]);
flow != IP_NULL;
flow = next)
{
ip_assert(flow->magic == IPIPSEC_FLOW_MAGIC);
next = IPCOM_LIST_NEXT(&flow->flow_list);
if (id == 0)
return flow;
if (id != flow->id)
continue;
if (next)
return next;
else
id = 0;
}
return IP_NULL;
}
/*
*===========================================================================
* ipipsec_flow_to_selector
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipipsec_flow_to_selector(Ipipsec_flow *flow, Ipipsec_ctrl_selector *sel)
{
ipcom_memset(sel, 0, sizeof(Ipipsec_ctrl_selector));
sel->Index = flow->id;
sel->Protocol = flow->flowsel.key.proto;
sel->domain = flow->flowsel.key.domain;
sel->direction = flow->flowsel.key.direction;
sel->flowtype = flow->flowtype;
sel->flowpri = flow->flowsel.key.priority;
switch (sel->Protocol)
{
case IP_IPPROTO_TCP:
case IP_IPPROTO_UDP:
sel->LocalPort = flow->flowsel.key.ports.udptcp_srcdst_n[0];
sel->LocalMaxPort = ip_htons(flow->flowsel.src_max_port);
sel->RemotePort = flow->flowsel.key.ports.udptcp_srcdst_n[1];
sel->RemoteMaxPort = ip_htons(flow->flowsel.dst_max_port);
break;
case IP_IPPROTO_ICMP:
case IP_IPPROTO_ICMPV6:
sel->ports[0] = flow->flowsel.key.ports.icmp_typecode[0];
sel->ports[1] = flow->flowsel.key.ports.icmp_typecode[1];
break;
case IP_IPPROTO_MH:
sel->ports[0] = flow->flowsel.key.ports.mh_type[0];
break;
default:
break;
}
#ifdef IPCOM_USE_INET
if (flow->flowsel.key.domain == IP_AF_INET)
{
sel->LocalId.in.s_addr = flow->flowsel.key.src.in.s_addr;
sel->LocalMaxId.in.s_addr = flow->flowsel.src_max.in.s_addr;
sel->RemoteId.in.s_addr = flow->flowsel.key.dst.in.s_addr;
sel->RemoteMaxId.in.s_addr = flow->flowsel.dst_max.in.s_addr;
sel->local_mask.in.s_addr = flow->flowsel.mask.src.in.s_addr;
sel->remote_mask.in.s_addr = flow->flowsel.mask.dst.in.s_addr;
}
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
if (flow->flowsel.key.domain == IP_AF_INET6)
{
ipcom_memcpy(&sel->LocalId.in6, &flow->flowsel.key.src, sizeof(struct Ip_in6_addr));
ipcom_memcpy(&sel->LocalMaxId.in6, &flow->flowsel.src_max, sizeof(struct Ip_in6_addr));
ipcom_memcpy(&sel->RemoteId.in6, &flow->flowsel.key.dst, sizeof(struct Ip_in6_addr));
ipcom_memcpy(&sel->RemoteMaxId.in6, &flow->flowsel.dst_max, sizeof(struct Ip_in6_addr));
ipcom_memcpy(&sel->local_mask, &flow->flowsel.mask.src, sizeof(struct Ip_in6_addr));
ipcom_memcpy(&sel->remote_mask, &flow->flowsel.mask.dst, sizeof(struct Ip_in6_addr));
}
#endif /* IPCOM_USE_INET6 */
if (flow->sa && flow->sasel == IP_NULL)
ipipsec_sa_to_handle(flow->sa, &sel->sa);
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipipsec_conf_internal
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipipsec_conf_internal(Ip_tag *ctrl_tags)
{
Ip_tag tagp[2];
Ip_err retval;
#ifdef IPIPSEC_USE_DAEMONS
Ipnet_sig *sig;
sig = ipipsec_suspend_daemons();
if (sig == IP_NULL)
return IPCOM_ERR_NO_MEMORY;
ipipsec_poll_control_pipe();
#else
IPIPSEC_DATA_LOCK();
#endif
for(;; ctrl_tags += 2)
{
/* Read the TAG value; need to copy since it may
* be a pointer in another memory space */
if (ipcom_memcpy(&tagp[0], ctrl_tags, sizeof(Ip_tag)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
if (tagp[0] == IP_TAG_END)
break;
/* Read data */
if (ipcom_memcpy(&tagp[1], ctrl_tags + 1, sizeof(Ip_tag)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
/* What are we dealing with? */
switch(tagp[0])
{
case IPIPSEC_CONF_GET_ENABLE_OUTFILTER:
tagp[1] = ipipsec_conf_enable_outfilter;
break;
case IPIPSEC_CONF_SET_ENABLE_OUTFILTER:
ipipsec_conf_enable_outfilter = tagp[1];
break;
case IPIPSEC_CONF_GET_ENABLE_ESP:
tagp[1] = ipipsec_conf_esp_enable;
break;
case IPIPSEC_CONF_SET_ENABLE_ESP:
ipipsec_conf_esp_enable = tagp[1];
break;
case IPIPSEC_CONF_GET_ENABLE_AH:
tagp[1] = ipipsec_conf_ah_enable;
break;
case IPIPSEC_CONF_SET_ENABLE_AH:
ipipsec_conf_ah_enable = tagp[1];
break;
case IPIPSEC_CONF_GET_ALLOW_IPIP:
tagp[1] = ipipsec_conf_ipip_allow;
break;
case IPIPSEC_CONF_SET_ALLOW_IPIP:
ipipsec_conf_ipip_allow = tagp[1];
break;
default:
IPIPSEC_LEAVE(IPCOM_ERR_UNSUPPORTED_TAG);
}
/* Restore value */
ipcom_memcpy(ctrl_tags + 1, &tagp[1], sizeof(Ip_tag));
}
retval = IPCOM_SUCCESS;
leave:
#ifdef IPIPSEC_USE_DAEMONS
ipipsec_resume_daemons(sig);
#else
IPIPSEC_DATA_UNLOCK();
#endif
return retval;
}
/*
*===========================================================================
* ipipsec_ctrl_internal
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipipsec_ctrl_internal(Ip_tag *ctrl_tags)
{
Ip_tag tagp[2];
Ip_err retval;
#ifdef IPIPSEC_USE_DAEMONS
Ipnet_sig *sig;
sig = ipipsec_suspend_daemons();
if (sig == IP_NULL)
return IPCOM_ERR_NO_MEMORY;
ipipsec_poll_control_pipe();
#else
IPIPSEC_DATA_LOCK();
#endif
#if defined(IPIPSEC_USE_FULL_CTRL_API) || defined(IPIPSEC_USE_MIB) || defined(IPIPSEC_USE_TRAPS)
for(;;ctrl_tags += 2)
#endif
{
/* Read the TAG value; need to copy
* since it may be a pointer in another memory space */
if (ipcom_memcpy(&tagp[0], ctrl_tags, sizeof(Ip_tag)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
if (tagp[0] == IP_TAG_END)
IPIPSEC_LEAVE(IPCOM_SUCCESS);
/*break;*/
/* Read data */
if (ipcom_memcpy(&tagp[1], ctrl_tags + 1, sizeof(Ip_tag)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
/* What are we dealing with? */
switch(tagp[0])
{
#ifdef IPIPSEC_USE_FULL_CTRL_API
case IPIPSEC_CTRLT_GET_SELECTOR:
{
Ipipsec_ctrl_selector sel;
Ipipsec_flow *flow;
if (ipcom_memcpy(&sel, (void *)tagp[1], sizeof(sel)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
flow = ipipsec_flow_sort_get(sel.Index);
if (flow == IP_NULL)
{
sel.Index = 0;
ipcom_memcpy((void *)tagp[1], &sel, sizeof(sel));
break;
}
ipipsec_flow_to_selector(flow, &sel);
ipcom_memcpy((void *)tagp[1], &sel, sizeof(sel));
}
break;
#endif /* ifdef IPIPSEC_USE_FULL_CTRL_API */
#ifdef IPIPSEC_USE_MIB
case IPIPSEC_CTRLT_GET_ipsecEspCurrentInboundSAs :
tagp[1] = ipipsec.stats.ipsecEspCurrentInboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecEspTotalInboundSAs :
tagp[1] = ipipsec.stats.ipsecEspTotalInboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecEspCurrentOutboundSAs :
tagp[1] = ipipsec.stats.ipsecEspCurrentOutboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecEspTotalOutboundSAs :
tagp[1] = ipipsec.stats.ipsecEspTotalOutboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecAhCurrentInboundSAs :
tagp[1] = ipipsec.stats.ipsecAhCurrentInboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecAhTotalInboundSAs :
tagp[1] = ipipsec.stats.ipsecAhCurrentInboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecAhCurrentOutboundSAs :
tagp[1] = ipipsec.stats.ipsecAhCurrentOutboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecAhTotalOutboundSAs :
tagp[1] = ipipsec.stats.ipsecAhTotalOutboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecDecryptionErrors :
tagp[1] = ipipsec.stats.ipsecAhTotalOutboundSAs;
break;
case IPIPSEC_CTRLT_GET_ipsecAuthenticationErrors :
tagp[1] = ipipsec.stats.ipsecAuthenticationErrors;
break;
case IPIPSEC_CTRLT_GET_ipsecReplayErrors :
tagp[1] = ipipsec.stats.ipsecAuthenticationErrors;
break;
case IPIPSEC_CTRLT_GET_ipsecPolicyErrors :
tagp[1] = ipipsec.stats.ipsecAuthenticationErrors;
break;
case IPIPSEC_CTRLT_GET_ipsecOtherReceiveErrors :
tagp[1] = ipipsec.stats.ipsecOtherReceiveErrors;
break;
case IPIPSEC_CTRLT_GET_ipsecSendErrors :
tagp[1] = ipipsec.stats.ipsecSendErrors;
break;
case IPIPSEC_CTRLT_GET_ipsecUnknownSpiErrors :
tagp[1] = ipipsec.stats.ipsecUnknownSpiErrors;
break;
#endif /* IPIPSEC_USE_MIB */
#ifdef IPIPSEC_USE_TRAPS
/* trap function */
case IPIPSEC_CTRLT_SET_TRAP_FUNCTION :
ipipsec.trap_cb = (Ipipsec_trap_func)tagp[1];
break;
/* traps get */
case IPIPSEC_CTRLT_GET_espAuthFailureTrapEnable :
tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espAuthFailureTrap];
break;
case IPIPSEC_CTRLT_GET_ahAuthFailureTrapEnable :
tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahAuthFailureTrap];
break;
case IPIPSEC_CTRLT_GET_espReplayFailureTrapEnable :
tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espReplayFailureTrap];
break;
case IPIPSEC_CTRLT_GET_ahReplayFailureTrapEnable :
tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahReplayFailureTrap];
break;
case IPIPSEC_CTRLT_GET_espPolicyFailureTrapEnable :
tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espPolicyFailureTrap];
break;
case IPIPSEC_CTRLT_GET_ahPolicyFailureTrapEnable :
tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahPolicyFailureTrap];
break;
case IPIPSEC_CTRLT_GET_invalidSpiTrapEnable :
tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_invalidSpiTrap];
break;
case IPIPSEC_CTRLT_GET_otherPolicyFailureTrapEnable :
tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_otherPolicyFailureTrap];
break;
/* traps set */
case IPIPSEC_CTRLT_SET_espAuthFailureTrapEnable :
ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espAuthFailureTrap] = (Ip_u32)tagp[1];
break;
case IPIPSEC_CTRLT_SET_ahAuthFailureTrapEnable :
ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahAuthFailureTrap] = (Ip_u32)tagp[1];
break;
case IPIPSEC_CTRLT_SET_espReplayFailureTrapEnable :
ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espReplayFailureTrap] = (Ip_u32)tagp[1];
break;
case IPIPSEC_CTRLT_SET_ahReplayFailureTrapEnable :
ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahReplayFailureTrap] = (Ip_u32)tagp[1];
break;
case IPIPSEC_CTRLT_SET_espPolicyFailureTrapEnable :
ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espPolicyFailureTrap] = (Ip_u32)tagp[1];
break;
case IPIPSEC_CTRLT_SET_ahPolicyFailureTrapEnable :
ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahPolicyFailureTrap] = (Ip_u32)tagp[1];
break;
case IPIPSEC_CTRLT_SET_invalidSpiTrapEnable :
ipipsec.enable_trap[IPIPSEC_TRAPTYPE_invalidSpiTrap] = (Ip_u32)tagp[1];
break;
case IPIPSEC_CTRLT_SET_otherPolicyFailureTrapEnable :
ipipsec.enable_trap[IPIPSEC_TRAPTYPE_otherPolicyFailureTrap] = (Ip_u32)tagp[1];
break;
#endif /* IPIPSEC_USE_TRAPS */
default:
IPIPSEC_LEAVE(IPCOM_ERR_UNSUPPORTED_TAG);
}
/* Restore value */
#if defined(IPIPSEC_USE_FULL_CTRL_API) || defined(IPIPSEC_USE_MIB) || defined(IPIPSEC_USE_TRAPS)
ipcom_memcpy(ctrl_tags + 1, &tagp[1], sizeof(Ip_tag));
#endif
}
#if defined(IPIPSEC_USE_FULL_CTRL_API) || defined(IPIPSEC_USE_MIB) || defined(IPIPSEC_USE_TRAPS)
retval = IPCOM_SUCCESS;
#endif
leave:
#ifdef IPIPSEC_USE_DAEMONS
ipipsec_resume_daemons(sig);
#else
IPIPSEC_DATA_UNLOCK();
#endif
return retval;
}
/*
*===========================================================================
* ipipsec_sactrl_internal
*===========================================================================
* Context:
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipipsec_sactrl_internal(Ipipsec_sa_handle *sah, Ip_tag *ctrl_tags)
{
Ip_tag tagp[5];
Ipipsec_sa *sa;
Ip_err retval;
Ipipsec_flow *flow;
Ipipsec_sa_handle sah_next;
Ip_tag *next_tag;
#ifdef IPIPSEC_USE_DAEMONS
Ipnet_sig *sig;
sig = ipipsec_suspend_daemons();
if (sig == IP_NULL)
return IPCOM_ERR_NO_MEMORY;
ipipsec_poll_control_pipe();
#else
IPIPSEC_DATA_LOCK();
#endif
/* Just to make certain that its in the memory space */
if (ipcom_memcpy(&sah_next, sah, sizeof(sah_next)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
/* Get SA pointer for SA get/set */
if (sah_next.spi_n)
{
Ipipsec_key key;
ipipsec_handle_to_key(&sah_next, &key);
sa = ipipsec_sa_lookup_exact(&key);
}
else
sa = IP_NULL;
/* Parse the vtags */
for (next_tag = ctrl_tags;; next_tag += 2)
{
Ip_size_t szu = sizeof(Ip_tag);
/* Go to next tag */
ctrl_tags = next_tag;
/* Read the TAG value; need to copy since it may
* be a pointer in another memory space */
if (ipcom_memcpy(&tagp[0], ctrl_tags, sizeof(Ip_tag)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
if (tagp[0] == IP_TAG_END)
break;
if (tagp[0] > IPIPSEC_SACTRLT_GET_NEXT_SA && tagp[0] <= IPIPSEC_SACTRLT_GET_LAST)
{
if (sa == IP_NULL)
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
/* Read data */
if (ipcom_memcpy(&tagp[1], ctrl_tags + 1, sizeof(Ip_tag)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_TAG_VALUE);
}
switch(tagp[0])
{
#ifdef IPIPSEC_USE_FULL_CTRL_API
/* This tag returns immediately after processing since it updates the 'sa' */
case IPIPSEC_SACTRLT_GET_NEXT_SA:
{
Ipipsec_sa *sa_next;
if (ipcom_memcpy(&sah_next, (void *)tagp[1], sizeof(sah_next)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
sa_next = ipipsec_sa_lex_get(sah, &sah_next);
if (sa_next != IP_NULL)
ipipsec_sa_to_handle(sa_next, &sah_next);
else
sah_next.spi_n = 0;
ipcom_memcpy((void *)tagp[1], &sah_next, sizeof(sah_next));
}
break;
#endif /* IPIPSEC_USE_FULL_CTRL_API */
case IPIPSEC_SACTRLT_GET_SaSelector:
{
Ipcom_list *list_element;
ip_assert(sa);
/* In MIB, only first selector is listed. Pick the output one first */
list_element = IPCOM_LIST_FIRST(&sa->flow_head);
flow = IPIPSEC_LIST_ENTRY(list_element, Ipipsec_flow, sa_list);
ip_assert(flow == IP_NULL || flow->magic == IPIPSEC_FLOW_MAGIC);
if (flow)
tagp[1] = flow->id;
else
tagp[1] = 0;
}
break;
case IPIPSEC_SACTRLT_GET_SaCreator:
tagp[1] = 1; /* 0=unknown,1=static,2=ike,3=other */
break;
case IPIPSEC_SACTRLT_GET_Encapsulation:
ip_assert(sa);
if (IP_BIT_ISSET(sa->sadb_sa_flags, SADB_X_SAFLAGS_TUNNEL))
tagp[1] = 1; /* 0=reserved,1=tunnel,2=transport */
else
tagp[1] = 2;
break;
case IPIPSEC_SACTRLT_GET_EncAlg:
ip_assert(sa);
tagp[1] = sa->sadb_sa_encrypt;
break;
case IPIPSEC_SACTRLT_GET_EncKeyLength:
ip_assert(sa);
tagp[1] = sa->encrypt ? (sa->encrypt->keyLen << 3) : 0;
break;
case IPIPSEC_SACTRLT_GET_AuthAlg:
ip_assert(sa);
tagp[1] = sa->sadb_sa_auth;
break;
case IPIPSEC_SACTRLT_GET_AuthKeyLength:
ip_assert(sa);
tagp[1] = sa->auth ? (sa->auth->keyLen << 3) : 0;
break;
case IPIPSEC_SACTRLT_GET_RepWinSize:
ip_assert(sa);
tagp[1] = sa->sadb_sa_replay;
break;
case IPIPSEC_SACTRLT_GET_LimitSeconds:
ip_assert(sa);
tagp[1] = sa->lthard.addtime;
break;
case IPIPSEC_SACTRLT_GET_LimitKbytes:
tagp[1] = 0; /*!!auto*/
break;
case IPIPSEC_SACTRLT_GET_AccSeconds:
ip_assert(sa);
if (sa->ltcurrent.usetime)
tagp[1] = (Ip_tag)(ipcom_time(0) - sa->ltcurrent.addtime);
else
tagp[1] = 0;
break;
case IPIPSEC_SACTRLT_GET_InAccKbytes:
ip_assert(sa);
tagp[1] = (IP_U64_GETLO(sa->bytes[IPIPSEC_DIR_IN]) >> 10);
tagp[1] += (IP_U64_GETHI(sa->bytes[IPIPSEC_DIR_IN]) << 22);
break;
case IPIPSEC_SACTRLT_GET_OutAccKbytes:
ip_assert(sa);
tagp[1] = (IP_U64_GETLO(sa->bytes[IPIPSEC_DIR_OUT]) >> 10);
tagp[1] += (IP_U64_GETHI(sa->bytes[IPIPSEC_DIR_OUT]) << 22);
break;
#ifdef IPIPSEC_USE_FULL_CTRL_API
case IPIPSEC_SACTRLT_GET_InUserOctets:
ip_assert(sa);
ipcom_memcpy((void *)tagp[1], &sa->bytes[IPIPSEC_DIR_IN], sizeof(Ip_u64));
break;
case IPIPSEC_SACTRLT_GET_OutUserOctets:
ip_assert(sa);
ipcom_memcpy((void *)tagp[1], &sa->bytes[IPIPSEC_DIR_OUT], sizeof(Ip_u64));
break;
case IPIPSEC_SACTRLT_GET_InPackets:
ip_assert(sa);
ipcom_memcpy((void *)tagp[1], &sa->packets[IPIPSEC_DIR_IN], sizeof(Ip_u64));
break;
case IPIPSEC_SACTRLT_GET_OutPackets:
ip_assert(sa);
ipcom_memcpy((void *)tagp[1], &sa->packets[IPIPSEC_DIR_OUT], sizeof(Ip_u64));
break;
#endif /* IPIPSEC_USE_FULL_CTRL_API */
#ifdef IPIPSEC_USE_MIB
case IPIPSEC_SACTRLT_GET_DecryptErrors:
ip_assert(sa);
tagp[1] = sa->err_in_decrypt;
break;
case IPIPSEC_SACTRLT_GET_AuthErrors:
ip_assert(sa);
tagp[1] = sa->err_in_auth;
break;
case IPIPSEC_SACTRLT_GET_ReplayErrors:
ip_assert(sa);
tagp[1] = sa->err_in_replay;
break;
case IPIPSEC_SACTRLT_GET_PolicyErrors:
ip_assert(sa);
tagp[1] = sa->err_in_policy;
break;
case IPIPSEC_SACTRLT_GET_PadErrors:
ip_assert(sa);
tagp[1] = sa->err_in_pad;
break;
case IPIPSEC_SACTRLT_GET_OtherReceiveErrors:
ip_assert(sa);
tagp[1] = sa->err_in_other;
break;
case IPIPSEC_SACTRLT_GET_OutSendErrors:
ip_assert(sa);
tagp[1] = sa->err_out_send;
break;
#endif /* IPIPSEC_USE_MIB */
#ifdef IPIPSEC_USE_FULL_CTRL_API
case IPIPSEC_SACTRLT_GET_Grouped:
ip_assert(sa);
if (ipcom_memcpy(&sah_next, (void *)tagp[1], sizeof(sah_next)) == IP_NULL)
{
IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG);
}
if (sa->group_next != IP_NULL)
ipipsec_sa_to_handle(sa->group_next, &sah_next);
else
sah_next.spi_n = 0;
ipcom_memcpy((void *)tagp[1], &sah_next, sizeof(sah_next));
break;
#endif /* #ifdef IPIPSEC_USE_FULL_CTRL_API */
case IPIPSEC_SACTRLT_GET_DstAddr:
ip_assert(sa);
tagp[1] = sa->key.dst.in.s_addr;
break;
case IPIPSEC_SACTRLT_GET_SrcAddr:
ip_assert(sa);
tagp[1] = sa->key.src.in.s_addr;
break;
case IPIPSEC_SACTRLT_GET_State:
ip_assert(sa);
tagp[1] = sa->sadb_sa_state;
break;
#ifdef IPCOM_USE_INET6
case IPIPSEC_SACTRLT_GET_DstAddr6:
case IPIPSEC_SACTRLT_GET_SrcAddr6:
ip_assert(sa);
if (sa->key.domain != IP_AF_INET6)
IPIPSEC_LEAVE(IPCOM_ERR_FAILED);
if (*tagp == IPIPSEC_SACTRLT_GET_DstAddr6)
ipcom_memcpy(&tagp[1], &sa->key.dst, 16);
else
ipcom_memcpy(&tagp[1], &sa->key.src, 16);
/* Advance three more tags */
next_tag += 3;
szu = 16;
break;
#endif /* IPCOM_USE_INET6 */
default:
IPIPSEC_LEAVE(IPCOM_ERR_UNSUPPORTED_TAG);
}
/* Restore value */
ipcom_memcpy(ctrl_tags + 1, &tagp[1], szu);
}
retval = IPCOM_SUCCESS;
leave:
#ifdef IPIPSEC_USE_DAEMONS
ipipsec_resume_daemons(sig);
#else
IPIPSEC_DATA_UNLOCK();
#endif
return retval;
}
#endif /* !IP_PORT_LAS */
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipipsec_sactrl
*===========================================================================
* Context:
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipipsec_sactrl(Ipipsec_sa_handle *sah, Ip_tag *ctrl_tags)
{
#if defined(IPNET)
Ip_fd pfd = IP_INVALID_SOCKET;
int err = 0;
void *ptr[2];
/* The arguments */
ptr[0] = sah;
ptr[1] = ctrl_tags;
/* Get a socket */
if ((pfd = ipcom_socket(IP_PF_KEY, IP_SOCK_RAW, PF_KEY_V2)) == IP_INVALID_SOCKET)
return ipcom_errno;
/* Do the sockopt */
if (ipcom_socketioctl(pfd, IP_SIOCXIPSEC_SA_CTL, ptr) < 0)
err = ipcom_errno;
ipcom_socketclose(pfd);
return err;
#elif defined(IPLITE)
Ip_err ret;
(void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_LOCK, IP_NULL);
ret = (int)ipipsec_sactrl_internal(sah, ctrl_tags);
(void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_UNLOCK, IP_NULL);
return ret;
#else
return -IP_ERRNO_EINVAL
#endif
}
/*
*===========================================================================
* ipipsec_ctrl
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipipsec_ctrl(Ip_tag *ctrl_tags)
{
#if defined(IPNET)
Ip_fd pfd;
int err = 0;
void *ptr = ctrl_tags;
/* Get a socket to do the ioctl */
if ((pfd = ipcom_socket(IP_PF_KEY, IP_SOCK_RAW, PF_KEY_V2)) == IP_INVALID_SOCKET)
return ipcom_errno;
/* Do the sockopt */
if (ipcom_socketioctl(pfd, IP_SIOCXIPSEC_CTL, &ptr) < 0)
err = ipcom_errno;
ipcom_socketclose(pfd);
return err;
#elif defined(IPLITE)
Ip_err ret;
(void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_LOCK, IP_NULL);
ret = ipipsec_ctrl_internal(ctrl_tags);
(void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_UNLOCK, IP_NULL);
return ret;
#else
return -IP_ERRNO_EINVAL
#endif
}
/*
*===========================================================================
* ipipsec_ctrl
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipipsec_conf(Ip_tag *ctrl_tags)
{
#if defined(IPNET)
Ip_fd pfd;
int err = 0;
void *ptr = ctrl_tags;
/* Get a socket to do the ioctl */
if ((pfd = ipcom_socket(IP_PF_KEY, IP_SOCK_RAW, PF_KEY_V2)) == IP_INVALID_SOCKET)
return ipcom_errno;
/* Do the sockopt */
if (ipcom_socketioctl(pfd, IP_SIOCXIPSEC_CONF_CTL, &ptr) < 0)
err = ipcom_errno;
ipcom_socketclose(pfd);
return err;
#elif defined(IPLITE)
Ip_err ret;
(void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_LOCK, IP_NULL);
ret = ipipsec_conf_internal(ctrl_tags);
(void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_UNLOCK, IP_NULL);
return ret;
#else
return -IP_ERRNO_EINVAL
#endif
}
#ifndef IP_PORT_LAS
/*
*===========================================================================
* ipipsec_sys_ioctl
*===========================================================================
* Description: IO control.
* Parameters: fd - A socket descriptor.
* request - The IO control request.
* argp - Request specific data.
* Returns: 0 = success, -1 = error (error code from ipcom_errno).
*
*/
IP_PUBLIC int
ipipsec_sys_ioctl(Ip_fd fd, unsigned long request, void *argp)
{
int ret = 0;
Ipipsec_sa *sa = IP_NULL;
Ipipsec_ioctl_sactrl *isa = argp;
#ifdef IPIPSEC_USE_DAEMONS
Ipnet_sig *sig;
sig = ipipsec_suspend_daemons();
if (sig == IP_NULL)
return -IP_ERRNO_ENOMEM;
ipipsec_poll_control_pipe();
#else
IPIPSEC_DATA_LOCK();
#endif
IPCOM_UNUSED_ARG(fd);
ip_assert(isa != IP_NULL);
switch(request)
{
case IP_SIOCXIPSEC_Grouped:
case IP_SIOCXIPSEC_InUserOctets:
case IP_SIOCXIPSEC_OutUserOctets:
case IP_SIOCXIPSEC_InUserPackets:
case IP_SIOCXIPSEC_OutUserPackets:
/* Get SA pointer for SA get/set */
if (isa->sa.spi_n)
{
Ipipsec_key key;
ipipsec_handle_to_key(&isa->sa, &key);
sa = ipipsec_sa_lookup_exact(&key);
}
if (sa == IP_NULL)
{
ret = -IP_ERRNO_ESRCH;
goto leave;
}
break;
default:
break;
}
switch (request)
{
case IP_SIOCXIPSEC_SELECTOR:
{
Ipipsec_ctrl_selector *sel = argp;
Ipipsec_flow *flow;
flow = ipipsec_flow_sort_get(sel->Index);
if (flow == IP_NULL)
sel->Index = 0;
else
ipipsec_flow_to_selector(flow, sel);
}
break;
case IP_SIOCXIPSEC_NEXT_SA:
{
Ipipsec_sa *sa_next;
sa_next = ipipsec_sa_lex_get(&isa->sa, &isa->arg.next);
if (sa_next != IP_NULL)
ipipsec_sa_to_handle(sa_next, &isa->arg.next);
else
isa->arg.next.spi_n = 0;
}
break;
case IP_SIOCXIPSEC_Grouped:
ip_assert(sa != IP_NULL);
if (sa->group_next != IP_NULL)
ipipsec_sa_to_handle(sa->group_next, &isa->arg.group);
else
isa->arg.group.spi_n = 0;
break;
case IP_SIOCXIPSEC_InUserOctets:
ip_assert(sa);
isa->arg.u64 = sa->bytes[IPIPSEC_DIR_IN];
break;
case IP_SIOCXIPSEC_OutUserOctets:
ip_assert(sa);
isa->arg.u64 = sa->bytes[IPIPSEC_DIR_OUT];
break;
case IP_SIOCXIPSEC_InUserPackets:
ip_assert(sa);
isa->arg.u64 = sa->packets[IPIPSEC_DIR_IN];
break;
case IP_SIOCXIPSEC_OutUserPackets:
ip_assert(sa);
isa->arg.u64 = sa->packets[IPIPSEC_DIR_OUT];
break;
default:
ret = -IP_ERRNO_EINVAL;
break;
}
leave:
#ifdef IPIPSEC_USE_DAEMONS
ipipsec_resume_daemons(sig);
#else
IPIPSEC_DATA_UNLOCK();
#endif
return ret;
}
#endif /* !IP_PORT_LAS */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/