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

842 lines
27 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_payload_sa.c,v $ $Revision: 1.32.10.15 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_payload_sa.c,v $
* $Author: yli12 $ $Date: 2016-03-25 09:56:29 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/* IKE Security Association Payload
NOTE! The current implementation does only support the IPSec DOI */
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipike_h.h"
#include "ipike_config.h"
#include "ipike_payload_sa.h"
#include "ipike_payload_proposal.h"
#include "ipike_sadb.h"
#include "ipike_util.h"
#include "ipike_configuration.h"
#include "ipike_ipsec_attributes.h"
#include <ipcom_clib.h>
#include <ipcom_syslog.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* ipike_sa_header_size
*===========================================================================
* Description: Returns the size of the SA payload header.
* Parameters: sa - a pointer to a SA payload.
* Returns: The size (in bytes) of the SA payload header.
*
*/
IP_STATIC Ip_u16
ipike_sa_header_size(Ipike_sa_payload* sa);
/*
*===========================================================================
* ipike_sa_proposal_data
*===========================================================================
* Description: Returns a pointer to the first proposal payload.
* Parameters: sa - a pointer to a SA payload.
* Returns: A pointer to the first proposal payload.
*
*/
IP_STATIC Ipike_proposal_payload*
ipike_sa_proposal_data(Ipike_sa_payload* sa);
/*
*===========================================================================
* ipike_sa_proposal_length
*===========================================================================
* Description: Returns the length of the proposal payload(s).
* Parameters: sa - a pointer to a SA payload.
* Returns: The length (in bytes) of the proposal payload(s).
*
*/
IP_STATIC Ip_u16
ipike_sa_proposal_length(Ipike_sa_payload* sa);
/*
*===========================================================================
* ipike_sa_process_message_ipsec
*===========================================================================
* Description: Updates the security association and exchange paramters
* with the selected encryption and hash alghorithm using
* IPSec domain of interpretation.
* Parameters: ie - paramters for the ongoing exchange.
* payload - a SA payload.
* sa - will be updated with the paramters from the SA payload
* if the call was successful.
* Returns: IPIKE_SUCCESS
* IPIKE_OUT_OF_MEMORY
* IPIKE_SA_NO_ACCEPTED_TRANSFORM,
* IPIKE_SA_DOI_SITUATION_UNSUPPORTED,
*
*/
IP_STATIC Ipike_error
ipike_sa_process_message_ipsec(Ipike_isakmp_exchange* ie, Ipike_sa_payload* payload, Ipike_sa* sa);
/*
*===========================================================================
* ipike_sa_print_payload
*===========================================================================
* Description: Prints the content of a security association payload to
* the system log.
* Parameters: sa - a SA payload.
* print_proposal_payload - a function that knowns how to print
* the proposal payload in the current phase and DOI.
* Returns:
*
*/
IP_STATIC void
ipike_sa_print_payload(
Ipike_sa_payload* sa,
void (*print_proposal_payload)(Ipike_proposal_payload*),
Ip_bool phase1);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_sa_header_size
*===========================================================================
*/
IP_STATIC Ip_u16
ipike_sa_header_size(Ipike_sa_payload *sa)
{
switch (ip_ntohl(sa->doi))
{
/* case IPIKE_DOI_ISAKMP:
return IPIKE_SA_HEADER_SIZE_ISAKMP;*/
case IPIKE_DOI_IPSEC:
return IPIKE_SA_HEADER_SIZE_IPSEC;
}
IPCOM_LOG1(ERR, "unsupported DOI (%d)", ip_ntohl(sa->doi));
return 0;
}
/*
*===========================================================================
* ipike_sa_proposal_data
*===========================================================================
*/
IP_STATIC Ipike_proposal_payload *
ipike_sa_proposal_data(Ipike_sa_payload *sa)
{
return (Ipike_proposal_payload *) ((Ip_u8 *) sa + ipike_sa_header_size(sa));
}
/*
*===========================================================================
* ipike_sa_proposal_length
*===========================================================================
*/
IP_STATIC Ip_u16
ipike_sa_proposal_length(Ipike_sa_payload *sa)
{
return (Ip_u16) (ip_ntohs(sa->header.length) - ipike_sa_header_size(sa));
}
/*
*===========================================================================
* ipike_sa_next_payload
*===========================================================================
*/
IP_STATIC Ipike_proposal_payload*
ipike_sa_next_payload(Ipike_proposal_payload* payload)
{
return (Ipike_proposal_payload*)ipike_next_payload_structure(&payload->header);
}
/*
*===========================================================================
* ipike_sa_process_message_ipsec
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_sa_process_message_ipsec(
Ipike_isakmp_exchange* ie,
Ipike_sa_payload* payload,
Ipike_sa* sa)
{
Ipike_proposal_payload* proposal_payload = ipike_sa_proposal_data(payload);
int proposal_count = 0;
Ipike_error err;
if (payload->situation.ip_sec == 0)
{
IPCOM_LOG0(WARNING, "No situation specified");
return IPIKE_SITUATION_UNSUPPORTED;
}
if ((payload->situation.ip_sec & IPIKE_SIT_SECRECY)
|| (payload->situation.ip_sec & IPIKE_SIT_INTEGRITY))
{
IPCOM_LOG2(WARNING, "Situation: [%s%s ] not supported",
payload->situation.ip_sec & IPIKE_SIT_SECRECY ? " SECRECY" : "",
payload->situation.ip_sec & IPIKE_SIT_INTEGRITY ? " INTEGRITY" : "");
return IPIKE_SITUATION_UNSUPPORTED;
}
while (proposal_payload != IP_NULL)
{
Ipike_proposal* proposal;
if (IP_NULL == (proposal = ipcom_calloc(1, sizeof(Ipike_proposal))))
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
err = ipike_proposal_extract(ie, proposal_payload, proposal);
if (err == IPIKE_SUCCESS)
{
proposal_count++;
err = ipike_array_add((void***) &sa->proposals, proposal);
if (IPIKE_SUCCESS != err)
return err;
}
else
ipike_proposal_free(proposal);
if (err != IPIKE_SUCCESS && err != IPIKE_SA_NO_ACCEPTED_TRANSFORM)
return err;
proposal_payload = ipike_sa_next_payload(proposal_payload);
}
sa->proposal_count = proposal_count;
/* In phase1, multi proposal in one sa is not allowed */
if ((ie->is_phase1) && (sa->proposal_count > 1))
{
return IPIKE_FAILED;
}
return proposal_count == 0 ? IPIKE_SA_NO_ACCEPTED_PROPOSAL : IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_sa_print_payload
*===========================================================================
*/
IP_STATIC void
ipike_sa_print_payload(
Ipike_sa_payload* sa,
void (*print_proposal_payload)(Ipike_proposal_payload*),
Ip_bool phase1)
{
Ipike_proposal_payload *proposal;
if ( ipike_sa_check_payload(sa, phase1) != IPIKE_SUCCESS )
{
IPCOM_LOG0(ERR,
"ipike_sa_print_payload() :: unable to print invalid sa payload");
return;
}
IPCOM_LOG1(DEBUG2, " DOI: %s",
ipike_doi_to_string(ip_ntohl(sa->doi)));
/* The only supported DOI is IPSec */
IPCOM_LOG3(DEBUG2, " situation: [%s%s%s ]",
sa->situation.ip_sec & IPIKE_SIT_IDENTITY_ONLY ? " IDENTITY" : "",
sa->situation.ip_sec & IPIKE_SIT_SECRECY ? " SECRECY" : "",
sa->situation.ip_sec & IPIKE_SIT_INTEGRITY ? " INTEGRITY" : "");
for (proposal = ipike_sa_proposal_data(sa);
IP_NULL != proposal;
proposal = ipike_sa_next_payload(proposal))
{
IPCOM_LOG1(DEBUG2, " << %s >>",
ipike_payload_type_to_string(IPIKE_PAYLOAD_PROPOSAL));
IPCOM_LOG2(DEBUG2, " Next Payload: %s (%d)",
ipike_payload_type_to_string(proposal->header.next_payload),
(int) proposal->header.next_payload);
IPCOM_LOG1(DEBUG2, " Payload Length: %d",
ip_ntohs(proposal->header.length));
print_proposal_payload(proposal);
}
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_sa_new
*===========================================================================
*/
IP_GLOBAL Ipike_sa_payload*
ipike_sa_new(
Ip_u32 doi,
Ipike_sa_situation situation,
Ipike_proposal_payload** proposals)
{
Ip_u16 sa_header_size;
Ip_u16 sa_size;
Ipike_sa_payload* sa_payload;
Ip_u8* proposal_data;
int i;
switch (doi)
{
case IPIKE_DOI_ISAKMP:
sa_header_size = (Ip_u16) IPIKE_SA_HEADER_SIZE_ISAKMP;
break;
case IPIKE_DOI_IPSEC:
sa_header_size = (Ip_u16) IPIKE_SA_HEADER_SIZE_IPSEC;
break;
default:
IPCOM_LOG1(ERR, "DOI %d is not supported", doi);
return IP_NULL;
}
sa_size = (Ip_u16)(ipike_payload_array_size((Ipike_payload_header**) proposals) + sa_header_size);
if (IP_NULL == (sa_payload = ipcom_calloc(1, sa_size)))
{
IPCOM_LOG0(CRIT, "ipike_sa_create: out of memory");
return IP_NULL;
}
sa_payload->header.length = ip_htons(sa_size);
sa_payload->header.next_payload = IPIKE_PAYLOAD_SECURITY_ASSOCIATION;
sa_payload->doi = ip_htonl(doi);
switch (doi)
{
case IPIKE_DOI_ISAKMP:
sa_payload->situation.isakmp = situation.isakmp;
break;
case IPIKE_DOI_IPSEC:
sa_payload->situation.ip_sec = situation.ip_sec;
break;
}
proposal_data = ((Ip_u8*) sa_payload + sa_header_size);
for (i = 0; proposals[i] != IP_NULL; i++)
{
if (proposals[i+1] != IP_NULL)
proposals[i]->header.next_payload = IPIKE_PAYLOAD_PROPOSAL;
else
proposals[i]->header.next_payload = IPIKE_PAYLOAD_NONE;
ipcom_memcpy(proposal_data, (void*)proposals[i], ip_ntohs(proposals[i]->header.length));
proposal_data += ip_ntohs(proposals[i]->header.length);
}
return sa_payload;
}
/*
*===========================================================================
* ipike_sa_free
*===========================================================================
*/
IP_GLOBAL void
ipike_sa_free(Ipike_sa *s, void(*free_func)(void*))
{
ipike_array_free((void**) s->proposals, (void(*)(void*)) ipike_proposal_free);
ipcom_memset(s, 0, sizeof(Ipike_sa));
if (free_func)
free_func(s);
}
/*
*===========================================================================
* ipike_sa_create
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_sa_create(Ipike_sa* sa, Ipike_sa_payload** payload)
{
Ipike_proposal_payload** proposals = IP_NULL;
Ipike_proposal_payload* proposal;
Ipike_error err = IPIKE_SUCCESS;
int i = 0;
Ipike_proposal* end_prop = IP_NULL;
ip_assert(sa->proposals != IP_NULL);
if (sa->selected_proposal >= 0)
{
/* TODO is this logic valid ? it assumes proposals with same
number are consecutive */
i = sa->selected_proposal;
end_prop = sa->proposals[i + ipike_sa_selected_proposal_count(sa)];
}
for (; sa->proposals[i] != end_prop; i++)
{
if (IPIKE_SUCCESS != (err = ipike_proposal_create(sa->proposals[i], &proposal)))
goto cleanup;
if (IPIKE_SUCCESS != (err = ipike_array_add((void***) &proposals, proposal)))
{
ipcom_free(proposal);
goto cleanup;
}
}
if (IP_NULL == (*payload = ipike_sa_new(sa->doi, sa->situation, proposals)))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
cleanup:
ipike_array_free((void**) proposals, ipcom_free); /*lint !e123 */
return err;
}
/*
*===========================================================================
* ipike_sa_ike_initialize
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_sa_ike_initialize(
Ipike_config_ike_sa* conf,
Ipike_sa* sa)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_proposal* p = IP_NULL;
if ((IP_NULL == conf->proposals) ||
(IP_NULL == conf->proposals[0]))
{
err = IPIKE_SA_NO_VALID_TRANSFORM_CONFIGURED;
}
else
{
/* We only support a single proposal with IKE v1, each configuration
* proposal is converted to an IKE v1 transform and added to one
* single IKE v1 proposal. */
if (IP_NULL == (p = ipcom_calloc(1, sizeof(*p))))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
if (IPIKE_SUCCESS == err)
err = ipike_proposal_ike_initialize(conf,
conf->proposals,
(Ip_u8)(1),
p);
if (IPIKE_SUCCESS == err)
err = ipike_array_add((void***) &sa->proposals, p);
if (IPIKE_SUCCESS != err)
ipike_proposal_free(p);
}
if (IPIKE_SUCCESS == err)
{
sa->doi = IPIKE_DOI_IPSEC;
sa->situation.isakmp = IPIKE_SIT_IDENTITY_ONLY;
sa->selected_proposal = -1;
sa->selected_proposal2 = -1;
sa->proposal_count = 0;
}
else
{
IPCOM_LOG0(ERR, "ipike_sa_ike_initialize: failed to intialize IKE SA");
}
return err;
}
/*
*===========================================================================
* ipike_sa_ipsec_initialize
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_sa_ipsec_initialize(
Ipike_config_ipsec_sa* conf,
Ipike_sa* sa)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_proposal* p = IP_NULL;
Ip_u8 i = 0;
Ip_u8 num = 0;
if ((IP_NULL == conf->proposals) ||
(IP_NULL == conf->proposals[0]))
{
err = IPIKE_SA_NO_VALID_TRANSFORM_CONFIGURED;
}
else
{
for (i=0; (IP_NULL != conf->proposals[i]); i++)
{
if (IP_NULL == (p = ipcom_calloc(1, sizeof(*p))))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
if (IPIKE_SUCCESS == err)
{
if (conf->proposals[i]->number != 0)
num = (Ip_u8)conf->proposals[i]->number;
else
num = (Ip_u8)(i+1);
err = ipike_proposal_ipsec_initialize(conf,
conf->proposals[i],
num,
p);
}
if (IPIKE_SUCCESS == err)
err = ipike_array_add((void***) &sa->proposals, p);
if (IPIKE_SUCCESS != err)
{
ipike_proposal_free(p);
break;
}
}
}
if (IPIKE_SUCCESS == err)
{
sa->doi = IPIKE_DOI_IPSEC;
sa->situation.isakmp = IPIKE_SIT_IDENTITY_ONLY;
sa->selected_proposal = -1;
sa->selected_proposal2 = -1;
sa->proposal_count = i;
}
else
{
IPCOM_LOG0(ERR, "ipike_sa_ipsec_initialize: failed to intialize IPSec SA");
}
return err;
}
/*
*===========================================================================
* ipike_sa_ipsec_set_behind_nat
*===========================================================================
*/
IP_GLOBAL void
ipike_sa_ipsec_set_behind_nat(Ipike_sa* sa)
{
int i;
int j;
/* Change encapsulation mode:
* tunnel > udp_tunnel
* transport > udp_transport */
for (i=0; i < sa->proposal_count; i++)
for (j=0; sa->proposals[i]->transforms[j] != IP_NULL; j++)
if (sa->proposals[i]->transforms[j]->ipsec.encapsulation_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_TUNNEL)
sa->proposals[i]->transforms[j]->ipsec.encapsulation_mode = IPIKE_IPSEC_ENCAPSULATION_MODE_UDP_TUNNEL;
else if (sa->proposals[i]->transforms[j]->ipsec.encapsulation_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_TRANSPORT)
{
sa->proposals[i]->transforms[j]->ipsec.encapsulation_mode = IPIKE_IPSEC_ENCAPSULATION_MODE_UDP_TRANSPORT;
sa->send_original_address = IP_TRUE;
}
return;
}
/*
*===========================================================================
* ipike_sa_check_payload
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_sa_check_payload(Ipike_sa_payload* sa, Ip_bool phase1)
{
Ipike_proposal_payload* proposal;
Ip_u32 proposal_payload_max_len;
Ip_s32 chain_length;
unsigned int next_payload;
int i = 0;
if ((sa->header.next_payload == IPIKE_PAYLOAD_PROPOSAL) ||
(sa->header.next_payload == IPIKE_PAYLOAD_TRANSFORM))
{
return IPIKE_WRONG_PAYLOAD;
}
/* Check DOI field */
if ( ip_ntohl(sa->doi) != IPIKE_DOI_ISAKMP &&
ip_ntohl(sa->doi) != IPIKE_DOI_IPSEC )
{
IPCOM_LOG1(ERR, "ipike_sa_check_payload() :: DOI not supported (%d)",
sa->doi);
return IPIKE_DOI_UNSUPPORTED;
}
/* Check situation field */
if ( sa->situation.ip_sec != IPIKE_SIT_IDENTITY_ONLY )
{
IPCOM_LOG1(ERR, "ipike_sa_check_payload() :: "\
"DOI situation not supported (0x%.2x)",
sa->situation.ip_sec);
return IPIKE_SITUATION_UNSUPPORTED;
}
proposal_payload_max_len = ipike_sa_proposal_length(sa);
proposal = ipike_sa_proposal_data(sa);
/* Check the length of the proposal payload chain */
chain_length = ipike_payload_chain_size(
&proposal->header, proposal_payload_max_len);
if (chain_length <= 0)
{
IPCOM_LOG0(ERR,
"the proposal payloads extends beyond the end of the SA payload size");
return IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
}
if (chain_length != (Ip_s32) proposal_payload_max_len)
{
IPCOM_LOG0(ERR, "the propsal payload is not as long as indicated by the SA payload header");
return IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
}
/* Save "next payload" so we can determine if the payload is supported */
next_payload = proposal->header.next_payload;
for (;IP_NULL != proposal; proposal = ipike_sa_next_payload(proposal))
{
Ipike_error err;
if(proposal->header.flags)
{
return IPIKE_ISAKMP_INVALID_PAYLOAD;
}
if((phase1 == IP_TRUE) && (i != 0))/* WIND00397389 */
{
return IPIKE_ISAKMP_INVALID_PAYLOAD;
}
/* Ignore unsupported payload */
if ( IPIKE_PAYLOAD_NONE != next_payload &&
IPIKE_PAYLOAD_PROPOSAL != next_payload )
{
IPCOM_LOG3(WARNING,
"ipike_check_proposal_payload: ignoring unsupported payload (%u) in field in "
"the proposal payload, only %d and %d are supported",
next_payload, IPIKE_PAYLOAD_NONE, IPIKE_PAYLOAD_PROPOSAL);
return IPIKE_ISAKMP_INVALID_PAYLOAD_PROPOSAL;
}
if (IPIKE_SUCCESS != (err = ipike_proposal_check_payload(proposal,phase1)))
return err;
next_payload = proposal->header.next_payload;
i++;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_sa_extract
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_sa_extract(
Ipike_isakmp_exchange* ie,
Ipike_sa_payload* payload,
Ipike_sa* sa)
{
Ipike_error err;
sa->selected_proposal = -1; /* No selected proposal */
sa->selected_proposal2 = -1; /* For ESP + AH */
sa->doi = ip_ntohl(payload->doi);
sa->situation.ip_sec = payload->situation.ip_sec;
switch ( sa->doi )
{
case IPIKE_DOI_IPSEC:
err = ipike_sa_process_message_ipsec(ie, payload, sa);
break;
default:
return IPIKE_DOI_UNSUPPORTED;
}
return err;
}
/*
*===========================================================================
* ipike_sa_selected_proposal_count
*===========================================================================
*/
IP_GLOBAL int
ipike_sa_selected_proposal_count(Ipike_sa* sa)
{
int count = 0;
Ip_u8 p_number;
if (sa->proposals == IP_NULL)
return 0;
if (sa->selected_proposal < 0)
return -1;
p_number = sa->proposals[sa->selected_proposal]->number;
while (sa->proposals[sa->selected_proposal + count] != IP_NULL
&& p_number == sa->proposals[sa->selected_proposal + count]->number)
count++;
return count;
}
/*
*===========================================================================
* ipike_sa_selected_proposal_get
*===========================================================================
*/
IP_GLOBAL Ipike_proposal *
ipike_sa_selected_proposal_get(Ipike_sa* sa)
{
if (sa->proposals == IP_NULL)
return IP_NULL;
if (sa->selected_proposal < 0)
return IP_NULL;
return sa->proposals[sa->selected_proposal];
}
/*
*===========================================================================
* ipike_sa_selected_transform_get
*===========================================================================
*/
IP_GLOBAL Ipike_transform *
ipike_sa_selected_transform_get(Ipike_sa* sa)
{
Ipike_proposal * proposal;
proposal = ipike_sa_selected_proposal_get(sa);
if (proposal == IP_NULL)
return IP_NULL;
if (proposal->transforms == IP_NULL)
return IP_NULL;
if (proposal->selected_transform < 0)
return IP_NULL;
return proposal->transforms[proposal->selected_transform];
}
/*
*===========================================================================
* ipike_sa_contains_transform_transport_nat
*===========================================================================
*/
IP_GLOBAL Ip_bool
ipike_sa_contains_transform_transport_nat(Ipike_sa * sa)
{
int i;
int j;
for (i=0; i < sa->proposal_count; i++)
{
for (j=0; sa->proposals[i]->transforms[j] != IP_NULL; j++)
{
if (sa->proposals[i]->transforms[j]->ipsec.encapsulation_mode ==
IPIKE_IPSEC_ENCAPSULATION_MODE_UDP_TRANSPORT)
{
return IP_TRUE;
}
}
}
return IP_FALSE;
}
/*
*===========================================================================
* ipike_sa_ike_print_payload
*===========================================================================
*/
IP_GLOBAL void
ipike_sa_ike_print_payload(Ipike_sa_payload* sa)
{
ipike_sa_print_payload(sa, ipike_proposal_ike_print_payload, IP_TRUE);
}
/*
*===========================================================================
* ipike_sa_ipsec_print_payload
*===========================================================================
*/
IP_GLOBAL void
ipike_sa_ipsec_print_payload(Ipike_sa_payload* sa)
{
ipike_sa_print_payload(sa, ipike_proposal_ipsec_print_payload, IP_FALSE);
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/